feat: 新增部分页面静态页面
This commit is contained in:
252
pages/user/salary/salaryManage.vue
Normal file
252
pages/user/salary/salaryManage.vue
Normal 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>
|
||||
Reference in New Issue
Block a user