178 lines
4.3 KiB
Vue
178 lines
4.3 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* 文件职责:交易流水列表表格与本页汇总行。
|
|
*/
|
|
import type { TablePaginationConfig, TableProps } from 'ant-design-vue';
|
|
|
|
import type { FinanceTransactionListItemDto } from '#/api/finance';
|
|
|
|
import { h } from 'vue';
|
|
|
|
import { Button, Table, Tag } from 'ant-design-vue';
|
|
|
|
import {
|
|
formatCurrency,
|
|
formatSignedAmount,
|
|
resolveAmountToneClass,
|
|
resolveTransactionTypeTagColor,
|
|
} from '../composables/transaction-page/helpers';
|
|
|
|
interface PaginationState {
|
|
page: number;
|
|
pageSize: number;
|
|
total: number;
|
|
}
|
|
|
|
interface Props {
|
|
loading: boolean;
|
|
pageIncomeAmount: number;
|
|
pageRefundAmount: number;
|
|
pagination: PaginationState;
|
|
rows: FinanceTransactionListItemDto[];
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const emit = defineEmits<{
|
|
(event: 'detail', transactionId: string): void;
|
|
(event: 'orderDetail', orderNo: string): void;
|
|
(event: 'pageChange', page: number, pageSize: number): void;
|
|
}>();
|
|
|
|
const columns: TableProps['columns'] = [
|
|
{
|
|
title: '流水号',
|
|
dataIndex: 'transactionNo',
|
|
width: 180,
|
|
customRender: ({ record }) =>
|
|
h(
|
|
Button,
|
|
{
|
|
type: 'link',
|
|
class: 'ft-link-action ft-mono',
|
|
onClick: () => emit('detail', String(record.transactionId ?? '')),
|
|
},
|
|
() => String(record.transactionNo ?? '--'),
|
|
),
|
|
},
|
|
{
|
|
title: '关联订单',
|
|
dataIndex: 'orderNo',
|
|
width: 170,
|
|
customRender: ({ record }) => {
|
|
const orderNo = String(record.orderNo ?? '').trim();
|
|
if (!orderNo) {
|
|
return h('span', { class: 'ft-mono' }, '--');
|
|
}
|
|
|
|
return h(
|
|
Button,
|
|
{
|
|
type: 'link',
|
|
class: 'ft-link-action ft-mono',
|
|
onClick: () => emit('orderDetail', orderNo),
|
|
},
|
|
() => `#${orderNo}`,
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '类型',
|
|
dataIndex: 'typeText',
|
|
width: 120,
|
|
customRender: ({ record }) =>
|
|
h(
|
|
Tag,
|
|
{ color: resolveTransactionTypeTagColor(String(record.type ?? '')) },
|
|
() => String(record.typeText ?? '--'),
|
|
),
|
|
},
|
|
{
|
|
title: '渠道',
|
|
dataIndex: 'channel',
|
|
width: 90,
|
|
},
|
|
{
|
|
title: '支付方式',
|
|
dataIndex: 'paymentMethod',
|
|
width: 110,
|
|
},
|
|
{
|
|
title: '金额',
|
|
dataIndex: 'amount',
|
|
width: 140,
|
|
align: 'right',
|
|
customRender: ({ record }) => {
|
|
const amount = Number(record.amount || 0);
|
|
return h(
|
|
'span',
|
|
{
|
|
class: `ft-amount ${resolveAmountToneClass(amount, Boolean(record.isIncome))}`,
|
|
},
|
|
formatSignedAmount(amount, Boolean(record.isIncome)),
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '交易时间',
|
|
dataIndex: 'occurredAt',
|
|
width: 180,
|
|
customRender: ({ text }) => h('span', { class: 'ft-time' }, String(text)),
|
|
},
|
|
{
|
|
title: '备注',
|
|
dataIndex: 'remark',
|
|
ellipsis: true,
|
|
customRender: ({ text }) =>
|
|
h(
|
|
'span',
|
|
{
|
|
class: 'ft-remark',
|
|
title: String(text ?? ''),
|
|
},
|
|
String(text || '--'),
|
|
),
|
|
},
|
|
];
|
|
|
|
function handleTableChange(next: TablePaginationConfig) {
|
|
emit('pageChange', Number(next.current || 1), Number(next.pageSize || 20));
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="ft-table-card">
|
|
<Table
|
|
row-key="transactionId"
|
|
:columns="columns"
|
|
:data-source="props.rows"
|
|
:loading="props.loading"
|
|
:pagination="{
|
|
current: props.pagination.page,
|
|
pageSize: props.pagination.pageSize,
|
|
total: props.pagination.total,
|
|
showSizeChanger: true,
|
|
pageSizeOptions: ['20', '50', '100'],
|
|
showTotal: (total: number) => `共 ${total} 条`,
|
|
}"
|
|
@change="handleTableChange"
|
|
>
|
|
<template #summary>
|
|
<Table.Summary.Row class="ft-summary-row">
|
|
<Table.Summary.Cell :index="0" :col-span="5" align="right">
|
|
本页合计
|
|
</Table.Summary.Cell>
|
|
<Table.Summary.Cell :index="5" align="right">
|
|
<span class="ft-summary-text">
|
|
收入 {{ formatCurrency(props.pageIncomeAmount) }} / 退款
|
|
{{ formatCurrency(props.pageRefundAmount) }}
|
|
</span>
|
|
</Table.Summary.Cell>
|
|
<Table.Summary.Cell :index="6" />
|
|
<Table.Summary.Cell :index="7" />
|
|
</Table.Summary.Row>
|
|
</template>
|
|
</Table>
|
|
</div>
|
|
</template>
|