From aaa700a2efc44c2f633f2c83885bc67ddcbcd770 Mon Sep 17 00:00:00 2001
From: 吴羡 <16976746+Xian-TT3@user.noreply.gitee.com>
Date: 星期三, 23 九月 2026 09:10:36 +0800
Subject: [PATCH] feat: 台账品名/材质/规格手工录入与产品编号选填、审批模板启用锁定编辑
---
src/views/officeProcessAutomation/ApproveManage/approve-template/components/FormConfigEditor.vue | 49 +++++----
src/views/procurementManagement/procurementLedger/index.vue | 188 ++++++-------------------------------
src/views/basicData/product/index.vue | 11 -
src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js | 11 ++
src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue | 15 ++-
5 files changed, 80 insertions(+), 194 deletions(-)
diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue
index b05b215..8d32398 100644
--- a/src/views/basicData/product/index.vue
+++ b/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("閫変腑鐨勫唴瀹瑰皢琚垹闄わ紝鏄惁纭鍒犻櫎锛�", "鍒犻櫎鎻愮ず", {
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-template/components/FormConfigEditor.vue b/src/views/officeProcessAutomation/ApproveManage/approve-template/components/FormConfigEditor.vue
index 6880f3f..afc6488 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-template/components/FormConfigEditor.vue
+++ b/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);
}
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue b/src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue
index 0a495c6..8e67f9f 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-template/index.vue
+++ b/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,
diff --git a/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js b/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
index 79e96bc..4f223c5 100644
--- a/src/views/officeProcessAutomation/ApproveManage/approve-template/useApproveTemplate.js
+++ b/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,
diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue
index 8d9caa6..fa55d87 100644
--- a/src/views/procurementManagement/procurementLedger/index.vue
+++ b/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; // 鎵惧埌鑺傜偣锛岃繑鍥炶鑺傜偣鐨刲abel
- }
- if (nodes[i].children && nodes[i].children.length > 0) {
- const foundNode = findNodeById(nodes[i].children, productId);
- if (foundNode) {
- return foundNode; // 鍦ㄥ瓙鑺傜偣涓壘鍒帮紝鐩存帴杩斿洖锛堝凡缁忔槸label瀛楃涓诧級
- }
- }
- }
- return null; // 娌℃湁鎵惧埌鑺傜偣锛岃繑鍥瀗ull
- };
-
- 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 = () => {
--
Gitblit v1.9.3