97 lines
3.5 KiB
TypeScript
97 lines
3.5 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { View, Text, Button } from '@tarojs/components';
|
|
import { useDidShow } from '@tarojs/taro';
|
|
import HqHeader from '../../components/HqHeader';
|
|
import HqTabBar from '../../components/HqTabBar';
|
|
import { request, type Paginated, toast } from '../../lib/api';
|
|
import { useHqSession } from '../../lib/session';
|
|
import { fmtMoney, fmtTime } from '../../lib/constants';
|
|
|
|
type RedeemRow = {
|
|
id: string;
|
|
redeemNo: string;
|
|
amount: number | string;
|
|
createdAt: string;
|
|
store?: { name: string; cityName?: string };
|
|
user?: { nickname?: string; phone?: string };
|
|
payout?: unknown;
|
|
};
|
|
|
|
// 门店核销到账比例(V2 手册:门店核销结算 60%)
|
|
const STORE_PAYOUT_RATE = 0.6;
|
|
|
|
export default function SettlementPage() {
|
|
useHqSession();
|
|
const [rows, setRows] = useState<RedeemRow[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
function load() {
|
|
setLoading(true);
|
|
request<Paginated<RedeemRow>>('/admin/redeem-records?pageSize=50')
|
|
.then((d) => setRows(d.items))
|
|
.catch(() => setRows([]))
|
|
.finally(() => setLoading(false));
|
|
}
|
|
|
|
useEffect(load, []);
|
|
useDidShow(load);
|
|
|
|
const totalRedeem = rows.reduce((s, r) => s + Number(r.amount || 0), 0);
|
|
const totalPayout = totalRedeem * STORE_PAYOUT_RATE;
|
|
const pendingCount = rows.filter((r) => !r.payout).length;
|
|
|
|
return (
|
|
<View className="hq-page hq-page--tab">
|
|
<HqHeader title="结算中心" />
|
|
|
|
<View className="hq-stat-grid">
|
|
<View className="hq-stat">
|
|
<Text className="hq-stat__label">核销总额</Text>
|
|
<Text className="hq-stat__value">¥{fmtMoney(totalRedeem)}</Text>
|
|
<Text className="hq-stat__sub">近 {rows.length} 笔核销</Text>
|
|
</View>
|
|
<View className="hq-stat">
|
|
<Text className="hq-stat__label">门店应结(60%)</Text>
|
|
<Text className="hq-stat__value">¥{fmtMoney(totalPayout)}</Text>
|
|
<Text className="hq-stat__sub">待打款 {pendingCount} 笔</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View style="margin:12px 16px">
|
|
<Button
|
|
className="hq-btn hq-btn--primary hq-btn--block"
|
|
onClick={() => toast('preV1 阶段批量打款为演示,暂不实际出款')}
|
|
>
|
|
批量打款(演示)
|
|
</Button>
|
|
</View>
|
|
|
|
<Text className="hq-section-title">门店核销结算明细</Text>
|
|
|
|
{loading && <View className="hq-empty">加载中…</View>}
|
|
{!loading && rows.length === 0 && <View className="hq-empty">暂无核销记录</View>}
|
|
|
|
{rows.map((r) => (
|
|
<View key={r.id} className="hq-card" style="margin-top:8px;margin-bottom:0">
|
|
<View className="hq-row">
|
|
<Text style="font-size:14px;font-weight:600">{r.store?.name || '门店'}</Text>
|
|
<Text className={`hq-badge ${r.payout ? 'hq-badge--ok' : 'hq-badge--warn'}`}>
|
|
{r.payout ? '已结算' : '待结算'}
|
|
</Text>
|
|
</View>
|
|
<Text className="hq-muted" style="display:block;margin-top:4px;font-size:12px">
|
|
{r.store?.cityName || ''} · {r.redeemNo}
|
|
</Text>
|
|
<View className="hq-row" style="margin-top:8px">
|
|
<Text className="hq-muted" style="font-size:12px">{fmtTime(r.createdAt)}</Text>
|
|
<Text style="font-size:15px;font-weight:700;color:var(--hq-red)">
|
|
核销 ¥{fmtMoney(r.amount)} · 应结 ¥{fmtMoney(Number(r.amount || 0) * STORE_PAYOUT_RATE)}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
))}
|
|
<HqTabBar selected={2} />
|
|
</View>
|
|
);
|
|
}
|