1
2 天以前 3a4a8c78098f41d3a7ce41f272cdefc35b572681
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<!-- 双向堆叠柱状图 -->
<template>
  <div ref="chartRef" :style="{ height: props.height }" v-loading="props.loading"> </div>
</template>
 
<script setup>
  import { useChartOps, useChartComponent } from '@/hooks/core/useChart'
  defineOptions({ name: 'ArtDualBarCompareChart' })
  const props = defineProps({
    height: { required: false, default: useChartOps().chartHeight },
    loading: { required: false, default: false },
    isEmpty: { required: false, default: false },
    colors: { required: false, default: () => useChartOps().colors },
    positiveData: { required: false, default: () => [] },
    negativeData: { required: false, default: () => [] },
    xAxisData: { required: false, default: () => [] },
    positiveName: { required: false, default: '正向数据' },
    negativeName: { required: false, default: '负向数据' },
    barWidth: { required: false, default: 16 },
    yAxisMin: { required: false, default: -100 },
    yAxisMax: { required: false, default: 100 },
    showDataLabel: { required: false, default: false },
    positiveBorderRadius: { required: false, default: () => [10, 10, 0, 0] },
    negativeBorderRadius: { required: false, default: () => [0, 0, 10, 10] },
    showAxisLabel: { required: false, default: true },
    showAxisLine: { required: false, default: false },
    showSplitLine: { required: false, default: false },
    showTooltip: { required: false, default: true },
    showLegend: { required: false, default: false },
    legendPosition: { required: false, default: 'bottom' }
  })
  const createSeriesConfig = (config) => {
    const { fontColor } = useChartOps()
    const animationConfig = getAnimationConfig()
    return {
      name: config.name,
      type: 'bar',
      stack: 'total',
      barWidth: props.barWidth,
      barGap: '-100%',
      data: config.data,
      itemStyle: {
        borderRadius: config.borderRadius,
        color: props.colors[config.colorIndex]
      },
      label: {
        show: props.showDataLabel,
        position: config.labelPosition,
        formatter: config.formatter || ((params) => String(params.value)),
        color: fontColor,
        fontSize: 12
      },
      ...animationConfig
    }
  }
  const {
    chartRef,
    getAxisLineStyle,
    getAxisLabelStyle,
    getAxisTickStyle,
    getSplitLineStyle,
    getAnimationConfig,
    getTooltipStyle,
    getLegendStyle,
    getGridWithLegend
  } = useChartComponent({
    props,
    checkEmpty: () => {
      return (
        props.isEmpty ||
        !props.positiveData.length ||
        !props.negativeData.length ||
        (props.positiveData.every((val) => val === 0) &&
          props.negativeData.every((val) => val === 0))
      )
    },
    watchSources: [
      () => props.positiveData,
      () => props.negativeData,
      () => props.xAxisData,
      () => props.colors
    ],
    generateOptions: () => {
      const processedNegativeData = props.negativeData.map((val) => (val > 0 ? -val : val))
      const gridConfig = {
        top: props.showLegend ? 50 : 20,
        right: 0,
        left: 0,
        bottom: 0,
        // 增加底部间距
        containLabel: true
      }
      const options = {
        backgroundColor: 'transparent',
        animation: true,
        animationDuration: 1e3,
        animationEasing: 'cubicOut',
        grid: getGridWithLegend(props.showLegend, props.legendPosition, gridConfig),
        // 优化的提示框配置
        tooltip: props.showTooltip
          ? {
              ...getTooltipStyle(),
              trigger: 'axis',
              axisPointer: {
                type: 'none'
                // 去除指示线
              }
            }
          : void 0,
        // 图例配置
        legend: props.showLegend
          ? {
              ...getLegendStyle(props.legendPosition),
              data: [props.negativeName, props.positiveName]
            }
          : void 0,
        // X轴配置
        xAxis: {
          type: 'category',
          data: props.xAxisData,
          axisTick: getAxisTickStyle(),
          axisLine: getAxisLineStyle(props.showAxisLine),
          axisLabel: getAxisLabelStyle(props.showAxisLabel),
          boundaryGap: true
        },
        // Y轴配置
        yAxis: {
          type: 'value',
          min: props.yAxisMin,
          max: props.yAxisMax,
          axisLabel: getAxisLabelStyle(props.showAxisLabel),
          axisLine: getAxisLineStyle(props.showAxisLine),
          splitLine: getSplitLineStyle(props.showSplitLine)
        },
        // 系列配置
        series: [
          // 负向数据系列
          createSeriesConfig({
            name: props.negativeName,
            data: processedNegativeData,
            borderRadius: props.negativeBorderRadius,
            labelPosition: 'bottom',
            colorIndex: 1,
            formatter: (params) => String(Math.abs(params.value))
          }),
          // 正向数据系列
          createSeriesConfig({
            name: props.positiveName,
            data: props.positiveData,
            borderRadius: props.positiveBorderRadius,
            labelPosition: 'top',
            colorIndex: 0
          })
        ]
      }
      return options
    }
  })
</script>