<script lang="ts" setup>
|
import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock';
|
import type { VbenFormSchema } from '#/adapter/form';
|
|
import { markRaw, ref } from 'vue';
|
|
import { useVbenModal } from '@vben/common-ui';
|
|
import { message } from 'ant-design-vue';
|
|
import { z } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
import { moveMaterialStock } from '#/api/mes/wm/materialstock';
|
import {
|
WmWarehouseAreaSelect,
|
WmWarehouseLocationSelect,
|
WmWarehouseSelect,
|
} from '#/views/wls/warehouse/components';
|
|
defineOptions({ name: 'WmStockMoveModal' });
|
|
const emit = defineEmits<{ success: [] }>();
|
|
const currentRow = ref<MesWmMaterialStockApi.MaterialStock>();
|
|
function useFormSchema(): VbenFormSchema[] {
|
return [
|
{
|
fieldName: 'itemCode',
|
label: '物料编码',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'itemName',
|
label: '物料名称',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'batchCode',
|
label: '批次号',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'warehouseName',
|
label: '当前仓库',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'locationName',
|
label: '当前库区',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'areaName',
|
label: '当前库位',
|
component: 'Input',
|
componentProps: { disabled: true },
|
},
|
{
|
fieldName: 'quantity',
|
label: '当前数量',
|
component: 'InputNumber',
|
componentProps: { disabled: true, class: '!w-full', precision: 2 },
|
},
|
{
|
fieldName: 'toWarehouseId',
|
label: '目标仓库',
|
component: markRaw(WmWarehouseSelect),
|
componentProps: {
|
placeholder: '请选择目标仓库',
|
onChange: async () => {
|
await formApi.setFieldValue('toLocationId', undefined);
|
await formApi.setFieldValue('toAreaId', undefined);
|
},
|
},
|
rules: 'selectRequired',
|
},
|
{
|
fieldName: 'toLocationId',
|
label: '目标库区',
|
component: markRaw(WmWarehouseLocationSelect),
|
componentProps: { placeholder: '请选择目标库区' },
|
dependencies: {
|
triggerFields: ['toWarehouseId'],
|
componentProps: (values) => ({
|
warehouseId: values.toWarehouseId,
|
placeholder: '请选择目标库区',
|
onChange: async () => {
|
await formApi.setFieldValue('toAreaId', undefined);
|
},
|
}),
|
trigger: (values, api) => {
|
if (values.toLocationId !== undefined) {
|
void api.setFieldValue('toLocationId', undefined);
|
void api.setFieldValue('toAreaId', undefined);
|
}
|
},
|
},
|
rules: 'selectRequired',
|
},
|
{
|
fieldName: 'toAreaId',
|
label: '目标库位',
|
component: markRaw(WmWarehouseAreaSelect),
|
componentProps: { placeholder: '请选择目标库位' },
|
dependencies: {
|
triggerFields: ['toLocationId'],
|
componentProps: (values) => ({
|
locationId: values.toLocationId,
|
placeholder: '请选择目标库位',
|
}),
|
trigger: (values, api) => {
|
if (values.toAreaId !== undefined) {
|
void api.setFieldValue('toAreaId', undefined);
|
}
|
},
|
},
|
rules: 'selectRequired',
|
},
|
{
|
fieldName: 'moveQuantity',
|
label: '移库数量',
|
component: 'InputNumber',
|
componentProps: {
|
class: '!w-full',
|
min: 0.01,
|
placeholder: '请输入移库数量',
|
precision: 2,
|
},
|
rules: z.number().positive('移库数量必须大于0'),
|
},
|
{
|
fieldName: 'remark',
|
label: '备注',
|
component: 'Textarea',
|
formItemClass: 'col-span-2',
|
componentProps: { placeholder: '请输入备注', rows: 3 },
|
},
|
];
|
}
|
|
const [Form, formApi] = useVbenForm({
|
commonConfig: {
|
componentProps: { class: 'w-full' },
|
formItemClass: 'col-span-1',
|
labelWidth: 100,
|
},
|
layout: 'horizontal',
|
schema: useFormSchema(),
|
showDefaultActions: false,
|
wrapperClass: 'grid-cols-2',
|
});
|
|
const [Modal, modalApi] = useVbenModal({
|
async onConfirm() {
|
const { valid } = await formApi.validate();
|
if (!valid) return;
|
|
const row = currentRow.value;
|
if (!row?.id) return;
|
|
const values = await formApi.getValues();
|
const moveQuantity = values.moveQuantity as number;
|
const quantity = (row.quantity || 0) as number;
|
const availableQuantity = (row.availableQuantity || 0) as number;
|
|
if (moveQuantity > quantity) {
|
message.error(`移库数量不能超过当前库存数量(${quantity.toFixed(2)})`);
|
return;
|
}
|
|
if (moveQuantity > availableQuantity) {
|
message.error(`移库数量不能超过可用量(${availableQuantity.toFixed(2)}),可用量 = 在库数量 - 冻结数量 - 占用量`);
|
return;
|
}
|
|
if (row.warehouseId === values.toWarehouseId && row.locationId === values.toLocationId && row.areaId === values.toAreaId) {
|
message.error('目标库位与当前库位相同,不允许移库');
|
return;
|
}
|
|
modalApi.lock();
|
try {
|
await moveMaterialStock({
|
materialStockId: row.id,
|
quantity: moveQuantity,
|
remark: values.remark,
|
toAreaId: values.toAreaId,
|
toLocationId: values.toLocationId,
|
toWarehouseId: values.toWarehouseId,
|
});
|
message.success('移库成功');
|
emit('success');
|
await modalApi.close();
|
} finally {
|
modalApi.unlock();
|
}
|
},
|
async onOpenChange(isOpen: boolean) {
|
if (!isOpen) {
|
currentRow.value = undefined;
|
return;
|
}
|
const data = modalApi.getData<MesWmMaterialStockApi.MaterialStock>();
|
if (!data?.id) return;
|
currentRow.value = data;
|
|
if (data.frozen) {
|
message.warning('该库存记录已冻结,不允许移库');
|
await modalApi.close();
|
return;
|
}
|
|
await formApi.setValues({
|
areaName: data.areaName,
|
batchCode: data.batchCode,
|
itemCode: data.itemCode,
|
itemName: data.itemName,
|
locationName: data.locationName,
|
quantity: data.quantity,
|
warehouseName: data.warehouseName,
|
});
|
},
|
title: '库存移库',
|
});
|
</script>
|
|
<template>
|
<Modal class="w-3/5">
|
<Form class="mx-4" />
|
</Modal>
|
</template>
|