fix: 修复和完善 Excel 功能。
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"name": "teek-design-vue3-template",
|
"name": "teek-design-vue3-template",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Teek Design Vue3 后台管理系统",
|
"description": "牛安后台管理系统",
|
||||||
"author": "Teeker <2456019588@qq.com>",
|
"author": "Teeker <2456019588@qq.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -47,9 +47,6 @@ importers:
|
|||||||
qs:
|
qs:
|
||||||
specifier: ^6.14.0
|
specifier: ^6.14.0
|
||||||
version: 6.14.0
|
version: 6.14.0
|
||||||
remixicon:
|
|
||||||
specifier: ^4.9.1
|
|
||||||
version: 4.9.1
|
|
||||||
sortablejs:
|
sortablejs:
|
||||||
specifier: ^1.15.6
|
specifier: ^1.15.6
|
||||||
version: 1.15.6
|
version: 1.15.6
|
||||||
@@ -4260,9 +4257,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==}
|
resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
remixicon@4.9.1:
|
|
||||||
resolution: {integrity: sha512-36gLSoujkabnCFZFDyP17VNh9piuBA/rsXUb4auSJWLGsHVXtmxLj/EM5FjaEAGnk8oIAj1Azob/DZ2N+90lAQ==}
|
|
||||||
|
|
||||||
repeat-element@1.1.4:
|
repeat-element@1.1.4:
|
||||||
resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
|
resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -9675,8 +9669,6 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
set-function-name: 2.0.2
|
set-function-name: 2.0.2
|
||||||
|
|
||||||
remixicon@4.9.1: {}
|
|
||||||
|
|
||||||
repeat-element@1.1.4: {}
|
repeat-element@1.1.4: {}
|
||||||
|
|
||||||
repeat-string@1.6.1: {}
|
repeat-string@1.6.1: {}
|
||||||
|
|||||||
@@ -80,6 +80,11 @@ export default {
|
|||||||
yes: "Yes",
|
yes: "Yes",
|
||||||
no: "No",
|
no: "No",
|
||||||
},
|
},
|
||||||
|
_component: {
|
||||||
|
baseFormWithTable: {
|
||||||
|
uploadTip: "Only xlsx/xls/csv files are allowed, max 10MB",
|
||||||
|
},
|
||||||
|
},
|
||||||
_prop: {
|
_prop: {
|
||||||
common: {
|
common: {
|
||||||
tel: "Tel",
|
tel: "Tel",
|
||||||
@@ -339,6 +344,8 @@ export default {
|
|||||||
formStatus: "Audit Status",
|
formStatus: "Audit Status",
|
||||||
customerName: "Customer Name",
|
customerName: "Customer Name",
|
||||||
customerId: "Customer",
|
customerId: "Customer",
|
||||||
|
storeNo: "Warehouse",
|
||||||
|
storeName: "Warehouse",
|
||||||
partNumber: "Part Number",
|
partNumber: "Part Number",
|
||||||
productSpecs: "Product Specs",
|
productSpecs: "Product Specs",
|
||||||
saleCount: "Sale Count",
|
saleCount: "Sale Count",
|
||||||
@@ -754,6 +761,27 @@ export default {
|
|||||||
},
|
},
|
||||||
sale: {
|
sale: {
|
||||||
saleorder: {
|
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",
|
delete_message: "Delete Order",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -830,14 +858,17 @@ export default {
|
|||||||
add: "Add Transfer",
|
add: "Add Transfer",
|
||||||
edit: "Edit Transfer",
|
edit: "Edit Transfer",
|
||||||
stock_check_failed: "Stock check failed",
|
stock_check_failed: "Stock check failed",
|
||||||
|
templateFileName: "Transfer Order Template",
|
||||||
},
|
},
|
||||||
warehousereceipt: {
|
warehousereceipt: {
|
||||||
add: "Add Receipt",
|
add: "Add Receipt",
|
||||||
edit: "Edit Receipt",
|
edit: "Edit Receipt",
|
||||||
|
templateFileName: "Warehouse Receipt Template",
|
||||||
},
|
},
|
||||||
inventorycount: {
|
inventorycount: {
|
||||||
add: "Add Count",
|
add: "Add Count",
|
||||||
edit: "Edit Count",
|
edit: "Edit Count",
|
||||||
|
templateFileName: "Inventory Count Template",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
@@ -847,6 +878,7 @@ export default {
|
|||||||
showItem: "BOM Items",
|
showItem: "BOM Items",
|
||||||
baseTitle: "BOM Info",
|
baseTitle: "BOM Info",
|
||||||
tableTitle: "BOM Details",
|
tableTitle: "BOM Details",
|
||||||
|
templateFileName: "BOM Template",
|
||||||
},
|
},
|
||||||
production_plan: {
|
production_plan: {
|
||||||
add: "Add Plan",
|
add: "Add Plan",
|
||||||
@@ -868,10 +900,12 @@ export default {
|
|||||||
baseTitle: "Receipt Basic Info",
|
baseTitle: "Receipt Basic Info",
|
||||||
tableTitle: "Product Details",
|
tableTitle: "Product Details",
|
||||||
outstockDialog: "Product Outstock",
|
outstockDialog: "Product Outstock",
|
||||||
|
templateFileName: "Finished Product Receipt Template",
|
||||||
},
|
},
|
||||||
finishedproductshipment: {
|
finishedproductshipment: {
|
||||||
add: "Add Shipment",
|
add: "Add Shipment",
|
||||||
edit: "Edit Shipment",
|
edit: "Edit Shipment",
|
||||||
|
templateFileName: "Finished Product Shipment Template",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
purchase: {
|
purchase: {
|
||||||
@@ -881,6 +915,7 @@ export default {
|
|||||||
showItem: "Plan Items",
|
showItem: "Plan Items",
|
||||||
baseTitle: "Purchase Plan Basic Info",
|
baseTitle: "Purchase Plan Basic Info",
|
||||||
tableTitle: "Purchase Details",
|
tableTitle: "Purchase Details",
|
||||||
|
templateFileName: "Purchase Plan Template",
|
||||||
},
|
},
|
||||||
purchaseorder: {
|
purchaseorder: {
|
||||||
add: "Add Purchase Order",
|
add: "Add Purchase Order",
|
||||||
@@ -888,6 +923,7 @@ export default {
|
|||||||
showItem: "Order Items",
|
showItem: "Order Items",
|
||||||
baseTitle: "Purchase Order Basic Info",
|
baseTitle: "Purchase Order Basic Info",
|
||||||
tableTitle: "Order Details",
|
tableTitle: "Order Details",
|
||||||
|
templateFileName: "Purchase Order Template",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sale: {
|
sale: {
|
||||||
@@ -897,6 +933,7 @@ export default {
|
|||||||
showItem: "Sale Details",
|
showItem: "Sale Details",
|
||||||
baseTitle: "Sale Order Basic Info",
|
baseTitle: "Sale Order Basic Info",
|
||||||
tableTitle: "Sale Details",
|
tableTitle: "Sale Details",
|
||||||
|
templateFileName: "Sale Order Template",
|
||||||
},
|
},
|
||||||
repairrecord: {
|
repairrecord: {
|
||||||
add: "Add Repair Record",
|
add: "Add Repair Record",
|
||||||
|
|||||||
@@ -80,6 +80,11 @@ export default {
|
|||||||
yes: "是",
|
yes: "是",
|
||||||
no: "否",
|
no: "否",
|
||||||
},
|
},
|
||||||
|
_component: {
|
||||||
|
baseFormWithTable: {
|
||||||
|
uploadTip: "只能上传 xlsx/xls/csv 文件,且不超过 10MB",
|
||||||
|
},
|
||||||
|
},
|
||||||
_prop: {
|
_prop: {
|
||||||
common: {
|
common: {
|
||||||
tel: "电话",
|
tel: "电话",
|
||||||
@@ -339,6 +344,8 @@ export default {
|
|||||||
formStatus: "审核状态",
|
formStatus: "审核状态",
|
||||||
customerName: "客户名称",
|
customerName: "客户名称",
|
||||||
customerId: "客户",
|
customerId: "客户",
|
||||||
|
storeNo: "出货仓库",
|
||||||
|
storeName: "出货仓库",
|
||||||
partNumber: "物料编号",
|
partNumber: "物料编号",
|
||||||
productSpecs: "物料型号",
|
productSpecs: "物料型号",
|
||||||
saleCount: "销售数量",
|
saleCount: "销售数量",
|
||||||
@@ -809,6 +816,7 @@ export default {
|
|||||||
sale: {
|
sale: {
|
||||||
saleorder: {
|
saleorder: {
|
||||||
select_customerId: "请选择客户",
|
select_customerId: "请选择客户",
|
||||||
|
select_storeNo: "请选择出货仓库",
|
||||||
input_formName: "请输入单据名称",
|
input_formName: "请输入单据名称",
|
||||||
input_formMark: "请输入单据备注",
|
input_formMark: "请输入单据备注",
|
||||||
input_formCode: "请输入单据编号",
|
input_formCode: "请输入单据编号",
|
||||||
@@ -928,6 +936,7 @@ export default {
|
|||||||
baseTitle: "调拨单基本信息",
|
baseTitle: "调拨单基本信息",
|
||||||
tableTitle: "调拨明细",
|
tableTitle: "调拨明细",
|
||||||
stock_check_failed: "库存检测失败",
|
stock_check_failed: "库存检测失败",
|
||||||
|
templateFileName: "调拨单模板",
|
||||||
},
|
},
|
||||||
warehousereceipt: {
|
warehousereceipt: {
|
||||||
add: "添加入库单",
|
add: "添加入库单",
|
||||||
@@ -935,6 +944,7 @@ export default {
|
|||||||
showItem: "入库明细",
|
showItem: "入库明细",
|
||||||
baseTitle: "入库单基本信息",
|
baseTitle: "入库单基本信息",
|
||||||
tableTitle: "入库明细",
|
tableTitle: "入库明细",
|
||||||
|
templateFileName: "入库单模板",
|
||||||
},
|
},
|
||||||
inventorycount: {
|
inventorycount: {
|
||||||
add: "添加盘点单",
|
add: "添加盘点单",
|
||||||
@@ -942,6 +952,7 @@ export default {
|
|||||||
showItem: "盘点明细",
|
showItem: "盘点明细",
|
||||||
baseTitle: "盘点单基本信息",
|
baseTitle: "盘点单基本信息",
|
||||||
tableTitle: "盘点明细",
|
tableTitle: "盘点明细",
|
||||||
|
templateFileName: "盘点单模板",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
production: {
|
production: {
|
||||||
@@ -951,6 +962,7 @@ export default {
|
|||||||
showItem: "BOM 明细",
|
showItem: "BOM 明细",
|
||||||
baseTitle: "BOM 基本信息",
|
baseTitle: "BOM 基本信息",
|
||||||
tableTitle: "BOM 明细",
|
tableTitle: "BOM 明细",
|
||||||
|
templateFileName: "BOM模板",
|
||||||
},
|
},
|
||||||
production_plan: {
|
production_plan: {
|
||||||
add: "新增生产计划",
|
add: "新增生产计划",
|
||||||
@@ -972,6 +984,7 @@ export default {
|
|||||||
baseTitle: "成品入库单基本信息",
|
baseTitle: "成品入库单基本信息",
|
||||||
tableTitle: "成品明细",
|
tableTitle: "成品明细",
|
||||||
outstockDialog: "成品出货",
|
outstockDialog: "成品出货",
|
||||||
|
templateFileName: "成品入库单模板",
|
||||||
},
|
},
|
||||||
finishedproductshipment: {
|
finishedproductshipment: {
|
||||||
add: "添加成品出货单",
|
add: "添加成品出货单",
|
||||||
@@ -979,6 +992,7 @@ export default {
|
|||||||
showItem: "成品明细",
|
showItem: "成品明细",
|
||||||
baseTitle: "成品出货单基本信息",
|
baseTitle: "成品出货单基本信息",
|
||||||
tableTitle: "成品明细",
|
tableTitle: "成品明细",
|
||||||
|
templateFileName: "成品出货单模板",
|
||||||
},
|
},
|
||||||
saleorder: {
|
saleorder: {
|
||||||
add: "添加销售订单",
|
add: "添加销售订单",
|
||||||
@@ -986,6 +1000,7 @@ export default {
|
|||||||
showItem: "销售明细",
|
showItem: "销售明细",
|
||||||
baseTitle: "销售订单基本信息",
|
baseTitle: "销售订单基本信息",
|
||||||
tableTitle: "销售明细",
|
tableTitle: "销售明细",
|
||||||
|
templateFileName: "销售订单模板",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
purchase: {
|
purchase: {
|
||||||
@@ -1001,6 +1016,7 @@ export default {
|
|||||||
unitPrice: "单价",
|
unitPrice: "单价",
|
||||||
totalPrice: "总价",
|
totalPrice: "总价",
|
||||||
purchaseStatus: "采购状态",
|
purchaseStatus: "采购状态",
|
||||||
|
templateFileName: "采购计划模板",
|
||||||
},
|
},
|
||||||
purchase_order: {
|
purchase_order: {
|
||||||
add: "新建采购订单",
|
add: "新建采购订单",
|
||||||
@@ -1009,6 +1025,7 @@ export default {
|
|||||||
qrcode: "二维码打印",
|
qrcode: "二维码打印",
|
||||||
baseTitle: "采购订单基本信息",
|
baseTitle: "采购订单基本信息",
|
||||||
tableTitle: "采购明细",
|
tableTitle: "采购明细",
|
||||||
|
templateFileName: "采购订单模板",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sale: {
|
sale: {
|
||||||
@@ -1018,6 +1035,7 @@ export default {
|
|||||||
showItem: "销售明细",
|
showItem: "销售明细",
|
||||||
baseTitle: "销售订单基本信息",
|
baseTitle: "销售订单基本信息",
|
||||||
tableTitle: "销售明细",
|
tableTitle: "销售明细",
|
||||||
|
templateFileName: "销售订单模板",
|
||||||
},
|
},
|
||||||
repairrecord: {
|
repairrecord: {
|
||||||
add: "添加维修记录",
|
add: "添加维修记录",
|
||||||
|
|||||||
@@ -3,56 +3,104 @@ import { Upload, Download } from "@icon-park/vue-next";
|
|||||||
import BaseForm from "../base-form/BaseForm.vue";
|
import BaseForm from "../base-form/BaseForm.vue";
|
||||||
import { ElMessage, type UploadInstance, type UploadUserFile } from "element-plus";
|
import { ElMessage, type UploadInstance, type UploadUserFile } from "element-plus";
|
||||||
import * as XLSX from "xlsx";
|
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 { Delete } from "@element-plus/icons-vue";
|
||||||
|
import { get } from "@/common/http/request";
|
||||||
|
import { $t } from "@/common/languages";
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: "update:mappedData", data: any[]): void;
|
|
||||||
(e: "error", msg: string): void;
|
(e: "error", msg: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
baseTitle: String,
|
baseTitle: String,
|
||||||
tableTitle: String,
|
tableTitle: String,
|
||||||
uploadDesc: String,
|
|
||||||
itemArrayName: { type: String, required: true },
|
itemArrayName: { type: String, required: true },
|
||||||
mappingConfig: { type: Object, required: true },
|
mappingConfig: { type: Object as () => FieldMappingConfig, required: true },
|
||||||
templateFileName: { type: String, default: "模板" },
|
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 emit = defineEmits<Emits>();
|
||||||
const form = defineModel<any>("form");
|
const form = defineModel<any>("form");
|
||||||
|
const visible = defineModel<boolean>("visible");
|
||||||
const uploadRef = ref<UploadInstance>();
|
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;
|
let rawValue: any;
|
||||||
|
|
||||||
// 1. 处理 sourceKey 是数组的情况 (多对一 / 降级策略)
|
// 1. 处理 sourceKey 是数组的情况 (多对一 / 降级策略)
|
||||||
if (Array.isArray(sourceKey)) {
|
for (const key of sourceKeys) {
|
||||||
for (const key of sourceKey) {
|
const val = row[key];
|
||||||
const val = row[key];
|
// 只要找到非 undefined 且非 null 的值,就立即停止查找
|
||||||
// 只要找到非 undefined 且非 null 的值,就立即停止查找
|
if (val !== undefined && val !== null && val !== "") {
|
||||||
if (val !== undefined && val !== null) {
|
rawValue = val;
|
||||||
rawValue = val;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2. 处理 sourceKey 是字符串的情况 (一对一)
|
|
||||||
else if (typeof sourceKey === "string") {
|
|
||||||
rawValue = row[sourceKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 如果没找到值,使用默认值
|
// 2. 如果没找到值,使用默认值
|
||||||
if (rawValue === undefined || rawValue === null) {
|
if (rawValue === undefined || rawValue === null) {
|
||||||
rawValue = defaultValue;
|
rawValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 执行转换函数 (如果有)
|
// 3. 执行转换函数 (如果有)
|
||||||
if (transform && typeof transform === "function") {
|
if (transform && typeof transform === "function") {
|
||||||
try {
|
try {
|
||||||
return transform(rawValue);
|
return transform(rawValue);
|
||||||
} catch (e) {
|
} 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;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,6 +108,9 @@ const getValue = (row: any, config: ExcelDataMapping) => {
|
|||||||
return rawValue;
|
return rawValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换 Excel 数据
|
||||||
|
*/
|
||||||
const convertData = (jsonData: any) => {
|
const convertData = (jsonData: any) => {
|
||||||
if (!Array.isArray(jsonData)) {
|
if (!Array.isArray(jsonData)) {
|
||||||
emit("error", "jsonData 必须是数组");
|
emit("error", "jsonData 必须是数组");
|
||||||
@@ -69,20 +120,67 @@ const convertData = (jsonData: any) => {
|
|||||||
const result = jsonData.map(row => {
|
const result = jsonData.map(row => {
|
||||||
const newRow: any = {};
|
const newRow: any = {};
|
||||||
|
|
||||||
// Object.entries 返回的是 [string, any][],我们需要断言为正确的类型
|
|
||||||
// 或者直接在循环内部使用 config 变量
|
|
||||||
for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
|
for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
|
||||||
// 显式断言 config 的类型,防止 entries 推断丢失泛型信息
|
const fieldConfig = config as ExcelColumnConfig;
|
||||||
const fieldConfig = config as ExcelDataMapping;
|
|
||||||
newRow[targetKey] = getValue(row, fieldConfig);
|
newRow[targetKey] = getValue(row, fieldConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newRow;
|
return newRow;
|
||||||
});
|
});
|
||||||
|
|
||||||
emit("update:mappedData", result);
|
|
||||||
return 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 = () => {
|
const clearAllData = () => {
|
||||||
// 1. 清空文件引用
|
// 1. 清空文件引用
|
||||||
currentFile.value = null;
|
currentFile.value = null;
|
||||||
@@ -96,10 +194,14 @@ const clearAllData = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. 清空验证
|
// 4. 清空验证
|
||||||
if (baseFormComponentRef.value) {
|
if (baseFormRef.value) {
|
||||||
baseFormComponentRef.value.clearValidate();
|
baseFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理文件变化
|
||||||
|
*/
|
||||||
const handleFileChange = (file: any) => {
|
const handleFileChange = (file: any) => {
|
||||||
// 文件大小校验
|
// 文件大小校验
|
||||||
const maxSize = 10 * 1024 * 1024; // 10MB
|
const maxSize = 10 * 1024 * 1024; // 10MB
|
||||||
@@ -114,6 +216,10 @@ const handleFileChange = (file: any) => {
|
|||||||
// 解析 Excel(追加模式,不清空原有数据)
|
// 解析 Excel(追加模式,不清空原有数据)
|
||||||
parseExcel(file.raw);
|
parseExcel(file.raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 Excel 文件
|
||||||
|
*/
|
||||||
const parseExcel = (file: any) => {
|
const parseExcel = (file: any) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
||||||
@@ -164,10 +270,9 @@ const parseExcel = (file: any) => {
|
|||||||
reader.readAsArrayBuffer(file);
|
reader.readAsArrayBuffer(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 【新增】存储当前上传的文件信息,用于显示和移除
|
/**
|
||||||
const currentFile = ref<UploadUserFile | null>(null);
|
* 只清理表格数据(保留基本表单数据)
|
||||||
|
*/
|
||||||
// 【新增】只清理表格数据(保留基本表单数据)
|
|
||||||
const clearTableData = () => {
|
const clearTableData = () => {
|
||||||
// 1. 清空表格数据
|
// 1. 清空表格数据
|
||||||
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
||||||
@@ -175,14 +280,16 @@ const clearTableData = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. 清空表单验证(仅表格相关)
|
// 2. 清空表单验证(仅表格相关)
|
||||||
if (baseFormComponentRef.value) {
|
if (baseFormRef.value) {
|
||||||
baseFormComponentRef.value.clearValidate();
|
baseFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
ElMessage.success("表格数据已清空");
|
ElMessage.success("表格数据已清空");
|
||||||
};
|
};
|
||||||
|
|
||||||
// 【新增】深度清理函数(清理表格+文件,保留基本表单数据)
|
/**
|
||||||
|
* 深度清理函数(清理表格+文件,保留基本表单数据)
|
||||||
|
*/
|
||||||
const resetFormData = () => {
|
const resetFormData = () => {
|
||||||
// 1. 清空表格数据
|
// 1. 清空表格数据
|
||||||
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
||||||
@@ -194,12 +301,14 @@ const resetFormData = () => {
|
|||||||
uploadRef.value?.clearFiles();
|
uploadRef.value?.clearFiles();
|
||||||
|
|
||||||
// 3. 清空表单验证
|
// 3. 清空表单验证
|
||||||
if (baseFormComponentRef.value) {
|
if (baseFormRef.value) {
|
||||||
baseFormComponentRef.value.clearValidate();
|
baseFormRef.value.clearValidate();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 【新增】增加一行
|
/**
|
||||||
|
* 增加一行
|
||||||
|
*/
|
||||||
const addRow = () => {
|
const addRow = () => {
|
||||||
if (!form.value) form.value = {};
|
if (!form.value) form.value = {};
|
||||||
if (!Array.isArray(form.value[props.itemArrayName])) {
|
if (!Array.isArray(form.value[props.itemArrayName])) {
|
||||||
@@ -208,39 +317,72 @@ const addRow = () => {
|
|||||||
// 创建一个空行,根据 mappingConfig 生成默认结构
|
// 创建一个空行,根据 mappingConfig 生成默认结构
|
||||||
const newRow: any = {};
|
const newRow: any = {};
|
||||||
for (const [key, config] of Object.entries(props.mappingConfig)) {
|
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 : "";
|
newRow[key] = fieldConfig.defaultValue !== undefined ? fieldConfig.defaultValue : "";
|
||||||
}
|
}
|
||||||
form.value[props.itemArrayName].push(newRow);
|
form.value[props.itemArrayName].push(newRow);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 【新增】删除指定行
|
/**
|
||||||
|
* 删除指定行
|
||||||
|
*/
|
||||||
const deleteRow = (index: number) => {
|
const deleteRow = (index: number) => {
|
||||||
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
if (form.value && Array.isArray(form.value[props.itemArrayName])) {
|
||||||
form.value[props.itemArrayName].splice(index, 1);
|
form.value[props.itemArrayName].splice(index, 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 【新增】移除文件
|
/**
|
||||||
|
* 移除文件
|
||||||
|
*/
|
||||||
const removeFile = () => {
|
const removeFile = () => {
|
||||||
clearAllData();
|
clearAllData();
|
||||||
ElMessage.success("文件已移除,表格数据已清空");
|
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 = () => {
|
const downloadTemplate = () => {
|
||||||
// 1. 根据 mappingConfig 生成表头
|
// 1. 根据模板列配置生成表头
|
||||||
const headers: string[] = [];
|
const headers: string[] = [];
|
||||||
for (const [targetKey, config] of Object.entries(props.mappingConfig)) {
|
const colWidths: { wch: number }[] = [];
|
||||||
const fieldConfig = config as ExcelDataMapping;
|
|
||||||
// 使用 sourceKey 作为表头,如果是数组则使用第一个
|
const templateColumns = getTemplateColumns();
|
||||||
let header: string;
|
|
||||||
if (Array.isArray(fieldConfig.sourceKey)) {
|
for (const [targetKey, config] of templateColumns) {
|
||||||
header = fieldConfig.sourceKey[0];
|
// 使用 header 或 sourceKey 的第一个值作为表头
|
||||||
} else {
|
const header = getHeaderText(config);
|
||||||
header = fieldConfig.sourceKey;
|
|
||||||
}
|
|
||||||
headers.push(header);
|
headers.push(header);
|
||||||
|
|
||||||
|
// 使用配置的列宽,默认 20
|
||||||
|
colWidths.push({ wch: config.width || 20 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 创建工作簿
|
// 2. 创建工作簿
|
||||||
@@ -250,7 +392,6 @@ const downloadTemplate = () => {
|
|||||||
const ws = XLSX.utils.aoa_to_sheet([headers]);
|
const ws = XLSX.utils.aoa_to_sheet([headers]);
|
||||||
|
|
||||||
// 4. 设置列宽
|
// 4. 设置列宽
|
||||||
const colWidths = headers.map(() => ({ wch: 20 }));
|
|
||||||
ws["!cols"] = colWidths;
|
ws["!cols"] = colWidths;
|
||||||
|
|
||||||
// 5. 将工作表添加到工作簿
|
// 5. 将工作表添加到工作簿
|
||||||
@@ -263,21 +404,55 @@ const downloadTemplate = () => {
|
|||||||
ElMessage.success("模板文件下载成功");
|
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 = () => {
|
const handleBaseFormReset = () => {
|
||||||
resetFormData();
|
resetFormData();
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
innerFormRef: computed(() => baseFormComponentRef.value?.formRef),
|
innerFormRef: computed(() => baseFormRef.value?.formRef),
|
||||||
|
baseFormRef: computed(() => baseFormRef.value?.formRef),
|
||||||
resetFormData,
|
resetFormData,
|
||||||
addRow,
|
addRow,
|
||||||
deleteRow,
|
deleteRow,
|
||||||
clearTableData,
|
clearTableData,
|
||||||
downloadTemplate,
|
downloadTemplate,
|
||||||
|
loadDetailData,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<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>
|
<template #form-items>
|
||||||
<el-divider content-position="left" v-if="props.baseTitle">
|
<el-divider content-position="left" v-if="props.baseTitle">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon><Document /></el-icon>
|
||||||
@@ -301,15 +476,11 @@ defineExpose({
|
|||||||
:on-change="handleFileChange"
|
:on-change="handleFileChange"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
>
|
>
|
||||||
<el-button type="primary">
|
<el-button type="primary" :loading="loading">
|
||||||
<el-icon><Upload /></el-icon>
|
<el-icon><Upload /></el-icon>
|
||||||
选择 Excel 文件
|
选择 Excel 文件
|
||||||
</el-button>
|
</el-button>
|
||||||
<span class="upload-tip-side">
|
<span class="upload-tip-side">{{ $t("_component.baseFormWithTable.uploadTip") }}</span>
|
||||||
只能上传 xlsx/xls/csv 文件,且不超过 10MB
|
|
||||||
<br v-if="props.uploadDesc" />
|
|
||||||
<span class="tip-desc" v-if="props.uploadDesc">{{ uploadDesc }}</span>
|
|
||||||
</span>
|
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<el-button type="success" @click="downloadTemplate">
|
<el-button type="success" @click="downloadTemplate">
|
||||||
<el-icon><Download /></el-icon>
|
<el-icon><Download /></el-icon>
|
||||||
@@ -318,10 +489,17 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</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>
|
<slot name="form-table-columns"></slot>
|
||||||
|
|
||||||
<!-- 【新增】固定操作列:删除行 -->
|
<!-- 固定操作列:删除行 -->
|
||||||
<el-table-column label="操作" width="80" align="center">
|
<el-table-column label="操作" width="80" align="center">
|
||||||
<template #default="{ $index }">
|
<template #default="{ $index }">
|
||||||
<el-button type="danger" link size="small" @click="deleteRow($index)">
|
<el-button type="danger" link size="small" @click="deleteRow($index)">
|
||||||
@@ -331,7 +509,7 @@ defineExpose({
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 【新增】表格下方操作栏 -->
|
<!-- 表格下方操作栏 -->
|
||||||
<div class="table-actions">
|
<div class="table-actions">
|
||||||
<el-button type="primary" link @click="addRow">
|
<el-button type="primary" link @click="addRow">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
/**
|
/**
|
||||||
* 用于映射 Excel 中的数据
|
* Excel 列配置
|
||||||
|
* 用于映射 Excel 中的数据以及生成模板文件
|
||||||
*/
|
*/
|
||||||
export interface ExcelDataMapping {
|
export interface ExcelColumnConfig {
|
||||||
/**
|
/**
|
||||||
* Excel 中的列名
|
* Excel 中的列名(支持多个,按顺序匹配)
|
||||||
|
* 例如:["物料编号", "partNumber", "商品编号"]
|
||||||
*/
|
*/
|
||||||
sourceKey: string | string[];
|
sourceKey: string | string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板表头显示文本
|
||||||
|
* 如果不设置,默认使用 sourceKey 的第一个值
|
||||||
|
*/
|
||||||
|
header?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板列宽(字符数)
|
||||||
|
* 默认 20
|
||||||
|
*/
|
||||||
|
width?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认值
|
* 默认值
|
||||||
*/
|
*/
|
||||||
@@ -23,4 +37,25 @@ export interface ExcelDataMapping {
|
|||||||
/**
|
/**
|
||||||
* 映射配置表 目标 key -> 规则
|
* 映射配置表 目标 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ElMessage, type FormInstance, type FormItemRule, type FormRules } from
|
|||||||
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
|
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
|
||||||
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
||||||
import { get } from "@/common/http/request";
|
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";
|
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,55 +129,56 @@ const operateButtonClick = (eventName: string, row: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mappingConfig: FieldMappingConfig = {
|
const mappingConfig: FieldMappingConfig = {
|
||||||
// partNumber <- "商品编号" (默认空字符串)
|
|
||||||
partNumber: {
|
partNumber: {
|
||||||
sourceKey: "商品编号",
|
sourceKey: ["商品编号", "partNumber"],
|
||||||
|
header: $t("_prop.production.bom_item.partNumber"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// itemPosition <- "位号" (默认空字符串)
|
|
||||||
itemPosition: {
|
itemPosition: {
|
||||||
sourceKey: "位号",
|
sourceKey: ["位号", "itemPosition"],
|
||||||
|
header: $t("_prop.production.bom_item.itemPosition"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// manufactureCount <- "用量" (默认 0,且需要转为数字)
|
|
||||||
manufactureCount: {
|
manufactureCount: {
|
||||||
sourceKey: "用量",
|
sourceKey: ["用量", "manufactureCount"],
|
||||||
|
header: $t("_prop.production.bom_item.manufactureCount"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
return isNaN(num) ? 0 : num;
|
return isNaN(num) ? 0 : num;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// productMark <- "备注" (默认空字符串)
|
|
||||||
productMark: {
|
productMark: {
|
||||||
sourceKey: "备注",
|
sourceKey: ["备注", "productMark"],
|
||||||
|
header: $t("_prop.production.bom_item.productMark"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// sameUseNum1 <- "替换料1" (默认空字符串)
|
|
||||||
sameUseNum1: {
|
sameUseNum1: {
|
||||||
sourceKey: "替换料1",
|
sourceKey: ["替换料1", "sameUseNum1"],
|
||||||
|
header: $t("_prop.production.bom_item.sameUseNum") + "1",
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// sameUseNum2 <- "替换料2" (默认空字符串)
|
|
||||||
sameUseNum2: {
|
sameUseNum2: {
|
||||||
sourceKey: "替换料2",
|
sourceKey: ["替换料2", "sameUseNum2"],
|
||||||
|
header: $t("_prop.production.bom_item.sameUseNum") + "2",
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// sameUseNum3 <- "替换料3" (默认空字符串)
|
|
||||||
sameUseNum3: {
|
sameUseNum3: {
|
||||||
sourceKey: "替换料3",
|
sourceKey: ["替换料3", "sameUseNum3"],
|
||||||
|
header: $t("_prop.production.bom_item.sameUseNum") + "3",
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// sameUseCount <- "替换料数量" (默认 0,且需要转为数字)
|
|
||||||
sameUseCount: {
|
sameUseCount: {
|
||||||
sourceKey: "替换料数量",
|
sourceKey: ["替换料数量", "sameUseCount"],
|
||||||
|
header: $t("_prop.production.bom_item.sameUseCount"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
@@ -185,6 +186,12 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const detailConfig: DetailLoadConfig = {
|
||||||
|
url: itemUrl,
|
||||||
|
paramName: "bomId",
|
||||||
|
dataPath: "data",
|
||||||
|
};
|
||||||
const validateManufactureCount = (index: number) => {
|
const validateManufactureCount = (index: number) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -404,8 +411,9 @@ const handleItemPositionBlur = (index: number) => {
|
|||||||
:base-title="$t('_title.production.bom.baseTitle')"
|
:base-title="$t('_title.production.bom.baseTitle')"
|
||||||
:table-title="$t('_title.production.bom.tableTitle')"
|
:table-title="$t('_title.production.bom.tableTitle')"
|
||||||
item-array-name="bomItems"
|
item-array-name="bomItems"
|
||||||
upload-desc="物料信息"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.production.bom.templateFileName')"
|
||||||
|
:detail-config="detailConfig"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
@@ -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 { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
||||||
import { get, post } from "@/common/http/request";
|
import { get, post } from "@/common/http/request";
|
||||||
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
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导入映射配置
|
// Excel导入映射配置
|
||||||
const mappingConfig: FieldMappingConfig = {
|
const mappingConfig: FieldMappingConfig = {
|
||||||
// productType <- "型号" (默认空字符串)
|
|
||||||
productType: {
|
productType: {
|
||||||
sourceKey: "型号",
|
sourceKey: ["型号", "productType"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.productType"),
|
||||||
|
width: 15,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// productSn <- "SN号" (默认空字符串)
|
|
||||||
productSn: {
|
productSn: {
|
||||||
sourceKey: "SN号",
|
sourceKey: ["SN号", "productSn"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.productSn"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// mac <- "MAC地址" (默认空字符串)
|
|
||||||
mac: {
|
mac: {
|
||||||
sourceKey: "MAC地址",
|
sourceKey: ["MAC地址", "mac"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.mac"),
|
||||||
|
width: 18,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// serialNum <- "序列号" (默认空字符串)
|
|
||||||
serialNum: {
|
serialNum: {
|
||||||
sourceKey: "序列号",
|
sourceKey: ["序列号", "serialNum"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.serialNum"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// softVersion <- "软件版本" (默认空字符串)
|
|
||||||
softVersion: {
|
softVersion: {
|
||||||
sourceKey: "软件版本",
|
sourceKey: ["软件版本", "softVersion"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.softVersion"),
|
||||||
|
width: 15,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// alVersion <- "算法版本" (默认空字符串)
|
|
||||||
alVersion: {
|
alVersion: {
|
||||||
sourceKey: "算法版本",
|
sourceKey: ["算法版本", "alVersion"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.alVersion"),
|
||||||
|
width: 15,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// alNum <- "算法标志" (默认空字符串)
|
|
||||||
alNum: {
|
alNum: {
|
||||||
sourceKey: "算法标志",
|
sourceKey: ["算法标志", "alNum"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.alNum"),
|
||||||
|
width: 15,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// alTxt <- "激活状态" (默认"未激活")
|
|
||||||
alTxt: {
|
alTxt: {
|
||||||
sourceKey: "激活状态",
|
sourceKey: ["激活状态", "alTxt"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.alTxt"),
|
||||||
|
width: 12,
|
||||||
defaultValue: "未激活",
|
defaultValue: "未激活",
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
if (val === "已激活" || val === "Activated" || val === true || val === "1") return "已激活";
|
if (val === "已激活" || val === "Activated" || val === true || val === "1") return "已激活";
|
||||||
@@ -189,19 +190,25 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
return "未激活";
|
return "未激活";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// createDate <- "生产日期" (默认空字符串)
|
|
||||||
createDate: {
|
createDate: {
|
||||||
sourceKey: "生产日期",
|
sourceKey: ["生产日期", "createDate"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.createDate"),
|
||||||
|
width: 15,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// mark <- "备注" (默认空字符串)
|
|
||||||
mark: {
|
mark: {
|
||||||
sourceKey: "备注",
|
sourceKey: ["备注", "mark"],
|
||||||
|
header: $t("_prop.production.finishedproductreceipt.mark"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const detailConfig: DetailLoadConfig = {
|
||||||
|
url: getDetailUrl,
|
||||||
|
paramName: "id",
|
||||||
|
dataPath: "data",
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* 可以自定义的变量
|
* 可以自定义的变量
|
||||||
*/
|
*/
|
||||||
@@ -425,8 +432,9 @@ const handleReset = () => {
|
|||||||
:base-title="$t('_title.production.finishedproductreceipt.baseTitle')"
|
:base-title="$t('_title.production.finishedproductreceipt.baseTitle')"
|
||||||
:table-title="$t('_title.production.finishedproductreceipt.tableTitle')"
|
:table-title="$t('_title.production.finishedproductreceipt.tableTitle')"
|
||||||
:item-array-name="itemArrayName"
|
:item-array-name="itemArrayName"
|
||||||
upload-desc="设备信息"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.production.finishedproductreceipt.templateFileName')"
|
||||||
|
:detail-config="detailConfig"
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
>
|
>
|
||||||
<template #form-items>
|
<template #form-items>
|
||||||
|
|||||||
@@ -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 { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
||||||
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
||||||
import ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
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";
|
import { watch } from "vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,11 +65,21 @@ const outStockTypeOptions = [
|
|||||||
|
|
||||||
const mappingConfig: FieldMappingConfig = {
|
const mappingConfig: FieldMappingConfig = {
|
||||||
partNumber: {
|
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: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
productCount: {
|
productCount: {
|
||||||
sourceKey: "数量",
|
sourceKey: ["数量", "productCount"],
|
||||||
|
header: $t("_prop.production.finishedproductshipment.productCount"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
@@ -77,11 +87,19 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
productMark: {
|
productMark: {
|
||||||
sourceKey: "备注",
|
sourceKey: ["备注", "productMark"],
|
||||||
|
header: $t("_prop.production.finishedproductshipment.productMark"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const detailConfig: DetailLoadConfig = {
|
||||||
|
url: getDetailUrl,
|
||||||
|
paramName: "id",
|
||||||
|
dataPath: "data",
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基本不变通用变量
|
* 基本不变通用变量
|
||||||
*/
|
*/
|
||||||
@@ -288,8 +306,9 @@ const handleReset = () => {
|
|||||||
:base-title="$t('_title.production.finishedproductshipment.baseTitle')"
|
:base-title="$t('_title.production.finishedproductshipment.baseTitle')"
|
||||||
:table-title="$t('_title.production.finishedproductshipment.tableTitle')"
|
:table-title="$t('_title.production.finishedproductshipment.tableTitle')"
|
||||||
:item-array-name="itemArrayName"
|
:item-array-name="itemArrayName"
|
||||||
upload-desc="物料信息"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.production.finishedproductshipment.templateFileName')"
|
||||||
|
:detail-config="detailConfig"
|
||||||
@reset="handleReset"
|
@reset="handleReset"
|
||||||
>
|
>
|
||||||
<template #form-items>
|
<template #form-items>
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const inboundForm = reactive({
|
|||||||
orderCode: "",
|
orderCode: "",
|
||||||
vendorName: "",
|
vendorName: "",
|
||||||
formCode: "",
|
formCode: "",
|
||||||
storeNo: null as number | null,
|
storeNo: null as number,
|
||||||
storeName: "",
|
storeName: "",
|
||||||
formMark: "",
|
formMark: "",
|
||||||
items: [] as any[],
|
items: [] as any[],
|
||||||
@@ -426,8 +426,9 @@ const getFormStatusTagType = (code: number | null): string => {
|
|||||||
:base-title="$t('_title.purchase.purchase_order.baseTitle')"
|
:base-title="$t('_title.purchase.purchase_order.baseTitle')"
|
||||||
:table-title="$t('_title.purchase.purchase_order.tableTitle')"
|
:table-title="$t('_title.purchase.purchase_order.tableTitle')"
|
||||||
item-array-name="items"
|
item-array-name="items"
|
||||||
upload-desc="采购明细"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.purchase.purchase_order.templateFileName')"
|
||||||
|
:template-columns="{ exclude: ['purchaseMark'] }"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
@@ -429,8 +429,8 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
:base-title="$t('_title.purchase.purchase_plan.baseTitle')"
|
:base-title="$t('_title.purchase.purchase_plan.baseTitle')"
|
||||||
:table-title="$t('_title.purchase.purchase_plan.tableTitle')"
|
:table-title="$t('_title.purchase.purchase_plan.tableTitle')"
|
||||||
item-array-name="planItems"
|
item-array-name="planItems"
|
||||||
upload-desc="采购明细"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.purchase.purchase_plan.templateFileName')"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import { formatDate } from "@/common/utils/format-utils";
|
|||||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
|
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
|
||||||
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
import BaseFormWithTable from "@/components/base/base-form-with-table/BaseFormWithTable.vue";
|
||||||
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.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 ExpandablePageableTable from "@/components/base/expandable-pageable-table/ExpandablePageableTable.vue";
|
||||||
import { get, post } from "@/common/http/request";
|
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";
|
import { useStatus } from "@/common/languages/mapping/base-info-mapping";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +27,7 @@ const rejectUrl = "/sale/saleorder/unapproveSaleOrder";
|
|||||||
const itemUrl = "/sale/saleorder/getSaleOrderItemList";
|
const itemUrl = "/sale/saleorder/getSaleOrderItemList";
|
||||||
const keyAccountSelectUrl = "/sys/keyaccount/getKeyAccountSelectList";
|
const keyAccountSelectUrl = "/sys/keyaccount/getKeyAccountSelectList";
|
||||||
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
|
const partNumberExistsUrl = "/warehouse/warehouseitem/existsWarehouseItem";
|
||||||
|
const warehouseSelectUrl = "/warehouse/warehouse/getWarehouseSelectList";
|
||||||
|
|
||||||
const searchers = [{ name: "searchCode", type: "text" as const, placeholder: $t("_prop.sale.saleorder.searchCode") }];
|
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" }],
|
formName: [{ required: true, message: $t("_message.sale.saleorder.input_formName"), trigger: "blur" }],
|
||||||
customerId: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
|
customerId: [{ required: true, message: $t("_message.sale.saleorder.select_customerId"), trigger: "change" }],
|
||||||
customerName: [{ 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: [
|
partNumber: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -77,10 +80,11 @@ const getDetailUrl = "/sale/saleorder/getSaleOrderItemList";
|
|||||||
* 基本不变通用变量
|
* 基本不变通用变量
|
||||||
*/
|
*/
|
||||||
const tableRef = ref<InstanceType<typeof ExpandablePageableTable> | null>(null);
|
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 { title, visible, formType, form, itemVisible, itemParentId } = useGeneralPageRef();
|
||||||
const { getFormStatusLabel } = useStatus();
|
const { getFormStatusLabel } = useStatus();
|
||||||
const baseFormWithTableRef = ref<InstanceType<typeof BaseFormWithTable>>();
|
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 = () => {
|
const add = () => {
|
||||||
form.value = {
|
form.value = {
|
||||||
formCode: generateFormCode(),
|
formCode: generateFormCode(),
|
||||||
@@ -134,21 +146,19 @@ const add = () => {
|
|||||||
|
|
||||||
const edit = (row: any) => {
|
const edit = (row: any) => {
|
||||||
title.value = "_title.sale.saleorder.edit";
|
title.value = "_title.sale.saleorder.edit";
|
||||||
form.value = {
|
form.value = { ...row };
|
||||||
...row,
|
|
||||||
saleOrderItems: [],
|
|
||||||
};
|
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
formType.value = true;
|
formType.value = true;
|
||||||
|
|
||||||
// 加载明细数据
|
// 延迟设置仓库名称,等待 BaseSelect 加载完成
|
||||||
get(getDetailUrl, { saleOrderId: row.id })
|
if (row.storeNo) {
|
||||||
.then(res => {
|
setTimeout(() => {
|
||||||
form.value.saleOrderItems = res.data || [];
|
const label = warehouseSelectRef.value?.getLabel();
|
||||||
})
|
if (label && !form.value.storeName) {
|
||||||
.catch(err => {
|
form.value.storeName = label;
|
||||||
console.error("Failed to load sale order items:", err);
|
}
|
||||||
});
|
}, 300);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = (row: any) => {
|
const remove = (row: any) => {
|
||||||
@@ -156,35 +166,11 @@ const remove = (row: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const approve = (row: any) => {
|
const approve = (row: any) => {
|
||||||
ElMessageBox.confirm($t("_message.sale.saleorder.approve_confirm"), $t("_level.warning"), {
|
useApprove(approveUrl, row.id, "_message.sale.saleorder.approve_confirm");
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const reject = (row: any) => {
|
const reject = (row: any) => {
|
||||||
ElMessageBox.confirm($t("_message.sale.saleorder.reject_confirm"), $t("_level.warning"), {
|
useReject(rejectUrl, row.id, "_message.sale.saleorder.reject_confirm");
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showItem = (row: any) => {
|
const showItem = (row: any) => {
|
||||||
@@ -236,26 +222,32 @@ const operateButtonClick = (eventName: string, row: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
||||||
// 已审核(status=1)时不显示审核按钮,显示反审按钮
|
// 已审核(formStatus=1)时不显示审核按钮,显示反审按钮
|
||||||
// 未审核(status=0)时显示审核按钮,不显示反审按钮
|
// 未审核(formStatus=0)时显示审核按钮,不显示反审按钮
|
||||||
if (row.status === 0 && button.eventName === "reject") return false;
|
if (row.formStatus === 0 && button.eventName === "reject") return false;
|
||||||
if (row.status === 1 && button.eventName === "approve") 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;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mappingConfig: FieldMappingConfig = {
|
const mappingConfig: FieldMappingConfig = {
|
||||||
partNumber: {
|
partNumber: {
|
||||||
sourceKey: "物料编号",
|
sourceKey: ["物料编号", "partNumber"],
|
||||||
|
header: $t("_prop.sale.saleorder.partNumber"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
productSpecs: {
|
productSpecs: {
|
||||||
sourceKey: "物料型号",
|
sourceKey: ["物料型号", "productSpecs"],
|
||||||
|
header: $t("_prop.sale.saleorder.productSpecs"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
saleCount: {
|
saleCount: {
|
||||||
sourceKey: "数量",
|
sourceKey: ["数量", "saleCount"],
|
||||||
|
header: $t("_prop.sale.saleorder.saleCount"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
@@ -263,7 +255,9 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
price: {
|
price: {
|
||||||
sourceKey: "单价",
|
sourceKey: ["单价", "price"],
|
||||||
|
header: $t("_prop.sale.saleorder.price"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
@@ -271,11 +265,19 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
saleMark: {
|
saleMark: {
|
||||||
sourceKey: "备注",
|
sourceKey: ["备注", "saleMark"],
|
||||||
|
header: $t("_prop.sale.saleorder.saleMark"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const detailConfig: DetailLoadConfig = {
|
||||||
|
url: getDetailUrl,
|
||||||
|
paramName: "saleOrderId",
|
||||||
|
dataPath: "data",
|
||||||
|
};
|
||||||
|
|
||||||
// 计算总价
|
// 计算总价
|
||||||
const calculateTotalPrice = (row: any) => {
|
const calculateTotalPrice = (row: any) => {
|
||||||
if (row.saleCount && row.price) {
|
if (row.saleCount && row.price) {
|
||||||
@@ -315,6 +317,7 @@ const getFormStatusTagType = (code: number | null): string => {
|
|||||||
<template #columns>
|
<template #columns>
|
||||||
<el-table-column :label="$t('_prop.sale.saleorder.formCode')" prop="formCode" />
|
<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.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.totalValue')" prop="totalValue" />
|
||||||
<el-table-column :label="$t('_prop.sale.saleorder.formName')" prop="formName" />
|
<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 />
|
<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')"
|
:base-title="$t('_title.sale.saleorder.baseTitle')"
|
||||||
:table-title="$t('_title.sale.saleorder.tableTitle')"
|
:table-title="$t('_title.sale.saleorder.tableTitle')"
|
||||||
item-array-name="saleOrderItems"
|
item-array-name="saleOrderItems"
|
||||||
:upload-desc="$t('_title.sale.saleorder.tableTitle')"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.sale.saleorder.templateFileName')"
|
||||||
|
:detail-config="detailConfig"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
@@ -375,14 +379,29 @@ const getFormStatusTagType = (code: number | null): string => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-form-item :label="$t('_prop.sale.saleorder.formMark')" prop="formMark">
|
<el-row :gutter="20">
|
||||||
<el-input
|
<el-col :span="8">
|
||||||
v-model="form.formMark"
|
<el-form-item :label="$t('_prop.sale.saleorder.storeNo')" prop="storeNo">
|
||||||
:placeholder="$t('_message.sale.saleorder.input_formMark')"
|
<BaseSelect
|
||||||
type="textarea"
|
ref="warehouseSelectRef"
|
||||||
:rows="2"
|
v-model="form.storeNo"
|
||||||
/>
|
:url="warehouseSelectUrl"
|
||||||
</el-form-item>
|
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>
|
||||||
<template #form-table-columns>
|
<template #form-table-columns>
|
||||||
<el-table-column :label="$t('_prop.sale.saleorder.partNumber')" width="150">
|
<el-table-column :label="$t('_prop.sale.saleorder.partNumber')" width="150">
|
||||||
@@ -393,6 +412,14 @@ const getFormStatusTagType = (code: number | null): string => {
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</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">
|
<el-table-column :label="$t('_prop.sale.saleorder.saleCount')" width="120">
|
||||||
<template #default="{ row, $index }">
|
<template #default="{ row, $index }">
|
||||||
<el-form-item :prop="`${itemArrayName}.${$index}.saleCount`">
|
<el-form-item :prop="`${itemArrayName}.${$index}.saleCount`">
|
||||||
|
|||||||
@@ -240,8 +240,8 @@ const getFormTypeText = (reserve1: number) => {
|
|||||||
:base-title="$t('_title.warehouse.inventorycount.baseTitle')"
|
:base-title="$t('_title.warehouse.inventorycount.baseTitle')"
|
||||||
:table-title="$t('_title.warehouse.inventorycount.tableTitle')"
|
:table-title="$t('_title.warehouse.inventorycount.tableTitle')"
|
||||||
item-array-name="countItems"
|
item-array-name="countItems"
|
||||||
upload-desc="盘点明细"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.warehouse.inventorycount.templateFileName')"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
@@ -351,8 +351,8 @@ const authShowFunc = (row: any, button: globalThis.ButtonProp) => {
|
|||||||
:base-title="$t('_title.warehouse.stocktransferorder.baseTitle')"
|
:base-title="$t('_title.warehouse.stocktransferorder.baseTitle')"
|
||||||
:table-title="$t('_title.warehouse.stocktransferorder.tableTitle')"
|
:table-title="$t('_title.warehouse.stocktransferorder.tableTitle')"
|
||||||
item-array-name="transferOrderItems"
|
item-array-name="transferOrderItems"
|
||||||
upload-desc="物料信息"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.warehouse.stocktransferorder.templateFileName')"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { ElMessage } from "element-plus";
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
import { generateDucumentNo } from "@/common/utils/document-no-generator/document-no-generator";
|
||||||
import { DocumentType } from "@/common/enums/DocumentType";
|
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";
|
import BaseItemDialog from "@/components/base/base-item-dialog/BaseItemDialog.vue";
|
||||||
|
|
||||||
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
|
const getPageUrl = "/warehouse/warehousereceipt/getWarehouseReceiptPage";
|
||||||
@@ -62,15 +62,21 @@ const rules = reactive<FormRules>({
|
|||||||
|
|
||||||
const mappingConfig: FieldMappingConfig = {
|
const mappingConfig: FieldMappingConfig = {
|
||||||
partNumber: {
|
partNumber: {
|
||||||
sourceKey: ["商品编号", "物料编号", "partNumber"],
|
sourceKey: ["商品编号", "物料编号", "partNumber", "物料编码"],
|
||||||
|
header: $t("_prop.warehouse.warehousereceipt.partNumber"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
productSpec: {
|
productSpec: {
|
||||||
sourceKey: ["型号", "物料型号", "productSpecs", "productSpec"],
|
sourceKey: ["物料规格", "型号", "物料型号", "规格", "规格型号", "productSpecs", "productSpec"],
|
||||||
|
header: $t("_prop.warehouse.warehousereceipt.productSpec"),
|
||||||
|
width: 20,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
productCount: {
|
productCount: {
|
||||||
sourceKey: ["数量", "入库数量", "productCount"],
|
sourceKey: ["数量", "入库数量", "productCount", "入库数"],
|
||||||
|
header: $t("_prop.warehouse.warehousereceipt.productCount"),
|
||||||
|
width: 15,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
transform: (val: any) => {
|
transform: (val: any) => {
|
||||||
const num = Number(val);
|
const num = Number(val);
|
||||||
@@ -79,6 +85,12 @@ const mappingConfig: FieldMappingConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const detailConfig: DetailLoadConfig = {
|
||||||
|
url: getItemUrl,
|
||||||
|
paramName: "id",
|
||||||
|
dataPath: "data",
|
||||||
|
};
|
||||||
|
|
||||||
const add = () => {
|
const add = () => {
|
||||||
form.value = {
|
form.value = {
|
||||||
formCode: generateDucumentNo(DocumentType.WarehouseReceipt),
|
formCode: generateDucumentNo(DocumentType.WarehouseReceipt),
|
||||||
@@ -96,16 +108,6 @@ const add = () => {
|
|||||||
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;
|
||||||
};
|
};
|
||||||
@@ -240,8 +242,9 @@ const submit = (form: any, formRef: FormInstance | undefined) => {
|
|||||||
:base-title="$t('_title.warehouse.warehousereceipt.baseTitle')"
|
:base-title="$t('_title.warehouse.warehousereceipt.baseTitle')"
|
||||||
:table-title="$t('_title.warehouse.warehousereceipt.tableTitle')"
|
:table-title="$t('_title.warehouse.warehousereceipt.tableTitle')"
|
||||||
item-array-name="receiptItems"
|
item-array-name="receiptItems"
|
||||||
upload-desc="物料信息"
|
|
||||||
:mapping-config="mappingConfig"
|
:mapping-config="mappingConfig"
|
||||||
|
:template-file-name="$t('_title.warehouse.warehousereceipt.templateFileName')"
|
||||||
|
:detail-config="detailConfig"
|
||||||
>
|
>
|
||||||
<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>
|
||||||
|
|||||||
Reference in New Issue
Block a user