|
@@ -1,4 +1,236 @@
|
|
|
-<script lang="ts" setup></script>
|
|
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import * as echarts from 'echarts'
|
|
|
|
|
+import {
|
|
|
|
|
+ ANIMATION,
|
|
|
|
|
+ ChartData,
|
|
|
|
|
+ CHART_RENDERER,
|
|
|
|
|
+ createLegend,
|
|
|
|
|
+ createTooltip,
|
|
|
|
|
+ FONT_FAMILY,
|
|
|
|
|
+ formatMonthLabel,
|
|
|
|
|
+ formatSeriesName,
|
|
|
|
|
+ THEME
|
|
|
|
|
+} from '@/utils/kb'
|
|
|
|
|
+import { IotStatApi } from '@/api/pms/stat'
|
|
|
|
|
+
|
|
|
|
|
+const chartData = ref<ChartData>({
|
|
|
|
|
+ xAxis: [],
|
|
|
|
|
+ series: []
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const chartRef = ref<HTMLDivElement>()
|
|
|
|
|
+let chart: echarts.ECharts | null = null
|
|
|
|
|
+const router = useRouter()
|
|
|
|
|
+let chartClickBound = false
|
|
|
|
|
+
|
|
|
|
|
+function getBarStyle(color: (typeof THEME.color)[keyof typeof THEME.color]) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ borderRadius: [12, 12, 0, 0],
|
|
|
|
|
+ shadowBlur: 12,
|
|
|
|
|
+ shadowColor: color.bg,
|
|
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
+ { offset: 0, color: color.light },
|
|
|
|
|
+ { offset: 0.55, color: color.mid },
|
|
|
|
|
+ { offset: 1, color: color.line }
|
|
|
|
|
+ ])
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatCount(value: number | string) {
|
|
|
|
|
+ return Number(value || 0).toLocaleString('en-US')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getChartOption(data: ChartData): echarts.EChartsOption {
|
|
|
|
|
+ const xAxisData = data.xAxis || []
|
|
|
|
|
+ const seriesData = data.series || []
|
|
|
|
|
+ const colorList = [THEME.color.green, THEME.color.orange]
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...ANIMATION,
|
|
|
|
|
+ grid: {
|
|
|
|
|
+ ...THEME.grid,
|
|
|
|
|
+ top: 50,
|
|
|
|
|
+ bottom: 10
|
|
|
|
|
+ },
|
|
|
|
|
+ tooltip: createTooltip({
|
|
|
|
|
+ trigger: 'axis',
|
|
|
|
|
+ axisPointer: {
|
|
|
|
|
+ type: 'shadow',
|
|
|
|
|
+ shadowStyle: {
|
|
|
|
|
+ color: THEME.split
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ valueFormatter(value: number | string) {
|
|
|
|
|
+ return formatCount(value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }),
|
|
|
|
|
+ legend: createLegend(
|
|
|
|
|
+ {
|
|
|
|
|
+ top: 4,
|
|
|
|
|
+ itemWidth: 12,
|
|
|
|
|
+ itemHeight: 12
|
|
|
|
|
+ },
|
|
|
|
|
+ seriesData.map((item) => formatSeriesName(item.name))
|
|
|
|
|
+ ),
|
|
|
|
|
+ xAxis: {
|
|
|
|
|
+ type: 'category',
|
|
|
|
|
+ data: xAxisData,
|
|
|
|
|
+ axisLine: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisTick: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ interval: 0,
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
|
|
+ formatter(value: string) {
|
|
|
|
|
+ return formatMonthLabel(value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ name: '次数',
|
|
|
|
|
+ splitNumber: 4,
|
|
|
|
|
+ nameTextStyle: {
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: 13,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ axisLine: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisTick: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: 12,
|
|
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
|
|
+ formatter(value: number) {
|
|
|
|
|
+ return formatCount(value)
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ splitLine: {
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: THEME.split,
|
|
|
|
|
+ type: 'dashed'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ series: seriesData.map((item, index) => {
|
|
|
|
|
+ const color = colorList[index % colorList.length]
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ name: formatSeriesName(item.name),
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ data: item.data || [],
|
|
|
|
|
+ barWidth: 22,
|
|
|
|
|
+ barMaxWidth: 30,
|
|
|
|
|
+ showBackground: true,
|
|
|
|
|
+ backgroundStyle: {
|
|
|
|
|
+ color: THEME.split,
|
|
|
|
|
+ borderRadius: [12, 12, 0, 0]
|
|
|
|
|
+ },
|
|
|
|
|
+ itemStyle: getBarStyle(color),
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'top',
|
|
|
|
|
+ distance: 10,
|
|
|
|
|
+ color: color.strong,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
|
|
+ formatter(params: any) {
|
|
|
|
|
+ return Number(params.value) ? formatCount(params.value) : ''
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ focus: 'series',
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ ...getBarStyle(color),
|
|
|
|
|
+ shadowColor: color.shadow,
|
|
|
|
|
+ shadowBlur: 18
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function initChart() {
|
|
|
|
|
+ if (!chartRef.value) return
|
|
|
|
|
+ chart?.dispose()
|
|
|
|
|
+ chart = echarts.init(chartRef.value, undefined, {
|
|
|
|
|
+ renderer: CHART_RENDERER
|
|
|
|
|
+ })
|
|
|
|
|
+ chart.getZr().on('click', handleChartClick)
|
|
|
|
|
+ chartClickBound = true
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function handleChartClick() {
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ name: 'WorkOrderCompletion'
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function renderChart() {
|
|
|
|
|
+ chart?.setOption(getChartOption(chartData.value), true)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function resizeChart() {
|
|
|
|
|
+ chart?.resize()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function destroyChart() {
|
|
|
|
|
+ if (chart) {
|
|
|
|
|
+ if (chartClickBound) {
|
|
|
|
|
+ chart.getZr().off('click', handleChartClick)
|
|
|
|
|
+ chartClickBound = false
|
|
|
|
|
+ }
|
|
|
|
|
+ chart.dispose()
|
|
|
|
|
+ chart = null
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function loadChart() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await IotStatApi.getRdRecentWbcs()
|
|
|
|
|
+ chartData.value = {
|
|
|
|
|
+ xAxis: (res?.xAxis || []).map((item) => `${item}`),
|
|
|
|
|
+ series: (res?.series || []).map((item) => ({
|
|
|
|
|
+ name: item.name,
|
|
|
|
|
+ data: (item.data || []).map((value) => Number(value || 0))
|
|
|
|
|
+ }))
|
|
|
|
|
+ }
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取维保次数失败:', error)
|
|
|
|
|
+ chartData.value = {
|
|
|
|
|
+ xAxis: [],
|
|
|
|
|
+ series: []
|
|
|
|
|
+ }
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ initChart()
|
|
|
|
|
+ loadChart()
|
|
|
|
|
+ window.addEventListener('resize', resizeChart)
|
|
|
|
|
+ window.addEventListener('rdkb:resize', resizeChart)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ window.removeEventListener('resize', resizeChart)
|
|
|
|
|
+ window.removeEventListener('rdkb:resize', resizeChart)
|
|
|
|
|
+ destroyChart()
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
|
|
|
<template>
|
|
<template>
|
|
|
<div class="panel flex flex-col">
|
|
<div class="panel flex flex-col">
|