1485 lines
46 KiB
Vue
1485 lines
46 KiB
Vue
<template>
|
||
<div class="modern-page-container">
|
||
<div class="page-wrapper">
|
||
<!-- 搜索表单卡片 -->
|
||
<el-card v-show="showSearch" class="search-card" shadow="never">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span class="card-title">
|
||
<el-icon class="title-icon"><Search /></el-icon>
|
||
筛选条件
|
||
</span>
|
||
</div>
|
||
</template>
|
||
<el-form :model="state.queryForm" ref="searchFormRef" :inline="true" @keyup.enter="getDataList" class="search-form">
|
||
<el-form-item label="采购编号" prop="purchaseNo">
|
||
<el-input v-model="state.queryForm.purchaseNo" placeholder="请输入采购编号" clearable style="width: 200px" />
|
||
</el-form-item>
|
||
<el-form-item label="采购项目名称" prop="projectName">
|
||
<el-input v-model="state.queryForm.projectName" placeholder="请输入采购项目名称" clearable style="width: 200px" />
|
||
</el-form-item>
|
||
<el-form-item label="项目类别" prop="projectType">
|
||
<el-select v-model="state.queryForm.projectType" placeholder="请选择项目类别" clearable style="width: 200px">
|
||
<el-option label="货物" value="A" />
|
||
<el-option label="工程" value="B" />
|
||
<el-option label="服务" value="C" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="状态" prop="status">
|
||
<el-select v-model="state.queryForm.status" placeholder="请选择状态" clearable style="width: 200px">
|
||
<el-option label="暂存" value="-1" />
|
||
<el-option label="运行中" value="0" />
|
||
<el-option label="完成" value="1" />
|
||
<el-option label="作废" value="2" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="是否集采" prop="isCentralized">
|
||
<el-select v-model="state.queryForm.isCentralized" placeholder="请选择是否集采" clearable style="width: 200px">
|
||
<el-option v-for="item in dictData.isCentralizedList" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="是否特殊" prop="isSpecial">
|
||
<el-select v-model="state.queryForm.isSpecial" placeholder="请选择是否特殊" clearable style="width: 200px">
|
||
<el-option v-for="item in dictData.isSpecialList" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="采购形式" prop="purchaseMode">
|
||
<el-select
|
||
v-model="state.queryForm.purchaseMode"
|
||
placeholder="请选择采购形式"
|
||
clearable
|
||
style="width: 200px"
|
||
@change="handlePurchaseModeChange"
|
||
>
|
||
<el-option label="部门自行采购" value="1" />
|
||
<el-option label="学校统一采购" value="2" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item v-if="state.queryForm.purchaseMode === '1'" label="采购途径" prop="purchaseChannel">
|
||
<el-select
|
||
v-model="state.queryForm.purchaseChannel"
|
||
placeholder="请选择采购途径"
|
||
clearable
|
||
style="width: 200px"
|
||
@change="handlePurchaseChannelChange"
|
||
>
|
||
<el-option label="自行采购" value="1" />
|
||
<el-option label="委托采购中心采购" value="2" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item v-if="showPurchaseTypeSelect" label="采购方式" prop="purchaseType">
|
||
<el-select v-model="state.queryForm.purchaseType" placeholder="请选择采购方式" clearable style="width: 200px">
|
||
<el-option v-for="item in purchaseTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="需求部门" prop="deptId">
|
||
<el-select v-model="state.queryForm.deptCode" placeholder="请选择需求部门" clearable filterable style="width: 200px">
|
||
<el-option v-for="item in secondDeptList" :key="item.id" :label="item.deptName" :value="item.deptCode" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" icon="Search" @click="getDataList">查询</el-button>
|
||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||
<el-button type="success" icon="Download" @click="handleExport">导出</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 内容卡片 -->
|
||
<el-card class="content-card" shadow="never">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span class="card-title">
|
||
<el-icon class="title-icon"><Document /></el-icon>
|
||
采购申请管理
|
||
</span>
|
||
<div class="header-actions">
|
||
<!-- <el-button icon="QuestionFilled" link type="primary"> 采购申请操作说明文档下载</el-button>-->
|
||
<el-button icon="FolderAdd" type="primary" @click="handleAdd" v-auth="'purchase_purchasingapply_add'"> 新增</el-button>
|
||
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList" />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 表格 -->
|
||
<el-table
|
||
ref="tableRef"
|
||
:data="state.dataList"
|
||
v-loading="state.loading"
|
||
stripe
|
||
:cell-style="tableStyle.cellStyle"
|
||
:header-cell-style="tableStyle.headerCellStyle"
|
||
class="modern-table"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="50" align="center" />
|
||
<el-table-column type="index" label="序号" width="50" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<List />
|
||
</el-icon>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="purchaseNo" label="申请单编号" min-width="170">
|
||
<template #header>
|
||
<el-icon>
|
||
<DocumentCopy />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">申请单编号</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<div class="purchase-no-cell">
|
||
<el-tooltip :content="scope.row.purchaseNo" placement="top" :show-after="0" v-if="scope.row.purchaseNo">
|
||
<span class="purchase-no-text">{{ scope.row.purchaseNo }}</span>
|
||
</el-tooltip>
|
||
<el-button
|
||
v-if="scope.row.purchaseNo"
|
||
type="primary"
|
||
link
|
||
size="small"
|
||
class="copy-btn"
|
||
@click.stop="copyToClipboard(scope.row.purchaseNo)"
|
||
>
|
||
<el-icon>
|
||
<CopyDocument />
|
||
</el-icon>
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="projectName" label="项目名称" min-width="200" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon>
|
||
<Document />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">项目名称</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<div class="project-name-cell">
|
||
<!-- 特殊情况标记 -->
|
||
<el-tooltip
|
||
v-if="scope.row.isSpecial && String(scope.row.isSpecial) !== '0'"
|
||
:content="getSpecialTooltip(scope.row.isSpecial)"
|
||
placement="top"
|
||
>
|
||
<span :class="['special-badge', `special-${scope.row.isSpecial}`]">{{ getSpecialBadgeText(scope.row.isSpecial) }}</span>
|
||
</el-tooltip>
|
||
<!-- 集采标记 -->
|
||
<el-tooltip v-if="scope.row.isCentralized && String(scope.row.isCentralized) !== '0'" content="政府集中采购" placement="top">
|
||
<span class="centralized-badge">政</span>
|
||
</el-tooltip>
|
||
<span class="project-name-text">{{ scope.row.projectName }}</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="applyDate" label="填报日期" width="120" align="center" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon>
|
||
<Calendar />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">填报日期</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="deptName" label="需求部门" min-width="150" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon>
|
||
<OfficeBuilding />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">需求部门</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="projectType" label="类别" width="80" align="left" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon>
|
||
<Collection />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">类别</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<div>
|
||
<el-tag v-if="scope.row.projectType === 'A'" type="success" style="margin-right: 8px">货物</el-tag>
|
||
<el-tag v-else-if="scope.row.projectType === 'B'" type="warning" style="margin-right: 8px">工程</el-tag>
|
||
<el-tag v-else-if="scope.row.projectType === 'C'" type="info" style="margin-right: 8px">服务</el-tag>
|
||
<span v-if="scope.row.categoryName" style="color: #606266; font-size: 12px">
|
||
{{ scope.row.categoryName }}
|
||
</span>
|
||
<span v-else-if="scope.row.categoryCode" style="color: #909399; font-size: 12px">
|
||
{{ scope.row.categoryCode }}
|
||
</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="budget" label="预算(元)" width="90" align="right">
|
||
<template #header>
|
||
<el-icon>
|
||
<Money />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">预算</span>
|
||
</template>
|
||
<template #default="scope">
|
||
{{ scope.row.budget ? Number(scope.row.budget).toLocaleString() : '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column prop="purchaseMode" label="采购形式" width="160" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<Shop />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">采购形式</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<div class="purchase-mode-cell">
|
||
<el-tag v-if="scope.row.purchaseMode === '1'" type="success">部门自行采购</el-tag>
|
||
<el-tag v-else-if="scope.row.purchaseMode === '2'" type="primary">学校统一采购</el-tag>
|
||
<span v-else>-</span>
|
||
<el-tag v-if="scope.row.purchaseMode === '1' && scope.row.purchaseChannel === '2'" type="warning" size="small" class="entrust-tag"
|
||
>委
|
||
</el-tag>
|
||
<el-tooltip
|
||
v-if="
|
||
scope.row.status === '1' && scope.row.purchaseMode === '1' && scope.row.purchaseChannel === '1' && scope.row.purchaseType !== '6'
|
||
"
|
||
:content="getSupplementTooltip(scope.row)"
|
||
placement="top"
|
||
>
|
||
<el-icon :class="['supplement-icon', getSupplementIconClass(scope.row)]" @click.stop="handleShowSupplement(scope.row)">
|
||
<component :is="getSupplementIcon(scope.row)" />
|
||
</el-icon>
|
||
</el-tooltip>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="purchaseType" label="采购方式" width="120" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<Shop />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">采购方式</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<el-tag v-if="scope.row.purchaseTypeLabel" type="primary">{{ scope.row.purchaseTypeLabel }}</el-tag>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="status" label="审核状态" width="100" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<InfoFilled />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">审核状态</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<el-tooltip v-if="scope.row.flowInstId" content="点击查看审批过程" placement="top">
|
||
<el-tag v-if="scope.row.status === '-2'" type="info" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>撤回
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '-1'" type="warning" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>暂存
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '0'" type="primary" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>运行中
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '1'" type="success" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>完成
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '2'" type="danger" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>作废
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '3'" type="info" class="status-tag-clickable" @click="handleShowFlowComment(scope.row)"
|
||
>终止
|
||
</el-tag>
|
||
<span v-else>-</span>
|
||
</el-tooltip>
|
||
<template v-else>
|
||
<el-tag v-if="scope.row.status === '-2'" type="info">撤回</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '-1'" type="warning">暂存</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '0'" type="primary">运行中</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '1'" type="success">完成</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '2'" type="danger">作废</el-tag>
|
||
<el-tag v-else-if="scope.row.status === '3'" type="info">终止</el-tag>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</template>
|
||
</el-table-column>
|
||
<!-- 招标审批列 -->
|
||
<el-table-column prop="fileFlowStatus" label="招标审批" width="100" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<DocumentChecked />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">招标审批</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<template v-if="scope.row.fileFlowInstId">
|
||
<el-tooltip v-if="scope.row.fileFlowInstId" content="点击查看审批流程及招标文件" placement="top">
|
||
<el-tag v-if="scope.row.fileFlowStatus === '0'" type="primary" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"
|
||
>运行中
|
||
</el-tag>
|
||
<el-tag
|
||
v-else-if="scope.row.fileFlowStatus === '1'"
|
||
type="success"
|
||
class="status-tag-clickable"
|
||
@click="handleShowDocAudit(scope.row)"
|
||
>完成
|
||
</el-tag>
|
||
<el-tag
|
||
v-else-if="scope.row.fileFlowStatus === '2'"
|
||
type="danger"
|
||
class="status-tag-clickable"
|
||
@click="handleShowDocAudit(scope.row)"
|
||
>作废
|
||
</el-tag>
|
||
<el-tag v-else-if="scope.row.fileFlowStatus === '3'" type="info" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)"
|
||
>终止
|
||
</el-tag>
|
||
<el-tag v-else type="warning" class="status-tag-clickable" @click="handleShowDocAudit(scope.row)">未知</el-tag>
|
||
</el-tooltip>
|
||
<el-tag v-else type="info">未发起</el-tag>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<!-- 采购合同列 -->
|
||
<el-table-column prop="contractFlowStatus" label="采购合同" width="100" align="center">
|
||
<template #header>
|
||
<el-icon>
|
||
<Tickets />
|
||
</el-icon>
|
||
<span style="margin-left: 4px">采购合同</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<template v-if="scope.row.status === '1'">
|
||
<el-tooltip v-if="scope.row.contractFlowStatus" content="点击查看合同详情" placement="top">
|
||
<el-tag v-if="scope.row.contractFlowStatus === '-1'" type="info" class="status-tag-clickable" @click="handleEditContract(scope.row)"
|
||
>已上传
|
||
</el-tag>
|
||
<el-tag
|
||
v-else-if="scope.row.contractFlowStatus === '0'"
|
||
type="warning"
|
||
class="status-tag-clickable"
|
||
@click="handleShowContractDetail(scope.row)"
|
||
>运行中
|
||
</el-tag>
|
||
<el-tag
|
||
v-else-if="scope.row.contractFlowStatus === '1'"
|
||
type="success"
|
||
class="status-tag-clickable"
|
||
@click="handleShowContractDetail(scope.row)"
|
||
>已完成
|
||
</el-tag>
|
||
<el-tag
|
||
v-else-if="scope.row.contractFlowStatus === '2'"
|
||
type="info"
|
||
class="status-tag-clickable"
|
||
@click="handleShowContractDetail(scope.row)"
|
||
>已作废
|
||
</el-tag>
|
||
</el-tooltip>
|
||
<el-button v-else type="primary" link size="small" @click="handleAddContract(scope.row)">添加合同</el-button>
|
||
</template>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="操作" align="center" fixed="right" width="150">
|
||
<template #default="scope">
|
||
<div class="op-cell">
|
||
<el-button type="primary" link icon="View" @click="handleView(scope.row)"> 查看</el-button>
|
||
<ActionDropdown :items="getActionMenuItems(scope.row)" @command="(command) => handleMoreCommand(command, scope.row)" />
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<pagination
|
||
v-if="state.pagination && state.pagination.total && state.pagination.total > 0"
|
||
:total="state.pagination.total"
|
||
:current="state.pagination.current"
|
||
:size="state.pagination.size"
|
||
@sizeChange="sizeChangeHandle"
|
||
@currentChange="currentChangeHandle"
|
||
/>
|
||
</el-card>
|
||
</div>
|
||
|
||
<!-- 新增/编辑/查看:统一使用 form.vue 弹窗(iframe 引入 add.vue) -->
|
||
<FormDialog ref="formDialogRef" :dict-data="dictData" @refresh="getDataList" />
|
||
|
||
<!-- 履约验收弹窗 -->
|
||
<PurchasingAcceptModal ref="acceptModalRef" />
|
||
|
||
<!-- 查看审批过程(申请单审批 / 文件审批) -->
|
||
<el-dialog
|
||
v-model="showFlowComment"
|
||
v-if="showFlowComment"
|
||
:title="currFlowCommentType === 'file' ? '查看文件审批过程' : '查看审批过程'"
|
||
top="20px"
|
||
width="90%"
|
||
append-to-body
|
||
destroy-on-close
|
||
@close="
|
||
currFlowJob = null;
|
||
currFlowCommentType = 'apply';
|
||
"
|
||
>
|
||
<FlowCommentTimeline v-if="currFlowJob" :key="String(currFlowJob.flowInstId) + currFlowCommentType" :curr-job="currFlowJob" />
|
||
</el-dialog>
|
||
|
||
<!-- 实施采购:iframe 嵌入 implement.vue,供列表与流程页面使用 -->
|
||
<ImplementForm ref="implementFormRef" />
|
||
|
||
<!-- 文件归档弹窗 -->
|
||
<FileArchiveDialog ref="fileArchiveDialogRef" />
|
||
|
||
<!-- 更新材料弹窗 -->
|
||
<UpdateFilesDialog ref="updateFilesDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 合同弹窗 -->
|
||
<ContractDialog ref="contractDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 补充材料弹窗 -->
|
||
<SupplementFilesDialog ref="supplementFilesDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 补充材料查看弹窗 -->
|
||
<SupplementViewDialog ref="supplementViewDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 招标文件审批查看弹窗 -->
|
||
<DocAuditViewDialog ref="docAuditViewDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 采购合同弹窗 -->
|
||
<PurchaseContractDialog ref="purchaseContractDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 采购合同详情弹窗 -->
|
||
<PurchaseContractDetailDialog ref="purchaseContractDetailDialogRef" />
|
||
|
||
<!-- 采购合同弹窗 -->
|
||
<PurchaseContractDialog ref="purchaseContractDialogRef" @refresh="getDataList" />
|
||
|
||
<!-- 采购合同详情弹窗 -->
|
||
<PurchaseContractDetailDialog ref="purchaseContractDetailDialogRef" />
|
||
|
||
|
||
|
||
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts" name="PurchasingRequisition">
|
||
import { ref, reactive, defineAsyncComponent, onMounted, computed } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { BasicTableProps, useTable } from '/@/hooks/table';
|
||
import {
|
||
getPage,
|
||
delObj,
|
||
submitObj,
|
||
getApplyTemplateDownloadUrl,
|
||
getFileApplyTemplateDownloadUrl,
|
||
exportPurchaseApply,
|
||
} from '/@/api/purchase/purchasingrequisition';
|
||
import { useMessage, useMessageBox } from '/@/hooks/message';
|
||
import { useAuth } from '/@/hooks/auth';
|
||
import { getDicts } from '/@/api/admin/dict';
|
||
import { getTree } from '/@/api/purchase/purchasingcategory';
|
||
import {
|
||
List,
|
||
Document,
|
||
DocumentCopy,
|
||
Search,
|
||
Money,
|
||
CircleCheck,
|
||
InfoFilled,
|
||
Calendar,
|
||
OfficeBuilding,
|
||
Warning,
|
||
DocumentChecked,
|
||
Tickets,
|
||
Edit,
|
||
Delete,
|
||
Upload,
|
||
FolderOpened,
|
||
Download,
|
||
User,
|
||
RefreshRight,
|
||
Shop,
|
||
CopyDocument,
|
||
Select,
|
||
CloseBold,
|
||
} from '@element-plus/icons-vue';
|
||
import other from '/@/utils/other';
|
||
import { Session } from '/@/utils/storage';
|
||
import { getByPurchaseId } from '/@/api/purchase/purchasingcontract';
|
||
import { getDeptListByLevelTwo } from '/@/api/basic/basicdept';
|
||
|
||
// 角色常量
|
||
const PURCHASE_DEPT_AUDIT_ROLE_CODE = 'PURCHASE_DEPT_AUDIT';
|
||
const roleCode = computed(() => Session.getRoleCode() || '');
|
||
const isDeptAuditRole = computed(() => roleCode.value === PURCHASE_DEPT_AUDIT_ROLE_CODE);
|
||
|
||
// 引入组件
|
||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||
const ImplementForm = defineAsyncComponent(() => import('./implementForm.vue'));
|
||
const ActionDropdown = defineAsyncComponent(() => import('/@/components/tools/action-dropdown.vue'));
|
||
const PurchasingAcceptModal = defineAsyncComponent(() => import('./accept/PurchasingAcceptModal.vue'));
|
||
const FlowCommentTimeline = defineAsyncComponent(() => import('/@/views/jsonflow/comment/timeline.vue'));
|
||
const FileArchiveDialog = defineAsyncComponent(() => import('./FileArchiveDialog.vue'));
|
||
const UpdateFilesDialog = defineAsyncComponent(() => import('./UpdateFilesDialog.vue'));
|
||
|
||
const SupplementFilesDialog = defineAsyncComponent(() => import('./SupplementFilesDialog.vue'));
|
||
const SupplementViewDialog = defineAsyncComponent(() => import('./SupplementViewDialog.vue'));
|
||
const DocAuditViewDialog = defineAsyncComponent(() => import('./DocAuditViewDialog.vue'));
|
||
const PurchaseContractDialog = defineAsyncComponent(() => import('./PurchaseContractDialog.vue'));
|
||
const PurchaseContractDetailDialog = defineAsyncComponent(() => import('./PurchaseContractDetailDialog.vue'));
|
||
// const DocAuditDialog = defineAsyncComponent(() => import('./docAudit/DocAuditDialog.vue'));
|
||
|
||
// 字典数据和品目树数据
|
||
const dictData = ref({
|
||
fundSourceList: [] as any[],
|
||
isCentralizedList: [] as any[],
|
||
isSpecialList: [] as any[],
|
||
purchaseTypeDeptList: [] as any[],
|
||
purchaseModeSchoolList: [] as any[],
|
||
purchaseTypeUnionList: [] as any[],
|
||
categoryTreeData: [] as any[],
|
||
});
|
||
|
||
// 搜索条件相关数据
|
||
const purchaseTypeDeptDelegationList = ref<any[]>([]); // 委托采购中心采购方式字典
|
||
const secondDeptList = ref<any[]>([]); // 二级部门列表
|
||
|
||
// 是否显示采购方式选择框
|
||
const showPurchaseTypeSelect = computed(() => {
|
||
const mode = state.queryForm.purchaseMode;
|
||
if (mode === '2') {
|
||
// 学校统一采购:显示采购方式
|
||
return true;
|
||
} else if (mode === '1') {
|
||
// 部门自行采购:需要先选择采购途径
|
||
return !!state.queryForm.purchaseChannel;
|
||
}
|
||
return false;
|
||
});
|
||
|
||
// 采购方式选项(根据采购形式和采购途径动态变化)
|
||
const purchaseTypeOptions = computed(() => {
|
||
const mode = state.queryForm.purchaseMode;
|
||
if (mode === '2') {
|
||
// 学校统一采购:使用 UNION_PURCHASE_TYPE 字典
|
||
return dictData.value.purchaseTypeUnionList;
|
||
} else if (mode === '1') {
|
||
const channel = state.queryForm.purchaseChannel;
|
||
if (channel === '1') {
|
||
// 自行采购:使用 DEPT_PURCHASE_TYPE 字典
|
||
return dictData.value.purchaseTypeDeptList;
|
||
} else if (channel === '2') {
|
||
// 委托采购中心采购:使用 PURCHASE_TYPE_DEPT_DELEGATION 字典
|
||
return purchaseTypeDeptDelegationList.value;
|
||
}
|
||
}
|
||
return [];
|
||
});
|
||
|
||
// 采购形式变化时清空采购途径和采购方式
|
||
const handlePurchaseModeChange = () => {
|
||
state.queryForm.purchaseChannel = '';
|
||
state.queryForm.purchaseType = '';
|
||
};
|
||
|
||
// 采购途径变化时清空采购方式
|
||
const handlePurchaseChannelChange = () => {
|
||
state.queryForm.purchaseType = '';
|
||
};
|
||
|
||
// 定义变量内容
|
||
const router = useRouter();
|
||
const tableRef = ref();
|
||
const formDialogRef = ref();
|
||
const acceptModalRef = ref();
|
||
const searchFormRef = ref();
|
||
const showSearch = ref(true);
|
||
const docAuditDialogRef = ref();
|
||
const { hasAuth } = useAuth();
|
||
/** 审批过程弹窗:是否显示、当前行对应的流程 job(供 Comment 组件用)、类型(申请单/文件) */
|
||
const showFlowComment = ref(false);
|
||
const currFlowJob = ref<{ id?: number; flowInstId?: number } | null>(null);
|
||
const currFlowCommentType = ref<'apply' | 'file'>('apply');
|
||
|
||
const implementFormRef = ref();
|
||
const fileArchiveDialogRef = ref();
|
||
const updateFilesDialogRef = ref();
|
||
const contractDialogRef = ref();
|
||
const supplementFilesDialogRef = ref();
|
||
const supplementViewDialogRef = ref();
|
||
const docAuditViewDialogRef = ref();
|
||
const purchaseContractDialogRef = ref();
|
||
const purchaseContractDetailDialogRef = ref();
|
||
|
||
const selectedRows = ref<any[]>([]);
|
||
|
||
/** 采购代表弹窗 */
|
||
const representorDialogVisible = ref(false);
|
||
const representorCurrentRow = ref<any>(null);
|
||
const representorForm = reactive({
|
||
mode: 'single' as 'single' | 'multi',
|
||
teacherNo: '',
|
||
multiIds: [] as string[],
|
||
identity: 'purchase_rep' as 'purchase_rep' | 'judge',
|
||
});
|
||
|
||
const representorSubmitting = ref(false);
|
||
|
||
|
||
|
||
/**
|
||
* 定义响应式表格数据
|
||
*/
|
||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||
pageList: getPage,
|
||
queryForm: {
|
||
purchaseNo: '',
|
||
projectName: '',
|
||
projectType: '',
|
||
status: '',
|
||
isCentralized: '',
|
||
isSpecial: '',
|
||
purchaseMode: '',
|
||
purchaseChannel: '',
|
||
purchaseType: '',
|
||
deptCode: '',
|
||
},
|
||
createdIsNeed: true,
|
||
});
|
||
|
||
/**
|
||
* 使用 useTable 定义表格相关操作
|
||
*/
|
||
const { getDataList, tableStyle, sizeChangeHandle, currentChangeHandle } = useTable(state);
|
||
|
||
/**
|
||
* 重置搜索表单
|
||
*/
|
||
const handleReset = () => {
|
||
searchFormRef.value?.resetFields();
|
||
getDataList();
|
||
};
|
||
|
||
/**
|
||
* 新增采购申请 - 统一通过 form.vue 弹窗(iframe 引入 add.vue)
|
||
*/
|
||
const handleAdd = () => {
|
||
formDialogRef.value?.openDialog('add');
|
||
};
|
||
|
||
/**
|
||
/**
|
||
* 点击审核状态:若有流程实例则打开「查看审批过程」弹窗(参考 hi-job.vue)
|
||
* @param row - 当前行数据(需含 flowInstId)
|
||
*/
|
||
/** 点击审核状态:打开申请单审批过程 */
|
||
const handleShowFlowComment = (row: any) => {
|
||
if (!row?.flowInstId) {
|
||
useMessage().info('暂存状态无审批过程');
|
||
return;
|
||
}
|
||
currFlowCommentType.value = 'apply';
|
||
currFlowJob.value = { id: row.id, flowInstId: row.flowInstId };
|
||
showFlowComment.value = true;
|
||
};
|
||
|
||
/** 点击文件审批状态:打开文件审批过程 */
|
||
const handleShowFileFlowComment = (row: any) => {
|
||
if (!row?.fileFlowInstId) {
|
||
useMessage().info('未发起文件审批流程');
|
||
return;
|
||
}
|
||
currFlowCommentType.value = 'file';
|
||
const flowInstId = typeof row.fileFlowInstId === 'string' ? parseInt(row.fileFlowInstId, 10) : row.fileFlowInstId;
|
||
currFlowJob.value = { id: row.id, flowInstId: Number.isNaN(flowInstId) ? row.fileFlowInstId : flowInstId };
|
||
showFlowComment.value = true;
|
||
};
|
||
|
||
/** 点击招标审批状态:打开招标文件审批查看弹窗 */
|
||
const handleShowDocAudit = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
docAuditViewDialogRef.value?.open(String(id), row);
|
||
};
|
||
|
||
const SUPPLEMENT_STATUS_MAP: Record<string, { icon: any; class: string; tooltip: string }> = {
|
||
'1': { icon: Select, class: 'supplement-done', tooltip: '补充材料已完成,点击查看' },
|
||
'0': { icon: CloseBold, class: 'supplement-running', tooltip: '补充材料审批中,点击查看' },
|
||
'-1': { icon: CloseBold, class: 'supplement-pending', tooltip: '补充材料已暂存,点击查看' },
|
||
};
|
||
|
||
const getSupplementIcon = (row: any) => {
|
||
const status = row?.supplementFlowStatus;
|
||
if (status === '1') return Select;
|
||
return CloseBold;
|
||
};
|
||
|
||
const getSupplementIconClass = (row: any) => {
|
||
const status = row?.supplementFlowStatus;
|
||
if (status === '1') return 'supplement-done';
|
||
if (status === '0') return 'supplement-running';
|
||
return 'supplement-pending';
|
||
};
|
||
|
||
const getSupplementTooltip = (row: any) => {
|
||
const status = row?.supplementFlowStatus;
|
||
if (status === '1') return '补充材料已完成,点击查看';
|
||
if (status === '0') return '补充材料审批中,点击查看';
|
||
if (status === '-1') return '补充材料已暂存,点击查看';
|
||
return '未补充材料,点击查看';
|
||
};
|
||
|
||
/** 获取特殊情况标记文字 */
|
||
const getSpecialBadgeText = (isSpecial: string): string => {
|
||
const map: Record<string, string> = {
|
||
'1': '紧',
|
||
'2': '单',
|
||
'3': '进',
|
||
};
|
||
return map[String(isSpecial)] || '';
|
||
};
|
||
|
||
/** 获取特殊情况完整提示文字 */
|
||
const getSpecialTooltip = (isSpecial: string): string => {
|
||
const map: Record<string, string> = {
|
||
'1': '紧急采购',
|
||
'2': '单一来源采购',
|
||
'3': '进口产品采购',
|
||
};
|
||
return map[String(isSpecial)] || '';
|
||
};
|
||
|
||
const handleShowSupplement = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
supplementViewDialogRef.value?.open(String(id), row);
|
||
};
|
||
|
||
/** 点击添加合同:打开采购合同弹窗 */
|
||
const handleAddContract = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
purchaseContractDialogRef.value?.open(String(id), 'add');
|
||
};
|
||
|
||
/** 点击已上传合同:打开采购合同编辑弹窗 */
|
||
const handleEditContract = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
purchaseContractDialogRef.value?.open(String(id), 'edit');
|
||
};
|
||
|
||
/** 点击采购合同状态:打开采购合同详情弹窗 */
|
||
const handleShowContractDetail = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
// 已完成(contractFlowStatus='1')或已作废(contractFlowStatus='2')时为查看模式
|
||
// 运行中(contractFlowStatus='0')时也为查看模式(流程进行中不可编辑)
|
||
const mode: 'view' | 'edit' = row.contractFlowStatus === '1' || row.contractFlowStatus === '2' || row.contractFlowStatus === '0' ? 'view' : 'edit';
|
||
purchaseContractDetailDialogRef.value?.open(String(id), mode);
|
||
};
|
||
|
||
/**
|
||
* 打开查看对话框
|
||
* @param row - 当前行数据
|
||
*/
|
||
const handleView = (row: any) => {
|
||
formDialogRef.value?.openDialog('view', row);
|
||
};
|
||
|
||
/**
|
||
* 打开编辑对话框
|
||
* @param row - 当前行数据
|
||
*/
|
||
const handleEdit = (row: any) => {
|
||
formDialogRef.value?.openDialog('edit', row);
|
||
};
|
||
|
||
/**
|
||
* 履约验收
|
||
* @param row - 当前行数据
|
||
*/
|
||
const handleAccept = (row: any) => {
|
||
acceptModalRef.value?.open(row);
|
||
};
|
||
|
||
/** 打开实施采购(仅暂存状态可点;通过 iframe 嵌入 implement.vue) */
|
||
const handleImplement = (row: any) => {
|
||
implementFormRef.value?.openDialog(row);
|
||
};
|
||
|
||
/** 复制到剪贴板 */
|
||
const copyToClipboard = async (text: string) => {
|
||
if (!text) return;
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
useMessage().success('复制成功');
|
||
} catch (err) {
|
||
// 降级方案
|
||
const textarea = document.createElement('textarea');
|
||
textarea.value = text;
|
||
textarea.style.position = 'fixed';
|
||
textarea.style.opacity = '0';
|
||
document.body.appendChild(textarea);
|
||
textarea.select();
|
||
document.execCommand('copy');
|
||
document.body.removeChild(textarea);
|
||
useMessage().success('复制成功');
|
||
}
|
||
};
|
||
|
||
/** 打开招标文件审核 */
|
||
const handleDocAudit = (row: any) => {
|
||
docAuditDialogRef.value?.open(row);
|
||
};
|
||
|
||
/**
|
||
* 删除当前行
|
||
* @param row - 当前行数据
|
||
*/
|
||
const handleDelete = async (row: any) => {
|
||
try {
|
||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||
} catch {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await delObj({ id: row.id });
|
||
useMessage().success('删除成功');
|
||
getDataList();
|
||
} catch (err: any) {
|
||
useMessage().error(err.msg || '删除失败');
|
||
}
|
||
};
|
||
|
||
/** 暂存状态下提交采购申请(启动流程) */
|
||
const handleSubmit = async (row: any) => {
|
||
try {
|
||
await useMessageBox().confirm('确定要提交该采购申请并启动流程吗?');
|
||
} catch {
|
||
return;
|
||
}
|
||
try {
|
||
await submitObj({ id: row.id });
|
||
useMessage().success('提交成功');
|
||
getDataList();
|
||
} catch (err: any) {
|
||
useMessage().error(err?.msg || '提交失败');
|
||
}
|
||
};
|
||
|
||
/** 操作栏「更多」菜单项配置 */
|
||
const getActionMenuItems = (row: any) => {
|
||
const isTemp = row?.status === '-1';
|
||
const isRunning = row?.status === '0';
|
||
const isCompleted = row?.status === '1';
|
||
const items = [
|
||
{
|
||
command: 'edit',
|
||
label: '编辑',
|
||
icon: Edit,
|
||
visible: () => isTemp,
|
||
},
|
||
{
|
||
command: 'submit',
|
||
label: '提交',
|
||
icon: Upload,
|
||
visible: () => isTemp,
|
||
},
|
||
{
|
||
command: 'delete',
|
||
label: '删除',
|
||
icon: Delete,
|
||
visible: () => isTemp,
|
||
},
|
||
{
|
||
command: 'accept',
|
||
label: '履约验收',
|
||
icon: DocumentChecked,
|
||
visible: () => isCompleted && hasAuth('purchase_accept'),
|
||
},
|
||
{
|
||
command: 'implement',
|
||
label: '实施采购',
|
||
icon: Upload,
|
||
// 学校统一采购 或 部门自行采购+委托采购中心采购 时显示
|
||
visible: () =>
|
||
isCompleted && hasAuth('purchase_implement') && (row.purchaseMode === '2' || (row.purchaseMode === '1' && row.purchaseChannel === '2')),
|
||
},
|
||
{
|
||
command: 'archive',
|
||
label: '文件归档',
|
||
icon: FolderOpened,
|
||
visible: () => isCompleted && hasAuth('purchase_archive'),
|
||
},
|
||
{
|
||
command: 'downloadApply',
|
||
label: '下载审批表',
|
||
icon: Download,
|
||
visible: () => isCompleted,
|
||
},
|
||
// {
|
||
// command: 'representor',
|
||
// label: '采购代表',
|
||
// icon: User,
|
||
// visible: () => isCompleted && isDeptAuditRole.value,
|
||
// },
|
||
// {
|
||
// command: 'updateFiles',
|
||
// label: '更新材料',
|
||
// icon: RefreshRight,
|
||
// visible: () => (isCompleted || isRunning) && hasAuth('purchase_purchasingapply_edit'),
|
||
// },
|
||
// {
|
||
// command: 'contract',
|
||
// label: '采购合同',
|
||
// icon: DocumentChecked,
|
||
// visible: () => isCompleted,
|
||
// },
|
||
{
|
||
command: 'supplementFiles',
|
||
label: '补充材料',
|
||
icon: Upload,
|
||
visible: () =>
|
||
isCompleted && row?.purchaseMode === '1' && row?.purchaseChannel === '1' && !row?.supplementFlowStatus && hasAuth('purchase_supplement'),
|
||
},
|
||
// {
|
||
// command: 'downloadFileApply',
|
||
// label: '下载文件审批表',
|
||
// icon: Download,
|
||
// visible: () => isCompleted,
|
||
// },
|
||
// {
|
||
// command: 'docAudit',
|
||
// label: '招标文件审核',
|
||
// icon: DocumentChecked,
|
||
// visible: () => row?.implementType === '2' && row?.agentId,
|
||
// },
|
||
];
|
||
// 过滤出有权限且可见的菜单项
|
||
return items.filter((item) => {
|
||
if (item.visible === undefined) return true;
|
||
if (typeof item.visible === 'boolean') return item.visible;
|
||
if (typeof item.visible === 'function') return item.visible();
|
||
return false;
|
||
});
|
||
};
|
||
|
||
/** 处理更多操作下拉菜单命令 */
|
||
const handleMoreCommand = (command: string, row: any) => {
|
||
switch (command) {
|
||
case 'edit':
|
||
handleEdit(row);
|
||
break;
|
||
case 'submit':
|
||
handleSubmit(row);
|
||
break;
|
||
case 'delete':
|
||
handleDelete(row);
|
||
break;
|
||
case 'accept':
|
||
handleAccept(row);
|
||
break;
|
||
case 'implement':
|
||
handleImplement(row);
|
||
break;
|
||
case 'archive':
|
||
handleArchive(row);
|
||
break;
|
||
case 'downloadApply':
|
||
handleDownloadApply(row);
|
||
break;
|
||
case 'downloadFileApply':
|
||
handleDownloadFileApply(row);
|
||
break;
|
||
case 'docAudit':
|
||
handleDocAudit(row);
|
||
break;
|
||
case 'representor':
|
||
openRepresentorDialog(row);
|
||
break;
|
||
case 'updateFiles':
|
||
handleUpdateFiles(row);
|
||
break;
|
||
case 'contract':
|
||
handleContract(row);
|
||
break;
|
||
case 'supplementFiles':
|
||
handleSupplementFiles(row);
|
||
break;
|
||
case 'submitSupplementFiles':
|
||
handleSubmitSupplementFiles(row);
|
||
break;
|
||
}
|
||
};
|
||
|
||
/** 更新材料 */
|
||
const handleUpdateFiles = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
updateFilesDialogRef.value?.open(id, row.purchaseNo);
|
||
};
|
||
|
||
/** 采购合同 */
|
||
const handleContract = async (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
try {
|
||
const res = await getByPurchaseId(id);
|
||
contractDialogRef.value?.open(row, res?.data || null);
|
||
} catch (e) {
|
||
useMessage().error('获取合同信息失败');
|
||
}
|
||
};
|
||
|
||
/** 补充材料 */
|
||
const handleSupplementFiles = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
supplementFilesDialogRef.value?.open(String(id));
|
||
};
|
||
|
||
/** 提交补充材料 */
|
||
const handleSubmitSupplementFiles = async (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (!id) {
|
||
useMessage().warning('无法获取采购申请ID');
|
||
return;
|
||
}
|
||
supplementFilesDialogRef.value?.open(String(id));
|
||
};
|
||
|
||
/** 下载审批表 */
|
||
const handleDownloadApply = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (id == null || id === '') {
|
||
useMessage().warning('无法获取申请单ID');
|
||
return;
|
||
}
|
||
const url = getApplyTemplateDownloadUrl(id);
|
||
const fileName = `审批表_${row?.purchaseNo || id}.docx`;
|
||
other.downBlobFile(url, {}, fileName);
|
||
};
|
||
|
||
/** 下载文件审批表 */
|
||
const handleDownloadFileApply = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (id == null || id === '') {
|
||
useMessage().warning('无法获取申请单ID');
|
||
return;
|
||
}
|
||
const url = getFileApplyTemplateDownloadUrl(id);
|
||
const fileName = `文件审批表_${row?.purchaseNo || id}.docx`;
|
||
other.downBlobFile(url, {}, fileName);
|
||
};
|
||
|
||
/** 文件归档:打开弹窗查看文件列表,支持打包下载 */
|
||
const handleArchive = (row: any) => {
|
||
const id = row?.id ?? row?.purchaseId;
|
||
if (id == null || id === '') {
|
||
useMessage().warning('无法获取申请单ID');
|
||
return;
|
||
}
|
||
fileArchiveDialogRef.value?.open(String(id), row?.purchaseNo);
|
||
};
|
||
|
||
// 获取字典数据和品目树数据
|
||
const loadDictData = async () => {
|
||
try {
|
||
const [
|
||
fundSourceRes,
|
||
isCentralizedRes,
|
||
isSpecialRes,
|
||
purchaseTypeDeptRes,
|
||
purchaseModeSchoolRes,
|
||
purchaseTypeUnionRes,
|
||
categoryTreeRes,
|
||
purchaseTypeDeptDelegationRes,
|
||
] = await Promise.all([
|
||
getDicts('PURCHASE_FUND_SOURCE'),
|
||
getDicts('PURCHASE_IS_CEN'),
|
||
getDicts('PURCHASE_IS_SPEC'),
|
||
getDicts('PURCHASE_TYPE_DEPT'),
|
||
getDicts('PURCHASE_MODE_SCHOOL'),
|
||
getDicts('PURCHASE_TYPE_UNION'),
|
||
getTree(),
|
||
getDicts('PURCHASE_TYPE_DEPT_DELEGATION'),
|
||
]);
|
||
|
||
// 处理资金来源字典
|
||
if (fundSourceRes.data && Array.isArray(fundSourceRes.data)) {
|
||
dictData.value.fundSourceList = fundSourceRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
} else {
|
||
dictData.value.fundSourceList = [
|
||
{ label: '切块经费', value: '0' },
|
||
{ label: '设备购置费', value: '1' },
|
||
{ label: '专项经费', value: '2' },
|
||
{ label: '代办费', value: '3' },
|
||
{ label: '培训经费', value: '4' },
|
||
{ label: '日常公用经费', value: '5' },
|
||
{ label: '技能大赛经费', value: '6' },
|
||
{ label: '基本建设资金', value: '7' },
|
||
{ label: '暂存款', value: '8' },
|
||
{ label: '会议费', value: '9' },
|
||
];
|
||
}
|
||
|
||
// 处理是否集采字典
|
||
if (isCentralizedRes.data && Array.isArray(isCentralizedRes.data)) {
|
||
dictData.value.isCentralizedList = isCentralizedRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
} else {
|
||
dictData.value.isCentralizedList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '政府集中采购', value: '1' },
|
||
{ label: '学校集中采购', value: '2' },
|
||
];
|
||
}
|
||
|
||
// 处理是否特殊情况字典
|
||
if (isSpecialRes.data && Array.isArray(isSpecialRes.data)) {
|
||
dictData.value.isSpecialList = isSpecialRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
} else {
|
||
dictData.value.isSpecialList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '紧急', value: '1' },
|
||
{ label: '单一', value: '2' },
|
||
{ label: '进口', value: '3' },
|
||
];
|
||
}
|
||
|
||
// 处理部门采购方式字典
|
||
if (purchaseTypeDeptRes.data && Array.isArray(purchaseTypeDeptRes.data)) {
|
||
dictData.value.purchaseTypeDeptList = purchaseTypeDeptRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
}
|
||
|
||
// 处理学校采购形式字典
|
||
if (purchaseModeSchoolRes.data && Array.isArray(purchaseModeSchoolRes.data)) {
|
||
dictData.value.purchaseModeSchoolList = purchaseModeSchoolRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
} else {
|
||
dictData.value.purchaseModeSchoolList = [
|
||
{ label: '政府采购', value: '1' },
|
||
{ label: '学校自主采购', value: '2' },
|
||
];
|
||
}
|
||
|
||
// 处理学校统一采购方式字典
|
||
if (purchaseTypeUnionRes.data && Array.isArray(purchaseTypeUnionRes.data)) {
|
||
dictData.value.purchaseTypeUnionList = purchaseTypeUnionRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
}
|
||
|
||
// 处理委托采购中心采购方式字典
|
||
if (purchaseTypeDeptDelegationRes.data && Array.isArray(purchaseTypeDeptDelegationRes.data)) {
|
||
purchaseTypeDeptDelegationList.value = purchaseTypeDeptDelegationRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code,
|
||
}));
|
||
}
|
||
|
||
// 处理品目树数据
|
||
if (categoryTreeRes.data && Array.isArray(categoryTreeRes.data)) {
|
||
dictData.value.categoryTreeData = categoryTreeRes.data;
|
||
} else {
|
||
dictData.value.categoryTreeData = [];
|
||
}
|
||
} catch (err) {
|
||
console.error('加载字典数据失败', err);
|
||
// 设置默认值
|
||
dictData.value.fundSourceList = [
|
||
{ label: '切块经费', value: '0' },
|
||
{ label: '设备购置费', value: '1' },
|
||
{ label: '专项经费', value: '2' },
|
||
{ label: '代办费', value: '3' },
|
||
{ label: '培训经费', value: '4' },
|
||
{ label: '日常公用经费', value: '5' },
|
||
{ label: '技能大赛经费', value: '6' },
|
||
{ label: '基本建设资金', value: '7' },
|
||
{ label: '暂存款', value: '8' },
|
||
{ label: '会议费', value: '9' },
|
||
];
|
||
dictData.value.isCentralizedList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '政府集中采购', value: '1' },
|
||
{ label: '学校集中采购', value: '2' },
|
||
];
|
||
dictData.value.isSpecialList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '紧急', value: '1' },
|
||
{ label: '单一', value: '2' },
|
||
{ label: '进口', value: '3' },
|
||
];
|
||
dictData.value.purchaseModeSchoolList = [
|
||
{ label: '政府采购', value: '1' },
|
||
{ label: '学校自主采购', value: '2' },
|
||
];
|
||
dictData.value.categoryTreeData = [];
|
||
}
|
||
};
|
||
|
||
// 获取二级部门列表
|
||
const loadSecondDeptList = async () => {
|
||
try {
|
||
const res = await getDeptListByLevelTwo();
|
||
if (res.data && Array.isArray(res.data)) {
|
||
secondDeptList.value = res.data.map((item: any) => ({
|
||
deptCode: item.deptCode,
|
||
deptName: item.deptName,
|
||
}));
|
||
}
|
||
} catch (err) {
|
||
console.error('加载二级部门列表失败', err);
|
||
secondDeptList.value = [];
|
||
}
|
||
};
|
||
|
||
// 导出功能
|
||
const handleExport = async () => {
|
||
try {
|
||
const ids = selectedRows.value.length > 0 ? selectedRows.value.map((row) => row.id) : undefined;
|
||
const res: any = await exportPurchaseApply(state.queryForm, ids);
|
||
downloadFile(res, '采购申请列表.xlsx');
|
||
} catch (err: any) {
|
||
useMessage().error(err.msg || '导出失败');
|
||
}
|
||
};
|
||
|
||
const handleSelectionChange = (rows: any[]) => {
|
||
selectedRows.value = rows;
|
||
};
|
||
|
||
const downloadFile = (blob: Blob, fileName: string) => {
|
||
const url = window.URL.createObjectURL(blob);
|
||
const link = document.createElement('a');
|
||
link.href = url;
|
||
link.download = fileName;
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
window.URL.revokeObjectURL(url);
|
||
};
|
||
|
||
// 页面加载时获取字典数据和品目树数据
|
||
onMounted(() => {
|
||
loadDictData();
|
||
loadSecondDeptList();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import '/@/assets/styles/modern-page.scss';
|
||
|
||
.op-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.status-tag-clickable {
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* 柔和统一的标签配色方案 - 校园系统专用 */
|
||
:deep(.el-tag) {
|
||
border-radius: 4px;
|
||
font-weight: 500;
|
||
border: none;
|
||
}
|
||
|
||
/* 成功/完成状态 - 柔和青绿色 */
|
||
:deep(.el-tag--success) {
|
||
--el-tag-bg-color: #e8f6f3;
|
||
--el-tag-border-color: #d1ebde;
|
||
--el-tag-text-color: #2a9d8f;
|
||
}
|
||
|
||
/* 警告/暂存状态 - 柔和琥珀色 */
|
||
:deep(.el-tag--warning) {
|
||
--el-tag-bg-color: #fef6e8;
|
||
--el-tag-border-color: #fce8c9;
|
||
--el-tag-text-color: #d48806;
|
||
}
|
||
|
||
/* 危险/作废状态 - 柔和玫瑰色 */
|
||
:deep(.el-tag--danger) {
|
||
--el-tag-bg-color: #fef2f2;
|
||
--el-tag-border-color: #fde8e8;
|
||
--el-tag-text-color: #c75b5b;
|
||
}
|
||
|
||
/* 进行中/运行中 - 柔和天蓝色 */
|
||
:deep(.el-tag--primary) {
|
||
--el-tag-bg-color: #eef6fc;
|
||
--el-tag-border-color: #d9ebf7;
|
||
--el-tag-text-color: #4a90a4;
|
||
}
|
||
|
||
/* 信息/中性状态 - 柔和灰色 */
|
||
:deep(.el-tag--info) {
|
||
--el-tag-bg-color: #f5f6f7;
|
||
--el-tag-border-color: #e8eaed;
|
||
--el-tag-text-color: #6b7280;
|
||
}
|
||
|
||
.purchase-no-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
|
||
.purchase-no-text {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
max-width: 120px;
|
||
}
|
||
|
||
.copy-btn {
|
||
flex-shrink: 0;
|
||
}
|
||
}
|
||
|
||
.purchase-mode-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
|
||
.entrust-tag {
|
||
font-size: 11px;
|
||
padding: 0 4px;
|
||
height: 18px;
|
||
line-height: 16px;
|
||
}
|
||
|
||
.supplement-icon {
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
margin-left: 4px;
|
||
transition: transform 0.2s;
|
||
|
||
&:hover {
|
||
transform: scale(1.2);
|
||
}
|
||
}
|
||
|
||
.supplement-done {
|
||
color: #2a9d8f;
|
||
}
|
||
|
||
.supplement-running {
|
||
color: #d48806;
|
||
}
|
||
|
||
.supplement-pending {
|
||
color: #c75b5b;
|
||
}
|
||
}
|
||
|
||
/* 项目名称单元格样式 */
|
||
.project-name-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
|
||
.project-name-text {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
|
||
/* 特殊情况圆形标记 */
|
||
.special-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: #fff;
|
||
flex-shrink: 0;
|
||
cursor: default;
|
||
|
||
/* 紧急 - 橙色 */
|
||
&.special-1 {
|
||
background-color: #f59e0b;
|
||
}
|
||
|
||
/* 单一 - 红色 */
|
||
&.special-2 {
|
||
background-color: #ef4444;
|
||
}
|
||
|
||
/* 进口 - 蓝色 */
|
||
&.special-3 {
|
||
background-color: #3b82f6;
|
||
}
|
||
}
|
||
|
||
/* 集采圆形标记 */
|
||
.centralized-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 50%;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: #fff;
|
||
background-color: #10b981;
|
||
flex-shrink: 0;
|
||
cursor: default;
|
||
}
|
||
</style>
|