src/views/basicData/product/index.vue
@@ -9,8 +9,7 @@ @clear="searchFilter" clearable prefix-icon="Search" /> <el-button v-if="false" type="primary" <el-button type="primary" @click="openProDia('addOne')" style="margin-left: 10px">新增产品大类</el-button> </div> @@ -55,7 +54,6 @@ style="margin-left: 4px" type="danger" link :disabled="isTopLevelNode(data, node)" @click="remove(node, data)"> 删除 </el-button> @@ -134,7 +132,7 @@ <el-row> <el-row> <el-col :span="24"> <el-form-item label="产品编号:" <el-form-item label="产品编号(选填):" prop="productCode"> <el-input v-model="modelForm.productCode" placeholder="请输入产品编号" @@ -346,7 +344,6 @@ modelRules: { model: [{ required: true, message: "请输入", trigger: "blur" }], unit: [{ required: true, message: "请输入", trigger: "blur" }], productCode: [{ required: true, message: "请输入", trigger: "blur" }], }, }); const { form, rules, modelForm, modelRules } = toRefs(data); @@ -458,10 +455,6 @@ // 删除产品 const remove = (node, data) => { if (isTopLevelNode(data, node)) { proxy.$modal.msgWarning("一级节点不能编辑或删除"); return; } let ids = []; ids.push(data.id); ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", { src/views/officeProcessAutomation/ApproveManage/approve-template/components/FormConfigEditor.vue
@@ -8,6 +8,7 @@ placeholder="如:请填写报销事由、金额等" maxlength="200" show-word-limit :disabled="readonly" @input="emitOut" /> </div> @@ -23,11 +24,11 @@ <div class="fce-toolbar-actions"> <el-dropdown trigger="click" :disabled="disableImport" :disabled="disableImport || readonly" @visible-change="onImportDropdownVisible" @command="importFromTemplate" > <el-button size="small" :loading="templateImportLoading" :disabled="disableImport"> <el-button size="small" :loading="templateImportLoading" :disabled="disableImport || readonly"> 从已有模板导入 </el-button> <template #dropdown> @@ -46,7 +47,7 @@ </el-dropdown-menu> </template> </el-dropdown> <el-button type="primary" size="small" :icon="Plus" @click="addField">添加填报项</el-button> <el-button v-if="!readonly" type="primary" size="small" :icon="Plus" @click="addField">添加填报项</el-button> </div> </div> @@ -76,7 +77,7 @@ <el-tag v-if="field.required" size="small" type="danger" effect="plain">必填</el-tag> <el-tag v-if="isFieldLocked(field)" size="small" type="info" effect="plain">内置项</el-tag> </div> <div v-if="!isFieldLocked(field)" class="fce-card-btns"> <div v-if="!isFieldDisabled(field)" class="fce-card-btns"> <el-tooltip content="上移" placement="top"> <el-button circle size="small" :disabled="index === 0" @click="moveField(index, -1)"> <el-icon><Top /></el-icon> @@ -109,7 +110,7 @@ v-model="field.label" placeholder="如:报销说明" maxlength="50" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @input="emitOut" /> </el-form-item> @@ -120,7 +121,7 @@ v-model="field.key" placeholder="如:summary" maxlength="50" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @input="emitOut" /> </el-form-item> @@ -130,7 +131,7 @@ <el-select v-model="field.type" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="onTypeChange(field)" > <el-option @@ -155,7 +156,7 @@ inline-prompt active-text="必填" inactive-text="选填" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" /> </el-form-item> @@ -168,7 +169,7 @@ :max="10" controls-position="right" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" /> </el-form-item> @@ -180,7 +181,7 @@ v-model="field.min" controls-position="right" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" /> </el-form-item> @@ -193,7 +194,7 @@ :max="4" controls-position="right" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" /> </el-form-item> @@ -211,7 +212,7 @@ :type="field.type === 'textarea' ? 'textarea' : 'text'" :rows="field.type === 'textarea' ? 2 : undefined" :placeholder="defaultPlaceholder(field)" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" clearable @input="emitOut" /> @@ -223,7 +224,7 @@ controls-position="right" placeholder="选填" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" /> <el-date-picker @@ -234,7 +235,7 @@ format="YYYY-MM-DD" value-format="YYYY-MM-DD" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" clearable @change="emitOut" /> @@ -248,7 +249,7 @@ format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" clearable @change="emitOut" /> @@ -260,7 +261,7 @@ clearable filterable :loading="optionSourceLoading" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="emitOut" > <el-option @@ -280,7 +281,7 @@ <el-select v-model="field.optionSource" style="width: 100%" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @change="onOptionSourceChange(field)" > <el-option @@ -304,7 +305,7 @@ link size="small" :icon="Plus" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @click="addOption(field)" > 添加选项 @@ -319,21 +320,21 @@ <el-input v-model="opt.label" placeholder="显示文本" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @input="emitOut" /> <el-input v-model="opt.value" placeholder="选项值" class="fce-option-value" :disabled="isFieldLocked(field)" :disabled="isFieldDisabled(field)" @input="emitOut" /> <el-button type="danger" link :icon="Delete" :disabled="isFieldLocked(field) || field.options.length <= 1" :disabled="isFieldDisabled(field) || field.options.length <= 1" @click="removeOption(field, oi)" /> </div> @@ -382,6 +383,8 @@ disableImport: { type: Boolean, default: false }, /** 系统内置模板编辑时,打开弹窗即存在的填报项 _uid,不可改删 */ lockedFieldUids: { type: Array, default: () => [] }, /** 只读:整体不可编辑 */ readonly: { type: Boolean, default: false }, }); const emit = defineEmits(["update:modelValue"]); @@ -401,6 +404,10 @@ return field?._uid != null && lockedUidSet.value.has(field._uid); } function isFieldDisabled(field) { return props.readonly || isFieldLocked(field); } function typeLabel(type) { return formFieldTypeLabel(type); } src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue
@@ -119,7 +119,7 @@ placeholder="如:项目立项审批" maxlength="50" show-word-limit :disabled="isEditingBuiltin" :disabled="isEditFormLocked" /> </el-form-item> @@ -134,7 +134,7 @@ v-model="form.businessType" placeholder="请选择" style="width: 100%" :disabled="isEditingBuiltin" :disabled="isEditFormLocked" > <el-option @@ -183,6 +183,8 @@ show-word-limit :disabled="isEditFormLocked" /> </el-form-item> @@ -192,7 +194,8 @@ <FormConfigEditor v-model="form.formConfigData" :exclude-template-id="form.id" :disable-import="isEditingBuiltin" :disable-import="isEditFormLocked" :readonly="isEditFormLocked" :locked-field-uids="isEditingBuiltin ? form.lockedFormFieldUids : []" /> @@ -202,7 +205,7 @@ <el-form-item label="审批流程" required> <TemplateFlowEditor v-model="form.flowNodes" :user-options="flowUserOptions" /> <TemplateFlowEditor v-model="form.flowNodes" :user-options="flowUserOptions" :readonly="isEditFormLocked" /> <p class="flow-tip"> @@ -216,7 +219,7 @@ <div class="upload-block"> <FileUpload v-model:file-list="form.storageBlobDTOs" :limit="10" button-text="点击选择文件" /> <FileUpload v-model:file-list="form.storageBlobDTOs" :limit="10" button-text="点击选择文件" :disabled="isEditFormLocked" /> </div> @@ -472,6 +475,8 @@ isEditingBuiltin, isEditFormLocked, detailDialog, detailRow, src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
@@ -56,13 +56,20 @@ const page = reactive({ current: 1, size: 10, total: 0 }); const tableData = ref([]); const formDialog = reactive({ visible: false, title: "", mode: "add" }); const formDialog = reactive({ visible: false, title: "", mode: "add", originEnabled: false }); const form = reactive(createEmptyTemplateForm()); const formRef = ref(); const isEditingBuiltin = computed( () => formDialog.mode === "edit" && Number(form.templateType) === TEMPLATE_TYPE_BUILTIN ); // 编辑启用中的模板时只能改启用状态,其他项只读(需先停用再编辑) const isEditingEnabled = computed( () => formDialog.mode === "edit" && formDialog.originEnabled === true ); const isEditFormLocked = computed(() => isEditingBuiltin.value || isEditingEnabled.value); async function loadTemplateTypeOptions() { try { @@ -229,6 +236,7 @@ } else { resetForm(mode === "edit" ? row : null); } formDialog.originEnabled = mode === "edit" && form.enabled !== false; formDialog.visible = true; } @@ -332,6 +340,7 @@ formRef, formRules, isEditingBuiltin, isEditFormLocked, detailDialog, detailRow, detailLoading, src/views/procurementManagement/procurementLedger/index.vue
@@ -105,6 +105,8 @@ width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="材质" prop="material" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" @@ -412,6 +414,8 @@ width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="材质" prop="material" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" @@ -540,34 +544,31 @@ ref="productFormRef"> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="产品大类:" prop="productId"> <el-tree-select v-model="productForm.productId" placeholder="请选择" clearable filterable check-strictly @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> <el-form-item label="品名:" prop="productCategory"> <el-input v-model="productForm.productCategory" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="材质:" prop="material"> <el-input v-model="productForm.material" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="规格型号:" prop="productModelId"> <el-select v-model="productForm.productModelId" placeholder="请选择" filterable clearable @change="getProductModel"> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> </el-select> prop="specificationModel"> <el-input v-model="productForm.specificationModel" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> @@ -744,9 +745,7 @@ const productData = ref([]); const selectedRows = ref([]); const productSelectedRows = ref([]); const modelOptions = ref([]); const userList = ref([]); const productOptions = ref([]); const salesContractList = ref([]); const supplierList = ref([]); const tableLoading = ref(false); @@ -759,7 +758,6 @@ const total = ref(0); const fileList = ref([]); import useUserStore from "@/store/modules/user"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import dayjs from "dayjs"; import FileUpload from "@/components/AttachmentUpload/file/index.vue"; @@ -954,9 +952,8 @@ const currentId = ref(""); const productFormData = reactive({ productForm: { productId: "", productCategory: "", productModelId: "", material: "", specificationModel: "", unit: "", quantity: "", @@ -969,8 +966,11 @@ isChecked: false, }, productRules: { productId: [{ required: true, message: "请选择", trigger: "change" }], productModelId: [{ required: true, message: "请选择", trigger: "change" }], productCategory: [{ required: true, message: "请输入", trigger: "blur" }], material: [{ required: true, message: "请输入", trigger: "blur" }], specificationModel: [ { required: true, message: "请输入", trigger: "blur" }, ], unit: [{ required: true, message: "请输入", trigger: "blur" }], quantity: [{ required: true, message: "请输入", trigger: "blur" }], taxInclusiveUnitPrice: [ @@ -1457,7 +1457,7 @@ dialogFormVisible.value = false; }; // 打开产品弹框 const openProductForm = async (type, row, index) => { const openProductForm = (type, row, index) => { // 编辑时检查产品入库审核状态,完全入库时不能编辑 if (type === "edit" && row && row.stockInApprovalStatus === "完全入库") { proxy.$modal.msgWarning("完全入库状态的产品不能编辑"); @@ -1470,12 +1470,6 @@ proxy.resetForm("productFormRef"); productFormVisible.value = true; // 先获取产品选项,确保数据加载完成 await getProductOptions(); // 等待 DOM 更新 await nextTick(); if (type === "add") { productForm.value.isChecked = false; } @@ -1483,130 +1477,8 @@ if (type === "edit") { // 复制行数据 productForm.value = { ...row }; // 如果是从模板加载的数据,可能没有 productId 和 productModelId // 需要根据 productCategory 和 specificationModel 来查找对应的 ID if (!productForm.value.productId && productForm.value.productCategory) { // 根据 productCategory 查找 productId const findProductIdByCategory = (nodes, categoryName) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].label === categoryName) { return nodes[i].value; } if (nodes[i].children && nodes[i].children.length > 0) { const found = findProductIdByCategory( nodes[i].children, categoryName ); if (found) return found; } } return null; }; const productId = findProductIdByCategory( productOptions.value, productForm.value.productCategory ); if (productId) { productForm.value.productId = productId; // 获取型号列表并等待完成 const modelRes = await modelList({ id: productId }); modelOptions.value = modelRes; // 等待 DOM 更新 await nextTick(); // 根据 specificationModel 查找 productModelId if ( productForm.value.specificationModel && modelOptions.value.length > 0 ) { const modelItem = modelOptions.value.find( item => item.model === productForm.value.specificationModel ); if (modelItem) { productForm.value.productModelId = modelItem.id; // 设置规格型号和单位 getProductModel(modelItem.id); } } } } else if (productForm.value.productId) { // 如果有 productId,正常加载型号列表 await getModels(productForm.value.productId); // 等待 DOM 更新 await nextTick(); if (productForm.value.productModelId) { getProductModel(productForm.value.productModelId); } } // 最后再等待一次 DOM 更新,确保所有数据都已设置 await nextTick(); } }; const getProductOptions = () => { return productTreeList().then(res => { productOptions.value = convertIdToValue(res); return res; }); }; const getModels = value => { if (value) { productForm.value.productCategory = findNodeById(productOptions.value, value) || ""; return modelList({ id: value }).then(res => { modelOptions.value = res; return res; }); } else { productForm.value.productCategory = ""; modelOptions.value = []; return Promise.resolve([]); } }; const getProductModel = value => { const index = modelOptions.value.findIndex(item => item.id === value); if (index !== -1) { productForm.value.specificationModel = modelOptions.value[index].model; productForm.value.unit = modelOptions.value[index].unit; } else { productForm.value.specificationModel = null; productForm.value.unit = null; } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].value === productId) { return nodes[i].label; // 找到节点,返回该节点的label } if (nodes[i].children && nodes[i].children.length > 0) { const foundNode = findNodeById(nodes[i].children, productId); if (foundNode) { return foundNode; // 在子节点中找到,直接返回(已经是label字符串) } } } return null; // 没有找到节点,返回null }; function convertIdToValue(data) { return data.map(item => { const { id, children, ...rest } = item; const newItem = { ...rest, value: id, // 将 id 改为 value }; if (children && children.length > 0) { newItem.children = convertIdToValue(children); } return newItem; }); } // 提交产品表单 const submitProduct = () => {