Files
school-developer/src/views/finance/purchasingrequisition/add.vue
2026-02-24 14:05:32 +08:00

1905 lines
85 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>
{{ pageTitle }}
</span>
</div>
</template>
<div v-loading="loading" style="padding-bottom: 20px;">
<el-form
ref="formRef"
:model="dataForm"
:rules="dataRules"
label-width="150px"
:disabled="isViewMode || flowFormDisabled"
class="compact-form">
<!-- 第一步基本信息查看/流程嵌入时单页展示否则按步骤切换 -->
<div v-show="isViewMode || isFlowEmbed || currentStep === 0">
<el-row :gutter="24">
<el-col :span="12" class="mb16">
<el-form-item label="采购项目名称" prop="projectName">
<el-input
v-model="dataForm.projectName"
placeholder="请输入采购项目名称"
clearable
:disabled="flowFieldDisabled('projectName')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16">
<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%"
:disabled="flowFieldDisabled('applyDate')" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb16">
<el-form-item label="资金来源" prop="fundSource">
<el-select
v-model="dataForm.fundSource"
placeholder="请选择资金来源"
clearable
style="width: 100%"
:disabled="flowFieldDisabled('fundSource')">
<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="mb16">
<el-form-item label="预算金额" prop="budget">
<div class="budget-yuan-wrap">
<el-input-number
v-model="dataForm.budget"
:min="0.01"
:precision="2"
placeholder="请输入金额"
:controls="false"
style="width: 100%"
:disabled="flowFieldDisabled('budget')" />
<span class="budget-unit"></span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12" class="mb16">
<el-form-item label="是否集采" prop="isCentralized">
<el-select
v-model="dataForm.isCentralized"
placeholder="请选择是否集采"
clearable
style="width: 100%"
:disabled="flowFieldDisabled('isCentralized')">
<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="mb16">
<el-form-item label="是否特殊情况" prop="isSpecial">
<el-select
v-model="dataForm.isSpecial"
placeholder="请选择是否特殊情况"
clearable
style="width: 100%"
:disabled="flowFieldDisabled('isSpecial')">
<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="mb16">
<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%"
:disabled="flowFieldDisabled('categoryCode')"
@change="handleCategoryChange" />
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 第二步采购详情查看/流程嵌入时单页展示否则按步骤切换 -->
<div v-show="isViewMode || isFlowEmbed || currentStep === 1">
<!-- 分支一部门自行采购单行两列流式布局条件显示的项自动填满两列 -->
<div class="mb20" v-if="isDeptPurchase">
<div class="step-title mb16">部门自行采购</div>
<el-row :gutter="24">
<el-col :span="12" class="mb16">
<el-form-item label="采购内容" prop="projectContent" class="mb16">
<el-input
v-model="dataForm.projectContent"
type="textarea"
:rows="3"
:maxlength="1000"
show-word-limit
placeholder="请输入采购内容限制1000字"
clearable
:disabled="flowFieldDisabled('projectContent')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="采购方式" prop="purchaseType" required class="mb16">
<el-select
v-model="dataForm.purchaseType"
placeholder="请选择采购方式"
clearable
:disabled="(isFlowEmbed && isPurchaseCenter) ? false : 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-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.BUSINESS_NEGOTIATION)">
<el-form-item label="商务洽谈表" prop="businessNegotiationTable" required class="mb16">
<upload-file v-model="dataForm.businessNegotiationTable" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.businessNegotiationTable }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('businessNegotiationTable')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('business_negotiation')" style="margin-top: 8px; display: inline-block">下载商务洽谈表模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.MARKET_PURCHASE)">
<el-form-item label="市场采购纪要" prop="marketPurchaseMinutes" required class="mb16">
<upload-file v-model="dataForm.marketPurchaseMinutes" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.marketPurchaseMinutes }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('marketPurchaseMinutes')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('market_purchase_minutes')" style="margin-top: 8px; display: inline-block">下载市场采购纪要模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ONLINE_MALL)">
<el-form-item label="网上商城采购相关材料" prop="onlineMallMaterials" required class="mb16">
<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" :disabled="flowFieldDisabled('onlineMallMaterials')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isInquiryPurchaseType">
<el-form-item label="询价模板" prop="inquiryTemplate" required class="mb16">
<upload-file v-model="dataForm.inquiryTemplate" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.inquiryTemplate }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('inquiryTemplate')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('inquiry')" style="margin-top: 8px; display: inline-block">下载部门采购询价模版模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER)">
<el-form-item label="委托采购中心方式" prop="entrustCenterType" class="mb16">
<el-radio-group v-model="dataForm.entrustCenterType" disabled>
<el-radio label="service_online">服务类网上商城</el-radio>
<el-radio label="other">其他方式</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col
:span="12"
class="mb16"
v-if="
isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER) &&
dataForm.entrustCenterType === 'service_online' &&
categoryCodePath &&
categoryCodePath[0] === 'C'
"
>
<el-form-item label="是否有供应商" prop="hasSupplier" class="mb16">
<el-radio-group v-model="dataForm.hasSupplier" :disabled="flowFieldDisabled('hasSupplier')">
<el-radio label="1">有</el-radio>
<el-radio label="0">无</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER) && dataForm.entrustCenterType === 'service_online' && categoryCodePath && categoryCodePath[0] === 'C' && dataForm.hasSupplier === '1'">
<el-form-item label="需求文件" prop="serviceDirectSelect" required class="mb16">
<upload-file v-model="dataForm.serviceDirectSelect" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.serviceDirectSelect }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('serviceDirectSelect')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('direct_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(直选)》模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER) && dataForm.entrustCenterType === 'service_online' && categoryCodePath && categoryCodePath[0] === 'C' && dataForm.hasSupplier === '0'">
<el-form-item label="需求文件" prop="serviceInviteSelect" required class="mb16">
<upload-file v-model="dataForm.serviceInviteSelect" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('serviceInviteSelect')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('public_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(公开比选)》模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER) && dataForm.entrustCenterType === 'other' && categoryCodePath && categoryCodePath[0] === 'A'">
<el-form-item label="需求模板" prop="purchaseRequirementTemplate" required class="mb16">
<upload-file v-model="dataForm.purchaseRequirementTemplate" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.purchaseRequirementTemplate }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('purchaseRequirementTemplate')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('purchase_requirement')" style="margin-top: 8px; display: inline-block">下载《表1需求模板》模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="showAutoInviteSelect">
<el-form-item label="是否有推荐供应商" prop="hasSupplier" class="mb16">
<el-radio-group v-model="dataForm.hasSupplier" :disabled="flowFieldDisabled('hasSupplier')">
<el-radio label="1">有</el-radio>
<el-radio label="0">无</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="12" class="mb16" v-if="showAutoInviteSelect && dataForm.hasSupplier === '1'">
<el-form-item label="推荐供应商" prop="suppliers" class="mb16">
<el-input v-model="dataForm.suppliers" placeholder="请输入三家供应商名称,用逗号分隔" clearable />
<div class="template-note mt5"><el-text type="info" size="small">请输入三家供应商名称,用逗号分隔</el-text></div>
</el-form-item>
</el-col> -->
<el-col :span="12" class="mb16" v-if="showAutoInviteSelect && dataForm.hasSupplier === '1'">
<el-form-item label="服务商城项目需求模板(邀请比选)" prop="serviceInviteSelect" required class="mb16">
<upload-file v-model="dataForm.serviceInviteSelect" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('serviceInviteSelect')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('invite_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(邀请比选)》模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="showAutoInviteSelect && dataForm.hasSupplier === '0'">
<el-form-item label="服务商城项目需求模板(公开比选)" prop="servicePublicSelectAuto" required class="mb16">
<upload-file v-model="dataForm.servicePublicSelectAuto" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.servicePublicSelectAuto }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('servicePublicSelectAuto')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('public_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(公开比选)》模版</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="其他材料" prop="otherMaterials" class="mb16">
<upload-file v-model="dataForm.otherMaterials" :limit="1" :file-type="['zip']" :data="{ fileType: FILE_TYPE_MAP.otherMaterials }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('otherMaterials')" />
<div class="template-note">支持上传zip格式的压缩包文件</div>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 分支二:学校统一采购(单行两列流式布局);申请时隐藏采购方式,由审批环节采购中心补充 -->
<div class="mb20" v-else>
<div class="step-title mb16">学校统一采购</div>
<el-row :gutter="24">
<el-col :span="12" class="mb16">
<el-form-item label="采购形式" prop="purchaseMode">
<el-radio-group v-model="dataForm.purchaseMode" :disabled="schoolUnifiedPurchaseFormDisabled">
<el-radio v-for="item in purchaseModeSchoolList" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
</el-radio-group>
<!-- <div v-if="schoolUnifiedPurchaseFormDefault != null" class="template-note mt5"><el-text type="info" size="small">根据预算金额与是否集采由系统自动选择</el-text></div> -->
</el-form-item>
</el-col>
<!-- 学校统一采购时申请阶段不显示采购方式;审批环节(流程嵌入)时显示,由采购中心补充选择、其他节点只读 -->
<el-col :span="12" class="mb16" v-if="isDeptPurchase || isFlowEmbed">
<el-form-item label="采购方式" prop="purchaseType" :required="!isDeptPurchase">
<el-select v-model="dataForm.purchaseType" placeholder="请选择采购方式" clearable :disabled="(isFlowEmbed && isPurchaseCenter) ? false : (isAutoSelectPurchaseTypeUnion || flowFieldDisabled('purchaseType'))" 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-col>
<el-col :span="12" class="mb16">
<el-form-item label="业务分管处室" prop="deptClassifyUserId" :required="!isDeptPurchase">
<el-select v-model="dataForm.deptClassifyUserId" placeholder="请选择业务分管处室" clearable filterable @change="handleBusinessDeptChange" style="width: 100%" :disabled="flowFieldDisabled('deptClassifyUserId')">
<el-option v-for="item in businessDeptList" :key="item.id" :label="item.deptName" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="分管校领导" prop="schoolLeaderUserId" :required="!isDeptPurchase">
<el-select v-model="dataForm.schoolLeaderUserId" placeholder="请选择分管校领导" clearable filterable @change="handleSchoolLeaderChange" style="width: 100%" :disabled="flowFieldDisabled('schoolLeaderUserId')">
<el-option v-for="item in schoolLeaderList" :key="item.id" :label="item.name" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="dataForm.budget && dataForm.budget >= 300000">
<el-form-item label="项目可行性论证报告" prop="feasibilityReport" required>
<upload-file v-model="dataForm.feasibilityReport" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.feasibilityReport }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('feasibilityReport')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('feasibility_report')" style="margin-top: 8px; display: inline-block">下载《项目可行性论证报告模板.doc》</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="dataForm.budget && dataForm.budget >= 300000 && !isUrgentSpecial && !isSpecialType('2') && !isSpecialType('3')">
<el-form-item label="会议纪要" prop="meetingMinutes" required>
<upload-file v-model="dataForm.meetingMinutes" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.meetingMinutes }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('meetingMinutes')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isUrgentSpecial">
<el-form-item label="会议纪要" prop="meetingMinutesUrgent" required>
<upload-file v-model="dataForm.meetingMinutesUrgent" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.meetingMinutesUrgent }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('meetingMinutesUrgent')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isSpecialType('2')">
<el-form-item label="单一来源论专家证附件" prop="singleSourceProof" required>
<upload-file v-model="dataForm.singleSourceProof" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.singleSourceProof }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('singleSourceProof')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('single_source')" style="margin-top: 8px; display: inline-block">下载《单一来源论专家证附件.docx》</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isSpecialType('2')">
<el-form-item label="会议纪要" prop="meetingMinutesSingle" required>
<upload-file v-model="dataForm.meetingMinutesSingle" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('meetingMinutesSingle')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isSpecialType('3')">
<el-form-item label="进口产品申请及专家论证意见表" prop="importApplication" required>
<upload-file v-model="dataForm.importApplication" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.importApplication }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('importApplication')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('import_application')" style="margin-top: 8px; display: inline-block">下载《进口产品申请及专家论证意见表.doc》</el-button>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="isSpecialType('3')">
<el-form-item label="会议纪要" prop="meetingMinutesImport" required>
<upload-file v-model="dataForm.meetingMinutesImport" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('meetingMinutesImport')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="showAutoInviteSelectSchool">
<el-form-item label="是否有推荐供应商" prop="hasSupplier">
<el-radio-group v-model="dataForm.hasSupplier" :disabled="flowFieldDisabled('hasSupplier')">
<el-radio label="1">有</el-radio>
<el-radio label="0">无</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="12" class="mb16" v-if="showAutoInviteSelectSchool && dataForm.hasSupplier === '1'">
<el-form-item label="推荐供应商" prop="suppliers">
<el-input v-model="dataForm.suppliers" type="textarea" :rows="2" placeholder="请输入至少三家供应商名称,用逗号或分号分隔" clearable :disabled="flowFieldDisabled('suppliers')" />
<div class="template-note mt5"><el-text type="info" size="small">请输入至少三家供应商名称,用逗号或分号分隔</el-text></div>
</el-form-item>
</el-col> -->
<el-col :span="12" class="mb16">
<el-form-item label="需求文件" :prop="getRequirementFileProp()" required class="mb16">
<template v-if="showAutoInviteSelectSchool">
<template v-if="dataForm.hasSupplier === '1'">
<upload-file v-model="dataForm.serviceInviteSelectSchool" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.serviceInviteSelectSchool }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('serviceInviteSelectSchool')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('invite_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(邀请比选)》模版</el-button>
</template>
<template v-else-if="dataForm.hasSupplier === '0'">
<upload-file v-model="dataForm.servicePublicSelectSchoolAuto" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchoolAuto }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('servicePublicSelectSchoolAuto')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('public_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(公开比选)》模版</el-button>
</template>
</template>
<template v-else-if="showAutoPublicSelect">
<upload-file v-model="dataForm.servicePublicSelectSchool" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchool }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('servicePublicSelectSchool')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('public_select')" style="margin-top: 8px; display: inline-block">下载《服务商城项目需求模板(公开比选)》模版</el-button>
</template>
<template v-else>
<upload-file v-model="dataForm.purchaseRequirement" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.purchaseRequirement }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('purchaseRequirement')" />
<el-button type="primary" link icon="Download" size="small" @click="downloadTemplate('purchase_requirement')" style="margin-top: 8px; display: inline-block">下载《需求模板》模版</el-button>
</template>
</el-form-item>
</el-col>
<el-col :span="12" class="mb16" v-if="dataForm.budget && dataForm.budget >= 1000000">
<el-form-item label="政府采购意向申请表" prop="governmentPurchaseIntent" required>
<upload-file v-model="dataForm.governmentPurchaseIntent" :limit="1" :file-type="['doc', 'docx', 'pdf']" :data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('governmentPurchaseIntent')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb16">
<el-form-item label="其他材料" prop="otherMaterials">
<upload-file v-model="dataForm.otherMaterials" :limit="1" :file-type="['zip']" :data="{ fileType: FILE_TYPE_MAP.otherMaterials }" upload-file-url="/purchase/purchasingfiles/upload" :disabled="flowFieldDisabled('otherMaterials')" />
<div class="template-note">支持上传zip格式的压缩包文件</div>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
<el-row :gutter="24" v-if="currentStep === 1 || isFlowEmbed">
<el-col :span="12" class="mb16">
<el-form-item label="备注" prop="remark" class="mb16">
<el-input
v-model="dataForm.remark"
type="textarea"
:rows="2"
placeholder="请输入备注"
clearable
:disabled="flowFieldDisabled('remark')" />
</el-form-item>
</el-col>
</el-row>
<!-- 查看时:实施采购信息 -->
<div v-if="isViewMode && (dataForm.implementType || viewImplementPurchaseFiles.length)" class="implement-info-block mb20">
<el-divider content-position="left">实施采购信息</el-divider>
<el-row :gutter="24">
<el-col :span="12" class="mb16" v-if="dataForm.implementType">
<div class="view-label">实施采购方式</div>
<div class="view-value">{{ dataForm.implementType === '1' ? '自行组织采购' : dataForm.implementType === '2' ? '委托代理采购' : dataForm.implementType || '—' }}</div>
</el-col>
<el-col :span="12" class="mb16" v-if="dataForm.fileFlowInstId">
<div class="view-label">文件审批状态</div>
<div class="view-value">
<el-tag v-if="dataForm.fileFlowStatus === '-2'" type="info">撤回</el-tag>
<el-tag v-else-if="dataForm.fileFlowStatus === '-1'" type="warning">暂存</el-tag>
<el-tag v-else-if="dataForm.fileFlowStatus === '0'" type="primary">运行中</el-tag>
<el-tag v-else-if="dataForm.fileFlowStatus === '1'" type="success">完成</el-tag>
<el-tag v-else-if="dataForm.fileFlowStatus === '2'" type="danger">作废</el-tag>
<el-tag v-else-if="dataForm.fileFlowStatus === '3'" type="info">终止</el-tag>
<span v-else>—</span>
</div>
</el-col>
</el-row>
<div v-if="viewImplementPurchaseFiles.length" class="mb16">
<div class="view-label mb8">采购文件</div>
<el-table :data="viewImplementPurchaseFiles" border size="small" max-height="240">
<el-table-column type="index" label="版本" width="70" align="center">
<template #default="{ $index }">V{{ $index + 1 }}</template>
</el-table-column>
<el-table-column prop="fileTitle" label="文件名" min-width="180" show-overflow-tooltip />
<el-table-column label="上传时间" width="165" align="center">
<template #default="{ row }">{{ formatImplementFileTime(row.createTime) }}</template>
</el-table-column>
<el-table-column label="操作" width="90" align="center">
<template #default="{ row }">
<el-button type="primary" link size="small" @click="downloadImplementFile(row)">下载</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-form>
<!-- 操作按钮(流程嵌入时隐藏取消/返回,由流程页处理) -->
<div class="form-footer">
<template v-if="isViewMode">
<el-button v-if="!isFlowEmbed" @click="handleCancel">返回</el-button>
</template>
<template v-else>
<el-button v-if="!isFlowEmbed" @click="handleCancel">取消</el-button>
<el-button v-if="!isFlowEmbed && currentStep > 0" @click="prevStep">上一步</el-button>
<el-button
v-if="!isFlowEmbed && currentStep < 1"
type="primary"
@click="nextStep"
:disabled="loading">
下一步
</el-button>
<template v-if="currentStep === 1 || isFlowEmbed">
<el-button
v-if="!isEditMode && !flowSubmitDisabled"
type="warning"
@click="handleTempStore"
:disabled="loading">
暂存
</el-button>
<!-- <el-button -->
<!-- v-if="currentStep === 1" -->
<!-- type="primary" -->
<!-- @click="handleSubmit" -->
<!-- :disabled="loading">-->
<!-- {{ isEditMode ? '保存' : '提交' }}-->
<!-- </el-button>-->
</template>
</template>
</div>
</div>
</el-card>
</div>
</div>
</template>
<script setup lang="ts" name="PurchasingRequisitionAdd">
import { reactive, ref, onMounted, computed, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { addObj, tempStore, getObj, editObj, getApplyFiles } 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';
import { Session } from '/@/utils/storage';
import * as orderVue from '/@/api/order/order-key-vue';
/** 采购中心角色编码:审批时仅该角色可编辑采购方式/采购形式 */
const PURCHASE_CENTER_ROLE_CODE = 'PURCHASE_CENTER';
// 兼容流程 dynamic-link 引用:接收 currJob / currElTab并支持 handleJob 事件
const props = defineProps({
currJob: { type: Object, default: null },
currElTab: { type: Object, default: null }
});
const emit = defineEmits(['handleJob']);
// 路由
const router = useRouter();
const route = useRoute();
/** 是否被流程 handle 页通过 dynamic-link 嵌入 */
const isFlowEmbed = computed(() => !!props.currJob);
/** 当前使用的申请单 ID优先来自流程 currJob.orderId否则来自 route.query.id */
const effectiveQueryId = computed(() => {
if (props.currJob?.orderId != null && props.currJob?.orderId !== '') {
return String(props.currJob.orderId);
}
const q = route.query.id;
return q ? String(q) : '';
});
// 模式add | edit | viewURL 参数 或 流程嵌入时的 currJob/currElTab
const isEditMode = computed(() => {
if (isFlowEmbed.value && props.currElTab) {
return !!effectiveQueryId.value && props.currElTab.isFormEdit !== '0' && !props.currJob?.hiJob;
}
return String(route.query.mode) === 'edit';
});
const isViewMode = computed(() => {
if (isFlowEmbed.value && props.currJob) {
if (props.currJob.hiJob) return true;
if (props.currElTab?.isFormEdit === '0') return true;
return false;
}
return String(route.query.mode) === 'view';
});
const pageTitle = computed(() => {
if (isViewMode.value) return '查看采购申请';
if (isEditMode.value) return '编辑采购申请';
return '新增采购申请';
});
/** 流程嵌入时,由 currElTabIsView 控制的只读/禁用提交 */
const flowFormDisabled = ref(false);
const flowSubmitDisabled = ref(false);
/** 流程嵌入时当前节点是否为采购中心(仅采购中心可编辑采购方式/采购形式) */
const isPurchaseCenter = ref(false);
/** 流程嵌入且为采购中心时,除采购方式/采购形式外其余字段均只读 */
function flowFieldDisabled(key: string) {
return isFlowEmbed.value && isPurchaseCenter.value && !['purchaseType', 'purchaseMode'].includes(key);
}
// 定义变量内容
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: '',
inquiryTemplate: '', // 询价模板
entrustCenterType: '',
hasSupplier: '0',
suppliers: '', // 供应商名称(逗号或分号分隔)
serviceDirectSelect: '',
servicePublicSelect: '',
purchaseRequirementTemplate: '',
serviceInviteSelect: '',
servicePublicSelectAuto: '',
// 学校统一采购字段
purchaseRequirement: '',
meetingMinutes: '',
feasibilityReport: '',
meetingMinutesUrgent: '',
meetingMinutesSingle: '',
meetingMinutesImport: '',
singleSourceProof: '',
importApplication: '',
governmentPurchaseIntent: '',
servicePublicSelectSchool: '',
// 学校统一采购特殊规则字段5万<=金额<40万
serviceInviteSelectSchool: '',
servicePublicSelectSchoolAuto: '',
// 业务分管处室和分管校领导
deptClassifyUserId: '',
deptClassifyName: '',
schoolLeaderUserId: '',
schoolLeaderName: '',
// 其他材料zip压缩包
otherMaterials: '',
// 实施采购信息(查看时展示)
implementType: '',
fileFlowInstId: '',
fileFlowStatus: '',
});
/** 查看时展示的采购文件列表(实施采购上传的 type=130 */
const viewImplementPurchaseFiles = ref<{ id: string; fileTitle?: string; createTime?: string; remark?: string }[]>([]);
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);
// 文件类型映射(对应数据库 file_type 字段)
// 10:商务洽谈纪要 20:市场采购纪要 30:网上商城采购相关材料 40:可行性论证报告 50:会议记录 60:其他材料 70:单一来源专家论证表 90:进口产品专家论证表 100:政府采购意向表 110:履约验收单 120:采购需求表 130:采购文件
const FILE_TYPE_MAP: Record<string, string> = {
businessNegotiationTable: '10', // 商务洽谈纪要
marketPurchaseMinutes: '20', // 市场采购纪要
inquiryTemplate: '20', // 询价模板(归类到市场采购纪要)
onlineMallMaterials: '30', // 网上商城采购相关材料
feasibilityReport: '40', // 可行性论证报告
meetingMinutes: '50', // 会议记录
meetingMinutesUrgent: '50', // 会议记录
meetingMinutesSingle: '50', // 会议记录
meetingMinutesImport: '50', // 会议记录
otherMaterials: '60', // 其他材料
singleSourceProof: '70', // 单一来源专家论证表
importApplication: '90', // 进口产品申请表
governmentPurchaseIntent: '100', // 政府采购意向表
// 需求文件相关 - 所有需求模板都应该是120采购需求表
serviceDirectSelect: '120', // 服务商城项目需求模板(直选)- 采购需求表
serviceInviteSelect: '120', // 服务商城项目需求模板(邀请比选)- 采购需求表
servicePublicSelect: '120', // 服务商城项目需求模板(公开比选)- 采购需求表
servicePublicSelectAuto: '120', // 服务商城项目需求模板(公开比选-自动)- 采购需求表
purchaseRequirementTemplate: '120', // 需求模板 - 采购需求表
purchaseRequirement: '120', // 需求模板 - 采购需求表
serviceInviteSelectSchool: '120', // 服务商城项目需求模板(邀请比选-学校)- 采购需求表
servicePublicSelectSchoolAuto: '120', // 服务商城项目需求模板(公开比选-学校-自动)- 采购需求表
servicePublicSelectSchool: '120', // 服务商城项目需求模板(公开比选-学校)- 采购需求表
};
// fileType -> 表单字段名数组(顺序与回填分配一致,同类型多字段时按此顺序分配)
const FILE_TYPE_TO_FIELDS: Record<string, string[]> = {};
Object.entries(FILE_TYPE_MAP).forEach(([field, type]) => {
if (!FILE_TYPE_TO_FIELDS[type]) FILE_TYPE_TO_FIELDS[type] = [];
FILE_TYPE_TO_FIELDS[type].push(field);
});
// 部门采购方式字典 value与 DeptPurchaseTypeEnum 一致)
const DEPT_PURCHASE_TYPE = {
ONLINE_MALL: '1',
MARKET_PURCHASE: '2',
BUSINESS_NEGOTIATION: '3',
ENTRUST_CENTER: '4',
INQUIRY: '6',
} as const;
// 学校统一采购方式字典 value与 PurchaseTypeEnum 一致)
const UNION_PURCHASE_TYPE = {
ONLINE_MALL: '8',
} as const;
// 辅助函数:判断当前采购方式是否为指定类型(通过字典 value 匹配)
const isPurchaseType = (dictValue: string) => {
if (!dataForm.purchaseType) return false;
return dataForm.purchaseType === dictValue;
};
// 辅助函数:判断当前采购方式是否为"询价"(通过 value 匹配)
const isInquiryPurchaseType = computed(() => isPurchaseType(DEPT_PURCHASE_TYPE.INQUIRY));
// 辅助函数:判断特殊情况是否为指定类型(通过字典 value 匹配)
const isSpecialType = (dictValue: string) => {
if (!dataForm.isSpecial) return false;
const item = isSpecialList.value.find(item => item.value === dictValue);
return item ? dataForm.isSpecial === item.value : dataForm.isSpecial === dictValue;
};
// 判断是否为部门自行采购
// 条件:特殊情况=否 且 集采=否 且 预算金额<5万 → 部门自行采购
// 其他情况 → 学校统一采购
const isDeptPurchase = computed(() => {
const isSpecialNo = isSpecialList.value.find(item => item.value === '0');
const isCentralizedNo = isCentralizedList.value.find(item => item.value === '0');
const isSpecialNoValue = isSpecialNo ? isSpecialNo.value : null;
const isCentralizedNoValue = isCentralizedNo ? isCentralizedNo.value : null;
return !!(isSpecialNoValue && isCentralizedNoValue &&
dataForm.isSpecial === isSpecialNoValue &&
dataForm.isCentralized === isCentralizedNoValue &&
dataForm.budget && dataForm.budget < 50000);
});
// 学校统一采购时采购形式默认值(不由用户选择):>=100万→政府采购('1')5万~100万且集采=否→学校自主('2')5万~100万且集采=政府集中采购→政府采购('1')5万~100万且集采=学校集中采购→学校自主('2')
const schoolUnifiedPurchaseFormDefault = computed(() => {
if (isDeptPurchase.value || dataForm.budget == null) return null;
const budget = Number(dataForm.budget);
if (budget >= 1000000) return '1'; // 政府采购
if (budget >= 50000 && budget < 1000000) {
if (dataForm.isCentralized === '0') return '2'; // 集采=否 → 学校自主采购
if (dataForm.isCentralized === '1') return '1'; // 政府集中采购 → 政府采购
if (dataForm.isCentralized === '2') return '2'; // 学校集中采购 → 学校自主采购
}
return null;
});
// 学校统一采购时采购形式是否禁用(由规则自动选择,不由用户选择)
const schoolUnifiedPurchaseFormDisabled = computed(() => flowFieldDisabled('purchaseMode') || (schoolUnifiedPurchaseFormDefault.value != null));
// 特殊情况字典 value0否 1紧急 2单一 3进口
const isUrgentSpecial = computed(() => dataForm.isSpecial === '1');
// 第二步标题
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' ;
});
// 判断是否为货物类
const isGoodsCategory = computed(() => {
const category = getCategoryInfo();
if (!category) return false;
return category.type === 'A';
});
// 判断是否为特殊服务类目isMallService=1、isProjectService=1
const isSpecialServiceCategory = computed(() => {
const category = getCategoryInfo();
if (!category) return false;
return Number(category.isMallService) === 1 || Number(category.isProjectService) === 1;
});
// 委托采购中心方式自动判断:
// - 服务类:若末级节点 isMallService=0 且 isMallProject=0则选“其他方式”否则选“服务类网上商城”
// - 非服务类:默认选“其他方式”
const calcEntrustCenterType = (): 'service_online' | 'other' | '' => {
if (!isPurchaseType(DEPT_PURCHASE_TYPE.ENTRUST_CENTER)) return '';
if (!dataForm.categoryCode) return '';
const category = getCategoryInfo();
if (!category) return '';
// 兼容字段:接口可能为 isMallProject也可能历史字段为 isProjectService
const mallService = Number(category.isMallService ?? 0);
const mallProject = Number(category.isMallProject ?? category.isProjectService ?? 0);
if (isServiceCategory.value) {
return mallService === 0 && mallProject === 0 ? 'other' : 'service_online';
}
return 'other';
};
// 监听品目/采购方式变化,自动设置委托采购中心方式,并清理无关字段
watch(
[() => dataForm.purchaseType, () => dataForm.categoryCode, () => categoryTreeData.value],
() => {
const nextType = calcEntrustCenterType();
if (!nextType) return;
const prevType = dataForm.entrustCenterType as any;
if (prevType === nextType) return;
dataForm.entrustCenterType = nextType;
// 切换时清理不相关字段,避免脏数据
if (nextType === 'other') {
dataForm.hasSupplier = '0';
dataForm.suppliers = '';
dataForm.serviceDirectSelect = '';
dataForm.serviceInviteSelect = '';
dataForm.servicePublicSelect = '';
dataForm.servicePublicSelectAuto = '';
} else if (nextType === 'service_online') {
dataForm.purchaseRequirementTemplate = '';
}
},
{ immediate: true }
);
// 判断是否自动选择网上商城采购方式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.hasSupplier === '1') {
return 'serviceInviteSelectSchool';
} else if (dataForm.hasSupplier === '0') {
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, () => isDeptPurchase.value, () => isFlowEmbed.value], () => {
// 学校统一采购申请阶段:采购方式隐藏,由审批环节采购中心补充,此处不自动写入且清空已有值
if (!isDeptPurchase.value && !isFlowEmbed.value) {
dataForm.purchaseType = '';
return;
}
// 部门自行采购:自动设置网上商城
if (isAutoSelectPurchaseType.value && isDeptPurchase.value) {
const onlineMallOption = purchaseTypeDeptList.value.find(item => item.value === DEPT_PURCHASE_TYPE.ONLINE_MALL);
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
dataForm.purchaseType = onlineMallOption.value;
}
}
// 学校统一采购审批阶段:自动设置网上商城采购方式
if (isAutoSelectPurchaseTypeUnion.value && !isDeptPurchase.value && isFlowEmbed.value) {
const onlineMallOption = purchaseTypeUnionList.value.find(item => item.value === UNION_PURCHASE_TYPE.ONLINE_MALL);
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
dataForm.purchaseType = onlineMallOption.value;
}
}
}, { immediate: true });
// 学校统一采购:采购形式由规则默认选择,随预算与集采变化自动更新
watch([() => schoolUnifiedPurchaseFormDefault.value, () => isDeptPurchase.value], () => {
if (isDeptPurchase.value) return;
const def = schoolUnifiedPurchaseFormDefault.value;
if (def != null && dataForm.purchaseMode !== def) {
dataForm.purchaseMode = def;
}
}, { 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' },
'inquiry': { fileName: '部门采购询价模版.docx', displayName: '部门采购询价模版.docx' },
'direct_select': { fileName: '服务商城项目需求模板(直选).doc', displayName: '服务商城项目需求模板(直选).doc' },
'public_select': { fileName: '服务商城项目需求模板(公开比选).doc', displayName: '服务商城项目需求模板(公开比选).doc' },
'invite_select': { fileName: '服务商城项目需求模板(邀请比选).doc', displayName: '服务商城项目需求模板(邀请比选).doc' },
'purchase_requirement': { fileName: '默认需求模板.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' }
],
// 学校统一采购时必填
deptClassifyUserId: [
{
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
if (!isDeptPurchase.value) {
if (!value || String(value).trim() === '') {
callback(new Error('请选择业务分管处室'));
return;
}
}
callback();
},
trigger: 'change'
}
],
schoolLeaderUserId: [
{
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
if (!isDeptPurchase.value) {
if (!value || String(value).trim() === '') {
callback(new Error('请选择分管校领导'));
return;
}
}
callback();
},
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 = () => {
// 流程嵌入时由流程页处理返回,不 postMessage
if (isFlowEmbed.value) {
return;
}
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:close'
}, '*');
} else {
router.back();
}
};
/** 根据申请单 ID 加载详情并回填表单(供 URL 与流程嵌入共用) */
async function loadDetail(applyId: string | number) {
if (!applyId) return;
try {
const res = await getObj(Number(applyId));
const detail = res?.data;
if (detail && typeof detail === 'object') {
Object.assign(dataForm, {
id: detail.id ?? dataForm.id,
projectName: detail.projectName ?? '',
projectType: detail.projectType ?? '',
projectContent: detail.projectContent ?? '',
applyDate: detail.applyDate ?? '',
fundSource: detail.fundSource ?? '',
budget: detail.budget != null ? Number(detail.budget) : null,
isCentralized: detail.isCentralized != null ? String(detail.isCentralized) : '',
isSpecial: detail.isSpecial != null ? String(detail.isSpecial) : '',
purchaseMode: detail.purchaseMode ?? '',
purchaseType: detail.purchaseType ?? '',
purchaseTypeUnion: detail.purchaseTypeUnion ?? '',
categoryCode: detail.categoryCode ?? '',
remark: detail.remark ?? '',
status: detail.status ?? '',
businessNegotiationTable: detail.businessNegotiationTable ?? '',
marketPurchaseMinutes: detail.marketPurchaseMinutes ?? '',
onlineMallMaterials: detail.onlineMallMaterials ?? '',
inquiryTemplate: detail.inquiryTemplate ?? '',
entrustCenterType: detail.entrustCenterType ?? '',
hasSupplier: detail.hasSupplier != null && detail.hasSupplier !== '' ? detail.hasSupplier : '0',
suppliers: detail.suppliers ?? '',
serviceDirectSelect: detail.serviceDirectSelect ?? '',
servicePublicSelect: detail.servicePublicSelect ?? '',
purchaseRequirementTemplate: detail.purchaseRequirementTemplate ?? '',
serviceInviteSelect: detail.serviceInviteSelect ?? '',
servicePublicSelectAuto: detail.servicePublicSelectAuto ?? '',
purchaseRequirement: detail.purchaseRequirement ?? '',
meetingMinutes: detail.meetingMinutes ?? '',
feasibilityReport: detail.feasibilityReport ?? '',
meetingMinutesUrgent: detail.meetingMinutesUrgent ?? '',
meetingMinutesSingle: detail.meetingMinutesSingle ?? '',
meetingMinutesImport: detail.meetingMinutesImport ?? '',
singleSourceProof: detail.singleSourceProof ?? '',
importApplication: detail.importApplication ?? '',
governmentPurchaseIntent: detail.governmentPurchaseIntent ?? '',
servicePublicSelectSchool: detail.servicePublicSelectSchool ?? '',
serviceInviteSelectSchool: detail.serviceInviteSelectSchool ?? '',
servicePublicSelectSchoolAuto: detail.servicePublicSelectSchoolAuto ?? '',
deptClassifyUserId: detail.deptClassifyUserId ?? '',
deptClassifyName: detail.deptClassifyName ?? '',
schoolLeaderUserId: detail.schoolLeaderUserId ?? '',
schoolLeaderName: detail.schoolLeaderName ?? '',
otherMaterials: detail.otherMaterials ?? '',
implementType: detail.implementType ?? '',
fileFlowInstId: detail.fileFlowInstId ?? '',
fileFlowStatus: detail.fileFlowStatus ?? '',
});
setCategoryCodePath();
currentStep.value = 0;
try {
const fileRes = await getApplyFiles(String(applyId));
const fileList: { id: string; fileType: string; fileTitle?: string }[] = fileRes?.data ?? [];
if (Array.isArray(fileList) && fileList.length > 0) {
const byType: Record<string, { id: string; fileTitle?: string }[]> = {};
fileList.forEach((f: any) => {
const t = String(f.fileType || '');
if (!byType[t]) byType[t] = [];
byType[t].push({ id: f.id, fileTitle: f.fileTitle });
});
Object.entries(byType).forEach(([fileType, files]) => {
const fields = FILE_TYPE_TO_FIELDS[fileType];
if (!fields || fields.length === 0) return;
const fileItems = files.map((f) => ({ id: f.id, name: f.fileTitle || '附件' }));
if (fields.length === 1) {
(dataForm as any)[fields[0]] = fileItems;
} else {
fields.forEach((field) => {
(dataForm as any)[field] = fileItems.length ? [...fileItems] : '';
});
}
});
// 查看时展示实施采购的采购文件列表type=130
const purchaseFiles = fileList.filter((f: any) => String(f.fileType) === '130').map((f: any) => ({
id: f.id,
fileTitle: f.fileTitle || f.file_title || '采购文件',
createTime: f.createTime || f.create_time,
remark: f.remark,
}));
viewImplementPurchaseFiles.value = purchaseFiles;
} else {
viewImplementPurchaseFiles.value = [];
}
} catch (err) {
console.error('加载采购申请附件失败', err);
viewImplementPurchaseFiles.value = [];
}
}
} catch (e) {
console.error('加载采购申请详情失败', e);
useMessage().error('加载详情失败');
}
}
function formatImplementFileTime(t?: string) {
if (!t) return '—';
const d = new Date(t);
return isNaN(d.getTime()) ? t : d.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
}
function downloadImplementFile(file: { remark?: string; fileTitle?: string }) {
if (!file?.remark) {
useMessage().warning('无法获取文件路径');
return;
}
const url = `/purchase/purchasingfiles/download?fileName=${encodeURIComponent(file.remark)}&fileTitle=${encodeURIComponent(file.fileTitle || '采购文件')}`;
other.downBlobFile(url, {}, file.fileTitle || '采购文件');
}
/** 流程嵌入时提供给 orderVue.currElTabIsView 的 methods只读/禁用提交) */
const flowMethods = {
disableForm(disabled?: boolean) {
flowFormDisabled.value = !!disabled;
},
disableSubmit() {
flowSubmitDisabled.value = true;
},
enableSubmit() {
flowSubmitDisabled.value = false;
},
};
/** 流程嵌入时采购申请权限根据前端缓存的角色cloud-ui:roleCode判断非采购中心整表只读采购中心仅采购方式/采购形式可编辑 */
function applyPurchaseApplyFormPerm() {
if (!isFlowEmbed.value) return;
const roleCode = Session.getRoleCode() || '';
isPurchaseCenter.value = roleCode === PURCHASE_CENTER_ROLE_CODE;
flowFormDisabled.value = !isPurchaseCenter.value;
}
/** 流程嵌入时的“保存”回调:校验后调用 editObj并通知流程已保存 */
async function flowSubmitForm() {
if (loading.value) return;
loading.value = true;
try {
const valid = await formRef.value?.validate().catch(() => false);
if (!valid) {
loading.value = false;
return;
}
const submitData: any = { ...dataForm };
const fileFields = [
'businessNegotiationTable', 'marketPurchaseMinutes', 'onlineMallMaterials', 'inquiryTemplate',
'serviceDirectSelect', 'servicePublicSelect', 'purchaseRequirementTemplate',
'serviceInviteSelect', 'servicePublicSelectAuto', 'purchaseRequirement',
'meetingMinutes', 'feasibilityReport', 'meetingMinutesUrgent',
'meetingMinutesSingle', 'meetingMinutesImport', 'singleSourceProof', 'importApplication',
'governmentPurchaseIntent', 'servicePublicSelectSchool', 'serviceInviteSelectSchool',
'servicePublicSelectSchoolAuto', 'otherMaterials'
];
const allFileIds: string[] = [];
fileFields.forEach(field => {
if (submitData[field]) {
allFileIds.push(...getFileIdsArray(submitData[field]));
delete submitData[field];
}
});
if (allFileIds.length > 0) submitData.fileIds = allFileIds;
await editObj(submitData);
useMessage().success('保存成功');
if (props.currJob && props.currElTab?.id) {
orderVue.currElTabIsSave(props.currJob, props.currElTab.id, true, emit);
}
} catch (err: any) {
if (!err?.msg) useMessage().error('保存失败');
} finally {
loading.value = false;
}
}
// 获取品目树形数据
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 = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}))
: [];
} catch (err) {
isCentralizedList.value = [];
}
};
// 获取是否特殊情况字典
const getIsSpecialDict = async () => {
try {
const res = await getDicts('PURCHASE_IS_SPEC');
isSpecialList.value = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}))
: [];
} catch (err) {
isSpecialList.value = [];
}
};
// 获取部门采购方式字典
const getPurchaseTypeDeptDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_DEPT');
purchaseTypeDeptList.value = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}))
: [];
} catch (err) {
purchaseTypeDeptList.value = [];
}
};
// 获取学校采购形式字典
const getPurchaseModeSchoolDict = async () => {
try {
const res = await getDicts('PURCHASE_MODE_SCHOOL');
purchaseModeSchoolList.value = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}))
: [];
} catch (err) {
purchaseModeSchoolList.value = [];
}
};
// 获取学校统一采购方式字典
const getPurchaseTypeUnionDict = async () => {
try {
const res = await getDicts('PURCHASE_TYPE_UNION');
purchaseTypeUnionList.value = res.data && Array.isArray(res.data)
? res.data.map((item: any) => ({
id: item.id,
label: item.label || item.dictLabel || item.name,
value: item.value || item.dictValue || item.code
}))
: [];
} catch (err) {
purchaseTypeUnionList.value = [];
}
};
// 获取业务分管处室列表
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.userId === value);
if (selected) {
dataForm.deptClassifyUserId = selected.userId;
dataForm.deptClassifyName = selected.deptName || '';
}
} else {
dataForm.deptClassifyUserId = '';
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字符串或对象数组转ID数组
// 支持:逗号分隔的字符串、字符串数组、{ id, name? }[](编辑回填时的格式)
const getFileIdsArray = (fileIds: string | string[] | { id?: string; name?: string }[]): string[] => {
if (!fileIds) return [];
if (Array.isArray(fileIds)) {
return fileIds.map((item: any) => {
if (item && typeof item === 'object' && item.id) return String(item.id).trim();
if (typeof item === 'string') return item.trim();
return '';
}).filter(Boolean);
}
const items = String(fileIds).split(',').filter((item: string) => item.trim());
const ids: string[] = [];
items.forEach(item => {
const trimmed = item.trim();
// 首先检查是否是直接的ID格式32位十六进制字符串
if (/^[a-f0-9]{32}$/i.test(trimmed)) {
ids.push(trimmed);
return;
}
// 如果不是ID格式尝试从URL中提取id参数
try {
const urlObj = new URL(trimmed, window.location.origin);
// 优先从URL参数中获取id
let id = urlObj.searchParams.get('id');
// 如果没有id参数尝试从路径中提取可能是直接的文件ID
if (!id) {
const pathParts = urlObj.pathname.split('/').filter(p => p);
const lastPart = pathParts[pathParts.length - 1];
if (lastPart && /^[a-f0-9]{32}$/i.test(lastPart)) {
id = lastPart;
}
}
if (id) {
ids.push(id);
} else {
// 如果无法提取ID使用原始字符串可能是URL
// 但这种情况不应该发生因为上传接口应该返回id
console.warn('无法从URL中提取文件ID:', trimmed);
ids.push(trimmed);
}
} catch {
// URL解析失败如果原始字符串是ID格式则使用否则忽略
if (/^[a-f0-9]{32}$/i.test(trimmed)) {
ids.push(trimmed);
} else {
console.warn('无法解析文件标识:', trimmed);
}
}
});
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,
};
// 学校统一采购申请阶段:采购方式由审批环节补充,提交时不写入
if (!isFlowEmbed.value && !isDeptPurchase.value) {
submitData.purchaseType = '';
}
// 处理所有文件字段 - 收集所有文件ID到fileIds数组中
const fileFields = [
'businessNegotiationTable', 'marketPurchaseMinutes', 'onlineMallMaterials', 'inquiryTemplate',
'serviceDirectSelect', 'servicePublicSelect', 'purchaseRequirementTemplate',
'serviceInviteSelect', 'servicePublicSelectAuto', 'purchaseRequirement',
'meetingMinutes', 'feasibilityReport', 'meetingMinutesUrgent',
'meetingMinutesSingle', 'meetingMinutesImport', 'singleSourceProof', 'importApplication',
'governmentPurchaseIntent', 'servicePublicSelectSchool', 'serviceInviteSelectSchool',
'servicePublicSelectSchoolAuto', 'otherMaterials'
];
// 收集所有文件ID到一个数组中
const allFileIds: string[] = [];
fileFields.forEach(field => {
if (submitData[field]) {
const ids = getFileIdsArray(submitData[field]);
console.log(`字段 ${field} 的文件ID:`, ids);
// 收集到总数组中
allFileIds.push(...ids);
// 清空原字段,不再单独传递
delete submitData[field];
}
});
// 将所有文件ID统一放到fileIds字段中
if (allFileIds.length > 0) {
submitData.fileIds = allFileIds;
console.log('所有文件ID (fileIds):', allFileIds);
}
console.log('提交数据:', submitData);
if (dataForm.id) {
await editObj(submitData);
useMessage().success('保存成功');
} else {
await addObj(submitData);
useMessage().success('提交成功');
}
// 如果是在 iframe 中,向父窗口发送消息
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:submitSuccess'
}, '*');
} else {
router.push('/finance/purchasingrequisition');
}
} catch (err: any) {
// 全局拦截器已经显示了错误提示,这里不需要再次显示
// 只有当错误没有 msg 时才显示默认错误提示
if (!err?.msg) {
useMessage().error('提交失败');
}
} 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,
};
// 学校统一采购申请阶段:采购方式由审批环节补充,暂存时不写入
if (!isFlowEmbed.value && !isDeptPurchase.value) {
submitData.purchaseType = '';
}
// 处理所有文件字段 - 收集所有文件ID到fileIds数组中
const fileFields = [
'businessNegotiationTable', 'marketPurchaseMinutes', 'onlineMallMaterials', 'inquiryTemplate',
'serviceDirectSelect', 'servicePublicSelect', 'purchaseRequirementTemplate',
'serviceInviteSelect', 'servicePublicSelectAuto', 'purchaseRequirement',
'meetingMinutes', 'feasibilityReport', 'meetingMinutesUrgent',
'meetingMinutesSingle', 'meetingMinutesImport', 'singleSourceProof', 'importApplication',
'governmentPurchaseIntent', 'servicePublicSelectSchool', 'serviceInviteSelectSchool',
'servicePublicSelectSchoolAuto', 'otherMaterials'
];
// 收集所有文件ID到一个数组中
const allFileIds: string[] = [];
fileFields.forEach(field => {
if (submitData[field]) {
const ids = getFileIdsArray(submitData[field]);
// 收集到总数组中
allFileIds.push(...ids);
// 清空原字段,不再单独传递
delete submitData[field];
}
});
// 将所有文件ID统一放到fileIds字段中
if (allFileIds.length > 0) {
submitData.fileIds = allFileIds;
}
await tempStore(submitData);
useMessage().success('暂存成功');
// 流程嵌入时不关闭、不跳转
if (!isFlowEmbed.value) {
if (window.parent !== window) {
window.parent.postMessage({
type: 'purchasingrequisition:submitSuccess'
}, '*');
} else {
router.push('/finance/purchasingrequisition');
}
}
} catch (err: any) {
if (!err?.msg) {
useMessage().error('暂存失败');
}
} 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 });
// 流程嵌入:切换工单时重新加载该 tab 对应的申请单
watch(
() => props.currJob?.id,
async (newVal, oldVal) => {
if (!isFlowEmbed.value || !props.currJob?.orderId) return;
if (newVal !== oldVal) {
await loadDetail(props.currJob.orderId);
}
}
);
// 初始化
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(),
]);
// 编辑/查看:从 URL 或流程 currJob.orderId 加载详情
const queryId = effectiveQueryId.value;
if (queryId) {
await loadDetail(queryId);
}
// 流程嵌入:注册 tab 显隐与保存回调,供审批页调用
if (isFlowEmbed.value && props.currJob && props.currElTab?.id) {
orderVue.currElTabIsExist(props.currJob, props.currElTab.id);
await orderVue.currElTabIsView(flowMethods, props.currJob, props.currElTab.id, flowSubmitForm);
applyPurchaseApplyFormPerm();
}
// 新增模式下设置默认值(只有在没有 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;
}
.mb16 {
margin-bottom: 16px;
}
.mb8 {
margin-bottom: 8px;
}
.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: 16px;
}
.implement-info-block {
.view-label {
font-size: 14px;
color: var(--el-text-color-secondary);
margin-bottom: 4px;
}
.view-value {
font-size: 14px;
color: var(--el-text-color-primary);
}
}
/* 紧凑表单样式 */
.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-yuan-wrap {
display: flex;
align-items: center;
width: 100%;
gap: 8px;
:deep(.el-input-number) {
flex: 1;
}
.budget-unit {
color: var(--el-text-color-regular);
font-size: 14px;
flex-shrink: 0;
}
}
.form-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-light);
margin-top: 16px;
}
</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>