<template>
|
<div>
|
<PanelHeader title="供应商采购排名" />
|
<div class="panel-item-customers">
|
<div class="switch-container">
|
<DateTypeSwitch v-model="radio1" @change="handleDateTypeChange" />
|
</div>
|
<Echarts
|
ref="chart"
|
:chartStyle="chartStyle"
|
:grid="grid"
|
:series="series"
|
:tooltip="tooltip"
|
:xAxis="xAxis"
|
:yAxis="yAxis"
|
:options="{ backgroundColor: 'transparent', textStyle: { color: BI.text } }"
|
style="height: 360px"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, computed } from 'vue'
|
import Echarts from '@/components/Echarts/echarts.vue'
|
import PanelHeader from '../PanelHeader.vue'
|
import DateTypeSwitch from '../DateTypeSwitch.vue'
|
import { supplierPurchaseRanking } from '@/api/viewIndex.js'
|
import { BI, withTooltip } from '../../theme.js'
|
|
const chartStyle = {
|
width: '100%',
|
height: '100%',
|
}
|
|
const radio1 = ref(3) // 1=周 2=月 3=季度,默认季度
|
|
// 原始数据
|
const dataArr = ref([])
|
|
// 排序后的数据(升序:值越大越靠上)
|
const dataArray = computed(() => {
|
return [...dataArr.value].sort((a, b) => a.NUM - b.NUM)
|
})
|
|
// 计算总数
|
const total = computed(() => {
|
return dataArray.value.reduce((sum, v) => sum + Number(v.NUM), 0)
|
})
|
|
// x轴数据(名称)
|
const xdataName = computed(() => {
|
return dataArray.value.map((v) => v.NAME)
|
})
|
|
// 排名配色:Top1 金色,Top2-3 亮蓝,其余暗蓝
|
const rankColor = (rank) => {
|
if (rank === 1) return '#F0B14A'
|
if (rank <= 3) return BI.accentBright
|
return '#2C4A9E'
|
}
|
|
const getRank = (i) => dataArray.value.length - i
|
|
// y轴数据(数值,带样式)
|
const dataNum = computed(() => {
|
return dataArray.value.map((v, i) => {
|
const rank = getRank(i)
|
return {
|
value: Number(v.NUM),
|
itemStyle: {
|
color: rankColor(rank),
|
barBorderRadius: [0, 10, 10, 0],
|
},
|
}
|
})
|
})
|
|
// 背景轨道数据
|
const bgData = computed(() => {
|
const maxValue = dataNum.value.length ? Math.max(...dataNum.value.map((v) => v.value)) : 0
|
return dataNum.value.map(() => maxValue * 1.08 || 1)
|
})
|
|
// tooltip
|
const tooltip = withTooltip({
|
trigger: 'axis',
|
formatter: function (params) {
|
let result = params[0].axisValueLabel + '<br/>'
|
result += `<div>${params[0].marker}${Number(params[0].value || 0).toLocaleString('zh-CN')}元</div>`
|
return result
|
},
|
})
|
|
// grid
|
const grid = computed(() => {
|
return { top: 0, left: '20%', right: '10%', bottom: 0 }
|
})
|
|
// xAxis
|
const xAxis = computed(() => {
|
return [
|
{
|
splitLine: { show: false },
|
axisLine: { show: false },
|
axisLabel: { show: false },
|
axisTick: { show: false },
|
},
|
]
|
})
|
|
// yAxis
|
const yAxis = computed(() => {
|
return [
|
{
|
type: 'category',
|
inverse: false,
|
data: xdataName.value,
|
axisLabel: {
|
formatter: (value) => {
|
if (!value) return ''
|
const maxLen = 6 // 每行最多字符数,可按需调整
|
if (value.length <= maxLen) return `{a|${value}}`
|
|
const lines = []
|
for (let i = 0; i < value.length; i += maxLen) {
|
lines.push(value.slice(i, i + maxLen))
|
}
|
// 多行文本,每行都套同一个 rich 样式
|
return lines.map((line) => `{a|${line}}`).join('\n')
|
},
|
rich: {
|
a: {
|
width: 120,
|
fontSize: 14,
|
color: BI.textStrong,
|
padding: [5, 4, 5, 0],
|
align: 'right',
|
},
|
},
|
},
|
axisLine: { show: false },
|
axisTick: { show: false },
|
splitLine: { show: false },
|
},
|
{
|
type: 'category',
|
data: dataNum.value.map((item) => item.value),
|
axisLabel: {
|
formatter: (params, index) => {
|
const value = typeof params === 'object' ? params.value : params
|
const percent = total.value ? ((value / total.value) * 100).toFixed(0) : 0
|
const rank = getRank(index)
|
return `{a${rank}|${percent} }{b${rank}|%}`
|
},
|
rich: dataNum.value.reduce((rich, _, i) => {
|
const rank = getRank(i)
|
const color = rank === 1 ? '#F0B14A' : rank <= 3 ? BI.accentBright : BI.text
|
rich[`a${rank}`] = { fontSize: 16, color, verticalAlign: 'bottom' }
|
rich[`b${rank}`] = { fontSize: 12, color, verticalAlign: 'bottom' }
|
return rich
|
}, {}),
|
},
|
axisLine: { show: false },
|
axisTick: { show: false },
|
splitLine: { show: false },
|
},
|
]
|
})
|
|
// series:背景轨道 + 实色条
|
const series = computed(() => [
|
{
|
name: '背景',
|
z: 5,
|
type: 'bar',
|
barWidth: 18,
|
tooltip: { show: false },
|
itemStyle: {
|
color: 'rgba(143, 163, 200, 0.12)',
|
barBorderRadius: [0, 10, 10, 0],
|
},
|
data: bgData.value,
|
},
|
{
|
name: '金额',
|
z: 6,
|
type: 'bar',
|
barWidth: 18,
|
barGap: '-100%',
|
data: dataNum.value,
|
},
|
])
|
|
// 供应商采购排名
|
const fetchSupplierRanking = () => {
|
supplierPurchaseRanking({ type: radio1.value })
|
.then((res) => {
|
if (res.code === 200 && Array.isArray(res.data) && res.data.length > 0) {
|
dataArr.value = res.data.map((item) => ({
|
NAME: item.supplierName,
|
NUM: Number(item.totalAmount) || 0,
|
}))
|
} else {
|
// 接口无数据时给一组模拟供应商,保证UI可用
|
dataArr.value = [
|
{ NAME: '供应商A', NUM: 102 },
|
{ NAME: '供应商B', NUM: 122 },
|
{ NAME: '供应商C', NUM: 282 },
|
{ NAME: '供应商D', NUM: 453 },
|
{ NAME: '供应商E', NUM: 753 },
|
]
|
}
|
})
|
.catch((error) => {
|
console.error('获取供应商采购排名失败:', error)
|
dataArr.value = [
|
{ NAME: '供应商A', NUM: 102 },
|
{ NAME: '供应商B', NUM: 122 },
|
{ NAME: '供应商C', NUM: 282 },
|
{ NAME: '供应商D', NUM: 453 },
|
{ NAME: '供应商E', NUM: 753 },
|
]
|
})
|
}
|
|
// 处理日期类型切换
|
const handleDateTypeChange = () => {
|
fetchSupplierRanking()
|
}
|
|
onMounted(() => {
|
fetchSupplierRanking()
|
})
|
</script>
|
|
<style scoped>
|
.panel-item-customers {
|
border: 1px solid var(--bi-panel-border);
|
background: var(--bi-panel-bg);
|
border-radius: 8px;
|
padding: 18px;
|
width: 100%;
|
height: 449px;
|
}
|
|
.switch-container {
|
display: flex;
|
justify-content: flex-end;
|
margin-bottom: 16px;
|
}
|
</style>
|