feat: 完成采购调拨单,入库单,部分库存盘点。

This commit is contained in:
c
2026-03-10 09:55:19 +08:00
parent d75f33dda7
commit 55bfbaeb38
6 changed files with 568 additions and 81 deletions

View File

@@ -68,6 +68,7 @@ export default {
remark: "Remark", remark: "Remark",
startdate: "Start Date", startdate: "Start Date",
enddate: "End Date", enddate: "End Date",
searchCode: "Doc No/Name/Remark",
}, },
warehouse: { warehouse: {
warehouse: { warehouse: {

View File

@@ -68,6 +68,7 @@ export default {
remark: "备注", remark: "备注",
startdate: "开始时间", startdate: "开始时间",
enddate: "结束时间", enddate: "结束时间",
searchCode: "单据编号/名称/备注",
}, },
warehouse: { warehouse: {
warehouse: { warehouse: {
@@ -128,15 +129,17 @@ export default {
storeName: "仓库名称", storeName: "仓库名称",
storeId: "仓库", storeId: "仓库",
partNumber: "物料编号", partNumber: "物料编号",
productSpec: "物料规格", productSpec: "物料型号",
productCount: "盘点数量", productCount: "盘点数量",
originalProductCount: "原始数量", originalProductCount: "原始数量",
diffCount: "差异数量", diffCount: "差异数量",
stockTakingMark: "盘点备注", stockTakingMark: "盘点备注",
reserve1: "预留字段1", reserve1: "单据类型",
reserve2: "预留字段2", reserve2: "预留字段2",
createDate: "创建时间", createDate: "创建时间",
formStatus: "单据状态", formStatus: "单据状态",
isInit: "初始库存",
searchCode: "单据编号/名称/备注",
}, },
}, },
production: { production: {
@@ -489,6 +492,10 @@ export default {
input_formMark: "请输入单据备注", input_formMark: "请输入单据备注",
delete_message: "删除入库单", delete_message: "删除入库单",
input_formCode: "请输入单据编号", input_formCode: "请输入单据编号",
input_partNumber: "请输入物料编号",
not_exist_partNumber: "物料编号不存在",
input_productCount: "请输入入库数量",
no_items: "请添加入库明细",
approve_confirm: "是否审核通过", approve_confirm: "是否审核通过",
approve_success: "审核成功", approve_success: "审核成功",
approve_fail: "审核失败", approve_fail: "审核失败",
@@ -507,7 +514,7 @@ export default {
input_formMark: "请输入单据备注", input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号", input_formCode: "请输入单据编号",
input_partNumber: "请输入物料编号", input_partNumber: "请输入物料编号",
input_productSpec: "请输入物料规格", input_productSpec: "请输入物料型号",
input_productCount: "请输入盘点数量", input_productCount: "请输入盘点数量",
input_originalProductCount: "请输入原始数量", input_originalProductCount: "请输入原始数量",
input_diffCount: "请输入差异数量", input_diffCount: "请输入差异数量",
@@ -525,6 +532,8 @@ export default {
import_success: "导入成功", import_success: "导入成功",
import_fail: "导入失败", import_fail: "导入失败",
delete_message: "删除盘点单", delete_message: "删除盘点单",
upload_countItems: "请上传盘点明细",
not_exist_partNumber: "物料编号不存在",
}, },
}, },
production: { production: {
@@ -805,6 +814,9 @@ export default {
warehousereceipt: { warehousereceipt: {
add: "添加入库单", add: "添加入库单",
edit: "编辑入库单", edit: "编辑入库单",
showItem: "入库明细",
baseTitle: "入库单基本信息",
tableTitle: "入库明细",
}, },
inventorycount: { inventorycount: {
add: "添加盘点单", add: "添加盘点单",

View File

@@ -3,9 +3,15 @@ import { $t } from "@/common/languages";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue"; import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue"; import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import type TreeSidePageableTable from "@/components/base/treeside-pageable-table/TreeSidePageableTable.vue";
export const usePage = ( export const usePage = (
tableRef: Ref<InstanceType<typeof BasePageableTable> | InstanceType<typeof ExpandablePageableTable> | null> tableRef: Ref<
| InstanceType<typeof BasePageableTable>
| InstanceType<typeof ExpandablePageableTable>
| InstanceType<typeof TreeSidePageableTable>
| null
>
) => { ) => {
const postForm = (url: string, form: any, visible: Ref<boolean>, type: string) => { const postForm = (url: string, form: any, visible: Ref<boolean>, type: string) => {
post(url, form) post(url, form)

View File

@@ -1,11 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import TreeSidePageableTable from "@/components/base/tree-side-pageable-table/TreeSidePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue"; import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue"; import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page"; import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue"; import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages"; import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus"; import type { FormInstance, FormRules } from "element-plus";
import TreeSidePageableTable from "@/components/base/treeside-pageable-table/TreeSidePageableTable.vue";
/** /**
* 必须要的变量 * 必须要的变量

View File

@@ -1,12 +1,15 @@
<script lang="ts" setup> <script lang="ts" setup>
import BasePageableTable from "@/components/base/base-pageable-table/BasePageableTable.vue";
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue"; import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue"; import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page"; import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue";
import { $t } from "@/common/languages"; import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus"; import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils"; import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import { get } from "@/common/http/request";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
/** /**
* 必须要的变量 * 必须要的变量
@@ -16,49 +19,97 @@ const getPageUrl = "/warehouse/inventorycount/getInventoryCountPage";
const addUrl = "/warehouse/inventorycount/addInventoryCount"; const addUrl = "/warehouse/inventorycount/addInventoryCount";
const editUrl = "/warehouse/inventorycount/updateInventoryCount"; const editUrl = "/warehouse/inventorycount/updateInventoryCount";
const removeUrl = "/warehouse/inventorycount/deleteInventoryCount"; const removeUrl = "/warehouse/inventorycount/deleteInventoryCount";
const itemUrl = "/warehouse/inventorycount/getInventoryCountDetail";
const warehouseSelectUrl = "/warehouse/warehouse/getWarehouseSelectList";
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const searchers = [ const searchers = [
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.inventorycount.searchCode") }, { name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.inventorycount.searchCode") },
]; ];
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.inventorycount.input_storeId"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formName"), trigger: "blur" }], formName: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.inventorycount.input_formMark"), trigger: "blur" }], storeNo: [{ required: true, message: $t("_message.warehouse.inventorycount.select_storeId"), trigger: "change" }],
storeName: [{ required: true, message: $t("_message.warehouse.inventorycount.select_storeId"), trigger: "change" }],
isInit: [{ required: true, message: "请选择是否初始库存", trigger: "change" }],
countItems: [
{
required: true,
validator: (rule, value, callback) => {
if (value === undefined || value.length === 0) {
callback($t("_message.warehouse.inventorycount.upload_countItems"));
}
callback();
},
trigger: "change",
},
],
partNumber: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
callback($t("_message.warehouse.inventorycount.input_partNumber"));
}
(async () => {
try {
const isExists = await get(partNumberExistsUrl, { partNumber: value }).then(res => res.data);
if (isExists) {
callback();
} else {
callback($t("_message.warehouse.inventorycount.not_exist_partNumber"));
}
} catch (err: any) {
callback(new Error(err));
}
})();
},
trigger: "blur",
},
],
}); });
const itemArrayName = "countItems";
/** /**
* 基本不变通用变量 * 基本不变通用变量
*/ */
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null); const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef); const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { title, visible, formType, form } = useGeneralPageRef(); const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
/** /**
* 可以自定义的变量 * 可以自定义的变量
*/ */
const add = () => { const add = () => {
form.value = {}; form.value = {};
// 前端生成单据编号
form.value.formCode = "PD" + new Date().toISOString().slice(0, 19).replace(/[-T:]/g, "");
form.value.isInit = 0;
title.value = "_title.warehouse.inventorycount.add"; title.value = "_title.warehouse.inventorycount.add";
visible.value = true; visible.value = true;
formType.value = false; formType.value = false;
}; };
const edit = (row: any) => { const edit = (row: any) => {
title.value = "_title.warehouse.inventorycount.edit"; title.value = "_title.warehouse.inventorycount.edit";
form.value = { ...row }; form.value = { ...row };
visible.value = true; visible.value = true;
formType.value = true; formType.value = true;
}; };
const remove = (row: any) => { const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.inventorycount.delete_message"); useRemove(removeUrl, row.id, "_message.warehouse.inventorycount.delete_message");
}; };
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) { const showItem = (row: any) => {
formRef.validate(valid => { itemParentId.value = row.id;
if (valid) { itemVisible.value = true;
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
}; };
const topButtonClick = (eventName: string) => { const topButtonClick = (eventName: string) => {
switch (eventName) { switch (eventName) {
case "add": case "add":
@@ -66,6 +117,7 @@ const topButtonClick = (eventName: string) => {
break; break;
} }
}; };
const operateButtonClick = (eventName: string, row: any) => { const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) { switch (eventName) {
case "edit": case "edit":
@@ -74,36 +126,222 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove": case "remove":
remove(row); remove(row);
break; break;
case "showItem":
showItem(row);
break;
} }
}; };
// Excel导入配置
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "物料编号",
defaultValue: "",
},
productSpec: {
sourceKey: "物料型号",
defaultValue: "",
},
productCount: {
sourceKey: "数量",
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
};
const submit = (formData: any, formRef: FormInstance | undefined) => {
const targetRef = formRef || (baseFormWithTableRef.value as any)?.baseFormRef;
if (!targetRef) return;
targetRef.validate((valid: any) => {
if (valid) {
// 设置storeName
if (formData.storeNo && baseSelectRef.value) {
formData.storeName = baseSelectRef.value.getLabel();
}
if (formType.value) useEdit(editUrl, formData, visible);
else useAdd(addUrl, formData, visible);
}
});
};
const baseSelectRef = ref<InstanceType<typeof BaseSelect> | null>(null);
// 处理仓库选择变化
const handleStoreChange = (val: number) => {
if (val && baseSelectRef.value) {
form.value.storeName = baseSelectRef.value.getLabel();
}
};
// 获取单据类型显示文本
const getFormTypeText = (reserve1: number) => {
return reserve1 === 1 ? $t("_prop.warehouse.inventorycount.isInit") : "盘点";
};
</script> </script>
<template> <template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef"> <ExpandablePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:item-url="itemUrl"
item-id-key="id"
item-id-name="id"
itemFieldName="inventory_count"
>
<template #tool-button> <template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" /> <DefaultToolButton @top-button-click="topButtonClick" />
</template> </template>
<template #columns> <template #columns>
<el-table-column prop="id" type="hidden" width="40" /> <el-table-column :label="$t('_prop.warehouse.inventorycount.reserve1')" width="100">
<el-table-column :label="$t('_prop.warehouse.inventorycount.formCode')" prop="formCode" /> <template #default="{ row }">
<span>{{ getFormTypeText(row.reserve1) }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.inventorycount.formCode')" prop="formCode" width="180" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.storeName')" prop="storeName" width="120" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName" /> <el-table-column :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.storeName')" prop="storeName" /> <el-table-column :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark" show-overflow-tooltip />
<el-table-column :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark" /> <el-table-column :label="$t('_prop.common.createDate')" prop="createDate" width="180" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" /> <DefaultOperateButtonColumn @operate-button-click="operateButtonClick" />
</template> </template>
</BasePageableTable> <template #item-content="{ itemData }">
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules"> <el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.warehouse.inventorycount.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.productSpec')" prop="productSpec" width="200" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.productCount')" prop="productCount" width="100" />
<el-table-column
:label="$t('_prop.warehouse.inventorycount.originalProductCount')"
prop="originalProductCount"
width="100"
/>
<el-table-column :label="$t('_prop.warehouse.inventorycount.diffCount')" prop="diffCount" width="100">
<template #default="{ row }">
<span :style="{ color: row.diffCount !== 0 ? '#f56c6c' : '#67c23a' }">
{{ row.diffCount }}
</span>
</template>
</el-table-column>
</el-table>
</template>
</ExpandablePageableTable>
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@submit="submit"
v-model:form="form"
:title="$t(title)"
:rules="rules"
:base-title="$t('_title.warehouse.inventorycount.baseTitle')"
:table-title="$t('_title.warehouse.inventorycount.tableTitle')"
item-array-name="countItems"
upload-desc="盘点明细"
:mapping-config="mappingConfig"
>
<template #form-items> <template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item> <el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.inventorycount.storeId')" prop="storeId"> <el-row :gutter="20">
<el-input v-model="form.storeId" :placeholder="$t('_message.warehouse.inventorycount.input_storeId')" /> <el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.inventorycount.storeId')" prop="storeNo">
<BaseSelect
ref="baseSelectRef"
v-model="form.storeNo"
:url="warehouseSelectUrl"
name="value"
label="label"
@change="handleStoreChange"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.inventorycount.formCode')" prop="formCode">
<el-input v-model="form.formCode" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName"> <el-form-item :label="$t('_prop.warehouse.inventorycount.formName')" prop="formName">
<el-input v-model="form.formName" :placeholder="$t('_message.warehouse.inventorycount.input_formName')" /> <el-input v-model="form.formName" :placeholder="$t('_message.warehouse.inventorycount.input_formName')" />
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.inventorycount.isInit')" prop="isInit">
<el-switch
v-model="form.isInit"
:active-value="1"
:inactive-value="0"
active-text=""
inactive-text=""
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark"> <el-form-item :label="$t('_prop.warehouse.inventorycount.formMark')" prop="formMark">
<el-input v-model="form.formMark" :placeholder="$t('_message.warehouse.inventorycount.input_formMark')" /> <el-input
v-model="form.formMark"
:placeholder="$t('_message.warehouse.inventorycount.input_formMark')"
type="textarea"
/>
</el-form-item> </el-form-item>
</template> </template>
</BaseForm>
<template #form-table-columns>
<el-table-column :label="$t('_prop.warehouse.inventorycount.partNumber')" width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.partNumber`" :rules="rules.partNumber">
<el-input v-model="row.partNumber" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.inventorycount.productSpec')" width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productSpec`">
<el-input v-model="row.productSpec" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.inventorycount.productCount')" width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productCount`">
<el-input-number v-model="row.productCount" size="small" :min="0" />
</el-form-item>
</template>
</el-table-column>
</template>
</BaseFormWithTable>
<BaseItemDialog
:title="$t('_title.warehouse.inventorycount.showItem')"
v-model:visible="itemVisible"
:url="itemUrl"
parent-param-name="id"
v-model:parent-param-value="itemParentId"
>
<template #columns>
<el-table-column :label="$t('_prop.warehouse.inventorycount.partNumber')" prop="partNumber" width="150" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.productSpec')" prop="productSpec" width="200" />
<el-table-column :label="$t('_prop.warehouse.inventorycount.productCount')" prop="productCount" width="100" />
<el-table-column
:label="$t('_prop.warehouse.inventorycount.originalProductCount')"
prop="originalProductCount"
width="100"
/>
<el-table-column :label="$t('_prop.warehouse.inventorycount.diffCount')" prop="diffCount" width="100">
<template #default="{ row }">
<span :style="{ color: row.diffCount !== 0 ? '#f56c6c' : '#67c23a' }">
{{ row.diffCount }}
</span>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.inventorycount.stockTakingMark')" prop="stockTakingMark" />
</template>
</BaseItemDialog>
</template> </template>

View File

@@ -3,62 +3,130 @@ import BasePageableTable from "@/components/base/base-pageable-table/BasePageabl
import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue"; import DefaultToolButton from "@/components/base/default-tool-button/DefaultToolButton.vue";
import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue"; import DefaultOperateButtonColumn from "@/components/base/default-column/DefaultOperateButtonColumn.vue";
import { usePage } from "@/composables/use-page"; import { usePage } from "@/composables/use-page";
import BaseForm from "@/components/base/base-form/BaseForm.vue"; import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import { $t } from "@/common/languages"; import { $t } from "@/common/languages";
import type { FormInstance, FormRules } from "element-plus"; import type { FormInstance, FormRules } from "element-plus";
import { formatDate } from "@/common/utils/format-utils"; import { formatDate } from "@/common/utils/format-utils";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
/** import DefaultStatusSwitchColumn from "@/components/base/default-column/DefaultStatusSwitchColumn.vue";
* 必须要的变量 import { useStatus } from "@/common/languages/mapping/base-info-mapping";
*/ import { get, post } from "@/common/http/request";
import { ElMessage } from "element-plus";
import { ref } from "vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { DocumentType } from "@/common/enums/DocumentType";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage"; const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
const getItemUrl = "/warehouse/warehousereceipt/getWarehouseReceiptDetail";
const addUrl = "/warehouse/warehousereceipt/addWarehouseReceipt"; const addUrl = "/warehouse/warehousereceipt/addWarehouseReceipt";
const editUrl = "/warehouse/warehousereceipt/updateWarehouseReceipt"; const editUrl = "/warehouse/warehousereceipt/updateWarehouseReceipt";
const removeUrl = "/warehouse/warehousereceipt/deleteWarehouseReceipt"; const removeUrl = "/warehouse/warehousereceipt/deleteWarehouseReceipt";
const searchers = [ const approveUrl = "/warehouse/warehousereceipt/approveWarehouseReceipt";
{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.warehouse.warehousereceipt.searchCode") }, const rejectUrl = "/warehouse/warehousereceipt/rejectWarehouseReceipt";
]; const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const getWarehouseSelectListUrl = "/warehouse/warehouse/getWarehouseSelectList";
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.common.searchCode") }];
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef, useApprove, useReject } = usePage(tableRef);
const { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
const { getFormStatusLabel } = useStatus();
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
const warehouseSelectRef = ref<InstanceType<typeof BaseSelect>>();
const itemArrayName = "receiptItems";
const rules = reactive<FormRules>({ const rules = reactive<FormRules>({
storeId: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_storeId"), trigger: "blur" }], storeNo: [{ required: true, message: $t("_message.warehouse.warehousereceipt.select_storeId"), trigger: "change" }],
storeName: [{ required: true, message: $t("_message.warehouse.warehousereceipt.select_storeId"), trigger: "change" }],
formCode: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formCode"), trigger: "blur" }],
formName: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formName"), trigger: "blur" }], formName: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formName"), trigger: "blur" }],
formMark: [{ required: true, message: $t("_message.warehouse.warehousereceipt.input_formMark"), trigger: "blur" }], formMark: [{ required: false, message: $t("_message.warehouse.warehousereceipt.input_formMark"), trigger: "blur" }],
receiptItems: [
{
required: true,
validator: (rule, value, callback) => {
if (value === undefined || value.length === 0) {
callback($t("_message.warehouse.warehousereceipt.no_items"));
}
callback();
},
trigger: "change",
},
],
}); });
/**
* 基本不变通用变量 const mappingConfig: FieldMappingConfig = {
*/ partNumber: {
const tableRef = ref<InstanceType<typeof BasePageableTable> | null>(null); sourceKey: ["商品编号", "物料编号", "partNumber"],
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef); defaultValue: "",
const { title, visible, formType, form } = useGeneralPageRef(); },
/** productSpec: {
* 可以自定义的变量 sourceKey: ["型号", "物料型号", "productSpecs", "productSpec"],
*/ defaultValue: "",
},
productCount: {
sourceKey: ["数量", "入库数量", "productCount"],
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
};
const add = () => { const add = () => {
form.value = {}; form.value = {
formCode: generateDucumentNo(DocumentType.WarehouseReceipt),
formName: "",
formMark: "",
storeNo: null,
storeName: "",
receiptItems: [],
};
title.value = "_title.warehouse.warehousereceipt.add"; title.value = "_title.warehouse.warehousereceipt.add";
visible.value = true; visible.value = true;
formType.value = false; formType.value = false;
}; };
const edit = (row: any) => { const edit = (row: any) => {
title.value = "_title.warehouse.warehousereceipt.edit"; title.value = "_title.warehouse.warehousereceipt.edit";
form.value = { ...row }; form.value = { ...row };
// 加载明细数据
get(getItemUrl, { id: row.id })
.then(res => {
if (res.code === 0) {
form.value.receiptItems = res.data || [];
}
})
.catch(() => {
form.value.receiptItems = [];
});
visible.value = true; visible.value = true;
formType.value = true; formType.value = true;
}; };
const remove = (row: any) => { const remove = (row: any) => {
useRemove(removeUrl, row.id, "_message.warehouse.warehousereceipt.delete_message"); useRemove(removeUrl, row.id, "_message.warehouse.warehousereceipt.delete_message");
}; };
const submit = (form: any, formRef: FormInstance | undefined) => {
if (formRef !== undefined) { const showItem = (row: any) => {
formRef.validate(valid => { itemParentId.value = row.id;
if (valid) { itemVisible.value = true;
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
}
}; };
const approve = (row: any) => {
useApprove(approveUrl, row.id, "_message.warehouse.warehousereceipt.approve_confirm");
};
const reject = (row: any) => {
useReject(rejectUrl, row.id, "_message.warehouse.warehousereceipt.reject_confirm");
};
const topButtonClick = (eventName: string) => { const topButtonClick = (eventName: string) => {
switch (eventName) { switch (eventName) {
case "add": case "add":
@@ -66,6 +134,7 @@ const topButtonClick = (eventName: string) => {
break; break;
} }
}; };
const operateButtonClick = (eventName: string, row: any) => { const operateButtonClick = (eventName: string, row: any) => {
switch (eventName) { switch (eventName) {
case "edit": case "edit":
@@ -74,36 +143,197 @@ const operateButtonClick = (eventName: string, row: any) => {
case "remove": case "remove":
remove(row); remove(row);
break; break;
case "showItem":
showItem(row);
break;
case "approve":
approve(row);
break;
case "reject":
reject(row);
break;
} }
}; };
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
if (row.formStatus === 1 && button.eventName === "edit") return false;
return true;
};
const submit = (form: any, formRef: FormInstance | undefined) => {
const targetRef = formRef || (baseFormWithTableRef.value as any)?.baseFormRef;
if (!targetRef) return;
// 从 BaseSelect 获取仓库名称
const storeName = warehouseSelectRef.value?.getLabel();
if (storeName) {
form.storeName = storeName;
}
targetRef.validate((valid: any) => {
if (valid) {
if (formType.value) useEdit(editUrl, form, visible);
else useAdd(addUrl, form, visible);
}
});
};
</script> </script>
<template> <template>
<BasePageableTable :url="getPageUrl" :searchers="searchers" ref="tableRef"> <ExpandablePageableTable
:url="getPageUrl"
:searchers="searchers"
ref="tableRef"
:item-url="getItemUrl"
item-id-key="id"
item-id-name="id"
item-field-name="receiptItems"
>
<template #tool-button> <template #tool-button>
<DefaultToolButton @top-button-click="topButtonClick" /> <DefaultToolButton @top-button-click="topButtonClick" />
</template> </template>
<template #columns> <template #columns>
<el-table-column prop="id" type="hidden" width="40" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" /> <el-table-column :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" /> <el-table-column :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" /> <el-table-column :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark" />
<el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" /> <el-table-column :label="$t('_prop.common.createDate')" prop="createDate" :formatter="formatDate" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" /> <DefaultStatusSwitchColumn status-param-name="formStatus" :status-label-mapping="getFormStatusLabel" />
<DefaultOperateButtonColumn @operate-button-click="operateButtonClick" :auth-show-func="authShowFunc" />
</template> </template>
</BasePageableTable> <template #item-content="{ itemData }">
<BaseForm v-model:visible="visible" @submit="submit" v-model:form="form" :title="$t(title)" :rules="rules"> <el-table :data="itemData" size="small" border stripe>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productSpec')" prop="productSpec" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productCount')" prop="productCount" />
</el-table>
</template>
</ExpandablePageableTable>
<BaseFormWithTable
ref="baseFormWithTableRef"
v-model:visible="visible"
@submit="submit"
v-model:form="form"
:title="$t(title)"
:rules="rules"
:base-title="$t('_title.warehouse.warehousereceipt.baseTitle')"
:table-title="$t('_title.warehouse.warehousereceipt.tableTitle')"
item-array-name="receiptItems"
upload-desc="物料信息"
:mapping-config="mappingConfig"
>
<template #form-items> <template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item> <el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.storeId')" prop="storeId"> <el-row :gutter="20">
<el-input v-model="form.storeId" :placeholder="$t('_message.warehouse.warehousereceipt.input_storeId')" /> <el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formCode')" prop="formCode">
<el-input
v-model="form.formCode"
:placeholder="$t('_message.warehouse.warehousereceipt.input_formCode')"
disabled
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.storeName')" prop="storeNo">
<BaseSelect
v-model="form.storeNo"
:url="getWarehouseSelectListUrl"
ref="warehouseSelectRef"
:placeholder="$t('_message.warehouse.warehousereceipt.select_storeId')"
:props="{ label: 'storeName', value: 'id' }"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName"> <el-form-item :label="$t('_prop.warehouse.warehousereceipt.formName')" prop="formName">
<el-input v-model="form.formName" :placeholder="$t('_message.warehouse.warehousereceipt.input_formName')" /> <el-input v-model="form.formName" :placeholder="$t('_message.warehouse.warehousereceipt.input_formName')" />
</el-form-item> </el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark"> <el-form-item :label="$t('_prop.warehouse.warehousereceipt.formMark')" prop="formMark">
<el-input v-model="form.formMark" :placeholder="$t('_message.warehouse.warehousereceipt.input_formMark')" /> <el-input
v-model="form.formMark"
:placeholder="$t('_message.warehouse.warehousereceipt.input_formMark')"
type="textarea"
autosize
/>
</el-form-item> </el-form-item>
</template> </template>
</BaseForm> <template #form-table-columns>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.partNumber')" width="180">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.partNumber`"
:rules="{
required: true,
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback($t('_message.warehouse.warehousereceipt.input_partNumber'));
}
(async () => {
try {
const isExists = await get(partNumberExistsUrl, { partNumber: value }).then(res => res.data);
if (isExists) {
callback();
}
callback($t('_message.warehouse.warehousereceipt.not_exist_partNumber'));
} catch (err: any) {
callback(new Error(err));
}
})();
},
trigger: 'blur',
}"
>
<el-input v-model="row.partNumber" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productSpec')" width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productSpec`">
<el-input v-model="row.productSpec" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productCount')" width="150">
<template #default="{ row, $index }">
<el-form-item
:prop="`${itemArrayName}.${$index}.productCount`"
:rules="{
required: true,
validator: (rule: any, value: any, callback: any) => {
if (!value || value <= 0) {
callback($t('_message.warehouse.warehousereceipt.input_productCount'));
}
callback();
},
trigger: 'blur',
}"
>
<el-input-number v-model="row.productCount" size="small" :min="1" />
</el-form-item>
</template>
</el-table-column>
</template>
</BaseFormWithTable>
<BaseItemDialog
:title="$t('_title.warehouse.warehousereceipt.showItem')"
v-model:visible="itemVisible"
:url="getItemUrl"
parent-param-name="id"
v-model:parent-param-value="itemParentId"
>
<template #columns>
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.partNumber')" prop="partNumber" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productSpec')" prop="productSpec" />
<el-table-column :label="$t('_prop.warehouse.warehousereceipt.productCount')" prop="productCount" />
</template>
</BaseItemDialog>
</template> </template>