Files
school-developer/src/views/finance/purchasingrequisition/add.vue
2026-02-03 11:31:19 +08:00

1731 lines
68 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="modern-page-container">
<div class="page-wrapper">
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Document /></el-icon>
新增采购申请
</span>
</div>
</template>
<div v-loading="loading" style="padding-bottom: 20px;">
<!-- 步骤条 -->
<!-- <el-steps :active="currentStep" finish-status="success" style="margin-bottom: 30px;">
<el-step title="基本信息" />
<el-step :title="stepTwoTitle" />
</el-steps> -->
<el-form
ref="formRef"
:model="dataForm"
:rules="dataRules"
label-width="140px">
<!-- 第一步基本信息 -->
<div v-show="currentStep === 0">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="采购项目名称" prop="projectName">
<el-input
v-model="dataForm.projectName"
placeholder="请输入采购项目名称"
clearable />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="填报日期" prop="applyDate">
<el-date-picker
v-model="dataForm.applyDate"
type="date"
placeholder="请选择填报日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="资金来源" prop="fundSource">
<el-select
v-model="dataForm.fundSource"
placeholder="请选择资金来源"
clearable
style="width: 100%">
<el-option
v-for="item in fundSourceList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="预算金额(元)" prop="budget">
<el-input-number
v-model="dataForm.budget"
:min="0.01"
:precision="2"
placeholder="请输入预算金额"
style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="是否集采" prop="isCentralized">
<el-select
v-model="dataForm.isCentralized"
placeholder="请选择是否集采"
clearable
style="width: 100%">
<el-option
v-for="item in isCentralizedList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="是否特殊情况" prop="isSpecial">
<el-select
v-model="dataForm.isSpecial"
placeholder="请选择是否特殊情况"
clearable
style="width: 100%">
<el-option
v-for="item in isSpecialList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-form-item label="品目编码" prop="categoryCode">
<el-cascader
v-model="categoryCodePath"
:options="categoryTreeData"
:props="{ value: 'code', label: 'name', children: 'children', checkStrictly: true }"
placeholder="请选择品目编码"
clearable
filterable
:show-all-levels="true"
style="width: 100%"
@change="handleCategoryChange" />
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 第二步采购详情 -->
<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">
<el-input
v-model="dataForm.projectContent"
type="textarea"
:rows="4"
:maxlength="1000"
show-word-limit
placeholder="请输入采购内容限制1000字"
clearable />
</el-form-item>
<el-form-item label="采购方式" prop="purchaseType" class="mb20">
<el-select
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
clearable
:disabled="isAutoSelectPurchaseType"
style="width: 100%">
<el-option
v-for="item in purchaseTypeDeptList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<!-- 商务洽谈 -->
<el-form-item
v-if="isPurchaseType(PURCHASE_TYPE_IDS.BUSINESS_NEGOTIATION)"
label="商务洽谈表"
prop="businessNegotiationTable"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('business_negotiation')"
class="mb10">
下载商务洽谈表模版
</el-button>
<upload-file
v-model="dataForm.businessNegotiationTable"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.businessNegotiationTable }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 市场采购 -->
<el-form-item
v-if="isPurchaseType(PURCHASE_TYPE_IDS.MARKET_PURCHASE)"
label="市场采购纪要"
prop="marketPurchaseMinutes"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('market_purchase_minutes')"
class="mb10">
下载市场采购纪要模版
</el-button>
<upload-file
v-model="dataForm.marketPurchaseMinutes"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.marketPurchaseMinutes }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 网上商城 -->
<el-form-item
v-if="isPurchaseType(PURCHASE_TYPE_IDS.ONLINE_MALL)"
label="网上商城采购相关材料"
prop="onlineMallMaterials"
class="mb20">
<upload-file
v-model="dataForm.onlineMallMaterials"
:limit="1"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.onlineMallMaterials }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 委托采购中心 -->
<template v-if="isPurchaseType(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>
<el-radio label="other">其他方式</el-radio>
</el-radio-group>
</el-form-item>
<!-- 服务类网上商城判断品目编码的第一个值是否为C -->
<template v-if="dataForm.entrustCenterType === 'service_online' && categoryCodePath && categoryCodePath.length > 0 && categoryCodePath[0] === 'C'">
<el-form-item label="是否有供应商" prop="hasSupplier" class="mb20">
<el-radio-group v-model="dataForm.hasSupplier">
<el-radio label="yes"></el-radio>
<el-radio label="no"></el-radio>
</el-radio-group>
</el-form-item>
<!-- 有供应商显示供应商名称输入框 -->
<template v-if="dataForm.hasSupplier === 'yes'">
<el-form-item
label="供应商名称"
prop="suppliers"
class="mb20">
<el-input
v-model="dataForm.suppliers"
type="textarea"
:rows="3"
placeholder="请输入供应商名称,多个供应商请用逗号或分号分隔"
maxlength="500"
show-word-limit />
<div class="template-note mt5">
<el-text type="info" size="small">多个供应商请用逗号,或分号;分隔</el-text>
</div>
</el-form-item>
<el-form-item
label="服务商城项目需求模板(直选)"
prop="serviceDirectSelect"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('direct_select')"
class="mb10">
下载服务商城项目需求模板直选模版
</el-button>
<upload-file
v-model="dataForm.serviceDirectSelect"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.serviceDirectSelect }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<el-form-item
v-if="dataForm.hasSupplier === 'no'"
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"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 其他方式货物类 -->
<el-form-item
v-if="dataForm.entrustCenterType === 'other' && categoryCodePath && categoryCodePath[0] === 'A'"
label="采购需求填报模板"
prop="purchaseRequirementTemplate"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('purchase_requirement')"
class="mb10">
下载表1采购需求填报模板模版
</el-button>
<upload-file
v-model="dataForm.purchaseRequirementTemplate"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirementTemplate }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊规则5<=金额<40万服务类目自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelect">
<el-form-item label="是否有推荐供应商" prop="hasRecommendedSupplier" class="mb20">
<el-radio-group v-model="dataForm.hasRecommendedSupplier">
<el-radio label="yes"></el-radio>
<el-radio label="no"></el-radio>
</el-radio-group>
</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"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 无推荐供应商显示公开比选模板 -->
<el-form-item
v-if="dataForm.hasRecommendedSupplier === 'no'"
label="服务商城项目需求模板(公开比选)"
prop="servicePublicSelectAuto"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
<upload-file
v-model="dataForm.servicePublicSelectAuto"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectAuto }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 其他材料zip压缩包 -->
<el-form-item label="其他材料" prop="otherMaterials" class="mb20">
<upload-file
v-model="dataForm.otherMaterials"
:limit="5"
:file-type="['zip']"
:data="{ fileType: FILE_TYPE_MAP.otherMaterials }"
upload-file-url="/purchase/purchasingfiles/upload" />
<div class="template-note">支持上传zip格式的压缩包文件</div>
</el-form-item>
</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
v-for="item in purchaseModeSchoolList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="采购方式" prop="purchaseTypeUnion" class="mb20">
<el-select
v-model="dataForm.purchaseTypeUnion"
placeholder="请选择采购方式"
clearable
:disabled="isAutoSelectPurchaseTypeUnion"
style="width: 100%">
<el-option
v-for="item in purchaseTypeUnionList"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<!-- 业务分管处室 -->
<el-form-item label="业务分管处室" prop="deptClassifyId" class="mb20">
<el-select
v-model="dataForm.deptClassifyId"
placeholder="请选择业务分管处室"
clearable
filterable
@change="handleBusinessDeptChange"
style="width: 100%">
<el-option
v-for="item in businessDeptList"
:key="item.id"
:label="item.deptName"
:value="item.id" />
</el-select>
</el-form-item>
<!-- 分管校领导 -->
<el-form-item label="分管校领导" prop="schoolLeaderUserId" class="mb20">
<el-select
v-model="dataForm.schoolLeaderUserId"
placeholder="请选择分管校领导"
clearable
filterable
@change="handleSchoolLeaderChange"
style="width: 100%">
<el-option
v-for="item in schoolLeaderList"
:key="item.id"
:label="item.name"
:value="item.userId" />
</el-select>
</el-form-item>
<!-- 金额>=30显示可行性论证报告和会议纪要 -->
<template v-if="dataForm.budget && dataForm.budget >= 300000">
<el-form-item
label="项目可行性论证报告"
prop="feasibilityReport"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('feasibility_report')"
class="mb10">
下载项目可行性论证报告模板.doc
</el-button>
<upload-file
v-model="dataForm.feasibilityReport"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.feasibilityReport }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutes" class="mb20">
<upload-file
v-model="dataForm.meetingMinutes"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊情况紧急 -->
<template v-if="isUrgentSpecial">
<el-form-item label="会议纪要" prop="meetingMinutesUrgent" class="mb20">
<upload-file
v-model="dataForm.meetingMinutesUrgent"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesUrgent }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊情况单一来源 -->
<template v-if="isSpecialType('2')">
<el-form-item
label="单一来源论专家证附件"
prop="singleSourceProof"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('single_source')"
class="mb10">
下载单一来源论专家证附件.docx
</el-button>
<upload-file
v-model="dataForm.singleSourceProof"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.singleSourceProof }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesSingle" class="mb20">
<upload-file
v-model="dataForm.meetingMinutesSingle"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊情况进口 -->
<template v-if="isSpecialType('3')">
<el-form-item
label="进口产品申请及专家论证意见表"
prop="importApplication"
class="mb20">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('import_application')"
class="mb10">
下载进口产品申请及专家论证意见表.doc
</el-button>
<upload-file
v-model="dataForm.importApplication"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.importApplication }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<el-form-item label="会议纪要" prop="meetingMinutesImport" class="mb20">
<upload-file
v-model="dataForm.meetingMinutesImport"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
</template>
<!-- 特殊规则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>
<!-- 有推荐供应商显示推荐供应商输入框 -->
<el-form-item
v-if="dataForm.hasRecommendedSupplierSchool === 'yes'"
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>
</template>
<!-- 需求文件 -->
<el-form-item label="需求文件" :prop="getRequirementFileProp()" class="mb20">
<!-- 特殊规则5<=金额<40万服务类目isMallService=1isProjectService=1自动使用邀请比选模版 -->
<template v-if="showAutoInviteSelectSchool">
<!-- 有推荐供应商显示邀请比选模板 -->
<template v-if="dataForm.hasRecommendedSupplierSchool === 'yes'">
<div class="mb10">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('invite_select')"
class="mb10">
下载服务商城项目需求模板邀请比选模版
</el-button>
</div>
<upload-file
v-model="dataForm.serviceInviteSelectSchool"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelectSchool }"
upload-file-url="/purchase/purchasingfiles/upload" />
</template>
<!-- 无推荐供应商显示公开比选模板 -->
<template v-else-if="dataForm.hasRecommendedSupplierSchool === 'no'">
<div class="mb10">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
</div>
<upload-file
v-model="dataForm.servicePublicSelectSchoolAuto"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchoolAuto }"
upload-file-url="/purchase/purchasingfiles/upload" />
</template>
</template>
<!-- 特殊规则40<=金额<100万服务类目自动使用公开比选需求模版 -->
<template v-else-if="showAutoPublicSelect">
<div class="mb10">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('public_select')"
class="mb10">
下载服务商城项目需求模板公开比选模版
</el-button>
</div>
<upload-file
v-model="dataForm.servicePublicSelectSchool"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchool }"
upload-file-url="/purchase/purchasingfiles/upload" />
</template>
<!-- 默认采购需求填报模板 -->
<template v-else>
<div class="mb10">
<el-button
type="primary"
link
icon="Download"
@click="downloadTemplate('purchase_requirement')"
class="mb10">
下载采购需求填报模板模版
</el-button>
</div>
<upload-file
v-model="dataForm.purchaseRequirement"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirement }"
upload-file-url="/purchase/purchasingfiles/upload" />
</template>
</el-form-item>
<!-- 金额>=100政府采购意向表 -->
<el-form-item
v-if="dataForm.budget && dataForm.budget >= 1000000"
label="政府采购意向申请表"
prop="governmentPurchaseIntent"
class="mb20">
<upload-file
v-model="dataForm.governmentPurchaseIntent"
:limit="5"
:file-type="['doc', 'docx', 'pdf']"
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
upload-file-url="/purchase/purchasingfiles/upload" />
</el-form-item>
<!-- 其他材料zip压缩包 -->
<el-form-item label="其他材料" prop="otherMaterials" class="mb20">
<upload-file
v-model="dataForm.otherMaterials"
:limit="5"
:file-type="['zip']"
:data="{ fileType: FILE_TYPE_MAP.otherMaterials }"
upload-file-url="/purchase/purchasingfiles/upload" />
<div class="template-note">支持上传zip格式的压缩包文件</div>
</el-form-item>
</div>
</div>
<el-form-item label="备注" prop="remark" v-if="currentStep === 1">
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="3"
placeholder="请输入备注"
clearable />
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="form-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button v-if="currentStep > 0" @click="prevStep">上一步</el-button>
<el-button
v-if="currentStep < 1"
type="primary"
@click="nextStep"
:disabled="loading">
下一步
</el-button>
<el-button
v-if="currentStep === 1"
type="warning"
@click="handleTempStore"
:disabled="loading">
暂存
</el-button>
<el-button
v-if="currentStep === 1"
type="primary"
@click="handleSubmit"
:disabled="loading">
提交
</el-button>
</div>
</div>
</el-card>
</div>
</div>
</template>
<script setup lang="ts" name="PurchasingRequisitionAdd">
import { reactive, ref, onMounted, computed, watch, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { addObj, tempStore } from '/@/api/finance/purchasingrequisition';
import { getTree } from '/@/api/finance/purchasingcategory';
import { getDicts } from '/@/api/admin/dict';
import { useMessage } from '/@/hooks/message';
import UploadFile from '/@/components/Upload/index.vue';
import other from '/@/utils/other';
import { Document, Download } from '@element-plus/icons-vue';
import { fetchList as getBusinessDeptList } from '/@/api/purchase/purchasingBusinessDept';
import { getPage as getSchoolLeaderPage } from '/@/api/finance/purchasingschoolleader';
// 路由
const router = useRouter();
// 定义变量内容
const formRef = ref();
const currentStep = ref(0);
const dataForm = reactive({
id: '',
projectName: '',
projectType: '',
projectContent: '',
applyDate: '',
fundSource: '',
budget: null as number | null,
isCentralized: '',
isSpecial: '',
purchaseMode: '',
purchaseType: '',
purchaseTypeUnion: '',
categoryCode: '',
remark: '',
status: '',
// 部门自行采购字段
businessNegotiationTable: '',
marketPurchaseMinutes: '',
onlineMallMaterials: '',
entrustCenterType: '',
hasSupplier: '',
suppliers: '', // 供应商名称(逗号或分号分隔)
serviceDirectSelect: '',
servicePublicSelect: '',
purchaseRequirementTemplate: '',
hasRecommendedSupplier: '',
recommendedSuppliers: '',
serviceInviteSelect: '',
servicePublicSelectAuto: '',
// 学校统一采购字段
purchaseRequirement: '',
meetingMinutes: '',
feasibilityReport: '',
meetingMinutesUrgent: '',
meetingMinutesSingle: '',
meetingMinutesImport: '',
singleSourceProof: '',
importApplication: '',
governmentPurchaseIntent: '',
servicePublicSelectSchool: '',
// 学校统一采购特殊规则字段5万<=金额<40万
hasRecommendedSupplierSchool: '',
recommendedSuppliersSchool: '',
serviceInviteSelectSchool: '',
servicePublicSelectSchoolAuto: '',
// 业务分管处室和分管校领导
deptClassifyId: '',
deptClassifyName: '',
schoolLeaderUserId: '',
schoolLeaderName: '',
// 其他材料zip压缩包
otherMaterials: '',
});
const categoryTreeData = ref<any[]>([]);
const categoryCodePath = ref<string[]>([]); // 级联选择器的路径数组
const fundSourceList = ref<any[]>([]);
const isCentralizedList = ref<any[]>([]);
const isSpecialList = ref<any[]>([]);
const purchaseTypeDeptList = ref<any[]>([]);
const purchaseModeSchoolList = ref<any[]>([]);
const purchaseTypeUnionList = ref<any[]>([]);
const businessDeptList = ref<any[]>([]);
const schoolLeaderList = ref<any[]>([]);
const loading = ref(false);
// 采购方式ID常量
const PURCHASE_TYPE_IDS = {
BUSINESS_NEGOTIATION: '77b429c146fc9e12ba4c5573da19ad70', // 商务洽谈
MARKET_PURCHASE: 'd522054027140e4d76e074cd96ecfc12', // 市场采购
ONLINE_MALL: 'e8723b4e3c3d51deb54f9349482ea894', // 网上商城
ENTRUST_CENTER: '981bf052a0b30b028a4a89ae490c9b1d' // 委托采购中心
};
// 文件类型映射(对应数据库 file_type 字段)
// 10:商务洽谈纪要 20:市场采购纪要 30:网上商城采购相关材料 40:可行性论证报告 50:会议记录 60:其他材料 70:单一来源专家论证表 80:进口产品申请表 90:进口产品专家论证表 100:政府采购意向表 110:履约验收单
const FILE_TYPE_MAP: Record<string, string> = {
businessNegotiationTable: '10', // 商务洽谈纪要
marketPurchaseMinutes: '20', // 市场采购纪要
onlineMallMaterials: '30', // 网上商城采购相关材料
feasibilityReport: '40', // 可行性论证报告
meetingMinutes: '50', // 会议记录
meetingMinutesUrgent: '50', // 会议记录
meetingMinutesSingle: '50', // 会议记录
meetingMinutesImport: '50', // 会议记录
otherMaterials: '60', // 其他材料
singleSourceProof: '70', // 单一来源专家论证表
importApplication: '80', // 进口产品申请表
governmentPurchaseIntent: '100', // 政府采购意向表
// 需求文件相关(暂时使用默认值,可根据实际需求调整)
serviceDirectSelect: '30', // 服务商城项目需求模板(直选)- 归类到网上商城采购相关材料
serviceInviteSelect: '30', // 服务商城项目需求模板(邀请比选)
servicePublicSelect: '30', // 服务商城项目需求模板(公开比选)
servicePublicSelectAuto: '30', // 服务商城项目需求模板(公开比选-自动)
purchaseRequirementTemplate: '30', // 采购需求填报模板
purchaseRequirement: '30', // 采购需求填报模板
serviceInviteSelectSchool: '30', // 服务商城项目需求模板(邀请比选-学校)
servicePublicSelectSchoolAuto: '30', // 服务商城项目需求模板(公开比选-学校-自动)
servicePublicSelectSchool: '30', // 服务商城项目需求模板(公开比选-学校)
};
// 辅助函数:判断当前采购方式是否为指定类型(通过 id 或 value 匹配)
const isPurchaseType = (purchaseTypeId: string) => {
if (!dataForm.purchaseType) return false;
// 在字典中查找匹配的项
const item = purchaseTypeDeptList.value.find(item =>
item.id === purchaseTypeId || item.value === purchaseTypeId
);
if (item) {
return dataForm.purchaseType === item.value;
}
// 如果字典中找不到,直接比较 value兼容性处理
return dataForm.purchaseType === purchaseTypeId;
};
// 辅助函数:判断特殊情况是否为指定类型(通过 id 或 value 匹配)
const isSpecialType = (specialIdOrValue: string) => {
if (!dataForm.isSpecial) return false;
// 在字典中查找匹配的项
const item = isSpecialList.value.find(item =>
item.id === specialIdOrValue || item.value === specialIdOrValue
);
if (item) {
return dataForm.isSpecial === item.value;
}
// 如果字典中找不到,直接比较 value兼容性处理
return dataForm.isSpecial === specialIdOrValue;
};
// 判断是否为部门自行采购
// 条件:特殊情况=否 且 集采=否 且 预算金额<5万 → 部门自行采购
// 其他情况 → 学校统一采购
const isDeptPurchase = computed(() => {
// 检查是否特殊情况是否为"否"(通过 id 或 value 查找value 为 '0'
const isSpecialNo = isSpecialList.value.find(item =>
item.id === '1799c07f3a3b8a484f60c495ab9227b6' || item.value === '0'
);
const isSpecialNoValue = isSpecialNo ? isSpecialNo.value : null;
// 检查是否集采是否为"否"(通过 id 或 value 查找value 为 '0'
const isCentralizedNo = isCentralizedList.value.find(item =>
item.id === '8e60f8860c1ea2459a41a8ae64fe5518' || item.value === '0'
);
const isCentralizedNoValue = isCentralizedNo ? isCentralizedNo.value : null;
// 三个条件必须同时满足:特殊情况=否 且 集采=否 且 预算金额<5万
if (isSpecialNoValue && isCentralizedNoValue &&
dataForm.isSpecial === isSpecialNoValue &&
dataForm.isCentralized === isCentralizedNoValue &&
dataForm.budget && dataForm.budget < 50000) {
return true;
}
return false;
});
// 判断是否为紧急情况(通过 id 或 value 查找value 为 '1'
const isUrgentSpecial = computed(() => {
const urgentItem = isSpecialList.value.find(item =>
item.id === '6509b59e24c1c6568f4277e544f3e55e' ||
(item.value === '1' && (item.label?.includes('紧急') || item.dictLabel?.includes('紧急')))
);
if (!urgentItem) return false;
return dataForm.isSpecial === urgentItem.value;
});
// 第二步标题
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) {
return null;
}
const findCategory = (data: any[], code: string): any => {
for (const item of data) {
if (item.code === code) {
return item;
}
if (item.children && item.children.length > 0) {
const found = findCategory(item.children, code);
if (found) return found;
}
}
return null;
};
return findCategory(categoryTreeData.value, dataForm.categoryCode);
};
// 判断是否为服务类
const isServiceCategory = computed(() => {
// 通过 categoryCodePath 判断:第一个字符为 'C' 表示服务类
if (categoryCodePath.value && categoryCodePath.value.length > 0) {
return categoryCodePath.value[0] === 'C';
}
// 备用判断:通过 category 对象判断
const category = getCategoryInfo();
if (!category) return false;
return category.type === 'C' || category.projectType === 'C';
});
// 判断是否为货物类
const isGoodsCategory = computed(() => {
const category = getCategoryInfo();
if (!category) return false;
return category.type === 'A' || category.projectType === 'A';
});
// 判断是否为特殊服务类目isMallService=1、isProjectService=1
const isSpecialServiceCategory = computed(() => {
const category = getCategoryInfo();
if (!category) return false;
return Number(category.isMallService) === 1 || Number(category.isProjectService) === 1;
});
// 判断是否自动选择网上商城采购方式5万<=金额<40万服务类目特殊服务类目
const isAutoSelectPurchaseType = computed(() => {
if (!dataForm.budget) return false;
const budget = dataForm.budget;
return budget >= 50000 && budget < 400000 && isServiceCategory.value && isSpecialServiceCategory.value;
});
// 判断是否显示自动邀请比选模版5万<=金额<40万服务类目特殊服务类目
const showAutoInviteSelect = computed(() => {
if (!isDeptPurchase.value) return false;
if (!dataForm.budget) return false;
const budget = dataForm.budget;
return budget >= 50000 && budget < 400000 && isServiceCategory.value && isSpecialServiceCategory.value;
});
// 判断是否显示学校统一采购的自动邀请比选模版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 && isSpecialServiceCategory.value;
});
// 获取需求文件的 prop 名称(用于表单验证)
const getRequirementFileProp = () => {
if (showAutoInviteSelectSchool.value) {
if (dataForm.hasRecommendedSupplierSchool === 'yes') {
return 'serviceInviteSelectSchool';
} else if (dataForm.hasRecommendedSupplierSchool === 'no') {
return 'servicePublicSelectSchoolAuto';
}
} else if (showAutoPublicSelect.value) {
return 'servicePublicSelectSchool';
}
return 'purchaseRequirement';
};
// 判断学校统一采购是否需要自动设置采购方式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 或 label 匹配)
const onlineMallOption = purchaseTypeDeptList.value.find(item => {
const label = item.label || item.dictLabel || item.name || '';
return item.id === PURCHASE_TYPE_IDS.ONLINE_MALL ||
item.value === PURCHASE_TYPE_IDS.ONLINE_MALL ||
label.includes('网上商城') || label.includes('商城');
});
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 });
// 下载模版
const downloadTemplate = async (type: string) => {
const templateMap: Record<string, { fileName: string, displayName: string }> = {
'business_negotiation': { fileName: '商务洽谈表.xlsx', displayName: '商务洽谈表.xlsx' },
'market_purchase_minutes': { fileName: '市场采购纪要.xlsx', displayName: '市场采购纪要.xlsx' },
'direct_select': { fileName: '服务商城项目需求模板(直选).doc', displayName: '服务商城项目需求模板(直选).doc' },
'public_select': { fileName: '服务商城项目需求模板(公开比选).doc', displayName: '服务商城项目需求模板(公开比选).doc' },
'invite_select': { fileName: '服务商城项目需求模板(邀请比选).doc', displayName: '服务商城项目需求模板(邀请比选).doc' },
'purchase_requirement': { fileName: '表1采购需求填报模板.doc', displayName: '采购需求填报模板.doc' },
'import_application': { fileName: '附件1进口产品申请及专家论证意见表.doc', displayName: '进口产品申请及专家论证意见表.doc' },
'single_source': { fileName: '表7单一来源论专家证附件.docx', displayName: '单一来源论专家证附件.docx' },
'feasibility_report': { fileName: '表6项目可行性论证报告模板.doc', displayName: '项目可行性论证报告模板.doc' },
};
const template = templateMap[type];
if (!template) {
useMessage().error('模版不存在');
return;
}
try {
const fileUrl = new URL(`../../assets/file/${template.fileName}`, import.meta.url).href;
const response = await fetch(fileUrl);
if (!response.ok) {
throw new Error('文件下载失败');
}
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = template.displayName;
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(link);
useMessage().success('模版下载成功');
} catch (error) {
try {
await other.downBlobFile(
`/purchase/purchasingfiles/downloadTemplate?type=${type}`,
{},
template.displayName
);
useMessage().success('模版下载成功');
} catch (err) {
useMessage().error('模版下载失败,请先维护模版文件');
}
}
};
const dataRules = reactive({
projectName: [
{ required: true, message: '采购项目名称不能为空', trigger: 'blur' }
],
applyDate: [
{ required: true, message: '填报日期不能为空', trigger: 'change' }
],
fundSource: [
{ required: true, message: '资金来源不能为空', trigger: 'change' }
],
budget: [
{ required: true, message: '预算金额不能为空', trigger: 'blur' },
{ type: 'number', min: 0.01, message: '预算金额必须大于0.01', trigger: 'blur' }
],
isCentralized: [
{ required: true, message: '请选择是否集采', trigger: 'change' }
],
isSpecial: [
{ required: true, message: '请选择是否特殊情况', trigger: 'change' }
],
categoryCode: [
{ required: true, message: '品目编码不能为空', trigger: 'change' }
],
projectContent: [
{ required: true, message: '采购内容不能为空', trigger: 'blur' },
{ max: 1000, message: '采购内容不能超过1000字', trigger: 'blur' }
],
purchaseType: [
{ required: true, message: '请选择采购方式', trigger: 'change' }
],
});
// 下一步
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('请完善第一步信息');
}
};
// 上一步
const prevStep = () => {
currentStep.value = 0;
};
// 取消
const handleCancel = () => {
// 如果是在 iframe 中,向父窗口发送关闭消息
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:close'
}, '*');
} else {
router.back();
}
};
// 获取品目树形数据
const getCategoryTreeData = async () => {
try {
const res = await getTree();
categoryTreeData.value = [];
if (res.data && Array.isArray(res.data)) {
categoryTreeData.value = res.data;
}
} catch (err: any) {
console.error('获取品目树形数据失败', err);
categoryTreeData.value = [];
}
};
// 获取资金来源字典
const getFundSourceDict = async () => {
try {
const res = await getDicts('PURCHASE_FUND_SOURCE');
fundSourceList.value = [];
if (res.data && Array.isArray(res.data)) {
fundSourceList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
fundSourceList.value = [
{ 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' },
];
}
} catch (err) {
fundSourceList.value = [
{ 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' },
];
}
};
// 获取是否集采字典
const getIsCentralizedDict = async () => {
try {
const res = await getDicts('PURCHASE_IS_CEN');
isCentralizedList.value = [];
if (res.data && Array.isArray(res.data)) {
isCentralizedList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
isCentralizedList.value = [
{ id: '8e60f8860c1ea2459a41a8ae64fe5518', label: '否', value: '0' },
{ id: '', label: '政府集中采购', value: '1' },
{ id: '', label: '学校集中采购', value: '2' }
];
}
} catch (err) {
isCentralizedList.value = [
{ id: '8e60f8860c1ea2459a41a8ae64fe5518', label: '否', value: '0' },
{ id: '', label: '政府集中采购', value: '1' },
{ id: '', label: '学校集中采购', value: '2' }
];
}
};
// 获取是否特殊情况字典
const getIsSpecialDict = async () => {
try {
const res = await getDicts('PURCHASE_IS_SPEC');
isSpecialList.value = [];
if (res.data && Array.isArray(res.data)) {
isSpecialList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
isSpecialList.value = [
{ id: '1799c07f3a3b8a484f60c495ab9227b6', label: '否', value: '0' },
{ id: '', label: '紧急', value: '1' },
{ id: '', label: '单一', value: '2' },
{ id: '', label: '进口', value: '3' }
];
}
} catch (err) {
isSpecialList.value = [
{ id: '1799c07f3a3b8a484f60c495ab9227b6', label: '否', value: '0' },
{ id: '', label: '紧急', value: '1' },
{ id: '', label: '单一', value: '2' },
{ id: '', label: '进口', value: '3' }
];
}
};
// 获取部门采购方式字典
const getPurchaseTypeDeptDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_DEPT');
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
}));
}
} catch (err) {
console.error('获取部门采购方式字典失败', err);
}
};
// 获取学校采购形式字典
const getPurchaseModeSchoolDict = async () => {
try {
const res = await getDicts('PURCHASE_MODE_SCHOOL');
purchaseModeSchoolList.value = [];
if (res.data && Array.isArray(res.data)) {
purchaseModeSchoolList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
} else {
purchaseModeSchoolList.value = [
{ label: '政府采购', value: '1' },
{ label: '学校自主采购', value: '2' }
];
}
} catch (err) {
purchaseModeSchoolList.value = [
{ label: '政府采购', value: '1' },
{ label: '学校自主采购', value: '2' }
];
}
};
// 获取学校统一采购方式字典
const getPurchaseTypeUnionDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_UNION');
purchaseTypeUnionList.value = [];
if (res.data && Array.isArray(res.data)) {
purchaseTypeUnionList.value = res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}));
}
} catch (err) {
console.error('获取学校统一采购方式字典失败', err);
}
};
// 获取业务分管处室列表
const getBusinessDeptListData = async () => {
try {
const res = await getBusinessDeptList({ records: 1000 }); // 获取所有数据
if (res.data && res.data.records) {
businessDeptList.value = res.data.records.map((item: any) => ({
id: item.id,
deptId: item.deptId,
deptName: item.deptName,
userId: item.userId,
name: item.name,
username: item.username
}));
}
} catch (err) {
console.error('获取业务分管处室列表失败:', err);
businessDeptList.value = [];
}
};
// 获取分管校领导列表
const getSchoolLeaderListData = async () => {
try {
const res = await getSchoolLeaderPage({ records: 1000 }); // 获取所有数据
if (res.data && res.data.records) {
schoolLeaderList.value = res.data.records.map((item: any) => ({
id: item.id,
userId: item.userId,
name: item.name,
username: item.username
}));
}
} catch (err) {
console.error('获取分管校领导列表失败:', err);
schoolLeaderList.value = [];
}
};
// 处理业务分管处室选择变化
const handleBusinessDeptChange = (value: string) => {
if (value) {
const selected = businessDeptList.value.find(item => item.id === value);
if (selected) {
dataForm.deptClassifyId = selected.id;
dataForm.deptClassifyName = selected.deptName || '';
}
} else {
dataForm.deptClassifyId = '';
dataForm.deptClassifyName = '';
}
};
// 处理分管校领导选择变化
const handleSchoolLeaderChange = (value: string) => {
if (value) {
const selected = schoolLeaderList.value.find(item => item.userId === value);
if (selected) {
dataForm.schoolLeaderUserId = selected.userId;
dataForm.schoolLeaderName = selected.name || '';
}
} else {
dataForm.schoolLeaderUserId = '';
dataForm.schoolLeaderName = '';
}
};
// 处理文件ID字符串转数组
// 从上传返回的URL中提取文件ID拼成数组格式["id1", "id2"]
const getFileIdsArray = (fileIds: string | string[]): string[] => {
if (!fileIds) return [];
if (Array.isArray(fileIds)) return fileIds;
const urls = fileIds.split(',').filter(url => url.trim());
const ids: string[] = [];
urls.forEach(url => {
try {
// 尝试解析为URL
const urlObj = new URL(url, window.location.origin);
// 优先从URL参数中获取id
let id = urlObj.searchParams.get('id');
// 如果没有id参数尝试从路径中提取可能是直接的文件ID
if (!id) {
const pathParts = urlObj.pathname.split('/').filter(p => p);
// 检查最后一个路径段是否是32位十六进制字符串文件ID格式
const lastPart = pathParts[pathParts.length - 1];
if (lastPart && /^[a-f0-9]{32}$/i.test(lastPart)) {
id = lastPart;
} else if (lastPart) {
id = lastPart;
}
}
if (id) {
ids.push(id);
} else {
// 如果URL解析失败检查原始字符串是否是ID格式
if (/^[a-f0-9]{32}$/i.test(url.trim())) {
ids.push(url.trim());
} else {
ids.push(url);
}
}
} catch {
// URL解析失败检查是否是直接的ID格式32位十六进制
if (/^[a-f0-9]{32}$/i.test(url.trim())) {
ids.push(url.trim());
} else {
// 否则直接使用原始字符串
ids.push(url);
}
}
});
return ids;
};
// 提交
const handleSubmit = async () => {
if (loading.value) return;
loading.value = true;
try {
const valid = await formRef.value?.validate().catch(() => {});
if (!valid) {
loading.value = false;
return false;
}
const submitData: any = {
...dataForm,
};
// 处理所有文件字段
const fileFields = [
'businessNegotiationTable', 'marketPurchaseMinutes', 'onlineMallMaterials',
'serviceDirectSelect', 'servicePublicSelect', 'purchaseRequirementTemplate',
'serviceInviteSelect', 'servicePublicSelectAuto', 'purchaseRequirement',
'meetingMinutes', 'feasibilityReport', 'meetingMinutesUrgent',
'meetingMinutesSingle', 'meetingMinutesImport', 'singleSourceProof', 'importApplication',
'governmentPurchaseIntent', 'servicePublicSelectSchool', 'serviceInviteSelectSchool',
'servicePublicSelectSchoolAuto', 'otherMaterials'
];
fileFields.forEach(field => {
if (submitData[field]) {
submitData[field] = getFileIdsArray(submitData[field]);
}
});
await addObj(submitData);
useMessage().success('提交成功');
// 如果是在 iframe 中,向父窗口发送消息
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:submitSuccess'
}, '*');
} else {
router.push('/finance/purchasingrequisition');
}
} catch (err: any) {
useMessage().error(err.msg || '提交失败');
} finally {
loading.value = false;
}
};
// 暂存
const handleTempStore = async () => {
if (loading.value) return;
loading.value = true;
try {
const valid = await formRef.value?.validate().catch(() => {});
if (!valid) {
loading.value = false;
return false;
}
const submitData: any = {
...dataForm,
};
const fileFields = [
'businessNegotiationTable', 'marketPurchaseMinutes', 'onlineMallMaterials',
'serviceDirectSelect', 'servicePublicSelect', 'purchaseRequirementTemplate',
'serviceInviteSelect', 'servicePublicSelectAuto', 'purchaseRequirement',
'meetingMinutes', 'feasibilityReport', 'meetingMinutesUrgent',
'meetingMinutesSingle', 'meetingMinutesImport', 'singleSourceProof', 'importApplication',
'governmentPurchaseIntent', 'servicePublicSelectSchool', 'serviceInviteSelectSchool',
'servicePublicSelectSchoolAuto', 'otherMaterials'
];
fileFields.forEach(field => {
if (submitData[field]) {
submitData[field] = getFileIdsArray(submitData[field]);
}
});
await tempStore(submitData);
useMessage().success('暂存成功');
// 如果是在 iframe 中,向父窗口发送消息
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:submitSuccess'
}, '*');
} else {
router.push('/finance/purchasingrequisition');
}
} catch (err: any) {
useMessage().error(err.msg || '暂存失败');
} finally {
loading.value = false;
}
};
// 设置品目编码回显路径
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 () => {
// 检测是否在 iframe 中,如果是,则修改相关元素的 overflow 样式以支持滚动
if (window.parent !== window) {
nextTick(() => {
// 修改 html 和 body
document.documentElement.style.overflow = 'auto';
document.documentElement.style.height = 'auto';
document.body.style.overflow = 'auto';
document.body.style.height = 'auto';
// 修改 html 和 body添加类名
document.documentElement.classList.add('iframe-mode');
document.body.classList.add('iframe-mode');
// 修改 #app
const app = document.getElementById('app');
if (app) {
app.style.overflow = 'auto';
app.style.height = 'auto';
app.style.minHeight = '100%';
// 添加一个类名标记,方便样式控制
app.classList.add('iframe-mode');
}
});
}
await Promise.all([
getCategoryTreeData(),
getFundSourceDict(),
getIsCentralizedDict(),
getIsSpecialDict(),
getPurchaseTypeDeptDict(),
getPurchaseModeSchoolDict(),
getPurchaseTypeUnionDict(),
getBusinessDeptListData(),
getSchoolLeaderListData(),
]);
// 新增模式下设置默认值(只有在没有 id 的情况下才设置)
if (!dataForm.id) {
// 填报日期默认为当天
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
dataForm.applyDate = `${year}-${month}-${day}`;
// 是否集采默认为"否"value: '0'
dataForm.isCentralized = '0';
// 是否特殊情况默认为"否"value: '0'
dataForm.isSpecial = '0';
}
// 如果有 categoryCode设置回显路径
if (dataForm.categoryCode) {
setCategoryCodePath();
}
});
</script>
<style scoped lang="scss">
@import '/@/assets/styles/modern-page.scss';
.mb20 {
margin-bottom: 20px;
}
.mb10 {
margin-bottom: 10px;
}
.mt5 {
margin-top: 5px;
}
.step-title {
font-size: 16px;
font-weight: 600;
color: var(--el-text-color-primary);
padding-bottom: 10px;
border-bottom: 1px solid var(--el-border-color-light);
margin-bottom: 20px;
}
.template-note {
margin-top: 5px;
color: var(--el-text-color-secondary);
}
.form-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding-top: 20px;
border-top: 1px solid var(--el-border-color-light);
}
</style>
<style>
/* 当页面在 iframe 中时,允许滚动 */
html.iframe-mode,
body.iframe-mode {
overflow: auto !important;
height: 100% !important;
min-height: 100% !important;
}
#app.iframe-mode {
overflow: auto !important;
height: auto !important;
min-height: 100% !important;
}
/* 在 iframe 模式下,修改页面容器样式 */
.iframe-mode .modern-page-container {
min-height: auto !important;
height: auto !important;
overflow: visible !important;
}
</style>