新增前端vue
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
<template>
|
||||
<Card title="账户汇总图" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<template #extra>
|
||||
<BasicForm
|
||||
:labelWidth="100"
|
||||
:schemas="schemas"
|
||||
:initialValues="defaultFormValues"
|
||||
@submit="handleFormSubmit"
|
||||
style="width: 200px;"
|
||||
/>
|
||||
</template>
|
||||
<div ref="chartDom" style="width: 100%; height: 300px;"></div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { BasicForm, FormSchema } from '@jeesite/core/components/Form';
|
||||
import { erpExpIncListAll, ErpExpInc } from '@jeesite/erp/api/erp/expInc';
|
||||
import * as echarts from 'echarts';
|
||||
import type {
|
||||
ECharts,
|
||||
EChartsOption,
|
||||
SeriesOption,
|
||||
BarSeriesOption
|
||||
} from 'echarts';
|
||||
|
||||
// 表单默认值
|
||||
const defaultFormValues = ref({
|
||||
cycleType: 'M'
|
||||
});
|
||||
|
||||
// 表单配置
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
label: '周期',
|
||||
field: 'cycleType',
|
||||
defaultValue: defaultFormValues.value.cycleType,
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
dictType: 'report_cycle',
|
||||
allowClear: true,
|
||||
onChange: (value: string) => {
|
||||
defaultFormValues.value.cycleType = value;
|
||||
fetchList({ cycleType: value });
|
||||
}
|
||||
},
|
||||
colProps: { md: 24, lg: 24 },
|
||||
},
|
||||
];
|
||||
|
||||
// 图表DOM引用
|
||||
const chartDom = ref<HTMLDivElement | null>(null);
|
||||
// 图表实例
|
||||
let myChart: ECharts | null = null;
|
||||
// 数据列表
|
||||
const tableData = ref<ErpExpInc[]>([]);
|
||||
// 加载状态
|
||||
const loading = ref(false);
|
||||
|
||||
/**
|
||||
* 单位转换:元转万元(除以10000)
|
||||
*/
|
||||
const convertToTenThousand = (num: number): number => {
|
||||
if (isNaN(num) || num === null || num === undefined) return 0;
|
||||
return num / 10000;
|
||||
};
|
||||
|
||||
/**
|
||||
* 单位转换:万元转元(乘以10000)- 用于Tooltip显示
|
||||
*/
|
||||
const convertToYuan = (num: number): number => {
|
||||
if (isNaN(num) || num === null || num === undefined) return 0;
|
||||
return num * 10000;
|
||||
};
|
||||
|
||||
/**
|
||||
* 日期排序工具:支持2025-Q1、2024-12等格式排序
|
||||
* @param dates 日期数组
|
||||
* @returns 排序后的日期数组(升序)
|
||||
*/
|
||||
const sortDates = (dates: string[]): string[] => {
|
||||
return dates.sort((a, b) => {
|
||||
// 解析日期格式:2025-Q1 → [2025, 1];2024-12 → [2024, 12]
|
||||
const parseDate = (dateStr: string) => {
|
||||
const [year, part] = dateStr.split(/[-Q]/);
|
||||
const quarterOrMonth = part ? parseInt(part) : 1;
|
||||
return { year: parseInt(year), quarterOrMonth };
|
||||
};
|
||||
|
||||
const dateA = parseDate(a);
|
||||
const dateB = parseDate(b);
|
||||
|
||||
// 先比较年份
|
||||
if (dateA.year !== dateB.year) {
|
||||
return dateA.year - dateB.year;
|
||||
}
|
||||
// 年份相同比较季度/月份
|
||||
return dateA.quarterOrMonth - dateB.quarterOrMonth;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取数据列表 - 增加类型约束和加载状态
|
||||
*/
|
||||
const fetchList = async (params: { cycleType?: string }) => {
|
||||
if (loading.value) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const cycleType = params.cycleType || defaultFormValues.value.cycleType;
|
||||
const result = await erpExpIncListAll({ cycleType });
|
||||
tableData.value = result || [];
|
||||
initChart();
|
||||
} catch (error) {
|
||||
console.error('获取数据列表失败:', error);
|
||||
tableData.value = [];
|
||||
if (myChart) {
|
||||
myChart.clear();
|
||||
showEmptyChart();
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 工具函数:保留2位小数(处理0值和整数,统一格式)
|
||||
*/
|
||||
const formatNumber = (num: number): string => {
|
||||
if (isNaN(num) || num === null || num === undefined) return '0.00';
|
||||
return num.toFixed(2);
|
||||
};
|
||||
|
||||
/**
|
||||
* 基础柱状图配置 - 增加圆角效果
|
||||
*/
|
||||
const baseBarConfig: BarSeriesOption = {
|
||||
type: 'bar',
|
||||
barWidth: 25, // 加宽柱子,适配总值显示
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
fontSize: 10,
|
||||
color: '#333',
|
||||
formatter: function(params: any) {
|
||||
// 多层校验,确保数值安全
|
||||
let value = 0;
|
||||
if (params && params.value !== undefined && params.value !== null) {
|
||||
value = typeof params.value === 'number' ? params.value : Number(params.value);
|
||||
}
|
||||
// 只有正数才显示标签,显示万元数值
|
||||
return value > 0 ? formatNumber(value) : '';
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
borderType: 'solid',
|
||||
// 圆角配置:四个角都设置圆角,数值越大越圆润(建议值:8-15,根据barWidth调整)
|
||||
borderRadius: [8, 8, 0, 0], // 上左、上右、下右、下左(只给顶部圆角,更符合视觉习惯)
|
||||
// 可选:添加轻微阴影增强立体感
|
||||
shadowBlur: 3,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowOffsetY: 2
|
||||
},
|
||||
legendHoverLink: false,
|
||||
animationDuration: 500,
|
||||
animationEasing: 'cubicOut'
|
||||
};
|
||||
|
||||
/**
|
||||
* 显示空数据图表
|
||||
*/
|
||||
const showEmptyChart = () => {
|
||||
if (!myChart) return;
|
||||
|
||||
const emptyOption: EChartsOption = {
|
||||
title: {
|
||||
text: '暂无数据',
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
textStyle: { fontSize: 16, color: '#999' }
|
||||
},
|
||||
xAxis: { type: 'category', data: [] },
|
||||
yAxis: { type: 'value', name: '金额(万元)' },
|
||||
series: [],
|
||||
tooltip: { trigger: 'none' }
|
||||
};
|
||||
|
||||
myChart.setOption(emptyOption);
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理数据表,生成ECharts所需结构(X轴为银行名称,展示最新周期数据)
|
||||
*/
|
||||
const processTableData = () => {
|
||||
// 过滤有效数据
|
||||
const validData = tableData.value.filter(item =>
|
||||
item?.statDate && item?.accountName && (item.incomeAmount || item.expenseAmount)
|
||||
);
|
||||
|
||||
if (validData.length === 0) {
|
||||
return { accountNames: [], series: [], bankDetailMap: {}, latestDate: '' };
|
||||
}
|
||||
|
||||
// 1. 获取所有日期并排序(支持季度/月份格式)
|
||||
const allDates = Array.from(new Set(validData.map(item => item.statDate!)));
|
||||
const sortedDates = sortDates(allDates);
|
||||
// 最新周期
|
||||
const latestDate = sortedDates[sortedDates.length - 1];
|
||||
|
||||
// 2. 按银行分组,汇总最新周期数据 + 保存所有周期明细
|
||||
const bankDetailMap: Record<string, Record<string, { income: number; expense: number }>> = {};
|
||||
const latestIncomeMap: Record<string, number> = {};
|
||||
const latestExpenseMap: Record<string, number> = {};
|
||||
|
||||
validData.forEach(item => {
|
||||
const accountName = item.accountName!;
|
||||
const statDate = item.statDate!;
|
||||
const incomeAmount = convertToTenThousand(Number(item.incomeAmount) || 0);
|
||||
const expenseAmount = convertToTenThousand(Number(item.expenseAmount) || 0);
|
||||
|
||||
// 初始化银行明细
|
||||
if (!bankDetailMap[accountName]) {
|
||||
bankDetailMap[accountName] = {};
|
||||
latestIncomeMap[accountName] = 0;
|
||||
latestExpenseMap[accountName] = 0;
|
||||
}
|
||||
|
||||
// 保存该周期明细
|
||||
bankDetailMap[accountName][statDate] = { income: incomeAmount, expense: expenseAmount };
|
||||
|
||||
// 累加最新周期数据
|
||||
if (statDate === latestDate) {
|
||||
latestIncomeMap[accountName] += incomeAmount;
|
||||
latestExpenseMap[accountName] += expenseAmount;
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 获取所有银行名称
|
||||
const accountNames = Array.from(new Set(Object.keys(bankDetailMap))).filter(Boolean);
|
||||
|
||||
// 4. 生成系列数据(收入和支出两个系列,展示最新周期数据)
|
||||
const incomeSeries: BarSeriesOption = {
|
||||
...baseBarConfig,
|
||||
name: '收入',
|
||||
data: accountNames.map(name => latestIncomeMap[name] || 0),
|
||||
itemStyle: {
|
||||
...baseBarConfig.itemStyle,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#73d13d' },
|
||||
{ offset: 1, color: '#52c41a' }
|
||||
])
|
||||
},
|
||||
label: {
|
||||
...baseBarConfig.label,
|
||||
color: '#52c41a'
|
||||
}
|
||||
};
|
||||
|
||||
const expenseSeries: BarSeriesOption = {
|
||||
...baseBarConfig,
|
||||
name: '支出',
|
||||
data: accountNames.map(name => latestExpenseMap[name] || 0),
|
||||
itemStyle: {
|
||||
...baseBarConfig.itemStyle,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#ff4d4f' },
|
||||
{ offset: 1, color: '#f5222d' }
|
||||
])
|
||||
},
|
||||
label: {
|
||||
...baseBarConfig.label,
|
||||
color: '#f5222d'
|
||||
}
|
||||
};
|
||||
|
||||
const series: SeriesOption[] = [incomeSeries, expenseSeries];
|
||||
return {
|
||||
accountNames,
|
||||
series,
|
||||
bankDetailMap,
|
||||
latestDate,
|
||||
sortedDates
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化图表(X轴为银行名称,Tooltip展示月度明细)
|
||||
*/
|
||||
const initChart = () => {
|
||||
if (!chartDom.value) return;
|
||||
|
||||
// 销毁旧实例
|
||||
if (myChart) {
|
||||
myChart.dispose();
|
||||
myChart = null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建新实例
|
||||
myChart = echarts.init(chartDom.value);
|
||||
|
||||
const { accountNames, series, bankDetailMap, latestDate, sortedDates } = processTableData();
|
||||
|
||||
// 空数据处理
|
||||
if (accountNames.length === 0) {
|
||||
showEmptyChart();
|
||||
return;
|
||||
}
|
||||
|
||||
const option: EChartsOption = {
|
||||
title: {
|
||||
left: 'center',
|
||||
textStyle: { fontSize: 16, color: '#333' }
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'shadow' },
|
||||
textStyle: { fontSize: 12 },
|
||||
padding: [10, 15],
|
||||
formatter: function(params: any) {
|
||||
if (!params || params.length === 0) return '';
|
||||
// 获取当前银行名称
|
||||
const bankName = params[0]?.axisValue || '';
|
||||
const bankDetails = bankDetailMap[bankName] || {};
|
||||
|
||||
// 生成各周期明细行
|
||||
let cycleRows = '';
|
||||
sortedDates.forEach(date => {
|
||||
const detail = bankDetails[date] || { income: 0, expense: 0 };
|
||||
const incomeYuan = convertToYuan(detail.income);
|
||||
const expenseYuan = convertToYuan(detail.expense);
|
||||
|
||||
if (incomeYuan > 0 || expenseYuan > 0) {
|
||||
cycleRows += `
|
||||
<div style="display: flex; justify-content: space-between; margin: 4px 0;">
|
||||
<span style="display: flex; align-items: center;">
|
||||
<span style="display: inline-block; width: 8px; height: 8px; background: ${incomeYuan > 0 ? '#52c41a' : '#f5222d'}; border-radius: 2px; margin-right: 6px;"></span>
|
||||
${date}
|
||||
</span>
|
||||
<span style="display: flex; gap: 15px;">
|
||||
<span style="color: #52c41a;">收入:${formatNumber(incomeYuan)} </span>
|
||||
<span style="color: #f5222d;">支出:${formatNumber(expenseYuan)} </span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
// 计算最新周期汇总
|
||||
const latestDetail = bankDetails[latestDate] || { income: 0, expense: 0 };
|
||||
const latestIncome = convertToYuan(latestDetail.income);
|
||||
const latestExpense = convertToYuan(latestDetail.expense);
|
||||
const netIncome = latestIncome - latestExpense;
|
||||
|
||||
return `
|
||||
<div style="font-weight: 600; margin-bottom: 8px;">${bankName}</div>
|
||||
${cycleRows}
|
||||
<div style="border-top: 1px solid #eee; margin: 8px 0; padding-top: 8px; display: flex; justify-content: space-between; font-weight: 600;">
|
||||
<span>本期总收入:</span>
|
||||
<span style="display: flex; gap: 15px;">
|
||||
<span style="color: #52c41a;">收入:${formatNumber(latestIncome)} 元</span>
|
||||
<span style="color: #f5222d;">支出:${formatNumber(latestExpense)} 元</span>
|
||||
</span>
|
||||
</div>
|
||||
<div style="text-align: left; color: #333; font-weight: 600;">
|
||||
本期净收入:${formatNumber(netIncome)} 元
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['收入', '支出'],
|
||||
top: 10,
|
||||
left: 'center',
|
||||
orient: 'horizontal',
|
||||
textStyle: { fontSize: 12, color: '#333' },
|
||||
itemWidth: 12,
|
||||
itemHeight: 12,
|
||||
itemGap: 20
|
||||
},
|
||||
grid: {
|
||||
left: '5%',
|
||||
right: '5%',
|
||||
bottom: '15%',
|
||||
top: '20%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: accountNames,
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
rotate: 15, // 银行名称旋转15度,避免重叠
|
||||
interval: 0
|
||||
},
|
||||
axisTick: { inside: true },
|
||||
axisLine: { onZero: true }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '金额(万元)',
|
||||
min: 0,
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
formatter: (value: any) => `${formatNumber(Number(value))} 万元`
|
||||
},
|
||||
splitLine: { lineStyle: { color: '#f0f0f0' } },
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
max: (value: { max: number }) => value.max > 0 ? value.max * 1.15 : 0.1
|
||||
},
|
||||
series: series,
|
||||
responsive: true,
|
||||
// 取消堆叠模式,改为分组显示
|
||||
barGap: '20%',
|
||||
barCategoryGap: '30%'
|
||||
};
|
||||
|
||||
myChart.setOption(option);
|
||||
} catch (error) {
|
||||
console.error('初始化图表失败:', error);
|
||||
showEmptyChart();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理表单提交
|
||||
*/
|
||||
const handleFormSubmit = (values: { cycleType?: string }) => {
|
||||
if (values.cycleType) {
|
||||
fetchList({ cycleType: values.cycleType });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 窗口缩放自适应
|
||||
*/
|
||||
const resizeChart = () => {
|
||||
if (myChart) {
|
||||
clearTimeout((window as any).chartResizeTimer);
|
||||
(window as any).chartResizeTimer = setTimeout(() => {
|
||||
myChart?.resize();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// 监听数据变化自动更新图表
|
||||
watch(tableData, () => {
|
||||
if (!loading.value) {
|
||||
initChart();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
fetchList({});
|
||||
window.addEventListener('resize', resizeChart);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', resizeChart);
|
||||
if (myChart) {
|
||||
myChart.dispose();
|
||||
myChart = null;
|
||||
}
|
||||
clearTimeout((window as any).chartResizeTimer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-card) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 图例颜色 */
|
||||
:deep(.echarts-legend-item:nth-child(1) .echarts-legend-symbol) {
|
||||
background-color: #52c41a !important;
|
||||
border-radius: 4px; /* 图例也添加圆角,保持风格统一 */
|
||||
}
|
||||
:deep(.echarts-legend-item:nth-child(2) .echarts-legend-symbol) {
|
||||
background-color: #f5222d !important;
|
||||
border-radius: 4px; /* 图例也添加圆角,保持风格统一 */
|
||||
}
|
||||
|
||||
/* Tooltip样式 */
|
||||
:deep(.echarts-tooltip) {
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.15);
|
||||
border: none;
|
||||
background: #fff;
|
||||
z-index: 9999 !important;
|
||||
max-width: 400px; /* 限制Tooltip宽度,避免过宽 */
|
||||
}
|
||||
|
||||
/* 优化标签显示效果 */
|
||||
:deep(.echarts-bar-label) {
|
||||
font-weight: 500;
|
||||
text-shadow: 0 1px 1px rgba(255,255,255,0.8);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 优化x轴标签显示 */
|
||||
:deep(.echarts-xaxis-label) {
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Card title="银行收支汇总图" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<Card title="周期汇总图" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<template #extra>
|
||||
<BasicForm
|
||||
:labelWidth="100"
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Card title="交易收支柱线图" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<Card title="交易柱线图" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<template #extra>
|
||||
<BasicForm
|
||||
:labelWidth="100"
|
||||
@@ -12,7 +12,6 @@
|
||||
<div ref="chartDom" style="width: 100%; height: 300px;"></div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
@@ -74,7 +73,12 @@ const formatNumber = (num: number | undefined, decimal = 2): number => {
|
||||
return Number(num.toFixed(decimal));
|
||||
};
|
||||
|
||||
// 柱状图标签配置(保留2位小数)
|
||||
// 转换为万元(保留2位小数)
|
||||
const toTenThousandYuan = (num: number | undefined): number => {
|
||||
return formatNumber((num || 0) / 10000);
|
||||
};
|
||||
|
||||
// 柱状图标签配置(显示万元)
|
||||
const barLabelConfig = {
|
||||
show: true,
|
||||
position: 'top',
|
||||
@@ -84,7 +88,7 @@ const barLabelConfig = {
|
||||
color: '#333',
|
||||
fontWeight: '500'
|
||||
},
|
||||
formatter: (params: any) => `${formatNumber(params.value).toFixed(2)} 元`
|
||||
formatter: (params: any) => `${formatNumber(params.value).toFixed(2)} 万元`
|
||||
};
|
||||
|
||||
// 折线图标签配置(保留2位小数)
|
||||
@@ -165,9 +169,9 @@ const initChart = () => {
|
||||
? listSummary.value.map(item => item.cdate || '')
|
||||
: [];
|
||||
|
||||
// 提取金额数据用于计算Y轴范围(保留2位小数)
|
||||
const thisValueData = listSummary.value.map(item => formatNumber(item.thisValue));
|
||||
const prevValueData = listSummary.value.map(item => formatNumber(item.prevValue));
|
||||
// 提取金额数据(转换为万元)用于计算Y轴范围
|
||||
const thisValueData = listSummary.value.map(item => toTenThousandYuan(item.thisValue));
|
||||
const prevValueData = listSummary.value.map(item => toTenThousandYuan(item.prevValue));
|
||||
const amountData = [...thisValueData, ...prevValueData];
|
||||
const [amountMin, amountMax] = calculateYAxisExtent(amountData);
|
||||
|
||||
@@ -175,6 +179,10 @@ const initChart = () => {
|
||||
const rateData = listSummary.value.map(item => formatNumber(item.momRate));
|
||||
const [rateMin, rateMax] = calculateYAxisExtent(rateData, true);
|
||||
|
||||
// 原始金额数据(用于tooltip显示元)
|
||||
const rawThisValueData = listSummary.value.map(item => formatNumber(item.thisValue));
|
||||
const rawPrevValueData = listSummary.value.map(item => formatNumber(item.prevValue));
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
left: 'center',
|
||||
@@ -186,10 +194,20 @@ const initChart = () => {
|
||||
textStyle: { fontSize: 12 },
|
||||
formatter: (params: any[]) => {
|
||||
let res = params[0].axisValue;
|
||||
params.forEach((param) => {
|
||||
const value = formatNumber(param.value).toFixed(2);
|
||||
const unit = param.seriesName === '环比' ? ' %' : ' 元';
|
||||
res += `<br/>${param.marker}${param.seriesName}:${value}${unit}`;
|
||||
params.forEach((param, index) => {
|
||||
// 区分金额和环比:金额显示原始元,环比显示百分比
|
||||
let value = param.value;
|
||||
let unit = ' 元';
|
||||
|
||||
if (param.seriesName === '环比') {
|
||||
value = formatNumber(param.value);
|
||||
unit = ' %';
|
||||
} else {
|
||||
// 还原为原始元数值(图表展示的是万元,需要乘10000)
|
||||
value = formatNumber(param.value * 10000);
|
||||
}
|
||||
|
||||
res += `<br/>${param.marker}${param.seriesName}:${value.toFixed(2)}${unit}`;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
@@ -218,7 +236,7 @@ const initChart = () => {
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '交易金额(元)',
|
||||
name: '交易金额(万元)', // Y轴名称改为万元
|
||||
axisLabel: {
|
||||
fontSize: 12,
|
||||
formatter: (value: number) => formatNumber(value).toFixed(2)
|
||||
@@ -264,7 +282,7 @@ const initChart = () => {
|
||||
{
|
||||
name: '本期金额',
|
||||
type: 'bar',
|
||||
data: thisValueData,
|
||||
data: thisValueData, // 展示万元数据
|
||||
itemStyle: {
|
||||
color: '#1890ff',
|
||||
borderRadius: [8, 8, 0, 0]
|
||||
@@ -272,12 +290,14 @@ const initChart = () => {
|
||||
barWidth: 25,
|
||||
barBorderRadius: [8, 8, 0, 0],
|
||||
label: barLabelConfig,
|
||||
yAxisIndex: 0
|
||||
yAxisIndex: 0,
|
||||
// 存储原始元数据用于tooltip
|
||||
rawData: rawThisValueData
|
||||
},
|
||||
{
|
||||
name: '上期金额',
|
||||
type: 'bar',
|
||||
data: prevValueData,
|
||||
data: prevValueData, // 展示万元数据
|
||||
itemStyle: {
|
||||
color: '#52c41a',
|
||||
borderRadius: [8, 8, 0, 0]
|
||||
@@ -285,7 +305,9 @@ const initChart = () => {
|
||||
barWidth: 25,
|
||||
barBorderRadius: [8, 8, 0, 0],
|
||||
label: barLabelConfig,
|
||||
yAxisIndex: 0
|
||||
yAxisIndex: 0,
|
||||
// 存储原始元数据用于tooltip
|
||||
rawData: rawPrevValueData
|
||||
},
|
||||
{
|
||||
name: '环比',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Card title="银行账户余额占比" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<Card title="账户余额占比" style="width: 100%; height: 400px; margin: 4px 0;">
|
||||
<div ref="chartDom" style="width: 100%; height: 300px;"></div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
<div class="dashboard-container">
|
||||
<div class="two-column-layout">
|
||||
<ChartPie />
|
||||
<ChartBar />
|
||||
<ChartLine />
|
||||
</div>
|
||||
<div class="two-column-layout">
|
||||
<ChartBarCycle />
|
||||
<ChartBarAccount />
|
||||
</div>
|
||||
<ChartLine class="chart-line-wrapper" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
|
||||
import ChartBar from './components/ChartBar.vue';
|
||||
import ChartPie from './components/ChartPie.vue';
|
||||
import ChartLine from './components/ChartLine.vue';
|
||||
import ChartBarCycle from './components/ChartBarCycle.vue';
|
||||
import ChartBarAccount from './components/ChartBarAccount.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-container {
|
||||
padding: 0 8px;
|
||||
|
||||
Reference in New Issue
Block a user