feat: 新增部分页面静态页面

This commit is contained in:
admin
2026-01-24 17:45:54 +08:00
parent 849647d3c9
commit 8c1224999d
20 changed files with 1828 additions and 339 deletions

View File

@@ -0,0 +1,252 @@
<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>