feat(admin): 新增后台财务看板与财务明细

This commit is contained in:
yml2213
2026-10-30 13:22:31 +08:00
parent ab5dac51f7
commit 4239bec519
10 changed files with 789 additions and 5 deletions
+2 -2
View File
@@ -194,9 +194,9 @@ dist/assets/AdminLayout-*.js 36.87 kB │ gzip 13.02 kB
## 5. 已知限制
1. 移动端订单列表/详情与消息中心已接入真实接口;下单、支付、交接、归还、结账等操作仍待迁移。
2. 后台已完成仪表盘、订单列表/详情、退款审核、提现审核、商品列表/详情与审核、用户列表/详情与人工操作、申诉仲裁,其余页面仍为统一占位。
2. 后台已完成仪表盘、订单列表/详情、退款审核、提现审核、商品列表/详情与审核、用户列表/详情与人工操作、申诉仲裁、财务看板,其余页面仍为统一占位。
3. 分销后台已完成主题、Logo、登录页与 Shell 轻改,页面结构未重写。
4. 后台菜单权限码按后端逐个核对:订单 `order:list` / `order:view` / `order:close`,商品 `listing:view` / `listing:approve` / `listing:reject` / `listing:offline`,用户 `user:view` / `user:freeze` / `user:unfreeze` / `user:deposit_free` / `user:growth_points` / `user:manual_realname` / `user:revoke_realname` / `user:wallet_adjust`,提现 `withdrawal:list` / `withdrawal:detail` / `withdrawal:review` / `withdrawal:pay`,申诉 `dispute:view` / `dispute:arbitrate`;其余页面仍需核对。
4. 后台菜单权限码按后端逐个核对:订单 `order:list` / `order:view` / `order:close`,商品 `listing:view` / `listing:approve` / `listing:reject` / `listing:offline`,用户 `user:view` / `user:freeze` / `user:unfreeze` / `user:deposit_free` / `user:growth_points` / `user:manual_realname` / `user:revoke_realname` / `user:wallet_adjust`,提现 `withdrawal:list` / `withdrawal:detail` / `withdrawal:review` / `withdrawal:pay`,申诉 `dispute:view` / `dispute:arbitrate`,财务 `wallet:view`;其余页面仍需核对。
5. SVG 中文尚未转曲。
6. 入口包已降至 495 kB(gzip 161 kB);AntD 共享基础设施仍在入口,后续可拆独立入口。
7. 移动端、订单、分销轻改与首屏优化均已提交;商品管理与审核在本批次提交。
+65
View File
@@ -0,0 +1,65 @@
# Phase 2 验收报告(后台财务看板)
> 日期:2026-10-30
> 项目:解忧商行(hfb_jysh)
> 范围:`/console-jy8k3m/finance`
> 结论:**本切片通过,财务总览、每日趋势与财务明细已接真实接口**
---
## 1. 接口与权限
| 能力 | 接口 | 权限码 |
| --- | --- | --- |
| 财务总览 | `GET /api/admin/finance/dashboard` | `wallet:view` |
| 财务明细 | `GET /api/admin/finance/details` | `wallet:view` |
日期参数:`start_date` / `end_date`(`YYYY-MM-DD`)。前端菜单权限已从推断值 `finance:view` 修正为 `wallet:view`。
## 2. 页面结构
`frontend/src/features/admin/AdminFinancePage.tsx`
- 顶部日期区间:默认近 7 天,可切换任意区间;总览与明细共用区间
- 主 KPI:总流水、总退款、平台收入、号主应得、渠道净额、资金异常、待打款、提现待审
- 次级摘要:待结算订单、线下提号、撞车商城净额、运营支出
- 每日趋势:流水、退款、渠道净额、平台收入、号主应得、结算/支付订单数、运营支出、已打款
- 财务明细:订单号、双方、订单金额、结账金额、支付/退款/渠道净额、财务状态、结算时间
- 明细支持订单号精确查询、日期类型(下单/结算/线下结算)、分页
- 点击订单号跳转订单管理并带上 `keyword` 查询
## 3. 财务状态
| 值 | 文案 |
| --- | --- |
| `normal` | 正常 |
| `refund_pending` | 退款中 |
| `refund_failed` | 退款失败 |
| `settlement_diff` | 结算差异 |
| `offline_settlement_pending` | 待线下结算 |
## 4. 验证结果
```text
npx tsc --noEmit 通过
npm run build 通过(入口 496.68 kB,gzip 161.26 kB)
GET /api/admin/finance/dashboard?start_date=2026-10-24&end_date=2026-10-30 ok,返回 summary/daily/各摘要
GET /api/admin/finance/details?...&page=1&page_size=5 ok,{"items":[],"total":0}
GET /console-jy8k3m/finance 200
```
开发库没有订单流水,总览与明细均为 0;接口字段与 DTO 已核对。
## 5. 已知限制
1. 未接线下出款、人工出款、运营支出登记与作废接口(需要 `finance:manual_disbursement` / `finance:operating_expense`)。
2. 未做图表可视化,当前以 KPI + 表格呈现。
3. 财务明细不支持按财务状态筛选(后端未提供该参数)。
4. 未做导出与对账单下载。
## 6. 下一步建议
1. 后台公告管理与系统配置。
2. 后台审计日志。
3. 线下出款/运营支出登记。
4. 移动端下单、支付与交接/归还/结账。
+1 -1
View File
@@ -395,7 +395,7 @@ hfb_jysh/
### Phase 4:管理后台核心(4–5 周)
> 状态:**进行中(2026-10-30)**。已完成仪表盘、订单列表/详情、退款审核、提现审核、商品列表/详情与审核、用户列表/详情与人工操作、申诉仲裁;财务看板、系统配置与审计日志待迁移。
> 状态:**进行中(2026-10-30)**。已完成仪表盘、订单、退款、提现、商品、用户、申诉与财务看板;线下出款/运营支出、系统配置与审计日志待迁移。
- 后台登录、工作台、订单列表、订单详情。
- 商品列表、商品详情、审核。
+6 -1
View File
@@ -93,6 +93,11 @@ const AdminDisputesPage = lazy(() =>
default: module.AdminDisputesPage,
}))
)
const AdminFinancePage = lazy(() =>
import('@/features/admin/AdminFinancePage').then(module => ({
default: module.AdminFinancePage,
}))
)
const AdminLayout = lazy(() =>
import('@/layouts/AdminLayout').then(module => ({ default: module.AdminLayout }))
)
@@ -101,7 +106,6 @@ const AdminSectionPlaceholder = lazy(() =>
)
const adminSections: Array<{ path: string; title: string; description: string }> = [
{ path: 'finance', title: '财务看板', description: '查看收入、退款、结算与资金趋势。' },
{ path: 'distribution/sites', title: '分销站点', description: '管理分站、规则、结算与站点钱包。' },
{ path: 'announcements', title: '公告管理', description: '维护主站与分站公告。' },
{ path: 'system-configs', title: '系统配置', description: '维护首页、发布、订单与支付配置。' },
@@ -144,6 +148,7 @@ export function AppRouter() {
<Route path="users" element={<AdminUsersPage />} />
<Route path="withdrawals" element={<AdminWithdrawalsPage />} />
<Route path="disputes" element={<AdminDisputesPage />} />
<Route path="finance" element={<AdminFinancePage />} />
{adminSections.map(section => (
<Route
key={section.path}
@@ -0,0 +1,534 @@
import { useMemo, useState } from 'react'
import { keepPreviousData, useQuery } from '@tanstack/react-query'
import {
Alert,
Button,
Card,
Col,
DatePicker,
Input,
Row,
Select,
Space,
Statistic,
Tag,
Typography,
type TableColumnsType,
} from 'antd'
import {
AccountBookOutlined,
BankOutlined,
ReloadOutlined,
RiseOutlined,
WalletOutlined,
WarningOutlined,
} from '@ant-design/icons'
import dayjs, { type Dayjs } from 'dayjs'
import { useNavigate } from 'react-router-dom'
import { fetchFinanceDashboard, fetchFinanceDetails } from '@/features/admin/api'
import { AdminPageHeader } from '@/features/admin/components/AdminPageHeader'
import { DataTable } from '@/features/admin/components/DataTable'
import { FilterBar, FilterField } from '@/features/admin/components/FilterBar'
import { StatusTag } from '@/features/admin/components/StatusTag'
import { financeStatusMap, orderStatusMap, readStatusMeta } from '@/features/admin/labels'
import type { FinanceDaily, FinanceDetail } from '@/features/admin/types'
import { formatDateTime, formatMoney, formatText } from '@/shared/utils/format'
type DateType = 'settled' | 'created' | 'offline_settled'
const dateTypeOptions = [
{ value: 'settled', label: '按结算时间' },
{ value: 'created', label: '按下单时间' },
{ value: 'offline_settled', label: '按线下结算时间' },
]
const dailyColumns: TableColumnsType<FinanceDaily> = [
{ title: '日期', dataIndex: 'date', width: 120, fixed: 'left' },
{
title: '流水',
dataIndex: 'total_flow_amount_cent',
width: 130,
align: 'right',
render: value => formatMoney(value),
},
{
title: '退款',
dataIndex: 'total_refund_amount_cent',
width: 120,
align: 'right',
render: value => formatMoney(value),
},
{
title: '渠道净额',
dataIndex: 'channel_net_amount_cent',
width: 130,
align: 'right',
render: value => formatMoney(value),
},
{
title: '平台收入',
dataIndex: 'platform_income_amount_cent',
width: 130,
align: 'right',
render: value => <span className="admin-money">{formatMoney(value)}</span>,
},
{
title: '号主应得',
dataIndex: 'owner_should_income_amount_cent',
width: 130,
align: 'right',
render: value => formatMoney(value),
},
{
title: '已结算订单',
dataIndex: 'settled_order_count',
width: 110,
align: 'right',
},
{
title: '支付订单',
dataIndex: 'paid_order_count',
width: 100,
align: 'right',
},
{
title: '运营支出',
dataIndex: 'operating_expense_amount_cent',
width: 130,
align: 'right',
render: value => formatMoney(value),
},
{
title: '已打款',
dataIndex: 'disbursement_paid_amount_cent',
width: 130,
align: 'right',
render: value => formatMoney(value),
},
]
function buildDetailColumns(onOpenOrder: (orderNo: string) => void): TableColumnsType<FinanceDetail> {
return [
{
title: '订单',
dataIndex: 'order_no',
width: 200,
fixed: 'left',
render: (_, row) => (
<div className="admin-stack">
<button type="button" className="admin-order-link" onClick={() => onOpenOrder(row.order_no)}>
{row.order_no}
</button>
<StatusTag meta={readStatusMeta(orderStatusMap, row.order_status)} />
<span>结算 {formatText(row.settlement_status)}</span>
</div>
),
},
{
title: '用户',
key: 'users',
width: 170,
render: (_, row) => (
<div className="admin-stack">
<span>租客 {formatText(row.renter_phone)}</span>
<span>号主 {formatText(row.owner_phone)}</span>
</div>
),
},
{
title: '订单金额',
key: 'order_amount',
width: 140,
align: 'right',
render: (_, row) => (
<div className="admin-amount">
<strong>{formatMoney(row.order_rent_amount_cent)}</strong>
<span>押金 {formatMoney(row.order_deposit_amount_cent)}</span>
</div>
),
},
{
title: '结账',
key: 'checkout',
width: 160,
align: 'right',
render: (_, row) => (
<div className="admin-amount">
<span>租金 {formatMoney(row.checkout_rent_amount_cent)}</span>
<span>号主 {formatMoney(row.checkout_owner_income_cent)}</span>
<span>平台费 {formatMoney(row.checkout_platform_fee_cent)}</span>
</div>
),
},
{
title: '支付 / 退款',
key: 'payment',
width: 160,
align: 'right',
render: (_, row) => (
<div className="admin-amount">
<strong>{formatMoney(row.paid_amount_cent)}</strong>
<span>退款 {formatMoney(row.refunded_amount_cent)}</span>
<span>渠道净额 {formatMoney(row.channel_net_amount_cent)}</span>
</div>
),
},
{
title: '财务状态',
dataIndex: 'finance_status',
width: 130,
render: value => <StatusTag meta={readStatusMeta(financeStatusMap, value)} />,
},
{
title: '结算时间',
dataIndex: 'settled_at',
width: 170,
render: value => formatDateTime(value),
},
{
title: '操作',
key: 'actions',
width: 100,
fixed: 'right',
render: (_, row) => (
<Button type="link" size="small" onClick={() => onOpenOrder(row.order_no)}>
查看订单
</Button>
),
},
]
}
export function AdminFinancePage() {
const navigate = useNavigate()
const [range, setRange] = useState<[Dayjs, Dayjs]>([
dayjs().subtract(6, 'day'),
dayjs(),
])
const [keyword, setKeyword] = useState('')
const [appliedKeyword, setAppliedKeyword] = useState('')
const [dateType, setDateType] = useState<DateType>('settled')
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(20)
const startDate = range[0].format('YYYY-MM-DD')
const endDate = range[1].format('YYYY-MM-DD')
const dashboard = useQuery({
queryKey: ['finance-dashboard', startDate, endDate],
queryFn: () => fetchFinanceDashboard({ start_date: startDate, end_date: endDate }),
staleTime: 60_000,
})
const details = useQuery({
queryKey: ['finance-details', startDate, endDate, appliedKeyword, dateType, page, pageSize],
queryFn: () =>
fetchFinanceDetails({
start_date: startDate,
end_date: endDate,
order_no: appliedKeyword,
date_type: dateType,
page,
page_size: pageSize,
}),
placeholderData: keepPreviousData,
})
const detailColumns = useMemo(
() => buildDetailColumns(orderNo => navigate(`/orders?keyword=${encodeURIComponent(orderNo)}`)),
[navigate]
)
const summary = dashboard.data?.summary
const disbursement = dashboard.data?.disbursement_summary
const pickup = dashboard.data?.pickup_summary
const mohong = dashboard.data?.mohong_summary
const expense = dashboard.data?.operating_expense_summary
const daily = dashboard.data?.daily_items ?? []
const applyDetailFilters = () => {
setAppliedKeyword(keyword.trim())
setPage(1)
}
const resetDetailFilters = () => {
setKeyword('')
setAppliedKeyword('')
setPage(1)
}
const errorText =
dashboard.error instanceof Error ? dashboard.error.message : '请稍后重试或重新登录后台。'
return (
<div className="admin-page">
<AdminPageHeader
eyebrow="JIEYOU OPS · 财务"
title="财务看板"
description="按时间区间核对流水、退款、平台收入、号主结算与出款压力。"
meta={
<Space size={8} wrap>
<Tag color="geekblue">
{startDate} ~ {endDate}
</Tag>
{dashboard.isFetching ? <Tag color="processing">正在更新</Tag> : null}
</Space>
}
extra={
<Space wrap>
<DatePicker.RangePicker
value={range}
allowClear={false}
onChange={value => {
if (value?.[0] && value[1]) {
setRange([value[0], value[1]])
setPage(1)
}
}}
/>
<Button
icon={<ReloadOutlined />}
onClick={() => {
void dashboard.refetch()
void details.refetch()
}}
loading={dashboard.isFetching}
>
刷新
</Button>
</Space>
}
/>
{dashboard.isError ? (
<Alert
type="error"
showIcon
className="admin-table-alert"
message="财务数据没有加载出来"
description={errorText}
action={
<Button size="small" onClick={() => void dashboard.refetch()}>
重试
</Button>
}
/>
) : null}
<Row gutter={[16, 16]}>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<AccountBookOutlined />
</div>
<Statistic title="总流水" value={formatMoney(summary?.total_flow_amount_cent ?? 0)} />
<span className="admin-kpi-card__foot">
支付 {summary?.successful_pay_count ?? 0} 笔 · 退款{' '}
{summary?.successful_refund_count ?? 0} 笔
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<WalletOutlined />
</div>
<Statistic title="总退款" value={formatMoney(summary?.total_refund_amount_cent ?? 0)} />
<span className="admin-kpi-card__foot">
待退款 {formatMoney(summary?.pending_refund_amount_cent ?? 0)} ·{' '}
{summary?.pending_refund_count ?? 0} 笔
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card admin-kpi-card--accent">
<div className="admin-kpi-card__icon">
<RiseOutlined />
</div>
<Statistic
title="平台收入"
value={formatMoney(summary?.platform_income_amount_cent ?? 0)}
/>
<span className="admin-kpi-card__foot">
订单 {formatMoney(summary?.normal_order_profit_amount_cent ?? 0)} · 提号{' '}
{formatMoney(summary?.pickup_profit_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<BankOutlined />
</div>
<Statistic
title="号主应得"
value={formatMoney(summary?.owner_should_income_amount_cent ?? 0)}
/>
<span className="admin-kpi-card__foot">
钱包入账 {formatMoney(summary?.owner_wallet_income_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<WalletOutlined />
</div>
<Statistic
title="渠道净额"
value={formatMoney(summary?.channel_net_amount_cent ?? 0)}
/>
<span className="admin-kpi-card__foot">
已结算订单 {summary?.settled_order_count ?? 0} 笔
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<WarningOutlined />
</div>
<Statistic title="资金异常" value={summary?.financial_exception_count ?? 0} />
<span className="admin-kpi-card__foot">
结算差异 {formatMoney(summary?.settlement_diff_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<BankOutlined />
</div>
<Statistic
title="待打款"
value={formatMoney(disbursement?.pending_payment_amount_cent ?? 0)}
/>
<span className="admin-kpi-card__foot">
{disbursement?.pending_payment_count ?? 0} 笔 · 已打款{' '}
{formatMoney(disbursement?.paid_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-kpi-card">
<div className="admin-kpi-card__icon">
<WarningOutlined />
</div>
<Statistic
title="提现待审"
value={formatMoney(disbursement?.withdrawal_review_amount_cent ?? 0)}
/>
<span className="admin-kpi-card__foot">
{disbursement?.withdrawal_review_count ?? 0} 笔 · 待打款{' '}
{formatMoney(disbursement?.withdrawal_pending_amount_cent ?? 0)}
</span>
</Card>
</Col>
</Row>
<Row gutter={[16, 16]} className="admin-finance-mini">
<Col xs={24} sm={12} xl={6}>
<Card className="admin-pending-card">
<div>
<span className="admin-pending-card__label">待结算订单</span>
<strong>{summary?.pending_settle_order_count ?? 0}</strong>
</div>
<span>待线下结算 {formatMoney(summary?.offline_settlement_pending_amount_cent ?? 0)}</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-pending-card">
<div>
<span className="admin-pending-card__label">线下提号</span>
<strong>{pickup?.completed_count ?? 0}</strong>
</div>
<span>
利润 {formatMoney(pickup?.profit_amount_cent ?? 0)} · 待结{' '}
{formatMoney(pickup?.pending_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-pending-card">
<div>
<span className="admin-pending-card__label">撞车商城净额</span>
<strong>{formatMoney(mohong?.net_amount_cent ?? 0)}</strong>
</div>
<span>
流水 {formatMoney(mohong?.flow_amount_cent ?? 0)} · 退款{' '}
{formatMoney(mohong?.refund_amount_cent ?? 0)}
</span>
</Card>
</Col>
<Col xs={24} sm={12} xl={6}>
<Card className="admin-pending-card">
<div>
<span className="admin-pending-card__label">运营支出</span>
<strong>{formatMoney(expense?.amount_cent ?? 0)}</strong>
</div>
<span>{expense?.count ?? 0} 笔已登记支出</span>
</Card>
</Col>
</Row>
<DataTable<FinanceDaily>
className="admin-finance-daily"
title={<span>每日趋势</span>}
extra={<Typography.Text type="secondary">数据更新于 {formatDateTime(dashboard.data?.generated_at)}</Typography.Text>}
rowKey="date"
columns={dailyColumns}
dataSource={daily}
loading={dashboard.isFetching}
emptyDescription="所选区间没有财务数据"
/>
<FilterBar
onSearch={applyDetailFilters}
onReset={appliedKeyword ? resetDetailFilters : undefined}
loading={details.isFetching}
extra={
<Select
value={dateType}
style={{ width: 160 }}
options={dateTypeOptions}
onChange={value => {
setDateType(value)
setPage(1)
}}
/>
}
>
<FilterField label="订单号" width={280}>
<Input
allowClear
value={keyword}
placeholder="按订单号精确查询"
onChange={event => setKeyword(event.target.value)}
/>
</FilterField>
</FilterBar>
<DataTable<FinanceDetail>
title={<span>财务明细</span>}
extra={
<Typography.Text type="secondary">
{details.data ? `共 ${details.data.total} 条` : '加载中'}
</Typography.Text>
}
rowKey="order_id"
columns={detailColumns}
dataSource={details.data?.items ?? []}
loading={details.isFetching}
total={details.data?.total ?? 0}
page={details.data?.page ?? page}
pageSize={details.data?.page_size ?? pageSize}
onPageChange={(nextPage, nextPageSize) => {
setPage(nextPageSize !== pageSize ? 1 : nextPage)
setPageSize(nextPageSize)
}}
emptyDescription="所选区间没有财务明细"
/>
</div>
)
}
+34
View File
@@ -20,6 +20,8 @@ import type {
AdminWithdrawalPage,
AdminWithdrawalQuery,
DashboardData,
FinanceDashboard,
FinanceDetailPage,
} from '@/features/admin/types'
export async function fetchAdminCaptcha() {
@@ -311,3 +313,35 @@ export async function arbitrateAdminDispute(
)
return data.data
}
export interface FinanceRangeQuery {
start_date?: string
end_date?: string
}
export async function fetchFinanceDashboard(range: FinanceRangeQuery) {
const { data } = await adminClient.get<ApiResponse<FinanceDashboard>>('/admin/finance/dashboard', {
params: compactParams(range),
})
return data.data
}
export async function fetchFinanceDetails(
query: FinanceRangeQuery & {
order_no?: string
date_type?: 'created' | 'settled' | 'offline_settled'
page?: number
page_size?: number
}
) {
const { data } = await adminClient.get<ApiResponse<Partial<FinanceDetailPage>>>(
'/admin/finance/details',
{ params: compactParams(query) }
)
return {
items: data.data.items ?? [],
total: data.data.total ?? 0,
page: data.data.page ?? query.page ?? 1,
page_size: data.data.page_size ?? query.page_size ?? 20,
}
}
+8
View File
@@ -189,3 +189,11 @@ export const withdrawalStatusMap: Record<string, StatusMeta> = {
}
export const withdrawalStatusOptions = toOptions(withdrawalStatusMap)
export const financeStatusMap: Record<string, StatusMeta> = {
normal: { label: '正常', tone: 'success' },
refund_pending: { label: '退款中', tone: 'blue' },
refund_failed: { label: '退款失败', tone: 'red' },
settlement_diff: { label: '结算差异', tone: 'orange' },
offline_settlement_pending: { label: '待线下结算', tone: 'gold' },
}
+129
View File
@@ -404,3 +404,132 @@ export interface AdminDisputePage {
page: number
page_size: number
}
export interface FinanceSummary {
total_flow_amount_cent: number
total_refund_amount_cent: number
pending_refund_amount_cent: number
channel_net_amount_cent: number
platform_income_amount_cent: number
normal_order_profit_amount_cent: number
pickup_profit_amount_cent: number
owner_should_income_amount_cent: number
owner_wallet_income_amount_cent: number
owner_effective_settlement_amount_cent: number
offline_settlement_amount_cent: number
offline_settlement_pending_amount_cent: number
settlement_diff_amount_cent: number
estimated_income_amount_cent: number
successful_pay_count: number
successful_refund_count: number
pending_refund_count: number
settled_order_count: number
pending_settle_order_count: number
offline_settlement_pending_count: number
financial_exception_count: number
}
export interface FinanceDaily {
date: string
total_flow_amount_cent: number
total_refund_amount_cent: number
platform_income_amount_cent: number
channel_net_amount_cent: number
owner_should_income_amount_cent: number
settled_order_count: number
paid_order_count: number
operating_expense_amount_cent: number
disbursement_paid_amount_cent: number
}
export interface FinancePickupSummary {
settled_amount_cent: number
profit_amount_cent: number
completed_count: number
in_progress_count: number
pending_amount_cent: number
pending_count: number
}
export interface FinanceMohongSummary {
flow_amount_cent: number
refund_amount_cent: number
net_amount_cent: number
paid_order_count: number
}
export interface FinanceDisbursementSummary {
paid_amount_cent: number
paid_count: number
pending_payment_amount_cent: number
pending_payment_count: number
withdrawal_amount_cent: number
withdrawal_fee_amount_cent: number
withdrawal_paid_amount_cent: number
withdrawal_paid_count: number
withdrawal_pending_amount_cent: number
withdrawal_pending_count: number
withdrawal_review_amount_cent: number
withdrawal_review_count: number
manual_paid_amount_cent: number
manual_paid_count: number
}
export interface FinanceOperatingExpenseSummary {
amount_cent: number
count: number
}
export interface FinanceDashboard {
summary: FinanceSummary
daily_items: FinanceDaily[]
pickup_summary: FinancePickupSummary
mohong_summary: FinanceMohongSummary
disbursement_summary: FinanceDisbursementSummary
operating_expense_summary: FinanceOperatingExpenseSummary
generated_at: string
}
export interface FinanceDetail {
order_id: number
order_no: string
order_status: string
settlement_status: string
refund_status: string
handoff_mode: string
settlement_mode: string
offline_settlement_status: string
offline_settlement_amount_cent: number
renter_id: number
renter_phone: string
renter_nickname: string
owner_id: number
owner_phone: string
owner_nickname: string
order_rent_amount_cent: number
order_deposit_amount_cent: number
checkout_rent_amount_cent: number
checkout_renter_refund_cent: number
checkout_owner_income_cent: number
checkout_platform_fee_cent: number
owner_wallet_income_amount_cent: number
owner_effective_settlement_amount_cent: number
paid_amount_cent: number
refunded_amount_cent: number
refunding_amount_cent: number
failed_refund_amount_cent: number
channel_net_amount_cent: number
platform_net_amount_cent: number
settlement_diff_amount_cent: number
finance_status: string
created_at: string
settled_at?: string | null
offline_settled_at?: string | null
}
export interface FinanceDetailPage {
items: FinanceDetail[]
total: number
page: number
page_size: number
}
+1 -1
View File
@@ -83,7 +83,7 @@ const allNavGroups: NavGroup[] = [
label: '财务',
icon: <AccountBookOutlined />,
children: [
{ key: '/finance', label: '财务看板', permission: 'finance:view' },
{ key: '/finance', label: '财务看板', permission: 'wallet:view' },
{ key: '/withdrawals', label: '提现审核', permission: 'withdrawal:list' },
],
},
+9
View File
@@ -1403,6 +1403,15 @@ a {
margin-bottom: 16px;
}
.admin-finance-mini {
margin-top: 16px;
}
.admin-finance-mini .admin-pending-card > .ant-card-body > span {
color: var(--ink-muted);
font-size: 11px;
}
.admin-detail {
display: flex;
flex-direction: column;