修复逻辑

This commit is contained in:
2026-02-01 23:08:45 +08:00
parent afdbd575e5
commit 4a3b969a2e
2 changed files with 299 additions and 67 deletions

View File

@@ -10,12 +10,12 @@
</span>
</div>
</template>
<div v-loading="loading">
<div v-loading="loading" style="padding-bottom: 20px;">
<!-- 步骤条 -->
<el-steps :active="currentStep" finish-status="success" style="margin-bottom: 30px;">
<!-- <el-steps :active="currentStep" finish-status="success" style="margin-bottom: 30px;">
<el-step title="基本信息" />
<el-step :title="stepTwoTitle" />
</el-steps>
</el-steps> -->
<el-form
ref="formRef"
@@ -108,15 +108,16 @@
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-form-item label="品目编码" prop="categoryCode">
<el-tree-select
v-model="dataForm.categoryCode"
:data="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children' }"
<el-cascader
v-model="categoryCodePath"
:options="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children', checkStrictly: true }"
placeholder="请选择品目编码(需要显示所有的层级)"
clearable
check-strictly
:render-after-expand="false"
style="width: 100%" />
filterable
:show-all-levels="true"
style="width: 100%"
@change="handleCategoryChange" />
</el-form-item>
</el-col>
</el-row>
@@ -125,7 +126,7 @@
<!-- 第二步采购详情 -->
<div v-show="currentStep === 1">
<!-- 分支一部门自行采购 -->
<div v-if="isDeptPurchase">
<div class="mb20" v-if="isDeptPurchase">
<div class="step-title mb20">部门自行采购</div>
<el-form-item label="采购内容" prop="projectContent" class="mb20">
<el-input
@@ -146,7 +147,7 @@
style="width: 100%">
<el-option
v-for="item in purchaseTypeDeptList"
:key="item.value"
:key="item.id"
:label="item.label"
:value="item.value" />
</el-select>
@@ -154,7 +155,7 @@
<!-- 商务洽谈 -->
<el-form-item
v-if="dataForm.purchaseType === 'business_negotiation'"
v-if="dataForm.purchaseType === PURCHASE_TYPE_IDS.BUSINESS_NEGOTIATION"
label="商务洽谈表"
prop="businessNegotiationTable"
class="mb20">
@@ -174,7 +175,7 @@
<!-- 市场采购 -->
<el-form-item
v-if="dataForm.purchaseType === 'market_purchase'"
v-if="dataForm.purchaseType === PURCHASE_TYPE_IDS.MARKET_PURCHASE"
label="市场采购纪要"
prop="marketPurchaseMinutes"
class="mb20">
@@ -194,7 +195,7 @@
<!-- 网上商城 -->
<el-form-item
v-if="dataForm.purchaseType === 'online_mall'"
v-if="dataForm.purchaseType === PURCHASE_TYPE_IDS.ONLINE_MALL"
label="网上商城采购相关材料"
prop="onlineMallMaterials"
class="mb20">
@@ -209,7 +210,7 @@
</el-form-item>
<!-- 委托采购中心 -->
<template v-if="dataForm.purchaseType === 'entrust_center'">
<template v-if="dataForm.purchaseType === PURCHASE_TYPE_IDS.ENTRUST_CENTER">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" class="mb20">
<el-radio-group v-model="dataForm.entrustCenterType">
<el-radio label="service_online">服务类网上商城</el-radio>
@@ -265,7 +266,7 @@
<!-- 其他方式货物类 -->
<el-form-item
v-if="dataForm.entrustCenterType === 'other' && isGoodsCategory"
v-if="dataForm.entrustCenterType === 'other' && categoryCodePath && categoryCodePath[0] === 'A'"
label="采购需求填报模板"
prop="purchaseRequirementTemplate"
class="mb20">
@@ -292,36 +293,39 @@
<el-radio label="no"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="dataForm.hasRecommendedSupplier === 'yes'"
label="推荐供应商"
prop="recommendedSuppliers"
class="mb20">
<el-input
v-model="dataForm.recommendedSuppliers"
placeholder="请输入三家供应商名称,用逗号分隔"
clearable />
<div class="template-note mt5">
<el-text type="info" size="small">请输入三家供应商名称用逗号分隔</el-text>
</div>
</el-form-item>
<el-form-item
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelect"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('invite_select')"
class="mb10">
下载服务商城项目需求模板邀请比选模版
</el-button>
<upload-file
v-model="dataForm.serviceInviteSelect"
:limit="5"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 有推荐供应商显示推荐供应商输入框和邀请比选模板 -->
<template v-if="dataForm.hasRecommendedSupplier === 'yes'">
<el-form-item
label="推荐供应商"
prop="recommendedSuppliers"
class="mb20">
<el-input
v-model="dataForm.recommendedSuppliers"
placeholder="请输入三家供应商名称,用逗号分隔"
clearable />
<div class="template-note mt5">
<el-text type="info" size="small">请输入三家供应商名称用逗号分隔</el-text>
</div>
</el-form-item>
<el-form-item
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelect"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('invite_select')"
class="mb10">
下载服务商城项目需求模板邀请比选模版
</el-button>
<upload-file
v-model="dataForm.serviceInviteSelect"
:limit="5"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 无推荐供应商显示公开比选模板 -->
<el-form-item
v-if="dataForm.hasRecommendedSupplier === 'no'"
label="服务商城项目需求模板(公开比选)"
@@ -344,10 +348,10 @@
</div>
<!-- 分支二学校统一采购 -->
<div v-else>
<div class="mb20" v-else >
<div class="step-title mb20">学校统一采购</div>
<el-form-item label="采购形式" prop="purchaseMode" class="mb20">
<el-select
<el-select
v-model="dataForm.purchaseMode"
placeholder="请选择采购形式"
clearable
@@ -364,6 +368,7 @@
v-model="dataForm.purchaseTypeUnion"
placeholder="请选择采购方式"
clearable
:disabled="isAutoSelectPurchaseTypeUnion"
style="width: 100%">
<el-option
v-for="item in purchaseTypeUnionList"
@@ -470,6 +475,69 @@
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 特殊规则5<=金额<40万服务类目isMallService=1isProjectService=1自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelectSchool">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplierSchool" class="mb20">
<el-radio-group v-model="dataForm.hasRecommendedSupplierSchool">
<el-radio label="yes"></el-radio>
<el-radio label="no"></el-radio>
</el-radio-group>
</el-form-item>
<!-- 有推荐供应商显示推荐供应商输入框和邀请比选模板 -->
<template v-if="dataForm.hasRecommendedSupplierSchool === 'yes'">
<el-form-item
label="推荐供应商"
prop="recommendedSuppliersSchool"
class="mb20">
<el-input
v-model="dataForm.recommendedSuppliersSchool"
type="textarea"
:rows="3"
placeholder="请输入三家供应商名称,用逗号或分号分隔"
clearable />
<div class="template-note mt5">
<el-text type="info" size="small">请输入三家供应商名称用逗号或分号分隔</el-text>
</div>
</el-form-item>
<el-form-item
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelectSchool"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('invite_select')"
class="mb10">
下载服务商城项目需求模板邀请比选模版
</el-button>
<upload-file
v-model="dataForm.serviceInviteSelectSchool"
:limit="5"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 无推荐供应商显示公开比选模板 -->
<el-form-item
v-if="dataForm.hasRecommendedSupplierSchool === 'no'"
label="服务商城项目需求模板(公开比选)"
prop="servicePublicSelectSchoolAuto"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
<upload-file
v-model="dataForm.servicePublicSelectSchoolAuto"
:limit="5"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊规则40<=金额<100万服务类目自动使用公开比选需求模版 -->
<el-form-item
v-if="showAutoPublicSelect"
@@ -602,8 +670,14 @@ const dataForm = reactive({
importApplication: '',
governmentPurchaseIntent: '',
servicePublicSelectSchool: '',
// 学校统一采购特殊规则字段5万<=金额<40万
hasRecommendedSupplierSchool: '',
recommendedSuppliersSchool: '',
serviceInviteSelectSchool: '',
servicePublicSelectSchoolAuto: '',
});
const categoryTreeData = ref<any[]>([]);
const categoryCodePath = ref<string[]>([]); // 级联选择器的路径数组
const fundSourceList = ref<any[]>([]);
const isCentralizedList = ref<any[]>([]);
const isSpecialList = ref<any[]>([]);
@@ -612,6 +686,14 @@ const purchaseModeSchoolList = ref<any[]>([]);
const purchaseTypeUnionList = ref<any[]>([]);
const loading = ref(false);
// 采购方式ID常量
const PURCHASE_TYPE_IDS = {
BUSINESS_NEGOTIATION: '77b429c146fc9e12ba4c5573da19ad70', // 商务洽谈
MARKET_PURCHASE: 'd522054027140e4d76e074cd96ecfc12', // 市场采购
ONLINE_MALL: 'e8723b4e3c3d51deb54f9349482ea894', // 网上商城
ENTRUST_CENTER: '981bf052a0b30b028a4a89ae490c9b1d' // 委托采购中心
};
// 判断是否为部门自行采购(是否集采=0
const isDeptPurchase = computed(() => {
return dataForm.isCentralized === '0';
@@ -622,6 +704,31 @@ const stepTwoTitle = computed(() => {
return isDeptPurchase.value ? '部门自行采购' : '学校统一采购';
});
// 根据 code 查找完整路径(用于回显)
const findCategoryPath = (data: any[], targetCode: string, path: string[] = []): string[] | null => {
for (const item of data) {
const currentPath = [...path, item.code];
if (item.code === targetCode) {
return currentPath;
}
if (item.children && item.children.length > 0) {
const found = findCategoryPath(item.children, targetCode, currentPath);
if (found) return found;
}
}
return null;
};
// 级联选择器变化处理
const handleCategoryChange = (value: string[]) => {
if (value && value.length > 0) {
// 取最后一个值作为选中的 code
dataForm.categoryCode = value[value.length - 1];
} else {
dataForm.categoryCode = '';
}
};
// 从品目编码中获取项目类型和属性
const getCategoryInfo = () => {
if (!dataForm.categoryCode || categoryTreeData.value.length === 0) {
@@ -678,20 +785,53 @@ const showAutoInviteSelect = computed(() => {
return budget >= 50000 && budget < 400000 && isServiceCategory.value && isSpecialServiceCategory.value;
});
// 判断是否显示自动公开比选模版(40万<=金额<100万服务类目特殊服务类目
// 判断是否显示学校统一采购的自动邀请比选模版(5万<=金额<40万服务类目特殊服务类目
const showAutoInviteSelectSchool = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
return budget >= 50000 && budget < 400000 && isSpecialServiceCategory.value;
});
// 判断是否显示自动公开比选模版40万<=金额<100万特殊服务类目isMallService=1、isProjectService=1
const showAutoPublicSelect = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
return budget >= 400000 && budget < 1000000 && isServiceCategory.value && isSpecialServiceCategory.value;
return budget >= 400000 && budget < 1000000 && isSpecialServiceCategory.value;
});
// 监听品目编码变化,自动设置采购方式
watch(() => dataForm.categoryCode, (newVal) => {
if (isAutoSelectPurchaseType.value && !dataForm.purchaseType) {
const onlineMallOption = purchaseTypeDeptList.value.find(item => item.value === 'online_mall');
if (onlineMallOption) {
dataForm.purchaseType = 'online_mall';
// 判断学校统一采购是否需要自动设置采购方式5万<=金额<40万服务类目特殊服务类目
const isAutoSelectPurchaseTypeUnion = computed(() => {
if (isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
return budget >= 50000 && budget < 400000 && isSpecialServiceCategory.value;
});
// 监听品目编码和预算金额变化,自动设置采购方式
watch([() => dataForm.categoryCode, () => dataForm.budget], () => {
// 部门自行采购:自动设置网上商城
if (isAutoSelectPurchaseType.value && isDeptPurchase.value) {
// 查找网上商城选项通过id或value匹配
const onlineMallOption = purchaseTypeDeptList.value.find(item =>
item.id === PURCHASE_TYPE_IDS.ONLINE_MALL ||
item.value === PURCHASE_TYPE_IDS.ONLINE_MALL
);
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
dataForm.purchaseType = onlineMallOption.value;
}
}
// 学校统一采购:自动设置网上商城采购方式
if (isAutoSelectPurchaseTypeUnion.value && !isDeptPurchase.value) {
// 查找学校统一采购方式字典中包含"网上商城"的选项
const onlineMallOption = purchaseTypeUnionList.value.find(item => {
const label = item.label || item.dictLabel || item.name || '';
return label.includes('网上商城') || label.includes('商城');
});
if (onlineMallOption && dataForm.purchaseTypeUnion !== onlineMallOption.value) {
dataForm.purchaseTypeUnion = onlineMallOption.value;
}
}
}, { immediate: true });
@@ -783,6 +923,16 @@ const nextStep = async () => {
try {
const fieldsToValidate = ['projectName', 'applyDate', 'fundSource', 'budget', 'isCentralized', 'isSpecial', 'categoryCode'];
await formRef.value?.validateField(fieldsToValidate);
// 打印品目编码的值
console.log('品目编码值 (categoryCode):', dataForm.categoryCode);
console.log('品目编码路径 (categoryCodePath):', categoryCodePath.value);
console.log('品目编码完整信息:', {
code: dataForm.categoryCode,
path: categoryCodePath.value,
categoryInfo: getCategoryInfo()
});
currentStep.value = 1;
} catch (error) {
useMessage().warning('请完善第一步信息');
@@ -882,7 +1032,7 @@ const getIsCentralizedDict = async () => {
// 获取是否特殊情况字典
const getIsSpecialDict = async () => {
try {
const res = await getDicts('PURCHASE_IS_SPECIAL');
const res = await getDicts('PURCHASE_IS_SPEC');
isSpecialList.value = [];
if (res.data && Array.isArray(res.data)) {
isSpecialList.value = res.data.map((item: any) => ({
@@ -914,8 +1064,9 @@ const getPurchaseTypeDeptDict = async () => {
purchaseTypeDeptList.value = [];
if (res.data && Array.isArray(res.data)) {
purchaseTypeDeptList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
value: item.id || item.dictValue || item.code
}));
}
} catch (err) {
@@ -1075,6 +1226,27 @@ const handleTempStore = async () => {
}
};
// 设置品目编码回显路径
const setCategoryCodePath = () => {
if (dataForm.categoryCode && categoryTreeData.value.length > 0) {
const path = findCategoryPath(categoryTreeData.value, dataForm.categoryCode);
if (path) {
categoryCodePath.value = path;
} else {
categoryCodePath.value = [];
}
} else {
categoryCodePath.value = [];
}
};
// 监听 categoryTreeData 变化,设置回显路径
watch(() => categoryTreeData.value, () => {
if (dataForm.categoryCode) {
setCategoryCodePath();
}
}, { deep: true });
// 初始化
onMounted(async () => {
await Promise.all([
@@ -1086,6 +1258,10 @@ onMounted(async () => {
getPurchaseModeSchoolDict(),
getPurchaseTypeUnionDict(),
]);
// 如果有 categoryCode设置回显路径
if (dataForm.categoryCode) {
setCategoryCodePath();
}
});
</script>

View File

@@ -109,16 +109,17 @@
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-form-item label="品目编码" prop="categoryCode">
<el-tree-select
v-model="dataForm.categoryCode"
:data="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children' }"
<el-cascader
v-model="categoryCodePath"
:options="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children', checkStrictly: true }"
placeholder="请选择品目编码(需要显示所有的层级)"
clearable
check-strictly
:render-after-expand="false"
filterable
:show-all-levels="true"
:disabled="isView"
style="width: 100%" />
style="width: 100%"
@change="handleCategoryChange" />
</el-form-item>
</el-col>
</el-row>
@@ -638,6 +639,7 @@ const dataForm = reactive({
servicePublicSelectSchool: '',
});
const categoryTreeData = ref<any[]>([]);
const categoryCodePath = ref<string[]>([]); // 级联选择器的路径数组
const selectedCategory = ref<any>(null);
const fundSourceList = ref<any[]>([]);
const isCentralizedList = ref<any[]>([]);
@@ -667,6 +669,45 @@ const stepTwoTitle = computed(() => {
return isDeptPurchase.value ? '部门自行采购' : '学校统一采购';
});
// 根据 code 查找完整路径(用于回显)
const findCategoryPath = (data: any[], targetCode: string, path: string[] = []): string[] | null => {
for (const item of data) {
const currentPath = [...path, item.code];
if (item.code === targetCode) {
return currentPath;
}
if (item.children && item.children.length > 0) {
const found = findCategoryPath(item.children, targetCode, currentPath);
if (found) return found;
}
}
return null;
};
// 级联选择器变化处理
const handleCategoryChange = (value: string[]) => {
if (value && value.length > 0) {
// 取最后一个值作为选中的 code
dataForm.categoryCode = value[value.length - 1];
} else {
dataForm.categoryCode = '';
}
};
// 设置品目编码回显路径
const setCategoryCodePath = () => {
if (dataForm.categoryCode && categoryTreeData.value.length > 0) {
const path = findCategoryPath(categoryTreeData.value, dataForm.categoryCode);
if (path) {
categoryCodePath.value = path;
} else {
categoryCodePath.value = [];
}
} else {
categoryCodePath.value = [];
}
};
// 从品目编码中获取项目类型和属性
const getCategoryInfo = () => {
if (!dataForm.categoryCode || categoryTreeData.value.length === 0) {
@@ -848,6 +889,7 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
currentStep.value = 0;
// 重置表单
categoryCodePath.value = []; // 重置级联选择器路径
Object.assign(dataForm, {
id: '',
projectName: '',
@@ -904,6 +946,10 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
getObj(rowData.id)
.then((res) => {
Object.assign(dataForm, res.data || {});
// 设置品目编码回显路径
if (dataForm.categoryCode) {
setCategoryCodePath();
}
if (type === 'edit' || type === 'view') {
currentStep.value = 1;
}
@@ -914,6 +960,9 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
.finally(() => {
loading.value = false;
});
} else {
// 新增时重置路径
categoryCodePath.value = [];
}
});
};
@@ -1002,7 +1051,7 @@ const getIsCentralizedDict = async () => {
// 获取是否特殊情况字典
const getIsSpecialDict = async () => {
try {
const res = await getDicts('PURCHASE_IS_SPECIAL');
const res = await getDicts('PURCHASE_IS_SPEC');
isSpecialList.value = [];
if (res.data && Array.isArray(res.data)) {
isSpecialList.value = res.data.map((item: any) => ({
@@ -1202,6 +1251,13 @@ const handleTempStore = async () => {
}
};
// 监听 categoryTreeData 变化,设置回显路径
watch(() => categoryTreeData.value, () => {
if (dataForm.categoryCode) {
setCategoryCodePath();
}
}, { deep: true });
// 暴露变量
defineExpose({
openDialog,