mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-26 16:26:41 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
89
jeecgboot-vue3/src/components/chart/Bar.vue
Normal file
89
jeecgboot-vue3/src/components/chart/Bar.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'bar',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
seriesColor: {
|
||||
type: String,
|
||||
default: '#1890ff',
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'bar',
|
||||
type: 'bar',
|
||||
data: [],
|
||||
color: props.seriesColor,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
let seriesData = props.chartData.map((item) => {
|
||||
return item.value;
|
||||
});
|
||||
let xAxisData = props.chartData.map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
option.series[0].data = seriesData;
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
option.series[0].color = props.seriesColor;
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
option.xAxis.data = xAxisData;
|
||||
setOptions(option);
|
||||
}
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
86
jeecgboot-vue3/src/components/chart/BarAndLine.vue
Normal file
86
jeecgboot-vue3/src/components/chart/BarAndLine.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'barAndLine',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'bar',
|
||||
type: 'bar',
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
//图例类型
|
||||
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
|
||||
//轴数据
|
||||
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
|
||||
let seriesData = [];
|
||||
typeArr.forEach((type) => {
|
||||
let obj = { name: type };
|
||||
let chartArr = props.chartData.filter((item) => type === item.type);
|
||||
//data数据
|
||||
obj['data'] = chartArr.map((item) => item.value);
|
||||
obj['type'] = chartArr[0].seriesType;
|
||||
seriesData.push(obj);
|
||||
});
|
||||
option.series = seriesData;
|
||||
option.xAxis.data = xAxisData;
|
||||
setOptions(option);
|
||||
}
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
122
jeecgboot-vue3/src/components/chart/BarMulti.vue
Normal file
122
jeecgboot-vue3/src/components/chart/BarMulti.vue
Normal file
@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'BarMulti',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<string>,
|
||||
default: 'bar',
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
seriesColor: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
},
|
||||
emits: ['click'],
|
||||
setup(props, { emit }) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
top: 60,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
//图例类型
|
||||
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
|
||||
//轴数据
|
||||
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
|
||||
let seriesData = [];
|
||||
typeArr.forEach((type) => {
|
||||
let obj: any = { name: type, type: props.type };
|
||||
// update-begin-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
|
||||
let data = [];
|
||||
xAxisData.forEach((x) => {
|
||||
let dataArr = props.chartData.filter((item) => type === item.type && item.name == x);
|
||||
if (dataArr && dataArr.length > 0) {
|
||||
data.push(dataArr[0].value);
|
||||
} else {
|
||||
data.push(null);
|
||||
}
|
||||
});
|
||||
// update-end-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
|
||||
//data数据
|
||||
obj['data'] = data;
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
if (props.seriesColor?.length) {
|
||||
const findItem = props.seriesColor.find((item: any) => item.type === type);
|
||||
if (findItem?.color) {
|
||||
obj['color'] = findItem.color;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
seriesData.push(obj);
|
||||
});
|
||||
option.series = seriesData;
|
||||
option.xAxis.data = xAxisData;
|
||||
setOptions(option);
|
||||
getInstance()?.off('click', onClick);
|
||||
getInstance()?.on('click', onClick);
|
||||
}
|
||||
|
||||
function onClick(params) {
|
||||
emit('click', params);
|
||||
}
|
||||
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
109
jeecgboot-vue3/src/components/chart/ChartCard.vue
Normal file
109
jeecgboot-vue3/src/components/chart/ChartCard.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<a-card :loading="loading" :body-style="{ padding: '20px 24px 8px' }" :bordered="false">
|
||||
<div class="chart-card-header">
|
||||
<div class="meta">
|
||||
<span class="chart-card-title">{{ title }}</span>
|
||||
<span class="chart-card-action">
|
||||
<slot name="action"></slot>
|
||||
</span>
|
||||
</div>
|
||||
<div class="total"
|
||||
><span>{{ total }}</span></div
|
||||
>
|
||||
</div>
|
||||
<div class="chart-card-content">
|
||||
<div class="content-fix">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-card-footer">
|
||||
<div class="field">
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
total: {
|
||||
type: [Number, String],
|
||||
default: '',
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-card-header {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
.meta {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card-action {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.chart-card-footer {
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding-top: 9px;
|
||||
margin-top: 8px;
|
||||
|
||||
> * {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.field {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-card-content {
|
||||
margin-bottom: 12px;
|
||||
position: relative;
|
||||
height: 46px;
|
||||
width: 100%;
|
||||
|
||||
.content-fix {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.total {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 0;
|
||||
font-size: 30px;
|
||||
line-height: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
||||
110
jeecgboot-vue3/src/components/chart/Gauge.vue
Normal file
110
jeecgboot-vue3/src/components/chart/Gauge.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { GaugeChart } from 'echarts/charts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'Gauge',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Object as PropType<Object>,
|
||||
default: () => [],
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
seriesColor: {
|
||||
type: String,
|
||||
default: '#1890ff',
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
series: [
|
||||
{
|
||||
type: 'gauge',
|
||||
progress: {
|
||||
show: true,
|
||||
width: 12,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 12,
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitLine: {
|
||||
length: 12,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: '#999',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
distance: 25,
|
||||
color: '#999',
|
||||
fontSize: 12,
|
||||
},
|
||||
anchor: {
|
||||
show: true,
|
||||
showAbove: true,
|
||||
size: 20,
|
||||
itemStyle: {
|
||||
borderWidth: 5,
|
||||
},
|
||||
},
|
||||
title: {},
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
fontSize: 25,
|
||||
formatter: '{value}%',
|
||||
offsetCenter: [0, '80%'],
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 70,
|
||||
name: '本地磁盘',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
echarts.use(GaugeChart);
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
option.series[0].data[0].name = props.chartData.name;
|
||||
option.series[0].data[0].value = props.chartData.value;
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
option.series[0].color = props.seriesColor;
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
setOptions(option);
|
||||
}
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
79
jeecgboot-vue3/src/components/chart/HeadInfo.vue
Normal file
79
jeecgboot-vue3/src/components/chart/HeadInfo.vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="head-info" :class="center && 'center'">
|
||||
<span>{{ title }}</span>
|
||||
<p :style="{ color: `${$props.iconColor}` }">{{ content }} <a-icon :type="icon" :style="{ fontSize: `24px`, color: `${$props.iconColor}` }" /></p>
|
||||
<em v-if="bordered" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'HeadInfo',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
center: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: false,
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
iconColor: {
|
||||
type: String,
|
||||
default: '#2b99ff',
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.head-info {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
padding: 0 32px 0 0;
|
||||
min-width: 125px;
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
em {
|
||||
background-color: #e8e8e8;
|
||||
position: absolute;
|
||||
height: 56px;
|
||||
width: 1px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
116
jeecgboot-vue3/src/components/chart/LineMulti.vue
Normal file
116
jeecgboot-vue3/src/components/chart/LineMulti.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LineMulti',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<string>,
|
||||
default: 'line',
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
emits: ['click'],
|
||||
setup(props, { emit }) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, getInstance } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
top: 60,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
//图例类型
|
||||
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
|
||||
//轴数据
|
||||
let xAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
|
||||
let seriesData = [];
|
||||
typeArr.forEach((type) => {
|
||||
let obj: any = { name: type, type: props.type };
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
const findItem: any = props.chartData.find((item: any) => item.type == type);
|
||||
if (findItem && findItem.color) {
|
||||
obj.color = findItem.color;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
// update-begin-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
|
||||
let data = [];
|
||||
xAxisData.forEach((x) => {
|
||||
let dataArr = props.chartData.filter((item) => type === item.type && item.name == x);
|
||||
if (dataArr && dataArr.length > 0) {
|
||||
data.push(dataArr[0].value);
|
||||
} else {
|
||||
data.push(null);
|
||||
}
|
||||
});
|
||||
// update-end-author:liusq date:2023-7-12 for: [issues/613] LineMulti 在数据不对齐时,横坐标计算错误
|
||||
//data数据
|
||||
obj['data'] = data;
|
||||
seriesData.push(obj);
|
||||
});
|
||||
option.series = seriesData;
|
||||
option.xAxis.data = xAxisData;
|
||||
console.log('option', option);
|
||||
setOptions(option);
|
||||
getInstance()?.off('click', onClick);
|
||||
getInstance()?.on('click', onClick);
|
||||
}
|
||||
|
||||
function onClick(params) {
|
||||
emit('click', params);
|
||||
}
|
||||
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
89
jeecgboot-vue3/src/components/chart/Pie.vue
Normal file
89
jeecgboot-vue3/src/components/chart/Pie.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, watchEffect, reactive, watch } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'Pie',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
size: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
emits: ['click'],
|
||||
setup(props, { emit }) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, getInstance, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
formatter: '{b} ({c})',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '72%',
|
||||
center: ['50%', '55%'],
|
||||
data: [],
|
||||
labelLine: { show: true },
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b} \n ({d}%)',
|
||||
color: '#B1B9D3',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
/**
|
||||
* 监听拖拽大小变化
|
||||
*/
|
||||
watch(
|
||||
() => props.size,
|
||||
() => {
|
||||
resize();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
option.series[0].data = props.chartData;
|
||||
setOptions(option);
|
||||
resize();
|
||||
getInstance()?.off('click', onClick);
|
||||
getInstance()?.on('click', onClick);
|
||||
}
|
||||
|
||||
function onClick(params) {
|
||||
emit('click', params);
|
||||
}
|
||||
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
282
jeecgboot-vue3/src/components/chart/README.md
Normal file
282
jeecgboot-vue3/src/components/chart/README.md
Normal file
@ -0,0 +1,282 @@
|
||||
# 报表组件文档
|
||||
|
||||
## 柱状图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import Bar from '/@/components/chart/Bar.vue';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "1月",
|
||||
"value": 320
|
||||
},
|
||||
{
|
||||
"name": "2月",
|
||||
"value": 457
|
||||
},
|
||||
{
|
||||
"name": "3月",
|
||||
"value": 182
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
##### 代码示例
|
||||
|
||||
```html
|
||||
<template>
|
||||
<Bar :chartData="chartData"></Bar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Bar from '/@/components/chart/Bar.vue';
|
||||
const chartData = [
|
||||
{
|
||||
name: '1月',
|
||||
value: 320,
|
||||
},
|
||||
{
|
||||
name: '2月',
|
||||
value: 457,
|
||||
},
|
||||
{
|
||||
name: '3月',
|
||||
value: 182,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
```
|
||||
|
||||
## 多列柱状图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import BarMulti from '/@/components/chart/BarMulti.vue';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "1月",
|
||||
"value": 320,
|
||||
"type": "2021"
|
||||
},
|
||||
{
|
||||
"name": "2月",
|
||||
"value": 457,
|
||||
"type": "2021"
|
||||
},
|
||||
{
|
||||
"name": "3月",
|
||||
"value": 182,
|
||||
"type": "2021"
|
||||
},
|
||||
{
|
||||
"name": "1月",
|
||||
"value": 240,
|
||||
"type": "2022"
|
||||
},
|
||||
{
|
||||
"name": "2月",
|
||||
"value": 357,
|
||||
"type": "2022"
|
||||
},
|
||||
{
|
||||
"name": "3月",
|
||||
"value": 456,
|
||||
"type": "2022"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 迷你柱状图
|
||||
|
||||
同柱形图,修改配置即可
|
||||
|
||||
## 面积图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import Line from '/@/components/chart/Line.vue';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
| option | object | | 配置项 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "1月",
|
||||
"value": 320
|
||||
},
|
||||
{
|
||||
"name": "2月",
|
||||
"value": 457
|
||||
},
|
||||
{
|
||||
"name": "3月",
|
||||
"value": 182
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 多行折线图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import LineMulti from '/@/components/chart/LineMulti.vue';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
| option | object | | 配置项 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
同柱形图
|
||||
|
||||
## 饼状图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import Pie from '/@/components/chart/Pie';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
| option | object | | 配置项 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{ "name": "一月", "value": 40 },
|
||||
{ "name": "二月", "value": 21 },
|
||||
{ "name": "三月", "value": 17 },
|
||||
{ "name": "四月", "value": 13 },
|
||||
{ "name": "五月", "value": 9 }
|
||||
]
|
||||
```
|
||||
|
||||
## 雷达图
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import Radar from '/@/components/chart/Radar';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
| option | object | | 配置项 |
|
||||
|
||||
##### chartData 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{ "item": "一月", "score": 40 },
|
||||
{ "item": "二月", "score": 20 },
|
||||
{ "item": "三月", "score": 67 },
|
||||
{ "item": "四月", "score": 43 },
|
||||
{ "item": "五月", "score": 90 }
|
||||
]
|
||||
```
|
||||
|
||||
## 仪表盘
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import Gauge from '/@/components/chart/Gauge';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| --------- | ------ | ---- | ---------- |
|
||||
| chartData | array | ✔️ | 报表数据源 |
|
||||
| width | number | | 报表宽度 |
|
||||
| height | number | | 报表高度 |
|
||||
| option | object | | 配置项 |
|
||||
|
||||
## 排名列表
|
||||
|
||||
##### 引用方式
|
||||
|
||||
```js
|
||||
import RankList from '@/components/chart/RankList';
|
||||
```
|
||||
|
||||
##### 参数列表
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
| ------ | ------ | ---- | ------------------------ |
|
||||
| title | string | | 报表标题 |
|
||||
| list | array | | 排名列表数据 |
|
||||
| height | number | | 报表高度,默认自适应高度 |
|
||||
|
||||
##### list 示例
|
||||
|
||||
```json
|
||||
[
|
||||
{ "name": "北京朝阳 1 号店", "total": 1981 },
|
||||
{ "name": "北京朝阳 2 号店", "total": 1359 },
|
||||
{ "name": "北京朝阳 3 号店", "total": 1354 },
|
||||
{ "name": "北京朝阳 4 号店", "total": 263 },
|
||||
{ "name": "北京朝阳 5 号店", "total": 446 },
|
||||
{ "name": "北京朝阳 6 号店", "total": 796 }
|
||||
]
|
||||
```
|
||||
89
jeecgboot-vue3/src/components/chart/Radar.vue
Normal file
89
jeecgboot-vue3/src/components/chart/Radar.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'Radar',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
title: {
|
||||
text: '基础雷达图',
|
||||
},
|
||||
legend: {
|
||||
data: ['文综'],
|
||||
},
|
||||
radar: {
|
||||
indicator: [{ name: '历史' }, { name: '地理' }, { name: '生物' }, { name: '化学' }, { name: '物理' }, { name: '政治' }],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar' as 'custom',
|
||||
data: [
|
||||
{
|
||||
value: [82, 70, 60, 55, 90, 66],
|
||||
name: '文综',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
//图例类型
|
||||
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
|
||||
//雷达数据
|
||||
let indicator = Array.from(
|
||||
new Set(
|
||||
props.chartData.map((item) => {
|
||||
let { name, max } = item;
|
||||
return { name, max };
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
let data = [];
|
||||
typeArr.forEach((type) => {
|
||||
let obj = { name: type };
|
||||
let chartArr = props.chartData.filter((item) => type === item.type);
|
||||
obj['value'] = chartArr.map((item) => item.value);
|
||||
//data数据
|
||||
data.push(obj);
|
||||
});
|
||||
option.radar.axisName = indicator;
|
||||
option.series[0]['data'] = data;
|
||||
setOptions(option);
|
||||
}
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
79
jeecgboot-vue3/src/components/chart/RankList.vue
Normal file
79
jeecgboot-vue3/src/components/chart/RankList.vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="rank">
|
||||
<h4 class="title">{{ title }}</h4>
|
||||
<ul class="list" :style="{ height: height ? `${height}px` : 'auto', overflow: 'auto' }">
|
||||
<li :key="index" v-for="(item, index) in list">
|
||||
<span :class="index < 3 ? 'active' : null">{{ index + 1 }}</span>
|
||||
<span>{{ item.name }}</span>
|
||||
<span>{{ item.total }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'RankList',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
list: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rank {
|
||||
padding: 0 32px 32px 72px;
|
||||
|
||||
.list {
|
||||
margin: 25px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
li {
|
||||
margin-top: 16px;
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
&:first-child {
|
||||
background-color: #f5f5f5;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
border-radius: 20px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-right: 24px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
&.active {
|
||||
background-color: #314659;
|
||||
color: #fff;
|
||||
}
|
||||
&:last-child {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile .rank {
|
||||
padding: 0 32px 32px 32px;
|
||||
}
|
||||
</style>
|
||||
91
jeecgboot-vue3/src/components/chart/SingleLine.vue
Normal file
91
jeecgboot-vue3/src/components/chart/SingleLine.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'single-line',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
seriesColor: {
|
||||
type: String,
|
||||
default: '#1890ff',
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
smooth: true,
|
||||
areaStyle: {},
|
||||
data: [],
|
||||
color: props.seriesColor,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
let seriesData = props.chartData.map((item) => {
|
||||
return item.value;
|
||||
});
|
||||
let xAxisData = props.chartData.map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
option.series[0].data = seriesData;
|
||||
// update-begin--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
option.series[0].color = props.seriesColor;
|
||||
// update-end--author:liaozhiyang---date:20240407---for:【QQYUN-8762】首页默认及echars颜色调整
|
||||
option.xAxis.data = xAxisData;
|
||||
setOptions(option);
|
||||
}
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
107
jeecgboot-vue3/src/components/chart/StackBar.vue
Normal file
107
jeecgboot-vue3/src/components/chart/StackBar.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, reactive, watchEffect, watch } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
export default defineComponent({
|
||||
name: 'StackBar',
|
||||
props: {
|
||||
chartData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
required: true,
|
||||
},
|
||||
size: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<string>,
|
||||
default: 'bar',
|
||||
},
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts, resize } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 30,
|
||||
},
|
||||
grid: {
|
||||
top: 60,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: [],
|
||||
},
|
||||
series: [],
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.chartData && initCharts();
|
||||
});
|
||||
/**
|
||||
* 监听拖拽大小变化
|
||||
*/
|
||||
watch(
|
||||
() => props.size,
|
||||
() => {
|
||||
console.log('props.size', props.size);
|
||||
resize();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
function initCharts() {
|
||||
if (props.option) {
|
||||
Object.assign(option, cloneDeep(props.option));
|
||||
}
|
||||
//图例类型
|
||||
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
|
||||
//轴数据
|
||||
let yAxisData = Array.from(new Set(props.chartData.map((item) => item.name)));
|
||||
let seriesData = [];
|
||||
typeArr.forEach((type) => {
|
||||
let obj = { name: type, type: props.type, stack: 'total' };
|
||||
let chartArr = props.chartData.filter((item) => type === item.type);
|
||||
//data数据
|
||||
obj['data'] = chartArr.map((item) => item.value);
|
||||
seriesData.push(obj);
|
||||
});
|
||||
option.series = seriesData;
|
||||
option.yAxis.data = yAxisData;
|
||||
setOptions(option);
|
||||
}
|
||||
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
90
jeecgboot-vue3/src/components/chart/Trend.vue
Normal file
90
jeecgboot-vue3/src/components/chart/Trend.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="chart-trend">
|
||||
{{ term }}
|
||||
<span>{{ rate }}%</span>
|
||||
<span :class="['trend-icon', trend]"><Icon :icon="'ant-design:caret-' + trend + '-outlined'" /></span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Trend',
|
||||
props: {
|
||||
// 同title
|
||||
term: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
// 百分比
|
||||
percentage: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: Boolean,
|
||||
default: null,
|
||||
},
|
||||
target: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
fixed: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const trend = computed(() => {
|
||||
let type = props.type === null ? props.value >= props.target : props.type;
|
||||
return type ? 'up' : 'down';
|
||||
});
|
||||
const rate = computed(() =>
|
||||
(props.percentage === null ? (Math.abs(props.value - props.target) * 100) / props.target : props.percentage).toFixed(props.fixed)
|
||||
);
|
||||
return {
|
||||
trend,
|
||||
rate,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-trend {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
|
||||
.trend-icon {
|
||||
font-size: 12px;
|
||||
|
||||
&.up,
|
||||
&.down {
|
||||
margin-left: 4px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
transform: scale(0.83);
|
||||
}
|
||||
}
|
||||
|
||||
&.up {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
&.down {
|
||||
color: #52c41a;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user