Files
dvcp_v2_webapp/ui/packages/tools/AiEchartV2.vue

237 lines
6.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<section class="AiEchart">
<div :ref="AiEchart" class="chart" :style="{minWidth:grid.width,minHeight:grid.height}"/>
<slot v-if="$slots.default"/>
<render-component v-else-if="ops.render" :render="ops.render" :options="chartOptions" :data="data"/>
</section>
</template>
<script>
const mergeOps = (ori = {}, ext = {}) => {
for (const k in ext) {
if (typeof ext[k] == 'object') {
ori[k] = mergeOps(ori[k], ext[k])
} else ori[k] = ext[k]
}
return ori
}
export default {
name: "AiEchartV2",
props: {
data: {default: () => []},
ops: {default: () => ({})},
type: {default: "line"},
tpl: String,
series: Object,
theme: {
default: '0'
}
},
components: {
renderComponent: {
functional: true,
props: {
render: Function,
options: {default: () => ({})},
data: {default: () => []}
},
render(h, ins) {
let {options = {}, data} = ins.props
return ins.props.render(h, {...options, data})
}
}
},
data() {
return {
chart: null,
timer: null,
AiEchart: `AiEchart-${new Date().getTime()}`
}
},
computed: {
colors() {
if (this.theme === '0') {
return ['#00F9FF', '#1890FF', '#B13BFF', '#FC3BFF', '#95FF44', '#ea7ccc']
}
return ['#FFBA44', '#EC6666', '#FF3E18', '#C9FF82', '#29D7FA', '#ea7ccc']
},
chartOptions() {
const {daemon = {}} = this.$echartTpls[this.tpl] || {}
let {type, data, ops: options = {}} = this,
style = this.series ? this.series : this.ops.daemon ? this.ops.daemon : {},
colors = this.theme === '1' ? this.colors : (options.color || this.colors),
legend = {textStyle: {color: '#fff', padding: [0, 0, 0, 8], fontSize: 14}, show: false}
const series = data?.[0] ? Array(Object.keys(data?.[0]).length - 1).fill(1)
.map((e, i) => ({type, ...mergeOps(daemon, typeof style == 'object' ? style : style(colors[i]))})) : []
return {
tooltip: {},
xAxis: {
type: 'category', nameGap: 20, axisTick: false,
axisLabel: {
color: '#C3C4C4',
interval: 0,
rotate: this.data.length > 10 ? 40 : 0
},
axisLine: {
lineStyle: {
color: this.theme === '1' ? 'rgba(239, 163, 51, 0.8)' : 'rgba(255,255,255,.5)',
width: 1
}
}
},
// 声明一个 Y 轴,数值轴。
yAxis: {
nameGap: 23, minInterval: 1,
splitLine: {
lineStyle: {
color: this.theme === '1' ? 'rgba(255, 197, 52, 0.4)' : 'rgba(255, 255, 255, .2)',
type: 'dashed'
}
},
axisLabel: {color: '#C3C4C4'},
axisLine: {
lineStyle: {
color: '#C3C4C4'
}
}
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
top: '26px',
containLabel: true
},
legend, series, ...options,
color: colors
}
},
grid() {
let {width, height} = this.chartOptions.grid || {}
return {
width: width ? (width - this.legend === '1' ? 160 : 0) + 'px' : 'auto',
height: height ? height + 'px' : 'auto'
}
}
},
watch: {
data: {
deep: true, handler(v, old) {
let oldDims = Object.keys(old?.[0] || {})?.toString(),
current = Object.keys(v?.[0] || {})?.toString()
this.getChartData(oldDims != current)
}
},
theme() {
this.refresh()
},
tpl(v) {
v && this.refresh()
}
},
methods: {
deepAssign() {
let name, options, src, copy
let length = arguments.length
// 记录要复制的对象的下标
let i = 1
// target默认是第一个参数
let target = arguments[0] || {}
// 如果target不是对象我们是无法进行复制的所以设为{}
if (typeof target !== 'object') {
target = {}
}
// 循环遍历要复制的对象
for (; i < length; i++) {
// 获取当前对象
options = arguments[i]
// 要求不能为空 避免extend(a,,b)这种情况
if (options != null) {
for (name in options) {
// 目标属性值
src = target[name]
// 要复制的对象的属性值
copy = options[name]
if (copy && typeof copy == 'object') {
// 递归调用
target[name] = this.deepAssign(src, copy)
} else if (copy !== undefined) {
target[name] = copy
}
}
}
}
return target
},
getChartData(render) {
if (!render) {
this.chart?.setOption({
dataset: {
source: this.data || []
}
})
} else {
this.chart?.setOption({
...this.chartOptions,
dataset: {
source: this.data || []
}
}, true)
}
},
initChart() {
this.chart = echarts.init(this.$refs[this.AiEchart])
this.chart.setOption(this.chartOptions || {})
},
watchResize() {
this.timer && clearInterval(this.timer)
this.timer = setInterval(() => {
if (this.chart?.getHeight() != this.$refs[this.AiEchart]?.clientHeight ||
this.chart?.getWidth() != this.$refs[this.AiEchart]?.clientWidth) {
this.chart?.resize()
}
}, 1000)
//5分钟后停止监听
setTimeout(() => this.timer && clearInterval(this.timer), 5 * 60 * 1000)
},
refresh() {
this.chart.setOption(this.chartOptions || {})
}
},
mounted() {
this.$nextTick(() => {
this.watchResize()
this.initChart()
this.getChartData()
})
},
beforeDestroy() {
this.timer && clearInterval(this.timer)
}
}
</script>
<style lang="scss" scoped>
.AiEchart {
display: flex;
width: 100%;
height: 100%;
flex: 1;
min-width: 100px;
min-height: 0;
position: relative;
.chart {
flex: 1;
height: 100%;
min-height: 100px;
}
}
</style>