|
|
@@ -1,4 +1,209 @@
|
|
|
-<script lang="ts" setup></script>
|
|
|
+<script lang="ts" setup>
|
|
|
+import * as echarts from 'echarts'
|
|
|
+import { ANIMATION, CHART_RENDERER, createTooltip, FONT_FAMILY, THEME } from '@/utils/kb'
|
|
|
+
|
|
|
+interface DeviceCategoryItem {
|
|
|
+ name: string
|
|
|
+ count: number
|
|
|
+}
|
|
|
+
|
|
|
+const chartRef = ref<HTMLDivElement>()
|
|
|
+let chart: echarts.ECharts | null = null
|
|
|
+
|
|
|
+const categoryData: DeviceCategoryItem[] = [
|
|
|
+ { name: '压裂泵车', count: 75 },
|
|
|
+ { name: '连油主车', count: 36 },
|
|
|
+ { name: '其他', count: 35 },
|
|
|
+ { name: '小车', count: 32 },
|
|
|
+ { name: '井控装备', count: 22 },
|
|
|
+ { name: '连油辅助设备', count: 19 },
|
|
|
+ { name: '货车', count: 17 },
|
|
|
+ { name: '四川瑞都设备', count: 16 },
|
|
|
+ { name: '卡车', count: 16 },
|
|
|
+ { name: '供液橇', count: 12 }
|
|
|
+]
|
|
|
+
|
|
|
+function getChartLayout() {
|
|
|
+ const { clientWidth = 0, clientHeight = 0 } = chartRef.value ?? {}
|
|
|
+ const compact = clientHeight > 0 && (clientHeight < 210 || clientWidth < 520)
|
|
|
+
|
|
|
+ return {
|
|
|
+ gridTop: compact ? 20 : 26,
|
|
|
+ gridRight: compact ? 32 : 40,
|
|
|
+ gridBottom: compact ? 22 : 28,
|
|
|
+ gridLeft: compact ? 12 : 12,
|
|
|
+ barWidth: compact ? 10 : 14,
|
|
|
+ axisFontSize: compact ? 10 : 12,
|
|
|
+ labelFontSize: compact ? 10 : 12
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function formatValue(value: number) {
|
|
|
+ return Number(value || 0).toLocaleString('en-US')
|
|
|
+}
|
|
|
+
|
|
|
+function getChartOption(): echarts.EChartsOption {
|
|
|
+ const layout = getChartLayout()
|
|
|
+ const values = categoryData.map((item) => item.count)
|
|
|
+ const maxValue = Math.max(...values, 1)
|
|
|
+ const xAxisMax = Math.ceil((maxValue * 1.12) / 10) * 10
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...ANIMATION,
|
|
|
+ grid: {
|
|
|
+ ...THEME.grid,
|
|
|
+ top: layout.gridTop,
|
|
|
+ right: layout.gridRight,
|
|
|
+ bottom: layout.gridBottom,
|
|
|
+ left: layout.gridLeft
|
|
|
+ },
|
|
|
+ tooltip: createTooltip({
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'shadow',
|
|
|
+ shadowStyle: {
|
|
|
+ color: THEME.split
|
|
|
+ }
|
|
|
+ },
|
|
|
+ formatter(params: any[]) {
|
|
|
+ const first = params[0]
|
|
|
+ const row = categoryData[first?.dataIndex ?? 0]
|
|
|
+ if (!row) return ''
|
|
|
+
|
|
|
+ return [
|
|
|
+ `<div style="min-width:132px;font-weight:700;color:#24364f;margin-bottom:6px;">${row.name}</div>`,
|
|
|
+ `<div style="display:flex;justify-content:space-between;gap:18px;line-height:22px;"><span>设备数量</span><b style="color:#1f5bb8;">${row.count} 台</b></div>`
|
|
|
+ ].join('')
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ xAxis: {
|
|
|
+ type: 'value',
|
|
|
+ name: '台',
|
|
|
+ max: xAxisMax,
|
|
|
+ axisLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: THEME.text.regular,
|
|
|
+ fontSize: layout.axisFontSize,
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
+ formatter(value: number) {
|
|
|
+ return formatValue(value)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ nameTextStyle: {
|
|
|
+ color: '#4c6c9b',
|
|
|
+ fontSize: layout.axisFontSize,
|
|
|
+ fontWeight: 600,
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
+ },
|
|
|
+ splitLine: {
|
|
|
+ lineStyle: {
|
|
|
+ color: 'rgba(31, 91, 184, 0.24)',
|
|
|
+ type: 'dashed'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: categoryData.map((item) => item.name),
|
|
|
+ inverse: true,
|
|
|
+ axisLine: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisTick: {
|
|
|
+ show: false
|
|
|
+ },
|
|
|
+ axisLabel: {
|
|
|
+ color: '#102a43',
|
|
|
+ fontSize: layout.axisFontSize,
|
|
|
+ fontWeight: 600,
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
+ width: 80,
|
|
|
+ overflow: 'truncate'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '设备数量',
|
|
|
+ type: 'bar',
|
|
|
+ data: values,
|
|
|
+ barWidth: layout.barWidth,
|
|
|
+ showBackground: true,
|
|
|
+ backgroundStyle: {
|
|
|
+ color: 'rgba(31, 91, 184, 0.08)',
|
|
|
+ borderRadius: 999
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ borderRadius: 999,
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
+ { offset: 0, color: THEME.color.blue.light },
|
|
|
+ { offset: 0.58, color: THEME.color.blue.mid },
|
|
|
+ { offset: 1, color: THEME.color.blue.line }
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ label: {
|
|
|
+ show: true,
|
|
|
+ position: 'right',
|
|
|
+ distance: 8,
|
|
|
+ color: THEME.text.strong,
|
|
|
+ fontSize: layout.labelFontSize,
|
|
|
+ fontWeight: 700,
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
+ formatter(params: any) {
|
|
|
+ return `${formatValue(params.value)}`
|
|
|
+ }
|
|
|
+ },
|
|
|
+ emphasis: {
|
|
|
+ itemStyle: {
|
|
|
+ shadowBlur: 16,
|
|
|
+ shadowColor: THEME.color.blue.shadow
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function initChart() {
|
|
|
+ if (!chartRef.value) return
|
|
|
+
|
|
|
+ chart?.dispose()
|
|
|
+ chart = echarts.init(chartRef.value, undefined, {
|
|
|
+ renderer: CHART_RENDERER
|
|
|
+ })
|
|
|
+ renderChart()
|
|
|
+}
|
|
|
+
|
|
|
+function renderChart() {
|
|
|
+ chart?.setOption(getChartOption(), true)
|
|
|
+}
|
|
|
+
|
|
|
+function resizeChart() {
|
|
|
+ chart?.resize()
|
|
|
+ renderChart()
|
|
|
+}
|
|
|
+
|
|
|
+function destroyChart() {
|
|
|
+ chart?.dispose()
|
|
|
+ chart = null
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initChart()
|
|
|
+ window.addEventListener('resize', resizeChart)
|
|
|
+ window.addEventListener('rdkb:resize', resizeChart)
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('resize', resizeChart)
|
|
|
+ window.removeEventListener('rdkb:resize', resizeChart)
|
|
|
+ destroyChart()
|
|
|
+})
|
|
|
+</script>
|
|
|
|
|
|
<template>
|
|
|
<div class="panel flex flex-col">
|
|
|
@@ -9,10 +214,16 @@
|
|
|
</div>
|
|
|
设备分类
|
|
|
</div>
|
|
|
- <div ref="chartRef" class="flex-1 min-h-0"></div>
|
|
|
+ <div ref="chartRef" class="device-category-chart"></div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
@import url('@/styles/kb.scss');
|
|
|
+
|
|
|
+.device-category-chart {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 0;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
</style>
|