Files
delivery-uniapp/pages/user/salary/salaryManage.vue
2026-01-24 17:45:54 +08:00

252 lines
5.8 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>
<s-layout title="账户余额" class="record-list-page">
<view class="page-wrap">
<!-- 余额卡片 -->
<view class="balance-card">
<view class="balance-top">
<text class="symbol">¥</text>
<text class="balance">{{ formatBalance(balance) }}</text>
</view>
<view class="balance-sub" @tap="openDetail()">
本月已入账 <up-icon name="arrow-right" color="#949494" size="15"></up-icon>
</view>
</view>
<!-- 列表按年分组的薪资账单 -->
<scroll-view class="list" scroll-y>
<view v-for="section in sections" :key="section.year" class="year-section">
<view class="year-header">{{ section.year }}年已出账薪资账单</view>
<view
class="month-row"
v-for="item in section.items"
:key="section.year + '-' + item.month"
@tap="openDetail(section.year, item.month)"
>
<text class="month-label">{{ item.month }}月份薪资</text>
<view class="month-right">
<text class="month-amount">¥ {{ formatAmount(item.amount) }}</text>
<up-icon name="arrow-right" color="#c7c7c7" size="16"></up-icon>
</view>
</view>
</view>
<view class="no-more">没有更多了~</view>
</scroll-view>
</view>
</s-layout>
</template>
<script setup>
import { ref } from 'vue';
import PayWalletApi from '@/sheep/api/pay/wallet';
import { onShow } from '@dcloudio/uni-app';
const balance = ref(0);
const sections = ref([]);
// 格式化显示余额(保留两位小数)
function formatBalance(val) {
if (val == null) return '0.00';
return (Number(val) || 0).toFixed(2);
}
// 列表金额格式(示例中是带一位小数,这里为兼容保留一位或两位)
function formatAmount(val) {
if (val == null) return '0.0';
// 如果本身有小数位则保留一位,否则保留一位
return (Number(val) || 0).toFixed(1);
}
// 将流水按 年 -> 月 聚合(支持后端 records 数组record.createTime 字段)
function groupTransactions(records = []) {
const map = {}; // { year: { month: amount } }
records.forEach((r) => {
// 兼容不同字段名,尝试 createTime 或 createdAt 或 time
const t = r.createTime ?? r.createdAt ?? r.time ?? r.create_date ?? r.date;
let d = t ? new Date(t) : null;
if (!d || isNaN(d.getTime())) {
// 如果没有时间则跳过
return;
}
const year = d.getFullYear();
const month = d.getMonth() + 1;
// 取金额字段amount / price / income / value / money
const amt = Number(r.amount ?? r.price ?? r.income ?? r.value ?? r.money ?? 0) || 0;
map[year] = map[year] || {};
map[year][month] = (map[year][month] || 0) + amt;
});
// 转换为数组并排序(年降序,月降序)
const result = Object.keys(map)
.map((y) => {
const monthsObj = map[y];
const items = Object.keys(monthsObj)
.map((m) => ({
month: Number(m),
amount: monthsObj[m],
}))
.sort((a, b) => b.month - a.month);
return {
year: Number(y),
items,
};
})
.sort((a, b) => b.year - a.year);
return result;
}
async function loadWallet() {
try {
const res = await PayWalletApi.getPayWallet();
if (res && res.code === 0 && res.data) {
balance.value = res.data.balance ?? res.data?.wallet?.balance ?? 0;
return;
}
} catch (e) {
// ignore
}
// 回退占位数据
balance.value = 1999.91;
}
async function loadTransactions() {
try {
// 请求分页(取足够多条用于按月聚合)
const res = await PayWalletApi.getWalletTransactionPage({ page: 1, size: 200 });
// 兼容常见返回结构:{ code:0, data: { records: [] } } 或 { code:0, data: [] }
let records = [];
if (res && res.code === 0) {
if (Array.isArray(res.data)) {
records = res.data;
} else if (res.data && Array.isArray(res.data.records)) {
records = res.data.records;
}
}
if (records.length) {
sections.value = groupTransactions(records);
return;
}
} catch (e) {
// ignore
}
// 回退示例数据(与原型一致)
sections.value = [
{
year: 2025,
items: [
{ month: 5, amount: 4563.5 },
{ month: 4, amount: 4563.5 },
{ month: 3, amount: 4563.5 },
{ month: 2, amount: 4563.5 },
{ month: 1, amount: 4563.5 },
],
},
{
year: 2024,
items: [{ month: 12, amount: 4563.5 }],
},
];
}
function openDetail(year, month) {
// 占位跳转:可以替换为真实的工资明细页
uni.navigateTo({
url: `/pages/user/salary/salaryList?year=${year}&month=${month}`,
});
}
function openMonthSummary() {
// 占位跳转到本月流水汇总
uni.navigateTo({
url: '/pages/user/walletSummary',
});
}
onShow(() => {
loadWallet();
loadTransactions();
});
</script>
<style>
.page-wrap {
padding: 16px;
background: transparent;
min-height: 100vh;
}
.balance-card {
background: #fff;
border-radius: 8px;
padding: 30px 16px;
margin-bottom: 12px;
text-align: center;
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
.balance-top {
display: flex;
justify-content: center;
align-items: baseline;
gap: 8px;
}
.symbol {
font-size: 28px;
color: #333;
margin-right: 6px;
}
.balance {
font-size: 40px;
font-weight: 700;
color: #333;
}
.balance-sub {
display: flex;
justify-content: center;
color: #999;
margin-top: 10px;
font-size: 14px;
}
.list {
margin-top: 8px;
}
.year-section {
margin-bottom: 12px;
}
.year-header {
background: #f5f5f5;
color: #666;
padding: 10px 12px;
font-weight: 600;
border-radius: 4px;
margin-bottom: 8px;
}
.month-row {
background: #fff;
padding: 14px 12px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #f0f0f0;
}
.month-label {
color: #333;
font-size: 15px;
}
.month-right {
display: flex;
align-items: center;
gap: 8px;
color: #999;
}
.month-amount {
color: #333;
font-weight: 600;
margin-right: 6px;
}
.no-more {
text-align: center;
color: #bbb;
padding: 20px 0;
}
</style>