feat: 新增部分页面静态页面
This commit is contained in:
270
pages/user/account/index.vue
Normal file
270
pages/user/account/index.vue
Normal file
@@ -0,0 +1,270 @@
|
||||
<template>
|
||||
<s-layout title="我的账户" class="account-page">
|
||||
<view class="page-wrap">
|
||||
<!-- 顶部周期选择 -->
|
||||
<view class="top-row">
|
||||
<view class="period-select" @tap="showPicker = true">
|
||||
<text class="period-label">{{ selectedLabel }}</text>
|
||||
<up-icon name="arrow-down" color="#333" size="14"></up-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 汇总卡片 -->
|
||||
<view class="summary-card">
|
||||
<text class="summary-amount">{{ formatSigned(totalAmount) }}</text>
|
||||
<text class="summary-sub">预计收入</text>
|
||||
<up-divider text=""></up-divider>
|
||||
<text class="summary-note">{{ summaryNote }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 交易列表 -->
|
||||
<scroll-view class="list" scroll-y>
|
||||
<view class="txn-item" v-for="item in items" :key="item.id">
|
||||
<view class="left" style="width:530rpx;">
|
||||
<text class="txn-title">{{ item.desc }}</text>
|
||||
<text class="txn-sub">{{ item.date }} {{ item.time }}</text>
|
||||
</view>
|
||||
<view class="right">
|
||||
<text class="txn-amount" :class="{ positive: item.amount >= 0 }">
|
||||
{{ formatSigned(item.amount) }}
|
||||
</text>
|
||||
<text class="txn-status">{{ item.statusText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="no-more">没有更多了~</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- picker -->
|
||||
<up-picker
|
||||
:show="showPicker"
|
||||
:columns="columns"
|
||||
@confirm="onConfirm"
|
||||
@cancel="showPicker = false"
|
||||
@close="showPicker = false"
|
||||
></up-picker>
|
||||
</view>
|
||||
</s-layout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import PayWalletApi from '@/sheep/api/pay/wallet';
|
||||
|
||||
// picker
|
||||
const showPicker = ref(false);
|
||||
const selectedLabel = ref('今日账单');
|
||||
const columns = [
|
||||
[
|
||||
{ text: '今日账单', value: 'today' },
|
||||
{ text: '昨日账单', value: 'yesterday' },
|
||||
{ text: '本月账单', value: 'month' },
|
||||
],
|
||||
];
|
||||
|
||||
// 数据
|
||||
const items = ref([]);
|
||||
const totalAmount = ref(0);
|
||||
const summaryNote = ref('');
|
||||
|
||||
// 本地回退示例(便于开发)
|
||||
const testList = [
|
||||
{ id: 't1', time: '18:02', date: '06-15', desc: '配送收入-#59-林记番薯粥(潮汕白粥,小炒,海鲜鱼)', amount: 6.1, statusText: '未到账' },
|
||||
{ id: 't2', time: '17:49', date: '06-15', desc: '配送收入-#57-林记番薯粥(潮汕白粥,小炒,海鲜鱼)', amount: 5.3, statusText: '未到账' },
|
||||
{ id: 't3', time: '17:42', date: '06-15', desc: '配送收入-#25-桐坑粿条(原汤猪肠·柠檬粿条)', amount: 4.6, statusText: '未到账' },
|
||||
{ id: 't4', time: '17:27', date: '06-15', desc: '配送收入-#110-万辉超市(潮阳店)', amount: 3.6, statusText: '未到账' },
|
||||
{ id: 't5', time: '16:56', date: '06-15', desc: '配送收入-#145-仓鼠便利超市(潮阳店)', amount: 3.1, statusText: '未到账' },
|
||||
];
|
||||
|
||||
function formatSigned(val) {
|
||||
const n = Number(val) || 0;
|
||||
const sign = n > 0 ? '+' : n < 0 ? '' : '+';
|
||||
return `${sign}${Math.abs(n).toFixed(2)}`;
|
||||
}
|
||||
|
||||
function toDateParts(t) {
|
||||
const d = t ? new Date(t) : null;
|
||||
if (!d || isNaN(d.getTime())) return { date: '', time: '' };
|
||||
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(d.getDate()).padStart(2, '0');
|
||||
const hh = String(d.getHours()).padStart(2, '0');
|
||||
const mi = String(d.getMinutes()).padStart(2, '0');
|
||||
return { date: `${mm}-${dd}`, time: `${hh}:${mi}` };
|
||||
}
|
||||
|
||||
// 根据 picker value 计算时间范围(返回 start/end Date)
|
||||
function rangeFor(value) {
|
||||
const now = new Date();
|
||||
if (value === 'today') {
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
|
||||
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
|
||||
return [start, end];
|
||||
}
|
||||
if (value === 'yesterday') {
|
||||
const y = new Date(now);
|
||||
y.setDate(now.getDate() - 1);
|
||||
const start = new Date(y.getFullYear(), y.getMonth(), y.getDate(), 0, 0, 0);
|
||||
const end = new Date(y.getFullYear(), y.getMonth(), y.getDate(), 23, 59, 59);
|
||||
return [start, end];
|
||||
}
|
||||
// month
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0);
|
||||
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
||||
return [start, end];
|
||||
}
|
||||
|
||||
// 加载并过滤流水
|
||||
async function load() {
|
||||
try {
|
||||
const res = await PayWalletApi.getWalletTransactionPage({ page: 1, size: 200 });
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
const pickerValue = columns[0].find((c) => c.text === selectedLabel.value)?.value ?? 'today';
|
||||
const [start, end] = rangeFor(pickerValue);
|
||||
|
||||
let filtered = [];
|
||||
if (records && records.length) {
|
||||
filtered = records.filter((r) => {
|
||||
const t = r.createTime ?? r.createdAt ?? r.time ?? r.create_date ?? r.date;
|
||||
if (!t) return false;
|
||||
const d = new Date(t);
|
||||
if (isNaN(d.getTime())) return false;
|
||||
return d >= start && d <= end;
|
||||
});
|
||||
}
|
||||
|
||||
if (!filtered.length) {
|
||||
// 使用本地回退示例
|
||||
items.value = testList;
|
||||
} else {
|
||||
items.value = filtered.map((r, idx) => {
|
||||
const t = r.createTime ?? r.createdAt ?? r.time ?? r.create_date ?? r.date;
|
||||
const parts = toDateParts(t);
|
||||
return {
|
||||
id: r.id ?? `r-${idx}`,
|
||||
date: parts.date,
|
||||
time: parts.time,
|
||||
desc: r.remark ?? r.note ?? r.title ?? r.typeName ?? r.description ?? '',
|
||||
amount: Number(r.amount ?? r.price ?? r.income ?? r.value ?? r.money ?? 0),
|
||||
statusText: r.statusText ?? r.stateText ?? r.payStatus ?? '',
|
||||
};
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// 回退示例
|
||||
items.value = testList;
|
||||
}
|
||||
|
||||
// 计算汇总
|
||||
totalAmount.value = items.value.reduce((s, it) => s + (Number(it.amount) || 0), 0);
|
||||
|
||||
// 汇总说明(取前两条简短描述拼接)
|
||||
summaryNote.value = items.value.slice(0, 2).map((i) => i.desc).join(' ');
|
||||
}
|
||||
|
||||
function onConfirm(e) {
|
||||
const v = e && e.value && e.value[0];
|
||||
if (v) {
|
||||
selectedLabel.value = v.text || String(v);
|
||||
}
|
||||
showPicker.value = false;
|
||||
load();
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
load();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrap {
|
||||
padding: 12px;
|
||||
background: transparent;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.top-row {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.period-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.period-label {
|
||||
font-weight: 700;
|
||||
}
|
||||
.summary-card {
|
||||
background: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.summary-amount {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #e74c3c;
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.summary-sub {
|
||||
color: #999;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
.summary-note {
|
||||
color: #bbb;
|
||||
font-size: 13px;
|
||||
}
|
||||
.list {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.txn-item {
|
||||
background: #fff;
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.txn-title {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.txn-sub {
|
||||
color: #999;
|
||||
font-size: 13px;
|
||||
}
|
||||
.txn-amount {
|
||||
font-weight: 700;
|
||||
color: #e74c3c;
|
||||
text-align: right;
|
||||
}
|
||||
.txn-amount.positive {
|
||||
color: #e74c3c;
|
||||
}
|
||||
.txn-status {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
.no-more {
|
||||
text-align: center;
|
||||
color: #bbb;
|
||||
padding: 20px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user