diff --git a/apps/admin-web/src/App.tsx b/apps/admin-web/src/App.tsx
index fc7b7cd..6d653a4 100644
--- a/apps/admin-web/src/App.tsx
+++ b/apps/admin-web/src/App.tsx
@@ -31,6 +31,7 @@ import ResourcesPage from './pages/ResourcesPage';
import StoreBillsPage from './pages/StoreBillsPage';
import PartnerBillsPage from './pages/PartnerBillsPage';
import WineryBillsPage from './pages/WineryBillsPage';
+import LogisticsBillsPage from './pages/LogisticsBillsPage';
import TicketsPage from './pages/TicketsPage';
import SupportTicketsPage from './pages/SupportTicketsPage';
import InvoicesPage from './pages/InvoicesPage';
@@ -95,6 +96,7 @@ export default function App() {
} />
} />
} />
+ } />
} />
} />
} />
diff --git a/apps/admin-web/src/layouts/AdminLayout.tsx b/apps/admin-web/src/layouts/AdminLayout.tsx
index 74efdd4..726ac90 100644
--- a/apps/admin-web/src/layouts/AdminLayout.tsx
+++ b/apps/admin-web/src/layouts/AdminLayout.tsx
@@ -75,6 +75,7 @@ const MENU_ITEMS: MenuProps['items'] = [
{ key: '/finance/store-bills', label: '门店账单' },
{ key: '/finance/partner-bills', label: '合伙人账单' },
{ key: '/finance/winery-bills', label: '酒厂账单' },
+ { key: '/finance/logistics-bills', label: '物流对账' },
],
},
{
@@ -156,6 +157,7 @@ function menuAllowed(key: string, permissionKeys: string[]): boolean {
'/finance/store-bills': 'finance',
'/finance/partner-bills': 'finance',
'/finance/winery-bills': 'finance',
+ '/finance/logistics-bills': 'finance',
'benefit-group': 'benefit',
'/benefit/coupons': 'benefit',
'/benefit/ledgers': 'benefit',
diff --git a/apps/admin-web/src/pages/FulfillmentProvidersPage.tsx b/apps/admin-web/src/pages/FulfillmentProvidersPage.tsx
index 588196c..e53b4ef 100644
--- a/apps/admin-web/src/pages/FulfillmentProvidersPage.tsx
+++ b/apps/admin-web/src/pages/FulfillmentProvidersPage.tsx
@@ -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() {
仓配管理
- 注册第三方履约接口并填写凭证;仓库绑定后,推单将使用此处配置的 API 地址与密钥
+ 注册承运商接口凭证,并配置物流对账用的银行账户、结算方式与计价标准