diff --git a/src/pages/finance/payments/index.module.less b/src/pages/finance/payments/index.module.less
new file mode 100644
index 0000000..38ddafa
--- /dev/null
+++ b/src/pages/finance/payments/index.module.less
@@ -0,0 +1,46 @@
+// ===== 汇总(按图片:左对齐两段加粗数字) =====
+.summary {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0 32px;
+ flex-shrink: 0;
+ padding: 14px 15px;
+ background: #fff;
+ border-radius: 8px;
+ font-size: 14px;
+ color: rgba(0, 0, 0, 0.85);
+}
+
+.summaryItem {
+ display: inline-flex;
+ align-items: baseline;
+}
+
+.summaryLabel {
+ color: rgba(0, 0, 0, 0.65);
+}
+
+.summaryValue {
+ font-weight: 600;
+ color: rgba(0, 0, 0, 0.85);
+ letter-spacing: 0.3px;
+ font-family:
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+}
+
+// ===== 表格 body 容器:占满 flex 剩余空间 =====
+.tableBody {
+ flex: 1;
+ min-height: 0;
+ overflow: hidden;
+
+ :global {
+ .ant-spin-nested-loading,
+ .ant-spin-container,
+ .ant-table,
+ .ant-table-container {
+ height: 100%;
+ }
+ }
+}
diff --git a/src/pages/finance/payments/index.tsx b/src/pages/finance/payments/index.tsx
index d61e398..bb354fc 100644
--- a/src/pages/finance/payments/index.tsx
+++ b/src/pages/finance/payments/index.tsx
@@ -1,4 +1,10 @@
import { defineComponent } from 'vue';
+import { Button, Input, Table, Form, Space, Pagination, Select, DatePicker } from 'ant-design-vue';
+import { usePaymentsModel } from './model/usePaymentsModel';
+import { useContainerSize } from '@/hooks';
+import styles from './index.module.less';
+
+const { RangePicker } = DatePicker;
/**
* 支付流水
@@ -6,9 +12,107 @@ import { defineComponent } from 'vue';
export default defineComponent({
name: 'FinancePayments',
setup() {
+ const {
+ filterForm,
+ loading,
+ dataSource,
+ columns,
+ summary,
+ pagination,
+ handleSearch,
+ handleReset,
+ handlePageChange,
+ PAYMENT_TYPE_OPTIONS,
+ } = usePaymentsModel();
+
+ const { containerRef, height } = useContainerSize({ headerOffset: 55 });
+
return () => (
-
支付流水 - 开发中
+ {/* ===== 筛选区 ===== */}
+
+
+ (filterForm.timeRange = val)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* ===== 表格区 ===== */}
+
+ {/* ===== 汇总区(按图片样式:左对齐的两段加粗数字) ===== */}
+
+
+ 总支付金额:
+ {summary.value.totalPay.toFixed(2)}元
+
+
+ 总退款金额:
+ {summary.value.totalRefund.toFixed(2)}元
+
+
+
+
+ {/* 独立分页,右下方 */}
+
+
);
},
diff --git a/src/pages/finance/payments/model/usePaymentsModel.ts b/src/pages/finance/payments/model/usePaymentsModel.ts
new file mode 100644
index 0000000..4e99ac0
--- /dev/null
+++ b/src/pages/finance/payments/model/usePaymentsModel.ts
@@ -0,0 +1,201 @@
+import { reactive, toRef, Ref } from 'vue';
+import { message } from 'ant-design-vue';
+import { useState, useDebounce, useThrottleFn } from '@/hooks';
+
+// ============================================================
+// 常量
+// ============================================================
+
+/** 类型选项(筛选) */
+export const PAYMENT_TYPE_OPTIONS = [
+ { value: '', label: '全部' },
+ { value: '报名', label: '报名' },
+ { value: '取消报名', label: '取消报名' },
+ { value: '提现', label: '提现' },
+] as const;
+
+// ============================================================
+// 汇总假数据
+// ============================================================
+
+const MOCK_SUMMARY = {
+ totalPay: 113255.0,
+ totalRefund: 3255.0,
+};
+
+// ============================================================
+// 支付流水假数据(5 条)
+// ============================================================
+
+const MOCK_DATA = [
+ {
+ key: '1',
+ flowNo: 'xxxxxx',
+ orderNo: 'xxxxxxxx',
+ type: '报名',
+ nickName: '张三',
+ phone: '12345678997',
+ amount: 99.0,
+ thirdFlowNo: 'xxxxxxxxxxxxxxxxxxxx',
+ tradeTime: '2026-05-26 08:00:00',
+ },
+ {
+ key: '2',
+ flowNo: '',
+ orderNo: '',
+ type: '取消报名',
+ nickName: '李四',
+ phone: '12345678998',
+ amount: 100.0,
+ thirdFlowNo: '',
+ tradeTime: '2026-05-26 07:00:00',
+ },
+ {
+ key: '3',
+ flowNo: '',
+ orderNo: '',
+ type: '提现',
+ nickName: '王五',
+ phone: '12345678998',
+ amount: 1000.0,
+ thirdFlowNo: '',
+ tradeTime: '2026-05-26 06:00:00',
+ },
+ {
+ key: '4',
+ flowNo: '',
+ orderNo: '',
+ type: '报名',
+ nickName: '赵六',
+ phone: '13800138000',
+ amount: 199.0,
+ thirdFlowNo: '',
+ tradeTime: '2026-05-25 19:30:00',
+ },
+ {
+ key: '5',
+ flowNo: '',
+ orderNo: '',
+ type: '取消报名',
+ nickName: '钱七',
+ phone: '13900139001',
+ amount: 50.0,
+ thirdFlowNo: '',
+ tradeTime: '2026-05-25 15:20:00',
+ },
+];
+
+// ============================================================
+// Model
+// ============================================================
+
+/**
+ * 支付流水页数据模型
+ */
+export function usePaymentsModel() {
+ // ===== 筛选条件 =====
+ const filterForm = reactive({
+ timeRange: null as [string, string] | null,
+ searchUserName: '',
+ searchPhone: '',
+ type: '',
+ });
+
+ // 可搜索字段防抖
+ const { debouncedValue: debouncedUserName } = useDebounce(
+ toRef(filterForm, 'searchUserName') as Ref,
+ { delay: 300 },
+ );
+ const { debouncedValue: debouncedPhone } = useDebounce(
+ toRef(filterForm, 'searchPhone') as Ref,
+ { delay: 300 },
+ );
+
+ // ===== 汇总 =====
+ const [summary, setSummary] = useState(MOCK_SUMMARY);
+
+ // ===== 表格状态 =====
+ const [loading, setLoading] = useState(false);
+ const [dataSource, setDataSource] = useState(MOCK_DATA);
+ const [pagination, setPagination] = useState({
+ current: 1,
+ pageSize: 10,
+ total: MOCK_DATA.length,
+ });
+
+ // ===== 表格列配置 =====
+ const columns = [
+ { title: '流水号', dataIndex: 'flowNo', key: 'flowNo', width: 140 },
+ { title: '订单编号', dataIndex: 'orderNo', key: 'orderNo', width: 140 },
+ { title: '类型', dataIndex: 'type', key: 'type', width: 110 },
+ { title: '用户昵称', dataIndex: 'nickName', key: 'nickName', width: 120 },
+ { title: '手机号', dataIndex: 'phone', key: 'phone', width: 140 },
+ {
+ title: '金额',
+ dataIndex: 'amount',
+ key: 'amount',
+ width: 120,
+ customRender: ({ text }: { text: number }) => `${(text || 0).toFixed(2)}`,
+ },
+ { title: '第三方流水单号', dataIndex: 'thirdFlowNo', key: 'thirdFlowNo', width: 220 },
+ {
+ title: '交易时间',
+ dataIndex: 'tradeTime',
+ key: 'tradeTime',
+ width: 170,
+ },
+ ];
+
+ // ===== 方法 =====
+
+ /** 查询(节流 500ms) */
+ const handleSearch = useThrottleFn(async () => {
+ setLoading(true);
+ try {
+ console.log('搜索条件:', {
+ timeRange: filterForm.timeRange,
+ nickName: debouncedUserName.value,
+ phone: debouncedPhone.value,
+ type: filterForm.type,
+ });
+ // TODO: 替换为真实 API 调用
+ setDataSource(MOCK_DATA);
+ setPagination({ ...pagination.value, total: MOCK_DATA.length });
+ setSummary(MOCK_SUMMARY);
+ message.success('查询成功');
+ } catch (error: any) {
+ message.error(error.msg || '查询失败');
+ } finally {
+ setLoading(false);
+ }
+ }, 500);
+
+ /** 重置(节流 500ms) */
+ const handleReset = useThrottleFn(() => {
+ filterForm.timeRange = null;
+ filterForm.searchUserName = '';
+ filterForm.searchPhone = '';
+ filterForm.type = '';
+ setPagination({ current: 1, pageSize: 10, total: MOCK_DATA.length });
+ setDataSource(MOCK_DATA);
+ setSummary(MOCK_SUMMARY);
+ }, 500);
+
+ const handlePageChange = (page: number, pageSize: number) => {
+ setPagination({ ...pagination.value, current: page, pageSize });
+ handleSearch();
+ };
+
+ return {
+ filterForm,
+ loading,
+ dataSource,
+ columns,
+ summary,
+ pagination,
+ handleSearch,
+ handleReset,
+ handlePageChange,
+ PAYMENT_TYPE_OPTIONS: PAYMENT_TYPE_OPTIONS as any,
+ };
+}