| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- <template>
- <view class="overview-chart">
- <l-echart ref="chartRef" class="overview-chart__echart" :style="{ height: chartHeight }"></l-echart>
- </view>
- </template>
- <script setup>
- import * as echarts from "echarts";
- import { ref, watch, nextTick, computed } from "vue";
- const props = defineProps({
- chartData: {
- type: Array,
- default: () => [],
- },
- colors: {
- type: Array,
- default: () => ["#40b883", "#4a90e2", "#6797ed", "#9978fa", "#4ecee2", "#ffbb62", "#ff7d2e"],
- },
- });
- const chartRef = ref(null);
- const ROW_HEIGHT = 44;
- const chartHeight = computed(() => {
- const count = Math.max(props.chartData.length, 1);
- return `${Math.max(160, count * ROW_HEIGHT + 24)}px`;
- });
- function getSortedData() {
- const data = props.chartData.length ? [...props.chartData] : [{ name: "暂无数据", value: 0 }];
- return data.sort((a, b) => (Number(a.value) || 0) - (Number(b.value) || 0));
- }
- function buildOption() {
- const sortedData = getSortedData();
- const names = sortedData.map((item) => item.name);
- const values = sortedData.map((item) => Number(item.value) || 0);
- const totalValue = values.reduce((sum, val) => sum + val, 0) || Math.max(...values, 1);
- return {
- grid: {
- left: 8,
- right: 16,
- top: 8,
- bottom: 8,
- containLabel: true,
- },
- xAxis: {
- type: "value",
- show: false,
- max: totalValue,
- },
- yAxis: [
- {
- type: "category",
- data: names,
- inverse: true,
- axisLine: { show: false },
- axisTick: { show: false },
- axisLabel: {
- color: "#666",
- fontSize: 11,
- width: 96,
- overflow: "truncate",
- margin: 10,
- },
- },
- {
- type: "category",
- data: values,
- inverse: true,
- axisLine: { show: false },
- axisTick: { show: false },
- axisLabel: {
- color: "#666",
- fontSize: 11,
- margin: 12,
- formatter: (value) => value,
- },
- },
- ],
- series: [
- {
- type: "bar",
- data: values.map(() => totalValue),
- barWidth: 12,
- barGap: "-100%",
- barCategoryGap: "40%",
- silent: true,
- z: 0,
- itemStyle: {
- color: "#f0f2f5",
- borderRadius: 6,
- },
- },
- {
- type: "bar",
- data: values.map((value, index) => ({
- value,
- itemStyle: {
- color: props.colors[index % props.colors.length],
- borderRadius: 6,
- },
- })),
- barWidth: 12,
- barCategoryGap: "40%",
- z: 1,
- },
- ],
- };
- }
- function renderChart() {
- nextTick(() => {
- if (!chartRef.value) return;
- chartRef.value.init(echarts, (instance) => {
- instance.setOption(buildOption(), true);
- setTimeout(() => instance.resize(), 80);
- });
- });
- }
- watch(() => props.chartData, renderChart, { deep: true, immediate: true });
- </script>
- <style lang="scss" scoped>
- .overview-chart {
- &__echart {
- width: 100%;
- min-height: 160px;
- }
- }
- </style>
|