fix: 修复和完善 Excel 功能。

This commit is contained in:
c
2026-03-19 16:58:10 +08:00
parent bf83b5e3b6
commit d88701f4ee
15 changed files with 546 additions and 220 deletions

View File

@@ -2,7 +2,7 @@
"name": "teek-design-vue3-template",
"version": "2.0.0",
"private": true,
"description": "Teek Design Vue3 后台管理系统",
"description": "牛安后台管理系统",
"author": "Teeker <2456019588@qq.com>",
"license": "MIT",
"type": "module",

8
pnpm-lock.yaml generated
View File

@@ -47,9 +47,6 @@ importers:
qs:
specifier: ^6.14.0
version: 6.14.0
remixicon:
specifier: ^4.9.1
version: 4.9.1
sortablejs:
specifier: ^1.15.6
version: 1.15.6
@@ -4260,9 +4257,6 @@ packages:
resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==}
engines: {node: '>= 0.4'}
remixicon@4.9.1:
resolution: {integrity: sha512-36gLSoujkabnCFZFDyP17VNh9piuBA/rsXUb4auSJWLGsHVXtmxLj/EM5FjaEAGnk8oIAj1Azob/DZ2N+90lAQ==}
repeat-element@1.1.4:
resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
engines: {node: '>=0.10.0'}
@@ -9675,8 +9669,6 @@ snapshots:
es-errors: 1.3.0
set-function-name: 2.0.2
remixicon@4.9.1: {}
repeat-element@1.1.4: {}
repeat-string@1.6.1: {}

View File

