Files
im-uniapp/pages/workbench/cost/cost.vue
2025-10-13 17:51:27 +08:00

289 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 加载状态 -->
<view v-if="loading" class="loading-view">
<uni-loading-icon size="24" color="#007aff"></uni-loading-icon>
<text class="loading-text">加载中...</text>
</view>
<!-- 内容区域加载完成后显示 -->
<view v-else>
<!-- 月份选择 -->
<view class="date-picker-container">
<picker mode="date" @change="onDateChange" fields="month" :value="currentDate" class="date-picker">
<view class="picker-view">
<text>{{ formattedDate }}</text>
</view>
</picker>
</view>
<fad-collapse title="指标汇总">
<SummaryCardsVue :cardsData="cardData"/>
</fad-collapse>
<fad-collapse title="月度收支">
<!-- <BarVue :chart-data="barChartData"></BarVue> -->
</fad-collapse>
<fad-collapse title="近六月趋势">
</fad-collapse>
<fad-collapse title="项目支出占比">
<PieVue :project-list="projectList"></PieVue>
</fad-collapse>
<fad-collapse title="明细表格">
</fad-collapse>
</view>
</view>
</template>
<script>
import {
barData,
findFinanceList2
} from '@/api/oa/finance/finance';
import {
getExchangeRate
} from '@/api/oa/finance/exchangeRate';
import {
projectData2
} from '@/api/oa/project';
import SummaryCardsVue from './components/SummaryCards.vue';
import PieVue from './components/Pie.vue'
import BarVue from './components/Bar.vue';
export default {
data() {
return {
loading: true,
currentDate: '',
cardData: [], // 改为数组,存储汇总卡片数据(核心)
monthlyDataMap: {}, // 初始化月度数据映射(用于图表/卡片)
currentList: [], // barData接口返回的列表
projectList: [], // projectData2接口返回的列表
financeList: [], // findFinanceList2接口返回的列表
queryFinanceParams: {}, // 接口请求参数(需确保已定义)
dateForProject: '' ,// 项目接口日期参数(需确保已定义)
barChartData: {},
exchangeRate: 7,
};
},
computed: {
formattedDate() {
const [year, month] = this.currentDate.split('-');
return `${year}${month}`;
}
},
components: {
SummaryCardsVue,
PieVue,
BarVue
},
onLoad() {
// 初始化日期为当前月份
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;
this.currentDate = `${year}-${month.toString().padStart(2, '0')}-01`;
this.loadAllData()
},
methods: {
async loadAllExchangeRates(months) {
for (const m of months) {
if (!this.monthlyDataMap[m]) this.monthlyDataMap[m] = {};
if (this.monthlyDataMap[m].exchangeRate) continue;
this.monthlyDataMap[m].exchangeRate = this.exchangeRate;
}
},
onDateChange(e) {
const value = e.detail.value;
this.currentDate = value + '-01';
this.loadAllData()
},
async loadAllData() {
this.loading = true;
this.exchangeRate = await getExchangeRate()
barData(this.queryFinanceParams)
.then(res => {
this.currentList = res.data;
})
.then(async () => {
const months = this.currentList.map(i => i.month);
await this.loadAllExchangeRates(months);
return Promise.all([
projectData2(this.currentDate),
findFinanceList2({
date: this.currentDate
})
]);
})
.then(([projRes, finRes]) => {
this.projectList = projRes.data;
this.financeList = finRes.data;
this.computeSummaries();
})
.finally(() => {
this.loading = false;
console.log('loadAllData done', this.monthlyDataMap);
this.$nextTick(this.initCharts);
});
},
computeSummaries() {
// 1. 获取当前选中月份格式YYYY-MM从currentDate提取
const currentMonth = this.currentDate.slice(0, 7);
// 2. 初始化月度数据映射(确保每个月份的基础结构存在)
this.currentList.forEach(item => {
const month = item.month;
if (!this.monthlyDataMap[month]) {
this.monthlyDataMap[month] = {
outTotal: 0,
inCNY: 0,
inUSD: 0,
exchangeRate: this.monthlyDataMap[month]?.exchangeRate || 0 // 保留已有汇率
};
}
// 赋值出库总额从barData接口获取
this.monthlyDataMap[month].outTotal = item.totalOut;
});
// 3. 初始化统计变量(月度/项目收支)
const initStats = {
monthlyOutCNY: 0, // 月度总支出(人民币)
monthlyOutUSD: 0, // 月度总支出(美元)
monthlyInCNY: 0, // 月度总收入(人民币)
monthlyInUSD: 0, // 月度总收入(美元)
projectOutCNY: 0, // 项目支出(人民币)
projectOutUSD: 0, // 项目支出(美元)
projectInCNY: 0, // 项目收入(人民币)
projectInUSD: 0 // 项目收入(美元)
};
Object.assign(this, initStats);
// 4. 遍历财务明细,计算收支数据
this.financeList.forEach(finItem => {
const itemMonth = finItem.date.slice(0, 7); // 明细所属月份
const amount = Number(finItem.amount) || 0; // 金额转数字避免NaN
const isOut = finItem.type === '0'; // 0=支出1=收入(按业务定义)
const currency = finItem.currency === 'USD' ? 'USD' : 'CNY'; // 货币类型
// 4.1 更新月度收入数据存入monthlyDataMap
const monthData = this.monthlyDataMap[itemMonth];
if (monthData && !isOut) {
monthData[`in${currency}`] += amount;
}
// 4.2 计算「当前选中月份」的统计数据
if (itemMonth === currentMonth) {
if (isOut) {
// 支出:更新月度总支出 + 项目支出有projectId才统计项目
this[`monthlyOut${currency}`] += amount;
if (finItem.projectId) {
this[`projectOut${currency}`] += amount;
}
} else {
// 收入:更新月度总收入 + 项目收入有projectId才统计项目
this[`monthlyIn${currency}`] += amount;
if (finItem.projectId) {
this[`projectIn${currency}`] += amount;
}
}
}
});
// 5. 构建汇总卡片数据核心适配SummaryCards组件
console.log(this.monthlyDataMap, '月度数据')
this.cardData = [
{
title: '月度总支出',
valueCNY: Number(this.monthlyOutCNY.toFixed(2)), // 保留2位小数转数字
valueUSD: Number(this.monthlyOutUSD.toFixed(2))
},
{
title: '月度总收入',
valueCNY: Number(this.monthlyInCNY.toFixed(2)),
valueUSD: Number(this.monthlyInUSD.toFixed(2))
},
{
title: '项目支出',
valueCNY: Number(this.projectOutCNY.toFixed(2)),
valueUSD: Number(this.projectOutUSD.toFixed(2))
},
{
title: '项目收入',
valueCNY: Number(this.projectInCNY.toFixed(2)),
valueUSD: Number(this.projectInUSD.toFixed(2))
}
];
},
}
};
</script>
<style scoped>
.container {
padding: 16rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
/* 日期选择器在折叠卡片额外内容中的样式 */
.picker-view {
display: flex;
align-items: center;
color: #666;
font-size: 24rpx;
padding: 4rpx 8rpx;
}
.icon-margin {
margin-right: 8rpx;
}
/* 图表样式调整 */
.chart-item {
width: 100%;
}
/* 加载状态样式 */
.loading-view {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.loading-text {
margin-top: 20rpx;
font-size: 28rpx;
color: #666;
}
/* 折叠卡片间距 */
.fad-collapse {
margin-bottom: 16rpx;
}
.date-picker-container {
background-color: #fff;
border-radius: 8rpx;
padding: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
}
.date-picker {
width: 100%;
}
.picker-view {
text-align: center;
font-size: 28rpx;
color: #007aff;
padding: 8rpx 0;
}
</style>