ERPTurbo_Admin/packages/app-operation/src/components/PaymentTask/PaymentTaskList.tsx
shenyifei b98026b9b7 feat(biz): 添加公司和付款任务类型支持
- 在BizContainer中新增company和paymentTask类型的支持
- 添加ProFormSelect组件用于公司选择
- 实现公司列表和付款任务列表的渲染功能
- 更新typing.ts中支持新的valueType类型
- 集成business服务的公司列表API
- 添加PaymentTaskFormItem和PaymentTaskList组件导出
- 优化付款任务创建和支付流程
- 修复付款凭证字段名称和数据结构
- 添加完整的付款记录列表页面和组件
- 更新本地化文件中的付款相关文案
- 修正数据类型定义中的ID字段类型
- 添加付款记录的统计和筛选功能
2026-01-07 15:20:17 +08:00

584 lines
15 KiB
TypeScript

import {
BizContainer,
BizValueType,
InvoicerStatisticCard,
ModeType,
OrderSupplierInvoiceList,
PaymentTaskCreate,
PaymentTaskPay,
SupplierFarmerList,
SupplierInvoiceList,
} 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, Space } 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.paymentTaskSn' }),
dataIndex: 'paymentTaskSn',
key: 'paymentTaskSn',
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.taskName' }),
dataIndex: 'taskName',
key: 'taskName',
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.supplier' }),
dataIndex: 'supplierVO',
key: 'supplierId',
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',
render: (
supplierInvoiceVO: BusinessAPI.SupplierInvoiceVO,
) => {
return (
supplierInvoiceVO && (
<SupplierFarmerList
ghost={true}
mode={'detail'}
supplierId={supplierInvoiceVO.supplierId}
trigger={() => (
<a>{supplierInvoiceVO.supplierName}</a>
)}
/>
)
);
},
},
{
title: '发票编码',
dataIndex: 'supplierInvoiceVO',
key: 'invoiceSn',
render: (
supplierInvoiceVO: BusinessAPI.SupplierInvoiceVO,
) => {
return (
<SupplierInvoiceList
ghost={true}
mode={'detail'}
supplierInvoiceId={
supplierInvoiceVO.supplierInvoiceId
}
trigger={() => (
<Space>
<a>{supplierInvoiceVO.invoiceSn}</a>
</Space>
)}
/>
);
},
},
]}
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',
render: (
supplierInvoiceVO: BusinessAPI.SupplierInvoiceVO,
) => {
return (
supplierInvoiceVO && (
<SupplierFarmerList
ghost={true}
mode={'detail'}
supplierId={supplierInvoiceVO.supplierId}
trigger={() => (
<a>{supplierInvoiceVO.supplierName}</a>
)}
/>
)
);
},
},
{
title: '发票编码',
dataIndex: 'supplierInvoiceVO',
key: 'invoiceSn',
render: (
supplierInvoiceVO: BusinessAPI.SupplierInvoiceVO,
) => {
return (
<SupplierInvoiceList
ghost={true}
mode={'detail'}
supplierInvoiceId={
supplierInvoiceVO.supplierInvoiceId
}
trigger={() => (
<Space>
<a>{supplierInvoiceVO.invoiceSn}</a>
</Space>
)}
/>
);
},
},
]}
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={{
ghost,
fieldProps: {
loading,
},
}}
remark={{
mode: 'editor',
}}
page={{
fieldProps: {
actionRef: actionRef,
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,
options: (paymentTaskVO: BusinessAPI.PaymentTaskVO, actionRef) => {
return [
// 付款抽屉
<PaymentTaskPay
insertPosition={'before:view'}
key={'pay'}
paymentTaskVO={paymentTaskVO}
onFinish={() => {
actionRef.current?.reload();
onValueChange?.();
}}
/>,
];
},
}}
create={false}
update={{
formType: 'drawer',
formContext: [],
}}
destroy={{}}
detail={{
rowId: paymentTaskId,
formType: 'drawer',
columns: detailColumns,
formContext: detailContext,
formContextMode: 'flat',
trigger,
}}
/>
);
}