Files
medical-mall/components/analytics/AnalyticsMultiLineChart.uvue
2026-02-04 09:14:37 +08:00

132 lines
3.5 KiB
Plaintext

<template>
<view class="chart-wrap" :style="{ height: heightPx }">
<EChartsView :option="chartOption" class="chart" />
</view>
</template>
<script lang="uts">
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
export default {
components: {
EChartsView
},
props: {
xLabels: { type: Array, default: () => [] },
series: { type: Array, default: () => [] },
height: { type: Number, default: 400 }
},
data() {
return {
heightPx: '400px',
chartOption: {} as any
}
},
watch: {
xLabels: { handler() { this.updateOption() }, deep: true },
series: { handler() { this.updateOption() }, deep: true },
height: {
handler() {
this.heightPx = `${this.height}px`
}
}
},
mounted() {
this.heightPx = `${this.height}px`
setTimeout(() => {
this.updateOption()
}, 200)
},
methods: {
toPlainObject(obj: any): any {
if (obj == null) return null
if (typeof obj !== 'object') return obj
if (Array.isArray(obj)) {
return obj.map((item) => this.toPlainObject(item))
}
const plain: any = {}
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const value = obj[key]
if (typeof value === 'function' || key.startsWith('_') || key === 'toJSON') {
continue
}
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
let isSimple = true
for (const k in value) {
if (typeof value[k] === 'object' && value[k] !== null) {
isSimple = false
break
}
}
plain[key] = isSimple ? { ...value } : this.toPlainObject(value)
} else {
plain[key] = value
}
}
}
return plain
},
updateOption() {
if (!this.xLabels || this.xLabels.length === 0) return
const seriesData = (this.series as Array<any>).map(s => {
return {
name: s.name,
type: 'line',
smooth: true,
showSymbol: false,
symbolSize: 0,
itemStyle: { color: s.color },
lineStyle: { width: 2 },
data: s.data
}
})
const option = {
grid: { left: 50, right: 30, top: 40, bottom: 60 },
tooltip: {
show: true,
trigger: 'axis',
confine: true,
backgroundColor: 'rgba(255, 255, 255, 0.9)',
textStyle: { color: '#666', fontSize: 12 }
},
legend: {
show: true,
top: 0,
right: 20,
itemWidth: 12,
itemHeight: 2,
textStyle: { fontSize: 11, color: '#666' }
},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.xLabels.map(s => String(s)),
axisLine: { lineStyle: { color: 'rgba(0,0,0,0.1)' } },
axisLabel: {
color: 'rgba(0,0,0,0.45)',
fontSize: 10,
rotate: 45
}
},
yAxis: {
type: 'value',
axisLine: { show: false },
splitLine: { lineStyle: { color: 'rgba(0,0,0,0.05)' } },
axisLabel: { color: 'rgba(0,0,0,0.45)', fontSize: 10 }
},
series: seriesData
}
this.chartOption = this.toPlainObject(option)
}
}
}
</script>
<style scoped>
.chart-wrap { width: 100%; position: relative; overflow: hidden; }
.chart { width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
</style>