大屏页面初始化

This commit is contained in:
2026-02-27 16:35:00 +08:00
parent ffbaa6e070
commit 7c66b7bab1
3 changed files with 254 additions and 14 deletions

View File

@@ -1,2 +1,239 @@
<template>
</template>
<div class="chart-card">
<div class="chart-card-header">
<span class="chart-card-title">余额结构分析</span>
<span class="total-amount">合计¥{{ formatAmount(totalAmount) }}</span>
</div>
<div class="pie-chart-container" ref="chartRef"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import { getErpAccountList } from '@/api/bizApi'
const vList = ref([])
const totalAmount = ref(0)
const chartRef = ref(null)
let chartInstance = null
const resizeHandler = () => chartInstance?.resize()
const formatAmount = (amount) => {
return Number(amount).toFixed(2)
}
async function getList() {
try {
const res = await getErpAccountList()
vList.value = res || []
calculateTotalAmount(vList.value)
initPieChart()
} catch (error) {
console.error('获取余额数据失败:', error)
vList.value = []
totalAmount.value = 0
}
}
function calculateTotalAmount(data) {
if (!Array.isArray(data)) {
totalAmount.value = 0
return
}
totalAmount.value = data.reduce((sum, item) => {
const value = Number(item.currentBalance) || 0
return sum + value
}, 0)
}
const initPieChart = () => {
const el = chartRef.value
if (!el) return
if (chartInstance) {
chartInstance.dispose()
}
chartInstance = echarts.init(el)
const pieData = vList.value.map(item => ({
name: item.accountName || '未知账户',
value: (Number(item.currentBalance) || 0) / 10000,
originalValue: Number(item.currentBalance) || 0
})).filter(item => item.value > 0)
const colorList = [
'#409EFF', '#36CFc9', '#67C23A', '#E6A23C', '#F56C6C',
'#909399', '#722ED1', '#EB2F96', '#1890FF', '#52C41A',
'#FAAD14', '#F5222D', '#8C8C8C', '#A062D4', '#F7BA1E'
]
const option = {
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(145, 200, 255, 0.9)',
borderColor: '#409EFF',
borderWidth: 1,
textStyle: { color: '#0a3b70', fontSize: 12 },
padding: [10, 15],
borderRadius: 6,
formatter: function(params) {
return `账户:${params.name}<br/>余额:${Number(params.data.originalValue).toFixed(2)}元<br/>占比:${params.percent.toFixed(2)}%`
}
},
legend: {
orient: 'horizontal',
top: '10%',
left: 'center',
textStyle: { fontSize: 11, color: '#e0e6ff' },
itemWidth: 12,
itemHeight: 12,
itemGap: 10,
pageIconColor: '#409EFF',
pageTextStyle: { color: '#e0e6ff', fontSize: 10 },
pageButtonItemGap: 6,
pageButtonGap: 10,
type: 'scroll'
},
series: [
{
name: '余额',
type: 'pie',
radius: ['30%', '55%'],
center: ['50%', '65%'],
avoidLabelOverlap: true,
itemStyle: {
borderRadius: 4,
borderColor: 'rgba(15, 52, 96, 0.9)',
borderWidth: 1
},
label: {
show: true,
position: 'outside',
fontSize: 10,
color: '#e0e6ff',
formatter: function(params) {
return `${params.name} ${Number(params.value).toFixed(2)}万元 (${params.percent.toFixed(2)}%)`
},
overflow: 'truncate',
ellipsis: '...',
distance: 8
},
labelLine: {
show: true,
length: 12,
length2: 8,
lineStyle: { color: '#e0e6ff', width: 1 },
smooth: 0.2,
minTurnAngle: 45
},
data: pieData,
color: colorList
}
]
}
chartInstance.setOption(option)
chartInstance.on('legendselectchanged', (params) => {
const selectedNames = Object.keys(params.selected).filter(name => params.selected[name])
const selectedData = vList.value.filter(item => {
const accountName = item.accountName || '未知账户'
return selectedNames.includes(accountName)
})
calculateTotalAmount(selectedData)
})
}
onMounted(async () => {
await getList()
window.addEventListener('resize', resizeHandler)
})
onUnmounted(() => {
window.removeEventListener('resize', resizeHandler)
if (chartInstance) {
chartInstance.dispose()
chartInstance = null
}
})
</script>
<style scoped>
.chart-card {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.chart-card-header {
height: 40px;
line-height: 40px;
padding: 0 16px;
background-color: rgba(26, 80, 139, 0.5);
border-bottom: 1px solid #1a508b;
display: flex;
align-items: center;
justify-content: space-between;
}
.chart-card-title {
font-size: 16px;
font-weight: 600;
color: #409EFF;
letter-spacing: 0.5px;
}
.total-amount {
font-size: 14px;
color: #e0e6ff;
font-weight: 500;
}
.pie-chart-container {
flex: 1;
width: 100%;
height: calc(100% - 40px);
margin: 0;
padding: 0;
}
:deep(.echarts-tooltip) {
background-color: rgba(145, 200, 255, 0.9) !important;
border-color: #409EFF !important;
color: #0a3b70 !important;
border-radius: 6px !important;
}
:deep(.echarts-legend-scroll) {
background-color: transparent !important;
}
:deep(.echarts-legend-scroll-text) {
color: #e0e6ff !important;
font-size: 11px !important;
}
:deep(.echarts-legend-scroll-button) {
border-color: #1a508b !important;
}
:deep(.echarts-legend-scroll-button-icon) {
color: #409EFF !important;
}
:deep(.ec-label) {
z-index: 9999 !important;
white-space: nowrap !important;
font-size: 10px !important;
color: #e0e6ff !important;
}
:deep(.ec-label-line) {
stroke: #e0e6ff !important;
stroke-width: 1px !important;
}
</style>

View File

@@ -19,16 +19,6 @@
<script setup>
import { ref, watch } from 'vue';
const currentYear = new Date().getFullYear().toString();
const FormValues = ref({
reqParam: currentYear
});
const initApp = (params) =>{
FormValues.value.reqParam = params;
}
const props = defineProps({
formParams: {
type: Object,
@@ -38,9 +28,6 @@ const props = defineProps({
watch(
() => props.formParams,
(newVal) => {
initApp(newVal);
},
{
deep: true,
immediate: true

View File

@@ -69,6 +69,22 @@
</template>
<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
formParams: {
type: Object,
default: () => ({})
}
});
watch(
() => props.formParams,
{
deep: true,
immediate: true
}
);
</script>
<style scoped>