579 lines
20 KiB
Vue
579 lines
20 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="-2" />
|
||
<el-option label="暂存" value="-1" />
|
||
<el-option label="运行中" value="0" />
|
||
<el-option label="完成" value="1" />
|
||
<el-option label="作废" value="2" />
|
||
<el-option label="终止" value="3" />
|
||
</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 label="否" value="0" />
|
||
<el-option label="是" value="1" />
|
||
</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-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="FolderAdd"
|
||
type="primary"
|
||
@click="handleAdd">
|
||
新增
|
||
</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">
|
||
<el-table-column type="index" label="序号" width="70" align="center">
|
||
<template #header>
|
||
<el-icon><List /></el-icon>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="code" label="申请单编号" min-width="140" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon><DocumentCopy /></el-icon>
|
||
<span style="margin-left: 4px">申请单编号</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="projectName" label="采购项目名称" min-width="200" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon><Document /></el-icon>
|
||
<span style="margin-left: 4px">采购项目名称</span>
|
||
</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="项目类别" min-width="200" align="left" show-overflow-tooltip>
|
||
<template #header>
|
||
<el-icon><Collection /></el-icon>
|
||
<span style="margin-left: 4px">项目类别</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<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="130" 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="isSpecial" label="是否特殊" width="100" align="center">
|
||
<template #header>
|
||
<el-icon><Warning /></el-icon>
|
||
<span style="margin-left: 4px">是否特殊</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<el-tag v-if="scope.row.isSpecial === '1' || scope.row.isSpecial === 1" type="warning">是</el-tag>
|
||
<el-tag v-else-if="scope.row.isSpecial === '0' || scope.row.isSpecial === 0" type="info">否</el-tag>
|
||
<span v-else>-</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="isCentralized" label="是否集采" width="100" align="center">
|
||
<template #header>
|
||
<el-icon><CircleCheck /></el-icon>
|
||
<span style="margin-left: 4px">是否集采</span>
|
||
</template>
|
||
<template #default="scope">
|
||
<el-tag v-if="scope.row.isCentralized === '1'" type="success">是</el-tag>
|
||
<el-tag v-else-if="scope.row.isCentralized === '0'" type="info">否</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-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>
|
||
</el-table-column>
|
||
<el-table-column label="操作" align="center" fixed="right" width="300">
|
||
<template #default="scope">
|
||
<el-button
|
||
icon="View"
|
||
link
|
||
type="primary"
|
||
@click="formDialogRef.openDialog('view', scope.row)">
|
||
查看
|
||
</el-button>
|
||
<el-button
|
||
v-if="scope.row.status === '-1'"
|
||
icon="Edit"
|
||
link
|
||
type="primary"
|
||
@click="formDialogRef.openDialog('edit', scope.row)">
|
||
编辑
|
||
</el-button>
|
||
<el-button
|
||
v-if="scope.row.status === '-1'"
|
||
icon="Delete"
|
||
link
|
||
type="danger"
|
||
@click="handleDelete(scope.row)">
|
||
删除
|
||
</el-button>
|
||
</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"
|
||
@pagination="getDataList"
|
||
/>
|
||
</el-card>
|
||
</div>
|
||
|
||
<!-- 新增页面 iframe 对话框 -->
|
||
<el-dialog
|
||
v-model="showAddIframe"
|
||
title="新增采购申请"
|
||
width="90%"
|
||
:style="{ maxWidth: '1600px' }"
|
||
:close-on-click-modal="false"
|
||
:close-on-press-escape="true"
|
||
destroy-on-close
|
||
class="iframe-dialog"
|
||
@close="closeAddIframe">
|
||
<div class="iframe-dialog-content">
|
||
<iframe
|
||
ref="addIframeRef"
|
||
:src="addIframeSrc"
|
||
frameborder="0"
|
||
class="add-iframe"
|
||
/>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑、新增表单对话框 -->
|
||
<FormDialog
|
||
ref="formDialogRef"
|
||
:dict-data="dictData"
|
||
@refresh="getDataList" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts" name="PurchasingRequisition">
|
||
import { ref, reactive, defineAsyncComponent, onUnmounted, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||
import { getPage, delObj } from "/@/api/finance/purchasingrequisition";
|
||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||
import { getDicts } from '/@/api/admin/dict';
|
||
import { getTree } from '/@/api/finance/purchasingcategory';
|
||
import { List, Document, DocumentCopy, Search, Collection, Money, CircleCheck, InfoFilled, Calendar, OfficeBuilding, Warning } from '@element-plus/icons-vue'
|
||
|
||
// 引入组件
|
||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||
|
||
// 字典数据和品目树数据
|
||
const dictData = ref({
|
||
fundSourceList: [] as any[],
|
||
isCentralizedList: [] as any[],
|
||
isSpecialList: [] as any[],
|
||
purchaseTypeDeptList: [] as any[],
|
||
purchaseModeSchoolList: [] as any[],
|
||
purchaseTypeUnionList: [] as any[],
|
||
categoryTreeData: [] as any[],
|
||
});
|
||
|
||
// 定义变量内容
|
||
const router = useRouter()
|
||
const tableRef = ref()
|
||
const formDialogRef = ref()
|
||
const searchFormRef = ref()
|
||
const showSearch = ref(true)
|
||
const showAddIframe = ref(false)
|
||
const addIframeRef = ref<HTMLIFrameElement>()
|
||
const addIframeSrc = ref('')
|
||
|
||
/**
|
||
* 定义响应式表格数据
|
||
*/
|
||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||
pageList: getPage,
|
||
queryForm: {
|
||
purchaseNo: '',
|
||
projectName: '',
|
||
projectType: '',
|
||
status: '',
|
||
isCentralized: '',
|
||
},
|
||
createdIsNeed: true
|
||
});
|
||
|
||
/**
|
||
* 使用 useTable 定义表格相关操作
|
||
*/
|
||
const { getDataList, tableStyle } = useTable(state);
|
||
|
||
/**
|
||
* 重置搜索表单
|
||
*/
|
||
const handleReset = () => {
|
||
searchFormRef.value?.resetFields();
|
||
getDataList();
|
||
};
|
||
|
||
/**
|
||
* 新增采购申请 - 在 iframe 中展示
|
||
*/
|
||
const handleAdd = () => {
|
||
// 构建 iframe 的 src,使用当前页面的 hash 路由
|
||
const baseUrl = window.location.origin + window.location.pathname
|
||
addIframeSrc.value = `${baseUrl}#/finance/purchasingrequisition/add`
|
||
showAddIframe.value = true
|
||
// 监听来自 iframe 的消息
|
||
window.addEventListener('message', handleIframeMessage)
|
||
};
|
||
|
||
/**
|
||
* 关闭新增 iframe
|
||
*/
|
||
const closeAddIframe = () => {
|
||
showAddIframe.value = false
|
||
// 移除消息监听器
|
||
window.removeEventListener('message', handleIframeMessage)
|
||
};
|
||
|
||
/**
|
||
* 处理 iframe 发送的消息
|
||
*/
|
||
const handleIframeMessage = (event: MessageEvent) => {
|
||
// 验证消息来源(可选,根据实际需求)
|
||
// if (event.origin !== window.location.origin) return
|
||
|
||
if (event.data && event.data.type === 'purchasingrequisition:submitSuccess') {
|
||
// 提交成功,关闭 iframe 并刷新列表
|
||
closeAddIframe()
|
||
getDataList()
|
||
useMessage().success('提交成功')
|
||
} else if (event.data && event.data.type === 'purchasingrequisition:close') {
|
||
// 关闭 iframe
|
||
closeAddIframe()
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 删除当前行
|
||
* @param row - 当前行数据
|
||
*/
|
||
const handleDelete = async (row: any) => {
|
||
try {
|
||
await useMessageBox().confirm('确定要删除该记录吗?');
|
||
} catch {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await delObj(row.id);
|
||
useMessage().success('删除成功');
|
||
getDataList();
|
||
} catch (err: any) {
|
||
useMessage().error(err.msg || '删除失败');
|
||
}
|
||
};
|
||
|
||
// 获取字典数据和品目树数据
|
||
const loadDictData = async () => {
|
||
try {
|
||
const [
|
||
fundSourceRes,
|
||
isCentralizedRes,
|
||
isSpecialRes,
|
||
purchaseTypeDeptRes,
|
||
purchaseModeSchoolRes,
|
||
purchaseTypeUnionRes,
|
||
categoryTreeRes
|
||
] = await Promise.all([
|
||
getDicts('PURCHASE_FUND_SOURCE'),
|
||
getDicts('PURCHASE_IS_CEN'),
|
||
getDicts('PURCHASE_IS_SPEC'),
|
||
getDicts('PURCHASE_TYPE_DEPT'),
|
||
getDicts('PURCHASE_MODE_SCHOOL'),
|
||
getDicts('PURCHASE_TYPE_UNION'),
|
||
getTree()
|
||
]);
|
||
|
||
// 处理资金来源字典
|
||
if (fundSourceRes.data && Array.isArray(fundSourceRes.data)) {
|
||
dictData.value.fundSourceList = fundSourceRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
} else {
|
||
dictData.value.fundSourceList = [
|
||
{ label: '切块经费', value: '0' },
|
||
{ label: '设备购置费', value: '1' },
|
||
{ label: '专项经费', value: '2' },
|
||
{ label: '代办费', value: '3' },
|
||
{ label: '培训经费', value: '4' },
|
||
{ label: '日常公用经费', value: '5' },
|
||
{ label: '技能大赛经费', value: '6' },
|
||
{ label: '基本建设资金', value: '7' },
|
||
{ label: '暂存款', value: '8' },
|
||
{ label: '会议费', value: '9' },
|
||
];
|
||
}
|
||
|
||
// 处理是否集采字典
|
||
if (isCentralizedRes.data && Array.isArray(isCentralizedRes.data)) {
|
||
dictData.value.isCentralizedList = isCentralizedRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
} else {
|
||
dictData.value.isCentralizedList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '政府集中采购', value: '1' },
|
||
{ label: '学校集中采购', value: '2' }
|
||
];
|
||
}
|
||
|
||
// 处理是否特殊情况字典
|
||
if (isSpecialRes.data && Array.isArray(isSpecialRes.data)) {
|
||
dictData.value.isSpecialList = isSpecialRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
} else {
|
||
dictData.value.isSpecialList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '紧急', value: '1' },
|
||
{ label: '单一', value: '2' },
|
||
{ label: '进口', value: '3' }
|
||
];
|
||
}
|
||
|
||
// 处理部门采购方式字典
|
||
if (purchaseTypeDeptRes.data && Array.isArray(purchaseTypeDeptRes.data)) {
|
||
dictData.value.purchaseTypeDeptList = purchaseTypeDeptRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
}
|
||
|
||
// 处理学校采购形式字典
|
||
if (purchaseModeSchoolRes.data && Array.isArray(purchaseModeSchoolRes.data)) {
|
||
dictData.value.purchaseModeSchoolList = purchaseModeSchoolRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
} else {
|
||
dictData.value.purchaseModeSchoolList = [
|
||
{ label: '政府采购', value: '1' },
|
||
{ label: '学校自主采购', value: '2' }
|
||
];
|
||
}
|
||
|
||
// 处理学校统一采购方式字典
|
||
if (purchaseTypeUnionRes.data && Array.isArray(purchaseTypeUnionRes.data)) {
|
||
dictData.value.purchaseTypeUnionList = purchaseTypeUnionRes.data.map((item: any) => ({
|
||
label: item.label || item.dictLabel || item.name,
|
||
value: item.value || item.dictValue || item.code
|
||
}));
|
||
}
|
||
|
||
// 处理品目树数据
|
||
if (categoryTreeRes.data && Array.isArray(categoryTreeRes.data)) {
|
||
dictData.value.categoryTreeData = categoryTreeRes.data;
|
||
} else {
|
||
dictData.value.categoryTreeData = [];
|
||
}
|
||
} catch (err) {
|
||
console.error('加载字典数据失败', err);
|
||
// 设置默认值
|
||
dictData.value.fundSourceList = [
|
||
{ label: '切块经费', value: '0' },
|
||
{ label: '设备购置费', value: '1' },
|
||
{ label: '专项经费', value: '2' },
|
||
{ label: '代办费', value: '3' },
|
||
{ label: '培训经费', value: '4' },
|
||
{ label: '日常公用经费', value: '5' },
|
||
{ label: '技能大赛经费', value: '6' },
|
||
{ label: '基本建设资金', value: '7' },
|
||
{ label: '暂存款', value: '8' },
|
||
{ label: '会议费', value: '9' },
|
||
];
|
||
dictData.value.isCentralizedList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '政府集中采购', value: '1' },
|
||
{ label: '学校集中采购', value: '2' }
|
||
];
|
||
dictData.value.isSpecialList = [
|
||
{ label: '否', value: '0' },
|
||
{ label: '紧急', value: '1' },
|
||
{ label: '单一', value: '2' },
|
||
{ label: '进口', value: '3' }
|
||
];
|
||
dictData.value.purchaseModeSchoolList = [
|
||
{ label: '政府采购', value: '1' },
|
||
{ label: '学校自主采购', value: '2' }
|
||
];
|
||
dictData.value.categoryTreeData = [];
|
||
}
|
||
};
|
||
|
||
// 页面加载时获取字典数据和品目树数据
|
||
onMounted(() => {
|
||
loadDictData();
|
||
});
|
||
|
||
// 组件卸载时清理事件监听器
|
||
onUnmounted(() => {
|
||
window.removeEventListener('message', handleIframeMessage)
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import '/@/assets/styles/modern-page.scss';
|
||
|
||
.iframe-dialog-content {
|
||
width: 100%;
|
||
height: 70vh;
|
||
min-height: 500px;
|
||
max-height: calc(100vh - 200px);
|
||
position: relative;
|
||
overflow: hidden;
|
||
|
||
.add-iframe {
|
||
width: 100%;
|
||
height: 100%;
|
||
min-height: 500px;
|
||
border: none;
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
:deep(.iframe-dialog) {
|
||
.el-dialog {
|
||
display: flex;
|
||
flex-direction: column;
|
||
max-height: 90vh;
|
||
margin-top: 5vh !important;
|
||
}
|
||
|
||
.el-dialog__header {
|
||
flex-shrink: 0;
|
||
padding: 20px 20px 10px;
|
||
}
|
||
|
||
.el-dialog__body {
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
flex: 1;
|
||
min-height: 0;
|
||
max-height: calc(100vh - 200px);
|
||
}
|
||
}
|
||
</style>
|
||
|