🎈 perf: 图表简单调整
This commit is contained in:
@@ -201,9 +201,9 @@ const handleQuery = () => {
|
||||
|
||||
// 重置按钮点击
|
||||
const handleReset = () => {
|
||||
timeGranularity.value = '';
|
||||
startDate.value = '';
|
||||
endDate.value = '';
|
||||
timeGranularity.value = 'week';
|
||||
startDate.value = new Date().toISOString().split('T')[0] + ' 00:00:00';
|
||||
calculateEndDate();
|
||||
emit('reset');
|
||||
};
|
||||
|
||||
@@ -219,7 +219,7 @@ watch(timeGranularity, (newVal) => {
|
||||
|
||||
// 初始时间设置为今天,触发一次qeury
|
||||
onMounted(() => {
|
||||
startDate.value = new Date().toISOString().split('T')[0] + ' 00:00:00';
|
||||
handleReset();
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
<el-row :gutter="20" class="content-container">
|
||||
<!-- 1. 时间选择区 - 使用封装的组件 -->
|
||||
<el-col :span="24" class="time-filter">
|
||||
<TimeFilter
|
||||
@query="fetchData"
|
||||
@reset="handleFilterReset"
|
||||
@dateChange="handleDateChange"
|
||||
/>
|
||||
<TimeFilter @query="fetchData" @reset="handleFilterReset" @dateChange="handleDateChange" />
|
||||
</el-col>
|
||||
|
||||
<!-- 2. 指标卡区域 -->
|
||||
@@ -36,7 +32,7 @@
|
||||
<el-col :span="6">
|
||||
<el-card class="indicator-card net-cashflow">
|
||||
<div class="card-header">
|
||||
<span>净现金流</span>
|
||||
<span>净收益</span>
|
||||
<i class="el-icon-refresh"></i>
|
||||
</div>
|
||||
<div class="card-value">{{ netCashflow | formatCurrency }}</div>
|
||||
@@ -60,7 +56,7 @@
|
||||
<el-col :span="24" class="charts-container">
|
||||
<!-- 收入支出趋势图 -->
|
||||
<el-row :gutter="20" class="chart-row">
|
||||
<el-col :span="24">
|
||||
<el-col :span="12">
|
||||
<el-card class="chart-card">
|
||||
<div slot="header" class="chart-header">
|
||||
<span>收入支出趋势</span>
|
||||
@@ -70,6 +66,16 @@
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card class="chart-card">
|
||||
<div slot="header" class="chart-header">
|
||||
<span>按供应商区分的支出</span>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div ref="supplierChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 按订单和客户/供应商分析 -->
|
||||
@@ -95,19 +101,6 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="chart-row">
|
||||
<el-col :span="24">
|
||||
<el-card class="chart-card">
|
||||
<div slot="header" class="chart-header">
|
||||
<span>按供应商区分的支出</span>
|
||||
</div>
|
||||
<div class="chart-content">
|
||||
<div ref="supplierChart" class="chart-wrapper"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
<!-- 4. 回款(应收未收)任务信息表格 -->
|
||||
@@ -116,80 +109,25 @@
|
||||
<div slot="header" class="table-header">
|
||||
<span>回款(应收未收)任务信息</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="receivableTasks"
|
||||
border
|
||||
style="width: 100%"
|
||||
v-loading="tableLoading"
|
||||
>
|
||||
<el-table-column
|
||||
prop="receivableId"
|
||||
label="应收ID"
|
||||
width="180"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="customerName"
|
||||
label="客户名称"
|
||||
width="150"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="orderId"
|
||||
label="订单ID"
|
||||
width="180"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="dueDate"
|
||||
label="到期日期"
|
||||
width="150"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="amount"
|
||||
label="总金额"
|
||||
width="120"
|
||||
align="center"
|
||||
:formatter="formatCurrency"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="paidAmount"
|
||||
label="已付金额"
|
||||
width="120"
|
||||
align="center"
|
||||
:formatter="formatCurrency"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="balanceAmount"
|
||||
label="未付金额"
|
||||
width="120"
|
||||
align="center"
|
||||
:formatter="formatCurrency"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="状态"
|
||||
width="100"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="备注"
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table :data="receivableTasks" border style="width: 100%" v-loading="tableLoading">
|
||||
<el-table-column prop="receivableId" label="应收ID" width="180" align="center"></el-table-column>
|
||||
<el-table-column prop="customerName" label="客户名称" width="150" align="center"></el-table-column>
|
||||
<el-table-column prop="orderId" label="订单ID" width="180" align="center"></el-table-column>
|
||||
<el-table-column prop="dueDate" label="到期日期" width="150" align="center"></el-table-column>
|
||||
<el-table-column prop="amount" label="总金额" width="120" align="center"
|
||||
:formatter="formatCurrency"></el-table-column>
|
||||
<el-table-column prop="paidAmount" label="已付金额" width="120" align="center"
|
||||
:formatter="formatCurrency"></el-table-column>
|
||||
<el-table-column prop="balanceAmount" label="未付金额" width="120" align="center"
|
||||
:formatter="formatCurrency"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" align="center"></el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="receivableTotal"
|
||||
></el-pagination>
|
||||
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
|
||||
:current-page="currentPage" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="receivableTotal"></el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -252,7 +190,7 @@ const initCharts = () => {
|
||||
if (supplierChart.value) {
|
||||
supplierChartInstance.value = echarts.init(supplierChart.value);
|
||||
}
|
||||
|
||||
|
||||
// 监听窗口大小变化,调整图表
|
||||
window.addEventListener('resize', () => {
|
||||
trendChartInstance.value?.resize();
|
||||
@@ -266,21 +204,21 @@ const initCharts = () => {
|
||||
const fetchData = async (timeParams) => {
|
||||
tableLoading.value = true;
|
||||
currentTimeParams.value = timeParams || currentTimeParams.value;
|
||||
|
||||
|
||||
try {
|
||||
// 获取应收数据
|
||||
const receivableRes = await listReceivable({ pageSize: 9999, pageNum: 1 });
|
||||
receivableData.value = receivableRes.rows || [];
|
||||
receivableTasks.value = receivableData.value.filter(item => item.status === '未结清');
|
||||
receivableTotal.value = receivableRes.total || 0;
|
||||
|
||||
|
||||
// 获取应付数据
|
||||
const payableRes = await listPayable({ pageSize: 9999, pageNum: 1 });
|
||||
payableData.value = payableRes.rows || [];
|
||||
|
||||
|
||||
// 处理数据并更新指标
|
||||
processData();
|
||||
|
||||
|
||||
// 更新图表
|
||||
updateCharts();
|
||||
} catch (error) {
|
||||
@@ -297,15 +235,15 @@ const processData = () => {
|
||||
totalIncome.value = receivableData.value.reduce((sum, item) => {
|
||||
return sum + parseFloat(item.amount || 0);
|
||||
}, 0);
|
||||
|
||||
|
||||
// 计算总支出(应付金额总和)
|
||||
totalExpense.value = payableData.value.reduce((sum, item) => {
|
||||
return sum + parseFloat(item.amount || 0);
|
||||
}, 0);
|
||||
|
||||
|
||||
// 计算净现金流
|
||||
netCashflow.value = totalIncome.value - totalExpense.value;
|
||||
|
||||
|
||||
// 计算未结清应收总额和数量
|
||||
const outstanding = receivableData.value.filter(item => item.status === '未结清');
|
||||
outstandingReceivable.value = outstanding.reduce((sum, item) => {
|
||||
@@ -326,12 +264,12 @@ const updateCharts = () => {
|
||||
const updateTrendChart = () => {
|
||||
// 按时间粒度处理数据
|
||||
const timeGroups = groupDataByTime();
|
||||
|
||||
|
||||
// 准备图表数据
|
||||
const xAxisData = Object.keys(timeGroups);
|
||||
const incomeData = xAxisData.map(key => timeGroups[key].income);
|
||||
const expenseData = xAxisData.map(key => timeGroups[key].expense);
|
||||
|
||||
|
||||
// 设置图表配置
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -391,7 +329,7 @@ const updateTrendChart = () => {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
trendChartInstance.value.setOption(option);
|
||||
};
|
||||
|
||||
@@ -399,7 +337,7 @@ const updateTrendChart = () => {
|
||||
const updateOrderChart = () => {
|
||||
// 按订单ID合并数据
|
||||
const orderMap = {};
|
||||
|
||||
|
||||
// 处理应收数据
|
||||
receivableData.value.forEach(item => {
|
||||
if (!orderMap[item.orderId]) {
|
||||
@@ -410,7 +348,7 @@ const updateOrderChart = () => {
|
||||
}
|
||||
orderMap[item.orderId].income += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 处理应付数据
|
||||
payableData.value.forEach(item => {
|
||||
if (!orderMap[item.orderId]) {
|
||||
@@ -421,7 +359,7 @@ const updateOrderChart = () => {
|
||||
}
|
||||
orderMap[item.orderId].expense += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 转换为图表数据
|
||||
const orderList = Object.entries(orderMap)
|
||||
.map(([orderId, data]) => ({
|
||||
@@ -432,11 +370,11 @@ const updateOrderChart = () => {
|
||||
}))
|
||||
.sort((a, b) => b.net - a.net)
|
||||
.slice(0, 10); // 只展示前10个订单
|
||||
|
||||
|
||||
const xAxisData = orderList.map(item => `订单 ${item.orderId.slice(-6)}`);
|
||||
const incomeData = orderList.map(item => item.income);
|
||||
const expenseData = orderList.map(item => item.expense);
|
||||
|
||||
|
||||
// 设置图表配置
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -494,7 +432,7 @@ const updateOrderChart = () => {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
orderChartInstance.value.setOption(option);
|
||||
};
|
||||
|
||||
@@ -502,7 +440,7 @@ const updateOrderChart = () => {
|
||||
const updateCustomerChart = () => {
|
||||
// 按客户分组计算收入
|
||||
const customerMap = {};
|
||||
|
||||
|
||||
receivableData.value.forEach(item => {
|
||||
if (!customerMap[item.customerId]) {
|
||||
customerMap[item.customerId] = {
|
||||
@@ -512,12 +450,12 @@ const updateCustomerChart = () => {
|
||||
}
|
||||
customerMap[item.customerId].amount += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 转换为图表数据并排序
|
||||
const customerList = Object.values(customerMap)
|
||||
.sort((a, b) => b.amount - a.amount)
|
||||
.slice(0, 10); // 只展示前10个客户
|
||||
|
||||
|
||||
// 设置图表配置
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -560,7 +498,7 @@ const updateCustomerChart = () => {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
customerChartInstance.value.setOption(option);
|
||||
};
|
||||
|
||||
@@ -568,7 +506,7 @@ const updateCustomerChart = () => {
|
||||
const updateSupplierChart = () => {
|
||||
// 按供应商分组计算支出
|
||||
const supplierMap = {};
|
||||
|
||||
|
||||
payableData.value.forEach(item => {
|
||||
if (!supplierMap[item.supplierId]) {
|
||||
supplierMap[item.supplierId] = {
|
||||
@@ -578,12 +516,12 @@ const updateSupplierChart = () => {
|
||||
}
|
||||
supplierMap[item.supplierId].amount += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 转换为图表数据并排序
|
||||
const supplierList = Object.values(supplierMap)
|
||||
.sort((a, b) => b.amount - a.amount)
|
||||
.slice(0, 10); // 只展示前10个供应商
|
||||
|
||||
|
||||
// 设置图表配置
|
||||
const option = {
|
||||
tooltip: {
|
||||
@@ -623,7 +561,7 @@ const updateSupplierChart = () => {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
supplierChartInstance.value.setOption(option);
|
||||
};
|
||||
|
||||
@@ -631,37 +569,37 @@ const updateSupplierChart = () => {
|
||||
const groupDataByTime = () => {
|
||||
const timeGroups = {};
|
||||
const granularity = currentTimeParams.value.timeGranularity || 'month';
|
||||
|
||||
|
||||
// 处理应收数据
|
||||
receivableData.value.forEach(item => {
|
||||
const date = new Date(item.dueDate);
|
||||
const timeKey = getTimeKey(date, granularity);
|
||||
|
||||
|
||||
if (!timeGroups[timeKey]) {
|
||||
timeGroups[timeKey] = {
|
||||
income: 0,
|
||||
expense: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
timeGroups[timeKey].income += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 处理应付数据
|
||||
payableData.value.forEach(item => {
|
||||
const date = new Date(item.dueDate);
|
||||
const timeKey = getTimeKey(date, granularity);
|
||||
|
||||
|
||||
if (!timeGroups[timeKey]) {
|
||||
timeGroups[timeKey] = {
|
||||
income: 0,
|
||||
expense: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
timeGroups[timeKey].expense += parseFloat(item.amount || 0);
|
||||
});
|
||||
|
||||
|
||||
// 排序时间分组
|
||||
return Object.keys(timeGroups).sort().reduce((obj, key) => {
|
||||
obj[key] = timeGroups[key];
|
||||
@@ -673,7 +611,7 @@ const groupDataByTime = () => {
|
||||
const getTimeKey = (date, granularity) => {
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
|
||||
|
||||
if (granularity === 'year') {
|
||||
return `${year}`;
|
||||
} else if (granularity === 'month') {
|
||||
@@ -719,14 +657,14 @@ const handleFilterReset = () => {
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 20px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
color: #1f2d3d;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
color: #8392a5;
|
||||
@@ -735,51 +673,51 @@ const handleFilterReset = () => {
|
||||
|
||||
.content-container {
|
||||
.time-filter {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.indicator-cards {
|
||||
margin-bottom: 20px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
.indicator-card {
|
||||
height: 100%;
|
||||
padding: 15px;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 5px;
|
||||
color: #8392a5;
|
||||
font-size: 14px;
|
||||
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.card-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
|
||||
|
||||
.card-desc {
|
||||
font-size: 12px;
|
||||
color: #8392a5;
|
||||
|
||||
|
||||
.rise {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
|
||||
.drop {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -791,70 +729,70 @@ const handleFilterReset = () => {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.total-income {
|
||||
&::after {
|
||||
background-color: #4e79a7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.total-expense {
|
||||
&::after {
|
||||
background-color: #e15759;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.net-cashflow {
|
||||
&::after {
|
||||
background-color: #59a14f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.outstanding-receivable {
|
||||
&::after {
|
||||
background-color: #9c755f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.charts-container {
|
||||
margin-bottom: 20px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
.chart-row {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.chart-card {
|
||||
height: 100%;
|
||||
|
||||
|
||||
.chart-header {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1f2d3d;
|
||||
padding: 15px 20px;
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
.chart-content {
|
||||
padding: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
.chart-wrapper {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.table-container {
|
||||
.table-header {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1f2d3d;
|
||||
padding: 15px 20px;
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 15px;
|
||||
text-align: right;
|
||||
@@ -874,12 +812,14 @@ const handleFilterReset = () => {
|
||||
@media (max-width: 992px) {
|
||||
.indicator-cards {
|
||||
.el-col {
|
||||
&:nth-child(1), &:nth-child(2) {
|
||||
|
||||
&:nth-child(1),
|
||||
&:nth-child(2) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.charts-container {
|
||||
.chart-row {
|
||||
.el-col {
|
||||
@@ -888,7 +828,7 @@ const handleFilterReset = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.chart-wrapper {
|
||||
height: 300px;
|
||||
}
|
||||
@@ -903,7 +843,7 @@ const handleFilterReset = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.charts-container {
|
||||
.chart-wrapper {
|
||||
height: 250px;
|
||||
|
||||
Reference in New Issue
Block a user