| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- <template>
- <div class="safety-platform-container">
- <div class="safety-platform-container__header">
- <div class="bread">
- <BreadcrumbBack />
- <div class="breadcrumb-title">{{ supplyRequestInfo?.planName || '物资采购申领详情' }}</div>
- </div>
- </div>
- <div class="safety-platform-container__main">
- <div class="detail-container">
- <header class="detail-header">
- <el-button
- type="primary"
- :icon="Plus"
- @click="handleAddMaterial"
- v-if="supplyRequestInfo?.status === SUPPLY_REQUEST_STATUS.APPLYING && supplyRequestManagePermission"
- >添加需求物资</el-button
- >
- <el-button type="primary" :icon="Download" @click="handleDownloadRecord">下载采购记录</el-button>
- </header>
- <div class="table-container">
- <el-table :data="tableData" :span-method="handleSpanMethod" border v-loading="loading" style="width: 100%">
- <el-table-column type="index" label="序号" width="80" align="center" />
- <el-table-column prop="materialName" label="物资名称" min-width="140" align="center" />
- <el-table-column prop="specification" label="规格" min-width="100" align="center" />
- <el-table-column prop="department" label="需求部门" min-width="140" align="center" />
- <el-table-column prop="quantity" label="数量" width="100" align="center" />
- <el-table-column prop="requestReason" label="申请理由" min-width="200" align="center" />
- <el-table-column prop="sizeDetails" label="尺寸明细" min-width="200" align="center" />
- <el-table-column prop="status" label="状态" width="120" align="center">
- <template #default="scope">
- <span>{{ getStatusText(scope.row.status) }}</span>
- </template>
- </el-table-column>
- <el-table-column
- prop="claim"
- label="通知领用"
- width="150"
- align="center"
- v-if="supplyRequestManagePermission"
- >
- <template #default="scope">
- <el-link
- v-if="scope.row.status === SUPPLY_REQUEST_DETAIL_STATUS.PURCHASING"
- type="primary"
- @click="handleNotify(scope.row)"
- >
- 通知
- </el-link>
- <el-link
- v-else-if="scope.row.status === SUPPLY_REQUEST_DETAIL_STATUS.NOTIFIED"
- type="primary"
- @click="handleClaim(scope.row)"
- >
- 领用
- </el-link>
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column
- prop="action"
- label="物资操作"
- width="150"
- align="center"
- fixed="right"
- v-if="supplyRequestManagePermission"
- >
- <template #default="scope">
- <div class="action-container">
- <el-link
- v-if="scope.row.status === SUPPLY_REQUEST_DETAIL_STATUS.APPLYING"
- type="primary"
- @click="handleEdit(scope.row)"
- >
- 编辑
- </el-link>
- <el-link
- v-if="scope.row.status === SUPPLY_REQUEST_DETAIL_STATUS.APPLYING"
- type="primary"
- style="margin-left: 8px"
- @click="handleDelete(scope.row)"
- >
- 删除
- </el-link>
- <span v-if="scope.row.status !== SUPPLY_REQUEST_DETAIL_STATUS.APPLYING">-</span>
- </div>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- </div>
- </div>
- <!-- 领用弹窗 -->
- <ReceiveSupplyDialog ref="receiveSupplyDialogRef" @success="handleClaimSuccess" />
- <!-- 添加物资弹窗 -->
- <AddSuppliesDrawer ref="addSupplyDrawerRef" @success="handleAddMaterialSuccess" />
- <!-- 通知部门领用弹窗 -->
- <NotifyDepartmentDialog ref="notifyDepartmentDialogRef" @success="handleNotifySuccess" />
- </template>
- <script setup lang="ts">
- import { ref, onMounted } from 'vue';
- import { useRoute } from 'vue-router';
- import { Plus, Download } from '@element-plus/icons-vue';
- import { ElMessage, ElMessageBox } from 'element-plus';
- import BreadcrumbBack from '@/components/BreadcrumbBack.vue';
- import {
- SUPPLY_REQUEST_STATUS,
- SUPPLY_REQUEST_DETAIL_STATUS,
- SUPPLY_REQUEST_DETAIL_STATUS_MAP,
- } from './src/constant';
- import {
- getSupplyRequestInfoById,
- getSupplyRequestDetail,
- deleteSupplyRequestDetail,
- exportSupplyRequestRecord,
- } from '@/api/emergency-supplier';
- import type { SupplyRequestDetailItem } from '@/types/emergency-supplier';
- import { SupplyRequestListItem } from '@/types/emergency-supplier';
- import { downloadFile } from '@/views/disaster/utils/download';
- import ReceiveSupplyDialog from './src/components/ReceiveSupplyDialog.vue';
- import { useUserInfoHook } from '@/hooks/useUserInfoHook';
- import { EMERGENCY_PERMISSIONS } from '@/views/emergency/src/constant';
- import AddSuppliesDrawer from './src/components/AddSuppliesDrawer.vue';
- import NotifyDepartmentDialog from './src/components/NotifyDepartmentDialog.vue';
- const { permissions } = useUserInfoHook();
- const supplyRequestManagePermission = ref<Boolean>(false);
- // 表格行数据类型
- interface TableRowData {
- id: number; // detailList 的 id
- requestId: number; // detailList 的 requestId
- infoId: number; // info 的 id,用于合并单元格
- materialName: string; // info 的 supplyName
- specification: string; // info 的 specs
- department: string; // detailList 的 deptName
- quantity: number; // detailList 的 quantity
- requestReason: string; // detailList 的 requestReason
- sizeDetails: string; // detailList 的 sizeDetail
- status: number; // detailList 的 status
- }
- const route = useRoute();
- const id = Number(route.params.id);
- const supplyRequestInfo = ref<SupplyRequestListItem>();
- const loading = ref(false);
- const tableData = ref<TableRowData[]>([]);
- const addSupplyDrawerRef = ref<InstanceType<typeof AddSuppliesDrawer>>();
- const supplyRequestDetailData = ref<SupplyRequestDetailItem[]>([]);
- // 通知部门领用弹窗相关
- const notifyDepartmentDialogRef = ref<InstanceType<typeof NotifyDepartmentDialog>>();
- // 领用弹窗相关
- const receiveSupplyDialogRef = ref<InstanceType<typeof ReceiveSupplyDialog>>();
- // 获取状态文本
- const getStatusText = (status: number) => {
- return SUPPLY_REQUEST_DETAIL_STATUS_MAP[status] || '';
- };
- // 合并单元格方法
- const handleSpanMethod = ({ row, rowIndex, columnIndex }: any) => {
- // 需要合并的列索引:物资名称(1)、规格(2)、物资操作(9)
- const mergeColumns = [1, 2, 9];
- if (!mergeColumns.includes(columnIndex)) {
- return { rowspan: 1, colspan: 1 };
- }
- // 按照 infoId 来分组,找到同一个 info 下的所有行
- const infoId = row.infoId;
- const sameInfoRows = tableData.value.filter((item) => item.infoId === infoId);
- const firstRowIndex = tableData.value.findIndex((item) => item.infoId === infoId);
- // 如果是第一行,返回合并的行数
- if (rowIndex === firstRowIndex) {
- return {
- rowspan: sameInfoRows.length,
- colspan: 1,
- };
- }
- // 其他行隐藏
- return {
- rowspan: 0,
- colspan: 0,
- };
- };
- // 获取详情数据
- const getDetailData = async () => {
- loading.value = true;
- try {
- const res = await getSupplyRequestDetail(id);
- supplyRequestDetailData.value = res;
- // 将 SupplyRequestDetailItem[] 转换为表格需要的扁平化数据结构
- const flatData: TableRowData[] = [];
- res.forEach((item) => {
- // 将每个 detailList 项与 info 合并成一行
- item.detailList.forEach((detail) => {
- flatData.push({
- id: detail.id,
- requestId: detail.requestId,
- infoId: item.info.id, // 用于合并单元格
- materialName: item.info.supplyName,
- specification: item.info.specs,
- department: detail.deptName,
- quantity: detail.quantity,
- requestReason: detail.requestReason,
- sizeDetails: detail.sizeDetail,
- status: detail.status,
- });
- });
- });
- tableData.value = flatData;
- } catch (error) {
- console.error('获取详情失败:', error);
- ElMessage.error('获取详情失败');
- } finally {
- loading.value = false;
- }
- };
- // 添加需求物资
- const handleAddMaterial = () => {
- addSupplyDrawerRef.value?.openDrawer();
- };
- // 添加物资成功回调
- const handleAddMaterialSuccess = async () => {
- await getDetailData();
- };
- // 下载采购记录
- const handleDownloadRecord = async () => {
- try {
- const res = await exportSupplyRequestRecord(id);
- if (res.size === 0) return;
- const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
- const url = window.URL.createObjectURL(blob);
- downloadFile(url, '采购申领记录.xlsx');
- } catch (error) {
- ElMessage.error('下载失败');
- }
- };
- // 通知领用
- const handleNotify = (row: TableRowData) => {
- notifyDepartmentDialogRef.value?.openDialog(row.id);
- };
- // 通知领用成功回调
- const handleNotifySuccess = async () => {
- await getDetailData();
- };
- // 领用
- const handleClaim = (row: TableRowData) => {
- receiveSupplyDialogRef.value?.openDialog(row.materialName, row.quantity, row.id, id);
- };
- // 领用成功回调
- const handleClaimSuccess = async () => {
- await getDetailData();
- };
- // 编辑
- const handleEdit = (row: TableRowData) => {
- // 根据 infoId 找到对应的 SupplyRequestDetailItem
- const editData = supplyRequestDetailData.value.find((item) => item.info.id === row.infoId);
- if (!editData) {
- ElMessage.error('未找到要编辑的数据');
- return;
- }
- addSupplyDrawerRef.value?.openDrawer(editData);
- };
- // 删除
- const handleDelete = async (row: TableRowData) => {
- try {
- await ElMessageBox.confirm('确定要删除该物资吗?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning',
- });
- await deleteSupplyRequestDetail(row.infoId);
- ElMessage.success('删除成功');
- await getDetailData();
- } catch (error) {
- console.error('删除失败:', error);
- }
- };
- onMounted(async () => {
- getDetailData();
- supplyRequestInfo.value = await getSupplyRequestInfoById(id);
- supplyRequestManagePermission.value = Boolean(
- permissions.find((item: { code: string }) => item.code === EMERGENCY_PERMISSIONS.SUPPLY_REQUEST_MANAGE),
- );
- });
- </script>
- <style scoped lang="scss">
- @use '@/styles/page-details-layout.scss' as *;
- @use './src/styles/page-common.scss' as *;
- .bread {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .detail-container {
- background: #fff;
- padding: 16px;
- border-radius: 4px;
- }
- .detail-header {
- display: flex;
- gap: 12px;
- margin-bottom: 16px;
- }
- .table-container {
- width: 100%;
- }
- .action-container {
- display: flex;
- align-items: center;
- justify-content: center;
- }
- </style>
|