2756 lines
100 KiB
Vue
2756 lines
100 KiB
Vue
<template>
|
||
<div class="modern-page-container">
|
||
<div class="page-wrapper">
|
||
<el-card class="content-card" shadow="never">
|
||
<template #header v-if="isEditMode">
|
||
<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">
|
||
<div class="form-toolbar mb12" style="text-align: right">
|
||
<el-button type="primary" link icon="QuestionFilled" @click="helpDialogVisible = true"> 帮助 </el-button>
|
||
</div>
|
||
<el-form
|
||
ref="formRef"
|
||
:model="dataForm"
|
||
:rules="dataRules"
|
||
label-width="150px"
|
||
:disabled="isViewMode || flowFormDisabled"
|
||
class="compact-form"
|
||
>
|
||
<!-- 基本信息(三列紧凑) -->
|
||
<div class="form-section-compact">
|
||
<el-row :gutter="16">
|
||
<el-col :span="8" class="mb12">
|
||
<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="8" class="mb12">
|
||
<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-col :span="8" class="mb12">
|
||
<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="8" class="mb12">
|
||
<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-col :span="8" class="mb12">
|
||
<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="8" class="mb12">
|
||
<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-col :span="8" class="mb12">
|
||
<el-form-item label="是否有资产" prop="hasAssets">
|
||
<el-radio-group v-model="dataForm.hasAssets" :disabled="flowFieldDisabled('hasAssets')">
|
||
<el-radio label="1">有</el-radio>
|
||
<el-radio label="0">无</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="24" class="mb12">
|
||
<el-form-item label="品目编码" prop="categoryCode">
|
||
<el-cascader
|
||
v-model="categoryCodePath"
|
||
:options="categoryTreeData"
|
||
:props="{ value: 'code', label: 'name', children: 'children', checkStrictly: false }"
|
||
placeholder="请选择品目编码(仅最后一级)"
|
||
clearable
|
||
filterable
|
||
:show-all-levels="true"
|
||
style="width: 100%"
|
||
:disabled="flowFieldDisabled('categoryCode')"
|
||
@change="handleCategoryChange"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
|
||
<!-- 采购详情(新增时需先填是否特殊情况、是否集采、预算金额后才显示) -->
|
||
<div>
|
||
<el-alert v-if="!showPurchaseDetailBlocks" type="info" :closable="false" class="mb16" show-icon>
|
||
请先填写上方「是否特殊情况」「是否集采」「预算金额」,系统将根据填写结果展示「部门自行采购」或「学校统一采购」表单。
|
||
</el-alert>
|
||
<!-- 部门采购会议纪要(预算超过2000元必须上传,不区分部门自行采购/学校统一采购) -->
|
||
<el-row :gutter="16" v-if="showPurchaseDetailBlocks && dataForm.budget != null && dataForm.budget >= BUDGET_DEPT_SELF_MEETING_MINUTES">
|
||
<el-col :span="8" class="mb12">
|
||
<el-form-item label="部门采购会议纪要" prop="deptSelfMeetingMinutes" required>
|
||
<upload-file
|
||
v-model="dataForm.deptSelfMeetingMinutes"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.deptSelfMeetingMinutes }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('deptSelfMeetingMinutes')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<!-- 分支一:部门自行采购(三列紧凑,textarea 单独一行) -->
|
||
<div class="mb20 form-section-compact" v-if="showPurchaseDetailBlocks && isDeptPurchase">
|
||
<div class="step-title mb12">部门自行采购</div>
|
||
<el-col :span="24" class="mb12">
|
||
<el-form-item label="采购内容" prop="projectContent">
|
||
<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-row :gutter="16">
|
||
<el-col :span="8" class="mb12">
|
||
<el-form-item label="采购途径" prop="purchaseChannel">
|
||
<el-select
|
||
v-model="dataForm.purchaseChannel"
|
||
placeholder="请选择采购途径"
|
||
clearable
|
||
:disabled="flowFieldDisabled('purchaseChannel')"
|
||
style="width: 100%"
|
||
>
|
||
<el-option :label="'自行采购'" :value="PURCHASE_CHANNEL.SELF" />
|
||
<el-option :label="'委托采购中心采购'" :value="PURCHASE_CHANNEL.ENTRUST_CENTER" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12">
|
||
<el-form-item label="采购方式" prop="purchaseType" :required="!isEntrustCenterChannel">
|
||
<el-select
|
||
v-model="dataForm.purchaseType"
|
||
placeholder="请选择采购方式"
|
||
clearable
|
||
:disabled="
|
||
isFlowEmbed && isPurchaseCenter ? false : isDeptSelfMallLocked || isAutoSelectPurchaseType || isEntrustCenterChannel
|
||
"
|
||
style="width: 100%"
|
||
>
|
||
<el-option v-for="item in purchaseTypeDeptOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
<!-- <div v-if="isFlowEmbed && isPurchaseCenter && isEntrustCenterChannel && isAutoSelectPurchaseType" class="template-note mt5">-->
|
||
<!-- <el-text type="info" size="small">服务网上商城</el-text>-->
|
||
<!-- </div>-->
|
||
</el-form-item>
|
||
</el-col>
|
||
|
||
<el-col :span="24" class="mb12" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.BUSINESS_NEGOTIATION)">
|
||
<el-form-item label="洽谈理由" prop="negotiationReason" required>
|
||
<el-input
|
||
v-model="dataForm.negotiationReason"
|
||
type="textarea"
|
||
:rows="3"
|
||
:maxlength="500"
|
||
show-word-limit
|
||
placeholder="请输入洽谈理由(限制500字)"
|
||
clearable
|
||
:disabled="flowFieldDisabled('negotiationReason')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.BUSINESS_NEGOTIATION)">
|
||
<el-form-item label="商务洽谈表" prop="businessNegotiationTable" required>
|
||
<upload-file
|
||
v-model="dataForm.businessNegotiationTable"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.MARKET_PURCHASE)">
|
||
<el-form-item label="市场采购纪要" prop="marketPurchaseMinutes" required>
|
||
<upload-file
|
||
v-model="dataForm.marketPurchaseMinutes"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="isPurchaseType(DEPT_PURCHASE_TYPE.ONLINE_MALL)">
|
||
<el-form-item label="网上商城采购相关材料" prop="onlineMallMaterials" required>
|
||
<upload-file
|
||
v-model="dataForm.onlineMallMaterials"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.onlineMallMaterials }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('onlineMallMaterials')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12" v-if="isInquiryPurchaseType">
|
||
<el-form-item label="询价模板" prop="inquiryTemplate" required>
|
||
<upload-file
|
||
v-model="dataForm.inquiryTemplate"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8"
|
||
class="mb12"
|
||
v-if="
|
||
isEntrustCenterChannel && dataForm.entrustCenterType === 'service_online' && categoryCodePath && categoryCodePath[0] === 'C'
|
||
"
|
||
>
|
||
<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="8"
|
||
class="mb12"
|
||
v-if="
|
||
isEntrustCenterChannel &&
|
||
dataForm.entrustCenterType === 'service_online' &&
|
||
categoryCodePath &&
|
||
categoryCodePath[0] === 'C' &&
|
||
dataForm.hasSupplier === '1'
|
||
"
|
||
>
|
||
<el-form-item label="需求文件" prop="serviceDirectSelect" required>
|
||
<upload-file
|
||
v-model="dataForm.serviceDirectSelect"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8"
|
||
class="mb12"
|
||
v-if="
|
||
isEntrustCenterChannel &&
|
||
dataForm.entrustCenterType === 'service_online' &&
|
||
categoryCodePath &&
|
||
categoryCodePath[0] === 'C' &&
|
||
dataForm.hasSupplier === '0'
|
||
"
|
||
>
|
||
<el-form-item label="需求文件" prop="serviceInviteSelect" required>
|
||
<upload-file
|
||
v-model="dataForm.serviceInviteSelect"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8"
|
||
class="mb12"
|
||
v-if="isEntrustCenterChannel && dataForm.entrustCenterType === 'other' && categoryCodePath && categoryCodePath[0] === 'A'"
|
||
>
|
||
<el-form-item label="需求模板" prop="purchaseRequirementTemplate" required>
|
||
<upload-file
|
||
v-model="dataForm.purchaseRequirementTemplate"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx']"
|
||
: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="8" class="mb12" v-if="showAutoInviteSelect">
|
||
<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="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '1'">
|
||
<el-form-item label="服务商城项目需求模板(邀请比选)" prop="serviceInviteSelect" required>
|
||
<upload-file
|
||
v-model="dataForm.serviceInviteSelect"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="showAutoInviteSelect && dataForm.hasSupplier === '0'">
|
||
<el-form-item label="服务商城项目需求模板(公开比选)" prop="servicePublicSelectAuto" required>
|
||
<upload-file
|
||
v-model="dataForm.servicePublicSelectAuto"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12">
|
||
<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 class="mb20 form-section-compact" v-if="showPurchaseDetailBlocks && !isDeptPurchase">
|
||
<div class="step-title mb12">学校统一采购</div>
|
||
<el-row :gutter="16">
|
||
<el-col :span="8" class="mb12">
|
||
<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>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12">
|
||
<el-form-item label="采购方式" prop="purchaseType">
|
||
<el-select
|
||
v-model="dataForm.purchaseType"
|
||
placeholder="请选择采购方式"
|
||
clearable
|
||
:disabled="
|
||
isFlowEmbed && isPurchaseCenter
|
||
? false
|
||
: isAutoSelectPurchaseTypeUnion || flowFieldDisabled('purchaseType') || !isPurchaseCenter
|
||
"
|
||
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="8" class="mb12">
|
||
<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="8" class="mb12" v-if="!isSpecialCase">
|
||
<el-form-item label="业务分管校领导" prop="schoolBusinessLeaderUserId" :required="!isDeptPurchase">
|
||
<el-select
|
||
v-model="dataForm.schoolBusinessLeaderUserId"
|
||
placeholder="请选择业务分管校领导"
|
||
clearable
|
||
filterable
|
||
@change="handleBusinessLeaderChange"
|
||
style="width: 100%"
|
||
:disabled="flowFieldDisabled('schoolBusinessLeaderUserId')"
|
||
>
|
||
<el-option v-for="item in businessLeaderList" :key="item.id" :label="item.name" :value="item.userId" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12">
|
||
<el-form-item label="校党委" prop="schoolLeaderUserId" v-if="isSpecialCase" :required="!isDeptPurchase && isSpecialCase">
|
||
<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="8" class="mb12">
|
||
<el-form-item label="采购分管校领导" prop="purchaseManagerUserId" :required="!isDeptPurchase">
|
||
<el-select
|
||
v-model="dataForm.purchaseManagerUserId"
|
||
placeholder="请选择采购分管校领导"
|
||
clearable
|
||
filterable
|
||
@change="handlePurchaseManagerChange"
|
||
style="width: 100%"
|
||
:disabled="flowFieldDisabled('purchaseManagerUserId')"
|
||
>
|
||
<el-option v-for="item in purchasingManagerList" :key="item.id" :label="item.name" :value="item.userId" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12" v-if="dataForm.budget && dataForm.budget >= BUDGET_FEASIBILITY_THRESHOLD">
|
||
<el-form-item label="项目可行性论证报告" prop="feasibilityReport" required>
|
||
<upload-file
|
||
v-model="dataForm.feasibilityReport"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8"
|
||
class="mb12"
|
||
v-if="
|
||
dataForm.budget &&
|
||
(dataForm.budget >= BUDGET_FEASIBILITY_THRESHOLD || !isSpecialType('0'))
|
||
|
||
"
|
||
>
|
||
<el-form-item label="校党委会议纪要" prop="meetingMinutes" required>
|
||
<upload-file
|
||
v-model="dataForm.meetingMinutes"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('meetingMinutes')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
|
||
<el-col :span="8" class="mb12" v-if="isSpecialType('2')">
|
||
<el-form-item label="单一来源论专家证附件" prop="singleSourceProof" required>
|
||
<upload-file
|
||
v-model="dataForm.singleSourceProof"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="isSpecialType('2')">
|
||
<el-form-item label="校党委会议纪要" prop="meetingMinutesSingle" required>
|
||
<upload-file
|
||
v-model="dataForm.meetingMinutesSingle"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('meetingMinutesSingle')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12" v-if="isSpecialType('3')">
|
||
<el-form-item label="进口产品申请及专家论证意见表" prop="importApplication" required>
|
||
<upload-file
|
||
v-model="dataForm.importApplication"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="isSpecialType('3')">
|
||
<el-form-item label="校党委会议纪要" prop="meetingMinutesImport" required>
|
||
<upload-file
|
||
v-model="dataForm.meetingMinutesImport"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('meetingMinutesImport')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12" 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="8" class="mb12" 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="8" class="mb12">
|
||
<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', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
: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="8" class="mb12" v-if="dataForm.budget && dataForm.budget >= BUDGET_GOV_PURCHASE_THRESHOLD">
|
||
<el-form-item label="政府采购意向申请表" prop="governmentPurchaseIntent" required>
|
||
<upload-file
|
||
v-model="dataForm.governmentPurchaseIntent"
|
||
:limit="1"
|
||
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
|
||
upload-file-url="/purchase/purchasingfiles/upload"
|
||
:disabled="flowFieldDisabled('governmentPurchaseIntent')"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8" class="mb12">
|
||
<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="16">
|
||
<el-col :span="24" class="mb12">
|
||
<el-form-item label="备注" prop="remark">
|
||
<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.agentName" class="implement-info-block mb20">
|
||
<el-divider content-position="left">招标代理</el-divider>
|
||
<el-row :gutter="24">
|
||
<el-col :span="8" class="mb12">
|
||
<div class="view-label">代理名称</div>
|
||
<div class="view-value">{{ dataForm.agentName }}</div>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
|
||
<div v-if="isViewMode && dataForm.representorName" class="implement-info-block mb20">
|
||
<el-divider content-position="left">采购代表/评委</el-divider>
|
||
<el-row :gutter="24">
|
||
<el-col :span="8" class="mb12">
|
||
<div class="view-label">参与人员</div>
|
||
<div class="view-value">
|
||
{{ dataForm.representorName }}
|
||
<el-tag v-if="dataForm.representorType" type="info" size="small" style="margin-left: 8px">
|
||
{{ dataForm.representorType }}
|
||
</el-tag>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
|
||
<!-- 帮助弹窗:展示金额与规则说明 -->
|
||
<el-dialog v-model="helpDialogVisible" title="帮助 - 采购规则说明" width="620px" destroy-on-close>
|
||
<el-alert type="info" :closable="false" show-icon class="mb12">
|
||
以下规则仅作为自动推荐与必填校验依据,实际录入时可在允许范围内调整。
|
||
</el-alert>
|
||
<el-scrollbar max-height="360px">
|
||
<ul class="help-rules-list">
|
||
<li>
|
||
<strong>部门自行采购 / 学校统一采购划分</strong>: 当「是否特殊情况 = 否」「是否集采 = 否」且预算金额 < 5 万({{
|
||
BUDGET_DEPT_PURCHASE_THRESHOLD
|
||
}}
|
||
元)时,系统判定为「部门自行采购」,否则为「学校统一采购」。
|
||
</li>
|
||
<li>
|
||
<strong>学校统一采购 - 采购形式默认值</strong>: 当预算金额 ≥ 100 万({{ BUDGET_GOV_PURCHASE_THRESHOLD }} 元)时默认「政府采购」;
|
||
当 5 万 ≤ 预算金额 < 100 万时,根据「是否集采」自动推荐「政府采购」或「学校自主采购」, 但申请人可以在界面上自行修改。
|
||
</li>
|
||
<li>
|
||
<strong>部门自行采购 - 自动网上商城</strong>:
|
||
在「部门自行采购」且为服务类特殊品目时,系统会自动将采购方式推荐为「网上商城」(服务类),同时要求上传相应模板文件。
|
||
</li>
|
||
<li>
|
||
<strong>学校统一采购 - 自动邀请/公开比选模板</strong>: 对服务类特殊品目: 当 5 万 ≤ 预算金额 < 40
|
||
万时,系统根据「是否有推荐供应商」在邀请比选 / 公开比选模板之间自动切换必填文件; 当 40 万 ≤ 预算金额 < 100
|
||
万时,系统默认要求使用公开比选模板。
|
||
</li>
|
||
<li>
|
||
<strong>可行性论证与会议纪要(学校统一采购)</strong>: 当预算金额 ≥ 30 万({{
|
||
BUDGET_FEASIBILITY_THRESHOLD
|
||
}}
|
||
元)且不是紧急/单一/进口等特殊情况时,
|
||
需要上传「项目可行性论证报告」和「会议纪要」;紧急、单一来源、进口等特殊情况对应有单独的证明材料与会议纪要要求。
|
||
</li>
|
||
<li>
|
||
<strong>政府采购意向表</strong>: 当预算金额 ≥ 100 万({{
|
||
BUDGET_GOV_PURCHASE_THRESHOLD
|
||
}}
|
||
元),需要填写政府采购意向表并上传对应模板文件。
|
||
</li>
|
||
<li>
|
||
<strong>委托采购中心采购</strong>:
|
||
在「部门自行采购」中选择「委托采购中心采购」作为采购途径时,申请阶段隐藏采购方式,由采购中心在审核环节选择;
|
||
对服务类特殊品目,采购中心会优先推荐「网上商城(服务网上商城)」方式。
|
||
</li>
|
||
</ul>
|
||
</el-scrollbar>
|
||
<template #footer>
|
||
<el-button type="primary" @click="helpDialogVisible = false">我知道了</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 查看时:实施采购信息 -->
|
||
<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="8" class="mb12" 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="8" class="mb12" 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="!isEditMode && !flowSubmitDisabled" type="warning" @click="handleTempStore" :disabled="loading"> 暂存 </el-button>
|
||
<!-- <el-button -->
|
||
<!-- type="primary" -->
|
||
<!-- @click="handleSubmit" -->
|
||
<!-- :disabled="loading">-->
|
||
<!-- {{ isEditMode ? '保存' : '提交' }}-->
|
||
<!-- </el-button>-->
|
||
</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/purchase/purchasingrequisition';
|
||
import { getTree } from '/@/api/purchase/purchasingcategory';
|
||
import { getDicts } from '/@/api/admin/dict';
|
||
import { useMessage } from '/@/hooks/message';
|
||
import { useUserInfo } from '/@/stores/userInfo';
|
||
import { usePurchaseRulesSingleton } from '/@/hooks/usePurchaseRules';
|
||
import UploadFile from '/@/components/Upload/index.vue';
|
||
import other from '/@/utils/other';
|
||
import { Document, Download, QuestionFilled } from '@element-plus/icons-vue';
|
||
import { fetchList as getBusinessDeptList } from '/@/api/purchase/purchasingBusinessDept';
|
||
import { getPage as getSchoolLeaderPage } from '/@/api/purchase/purchasingschoolleader';
|
||
import { fetchList as getPurchasingManagerList } from '/@/api/purchase/purchasingPurchaseManager';
|
||
import { fetchList as getBusinessLeaderList } from '/@/api/purchase/purchasingBusinessLeader';
|
||
import { Session } from '/@/utils/storage';
|
||
import * as orderVue from '/@/api/order/order-key-vue';
|
||
|
||
/** 采购中心角色编码:审批时仅该角色可编辑采购方式/采购形式 */
|
||
const PURCHASE_CENTER_ROLE_CODE = 'PURCHASE_CENTER';
|
||
const PURCHASE_DEPT_APPLY_ROLE_CODE = 'ROLE_PURCHASE_DEPT_APPLY';
|
||
|
||
// 兼容流程 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 | view(URL 参数 或 流程嵌入时的 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) {
|
||
if (isFlowEmbed.value && isPurchaseCenter.value) return false;
|
||
if (isFlowEmbed.value && isApplicant.value) return false;
|
||
return !!isFlowEmbed.value;
|
||
}
|
||
|
||
/** 当前用户是否为申请人(在流程中可编辑) */
|
||
const isApplicant = computed(() => {
|
||
|
||
const stores = useUserInfo();
|
||
const currentUser = stores.userInfos?.user || {};
|
||
console.log(currentUser)
|
||
if (!dataForm.createBy) return false;
|
||
|
||
// const stores = useUserInfo();
|
||
// const currentUser = stores.userInfos?.user || {};
|
||
return dataForm.createBy === currentUser.username;
|
||
});
|
||
|
||
// 定义变量内容
|
||
const formRef = ref();
|
||
const dataForm = reactive({
|
||
id: '',
|
||
projectName: '',
|
||
projectType: '',
|
||
projectContent: '',
|
||
applyDate: '',
|
||
fundSource: '',
|
||
budget: null as number | null,
|
||
isCentralized: '',
|
||
isSpecial: '',
|
||
hasAssets: '0',
|
||
purchaseMode: '',
|
||
purchaseType: '',
|
||
purchaseTypeUnion: '',
|
||
purchaseChannel: '',
|
||
categoryCode: '',
|
||
remark: '',
|
||
status: '',
|
||
createBy: '', // 创建人用户名,用于判断是否为申请人
|
||
// 部门自行采购字段
|
||
businessNegotiationTable: '',
|
||
marketPurchaseMinutes: '',
|
||
onlineMallMaterials: '',
|
||
inquiryTemplate: '', // 询价模板
|
||
entrustCenterType: '',
|
||
hasSupplier: '0',
|
||
suppliers: '', // 供应商名称(逗号或分号分隔)
|
||
serviceDirectSelect: '',
|
||
servicePublicSelect: '',
|
||
purchaseRequirementTemplate: '',
|
||
|
||
serviceInviteSelect: '',
|
||
servicePublicSelectAuto: '',
|
||
deptSelfMeetingMinutes: '', // 部门自行采购会议纪要
|
||
// 学校统一采购字段
|
||
purchaseRequirement: '',
|
||
meetingMinutes: '',
|
||
feasibilityReport: '',
|
||
meetingMinutesUrgent: '',
|
||
meetingMinutesSingle: '',
|
||
meetingMinutesImport: '',
|
||
singleSourceProof: '',
|
||
importApplication: '',
|
||
governmentPurchaseIntent: '',
|
||
servicePublicSelectSchool: '',
|
||
// 学校统一采购特殊规则字段(5万<=金额<40万)
|
||
|
||
serviceInviteSelectSchool: '',
|
||
servicePublicSelectSchoolAuto: '',
|
||
// 业务分管处室和分管校领导
|
||
deptClassifyUserId: '',
|
||
deptClassifyName: '',
|
||
schoolLeaderUserId: '',
|
||
schoolLeaderName: '',
|
||
// 业务分管校领导
|
||
schoolBusinessLeaderUserId: '',
|
||
schoolBusinessLeaderName: '',
|
||
// 采购分管
|
||
purchaseManagerUserId: '',
|
||
purchaseManagerName: '',
|
||
// 其他材料(zip压缩包)
|
||
otherMaterials: '',
|
||
// 实施采购信息(查看时展示)
|
||
implementType: '',
|
||
fileFlowInstId: '',
|
||
fileFlowStatus: '',
|
||
agentId: '',
|
||
agentName: '',
|
||
representorName: '',
|
||
representorType: '',
|
||
negotiationReason: '',
|
||
});
|
||
/** 查看时展示的招标文件列表(实施采购上传的 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 purchaseTypeDeptDelegationList = ref<any[]>([]);
|
||
const purchaseModeSchoolList = ref<any[]>([]);
|
||
const purchaseTypeUnionList = ref<any[]>([]);
|
||
const businessDeptList = ref<any[]>([]);
|
||
const schoolLeaderList = ref<any[]>([]);
|
||
const purchasingManagerList = ref<any[]>([]);
|
||
const businessLeaderList = ref<any[]>([]);
|
||
/** 人员类型字典(采购代表/评委) */
|
||
const representorTypeList = ref<any[]>([]);
|
||
const loading = ref(false);
|
||
const helpDialogVisible = ref(false);
|
||
|
||
// 文件类型映射(对应数据库 file_type 字段)
|
||
// 10:商务洽谈纪要 20:市场采购纪要 30:网上商城采购相关材料 40:可行性论证报告 50:会议记录 60:其他材料 70:单一来源专家论证表 90:进口产品专家论证表 100:政府采购意向表 110:履约验收单 120:采购需求表 130:招标文件 140: 部门自行采购会议纪要
|
||
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', // 服务商城项目需求模板(公开比选 - 学校)- 采购需求表
|
||
deptSelfMeetingMinutes: '140', // 部门自行采购会议纪要
|
||
};
|
||
|
||
// 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);
|
||
});
|
||
|
||
// 金额阈值(从规则配置动态获取,默认值与后端 PurchaseConstants 保持一致)
|
||
const { rules: purchaseRules, getThresholds, evaluate: evaluatePurchaseRules } = usePurchaseRulesSingleton();
|
||
|
||
const BUDGET_DEPT_PURCHASE_THRESHOLD = computed(() => getThresholds().deptPurchase);
|
||
const BUDGET_FEASIBILITY_THRESHOLD = computed(() => getThresholds().feasibility);
|
||
const BUDGET_PUBLIC_SELECT_THRESHOLD = computed(() => getThresholds().publicSelect);
|
||
const BUDGET_GOV_PURCHASE_THRESHOLD = computed(() => getThresholds().govPurchase);
|
||
const BUDGET_DEPT_SELF_MEETING_MINUTES = computed(() => getThresholds().deptSelfMeetingMinutes);
|
||
|
||
// 部门采购方式字典 value(与 DeptPurchaseTypeEnum 一致)
|
||
const DEPT_PURCHASE_TYPE = {
|
||
ONLINE_MALL: '1',
|
||
MARKET_PURCHASE: '2',
|
||
BUSINESS_NEGOTIATION: '3',
|
||
ENTRUST_CENTER: '4',
|
||
INQUIRY: '5',
|
||
/** 公开招标(部门自行采购下委托采购中心采购时可选择) */
|
||
OPEN_TENDERING: '100',
|
||
} 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;
|
||
};
|
||
|
||
// 辅助函数:根据人员类型值获取标签(采购代表/评委类型)
|
||
const getRepresentorTypeLabel = (value: string): string => {
|
||
const item = representorTypeList.value.find((item) => item.value === value);
|
||
return item ? item.label : value;
|
||
};
|
||
|
||
// 采购途径(与后端 purchasing_apply.purchase_channel 一致:1 自行采购 2 委托采购中心采购)
|
||
const PURCHASE_CHANNEL = {
|
||
SELF: '1',
|
||
ENTRUST_CENTER: '2',
|
||
} as const;
|
||
|
||
// 判断是否为部门自行采购
|
||
// 条件:特殊情况=否 且 集采=否 且 预算金额<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 < BUDGET_DEPT_PURCHASE_THRESHOLD.value
|
||
);
|
||
});
|
||
|
||
// 是否为“委托采购中心采购”途径
|
||
const isEntrustCenterChannel = computed(() => dataForm.purchaseChannel === PURCHASE_CHANNEL.ENTRUST_CENTER);
|
||
|
||
// 是否已填入“是否特殊情况”“是否集采”“预算金额”,从而能明确是部门自行采购还是学校统一采购(新增时先隐藏采购详情,填完后再显示)
|
||
const isPurchaseTypeDetermined = computed(() => {
|
||
return dataForm.isSpecial !== '' && dataForm.isCentralized !== '' && dataForm.budget != null && Number(dataForm.budget) > 0;
|
||
});
|
||
// 是否显示“部门自行采购/学校统一采购”区块:查看/编辑/流程嵌入/已保存过 时直接显示;新增时仅当类型已明确后显示
|
||
const showPurchaseDetailBlocks = computed(() => {
|
||
return !!isViewMode.value || !!isFlowEmbed.value || !!dataForm.id || isPurchaseTypeDetermined.value;
|
||
});
|
||
|
||
// 学校统一采购时采购形式默认值(不由用户选择):>=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 >= BUDGET_GOV_PURCHASE_THRESHOLD.value) return '1'; // 政府采购
|
||
if (budget >= BUDGET_DEPT_PURCHASE_THRESHOLD.value && budget < BUDGET_GOV_PURCHASE_THRESHOLD.value) {
|
||
if (dataForm.isCentralized === '0') return '2'; // 集采=否 → 学校自主采购
|
||
if (dataForm.isCentralized === '1') return '1'; // 政府集中采购 → 政府采购
|
||
if (dataForm.isCentralized === '2') return '2'; // 学校集中采购 → 学校自主采购
|
||
}
|
||
return null;
|
||
});
|
||
|
||
// 学校统一采购时采购形式是否禁用
|
||
// 申请阶段:始终可选(根据默认值自动选中后,允许用户自行修改)
|
||
// 流程嵌入:采购中心节点可编辑,其他节点只读
|
||
const schoolUnifiedPurchaseFormDisabled = computed(() => {
|
||
// if (!isFlowEmbed.value) {
|
||
// return false;
|
||
// }
|
||
// 流程嵌入且为采购中心:放开编辑
|
||
if (isPurchaseCenter.value) {
|
||
return false;
|
||
}
|
||
// 其他流程节点只读
|
||
return true;
|
||
});
|
||
|
||
// 特殊情况字典 value:0否 1紧急 2单一 3进口
|
||
const isUrgentSpecial = computed(() => dataForm.isSpecial === '1');
|
||
|
||
// 是否为特殊情况(非0即为特殊情况:紧急、单一、进口)
|
||
const isSpecialCase = computed(() => {
|
||
return dataForm.isSpecial && dataForm.isSpecial !== '0';
|
||
});
|
||
|
||
// 第二步标题
|
||
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;
|
||
});
|
||
|
||
// 部门自行采购 & 采购途径=自行采购 & 特殊服务类目 → 采购方式固定网上商城
|
||
const isDeptSelfMallLocked = computed(() => {
|
||
return isDeptPurchase.value && !isEntrustCenterChannel.value && isSpecialServiceCategory.value;
|
||
});
|
||
|
||
// 委托采购中心方式自动判断:
|
||
// - 服务类:若末级节点 isMallService=0 且 isMallProject=0,则选“其他方式”,否则选“服务类网上商城”
|
||
// - 非服务类:默认选“其他方式”
|
||
const calcEntrustCenterType = (): 'service_online' | 'other' | '' => {
|
||
if (!isEntrustCenterChannel.value) 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.purchaseChannel, () => 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 >= BUDGET_DEPT_PURCHASE_THRESHOLD.value &&
|
||
budget < BUDGET_PUBLIC_SELECT_THRESHOLD.value &&
|
||
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 >= BUDGET_DEPT_PURCHASE_THRESHOLD.value &&
|
||
budget < BUDGET_PUBLIC_SELECT_THRESHOLD.value &&
|
||
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 >= BUDGET_DEPT_PURCHASE_THRESHOLD.value && budget < BUDGET_PUBLIC_SELECT_THRESHOLD.value && 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 >= BUDGET_PUBLIC_SELECT_THRESHOLD.value && budget < BUDGET_GOV_PURCHASE_THRESHOLD.value && 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 >= BUDGET_DEPT_PURCHASE_THRESHOLD.value && budget < BUDGET_PUBLIC_SELECT_THRESHOLD.value && isSpecialServiceCategory.value;
|
||
});
|
||
|
||
// 监听品目编码、预算金额、采购类型及采购途径变化,自动设置/清空采购方式
|
||
watch(
|
||
[
|
||
() => dataForm.categoryCode,
|
||
() => dataForm.budget,
|
||
() => isDeptPurchase.value,
|
||
() => isFlowEmbed.value,
|
||
() => dataForm.purchaseChannel,
|
||
() => isPurchaseCenter.value,
|
||
],
|
||
() => {
|
||
// 部门自行采购 & 采购途径为”委托采购中心采购”且为新增申请阶段:采购方式隐藏且不设置
|
||
// 注意:查看模式和编辑模式不清空已有的采购方式
|
||
if (isDeptPurchase.value && isEntrustCenterChannel.value && !isFlowEmbed.value && !isViewMode.value && !isEditMode.value) {
|
||
dataForm.purchaseType = '';
|
||
return;
|
||
}
|
||
|
||
// 部门自行采购 & 采购途径为“自行采购” & 特殊服务类目:固定网上商城(无论金额区间)
|
||
if (isDeptSelfMallLocked.value) {
|
||
const onlineMallOption = purchaseTypeDeptList.value.find((item) => item.value === DEPT_PURCHASE_TYPE.ONLINE_MALL);
|
||
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
|
||
dataForm.purchaseType = onlineMallOption.value;
|
||
}
|
||
// 已锁定网上商城,不再走后续自动推荐逻辑
|
||
return;
|
||
}
|
||
|
||
// 其他部门自行采购 & 采购途径为“自行采购”:在金额区间内自动推荐网上商城
|
||
if (isAutoSelectPurchaseType.value && isDeptPurchase.value && !isEntrustCenterChannel.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 (isDeptPurchase.value && isEntrustCenterChannel.value && isFlowEmbed.value && isPurchaseCenter.value) {
|
||
const onlineMallOption = purchaseTypeDeptList.value.find((item) => item.value === DEPT_PURCHASE_TYPE.ONLINE_MALL);
|
||
if (onlineMallOption && dataForm.purchaseType !== onlineMallOption.value) {
|
||
dataForm.purchaseType = onlineMallOption.value;
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 学校统一采购审批阶段:自动设置网上商城采购方式
|
||
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 }
|
||
);
|
||
|
||
// 下载模版:统一走后端接口,按原始文件下载(避免前端静态资源被当成 HTML 返回)
|
||
const downloadTemplate = async (type: string) => {
|
||
const templateMap: Record<string, { displayName: string }> = {
|
||
business_negotiation: { displayName: '商务洽谈表.doc' },
|
||
market_purchase_minutes: { displayName: '部门自行采购市场采购纪要.doc' },
|
||
inquiry: { displayName: '部门采购询价模版.doc' },
|
||
direct_select: { displayName: '服务商城项目需求模板(直选).doc' },
|
||
public_select: { displayName: '服务商城项目需求模板(公开比选).doc' },
|
||
invite_select: { displayName: '服务商城项目需求模板(邀请比选).doc' },
|
||
purchase_requirement: { displayName: '采购需求填报模板.doc' },
|
||
import_application: { displayName: '进口产品申请及专家论证意见表.doc' },
|
||
single_source: { displayName: '单一来源论专家证附件.docx' },
|
||
feasibility_report: { displayName: '项目可行性论证报告模板.doc' },
|
||
};
|
||
|
||
const template = templateMap[type];
|
||
if (!template) {
|
||
useMessage().error('模版不存在');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await other.downBlobFile(`/purchase/purchasingtemplate/download?type=${encodeURIComponent(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' },
|
||
],
|
||
purchaseChannel: [
|
||
{
|
||
required: true,
|
||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||
if (!isDeptPurchase.value) {
|
||
callback();
|
||
return;
|
||
}
|
||
if (!value || String(value).trim() === '') {
|
||
callback(new Error('请选择采购途径'));
|
||
return;
|
||
}
|
||
callback();
|
||
},
|
||
trigger: 'change',
|
||
},
|
||
],
|
||
purchaseType: [
|
||
{
|
||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||
// 学校统一采购:申请阶段不要求采购方式,由审批环节采购中心补充
|
||
if (!isDeptPurchase.value) {
|
||
callback();
|
||
return;
|
||
}
|
||
// 部门自行采购且采购途径为"委托采购中心采购"并且为申请阶段:此处不校验采购方式
|
||
if (isEntrustCenterChannel.value && !isFlowEmbed.value) {
|
||
callback();
|
||
return;
|
||
}
|
||
if (!value || String(value).trim() === '') {
|
||
callback(new Error('请选择采购方式'));
|
||
return;
|
||
}
|
||
callback();
|
||
},
|
||
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',
|
||
},
|
||
],
|
||
schoolBusinessLeaderUserId: [
|
||
{
|
||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||
// 仅非特殊情况时校验
|
||
if (!isDeptPurchase.value && !isSpecialCase.value) {
|
||
if (!value || String(value).trim() === '') {
|
||
callback(new Error('请选择业务分管校领导'));
|
||
return;
|
||
}
|
||
}
|
||
callback();
|
||
},
|
||
trigger: 'change',
|
||
},
|
||
],
|
||
purchaseManagerUserId: [
|
||
{
|
||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||
// 仅特殊情况时校验
|
||
if (!isDeptPurchase.value && isSpecialCase.value) {
|
||
if (!value || String(value).trim() === '') {
|
||
callback(new Error('请选择采购分管校领导'));
|
||
return;
|
||
}
|
||
}
|
||
callback();
|
||
},
|
||
trigger: 'change',
|
||
},
|
||
],
|
||
negotiationReason: [
|
||
{
|
||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||
if (isPurchaseType(DEPT_PURCHASE_TYPE.BUSINESS_NEGOTIATION)) {
|
||
if (!value || String(value).trim() === '') {
|
||
callback(new Error('采购方式为商务洽谈时,洽谈理由不能为空'));
|
||
return;
|
||
}
|
||
}
|
||
callback();
|
||
},
|
||
trigger: 'blur',
|
||
},
|
||
],
|
||
});
|
||
|
||
// 取消
|
||
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(String(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 != null ? String(detail.purchaseMode) : '',
|
||
purchaseType:
|
||
detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER
|
||
? ''
|
||
: detail.purchaseType != null
|
||
? String(detail.purchaseType)
|
||
: detail.purchaseTypeUnion != null
|
||
? String(detail.purchaseTypeUnion)
|
||
: '',
|
||
purchaseChannel:
|
||
(detail as any).purchaseChannel ?? (detail.purchaseType === DEPT_PURCHASE_TYPE.ENTRUST_CENTER ? PURCHASE_CHANNEL.ENTRUST_CENTER : ''),
|
||
purchaseTypeUnion: detail.purchaseTypeUnion != null ? String(detail.purchaseTypeUnion) : '',
|
||
categoryCode: detail.categoryCode ?? '',
|
||
remark: detail.remark ?? '',
|
||
status: detail.status ?? '',
|
||
createBy: detail.createBy ?? '',
|
||
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 ?? '',
|
||
schoolBusinessLeaderUserId: detail.schoolBusinessLeaderUserId ?? '',
|
||
schoolBusinessLeaderName: detail.schoolBusinessLeaderName ?? '',
|
||
purchaseManagerUserId: detail.purchaseManagerUserId ?? '',
|
||
purchaseManagerName: detail.purchaseManagerName ?? '',
|
||
otherMaterials: detail.otherMaterials ?? '',
|
||
implementType: detail.implementType ?? '',
|
||
fileFlowInstId: detail.fileFlowInstId ?? '',
|
||
fileFlowStatus: detail.fileFlowStatus ?? '',
|
||
agentId: detail.agentId ?? '',
|
||
agentName: detail.agentName ?? '',
|
||
representorName: detail.representorName ?? '',
|
||
representorType: detail.representorType ?? '',
|
||
negotiationReason: detail.negotiationReason ?? '',
|
||
});
|
||
setCategoryCodePath();
|
||
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: { id?: string; remark?: string; fileTitle?: string }) {
|
||
// 优先使用文件ID下载
|
||
if (file?.id) {
|
||
const url = `/purchase/purchasingfiles/downloadById?fileId=${encodeURIComponent(file.id)}`;
|
||
other.downBlobFile(url, {}, file.fileTitle || '招标文件');
|
||
return;
|
||
}
|
||
// 兼容旧数据:使用文件路径下载
|
||
if (file?.remark) {
|
||
const url = `/purchase/purchasingfiles/download?fileName=${encodeURIComponent(file.remark)}&fileTitle=${encodeURIComponent(
|
||
file.fileTitle || '招标文件'
|
||
)}`;
|
||
other.downBlobFile(url, {}, file.fileTitle || '招标文件');
|
||
return;
|
||
}
|
||
useMessage().warning('无法获取文件信息');
|
||
}
|
||
|
||
/** 流程嵌入时提供给 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;
|
||
if (isApplicant.value) {
|
||
flowFormDisabled.value = false;
|
||
} else {
|
||
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',
|
||
'deptSelfMeetingMinutes', // 部门自行采购会议纪要
|
||
'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,
|
||
}))
|
||
.filter((item: any) => item.value !== DEPT_PURCHASE_TYPE.ENTRUST_CENTER)
|
||
: [];
|
||
} catch (err) {
|
||
purchaseTypeDeptList.value = [];
|
||
}
|
||
};
|
||
|
||
// 获取部门采购方式字典(委托采购中心采购时使用)
|
||
const getPurchaseTypeDeptDelegationDict = async () => {
|
||
try {
|
||
const res = await getDicts('PURCHASE_TYPE_DEPT_DELEGATION');
|
||
purchaseTypeDeptDelegationList.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) {
|
||
purchaseTypeDeptDelegationList.value = [];
|
||
}
|
||
};
|
||
|
||
/** 部门采购方式下拉选项:根据采购途径动态切换字典 */
|
||
const purchaseTypeDeptOptions = computed(() => {
|
||
if (isEntrustCenterChannel.value) {
|
||
return purchaseTypeDeptDelegationList.value;
|
||
}
|
||
return 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,
|
||
}));
|
||
|
||
businessDeptList.value.push({
|
||
id: '0',
|
||
deptId: '0',
|
||
deptName: '无',
|
||
userId: '0',
|
||
name: '无',
|
||
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 getPurchasingManagerListData = async () => {
|
||
try {
|
||
const res = await getPurchasingManagerList({ records: 1000 }); // 获取所有数据
|
||
if (res.data && res.data.records) {
|
||
purchasingManagerList.value = res.data.records.map((item: any) => ({
|
||
id: item.id,
|
||
userId: item.userId,
|
||
name: item.name,
|
||
username: item.username,
|
||
deptName: item.deptName,
|
||
}));
|
||
}
|
||
} catch (err) {
|
||
console.error('获取采购分管列表失败:', err);
|
||
purchasingManagerList.value = [];
|
||
}
|
||
};
|
||
|
||
// 获取业务分管校领导列表
|
||
const getBusinessLeaderListData = async () => {
|
||
try {
|
||
const res = await getBusinessLeaderList({ size: 1000 }); // 获取所有数据
|
||
if (res.data && res.data.records) {
|
||
businessLeaderList.value = res.data.records.map((item: any) => ({
|
||
id: item.id,
|
||
userId: item.userId,
|
||
name: item.name,
|
||
username: item.username,
|
||
}));
|
||
}
|
||
} catch (err) {
|
||
console.error('获取业务分管校领导列表失败:', err);
|
||
businessLeaderList.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 = '';
|
||
}
|
||
};
|
||
|
||
// 处理采购分管选择变化
|
||
const handlePurchaseManagerChange = (value: string) => {
|
||
if (value) {
|
||
const selected = purchasingManagerList.value.find((item) => item.userId === value);
|
||
if (selected) {
|
||
dataForm.purchaseManagerUserId = selected.userId;
|
||
dataForm.purchaseManagerName = selected.name || '';
|
||
}
|
||
} else {
|
||
dataForm.purchaseManagerUserId = '';
|
||
dataForm.purchaseManagerName = '';
|
||
}
|
||
};
|
||
|
||
// 处理业务分管校领导选择变化
|
||
const handleBusinessLeaderChange = (value: string) => {
|
||
if (value) {
|
||
const selected = businessLeaderList.value.find((item) => item.userId === value);
|
||
if (selected) {
|
||
dataForm.schoolBusinessLeaderUserId = selected.userId;
|
||
dataForm.schoolBusinessLeaderName = selected.name || '';
|
||
}
|
||
} else {
|
||
dataForm.schoolBusinessLeaderUserId = '';
|
||
dataForm.schoolBusinessLeaderName = '';
|
||
}
|
||
};
|
||
|
||
// 处理文件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',
|
||
'deptSelfMeetingMinutes', // 部门自行采购会议纪要
|
||
'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('/purchase/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',
|
||
'deptSelfMeetingMinutes', // 部门自行采购会议纪要
|
||
'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('/purchase/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(),
|
||
getPurchaseTypeDeptDelegationDict(),
|
||
getPurchaseModeSchoolDict(),
|
||
getPurchaseTypeUnionDict(),
|
||
getBusinessDeptListData(),
|
||
getSchoolLeaderListData(),
|
||
getPurchasingManagerListData(),
|
||
getBusinessLeaderListData(),
|
||
]);
|
||
|
||
// 编辑/查看:从 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>
|