import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { Alert, Button, Card, Col, Descriptions, Form, Image, Input, InputNumber, Row, Select, Space, Tabs, Tag, Typography, message, } from 'antd'; import { request } from '../lib/api'; type XfxConfig = { provider: string; activeProvider: string; apiUrl: string; appId: string | null; mchId: string | null; mchIdMasked: string | null; hasApiKey: boolean; signType: string; ready: boolean; source?: string; hint?: string; }; type ApiResult = { ok: boolean; elapsedMs: number; data?: unknown; error?: string; code?: string; provider?: string; raw?: unknown; }; const CREATE_DEFAULTS = { outNumber: `TEST-${Date.now()}`, fromName: '杜康仓库', fromMobile: '13800000000', fromAddress: '河南省郑州市金水区', fromAddressDetail: '杜康酒业仓', fromLng: 113.665, fromLat: 34.757, toName: '测试收货人', toMobile: '13800000001', toAddress: '河南省郑州市二七区', toAddressDetail: '测试路 1 号', toLng: 113.640, toLat: 34.720, goodsName: '杜康酒', goodsNum: 2, weight: 2, payMode: '1', remark: 'Admin 联调测试', }; function ResultPanel({ result }: { result: ApiResult | null }) { if (!result) return 点击「调用接口」后在此显示响应; const display = (() => { if (!result.data || typeof result.data !== 'object') return result; const data = result.data as { count?: number; data?: string[] }; if (!Array.isArray(data.data)) return result; return { ...result, data: { ...data, data: data.data.map((item) => typeof item === 'string' && item.length > 120 ? `${item.slice(0, 80)}…(len=${item.length})` : item, ), }, }; })(); return (
{result.ok ? '成功' : '失败'} {result.elapsedMs} ms {result.code && code: {result.code}}
        {JSON.stringify(display, null, 2)}
      
); } export default function XiaofeixiaTestPage() { const [config, setConfig] = useState(null); const [loading, setLoading] = useState(false); const [result, setResult] = useState(null); const [freightForm] = Form.useForm(); const [coverageForm] = Form.useForm(); const [createForm] = Form.useForm(); const [queryForm] = Form.useForm(); const [batchForm] = Form.useForm(); const [trackForm] = Form.useForm(); const [signPhotoForm] = Form.useForm(); const [cancelForm] = Form.useForm(); const [signPhotoPreview, setSignPhotoPreview] = useState([]); useEffect(() => { void request('/admin/courier/xiaofeixia/config').then(setConfig); createForm.setFieldsValue(CREATE_DEFAULTS); freightForm.setFieldsValue({ weight: 2 }); coverageForm.setFieldsValue({ toAddress: '河南省郑州市二七区测试路1号' }); }, [createForm, freightForm, coverageForm]); async function invoke(path: string, body: unknown) { setLoading(true); setResult(null); try { const res = await request(path, { method: 'POST', body: JSON.stringify(body), }); setResult(res); if (path.endsWith('/get-sign-photos')) { const data = (res.data as { data?: string[] } | undefined)?.data; setSignPhotoPreview(Array.isArray(data) ? data.filter((u) => typeof u === 'string') : []); } else { setSignPhotoPreview([]); } if (res.ok) message.success('调用成功'); else message.warning(res.error || '调用失败'); } catch (e) { const err = e instanceof Error ? e.message : String(e); message.error(err); setResult({ ok: false, elapsedMs: 0, error: err }); setSignPhotoPreview([]); } finally { setLoading(false); } } function parseList(text?: string) { return (text ?? '').split(/[,,\s]+/).map((s) => s.trim()).filter(Boolean); } return (
小飞侠接口联调 通过 HQ 后台直接调用后端封装的小飞侠 API(cmd 100101~100301,含签收图片 100108)。凭证请在 仓配管理 中配置;联调会优先使用仓配管理里启用的小飞侠承运商。 {config && ( {config.activeProvider} {config.apiUrl} {config.mchIdMasked || '—'} {config.signType} {config.hasApiKey ? 已配置 : 未配置} {config.ready ? 可调用 : 配置不完整} {config.source === 'fulfillment_provider' ? '仓配管理' : '环境变量(兼容)'} {config.hint ? ` · ${config.hint}` : ''} {!config.ready && ( )} )} void invoke('/admin/courier/xiaofeixia/estimate-freight', v)}> ), }, { key: 'coverage', label: '配送范围 (100301)', children: (
void invoke('/admin/courier/xiaofeixia/check-coverage', v)}>
), }, { key: 'create', label: '创建订单 (100101)', children: (
void invoke('/admin/courier/xiaofeixia/create-shipment', v)}> 寄件人 收件人
), }, { key: 'query', label: '查询订单 (100104)', children: (
void invoke('/admin/courier/xiaofeixia/get-shipment', v)}>
), }, { key: 'batch', label: '批量查询 (100106)', children: (
void invoke('/admin/courier/xiaofeixia/batch-get-shipments', { trackingNumbers: parseList(v.trackingNumbersText), outNumbers: parseList(v.outNumbersText), })}>
), }, { key: 'track', label: '路由查询 (100102)', children: (
void invoke('/admin/courier/xiaofeixia/get-track', v)}>
), }, { key: 'signPhotos', label: '签收图片 (100108)', children: (
void invoke('/admin/courier/xiaofeixia/get-sign-photos', v)} >
), }, { key: 'cancel', label: '取消订单 (100103)', children: (
void invoke('/admin/courier/xiaofeixia/cancel-shipment', v)}>
), }, ]} /> {signPhotoPreview.length > 0 ? (
签收照片预览({signPhotoPreview.length}) {signPhotoPreview.map((url, index) => ( ))}
) : null}
); }