@@ -80,6 +80,11 @@ export default {
yes: "Yes",
no: "No",
},
_component: {
baseFormWithTable: {
uploadTip: "Only xlsx/xls/csv files are allowed, max 10MB",
},
},
_prop: {
common: {
tel: "Tel",
@@ -339,6 +344,8 @@ export default {
formStatus: "Audit Status",
customerName: "Customer Name",
customerId: "Customer",
storeNo: "Warehouse",
storeName: "Warehouse",
partNumber: "Part Number",
productSpecs: "Product Specs",
saleCount: "Sale Count",
@@ -754,6 +761,27 @@ export default {
},
sale: {
saleorder: {
select_customerId: "Please select customer",
select_storeNo: "Please select warehouse",
input_formName: "Please enter form name",
input_formMark: "Please enter form remark",
input_formCode: "Please enter form code",
input_partNumber: "Please enter part number",
input_saleCount: "Please enter sale count",
input_price: "Please enter price",
input_saleMark: "Please enter remark",
approve_confirm: "Confirm approval",
approve_success: "Approval success",
approve_fail: "Approval failed",
reject_confirm: "Confirm reject",
reject_success: "Reject success",
reject_fail: "Reject failed",
already_approved: "Sale order already approved",
not_approved: "Sale order not approved",
no_sale_order_items: "Sale order has no items",
cannot_unapprove_with_shipped: "Sale order already shipped, cannot unapprove",
import_success: "Import success",
import_fail: "Import failed",
delete_message: "Delete Order",
},
},
@@ -830,14 +858,17 @@ export default {
add: "Add Transfer",
edit: "Edit Transfer",
stock_check_failed: "Stock check failed",
templateFileName: "Transfer Order Template",
},
warehousereceipt: {
add: "Add Receipt",
edit: "Edit Receipt",
templateFileName: "Warehouse Receipt Template",
},
inventorycount: {
add: "Add Count",
edit: "Edit Count",
templateFileName: "Inventory Count Template",
},
},
production: {
@@ -847,6 +878,7 @@ export default {
showItem: "BOM Items",
baseTitle: "BOM Info",
tableTitle: "BOM Details",
templateFileName: "BOM Template",
},
production_plan: {
add: "Add Plan",
@@ -868,10 +900,12 @@ export default {
baseTitle: "Receipt Basic Info",
tableTitle: "Product Details",
outstockDialog: "Product Outstock",
templateFileName: "Finished Product Receipt Template",
},
finishedproductshipment: {
add: "Add Shipment",
edit: "Edit Shipment",
templateFileName: "Finished Product Shipment Template",
},
},
purchase: {
@@ -881,6 +915,7 @@ export default {
showItem: "Plan Items",
baseTitle: "Purchase Plan Basic Info",
tableTitle: "Purchase Details",
templateFileName: "Purchase Plan Template",
},
purchaseorder: {
add: "Add Purchase Order",
@@ -888,6 +923,7 @@ export default {
showItem: "Order Items",
baseTitle: "Purchase Order Basic Info",
tableTitle: "Order Details",
templateFileName: "Purchase Order Template",
},
},
sale: {
@@ -897,6 +933,7 @@ export default {
showItem: "Sale Details",
baseTitle: "Sale Order Basic Info",
tableTitle: "Sale Details",
templateFileName: "Sale Order Template",
},
repairrecord: {
add: "Add Repair Record",

View File

@@ -80,6 +80,11 @@ export default {
yes: "是",
no: "否",
},
_component: {
baseFormWithTable: {
uploadTip: "只能上传 xlsx/xls/csv 文件,且不超过 10MB",
},
},
_prop: {
common: {
tel: "电话",
@@ -339,6 +344,8 @@ export default {
formStatus: "审核状态",
customerName: "客户名称",
customerId: "客户",
storeNo: "出货仓库",
storeName: "出货仓库",
partNumber: "物料编号",
productSpecs: "物料型号",
saleCount: "销售数量",
@@ -809,6 +816,7 @@ export default {
sale: {
saleorder: {
select_customerId: "请选择客户",
select_storeNo: "请选择出货仓库",
input_formName: "请输入单据名称",
input_formMark: "请输入单据备注",
input_formCode: "请输入单据编号",
@@ -928,6 +936,7 @@ export default {
baseTitle: "调拨单基本信息",
tableTitle: "调拨明细",
stock_check_failed: "库存检测失败",
templateFileName: "调拨单模板",
},
warehousereceipt: {
add: "添加入库单",
@@ -935,6 +944,7 @@ export default {
showItem: "入库明细",
baseTitle: "入库单基本信息",
tableTitle: "入库明细",
templateFileName: "入库单模板",
},
inventorycount: {
add: "添加盘点单",
@@ -942,6 +952,7 @@ export default {
showItem: "盘点明细",
baseTitle: "盘点单基本信息",
tableTitle: "盘点明细",
templateFileName: "盘点单模板",
},
},
production: {
@@ -951,6 +962,7 @@ export default {
showItem: "BOM 明细",
baseTitle: "BOM 基本信息",
tableTitle: "BOM 明细",
templateFileName: "BOM模板",
},
production_plan: {
add: "新增生产计划",
@@ -972,6 +984,7 @@ export default {
baseTitle: "成品入库单基本信息",
tableTitle: "成品明细",
outstockDialog: "成品出货",
templateFileName: "成品入库单模板",
},
finishedproductshipment: {
add: "添加成品出货单",
@@ -979,6 +992,7 @@ export default {
showItem: "成品明细",
baseTitle: "成品出货单基本信息",
tableTitle: "成品明细",
templateFileName: "成品出货单模板",
},
saleorder: {
add: "添加销售订单",
@@ -986,6 +1000,7 @@ export default {
showItem: "销售明细",
baseTitle: "销售订单基本信息",
tableTitle: "销售明细",
templateFileName: "销售订单模板",
},
},
purchase: {
@@ -1001,6 +1016,7 @@ export default {
unitPrice: "单价",
totalPrice: "总价",
purchaseStatus: "采购状态",
templateFileName: "采购计划模板",
},
purchase_order: {
add: "新建采购订单",
@@ -1009,6 +1025,7 @@ export default {
qrcode: "二维码打印",
baseTitle: "采购订单基本信息",
tableTitle: "采购明细",
templateFileName: "采购订单模板",
},
},
sale: {
@@ -1018,6 +1035,7 @@ export default {
showItem: "销售明细",
baseTitle: "销售订单基本信息",
tableTitle: "销售明细",
templateFileName: "销售订单模板",
},
repairrecord: {
add: "添加维修记录",

View File

@@ -3,56 +3,104 @@ import { Upload, Download } from "@icon-park/vue-next";
import BaseForm from "../base-form/BaseForm.vue";
import { ElMessage, type UploadInstance, type UploadUserFile } from "element-plus";
import * as XLSX from "xlsx";
import { type ExcelDataMapping } from "./type";
import { type ExcelColumnConfig, type FieldMappingConfig, type DetailLoadConfig } from "./type";
import { Delete } from "@element-plus/icons-vue";
import { get } from "@/common/http/request";
import { $t } from "@/common/languages";
interface Emits {
(e: "update:mappedData", data: any[]): void;
(e: "error", msg: string): void;
}
const props = defineProps({
baseTitle: String,
tableTitle: String,
uploadDesc: String,
itemArrayName: { type: String, required: true },
mappingConfig: { type: Object, required: true },
templateFileName: { type: String, default: "模板" },
mappingConfig: { type: Object as () => FieldMappingConfig, required: true },
templateFileName: { type: String, required: true },
/**
* 明细数据加载配置
* 传入此配置后,组件会在编辑模式下自动加载明细数据
*/
detailConfig: { type: Object as () => DetailLoadConfig | null, default: null },
/**
* 模板列配置
* 用于控制模板中显示哪些列,如果不传则使用 mappingConfig 中的所有列
* 可以设置 include 或 exclude 来控制列的显示
* include: 只包含指定的列
* exclude: 排除指定的列
*/
templateColumns: {
type: Object as () => {
include?: string[];
exclude?: string[];
} | null,
default: null,
},
});
const emit = defineEmits<Emits>();
const form = defineModel<any>("form");
const visible = defineModel<boolean>("visible");
const uploadRef = ref<UploadInstance>();
const baseFormComponentRef = ref<InstanceType<typeof BaseForm> | null>(null);
const baseFormRef = ref<InstanceType<typeof BaseForm> | null>(null);
const getValue = (row: any, config: ExcelDataMapping) => {
const { sourceKey, defaultValue, transform } = config;
// 加载状态
const loading = ref(false);
/**
* 获取 Excel 列配置
* 统一处理为数组形式
*/
const getSourceKeys = (config: ExcelColumnConfig): string[] => {
const { sourceKey } = config;
if (Array.isArray(sourceKey)) {
return sourceKey;
}
return [sourceKey];
};
/**
* 获取表头文本
* 优先使用 header如果没有则使用 sourceKey 的第一个值
*/
const getHeaderText = (config: ExcelColumnConfig): string => {
if (config.header) {
return config.header;
}
const sourceKeys = getSourceKeys(config);
return sourceKeys[0] || "";
};
/**
* 从行数据中获取值
*/
const getValue = (row: any, config: ExcelColumnConfig) => {
const sourceKeys = getSourceKeys(config);
const { defaultValue, transform } = config;
let rawValue: any;
// 1. 处理 sourceKey 是数组的情况 (多对一 / 降级策略)
if (Array.isArray(sourceKey)) {
for (const key of sourceKey) {
const val = row[key];
// 只要找到非 undefined 且非 null 的值,就立即停止查找
if (val !== undefined && val !== null) {
rawValue = val;
break;
}
for (const key of sourceKeys) {
const val = row[key];
// 只要找到非 undefined 且非 null 的值,就立即停止查找
if (val !== undefined && val !== null && val !== "") {
rawValue = val;
break;
}
}
// 2. 处理 sourceKey 是字符串的情况 (一对一)
else if (typeof sourceKey === "string") {
rawValue = row[sourceKey];
}
// 3. 如果没找到值,使用默认值
// 2. 如果没找到值,使用默认值
if (rawValue === undefined || rawValue === null) {
rawValue = defaultValue;
}
// 4. 执行转换函数 (如果有)
// 3. 执行转换函数 (如果有)
if (transform && typeof transform === "function") {
try {
return transform(rawValue);
} catch (e) {
console.warn(`Transform error for key ${Array.isArray(sourceKey) ? sourceKey.join("/") : sourceKey}:`, e);
console.warn(`Transform error for key ${sourceKeys.join("/")}:`, e);
return defaultValue;
}
}
@@ -60,6 +108,9 @@ const getValue = (row: any, config: ExcelDataMapping) => {
return rawValue;
};
/**
* 转换 Excel 数据
*/
const convertData = (jsonData: any) => {
if (!Array.isArray(jsonData)) {
emit("error", "jsonData 必须是数组");
@@ -69,20 +120,67 @@ const convertData = (jsonData: any) => {
const result = jsonData.map(row => {
const newRow: any = {};
// Object.entries 返回的是 [string, any][],我们需要断言为正确的类型
// 或者直接在循环内部使用 config 变量
for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
// 显式断言 config 的类型,防止 entries 推断丢失泛型信息
const fieldConfig = config as ExcelDataMapping;
const fieldConfig = config as ExcelColumnConfig;
newRow[targetKey] = getValue(row, fieldConfig);
}
return newRow;
});
emit("update:mappedData", result);
return result;
};
/**
* 加载明细数据
*/
const loadDetailData = async () => {
if (!props.detailConfig || !form.value?.id) return;
const { url, paramName, dataPath = "data" } = props.detailConfig;
loading.value = true;
try {
const res = await get(url, { [paramName]: form.value.id });
// 根据 dataPath 获取数据
const keys = dataPath.split(".");
let items = res;
for (const key of keys) {
items = items?.[key];
if (items === undefined || items === null) break;
}
form.value[props.itemArrayName] = items || [];
} catch (error) {
console.error("加载明细数据失败:", error);
ElMessage.error("加载明细数据失败");
form.value[props.itemArrayName] = [];
} finally {
loading.value = false;
}
};
/**
* 监听 visible 变化
* 当弹窗打开且是编辑模式(有 id自动加载明细数据
*/
watch(
() => visible.value,
newVisible => {
if (newVisible && props.detailConfig && form.value?.id) {
// 编辑模式,自动加载明细
loadDetailData();
}
}
);
// 存储当前上传的文件信息,用于显示和移除
const currentFile = ref<UploadUserFile | null>(null);
/**
* 清空所有数据(文件 + 表格)
*/
const clearAllData = () => {
// 1. 清空文件引用
currentFile.value = null;
@@ -96,10 +194,14 @@ const clearAllData = () => {
}
// 4. 清空验证
if (baseFormComponentRef.value) {
baseFormComponentRef.value.clearValidate();
if (baseFormRef.value) {
baseFormRef.value.clearValidate();
}
};
/**
* 处理文件变化
*/
const handleFileChange = (file: any) => {
// 文件大小校验
const maxSize = 10 * 1024 * 1024; // 10MB
@@ -114,6 +216,10 @@ const handleFileChange = (file: any) => {
// 解析 Excel追加模式不清空原有数据
parseExcel(file.raw);
};
/**
* 解析 Excel 文件
*/
const parseExcel = (file: any) => {
const reader = new FileReader();
@@ -164,10 +270,9 @@ const parseExcel = (file: any) => {
reader.readAsArrayBuffer(file);
};
// 【新增】存储当前上传的文件信息,用于显示和移除
const currentFile = ref<UploadUserFile | null>(null);
// 【新增】只清理表格数据(保留基本表单数据)
/**
* 只清理表格数据(保留基本表单数据)
*/
const clearTableData = () => {
// 1. 清空表格数据
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
@@ -175,14 +280,16 @@ const clearTableData = () => {
}
// 2. 清空表单验证(仅表格相关)
if (baseFormComponentRef.value) {
baseFormComponentRef.value.clearValidate();
if (baseFormRef.value) {
baseFormRef.value.clearValidate();
}
ElMessage.success("表格数据已清空");
};
// 【新增】深度清理函数(清理表格+文件,保留基本表单数据)
/**
* 深度清理函数(清理表格+文件,保留基本表单数据)
*/
const resetFormData = () => {
// 1. 清空表格数据
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
@@ -194,12 +301,14 @@ const resetFormData = () => {
uploadRef.value?.clearFiles();
// 3. 清空表单验证
if (baseFormComponentRef.value) {
baseFormComponentRef.value.clearValidate();
if (baseFormRef.value) {
baseFormRef.value.clearValidate();
}
};
// 【新增】增加一行
/**
* 增加一行
*/
const addRow = () => {
if (!form.value) form.value = {};
if (!Array.isArray(form.value[props.itemArrayName])) {
@@ -208,39 +317,72 @@ const addRow = () => {
// 创建一个空行,根据 mappingConfig 生成默认结构
const newRow: any = {};
for (const [key, config] of Object.entries(props.mappingConfig)) {
const fieldConfig = config as ExcelDataMapping;
const fieldConfig = config as ExcelColumnConfig;
newRow[key] = fieldConfig.defaultValue !== undefined ? fieldConfig.defaultValue : "";
}
form.value[props.itemArrayName].push(newRow);
};
// 【新增】删除指定行
/**
* 删除指定行
*/
const deleteRow = (index: number) => {
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
form.value[props.itemArrayName].splice(index, 1);
}
};
// 【新增】移除文件
/**
* 移除文件
*/
const removeFile = () => {
clearAllData();
ElMessage.success("文件已移除,表格数据已清空");
};
// 【新增】下载模板文件
/**
* 获取模板列配置
* 根据 templateColumns 配置过滤 mappingConfig
*/
const getTemplateColumns = (): [string, ExcelColumnConfig][] => {
const allEntries = Object.entries(props.mappingConfig) as [string, ExcelColumnConfig][];
if (!props.templateColumns) {
return allEntries;
}
const { include, exclude } = props.templateColumns;
if (include && include.length > 0) {
// 只包含指定的列
return allEntries.filter(([key]) => include.includes(key));
}
if (exclude && exclude.length > 0) {
// 排除指定的列
return allEntries.filter(([key]) => !exclude.includes(key));
}
return allEntries;
};
/**
* 下载模板文件
*/
const downloadTemplate = () => {
// 1. 根据 mappingConfig 生成表头
// 1. 根据模板列配置生成表头
const headers: string[] = [];
for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
const fieldConfig = config as ExcelDataMapping;
// 使用 sourceKey 作为表头,如果是数组则使用第一个
let header: string;
if (Array.isArray(fieldConfig.sourceKey)) {
header = fieldConfig.sourceKey[0];
} else {
header = fieldConfig.sourceKey;
}
const colWidths: { wch: number }[] = [];
const templateColumns = getTemplateColumns();
for (const [targetKey, config] of templateColumns) {
// 使用 header 或 sourceKey 的第一个值作为表头
const header = getHeaderText(config);
headers.push(header);
// 使用配置的列宽,默认 20
colWidths.push({ wch: config.width || 20 });
}
// 2. 创建工作簿
@@ -250,7 +392,6 @@ const downloadTemplate = () => {
const ws = XLSX.utils.aoa_to_sheet([headers]);
// 4. 设置列宽
const colWidths = headers.map(() => ({ wch: 20 }));
ws["!cols"] = colWidths;
// 5. 将工作表添加到工作簿
@@ -263,21 +404,55 @@ const downloadTemplate = () => {
ElMessage.success("模板文件下载成功");
};
// 监听 BaseForm 发出的 reset 事件
/**
* 计算属性:确保表格数据始终是一个数组
*/
const tableData = computed(() => {
if (!form.value) return [];
const data = form.value[props.itemArrayName];
return Array.isArray(data) ? data : [];
});
/**
* 监听 form 变化,确保 itemArrayName 对应的属性是数组
*/
watch(
() => form.value,
newVal => {
if (newVal && !Array.isArray(newVal[props.itemArrayName])) {
newVal[props.itemArrayName] = [];
}
},
{ immediate: true }
);
/**
* 监听 BaseForm 发出的 reset 事件
*/
const handleBaseFormReset = () => {
resetFormData();
};
defineExpose({
innerFormRef: computed(() => baseFormComponentRef.value?.formRef),
innerFormRef: computed(() => baseFormRef.value?.formRef),
baseFormRef: computed(() => baseFormRef.value?.formRef),
resetFormData,
addRow,
deleteRow,
clearTableData,
downloadTemplate,
loadDetailData,
});
</script>
<template>
<BaseForm ref="baseFormRef" v-bind="$attrs" class="form-dialog" v-model:form="form" @reset="handleBaseFormReset">
<BaseForm
ref="baseFormRef"
v-bind="$attrs"
class="form-dialog"
v-model:form="form"
v-model:visible="visible"
@reset="handleBaseFormReset"
>
<template #form-items>
<el-divider content-position="left" v-if="props.baseTitle">
<el-icon><Document /></el-icon>
@@ -301,15 +476,11 @@ defineExpose({
:on-change="handleFileChange"
:show-file-list="false"
>
<el-button type="primary">
<el-button type="primary" :loading="loading">
<el-icon><Upload /></el-icon>
选择 Excel 文件
</el-button>
<span class="upload-tip-side">
只能上传 xlsx/xls/csv 文件且不超过 10MB
<br v-if="props.uploadDesc" />
<span class="tip-desc" v-if="props.uploadDesc">{{ uploadDesc }}</span>
</span>
<span class="upload-tip-side">{{ $t("_component.baseFormWithTable.uploadTip") }}</span>
</el-upload>
<el-button type="success" @click="downloadTemplate">
<el-icon><Download /></el-icon>
@@ -318,10 +489,17 @@ defineExpose({
</div>
</el-form-item>
<el-table :data="form[itemArrayName]" border style="width: 100%" max-height="400" class="form-item-table">
<el-table
:data="tableData"
border
style="width: 100%"
max-height="400"
class="form-item-table"
v-loading="loading"
>
<slot name="form-table-columns"></slot>
<!-- 新增固定操作列删除行 -->
<!-- 固定操作列删除行 -->
<el-table-column label="操作" width="80" align="center">
<template #default="{ $index }">
<el-button type="danger" link size="small" @click="deleteRow($index)">
@@ -331,7 +509,7 @@ defineExpose({
</el-table-column>
</el-table>
<!-- 新增表格下方操作栏 -->
<!-- 表格下方操作栏 -->
<div class="table-actions">
<el-button type="primary" link @click="addRow">
<el-icon><Plus /></el-icon>

View File

@@ -1,12 +1,26 @@
/**
* 用于映射 Excel 中的数据
* Excel 列配置
* 用于映射 Excel 中的数据以及生成模板文件
*/
export interface ExcelDataMapping {
export interface ExcelColumnConfig {
/**
* Excel 中的列名
* Excel 中的列名(支持多个,按顺序匹配)
* 例如:["物料编号", "partNumber", "商品编号"]
*/
sourceKey: string | string[];
/**
* 模板表头显示文本
* 如果不设置,默认使用 sourceKey 的第一个值
*/
header?: string;
/**
* 模板列宽(字符数)
* 默认 20
*/
width?: number;
/**
* 默认值
*/
@@ -23,4 +37,25 @@ export interface ExcelDataMapping {
/**
* 映射配置表 目标 key -> 规则
*/
export type FieldMappingConfig = Record<string, ExcelDataMapping>;
export type FieldMappingConfig = Record<string, ExcelColumnConfig>;
/**
* 明细数据加载配置
*/
export interface DetailLoadConfig {
/**
* 加载明细的接口地址
*/
url: string;
/**
* 参数名,如 'orderId'、'id'
*/
paramName: string;
/**
* 响应数据路径,如 'data'、'data.items'
* 默认 'data'
*/
dataPath?: string;
}

View File

@@ -7,7 +7,7 @@ import { ElMessage, type FormInstance, type FormItemRule, type FormRules } from
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 { type FieldMappingConfig, type DetailLoadConfig } from "@/components/base/base-form-with-table/type";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
/**
@@ -129,55 +129,56 @@ const operateButtonClick = (eventName: string, row: any) => {
};
const mappingConfig: FieldMappingConfig = {
// partNumber <- "商品编号" (默认空字符串)
partNumber: {
sourceKey: "商品编号",
sourceKey: ["商品编号", "partNumber"],
header: $t("_prop.production.bom_item.partNumber"),
width: 20,
defaultValue: "",
},
// itemPosition <- "位号" (默认空字符串)
itemPosition: {
sourceKey: "位号",
sourceKey: ["位号", "itemPosition"],
header: $t("_prop.production.bom_item.itemPosition"),
width: 20,
defaultValue: "",
},
// manufactureCount <- "用量" (默认 0且需要转为数字)
manufactureCount: {
sourceKey: "用量",
sourceKey: ["用量", "manufactureCount"],
header: $t("_prop.production.bom_item.manufactureCount"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
return isNaN(num) ? 0 : num;
},
},
// productMark <- "备注" (默认空字符串)
productMark: {
sourceKey: "备注",
sourceKey: ["备注", "productMark"],
header: $t("_prop.production.bom_item.productMark"),
width: 20,
defaultValue: "",
},
// sameUseNum1 <- "替换料1" (默认空字符串)
sameUseNum1: {
sourceKey: "替换料1",
sourceKey: ["替换料1", "sameUseNum1"],
header: $t("_prop.production.bom_item.sameUseNum") + "1",
width: 20,
defaultValue: "",
},
// sameUseNum2 <- "替换料2" (默认空字符串)
sameUseNum2: {
sourceKey: "替换料2",
sourceKey: ["替换料2", "sameUseNum2"],
header: $t("_prop.production.bom_item.sameUseNum") + "2",
width: 20,
defaultValue: "",
},
// sameUseNum3 <- "替换料3" (默认空字符串)
sameUseNum3: {
sourceKey: "替换料3",
sourceKey: ["替换料3", "sameUseNum3"],
header: $t("_prop.production.bom_item.sameUseNum") + "3",
width: 20,
defaultValue: "",
},
// sameUseCount <- "替换料数量" (默认 0且需要转为数字)
sameUseCount: {
sourceKey: "替换料数量",
sourceKey: ["替换料数量", "sameUseCount"],
header: $t("_prop.production.bom_item.sameUseCount"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
@@ -185,6 +186,12 @@ const mappingConfig: FieldMappingConfig = {
},
},
};
const detailConfig: DetailLoadConfig = {
url: itemUrl,
paramName: "bomId",
dataPath: "data",
};
const validateManufactureCount = (index: number) => {
return [
{
@@ -404,8 +411,9 @@ const handleItemPositionBlur = (index: number) => {
:base-title="$t('_title.production.bom.baseTitle')"
:table-title="$t('_title.production.bom.tableTitle')"
item-array-name="bomItems"
upload-desc="物料信息"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.production.bom.templateFileName')"
:detail-config="detailConfig"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -14,7 +14,7 @@ import BaseTableForm from "@/components/base/base-table-form/BaseTableForm.vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { get, post } from "@/common/http/request";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import { type FieldMappingConfig, type DetailLoadConfig } from "@/components/base/base-form-with-table/type";
/**
* 必须要的变量
@@ -137,51 +137,52 @@ const handleOutstockSelectionChange = (selection: any[]) => {
// Excel导入映射配置
const mappingConfig: FieldMappingConfig = {
// productType <- "型号" (默认空字符串)
productType: {
sourceKey: "型号",
sourceKey: ["型号", "productType"],
header: $t("_prop.production.finishedproductreceipt.productType"),
width: 15,
defaultValue: "",
},
// productSn <- "SN号" (默认空字符串)
productSn: {
sourceKey: "SN号",
sourceKey: ["SN号", "productSn"],
header: $t("_prop.production.finishedproductreceipt.productSn"),
width: 20,
defaultValue: "",
},
// mac <- "MAC地址" (默认空字符串)
mac: {
sourceKey: "MAC地址",
sourceKey: ["MAC地址", "mac"],
header: $t("_prop.production.finishedproductreceipt.mac"),
width: 18,
defaultValue: "",
},
// serialNum <- "序列号" (默认空字符串)
serialNum: {
sourceKey: "序列号",
sourceKey: ["序列号", "serialNum"],
header: $t("_prop.production.finishedproductreceipt.serialNum"),
width: 20,
defaultValue: "",
},
// softVersion <- "软件版本" (默认空字符串)
softVersion: {
sourceKey: "软件版本",
sourceKey: ["软件版本", "softVersion"],
header: $t("_prop.production.finishedproductreceipt.softVersion"),
width: 15,
defaultValue: "",
},
// alVersion <- "算法版本" (默认空字符串)
alVersion: {
sourceKey: "算法版本",
sourceKey: ["算法版本", "alVersion"],
header: $t("_prop.production.finishedproductreceipt.alVersion"),
width: 15,
defaultValue: "",
},
// alNum <- "算法标志" (默认空字符串)
alNum: {
sourceKey: "算法标志",
sourceKey: ["算法标志", "alNum"],
header: $t("_prop.production.finishedproductreceipt.alNum"),
width: 15,
defaultValue: "",
},
// alTxt <- "激活状态" (默认"未激活")
alTxt: {
sourceKey: "激活状态",
sourceKey: ["激活状态", "alTxt"],
header: $t("_prop.production.finishedproductreceipt.alTxt"),
width: 12,
defaultValue: "未激活",
transform: (val: any) => {
if (val === "已激活" || val === "Activated" || val === true || val === "1") return "已激活";
@@ -189,19 +190,25 @@ const mappingConfig: FieldMappingConfig = {
return "未激活";
},
},
// createDate <- "生产日期" (默认空字符串)
createDate: {
sourceKey: "生产日期",
sourceKey: ["生产日期", "createDate"],
header: $t("_prop.production.finishedproductreceipt.createDate"),
width: 15,
defaultValue: "",
},
// mark <- "备注" (默认空字符串)
mark: {
sourceKey: "备注",
sourceKey: ["备注", "mark"],
header: $t("_prop.production.finishedproductreceipt.mark"),
width: 20,
defaultValue: "",
},
};
const detailConfig: DetailLoadConfig = {
url: getDetailUrl,
paramName: "id",
dataPath: "data",
};
/**
* 可以自定义的变量
*/
@@ -425,8 +432,9 @@ const handleReset = () => {
:base-title="$t('_title.production.finishedproductreceipt.baseTitle')"
:table-title="$t('_title.production.finishedproductreceipt.tableTitle')"
:item-array-name="itemArrayName"
upload-desc="设备信息"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.production.finishedproductreceipt.templateFileName')"
:detail-config="detailConfig"
@reset="handleReset"
>
<template #form-items>

View File

@@ -12,7 +12,7 @@ import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import { type FieldMappingConfig, type DetailLoadConfig } from "@/components/base/base-form-with-table/type";
import { watch } from "vue";
/**
@@ -65,11 +65,21 @@ const outStockTypeOptions = [
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "物料编号",
sourceKey: ["物料编号", "partNumber"],
header: $t("_prop.production.finishedproductshipment.partNumber"),
width: 20,
defaultValue: "",
},
productSpecs: {
sourceKey: ["型号", "物料型号", "productSpecs", "productSpec"],
header: $t("_prop.production.finishedproductshipment.productSpecs"),
width: 20,
defaultValue: "",
},
productCount: {
sourceKey: "数量",
sourceKey: ["数量", "productCount"],
header: $t("_prop.production.finishedproductshipment.productCount"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
@@ -77,11 +87,19 @@ const mappingConfig: FieldMappingConfig = {
},
},
productMark: {
sourceKey: "备注",
sourceKey: ["备注", "productMark"],
header: $t("_prop.production.finishedproductshipment.productMark"),
width: 20,
defaultValue: "",
},
};
const detailConfig: DetailLoadConfig = {
url: getDetailUrl,
paramName: "id",
dataPath: "data",
};
/**
* 基本不变通用变量
*/
@@ -288,8 +306,9 @@ const handleReset = () => {
:base-title="$t('_title.production.finishedproductshipment.baseTitle')"
:table-title="$t('_title.production.finishedproductshipment.tableTitle')"
:item-array-name="itemArrayName"
upload-desc="物料信息"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.production.finishedproductshipment.templateFileName')"
:detail-config="detailConfig"
@reset="handleReset"
>
<template #form-items>

View File

@@ -97,7 +97,7 @@ const inboundForm = reactive({
orderCode: "",
vendorName: "",
formCode: "",
storeNo: null as number | null,
storeNo: null as number,
storeName: "",
formMark: "",
items: [] as any[],
@@ -426,8 +426,9 @@ const getFormStatusTagType = (code: number | null): string => {
:base-title="$t('_title.purchase.purchase_order.baseTitle')"
:table-title="$t('_title.purchase.purchase_order.tableTitle')"
item-array-name="items"
upload-desc="采购明细"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.purchase.purchase_order.templateFileName')"
:template-columns="{ exclude: ['purchaseMark'] }"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -429,8 +429,8 @@ const mappingConfig: FieldMappingConfig = {
:base-title="$t('_title.purchase.purchase_plan.baseTitle')"
:table-title="$t('_title.purchase.purchase_plan.tableTitle')"
item-array-name="planItems"
upload-desc="采购明细"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.purchase.purchase_plan.templateFileName')"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -8,9 +8,10 @@ import { formatDate } from "@/common/utils/format-utils";
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
import BaseSelect from "@/components/base/base-select/BaseSelect.vue";
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
import { get, post } from "@/common/http/request";
import { type FieldMappingConfig } from "@/components/base/base-form-with-table/type";
import { type FieldMappingConfig, type DetailLoadConfig } from "@/components/base/base-form-with-table/type";
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
/**
@@ -26,6 +27,7 @@ const rejectUrl = "/sale/saleorder/unapproveSaleOrder";
const itemUrl = "/sale/saleorder/getSaleOrderItemList";
const keyAccountSelectUrl = "/sys/keyaccount/getKeyAccountSelectList";
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
const warehouseSelectUrl = "/warehouse/warehouse/getWarehouseSelectList";
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.saleorder.searchCode") }];
@@ -34,6 +36,7 @@ const rules = reactive<FormRules>({
formName: [{ required: true, message: $t("_message.sale.saleorder.input_formName"), trigger: "blur" }],
customerId: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
customerName: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
storeNo: [{ required: true, message: $t("_message.sale.saleorder.select_storeNo"), trigger: "change" }],
partNumber: [
{
required: true,
@@ -77,10 +80,11 @@ const getDetailUrl = "/sale/saleorder/getSaleOrderItemList";
* 基本不变通用变量
*/
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
const { useAdd, useEdit, useRemove, useGeneralPageRef } = usePage(tableRef);
const { useAdd, useEdit, useRemove, useApprove, useReject, useGeneralPageRef } = 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>>();
/**
* 可以自定义的变量
@@ -123,6 +127,14 @@ const handleCustomerChange = (value: number) => {
}
};
// 监听仓库选择变化,同步更新仓库名称
const handleWarehouseChange = () => {
const label = warehouseSelectRef.value?.getLabel();
if (label) {
form.value.storeName = label;
}
};
const add = () => {
form.value = {
formCode: generateFormCode(),
@@ -134,21 +146,19 @@ const add = () => {
const edit = (row: any) => {
title.value = "_title.sale.saleorder.edit";
form.value = {
...row,
saleOrderItems: [],
};
form.value = { ...row };
visible.value = true;
formType.value = true;
// 加载明细数据
get(getDetailUrl, { saleOrderId: row.id })
.then(res => {
form.value.saleOrderItems = res.data || [];
})
.catch(err => {
console.error("Failed to load sale order items:", err);
});
// 延迟设置仓库名称,等待 BaseSelect 加载完成
if (row.storeNo) {
setTimeout(() => {
const label = warehouseSelectRef.value?.getLabel();
if (label && !form.value.storeName) {
form.value.storeName = label;
}
}, 300);
}
};
const remove = (row: any) => {
@@ -156,35 +166,11 @@ const remove = (row: any) => {
};
const approve = (row: any) => {
ElMessageBox.confirm($t("_message.sale.saleorder.approve_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(approveUrl, { id: row.id });
ElMessage.success($t("_message.sale.saleorder.approve_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.sale.saleorder.approve_fail") + err);
}
});
useApprove(approveUrl, row.id, "_message.sale.saleorder.approve_confirm");
};
const reject = (row: any) => {
ElMessageBox.confirm($t("_message.sale.saleorder.reject_confirm"), $t("_level.warning"), {
confirmButtonText: $t("_button.confirm"),
cancelButtonText: $t("_button.cancel"),
type: "warning",
}).then(async () => {
try {
await post(rejectUrl, { id: row.id });
ElMessage.success($t("_message.sale.saleorder.reject_success"));
tableRef.value?.reload();
} catch (err: any) {
ElMessage.error($t("_message.sale.saleorder.reject_fail") + err);
}
});
useReject(rejectUrl, row.id, "_message.sale.saleorder.reject_confirm");
};
const showItem = (row: any) => {
@@ -236,26 +222,32 @@ const operateButtonClick = (eventName: string, row: any) => {
};
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
// 已审核(status=1)时不显示审核按钮,显示反审按钮
// 未审核(status=0)时显示审核按钮,不显示反审按钮
if (row.status === 0 && button.eventName === "reject") return false;
if (row.status === 1 && button.eventName === "approve") return false;
// 已审核(formStatus=1)时不显示审核按钮,显示反审按钮
// 未审核(formStatus=0)时显示审核按钮,不显示反审按钮
if (row.formStatus === 0 && button.eventName === "reject") return false;
if (row.formStatus === 1 && button.eventName === "approve") return false;
// 已审核后不能编辑和删除
if (row.status === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
if (row.formStatus === 1 && (button.eventName === "edit" || button.eventName === "remove")) return false;
return true;
};
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: "物料编号",
sourceKey: ["物料编号", "partNumber"],
header: $t("_prop.sale.saleorder.partNumber"),
width: 20,
defaultValue: "",
},
productSpecs: {
sourceKey: "物料型号",
sourceKey: ["物料型号", "productSpecs"],
header: $t("_prop.sale.saleorder.productSpecs"),
width: 20,
defaultValue: "",
},
saleCount: {
sourceKey: "数量",
sourceKey: ["数量", "saleCount"],
header: $t("_prop.sale.saleorder.saleCount"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
@@ -263,7 +255,9 @@ const mappingConfig: FieldMappingConfig = {
},
},
price: {
sourceKey: "单价",
sourceKey: ["单价", "price"],
header: $t("_prop.sale.saleorder.price"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
@@ -271,11 +265,19 @@ const mappingConfig: FieldMappingConfig = {
},
},
saleMark: {
sourceKey: "备注",
sourceKey: ["备注", "saleMark"],
header: $t("_prop.sale.saleorder.saleMark"),
width: 20,
defaultValue: "",
},
};
const detailConfig: DetailLoadConfig = {
url: getDetailUrl,
paramName: "saleOrderId",
dataPath: "data",
};
// 计算总价
const calculateTotalPrice = (row: any) => {
if (row.saleCount && row.price) {
@@ -315,6 +317,7 @@ const getFormStatusTagType = (code: number | null): string => {
<template #columns>
<el-table-column :label="$t('_prop.sale.saleorder.formCode')" prop="formCode" />
<el-table-column :label="$t('_prop.sale.saleorder.customerName')" prop="customerName" />
<el-table-column :label="$t('_prop.sale.saleorder.storeName')" prop="storeName" />
<el-table-column :label="$t('_prop.sale.saleorder.totalValue')" prop="totalValue" />
<el-table-column :label="$t('_prop.sale.saleorder.formName')" prop="formName" />
<el-table-column :label="$t('_prop.sale.saleorder.formMark')" prop="formMark" show-overflow-tooltip />
@@ -346,8 +349,9 @@ const getFormStatusTagType = (code: number | null): string => {
:base-title="$t('_title.sale.saleorder.baseTitle')"
:table-title="$t('_title.sale.saleorder.tableTitle')"
item-array-name="saleOrderItems"
:upload-desc="$t('_title.sale.saleorder.tableTitle')"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.sale.saleorder.templateFileName')"
:detail-config="detailConfig"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>
@@ -375,14 +379,29 @@ const getFormStatusTagType = (code: number | null): string => {
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="$t('_prop.sale.saleorder.formMark')" prop="formMark">
<el-input
v-model="form.formMark"
:placeholder="$t('_message.sale.saleorder.input_formMark')"
type="textarea"
:rows="2"
/>
</el-form-item>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item :label="$t('_prop.sale.saleorder.storeNo')" prop="storeNo">
<BaseSelect
ref="warehouseSelectRef"
v-model="form.storeNo"
:url="warehouseSelectUrl"
style="width: 100%"
@change="handleWarehouseChange"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item :label="$t('_prop.sale.saleorder.formMark')" prop="formMark">
<el-input
v-model="form.formMark"
:placeholder="$t('_message.sale.saleorder.input_formMark')"
type="textarea"
:rows="1"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<template #form-table-columns>
<el-table-column :label="$t('_prop.sale.saleorder.partNumber')" width="150">
@@ -393,6 +412,14 @@ const getFormStatusTagType = (code: number | null): string => {
</template>
</el-table-column>
<el-table-column :label="$t('_prop.sale.saleorder.productSpecs')" width="200">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.productSpecs`">
<el-input v-model="row.productSpecs" size="small" />
</el-form-item>
</template>
</el-table-column>
<el-table-column :label="$t('_prop.sale.saleorder.saleCount')" width="120">
<template #default="{ row, $index }">
<el-form-item :prop="`${itemArrayName}.${$index}.saleCount`">

View File

@@ -240,8 +240,8 @@ const getFormTypeText = (reserve1: number) => {
:base-title="$t('_title.warehouse.inventorycount.baseTitle')"
:table-title="$t('_title.warehouse.inventorycount.tableTitle')"
item-array-name="countItems"
upload-desc="盘点明细"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.warehouse.inventorycount.templateFileName')"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -351,8 +351,8 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
:base-title="$t('_title.warehouse.stocktransferorder.baseTitle')"
:table-title="$t('_title.warehouse.stocktransferorder.tableTitle')"
item-array-name="transferOrderItems"
upload-desc="物料信息"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.warehouse.stocktransferorder.templateFileName')"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>

View File

@@ -16,7 +16,7 @@ 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 { type FieldMappingConfig, type DetailLoadConfig } from "@/components/base/base-form-with-table/type";
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
@@ -62,15 +62,21 @@ const rules = reactive<FormRules>({
const mappingConfig: FieldMappingConfig = {
partNumber: {
sourceKey: ["商品编号", "物料编号", "partNumber"],
sourceKey: ["商品编号", "物料编号", "partNumber", "物料编码"],
header: $t("_prop.warehouse.warehousereceipt.partNumber"),
width: 20,
defaultValue: "",
},
productSpec: {
sourceKey: ["型号", "物料型号", "productSpecs", "productSpec"],
sourceKey: ["物料规格", "型号", "物料型号", "规格", "规格型号", "productSpecs", "productSpec"],
header: $t("_prop.warehouse.warehousereceipt.productSpec"),
width: 20,
defaultValue: "",
},
productCount: {
sourceKey: ["数量", "入库数量", "productCount"],
sourceKey: ["数量", "入库数量", "productCount", "入库数"],
header: $t("_prop.warehouse.warehousereceipt.productCount"),
width: 15,
defaultValue: 0,
transform: (val: any) => {
const num = Number(val);
@@ -79,6 +85,12 @@ const mappingConfig: FieldMappingConfig = {
},
};
const detailConfig: DetailLoadConfig = {
url: getItemUrl,
paramName: "id",
dataPath: "data",
};
const add = () => {
form.value = {
formCode: generateDucumentNo(DocumentType.WarehouseReceipt),
@@ -96,16 +108,6 @@ const add = () => {
const edit = (row: any) => {
title.value = "_title.warehouse.warehousereceipt.edit";
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;
formType.value = true;
};
@@ -240,8 +242,9 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
:base-title="$t('_title.warehouse.warehousereceipt.baseTitle')"
:table-title="$t('_title.warehouse.warehousereceipt.tableTitle')"
item-array-name="receiptItems"
upload-desc="物料信息"
:mapping-config="mappingConfig"
:template-file-name="$t('_title.warehouse.warehousereceipt.templateFileName')"
:detail-config="detailConfig"
>
<template #form-items>
<el-form-item prop="id" v-if="false"><el-input v-model="form.id" /></el-form-item>