物流对账单

This commit is contained in:
2026-07-26 09:51:33 +08:00
parent 2b7ef65cce
commit 19cb312465
21 changed files with 1909 additions and 27 deletions
@@ -2,8 +2,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import {
Alert,
Button,
Divider,
Form,
Input,
InputNumber,
Modal,
Select,
Space,
@@ -14,10 +16,13 @@ import {
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import {
DEFAULT_XFX_LOGISTICS_PRICING,
FULFILLMENT_PROVIDER_STATUS_LABELS,
FULFILLMENT_PROVIDER_TYPE_LABELS,
FulfillmentProviderStatus,
FulfillmentProviderType,
LOGISTICS_SETTLEMENT_METHOD_LABELS,
LogisticsSettlementMethod,
isXfxProviderCode,
type FulfillmentProviderDto,
} from '@dukang/shared-types';
@@ -32,6 +37,9 @@ const STATUS_OPTIONS = Object.entries(FULFILLMENT_PROVIDER_STATUS_LABELS).map(([
value,
label,
}));
const SETTLEMENT_OPTIONS = Object.entries(LOGISTICS_SETTLEMENT_METHOD_LABELS).map(
([value, label]) => ({ value, label }),
);
const SIGN_OPTIONS = [
{ value: 'MD5', label: 'MD5' },
{ value: 'HMAC-SHA256', label: 'HMAC-SHA256' },
@@ -77,6 +85,12 @@ export default function FulfillmentProvidersPage() {
status: FulfillmentProviderStatus.ACTIVE,
apiUrl: DEFAULT_XFX_API_URL,
signType: 'MD5',
settlementMethod: LogisticsSettlementMethod.PREPAID,
baseBottles: DEFAULT_XFX_LOGISTICS_PRICING.baseBottles,
baseFee: DEFAULT_XFX_LOGISTICS_PRICING.baseFee,
extraBottleFee: DEFAULT_XFX_LOGISTICS_PRICING.extraBottleFee,
boxBottles: DEFAULT_XFX_LOGISTICS_PRICING.boxBottles,
boxFee: DEFAULT_XFX_LOGISTICS_PRICING.boxFee,
});
setOpen(true);
}
@@ -84,6 +98,7 @@ export default function FulfillmentProvidersPage() {
function openEdit(row: FulfillmentProviderDto) {
setEditRow(row);
const xfx = row.xiaofeixiaConfig;
const pricing = row.pricingRules;
form.setFieldsValue({
code: row.code,
name: row.name,
@@ -94,6 +109,16 @@ export default function FulfillmentProvidersPage() {
apiKey: '',
signType: xfx?.signType || 'MD5',
appId: xfx?.appId || '',
bankAccountName: row.bankAccountName || '',
bankName: row.bankName || '',
bankBranch: row.bankBranch || '',
bankAccountNo: row.bankAccountNo || '',
settlementMethod: row.settlementMethod || LogisticsSettlementMethod.PREPAID,
baseBottles: pricing?.baseBottles ?? DEFAULT_XFX_LOGISTICS_PRICING.baseBottles,
baseFee: pricing?.baseFee ?? DEFAULT_XFX_LOGISTICS_PRICING.baseFee,
extraBottleFee: pricing?.extraBottleFee ?? DEFAULT_XFX_LOGISTICS_PRICING.extraBottleFee,
boxBottles: pricing?.boxBottles ?? DEFAULT_XFX_LOGISTICS_PRICING.boxBottles,
boxFee: pricing?.boxFee ?? DEFAULT_XFX_LOGISTICS_PRICING.boxFee,
});
setOpen(true);
}
@@ -104,6 +129,18 @@ export default function FulfillmentProvidersPage() {
name: v.name,
type: v.type,
status: v.status,
bankAccountName: v.bankAccountName || null,
bankName: v.bankName || null,
bankBranch: v.bankBranch || null,
bankAccountNo: v.bankAccountNo || null,
settlementMethod: v.settlementMethod,
pricingRules: {
baseBottles: Number(v.baseBottles),
baseFee: Number(v.baseFee),
extraBottleFee: Number(v.extraBottleFee),
boxBottles: v.boxBottles != null ? Number(v.boxBottles) : undefined,
boxFee: v.boxFee != null ? Number(v.boxFee) : undefined,
},
};
if (isXfxProviderCode(String(v.code)) && v.type === FulfillmentProviderType.API) {
@@ -144,6 +181,19 @@ export default function FulfillmentProvidersPage() {
dataIndex: 'type',
render: (v) => FULFILLMENT_PROVIDER_TYPE_LABELS[v as FulfillmentProviderType] || v,
},
{
title: '结算',
dataIndex: 'settlementMethod',
width: 100,
render: (v) =>
LOGISTICS_SETTLEMENT_METHOD_LABELS[v as LogisticsSettlementMethod] || v || '—',
},
{
title: '充值余额',
dataIndex: 'prepaidBalance',
width: 100,
render: (v) => `¥${Number(v || 0).toFixed(2)}`,
},
{
title: '状态',
dataIndex: 'status',
@@ -188,7 +238,7 @@ export default function FulfillmentProvidersPage() {
</Typography.Title>
<Typography.Text type="secondary">
使 API
</Typography.Text>
</div>
<Button type="primary" onClick={openCreate}>
@@ -200,7 +250,7 @@ export default function FulfillmentProvidersPage() {
type="info"
showIcon
style={{ marginBottom: 16 }}
message="小飞侠配置已从「系统设置 → 同城配送」迁至本页。寄件地址以仓库联系人/地址为准。"
message="小飞侠默认计价:2瓶6元,加一瓶+2元,6瓶一箱14元。财务对账见「财务 → 物流对账」。"
/>
<Table rowKey="id" loading={loading} columns={columns} dataSource={rows} pagination={false} />
@@ -210,7 +260,7 @@ export default function FulfillmentProvidersPage() {
open={open}
onCancel={() => setOpen(false)}
onOk={() => void submit()}
width={560}
width={640}
destroyOnClose
>
<Form form={form} layout="vertical">
@@ -227,11 +277,58 @@ export default function FulfillmentProvidersPage() {
<Select options={STATUS_OPTIONS} />
</Form.Item>
<Divider orientation="left"></Divider>
<Form.Item name="settlementMethod" label="结算方式" rules={[{ required: true }]}>
<Select options={SETTLEMENT_OPTIONS} />
</Form.Item>
<Form.Item name="bankAccountName" label="收款户名">
<Input />
</Form.Item>
<Form.Item name="bankName" label="开户银行">
<Input />
</Form.Item>
<Form.Item name="bankBranch" label="开户支行">
<Input />
</Form.Item>
<Form.Item name="bankAccountNo" label="银行账号">
<Input />
</Form.Item>
<Space wrap style={{ width: '100%' }}>
<Form.Item
name="baseBottles"
label="起送瓶数"
rules={[{ required: true }]}
style={{ marginBottom: 12 }}
>
<InputNumber min={1} style={{ width: 120 }} />
</Form.Item>
<Form.Item
name="baseFee"
label="起送费用(元)"
rules={[{ required: true }]}
style={{ marginBottom: 12 }}
>
<InputNumber min={0} precision={2} style={{ width: 120 }} />
</Form.Item>
<Form.Item
name="extraBottleFee"
label="加一瓶(元)"
rules={[{ required: true }]}
style={{ marginBottom: 12 }}
>
<InputNumber min={0} precision={2} style={{ width: 120 }} />
</Form.Item>
<Form.Item name="boxBottles" label="箱规瓶数" style={{ marginBottom: 12 }}>
<InputNumber min={1} style={{ width: 120 }} />
</Form.Item>
<Form.Item name="boxFee" label="一箱费用(元)" style={{ marginBottom: 12 }}>
<InputNumber min={0} precision={2} style={{ width: 120 }} />
</Form.Item>
</Space>
{showXfxFields && (
<>
<Typography.Title level={5} style={{ marginTop: 8 }}>
</Typography.Title>
<Divider orientation="left"></Divider>
<Form.Item
name="apiUrl"
label="API 地址"