ERPTurbo_Admin/packages/app-operation/src/components/PaymentTask/PaymentTaskList.tsx
shenyifei b53d26ec65 feat(components): 添加供应商瓜农组件和支付任务管理功能
- 添加 SupplierFarmerList 和 SupplierStallList 组件
- 添加 PaymentTaskList、PaymentTaskCreate、InvoicerStatisticCard 等支付任务相关组件
- 将 MelonFarmerList 重命名为 SupplierFarmerList 并移至 Supplier 目录
- 在 BizContainer 中添加 supplier 类型渲染支持
- 为 BizDetail 组件添加 formContextMode 属性和渲染逻辑
- 添加供应商类型到 BizValueType 类型定义中
- 添加开票方统计卡片和订单供应商发票列表组件
- 更新组件导出配置和本地化文件
2026-01-06 11:10:08 +08:00

506 lines
13 KiB
TypeScript

import {
BizContainer,
BizValueType,
InvoicerStatisticCard,
ModeType,
OrderSupplierInvoiceList,
PaymentTaskCreate,
} from '@/components';
import { business } from '@/services';
import { calculateOrderSupplierStatistics } from '@/utils/calculateOrderSupplierStatistics';
import { formatCurrency } from '@/utils/format';
import { useIntl } from '@@/exports';
import {
ActionType,
ProColumns,
StatisticCard,
} from '@ant-design/pro-components';
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import { Image } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
interface IPaymentTaskListProps {
ghost?: boolean;
paymentTaskId?: BusinessAPI.PaymentTaskVO['paymentTaskId'];
search?: boolean;
onValueChange?: () => void;
mode?: ModeType;
trigger?: () => React.ReactNode;
}
export default function PaymentTaskList(props: IPaymentTaskListProps) {
const {
ghost = false,
paymentTaskId,
search = true,
mode = 'page',
trigger,
onValueChange,
} = props;
const intl = useIntl();
const intlPrefix = 'paymentTask';
const actionRef = useRef<ActionType>();
const [activeKey, setActiveKey] = useState<string>('PENDING');
const [statisticsPaymentTask, setStatisticsPaymentTask] =
useState<BusinessAPI.PaymentTaskStatisticsVO>();
const [loading, setLoading] = useState(true);
const initStatistic = async () => {
const { data } = await business.paymentTask.statisticsPaymentTask({
statisticsQry: {},
});
setStatisticsPaymentTask(data);
setLoading(false);
};
useEffect(() => {
initStatistic().then();
}, []);
/** 状态文本映射 */
const stateMap: Record<string, { text: string; color: string }> = {
PENDING: {
text: intl.formatMessage({ id: intlPrefix + '.state.pending' }),
color: 'orange',
},
PARTIAL: {
text: intl.formatMessage({ id: intlPrefix + '.state.partial' }),
color: 'blue',
},
COMPLETED: {
text: intl.formatMessage({ id: intlPrefix + '.state.completed' }),
color: 'green',
},
CANCELLED: {
text: intl.formatMessage({ id: intlPrefix + '.state.cancelled' }),
color: 'red',
},
};
const columns: ProColumns<BusinessAPI.PaymentTaskVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.paymentCode' }),
dataIndex: 'paymentCode',
key: 'paymentCode',
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.taskName' }),
dataIndex: 'taskName',
key: 'taskName',
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.supplier' }),
dataIndex: 'supplierVO',
key: 'supplier',
valueType: 'supplier',
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.totalAmount' }),
dataIndex: 'totalAmount',
key: 'totalAmount',
valueType: 'money',
search: false,
renderText: (value: number) => formatCurrency(value),
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.paidAmount' }),
dataIndex: 'paidAmount',
key: 'paidAmount',
valueType: 'money',
search: false,
renderText: (value: number) => formatCurrency(value),
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.unpaidAmount' }),
key: 'unpaidAmount',
search: false,
render: (_, record) => {
const unpaid = (record.totalAmount || 0) - (record.paidAmount || 0);
return <span>{formatCurrency(unpaid)}</span>;
},
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.orderCount' }),
dataIndex: 'orderCount',
key: 'orderCount',
search: false,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.state' }),
dataIndex: 'state',
key: 'state',
valueType: 'select',
valueEnum: {
PENDING: { text: stateMap.PENDING.text, status: 'Warning' },
PARTIAL: { text: stateMap.PARTIAL.text, status: 'Processing' },
COMPLETED: { text: stateMap.COMPLETED.text, status: 'Success' },
CANCELLED: { text: stateMap.CANCELLED.text, status: 'Error' },
},
search: false,
render: (_, record) => {
const stateInfo = stateMap[record.state] || stateMap.PENDING;
return <span style={{ color: stateInfo.color }}>{stateInfo.text}</span>;
},
},
];
const detailColumns: ProDescriptionsItemProps<
BusinessAPI.PaymentTaskVO,
BizValueType
>[] = columns as ProDescriptionsItemProps<
BusinessAPI.PaymentTaskVO,
BizValueType
>[];
const detailContext = (paymentTaskVO: BusinessAPI.PaymentTaskVO) => {
// 统计车次数据
const statistics = calculateOrderSupplierStatistics(
paymentTaskVO.orderSupplierVOList,
);
return [
// 统计卡片 Tab
{
label: intl.formatMessage({
id: intlPrefix + '.detail.tab.statistics',
}),
key: 'statistics',
children: (
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: 12,
marginBottom: 16,
}}
>
<InvoicerStatisticCard
title={intl.formatMessage({
id: intlPrefix + '.detail.invoiceType.selfInvoice',
})}
count={statistics.selfInvoiceCount}
amount={statistics.selfInvoiceAmount}
color={'#52c41a'}
/>
<InvoicerStatisticCard
title={intl.formatMessage({
id: intlPrefix + '.detail.invoiceType.proxyInvoice',
})}
count={statistics.proxyInvoiceCount}
amount={statistics.proxyInvoiceAmount}
color={'#1890ff'}
/>
<InvoicerStatisticCard
title={intl.formatMessage({
id: intlPrefix + '.detail.invoiceType.noInvoice',
})}
count={statistics.noInvoiceCount}
amount={statistics.noInvoiceAmount}
color={'#ff4d4f'}
/>
</div>
),
},
// 开票方统计 Tab
...(statistics.invoicerStatistics.length > 0
? [
{
label: intl.formatMessage({
id: intlPrefix + '.detail.tab.invoicerStatistics',
}),
key: 'invoicerStatistics',
children: (
<div
style={{
display: 'grid',
gridTemplateColumns:
'repeat(auto-fill, minmax(250px, 1fr))',
gap: 12,
}}
>
{statistics.invoicerStatistics.map((stat, index) => (
<InvoicerStatisticCard
key={index}
title={stat.supplierName}
count={stat.count}
amount={stat.amount}
color={'#722ed1'}
/>
))}
</div>
),
},
]
: []),
// 自开车次列表 Tab
...(statistics.selfInvoiceList.length > 0
? [
{
label: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.selfInvoiceList' },
{ count: statistics.selfInvoiceCount },
),
key: 'selfInvoiceList',
subTitle: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.selfInvoiceList.subTitle' },
{ count: statistics.selfInvoiceCount },
),
children: (
<OrderSupplierInvoiceList
rowKey="orderSupplierId"
dataSource={statistics.selfInvoiceList}
columns={[
{
title: '开票瓜农',
dataIndex: ['supplierInvoiceVO', 'supplierName'],
key: 'supplierName',
},
{
title: '发票编码',
dataIndex: 'supplierInvoiceVO',
key: 'invoiceSn',
render: (
supplierInvoiceVO: BusinessAPI.SupplierInvoiceVO,
) => {
return <a>{supplierInvoiceVO.invoiceSn}</a>;
},
},
]}
pagination={false}
size="small"
/>
),
},
]
: []),
// 代开车次列表 Tab
...(statistics.proxyInvoiceList.length > 0
? [
{
label: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.proxyInvoiceList' },
{ count: statistics.proxyInvoiceCount },
),
key: 'proxyInvoiceList',
subTitle: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.proxyInvoiceList.subTitle' },
{ count: statistics.proxyInvoiceCount },
),
children: (
<OrderSupplierInvoiceList
rowKey="orderSupplierId"
dataSource={statistics.proxyInvoiceList}
columns={[
{
title: '开票瓜农',
dataIndex: ['supplierInvoiceVO', 'supplierName'],
key: 'supplierName',
},
{
title: '发票编码',
dataIndex: ['supplierInvoiceVO', 'invoiceNo'],
key: 'invoiceNo',
},
]}
pagination={false}
size="small"
/>
),
},
]
: []),
// 无发票车次列表 Tab
...(statistics.noInvoiceList.length > 0
? [
{
label: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.noInvoiceList' },
{ count: statistics.noInvoiceCount },
),
key: 'noInvoiceList',
subTitle: intl.formatMessage(
{ id: intlPrefix + '.detail.tab.noInvoiceList.subTitle' },
{ count: statistics.noInvoiceCount },
),
children: (
<OrderSupplierInvoiceList
rowKey="orderSupplierId"
columns={[
{
title: '瓜农收款码',
dataIndex: 'wechatQr',
key: 'wechatQr',
render: (wechatQr: string) => {
if (!wechatQr) {
return '暂无微信收款码';
}
return (
<Image
src={wechatQr}
alt="微信收款码"
style={{ width: 40, height: 40 }}
/>
);
},
},
]}
dataSource={statistics.noInvoiceList}
pagination={false}
size="small"
/>
),
},
]
: []),
];
};
return (
<BizContainer<
typeof business.paymentTask,
BusinessAPI.PaymentTaskVO,
BusinessAPI.PaymentTaskPageQry,
BusinessAPI.PaymentTaskCreateCmd,
BusinessAPI.PaymentTaskUpdateCmd
>
rowKey={'paymentTaskId'}
permission={'operation-payment-task'}
func={business.paymentTask}
method={'paymentTask'}
methodUpper={'PaymentTask'}
intlPrefix={intlPrefix}
modeType={mode}
onValueChange={onValueChange}
container={{
fieldProps: {
ghost,
loading,
},
}}
remark={{
mode: 'editor',
}}
page={{
fieldProps: {
bordered: true,
...(!ghost && {
tableExtraRender: () => (
<StatisticCard.Group className={'statistics'}>
<StatisticCard
statistic={{
title: '全部',
value: statisticsPaymentTask?.totalCount || 0,
}}
/>
<StatisticCard.Operation>=</StatisticCard.Operation>
<StatisticCard
statistic={{
title: '待付款数量',
value: statisticsPaymentTask?.pendingCount || 0,
}}
/>
<StatisticCard.Operation>+</StatisticCard.Operation>
<StatisticCard
statistic={{
title: '部分付款数量',
value: statisticsPaymentTask?.partialCount || 0,
}}
/>
<StatisticCard.Operation>+</StatisticCard.Operation>
<StatisticCard
statistic={{
title: '已完成数量',
value: statisticsPaymentTask?.completedCount || 0,
}}
/>
<StatisticCard.Operation>+</StatisticCard.Operation>
<StatisticCard
statistic={{
title: '已取消数量',
value: statisticsPaymentTask?.cancelledCount || 0,
}}
/>
</StatisticCard.Group>
),
}),
ghost,
//@ts-ignore
search,
params: {
...(activeKey !== 'ALL' && {
state: activeKey as BusinessAPI.PaymentTaskVO['state'],
}),
taskType: 'MELON_FARMER',
},
toolbar: {
menu: {
type: 'tab',
activeKey: activeKey,
items: [
{
key: 'ALL',
label: intl.formatMessage({
id: intlPrefix + '.tab.all',
}),
},
{
key: 'PENDING',
label: intl.formatMessage({
id: intlPrefix + '.tab.pending',
}),
},
{
key: 'PARTIAL',
label: intl.formatMessage({
id: intlPrefix + '.tab.partial',
}),
},
{
key: 'COMPLETED',
label: intl.formatMessage({
id: intlPrefix + '.tab.completed',
}),
},
{
key: 'CANCELLED',
label: intl.formatMessage({
id: intlPrefix + '.tab.cancelled',
}),
},
],
onChange: (key) => {
setActiveKey(key as string);
},
},
actions: [
<PaymentTaskCreate
key={'create'}
onFinish={() => {
actionRef.current?.reload();
onValueChange?.();
}}
/>,
],
},
},
columns,
actionRef: actionRef,
}}
create={false}
update={{
formType: 'drawer',
formContext: [],
}}
destroy={{}}
detail={{
rowId: paymentTaskId,
formType: 'drawer',
columns: detailColumns,
formContext: detailContext,
formContextMode: 'flat',
trigger,
}}
/>
);
}