修复BUG
This commit is contained in:
@@ -127,6 +127,8 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
|
||||
// 供应商采购明细页签
|
||||
const [supplierId, setSupplierId] = useState<number>(0);
|
||||
/** 市场筛选('' = 全部市场) */
|
||||
const [marketFilter, setMarketFilter] = useState<string>('');
|
||||
|
||||
// 导出弹窗:商品明细(供应商筛选)/ 门店购买详情 / 供应商采购明细
|
||||
const [itemExportOpen, setItemExportOpen] = useState(false);
|
||||
@@ -147,11 +149,23 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
return Array.from(map, ([id, name]) => ({ id, name }));
|
||||
}, [detail?.items]);
|
||||
|
||||
/** 供应商采购明细行:按供应商过滤矩阵行,金额=数量×成本价(成本口径) */
|
||||
/** 当前供应商在采购单内出现的市场列表(市场筛选下拉选项) */
|
||||
const supplierMarkets = useMemo(() => {
|
||||
const markets = new Set<string>();
|
||||
(detail?.items ?? []).forEach((row) => {
|
||||
if (row.supplier_id === supplierId && row.market) {
|
||||
markets.add(row.market);
|
||||
}
|
||||
});
|
||||
return Array.from(markets);
|
||||
}, [detail?.items, supplierId]);
|
||||
|
||||
/** 供应商采购明细行:按供应商+市场过滤矩阵行,金额=数量×成本价(成本口径) */
|
||||
const supplierItems = useMemo<IPurchaseSupplierItem[]>(() => {
|
||||
if (!detail || supplierId <= 0) return [];
|
||||
return detail.items
|
||||
.filter((row) => row.supplier_id === supplierId)
|
||||
.filter((row) => marketFilter === '' || (row.market ?? '') === marketFilter)
|
||||
.map((row) => ({
|
||||
product_id: row.product_id,
|
||||
product_name: row.product_name,
|
||||
@@ -163,7 +177,7 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
weight: String(row.weight),
|
||||
amount: (row.quantity * Number(row.cost_price)).toFixed(2),
|
||||
}));
|
||||
}, [detail, supplierId]);
|
||||
}, [detail, supplierId, marketFilter]);
|
||||
|
||||
// 生成账单(已完成采购单按门店生成:填写配送费/周转筐/托盘数量,金额只读)
|
||||
const [billOpen, setBillOpen] = useState(false);
|
||||
@@ -426,6 +440,8 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
delivery_fee: row.bill ? Number(row.bill.delivery_fee) : 0,
|
||||
box_num: row.bill ? row.bill.box_num : 0,
|
||||
tray_num: row.bill ? row.bill.tray_num : 0,
|
||||
after_sale: row.bill?.after_sale ?? '',
|
||||
remark: row.bill?.remark ?? '',
|
||||
})),
|
||||
});
|
||||
} finally {
|
||||
@@ -464,7 +480,7 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 明细矩阵列:品名/供应商/参考零售价/包规/单位/成本 + 每门店一列(数量)+ 合计 + 操作 */
|
||||
/** 明细矩阵列:品名/供应商/单价/包规/单位/成本 + 每门店一列(数量)+ 合计 + 操作 */
|
||||
const buildItemColumns = (): TableProps<IPurchaseDetailRow>['columns'] => {
|
||||
const fixed: NonNullable<TableProps<IPurchaseDetailRow>['columns']> = [
|
||||
{ title: '品名', dataIndex: 'product_name', width: 120, align: 'center' },
|
||||
@@ -477,7 +493,7 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
},
|
||||
{ title: '市场', dataIndex: 'market', width: 90, align: 'center', render: (v) => v || '-' },
|
||||
{
|
||||
title: '参考零售价',
|
||||
title: '单价',
|
||||
key: 'retail_price',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
@@ -578,12 +594,12 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
/** 门店购买详情列:商品/市场/购买参考零售价(单价÷包规)/包规/单位/单价/数量/预计金额 + 操作 */
|
||||
/** 门店购买详情列:商品/市场/购买单价(单价÷包规)/包规/单位/单价/数量/预计金额 + 操作 */
|
||||
const storeColumns: TableProps<IPurchaseStoreItem>['columns'] = [
|
||||
{ title: '商品', dataIndex: 'product_name', width: 160, align: 'center' },
|
||||
{ title: '市场', dataIndex: 'market', width: 90, align: 'center', render: (v) => v || '-' },
|
||||
{
|
||||
title: '参考零售价',
|
||||
title: '单价',
|
||||
key: 'retail_price',
|
||||
width: 130,
|
||||
align: 'center',
|
||||
@@ -1082,13 +1098,26 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
<Text>选择供应商:</Text>
|
||||
<Select
|
||||
value={supplierId || undefined}
|
||||
onChange={(value) => setSupplierId(value)}
|
||||
onChange={(value) => {
|
||||
setSupplierId(value);
|
||||
setMarketFilter('');
|
||||
}}
|
||||
placeholder="选择供应商"
|
||||
className="w-60!"
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
options={purchaseSuppliers.map((s) => ({ value: s.id, label: s.name }))}
|
||||
/>
|
||||
<Text>市场:</Text>
|
||||
<Select
|
||||
value={marketFilter}
|
||||
onChange={setMarketFilter}
|
||||
className="w-40!"
|
||||
options={[
|
||||
{ value: '', label: '全部市场' },
|
||||
...supplierMarkets.map((m) => ({ value: m, label: m })),
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<AuthButton auth="purchase.order.export">
|
||||
<Button
|
||||
@@ -1404,14 +1433,14 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
confirmLoading={billSaving}
|
||||
okText="确认生成"
|
||||
okButtonProps={{ disabled: billAllGenerated }}
|
||||
width={960}
|
||||
width={1280}
|
||||
destroyOnHidden
|
||||
>
|
||||
<Spin spinning={billLoading}>
|
||||
{billPrepare && (
|
||||
<>
|
||||
<div className="py-2 text-gray-500">
|
||||
每个门店单独生成一张账单;商品金额由订单汇总不可修改,请填写各门店的配送费与周转筐/托盘数量(正数=压筐附加金额,负数=回筐抵扣金额)。
|
||||
每个门店单独生成一张账单;商品金额由订单汇总不可修改,请填写各门店的配送费、周转筐/托盘数量(正数=压筐附加金额,负数=回筐抵扣金额)与售后/备注(可选,随账单存档)。
|
||||
{billAllGenerated ? '该采购单已全部生成账单,仅可查看。' : '生成后采购单中的全部订单将关联到对应门店账单。'}
|
||||
</div>
|
||||
<Form form={billForm} layout="vertical" onFinish={handleBillSave}>
|
||||
@@ -1424,6 +1453,8 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
<div className="w-32 shrink-0 text-center">配送费(元)</div>
|
||||
<div className="w-32 shrink-0 text-center">周转筐(¥{billPrepare.stores[0]?.box_price ?? '0.00'}/个)</div>
|
||||
<div className="w-32 shrink-0 text-center">周转托盘(¥{billPrepare.stores[0]?.tray_price ?? '0.00'}/个)</div>
|
||||
<div className="w-36 shrink-0 text-center">售后</div>
|
||||
<div className="w-36 shrink-0 text-center">备注</div>
|
||||
<div className="w-28 shrink-0 text-center">附加金额</div>
|
||||
<div className="flex-1 text-center">账单总金额</div>
|
||||
</div>
|
||||
@@ -1482,6 +1513,26 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
placeholder="正压负回"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
className="m-0! w-36 shrink-0 px-1!"
|
||||
name={[field.name, 'after_sale']}
|
||||
>
|
||||
<Input
|
||||
maxLength={255}
|
||||
disabled={billed}
|
||||
placeholder="售后说明(可选)"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
className="m-0! w-36 shrink-0 px-1!"
|
||||
name={[field.name, 'remark']}
|
||||
>
|
||||
<Input
|
||||
maxLength={255}
|
||||
disabled={billed}
|
||||
placeholder="备注(可选)"
|
||||
/>
|
||||
</Form.Item>
|
||||
<div className="w-28 shrink-0 text-center">
|
||||
¥{(billed ? Number(row.bill!.added_amount) : billPreview[field.name]?.added ?? 0).toFixed(2)}
|
||||
</div>
|
||||
@@ -1638,7 +1689,7 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
{/* 供应商采购明细导出:当前供应商 / 全部供应商(多工作表) */}
|
||||
{/* 供应商采购明细导出:当前供应商 / 全部供应商(按「供应商×市场」拆分工作表) */}
|
||||
<Modal
|
||||
title="导出供应商采购明细"
|
||||
open={supplierExportOpen}
|
||||
@@ -1655,13 +1706,16 @@ const PurchaseOrderPage: React.FC = () => {
|
||||
okText="导出"
|
||||
destroyOnHidden
|
||||
>
|
||||
<div className="py-2 text-gray-500">
|
||||
导出 XLSX 按「供应商 × 市场」拆分工作表,列序:品名、汇总、市场、各门店明细,有数据的单元格突出显示。
|
||||
</div>
|
||||
<Radio.Group
|
||||
className="py-2"
|
||||
value={supplierExportScope}
|
||||
onChange={(e) => setSupplierExportScope(e.target.value)}
|
||||
options={[
|
||||
{ value: 'current', label: `当前供应商(${purchaseSuppliers.find((s) => s.id === supplierId)?.name ?? '-'})` },
|
||||
{ value: 'all', label: '全部供应商(合并为一个 XLSX,每供应商一个工作表)' },
|
||||
{ value: 'all', label: '全部供应商(合并为一个 XLSX,每供应商×市场一个工作表)' },
|
||||
]}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user