周转箱

This commit is contained in:
liu
2026-08-11 19:09:10 +08:00
parent 5a3995d6ba
commit 06c7bd9f88
10 changed files with 306 additions and 651 deletions
+9
View File
@@ -19,6 +19,15 @@ export async function updateOrderStatus(id: number, status: number) {
});
}
/** 修改周转框/周转托盘数量(自动重算附加金额与订单总金额,仅已接单/采购中/配送中可改) */
export async function updateOrderContainer(id: number, data: { box_num: number; tray_num: number }) {
return createAxios({
url: `/order/store/${id}/container`,
method: 'put',
data,
});
}
/** 待汇总预览(按商品聚合) */
export async function getOrderSummary() {
return createAxios<IOrderSummaryRow[]>({
+8
View File
@@ -36,6 +36,14 @@ export default interface IStoreOrder {
added_amount: string;
box_num: number;
tray_num: number;
/** 周转框单价(列表接口附加) */
box_price?: string;
/** 周转托盘单价(列表接口附加) */
tray_price?: string;
/** 周转框金额(列表接口附加) */
box_amount?: string;
/** 周转托盘金额(列表接口附加) */
tray_amount?: string;
/** 0待接单 1已接单 2采购中 3配送中 4已完成 9已取消 */
status?: number;
remark?: string;
+107 -8
View File
@@ -3,7 +3,10 @@ import {
Button,
Descriptions,
Drawer,
Form,
InputNumber,
message,
Modal,
Popconfirm,
Space,
Table,
@@ -21,13 +24,17 @@ import type {
import type IStoreOrder from '@/domain/iStoreOrder.ts';
import type { IStoreOrderItem } from '@/domain/iStoreOrder.ts';
import { STORE_ORDER_STATUS_MAP } from '@/domain/iStoreOrder.ts';
import { getStoreOrder, updateOrderStatus } from '@/api/order/store.ts';
import { getStoreOrder, updateOrderContainer, updateOrderStatus } from '@/api/order/store.ts';
import { getStoreOptions } from '@/api/customer/store.ts';
import type IStore from '@/domain/iStore.ts';
import AuthButton from '@/components/AuthButton';
import {UnorderedListOutlined} from "@ant-design/icons";
const { Title, Text } = Typography;
/** 允许修改周转框/托盘数量的订单状态:已接单、采购中、配送中 */
const CONTAINER_EDITABLE_STATUS = [1, 2, 3];
/**
* 状态流转合法路径:待汇总→配送中/取消;已汇总→配送中;配送中→已完成
*/
@@ -51,6 +58,11 @@ const StoreOrderPage: React.FC = () => {
const [detail, setDetail] = useState<IStoreOrder | null>(null);
const [detailLoading, setDetailLoading] = useState(false);
const [containerOpen, setContainerOpen] = useState(false);
const [containerOrder, setContainerOrder] = useState<IStoreOrder | null>(null);
const [containerSaving, setContainerSaving] = useState(false);
const [containerForm] = Form.useForm<{ box_num: number; tray_num: number }>();
useEffect(() => {
getStoreOptions().then((res) => setStores(res.data.data ?? []));
}, []);
@@ -73,6 +85,32 @@ const StoreOrderPage: React.FC = () => {
await tableRef.current?.reload();
};
const openContainer = (record: IStoreOrder) => {
setContainerOrder(record);
containerForm.setFieldsValue({ box_num: record.box_num, tray_num: record.tray_num });
setContainerOpen(true);
};
const handleContainerSave = async (values: { box_num: number; tray_num: number }) => {
if (!containerOrder?.id) return;
setContainerSaving(true);
try {
await updateOrderContainer(containerOrder.id, values);
message.success('周转框/托盘数量已更新');
setContainerOpen(false);
await tableRef.current?.reload();
} finally {
setContainerSaving(false);
}
};
// 弹窗内实时预览:附加金额 = 框×单价 + 托盘×单价;订单总金额 = 商品金额 + 附加金额
const watchBoxNum = Number(Form.useWatch('box_num', containerForm) ?? 0);
const watchTrayNum = Number(Form.useWatch('tray_num', containerForm) ?? 0);
const previewAdded = watchBoxNum * Number(containerOrder?.box_price ?? 0)
+ watchTrayNum * Number(containerOrder?.tray_price ?? 0);
const previewTotal = Number(containerOrder?.product_amount ?? 0) + previewAdded;
const itemColumns: TableProps<IStoreOrderItem>['columns'] = [
{ title: '品名', dataIndex: 'product_name' },
{ title: '规格', dataIndex: 'product_spec', render: (v) => v || '-' },
@@ -245,12 +283,29 @@ const StoreOrderPage: React.FC = () => {
valueType: 'digit',
hideInForm: true,
},
];
const operateRender: XinTableProps<IStoreOrder>['operateRender'] = (record) => [
<Button key="detail" size="small" onClick={() => openDetail(record.id!)}>
</Button>,
{
title: '操作栏',
dataIndex: 'operate',
align: 'center',
hideInForm: true,
hideInSearch: true,
render: (_, record) => (
<Space orientation={'vertical'}>
<Button key="detail" type={'primary'} icon={<UnorderedListOutlined />} onClick={() => openDetail(record.id!)}>
</Button>
{
CONTAINER_EDITABLE_STATUS.includes(record.status ?? -1) ? (
<AuthButton key="container" auth="order.store.update">
<Button type={'primary'} onClick={() => openContainer(record)}>
</Button>
</AuthButton>
) : null
}
</Space>
)
}
];
const tableProps: XinTableProps<IStoreOrder> = {
@@ -259,7 +314,7 @@ const StoreOrderPage: React.FC = () => {
rowKey: 'id',
accessName: 'order.store',
tableRef,
operateRender,
operateShow: false,
formProps: false,
};
@@ -341,6 +396,50 @@ const StoreOrderPage: React.FC = () => {
</>
) : null}
</Drawer>
{/* 修改周转框/托盘数量 */}
<Modal
title="修改周转框/托盘"
open={containerOpen}
onCancel={() => setContainerOpen(false)}
onOk={() => containerForm.submit()}
confirmLoading={containerSaving}
okText="保存"
destroyOnHidden
>
<div className="py-2 text-gray-500">
{containerOrder?.order_no}
</div>
<Form form={containerForm} layout="vertical" onFinish={handleContainerSave}>
<Form.Item
label={`周转框数量(单价 ¥${containerOrder?.box_price ?? '0.00'}`}
name="box_num"
rules={[{ required: true, message: '请输入周转框数量' }]}
>
<InputNumber className="w-full" min={0} precision={0} placeholder="请输入周转框数量" />
</Form.Item>
<Form.Item
label={`周转托盘数量(单价 ¥${containerOrder?.tray_price ?? '0.00'}`}
name="tray_num"
rules={[{ required: true, message: '请输入周转托盘数量' }]}
>
<InputNumber className="w-full" min={0} precision={0} placeholder="请输入周转托盘数量" />
</Form.Item>
</Form>
<Space orientation="vertical" className="w-full rounded bg-gray-50 p-3">
<div>
<Text type="secondary"></Text>¥{containerOrder?.product_amount ?? '0.00'}
</div>
<div>
<Text type="secondary"></Text>
<Text strong>¥{previewAdded.toFixed(2)}</Text>
</div>
<div>
<Text type="secondary"></Text>
<Text strong type="danger">¥{previewTotal.toFixed(2)}</Text>
</div>
</Space>
</Modal>
</>
);
};