forked from yoone/WEB
716 lines
21 KiB
TypeScript
716 lines
21 KiB
TypeScript
import { productcontrollerSearchproducts } from '@/servers/api/product';
|
|
import {
|
|
stockcontrollerCanceltransfer,
|
|
stockcontrollerCreatetransfer,
|
|
stockcontrollerGetallstockpoints,
|
|
stockcontrollerGetpurchaseorder,
|
|
stockcontrollerGettransfers,
|
|
stockcontrollerLosttransfer,
|
|
stockcontrollerReceivetransfer,
|
|
stockcontrollerUpdatetransfer,
|
|
} from '@/servers/api/stock';
|
|
import { EditOutlined, PlusOutlined } from '@ant-design/icons';
|
|
import {
|
|
ActionType,
|
|
DrawerForm,
|
|
PageContainer,
|
|
ProColumns,
|
|
ProForm,
|
|
ProFormDatePicker,
|
|
ProFormDependency,
|
|
ProFormDigit,
|
|
ProFormList,
|
|
ProFormSelect,
|
|
ProFormText,
|
|
ProFormTextArea,
|
|
ProTable,
|
|
} from '@ant-design/pro-components';
|
|
import { App, Button, Divider, Form, Popconfirm } from 'antd';
|
|
import { useRef } from 'react';
|
|
|
|
const TransferPage: React.FC = () => {
|
|
const { message } = App.useApp();
|
|
const actionRef = useRef<ActionType>();
|
|
const columns: ProColumns[] = [
|
|
{
|
|
title: '订单编号',
|
|
dataIndex: 'orderNumber',
|
|
},
|
|
{
|
|
title: '源仓库',
|
|
dataIndex: 'sourceStockPointName',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '目标仓库',
|
|
dataIndex: 'destStockPointName',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '状态',
|
|
dataIndex: 'status',
|
|
hideInSearch: true,
|
|
render(_, record) {
|
|
if (record.isLost) return '已丢失';
|
|
if (record.isCancel) return '已取消';
|
|
if (record.isArrived) return '已到达';
|
|
return '运输中';
|
|
},
|
|
},
|
|
{
|
|
title: '数量',
|
|
hideInSearch: true,
|
|
render(_, record) {
|
|
return record?.items?.reduce?.((cur, next) => {
|
|
return cur + next.quantity;
|
|
}, 0);
|
|
},
|
|
},
|
|
{
|
|
title: '备注',
|
|
dataIndex: 'note',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '到货时间',
|
|
dataIndex: 'arriveAt',
|
|
valueType: 'dateTime',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '发货时间',
|
|
dataIndex: 'sendAt',
|
|
valueType: 'dateTime',
|
|
hideInSearch: true,
|
|
},
|
|
{
|
|
title: '操作',
|
|
dataIndex: 'option',
|
|
valueType: 'option',
|
|
render: (_, record) => (
|
|
<>
|
|
{!record.isCancel && !record.isArrived && !record.isLost ? (
|
|
<>
|
|
<UpdateForm tableRef={actionRef} values={record} />
|
|
<Divider type="vertical" />
|
|
<Popconfirm
|
|
title="入库"
|
|
description="确认已到达?"
|
|
onConfirm={async () => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await stockcontrollerReceivetransfer({
|
|
id: record.id as number,
|
|
});
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
actionRef.current?.reload();
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<Button type="primary">入库</Button>
|
|
</Popconfirm>
|
|
<Divider type="vertical" />
|
|
<Popconfirm
|
|
title="丢失"
|
|
description="确认该批货已丢失?"
|
|
onConfirm={async () => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await stockcontrollerLosttransfer({
|
|
id: record.id as number,
|
|
});
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
actionRef.current?.reload();
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<Button type="primary">丢失</Button>
|
|
</Popconfirm>
|
|
<Divider type="vertical" />
|
|
<Popconfirm
|
|
title="取消"
|
|
description="确认取消?"
|
|
onConfirm={async () => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await stockcontrollerCanceltransfer({
|
|
id: record.id as number,
|
|
});
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
actionRef.current?.reload();
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<Button type="primary" danger>
|
|
取消
|
|
</Button>
|
|
</Popconfirm>
|
|
</>
|
|
) : (
|
|
<DetailForm tableRef={actionRef} values={record} />
|
|
)}
|
|
</>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<PageContainer ghost>
|
|
<ProTable
|
|
headerTitle="查询表格"
|
|
actionRef={actionRef}
|
|
rowKey="id"
|
|
request={async (params) => {
|
|
const { data, success } = await stockcontrollerGettransfers(params);
|
|
return {
|
|
total: data?.total || 0,
|
|
data: data?.items || [],
|
|
success,
|
|
};
|
|
}}
|
|
columns={columns}
|
|
toolBarRender={() => [<CreateForm tableRef={actionRef} />]}
|
|
/>
|
|
</PageContainer>
|
|
);
|
|
};
|
|
|
|
const CreateForm: React.FC<{
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
}> = ({ tableRef }) => {
|
|
const { message } = App.useApp();
|
|
const [form] = Form.useForm();
|
|
return (
|
|
<DrawerForm
|
|
title="新建"
|
|
trigger={
|
|
<Button type="primary">
|
|
<PlusOutlined />
|
|
新建
|
|
</Button>
|
|
}
|
|
form={form}
|
|
autoFocusFirstInput
|
|
layout="vertical"
|
|
drawerProps={{
|
|
destroyOnHidden: true,
|
|
}}
|
|
onFinish={async ({ orderNumber, ...values }) => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await stockcontrollerCreatetransfer(values);
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
tableRef.current?.reload();
|
|
message.success('提交成功');
|
|
return true;
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<ProFormDatePicker
|
|
name="sendAt"
|
|
label="发货时间"
|
|
rules={[{ required: true, message: '请选择发货时间' }]}
|
|
/>
|
|
<ProFormSelect
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sourceStockPointId"
|
|
label="源仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源仓库' }]}
|
|
/>
|
|
<ProFormSelect
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="destStockPointId"
|
|
label="目标仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源目标仓库' }]}
|
|
/>
|
|
<ProFormTextArea name="note" label="备注" />
|
|
<ProFormText
|
|
name={'orderNumber'}
|
|
addonAfter={
|
|
<Button
|
|
onClick={async () => {
|
|
const orderNumber = await form.getFieldValue('orderNumber');
|
|
const { data } = await stockcontrollerGetpurchaseorder({
|
|
orderNumber,
|
|
});
|
|
form.setFieldsValue({
|
|
items: data?.map(
|
|
(item: { productName: string; sku: string }) => ({
|
|
...item,
|
|
sku: {
|
|
label: item.productName,
|
|
value: item.sku,
|
|
},
|
|
}),
|
|
),
|
|
});
|
|
}}
|
|
>
|
|
引用
|
|
</Button>
|
|
}
|
|
/>
|
|
<ProFormDependency name={['items']}>
|
|
{({ items }) => {
|
|
return (
|
|
'数量:' +
|
|
(items?.reduce?.((acc, cur) => acc + cur.quantity, 0) || 0)
|
|
);
|
|
}}
|
|
</ProFormDependency>
|
|
<ProFormList
|
|
name="items"
|
|
label="产品"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: '至少需要一个商品',
|
|
validator: (_, value) =>
|
|
value && value.length > 0
|
|
? Promise.resolve()
|
|
: Promise.reject('至少需要一个商品'),
|
|
},
|
|
]}
|
|
creatorButtonProps={{ children: '新增', size: 'large' }}
|
|
wrapperCol={{ span: 24 }}
|
|
>
|
|
{(fields, idx, { remove }) => (
|
|
<div key={idx}>
|
|
<ProFormSelect
|
|
request={async ({ keyWords }) => {
|
|
if (keyWords.length < 2) return [];
|
|
try {
|
|
const { data } = await productcontrollerSearchproducts({
|
|
name: keyWords,
|
|
});
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: `${item.name} - ${item.nameCn}`,
|
|
value: item.sku,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sku"
|
|
label={'产品' + (idx + 1)}
|
|
width="lg"
|
|
placeholder="请选择产品"
|
|
tooltip="至少输入3个字符"
|
|
fieldProps={{
|
|
showSearch: true,
|
|
}}
|
|
transform={(value) => {
|
|
return value?.value || value;
|
|
}}
|
|
debounceTime={300} // 防抖,减少请求频率
|
|
rules={[{ required: true, message: '请选择产品' }]}
|
|
onChange={(_, option) => {
|
|
form.setFieldValue(
|
|
['items', fields.key, 'productName'],
|
|
option.title,
|
|
);
|
|
}}
|
|
/>
|
|
<ProFormText name={'productName'} label="产品名称" hidden={true} />
|
|
<ProFormDigit
|
|
name="quantity"
|
|
label="数量"
|
|
placeholder="请输入数量"
|
|
rules={[{ required: true, message: '请输入数量' }]}
|
|
fieldProps={{
|
|
precision: 0,
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
</ProFormList>
|
|
</DrawerForm>
|
|
);
|
|
};
|
|
|
|
const UpdateForm: React.FC<{
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
values: API.UpdatePurchaseOrderDTO & {
|
|
id: number;
|
|
};
|
|
}> = ({ tableRef, values }) => {
|
|
const { message } = App.useApp();
|
|
const [form] = Form.useForm();
|
|
const initialValues = {
|
|
...values,
|
|
items: values?.items?.map((item: API.PurchaseOrderItem) => ({
|
|
...item,
|
|
sku: {
|
|
label: item.productName,
|
|
value: item.sku,
|
|
},
|
|
})),
|
|
};
|
|
return (
|
|
<DrawerForm<API.UpdatePurchaseOrderDTO>
|
|
title="编辑"
|
|
form={form}
|
|
initialValues={initialValues}
|
|
trigger={
|
|
<Button type="primary">
|
|
<EditOutlined />
|
|
编辑
|
|
</Button>
|
|
}
|
|
autoFocusFirstInput
|
|
drawerProps={{
|
|
destroyOnHidden: true,
|
|
}}
|
|
onFinish={async (values) => {
|
|
try {
|
|
const { success, message: errMsg } =
|
|
await stockcontrollerUpdatetransfer(
|
|
{ id: initialValues.id },
|
|
values,
|
|
);
|
|
if (!success) {
|
|
throw new Error(errMsg);
|
|
}
|
|
message.success('提交成功');
|
|
tableRef.current?.reload();
|
|
return true;
|
|
} catch (error: any) {
|
|
message.error(error.message);
|
|
}
|
|
}}
|
|
>
|
|
<ProFormSelect
|
|
readonly
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sourceStockPointId"
|
|
label="源仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源仓库' }]}
|
|
/>
|
|
<ProFormSelect
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="destStockPointId"
|
|
label="目标仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源目标仓库' }]}
|
|
/>
|
|
<ProFormTextArea name="note" label="备注" />
|
|
<ProFormDependency name={['items']}>
|
|
{({ items }) => {
|
|
return '数量:' + items?.reduce?.((acc, cur) => acc + cur.quantity, 0);
|
|
}}
|
|
</ProFormDependency>
|
|
<ProFormList
|
|
name="items"
|
|
label="产品"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: '至少需要一个商品',
|
|
validator: (_, value) =>
|
|
value && value.length > 0
|
|
? Promise.resolve()
|
|
: Promise.reject('至少需要一个商品'),
|
|
},
|
|
]}
|
|
creatorButtonProps={{ children: '新增', size: 'large' }}
|
|
wrapperCol={{ span: 24 }}
|
|
>
|
|
{(fields, idx, { remove }) => (
|
|
<div key={idx}>
|
|
<ProFormSelect
|
|
request={async ({ keyWords }) => {
|
|
if (keyWords.length < 2) return [];
|
|
try {
|
|
const { data } = await productcontrollerSearchproducts({
|
|
name: keyWords,
|
|
});
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: `${item.name} - ${item.nameCn}`,
|
|
value: item.sku,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sku"
|
|
label={'产品' + (idx + 1)}
|
|
width="lg"
|
|
placeholder="请选择产品"
|
|
tooltip="至少输入3个字符"
|
|
fieldProps={{
|
|
showSearch: true,
|
|
}}
|
|
transform={(value) => {
|
|
return value?.value || value;
|
|
}}
|
|
debounceTime={300} // 防抖,减少请求频率
|
|
rules={[{ required: true, message: '请选择产品' }]}
|
|
onChange={(_, option) => {
|
|
form.setFieldValue(
|
|
['items', fields.key, 'productName'],
|
|
option.title,
|
|
);
|
|
}}
|
|
/>
|
|
<ProFormText name={'productName'} label="产品名称" hidden={true} />
|
|
<ProFormDigit
|
|
name="quantity"
|
|
label="数量"
|
|
placeholder="请输入数量"
|
|
rules={[{ required: true, message: '请输入数量' }]}
|
|
fieldProps={{
|
|
precision: 0,
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
</ProFormList>
|
|
</DrawerForm>
|
|
);
|
|
};
|
|
|
|
const DetailForm: React.FC<{
|
|
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
values: Record<string, any>;
|
|
}> = ({ tableRef, values }) => {
|
|
const { message } = App.useApp();
|
|
const [form] = Form.useForm();
|
|
const initialValues = {
|
|
...values,
|
|
items: values?.items?.map((item: { productName: string; sku: string }) => ({
|
|
...item,
|
|
sku: {
|
|
label: item.productName,
|
|
value: item.sku,
|
|
},
|
|
})),
|
|
};
|
|
return (
|
|
<DrawerForm
|
|
title="详情"
|
|
form={form}
|
|
initialValues={initialValues}
|
|
trigger={<Button type="primary">详情</Button>}
|
|
autoFocusFirstInput
|
|
drawerProps={{
|
|
destroyOnHidden: true,
|
|
}}
|
|
readonly={true}
|
|
layout="vertical"
|
|
>
|
|
<ProFormText
|
|
name="orderNumber"
|
|
label="订单编号"
|
|
placeholder="请输入订单编号"
|
|
width={'lg'}
|
|
rules={[{ required: true, message: '请输入订单编号' }]}
|
|
/>
|
|
<ProFormSelect
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sourceStockPointId"
|
|
label="源仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源仓库' }]}
|
|
/>
|
|
<ProFormSelect
|
|
request={async () => {
|
|
try {
|
|
const { data } = await stockcontrollerGetallstockpoints();
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: item.name,
|
|
value: item.id,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="destStockPointId"
|
|
label="目标仓库"
|
|
width="lg"
|
|
placeholder="请选择仓库"
|
|
rules={[{ required: true, message: '请选择源目标仓库' }]}
|
|
/>
|
|
<ProFormTextArea name="note" label="备注" />
|
|
<ProFormList<API.PurchaseOrderItem>
|
|
name="items"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: '至少需要一个商品',
|
|
validator: (_, value) =>
|
|
value && value.length > 0
|
|
? Promise.resolve()
|
|
: Promise.reject('至少需要一个商品'),
|
|
},
|
|
]}
|
|
creatorButtonProps={{ children: '新增', size: 'large' }}
|
|
wrapperCol={{ span: 24 }}
|
|
>
|
|
{(fields, idx, { remove }) => (
|
|
<div key={idx}>
|
|
<ProForm.Group>
|
|
<ProFormSelect
|
|
request={async ({ keyWords }) => {
|
|
if (keyWords.length < 2) return [];
|
|
try {
|
|
const { data } = await productcontrollerSearchproducts({
|
|
name: keyWords,
|
|
});
|
|
return (
|
|
data?.map((item) => {
|
|
return {
|
|
label: `${item.name} - ${item.nameCn}`,
|
|
value: item.sku,
|
|
};
|
|
}) || []
|
|
);
|
|
} catch (error) {
|
|
return [];
|
|
}
|
|
}}
|
|
name="sku"
|
|
label="产品"
|
|
width="lg"
|
|
placeholder="请选择产品"
|
|
tooltip="至少输入3个字符"
|
|
fieldProps={{
|
|
showSearch: true,
|
|
}}
|
|
transform={(value) => {
|
|
return value?.value || value;
|
|
}}
|
|
debounceTime={300} // 防抖,减少请求频率
|
|
rules={[{ required: true, message: '请选择产品' }]}
|
|
onChange={(_, option) => {
|
|
form.setFieldValue(
|
|
['items', fields.key, 'productName'],
|
|
option?.title,
|
|
);
|
|
}}
|
|
/>
|
|
<ProFormText name="productName" label="产品名称" hidden={true} />
|
|
<ProFormDigit
|
|
name="quantity"
|
|
label="数量"
|
|
placeholder="请输入数量"
|
|
rules={[{ required: true, message: '请输入数量' }]}
|
|
fieldProps={{
|
|
precision: 0,
|
|
}}
|
|
/>
|
|
</ProForm.Group>
|
|
</div>
|
|
)}
|
|
</ProFormList>
|
|
</DrawerForm>
|
|
);
|
|
};
|
|
|
|
export default TransferPage;
|