This commit is contained in:
2026-02-03 19:18:57 +08:00
parent 777e18a8a5
commit ddab0a9072
3 changed files with 1125 additions and 483 deletions

View File

@@ -21,12 +21,13 @@
ref="formRef"
:model="dataForm"
:rules="dataRules"
label-width="140px">
label-width="120px"
class="compact-form">
<!-- 第一步基本信息 -->
<div v-show="currentStep === 0">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="采购项目名称" prop="projectName">
<el-input
v-model="dataForm.projectName"
@@ -34,7 +35,7 @@
clearable />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="12" class="mb16">
<el-form-item label="填报日期" prop="applyDate">
<el-date-picker
v-model="dataForm.applyDate"
@@ -46,8 +47,8 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="资金来源" prop="fundSource">
<el-select
v-model="dataForm.fundSource"
@@ -62,19 +63,31 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="预算金额(元)" prop="budget">
<el-col :span="12" class="mb16">
<el-form-item label="预算金额" prop="budget">
<div class="budget-input-group">
<el-input-number
v-model="dataForm.budget"
v-model="budgetInputValue"
:min="0.01"
:precision="2"
placeholder="请输入预算金额"
style="width: 100%" />
:placeholder="getBudgetPlaceholder()"
:controls="false"
class="budget-input"
@change="handleBudgetChange" />
<el-select
v-model="budgetUnit"
class="budget-unit-select"
@change="handleBudgetUnitChange">
<el-option label="元" value="yuan" />
<el-option label="千元" value="thousand" />
<el-option label="万元" value="wan" />
</el-select>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="是否集采" prop="isCentralized">
<el-select
v-model="dataForm.isCentralized"
@@ -89,7 +102,7 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="12" class="mb16">
<el-form-item label="是否特殊情况" prop="isSpecial">
<el-select
v-model="dataForm.isSpecial"
@@ -105,8 +118,8 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-row :gutter="20">
<el-col :span="24" class="mb16">
<el-form-item label="品目编码" prop="categoryCode">
<el-cascader
v-model="categoryCodePath"
@@ -127,18 +140,18 @@
<div v-show="currentStep === 1">
<!-- 分支一部门自行采购 -->
<div class="mb20" v-if="isDeptPurchase">
<div class="step-title mb20">部门自行采购</div>
<el-form-item label="采购内容" prop="projectContent" class="mb20">
<div class="step-title mb16">部门自行采购</div>
<el-form-item label="采购内容" prop="projectContent" class="mb16">
<el-input
v-model="dataForm.projectContent"
type="textarea"
:rows="4"
:rows="3"
:maxlength="1000"
show-word-limit
placeholder="请输入采购内容限制1000字"
clearable />
</el-form-item>
<el-form-item label="采购方式" prop="purchaseType" class="mb20">
<el-form-item label="采购方式" prop="purchaseType" class="mb16">
<el-select
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
@@ -158,7 +171,7 @@
v-if="isPurchaseType(PURCHASE_TYPE_IDS.BUSINESS_NEGOTIATION)"
label="商务洽谈表"
prop="businessNegotiationTable"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -180,7 +193,7 @@
v-if="isPurchaseType(PURCHASE_TYPE_IDS.MARKET_PURCHASE)"
label="市场采购纪要"
prop="marketPurchaseMinutes"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -202,7 +215,7 @@
v-if="isPurchaseType(PURCHASE_TYPE_IDS.ONLINE_MALL)"
label="网上商城采购相关材料"
prop="onlineMallMaterials"
class="mb20">
class="mb16">
<upload-file
v-model="dataForm.onlineMallMaterials"
:limit="1"
@@ -216,7 +229,7 @@
v-if="isInquiryPurchaseType"
label="询价模板"
prop="inquiryTemplate"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -235,7 +248,7 @@
<!-- 委托采购中心 -->
<template v-if="isPurchaseType(PURCHASE_TYPE_IDS.ENTRUST_CENTER)">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" class="mb20">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" class="mb16">
<!-- 由系统根据品目末级节点标记自动判断不允许用户手动选择 -->
<el-radio-group v-model="dataForm.entrustCenterType" disabled>
<el-radio label="service_online">服务类网上商城</el-radio>
@@ -245,7 +258,7 @@
<!-- 服务类网上商城判断品目编码的第一个值是否为C -->
<template v-if="dataForm.entrustCenterType === 'service_online' && categoryCodePath && categoryCodePath.length > 0 && categoryCodePath[0] === 'C'">
<el-form-item label="是否有供应商" prop="hasSupplier" class="mb20">
<el-form-item label="是否有供应商" prop="hasSupplier" class="mb16">
<el-radio-group v-model="dataForm.hasSupplier">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
@@ -256,11 +269,11 @@
<el-form-item
label="供应商名称"
prop="suppliers"
class="mb20">
class="mb16">
<el-input
v-model="dataForm.suppliers"
type="textarea"
:rows="3"
:rows="2"
placeholder="请输入供应商名称,多个供应商请用逗号或分号分隔"
maxlength="500"
show-word-limit />
@@ -271,7 +284,7 @@
<el-form-item
label="服务商城项目需求模板(直选)"
prop="serviceDirectSelect"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -292,7 +305,7 @@
v-if="dataForm.hasSupplier === 'no'"
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelect"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -315,7 +328,7 @@
v-if="dataForm.entrustCenterType === 'other' && categoryCodePath && categoryCodePath[0] === 'A'"
label="采购需求填报模板"
prop="purchaseRequirementTemplate"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -335,18 +348,18 @@
<!-- 特殊规则5<=金额<40万服务类目自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelect">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplier" class="mb20">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplier" class="mb16">
<el-radio-group v-model="dataForm.hasRecommendedSupplier">
<el-radio label="yes"></el-radio>
<el-radio label="no"></el-radio>
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
</el-radio-group>
</el-form-item>
<!-- 有推荐供应商显示推荐供应商输入框和邀请比选模板 -->
<template v-if="dataForm.hasRecommendedSupplier === 'yes'">
<template v-if="dataForm.hasRecommendedSupplier === '1'">
<el-form-item
label="推荐供应商"
prop="recommendedSuppliers"
class="mb20">
class="mb16">
<el-input
v-model="dataForm.recommendedSuppliers"
placeholder="请输入三家供应商名称,用逗号分隔"
@@ -358,7 +371,7 @@
<el-form-item
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelect"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -380,7 +393,7 @@
v-if="dataForm.hasRecommendedSupplier === 'no'"
label="服务商城项目需求模板(公开比选)"
prop="servicePublicSelectAuto"
class="mb20">
class="mb16">
<el-button
type="primary"
link
@@ -399,7 +412,7 @@
</template>
<!-- 其他材料zip压缩包 -->
<el-form-item label="其他材料" prop="otherMaterials" class="mb20">
<el-form-item label="其他材料" prop="otherMaterials" class="mb16">
<upload-file
v-model="dataForm.otherMaterials"
:limit="5"
@@ -411,22 +424,23 @@
</div>
<!-- 分支二学校统一采购 -->
<div class="mb20" v-else >
<div class="step-title mb20">学校统一采购</div>
<el-form-item label="采购形式" prop="purchaseMode" class="mb20">
<el-select
v-model="dataForm.purchaseMode"
placeholder="请选择采购形式"
clearable
style="width: 100%">
<el-option
<div class="mb20" v-else>
<div class="step-title mb16">学校统一采购</div>
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="采购形式" prop="purchaseMode">
<el-radio-group v-model="dataForm.purchaseMode">
<el-radio
v-for="item in purchaseModeSchoolList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
:label="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="采购方式" prop="purchaseTypeUnion" class="mb20">
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="采购方式" prop="purchaseTypeUnion">
<el-select
v-model="dataForm.purchaseTypeUnion"
placeholder="请选择采购方式"
@@ -440,9 +454,13 @@
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 业务分管处室 -->
<el-form-item label="业务分管处室" prop="deptClassifyId" class="mb20">
<el-col :span="12" class="mb16">
<el-form-item label="业务分管处室" prop="deptClassifyId">
<el-select
v-model="dataForm.deptClassifyId"
placeholder="请选择业务分管处室"
@@ -457,9 +475,11 @@
:value="item.id" />
</el-select>
</el-form-item>
</el-col>
<!-- 分管校领导 -->
<el-form-item label="分管校领导" prop="schoolLeaderUserId" class="mb20">
<el-col :span="12" class="mb16">
<el-form-item label="分管校领导" prop="schoolLeaderUserId">
<el-select
v-model="dataForm.schoolLeaderUserId"
placeholder="请选择分管校领导"
@@ -474,13 +494,16 @@
:value="item.userId" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 金额>=30显示可行性论证报告和会议纪要 -->
<template v-if="dataForm.budget && dataForm.budget >= 300000">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item
label="项目可行性论证报告"
prop="feasibilityReport"
class="mb20">
prop="feasibilityReport">
<el-button
type="primary"
link
@@ -496,7 +519,15 @@
:data="{ fileType: FILE_TYPE_MAP.feasibilityReport }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutes" class="mb20">
</el-col>
<!-- 通用会议纪要只有在没有选择特殊情况时才显示 -->
<el-col
v-if="!isUrgentSpecial && !isSpecialType('2') && !isSpecialType('3')"
:span="12"
class="mb16">
<el-form-item
label="会议纪要"
prop="meetingMinutes">
<upload-file
v-model="dataForm.meetingMinutes"
:limit="5"
@@ -504,11 +535,15 @@
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 特殊情况紧急 -->
<template v-if="isUrgentSpecial">
<el-form-item label="会议纪要" prop="meetingMinutesUrgent" class="mb20">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="会议纪要" prop="meetingMinutesUrgent">
<upload-file
v-model="dataForm.meetingMinutesUrgent"
:limit="5"
@@ -516,14 +551,17 @@
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesUrgent }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 特殊情况单一来源 -->
<template v-if="isSpecialType('2')">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item
label="单一来源论专家证附件"
prop="singleSourceProof"
class="mb20">
prop="singleSourceProof">
<el-button
type="primary"
link
@@ -539,7 +577,9 @@
:data="{ fileType: FILE_TYPE_MAP.singleSourceProof }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesSingle" class="mb20">
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="会议纪要" prop="meetingMinutesSingle">
<upload-file
v-model="dataForm.meetingMinutesSingle"
:limit="5"
@@ -547,14 +587,17 @@
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 特殊情况进口 -->
<template v-if="isSpecialType('3')">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item
label="进口产品申请及专家论证意见表"
prop="importApplication"
class="mb20">
prop="importApplication">
<el-button
type="primary"
link
@@ -570,7 +613,9 @@
:data="{ fileType: FILE_TYPE_MAP.importApplication }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesImport" class="mb20">
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="会议纪要" prop="meetingMinutesImport">
<upload-file
v-model="dataForm.meetingMinutesImport"
:limit="5"
@@ -578,36 +623,45 @@
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 特殊规则5<=金额<40万服务类目isMallService=1isProjectService=1自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelectSchool">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplierSchool" class="mb20">
<el-row :gutter="20">
<el-col :span="12" class="mb16">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplierSchool">
<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>
</el-col>
<!-- 有推荐供应商显示推荐供应商输入框 -->
<el-form-item
<el-col
v-if="dataForm.hasRecommendedSupplierSchool === 'yes'"
:span="12"
class="mb16">
<el-form-item
label="推荐供应商"
prop="recommendedSuppliersSchool"
class="mb20">
prop="recommendedSuppliersSchool">
<el-input
v-model="dataForm.recommendedSuppliersSchool"
type="textarea"
:rows="3"
:rows="2"
placeholder="请输入三家供应商名称,用逗号或分号分隔"
clearable />
<div class="template-note mt5">
<el-text type="info" size="small">请输入三家供应商名称用逗号或分号分隔</el-text>
</div>
</el-form-item>
</el-col>
</el-row>
</template>
<!-- 需求文件 -->
<el-form-item label="需求文件" :prop="getRequirementFileProp()" class="mb20">
<el-form-item label="需求文件" :prop="getRequirementFileProp()" class="mb16">
<!-- 特殊规则5<=金额<40万服务类目isMallService=1isProjectService=1自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelectSchool">
<!-- 有推荐供应商显示邀请比选模板 -->
@@ -691,12 +745,15 @@
</template>
</el-form-item>
<el-row :gutter="20">
<!-- 金额>=100政府采购意向表 -->
<el-form-item
<el-col
v-if="dataForm.budget && dataForm.budget >= 1000000"
:span="12"
class="mb16">
<el-form-item
label="政府采购意向申请表"
prop="governmentPurchaseIntent"
class="mb20">
prop="governmentPurchaseIntent">
<upload-file
v-model="dataForm.governmentPurchaseIntent"
:limit="5"
@@ -704,9 +761,11 @@
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</el-col>
<!-- 其他材料zip压缩包 -->
<el-form-item label="其他材料" prop="otherMaterials" class="mb20">
<el-col :span="12" class="mb16">
<el-form-item label="其他材料" prop="otherMaterials">
<upload-file
v-model="dataForm.otherMaterials"
:limit="5"
@@ -715,14 +774,16 @@
upload-file-url="/purchase/purchasingfiles/upload" />
<div class="template-note">支持上传zip格式的压缩包文件</div>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<el-form-item label="备注" prop="remark" v-if="currentStep === 1">
<el-form-item label="备注" prop="remark" v-if="currentStep === 1" class="mb16">
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="3"
:rows="2"
placeholder="请输入备注"
clearable />
</el-form-item>
@@ -846,6 +907,10 @@ const businessDeptList = ref<any[]>([]);
const schoolLeaderList = ref<any[]>([]);
const loading = ref(false);
// 预算金额输入相关
const budgetUnit = ref<'yuan' | 'thousand' | 'wan'>('yuan');
const budgetInputValue = ref<number | null>(null);
// 采购方式ID常量
const PURCHASE_TYPE_IDS = {
BUSINESS_NEGOTIATION: '77b429c146fc9e12ba4c5573da19ad70', // 商务洽谈
@@ -1635,7 +1700,11 @@ const handleSubmit = async () => {
router.push('/finance/purchasingrequisition');
}
} catch (err: any) {
useMessage().error(err.msg || '提交失败');
// 全局拦截器已经显示了错误提示,这里不需要再次显示
// 只有当错误没有 msg 时才显示默认错误提示
if (!err?.msg) {
useMessage().error('提交失败');
}
} finally {
loading.value = false;
}
@@ -1698,7 +1767,11 @@ const handleTempStore = async () => {
router.push('/finance/purchasingrequisition');
}
} catch (err: any) {
useMessage().error(err.msg || '暂存失败');
// 全局拦截器已经显示了错误提示,这里不需要再次显示
// 只有当错误没有 msg 时才显示默认错误提示
if (!err?.msg) {
useMessage().error('暂存失败');
}
} finally {
loading.value = false;
}
@@ -1718,6 +1791,83 @@ const setCategoryCodePath = () => {
}
};
// 预算金额单位转换
const handleBudgetChange = (value: number | null) => {
if (value === null || value === undefined) {
dataForm.budget = null;
return;
}
// 根据单位转换为元
switch (budgetUnit.value) {
case 'yuan':
dataForm.budget = value;
break;
case 'thousand':
dataForm.budget = value * 1000;
break;
case 'wan':
dataForm.budget = value * 10000;
break;
}
};
// 预算金额单位变化处理
const handleBudgetUnitChange = (unit: 'yuan' | 'thousand' | 'wan') => {
if (!dataForm.budget) {
budgetInputValue.value = null;
return;
}
// 根据新单位转换显示值
switch (unit) {
case 'yuan':
budgetInputValue.value = dataForm.budget;
break;
case 'thousand':
budgetInputValue.value = dataForm.budget / 1000;
break;
case 'wan':
budgetInputValue.value = dataForm.budget / 10000;
break;
}
};
// 获取预算金额输入框的 placeholder
const getBudgetPlaceholder = (): string => {
switch (budgetUnit.value) {
case 'yuan':
return '请输入金额';
case 'thousand':
return '请输入金额(千元)';
case 'wan':
return '请输入金额(万元)';
default:
return '请输入金额';
}
};
// 监听 dataForm.budget 变化,同步到 budgetInputValue
watch(() => dataForm.budget, (newVal) => {
if (newVal === null || newVal === undefined) {
budgetInputValue.value = null;
return;
}
// 根据当前单位转换显示值
switch (budgetUnit.value) {
case 'yuan':
budgetInputValue.value = newVal;
break;
case 'thousand':
budgetInputValue.value = newVal / 1000;
break;
case 'wan':
budgetInputValue.value = newVal / 10000;
break;
}
}, { immediate: true });
// 监听 categoryTreeData 变化,设置回显路径
watch(() => categoryTreeData.value, () => {
if (dataForm.categoryCode) {
@@ -1780,6 +1930,11 @@ onMounted(async () => {
dataForm.isSpecial = '0';
}
// 初始化预算金额显示值
if (dataForm.budget) {
budgetInputValue.value = dataForm.budget;
}
// 如果有 categoryCode设置回显路径
if (dataForm.categoryCode) {
setCategoryCodePath();
@@ -1793,6 +1948,9 @@ onMounted(async () => {
.mb20 {
margin-bottom: 20px;
}
.mb16 {
margin-bottom: 16px;
}
.mb10 {
margin-bottom: 10px;
}
@@ -1805,18 +1963,94 @@ onMounted(async () => {
color: var(--el-text-color-primary);
padding-bottom: 10px;
border-bottom: 1px solid var(--el-border-color-light);
margin-bottom: 20px;
margin-bottom: 16px;
}
/* 紧凑表单样式 */
.compact-form {
:deep(.el-form-item) {
margin-bottom: 16px;
}
:deep(.el-form-item__label) {
padding-right: 12px;
font-size: 14px;
}
:deep(.el-input__inner),
:deep(.el-textarea__inner) {
font-size: 14px;
}
}
.template-note {
margin-top: 5px;
color: var(--el-text-color-secondary);
font-size: 12px;
}
/* 预算金额输入组样式 - 并排显示,无缝连接 */
.budget-input-group {
display: flex;
align-items: stretch;
width: 100%;
transition: all 0.2s ease;
.budget-input {
flex: 1;
:deep(.el-input__wrapper) {
border-radius: 4px 0 0 4px;
border-right: none;
transition: all 0.2s ease;
}
:deep(.el-input__wrapper:hover) {
z-index: 1;
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary-light-7);
}
:deep(.el-input__wrapper.is-focus) {
z-index: 1;
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary-light-7);
}
}
.budget-unit-select {
width: 100px;
flex-shrink: 0;
cursor: pointer;
:deep(.el-input__wrapper) {
border-radius: 0 4px 4px 0;
border-left: 1px solid var(--el-border-color);
margin-left: -1px;
transition: all 0.2s ease;
}
:deep(.el-input__wrapper:hover) {
z-index: 1;
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary-light-7);
}
:deep(.el-input__wrapper.is-focus) {
z-index: 1;
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary-light-7);
}
}
}
.form-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-light);
margin-top: 16px;
}
</style>

View File

@@ -2,12 +2,17 @@
<el-dialog
:title="dialogTitle"
v-model="visible"
width="1200px"
:width="isView ? '1400px' : '1200px'"
:close-on-click-modal="false"
draggable>
<div v-loading="loading">
<!-- 步骤条 -->
<el-steps :active="currentStep" finish-status="success" style="margin-bottom: 30px;">
draggable
:class="{ 'view-dialog': isView }">
<div v-loading="loading" :class="{ 'view-content': isView }">
<!-- 步骤条查看模式下隐藏 -->
<el-steps
v-if="!isView"
:active="currentStep"
finish-status="success"
style="margin-bottom: 30px;">
<el-step title="基本信息" />
<el-step :title="stepTwoTitle" />
</el-steps>
@@ -16,41 +21,49 @@
ref="formRef"
:model="dataForm"
:rules="dataRules"
label-width="140px">
:label-width="isView ? '120px' : '140px'"
:class="{ 'view-form': isView }">
<!-- 第一步基本信息 -->
<div v-show="currentStep === 0">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<div v-show="currentStep === 0 || isView">
<el-row :gutter="isView ? 16 : 24">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="采购项目名称" prop="projectName">
<template v-if="isView">
<span class="view-text">{{ dataForm.projectName || '-' }}</span>
</template>
<el-input
v-else
v-model="dataForm.projectName"
placeholder="请输入采购项目名称"
clearable
:disabled="isView" />
clearable />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="填报日期" prop="applyDate">
<template v-if="isView">
<span class="view-text">{{ dataForm.applyDate || '-' }}</span>
</template>
<el-date-picker
v-else
v-model="dataForm.applyDate"
type="date"
placeholder="请选择填报日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:disabled="isView"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="资金来源" prop="fundSource">
<template v-if="isView">
<span class="view-text">{{ getDictLabel(fundSourceList, dataForm.fundSource) || '-' }}</span>
</template>
<el-select
v-else
v-model="dataForm.fundSource"
placeholder="请选择资金来源"
clearable
:disabled="isView"
style="width: 100%">
<el-option
v-for="item in fundSourceList"
@@ -60,26 +73,34 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
</el-row>
<el-row :gutter="isView ? 16 : 24">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="预算金额(元)" prop="budget">
<template v-if="isView">
<span class="view-text">{{ dataForm.budget ? Number(dataForm.budget).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : '-' }}</span>
</template>
<el-input-number
v-else
v-model="dataForm.budget"
:min="0.01"
:precision="2"
placeholder="请输入预算金额"
:disabled="isView"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="是否集采" prop="isCentralized">
<template v-if="isView">
<el-tag v-if="dataForm.isCentralized === '1'" type="success"></el-tag>
<el-tag v-else-if="dataForm.isCentralized === '0'" type="info"></el-tag>
<span v-else class="view-text">-</span>
</template>
<el-select
v-else
v-model="dataForm.isCentralized"
placeholder="请选择是否集采"
clearable
:disabled="isView"
style="width: 100%">
<el-option
v-for="item in isCentralizedList"
@@ -89,13 +110,16 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="isView ? 8 : 12" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="是否特殊情况" prop="isSpecial">
<template v-if="isView">
<span class="view-text">{{ getDictLabel(isSpecialList, dataForm.isSpecial) || '-' }}</span>
</template>
<el-select
v-else
v-model="dataForm.isSpecial"
placeholder="请选择是否特殊情况"
clearable
:disabled="isView"
style="width: 100%">
<el-option
v-for="item in isSpecialList"
@@ -106,10 +130,14 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-row :gutter="isView ? 16 : 24">
<el-col :span="24" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="品目编码" prop="categoryCode">
<template v-if="isView">
<span class="view-text">{{ getCategoryDisplayText() }}</span>
</template>
<el-cascader
v-else
v-model="categoryCodePath"
:options="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children', checkStrictly: true }"
@@ -117,7 +145,6 @@
clearable
filterable
:show-all-levels="true"
:disabled="isView"
style="width: 100%"
@change="handleCategoryChange" />
</el-form-item>
@@ -126,27 +153,34 @@
</div>
<!-- 第二步采购详情 -->
<div v-show="currentStep === 1">
<div v-show="currentStep === 1 || isView">
<!-- 分支一部门自行采购 -->
<div v-if="isDeptPurchase">
<div class="step-title mb20">部门自行采购</div>
<el-form-item label="采购内容" prop="projectContent" class="mb20">
<div :class="isView ? 'step-title mb16' : 'step-title mb20'">部门自行采购</div>
<el-form-item label="采购内容" prop="projectContent" :class="isView ? 'mb16' : 'mb20'">
<template v-if="isView">
<div class="view-text view-textarea">{{ dataForm.projectContent || '-' }}</div>
</template>
<el-input
v-else
v-model="dataForm.projectContent"
type="textarea"
:rows="4"
:maxlength="1000"
show-word-limit
placeholder="请输入采购内容限制1000字"
clearable
:disabled="isView" />
clearable />
</el-form-item>
<el-form-item label="采购方式" prop="purchaseType" class="mb20">
<el-form-item label="采购方式" prop="purchaseType" :class="isView ? 'mb16' : 'mb20'">
<template v-if="isView">
<span class="view-text">{{ getDictLabel(purchaseTypeDeptList, dataForm.purchaseType) || '-' }}</span>
</template>
<el-select
v-else
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
clearable
:disabled="isView || isAutoSelectPurchaseType"
:disabled="isAutoSelectPurchaseType"
style="width: 100%">
<el-option
v-for="item in purchaseTypeDeptList"
@@ -161,16 +195,17 @@
v-if="dataForm.purchaseType === 'business_negotiation'"
label="商务洽谈表"
prop="businessNegotiationTable"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('business_negotiation')"
:disabled="isView"
class="mb10">
下载商务洽谈表模版
</el-button>
</template>
<upload-file
v-model="dataForm.businessNegotiationTable"
:limit="5"
@@ -183,16 +218,17 @@
v-if="dataForm.purchaseType === 'market_purchase'"
label="市场采购纪要"
prop="marketPurchaseMinutes"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('market_purchase_minutes')"
:disabled="isView"
class="mb10">
下载市场采购纪要模版
</el-button>
</template>
<upload-file
v-model="dataForm.marketPurchaseMinutes"
:limit="5"
@@ -205,22 +241,25 @@
v-if="dataForm.purchaseType === 'online_mall'"
label="网上商城采购相关材料"
prop="onlineMallMaterials"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<upload-file
v-model="dataForm.onlineMallMaterials"
:limit="1"
accept=".zip"
:disabled="isView"
upload-file-url="/purchase/purchasingfiles/upload" />
<div class="template-note mt5">
<div v-if="!isView" class="template-note mt5">
<el-text type="info" size="small">请上传zip格式的压缩包</el-text>
</div>
</el-form-item>
<!-- 委托采购中心 -->
<template v-if="dataForm.purchaseType === 'entrust_center'">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" class="mb20">
<el-radio-group v-model="dataForm.entrustCenterType" :disabled="isView">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" :class="isView ? 'mb16' : 'mb20'">
<template v-if="isView">
<span class="view-text">{{ dataForm.entrustCenterType === 'service_online' ? '服务类网上商城' : dataForm.entrustCenterType === 'other' ? '其他方式' : '-' }}</span>
</template>
<el-radio-group v-else v-model="dataForm.entrustCenterType">
<el-radio label="service_online">服务类网上商城</el-radio>
<el-radio label="other">其他方式</el-radio>
</el-radio-group>
@@ -281,16 +320,17 @@
v-if="dataForm.entrustCenterType === 'other' && isGoodsCategory"
label="采购需求填报模板"
prop="purchaseRequirementTemplate"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('purchase_requirement')"
:disabled="isView"
class="mb10">
下载表1采购需求填报模板模版
</el-button>
</template>
<upload-file
v-model="dataForm.purchaseRequirementTemplate"
:limit="5"
@@ -301,8 +341,11 @@
<!-- 特殊规则5<=金额<40万服务类目自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelect">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplier" class="mb20">
<el-radio-group v-model="dataForm.hasRecommendedSupplier" :disabled="isView">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplier" :class="isView ? 'mb16' : 'mb20'">
<template v-if="isView">
<span class="view-text">{{ dataForm.hasRecommendedSupplier === 'yes' ? '有' : dataForm.hasRecommendedSupplier === 'no' ? '无' : '-' }}</span>
</template>
<el-radio-group v-else v-model="dataForm.hasRecommendedSupplier">
<el-radio label="yes"></el-radio>
<el-radio label="no"></el-radio>
</el-radio-group>
@@ -311,29 +354,34 @@
v-if="dataForm.hasRecommendedSupplier === 'yes'"
label="推荐供应商"
prop="recommendedSuppliers"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="isView">
<span class="view-text">{{ dataForm.recommendedSuppliers || '-' }}</span>
</template>
<template v-else>
<el-input
v-model="dataForm.recommendedSuppliers"
placeholder="请输入三家供应商名称,用逗号分隔"
clearable
:disabled="isView" />
clearable />
<div class="template-note mt5">
<el-text type="info" size="small">请输入三家供应商名称用逗号分隔</el-text>
</div>
</template>
</el-form-item>
<el-form-item
label="服务商城项目需求模板(邀请比选)"
prop="serviceInviteSelect"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('invite_select')"
:disabled="isView"
class="mb10">
下载服务商城项目需求模板邀请比选模版
</el-button>
</template>
<upload-file
v-model="dataForm.serviceInviteSelect"
:limit="5"
@@ -344,16 +392,17 @@
v-if="dataForm.hasRecommendedSupplier === 'no'"
label="服务商城项目需求模板(公开比选)"
prop="servicePublicSelectAuto"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
:disabled="isView"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
</template>
<upload-file
v-model="dataForm.servicePublicSelectAuto"
:limit="5"
@@ -365,13 +414,18 @@
<!-- 分支二学校统一采购 -->
<div v-else>
<div class="step-title mb20">学校统一采购</div>
<el-form-item label="采购形式" prop="purchaseMode" class="mb20">
<div :class="isView ? 'step-title mb16' : 'step-title mb20'">学校统一采购</div>
<el-row :gutter="isView ? 16 : 24">
<el-col :span="isView ? 12 : 24" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="采购形式" prop="purchaseMode">
<template v-if="isView">
<span class="view-text">{{ getDictLabel(purchaseModeSchoolList, dataForm.purchaseMode) || '-' }}</span>
</template>
<el-select
v-else
v-model="dataForm.purchaseMode"
placeholder="请选择采购形式"
clearable
:disabled="isView"
style="width: 100%">
<el-option
v-for="item in purchaseModeSchoolList"
@@ -380,12 +434,17 @@
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="采购方式" prop="purchaseTypeUnion" class="mb20">
</el-col>
<el-col :span="isView ? 12 : 24" :class="isView ? 'mb16' : 'mb20'">
<el-form-item label="采购方式" prop="purchaseTypeUnion">
<template v-if="isView">
<span class="view-text">{{ getDictLabel(purchaseTypeUnionList, dataForm.purchaseTypeUnion) || '-' }}</span>
</template>
<el-select
v-else
v-model="dataForm.purchaseTypeUnion"
placeholder="请选择采购方式"
clearable
:disabled="isView"
style="width: 100%">
<el-option
v-for="item in purchaseTypeUnionList"
@@ -394,29 +453,32 @@
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 金额>=30显示可行性论证报告和会议纪要 -->
<template v-if="dataForm.budget && dataForm.budget >= 300000">
<el-form-item
label="项目可行性论证报告"
prop="feasibilityReport"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('feasibility_report')"
:disabled="isView"
class="mb10">
下载项目可行性论证报告模板.doc
</el-button>
</template>
<upload-file
v-model="dataForm.feasibilityReport"
:limit="5"
:disabled="isView"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutes" class="mb20">
<el-form-item label="会议纪要" prop="meetingMinutes" :class="isView ? 'mb16' : 'mb20'">
<upload-file
v-model="dataForm.meetingMinutes"
:limit="5"
@@ -430,23 +492,24 @@
<el-form-item
label="单一来源论专家证附件"
prop="singleSourceProof"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('single_source')"
:disabled="isView"
class="mb10">
下载单一来源论专家证附件.docx
</el-button>
</template>
<upload-file
v-model="dataForm.singleSourceProof"
:limit="5"
:disabled="isView"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesSingle" class="mb20">
<el-form-item label="会议纪要" prop="meetingMinutesSingle" :class="isView ? 'mb16' : 'mb20'">
<upload-file
v-model="dataForm.meetingMinutesSingle"
:limit="5"
@@ -460,23 +523,24 @@
<el-form-item
label="进口产品申请及专家论证意见表"
prop="importApplication"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('import_application')"
:disabled="isView"
class="mb10">
下载进口产品申请及专家论证意见表.doc
</el-button>
</template>
<upload-file
v-model="dataForm.importApplication"
:limit="5"
:disabled="isView"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesImport" class="mb20">
<el-form-item label="会议纪要" prop="meetingMinutesImport" :class="isView ? 'mb16' : 'mb20'">
<upload-file
v-model="dataForm.meetingMinutesImport"
:limit="5"
@@ -486,16 +550,17 @@
</template>
<!-- 需求文件默认 -->
<el-form-item label="需求文件" prop="purchaseRequirement" class="mb20">
<el-form-item label="需求文件" prop="purchaseRequirement" :class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('purchase_requirement')"
:disabled="isView"
class="mb10">
下载采购需求填报模板模版
</el-button>
</template>
<upload-file
v-model="dataForm.purchaseRequirement"
:limit="5"
@@ -508,16 +573,17 @@
v-if="showAutoPublicSelect"
label="服务商城项目需求模板(公开比选)"
prop="servicePublicSelectSchool"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<template v-if="!isView">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
:disabled="isView"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
</template>
<upload-file
v-model="dataForm.servicePublicSelectSchool"
:limit="5"
@@ -530,7 +596,7 @@
v-if="dataForm.budget && dataForm.budget >= 1000000"
label="政府采购意向申请表"
prop="governmentPurchaseIntent"
class="mb20">
:class="isView ? 'mb16' : 'mb20'">
<upload-file
v-model="dataForm.governmentPurchaseIntent"
:limit="5"
@@ -540,11 +606,11 @@
</div>
</div>
<el-form-item label="备注" prop="remark" v-if="currentStep === 1">
<el-form-item label="备注" prop="remark" v-if="currentStep === 1 || isView">
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="3"
:rows="isView ? 2 : 3"
placeholder="请输入备注"
clearable
:disabled="isView" />
@@ -638,6 +704,19 @@ const dataForm = reactive({
governmentPurchaseIntent: '',
servicePublicSelectSchool: '',
});
// 定义 props
const props = defineProps<{
dictData?: {
fundSourceList?: any[];
isCentralizedList?: any[];
isSpecialList?: any[];
purchaseTypeDeptList?: any[];
purchaseModeSchoolList?: any[];
purchaseTypeUnionList?: any[];
categoryTreeData?: any[];
};
}>();
const categoryTreeData = ref<any[]>([]);
const categoryCodePath = ref<string[]>([]); // 级联选择器的路径数组
const selectedCategory = ref<any>(null);
@@ -669,6 +748,77 @@ const stepTwoTitle = computed(() => {
return isDeptPurchase.value ? '部门自行采购' : '学校统一采购';
});
// 获取字典项的label
const getDictLabel = (list: any[], value: string | number | null | undefined): string => {
if (!value || !list || list.length === 0) return '';
const item = list.find(item => item.value === value || item.id === value);
return item ? (item.label || item.dictLabel || item.name || '') : '';
};
// 获取品目编码的显示文本(用于查看模式)
const getCategoryDisplayText = (): string => {
if (!dataForm.categoryCode) return '-';
// 如果 categoryCodePath 已经有值,根据路径查找名称
if (categoryCodePath.value && categoryCodePath.value.length > 0) {
const names: string[] = [];
let currentData = categoryTreeData.value;
for (const code of categoryCodePath.value) {
const found = findCategoryByCode(currentData, code);
if (found) {
names.push(found.name || found.label || code);
currentData = found.children || [];
} else {
names.push(code);
}
}
return names.length > 0 ? names.join(' / ') : dataForm.categoryCode;
}
// 如果 categoryCodePath 没有值,尝试查找路径
if (categoryTreeData.value && categoryTreeData.value.length > 0) {
const path = findCategoryPath(categoryTreeData.value, dataForm.categoryCode);
if (path && path.length > 0) {
// 根据路径查找名称
const names: string[] = [];
let currentData = categoryTreeData.value;
for (const code of path) {
const found = findCategoryByCode(currentData, code);
if (found) {
names.push(found.name || found.label || code);
currentData = found.children || [];
} else {
names.push(code);
}
}
return names.length > 0 ? names.join(' / ') : dataForm.categoryCode;
}
}
return dataForm.categoryCode || '-';
};
// 根据 code 查找分类项
const findCategoryByCode = (data: any[], code: string): any => {
if (!data || !Array.isArray(data) || !code) {
return null;
}
for (const item of data) {
if (item && item.code === code) {
return item;
}
if (item && item.children && Array.isArray(item.children) && item.children.length > 0) {
const found = findCategoryByCode(item.children, code);
if (found) return found;
}
}
return null;
};
// 根据 code 查找完整路径(用于回显)
const findCategoryPath = (data: any[], targetCode: string, path: string[] = []): string[] | null => {
for (const item of data) {
@@ -929,6 +1079,17 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
servicePublicSelectSchool: '',
});
// 如果通过 props 传递了字典数据,直接使用;否则调用接口获取
if (props.dictData) {
fundSourceList.value = props.dictData.fundSourceList || [];
isCentralizedList.value = props.dictData.isCentralizedList || [];
isSpecialList.value = props.dictData.isSpecialList || [];
purchaseTypeDeptList.value = props.dictData.purchaseTypeDeptList || [];
purchaseModeSchoolList.value = props.dictData.purchaseModeSchoolList || [];
purchaseTypeUnionList.value = props.dictData.purchaseTypeUnionList || [];
categoryTreeData.value = props.dictData.categoryTreeData || [];
} else {
// 如果没有传递字典数据,则调用接口获取(兼容性处理)
await Promise.all([
getCategoryTreeData(),
getFundSourceDict(),
@@ -938,6 +1099,7 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
getPurchaseModeSchoolDict(),
getPurchaseTypeUnionDict(),
]);
}
nextTick(() => {
formRef.value?.resetFields();
@@ -946,11 +1108,16 @@ const openDialog = async (type: 'add' | 'edit' | 'view', rowData?: any) => {
getObj(rowData.id)
.then((res) => {
Object.assign(dataForm, res.data || {});
// 设置品目编码回显路径
// 设置品目编码回显路径 - 使用 nextTick 确保 categoryTreeData 已经设置
if (dataForm.categoryCode) {
nextTick(() => {
setCategoryCodePath();
});
}
if (type === 'edit' || type === 'view') {
if (type === 'edit') {
currentStep.value = 1;
} else if (type === 'view') {
// 查看模式下直接显示所有内容,不需要步骤
currentStep.value = 1;
}
})
@@ -1252,11 +1419,20 @@ const handleTempStore = async () => {
};
// 监听 categoryTreeData 变化,设置回显路径
watch(() => categoryTreeData.value, () => {
if (dataForm.categoryCode) {
watch(() => categoryTreeData.value, (newVal) => {
if (newVal && newVal.length > 0 && dataForm.categoryCode) {
setCategoryCodePath();
}
}, { deep: true });
}, { deep: true, immediate: false });
// 监听 dataForm.categoryCode 变化,设置回显路径(用于查看模式)
watch(() => dataForm.categoryCode, (newVal) => {
if (newVal && categoryTreeData.value && categoryTreeData.value.length > 0) {
nextTick(() => {
setCategoryCodePath();
});
}
});
// 暴露变量
defineExpose({
@@ -1268,6 +1444,9 @@ defineExpose({
.mb20 {
margin-bottom: 20px;
}
.mb16 {
margin-bottom: 16px;
}
.mb10 {
margin-bottom: 10px;
}
@@ -1285,4 +1464,57 @@ defineExpose({
margin-top: 5px;
color: var(--el-text-color-secondary);
}
/* 查看模式优化样式 */
:deep(.view-dialog) {
.el-dialog__body {
max-height: calc(100vh - 150px);
overflow-y: auto;
overflow-x: hidden;
padding: 20px;
}
}
.view-content {
max-height: calc(100vh - 200px);
overflow-y: auto;
overflow-x: hidden;
}
.view-form {
/* 查看模式下使用更紧凑的布局 */
}
.view-form :deep(.el-form-item) {
margin-bottom: 16px;
}
.view-form :deep(.el-form-item__label) {
font-weight: 500;
color: #606266;
}
/* 查看模式文本样式 */
.view-text {
color: #303133;
font-size: 14px;
line-height: 1.5;
word-break: break-word;
}
.view-textarea {
white-space: pre-wrap;
min-height: 40px;
padding: 8px 0;
}
/* 查看模式下两列布局优化 */
.view-form :deep(.el-row) {
margin-bottom: 0;
}
.view-form :deep(.el-col) {
margin-bottom: 16px;
}
</style>

View File

@@ -102,16 +102,10 @@
<el-icon><List /></el-icon>
</template>
</el-table-column>
<el-table-column prop="code" label="编号" min-width="120" show-overflow-tooltip>
<el-table-column prop="code" label="申请单编号" min-width="140" show-overflow-tooltip>
<template #header>
<el-icon><DocumentCopy /></el-icon>
<span style="margin-left: 4px">编号</span>
</template>
</el-table-column>
<el-table-column prop="purchaseNo" label="采购编号" min-width="120" show-overflow-tooltip>
<template #header>
<el-icon><DocumentCopy /></el-icon>
<span style="margin-left: 4px">采购编号</span>
<span style="margin-left: 4px">申请单编号</span>
</template>
</el-table-column>
<el-table-column prop="projectName" label="采购项目名称" min-width="200" show-overflow-tooltip>
@@ -120,27 +114,57 @@
<span style="margin-left: 4px">采购项目名称</span>
</template>
</el-table-column>
<el-table-column prop="projectType" label="项目类别" width="100" align="center">
<el-table-column prop="applyDate" label="填报日期" width="120" align="center" show-overflow-tooltip>
<template #header>
<el-icon><Calendar /></el-icon>
<span style="margin-left: 4px">填报日期</span>
</template>
</el-table-column>
<el-table-column prop="deptName" label="需求部门" min-width="150" show-overflow-tooltip>
<template #header>
<el-icon><OfficeBuilding /></el-icon>
<span style="margin-left: 4px">需求部门</span>
</template>
</el-table-column>
<el-table-column prop="projectType" label="项目类别" min-width="200" align="left" show-overflow-tooltip>
<template #header>
<el-icon><Collection /></el-icon>
<span style="margin-left: 4px">项目类别</span>
</template>
<template #default="scope">
<el-tag v-if="scope.row.projectType === 'A'" type="success">货物</el-tag>
<el-tag v-else-if="scope.row.projectType === 'B'" type="warning">工程</el-tag>
<el-tag v-else-if="scope.row.projectType === 'C'" type="info">服务</el-tag>
<span v-else>-</span>
<div>
<el-tag v-if="scope.row.projectType === 'A'" type="success" style="margin-right: 8px;">货物</el-tag>
<el-tag v-else-if="scope.row.projectType === 'B'" type="warning" style="margin-right: 8px;">工程</el-tag>
<el-tag v-else-if="scope.row.projectType === 'C'" type="info" style="margin-right: 8px;">服务</el-tag>
<span v-if="scope.row.categoryName" style="color: #606266; font-size: 12px;">
{{ scope.row.categoryName }}
</span>
<span v-else-if="scope.row.categoryCode" style="color: #909399; font-size: 12px;">
{{ scope.row.categoryCode }}
</span>
</div>
</template>
</el-table-column>
<el-table-column prop="budget" label="预算金额(元)" width="120" align="right">
<el-table-column prop="budget" label="项目预算(元)" width="130" align="right">
<template #header>
<el-icon><Money /></el-icon>
<span style="margin-left: 4px">预算金额</span>
<span style="margin-left: 4px">项目预算</span>
</template>
<template #default="scope">
{{ scope.row.budget ? Number(scope.row.budget).toLocaleString() : '-' }}
</template>
</el-table-column>
<el-table-column prop="isSpecial" label="是否特殊" width="100" align="center">
<template #header>
<el-icon><Warning /></el-icon>
<span style="margin-left: 4px">是否特殊</span>
</template>
<template #default="scope">
<el-tag v-if="scope.row.isSpecial === '1' || scope.row.isSpecial === 1" type="warning"></el-tag>
<el-tag v-else-if="scope.row.isSpecial === '0' || scope.row.isSpecial === 0" type="info"></el-tag>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="isCentralized" label="是否集采" width="100" align="center">
<template #header>
<el-icon><CircleCheck /></el-icon>
@@ -152,10 +176,10 @@
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<el-table-column prop="status" label="审核状态" width="100" align="center">
<template #header>
<el-icon><InfoFilled /></el-icon>
<span style="margin-left: 4px">状态</span>
<span style="margin-left: 4px">审核状态</span>
</template>
<template #default="scope">
<el-tag v-if="scope.row.status === '-2'" type="info">撤回</el-tag>
@@ -167,13 +191,7 @@
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180" show-overflow-tooltip>
<template #header>
<el-icon><Clock /></el-icon>
<span style="margin-left: 4px">创建时间</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" width="200">
<el-table-column label="操作" align="center" fixed="right" width="300">
<template #default="scope">
<el-button
icon="View"
@@ -204,10 +222,10 @@
<!-- 分页 -->
<pagination
v-show="state.total > 0"
:total="state.total"
v-model:page="state.page"
v-model:limit="state.limit"
v-if="state.pagination && state.pagination.total && state.pagination.total > 0"
:total="state.pagination.total"
:current="state.pagination.current"
:size="state.pagination.size"
@pagination="getDataList"
/>
</el-card>
@@ -217,7 +235,8 @@
<el-dialog
v-model="showAddIframe"
title="新增采购申请"
width="1000px"
width="90%"
:style="{ maxWidth: '1600px' }"
:close-on-click-modal="false"
:close-on-press-escape="true"
destroy-on-close
@@ -229,26 +248,42 @@
:src="addIframeSrc"
frameborder="0"
class="add-iframe"
@load="onIframeLoad" />
/>
</div>
</el-dialog>
<!-- 编辑新增表单对话框 -->
<FormDialog ref="formDialogRef" @refresh="getDataList" />
<FormDialog
ref="formDialogRef"
:dict-data="dictData"
@refresh="getDataList" />
</div>
</template>
<script setup lang="ts" name="PurchasingRequisition">
import { ref, reactive, defineAsyncComponent, onUnmounted } from 'vue'
import { ref, reactive, defineAsyncComponent, onUnmounted, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { BasicTableProps, useTable } from "/@/hooks/table";
import { getPage, delObj } from "/@/api/finance/purchasingrequisition";
import { useMessage, useMessageBox } from "/@/hooks/message";
import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Clock } from '@element-plus/icons-vue'
import { getDicts } from '/@/api/admin/dict';
import { getTree } from '/@/api/finance/purchasingcategory';
import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning } from '@element-plus/icons-vue'
// 引入组件
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
// 字典数据和品目树数据
const dictData = ref({
fundSourceList: [] as any[],
isCentralizedList: [] as any[],
isSpecialList: [] as any[],
purchaseTypeDeptList: [] as any[],
purchaseModeSchoolList: [] as any[],
purchaseTypeUnionList: [] as any[],
categoryTreeData: [] as any[],
});
// 定义变量内容
const router = useRouter()
const tableRef = ref()
@@ -332,11 +367,7 @@ const handleIframeMessage = (event: MessageEvent) => {
*/
const handleDelete = async (row: any) => {
try {
await useMessageBox().confirm('确定要删除该记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
await useMessageBox().confirm('确定要删除该记录吗?');
} catch {
return;
}
@@ -350,6 +381,151 @@ const handleDelete = async (row: any) => {
}
};
// 获取字典数据和品目树数据
const loadDictData = async () => {
try {
const [
fundSourceRes,
isCentralizedRes,
isSpecialRes,
purchaseTypeDeptRes,
purchaseModeSchoolRes,
purchaseTypeUnionRes,
categoryTreeRes
] = await Promise.all([
getDicts('PURCHASE_FUND_SOURCE'),
getDicts('PURCHASE_IS_CEN'),
getDicts('PURCHASE_IS_SPEC'),
getDicts('PURCHASE_TYPE_DEPT'),
getDicts('PURCHASE_MODE_SCHOOL'),
getDicts('PURCHASE_TYPE_UNION'),
getTree()
]);
// 处理资金来源字典
if (fundSourceRes.data && Array.isArray(fundSourceRes.data)) {
dictData.value.fundSourceList = fundSourceRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
dictData.value.fundSourceList = [
{ label: '切块经费', value: '0' },
{ label: '设备购置费', value: '1' },
{ label: '专项经费', value: '2' },
{ label: '代办费', value: '3' },
{ label: '培训经费', value: '4' },
{ label: '日常公用经费', value: '5' },
{ label: '技能大赛经费', value: '6' },
{ label: '基本建设资金', value: '7' },
{ label: '暂存款', value: '8' },
{ label: '会议费', value: '9' },
];
}
// 处理是否集采字典
if (isCentralizedRes.data && Array.isArray(isCentralizedRes.data)) {
dictData.value.isCentralizedList = isCentralizedRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
dictData.value.isCentralizedList = [
{ label: '否', value: '0' },
{ label: '政府集中采购', value: '1' },
{ label: '学校集中采购', value: '2' }
];
}
// 处理是否特殊情况字典
if (isSpecialRes.data && Array.isArray(isSpecialRes.data)) {
dictData.value.isSpecialList = isSpecialRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
dictData.value.isSpecialList = [
{ label: '否', value: '0' },
{ label: '紧急', value: '1' },
{ label: '单一', value: '2' },
{ label: '进口', value: '3' }
];
}
// 处理部门采购方式字典
if (purchaseTypeDeptRes.data && Array.isArray(purchaseTypeDeptRes.data)) {
dictData.value.purchaseTypeDeptList = purchaseTypeDeptRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
}
// 处理学校采购形式字典
if (purchaseModeSchoolRes.data && Array.isArray(purchaseModeSchoolRes.data)) {
dictData.value.purchaseModeSchoolList = purchaseModeSchoolRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
dictData.value.purchaseModeSchoolList = [
{ label: '政府采购', value: '1' },
{ label: '学校自主采购', value: '2' }
];
}
// 处理学校统一采购方式字典
if (purchaseTypeUnionRes.data && Array.isArray(purchaseTypeUnionRes.data)) {
dictData.value.purchaseTypeUnionList = purchaseTypeUnionRes.data.map((item: any) => ({
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
}
// 处理品目树数据
if (categoryTreeRes.data && Array.isArray(categoryTreeRes.data)) {
dictData.value.categoryTreeData = categoryTreeRes.data;
} else {
dictData.value.categoryTreeData = [];
}
} catch (err) {
console.error('加载字典数据失败', err);
// 设置默认值
dictData.value.fundSourceList = [
{ label: '切块经费', value: '0' },
{ label: '设备购置费', value: '1' },
{ label: '专项经费', value: '2' },
{ label: '代办费', value: '3' },
{ label: '培训经费', value: '4' },
{ label: '日常公用经费', value: '5' },
{ label: '技能大赛经费', value: '6' },
{ label: '基本建设资金', value: '7' },
{ label: '暂存款', value: '8' },
{ label: '会议费', value: '9' },
];
dictData.value.isCentralizedList = [
{ label: '否', value: '0' },
{ label: '政府集中采购', value: '1' },
{ label: '学校集中采购', value: '2' }
];
dictData.value.isSpecialList = [
{ label: '否', value: '0' },
{ label: '紧急', value: '1' },
{ label: '单一', value: '2' },
{ label: '进口', value: '3' }
];
dictData.value.purchaseModeSchoolList = [
{ label: '政府采购', value: '1' },
{ label: '学校自主采购', value: '2' }
];
dictData.value.categoryTreeData = [];
}
};
// 页面加载时获取字典数据和品目树数据
onMounted(() => {
loadDictData();
});
// 组件卸载时清理事件监听器
onUnmounted(() => {
window.removeEventListener('message', handleIframeMessage)