|
@@ -0,0 +1,178 @@
|
|
|
|
|
+<script lang="ts" setup>
|
|
|
|
|
+import * as echarts from 'echarts'
|
|
|
|
|
+import { ANIMATION, ChartItem, createTooltip, FONT_FAMILY, THEME } from '@/utils/kb'
|
|
|
|
|
+import { IotStatApi } from '@/api/pms/stat'
|
|
|
|
|
+
|
|
|
|
|
+const chartData = ref<ChartItem[]>([])
|
|
|
|
|
+
|
|
|
|
|
+const chartRef = ref<HTMLDivElement>()
|
|
|
|
|
+let chart: echarts.ECharts | null = null
|
|
|
|
|
+
|
|
|
|
|
+function getChartOption(data: ChartItem[]): echarts.EChartsOption {
|
|
|
|
|
+ const names = data.map((item) => item.name)
|
|
|
|
|
+ const values = data.map((item) => item.value)
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...ANIMATION,
|
|
|
|
|
+ grid: { ...THEME.grid, right: 36 },
|
|
|
|
|
+ tooltip: createTooltip({
|
|
|
|
|
+ trigger: 'axis',
|
|
|
|
|
+ axisPointer: {
|
|
|
|
|
+ type: 'shadow',
|
|
|
|
|
+ shadowStyle: {
|
|
|
|
|
+ color: THEME.split
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }),
|
|
|
|
|
+ xAxis: {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ splitNumber: 4,
|
|
|
|
|
+ axisLine: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisTick: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ splitLine: {
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: THEME.split,
|
|
|
|
|
+ type: 'dashed'
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
|
|
+ type: 'category',
|
|
|
|
|
+ data: names,
|
|
|
|
|
+ inverse: true,
|
|
|
|
|
+ axisLine: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisTick: {
|
|
|
|
|
+ show: false
|
|
|
|
|
+ },
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ margin: 16,
|
|
|
|
|
+ fontWeight: 500,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '设备类型',
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ data: values,
|
|
|
|
|
+ barWidth: 14,
|
|
|
|
|
+ showBackground: true,
|
|
|
|
|
+ backgroundStyle: {
|
|
|
|
|
+ color: THEME.split,
|
|
|
|
|
+ borderRadius: 999
|
|
|
|
|
+ },
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ borderRadius: 999,
|
|
|
|
|
+ shadowBlur: 12,
|
|
|
|
|
+ shadowColor: THEME.color.blue.bg,
|
|
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
+ { offset: 0, color: THEME.color.blue.light },
|
|
|
|
|
+ { offset: 0.5, color: THEME.color.blue.mid },
|
|
|
|
|
+ { offset: 1, color: THEME.color.blue.line }
|
|
|
|
|
+ ])
|
|
|
|
|
+ },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'right',
|
|
|
|
|
+ distance: 8,
|
|
|
|
|
+ color: THEME.color.blue.strong,
|
|
|
|
|
+ fontSize: 16,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ emphasis: {
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ shadowBlur: 16,
|
|
|
|
|
+ shadowColor: THEME.color.blue.shadow
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function initChart() {
|
|
|
|
|
+ if (!chartRef.value) return
|
|
|
|
|
+ if (chart) {
|
|
|
|
|
+ chart.dispose()
|
|
|
|
|
+ }
|
|
|
|
|
+ chart = echarts.init(chartRef.value, undefined, {
|
|
|
|
|
+ renderer: 'svg'
|
|
|
|
|
+ })
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function renderChart() {
|
|
|
|
|
+ if (!chart) return
|
|
|
|
|
+
|
|
|
|
|
+ const data = chartData.value || []
|
|
|
|
|
+
|
|
|
|
|
+ chart.setOption(getChartOption(data), true)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function resizeChart() {
|
|
|
|
|
+ chart?.resize()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function destroyChart() {
|
|
|
|
|
+ if (chart) {
|
|
|
|
|
+ chart.dispose()
|
|
|
|
|
+ chart = null
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function loadChart() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await IotStatApi.getDeviceTypeCount('ry')
|
|
|
|
|
+ chartData.value = Array.isArray(res)
|
|
|
|
|
+ ? res.map((item) => ({ name: item.category, value: item.value }))
|
|
|
|
|
+ : []
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取设备类型失败:', error)
|
|
|
|
|
+ chartData.value = []
|
|
|
|
|
+ renderChart()
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ initChart()
|
|
|
|
|
+ loadChart()
|
|
|
|
|
+ window.addEventListener('resize', resizeChart)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onUnmounted(() => {
|
|
|
|
|
+ window.removeEventListener('resize', resizeChart)
|
|
|
|
|
+ destroyChart()
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="panel flex flex-col">
|
|
|
|
|
+ <div class="panel-title h-9">
|
|
|
|
|
+ <div class="icon-decorator">
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ <span></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ 设备类别top
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div ref="chartRef" class="flex-1 min-h-0"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+@import url('@/styles/kb.scss');
|
|
|
|
|
+</style>
|