From a874c2cb0b27ca11ac6f8a029bfaa83a3c9e114a Mon Sep 17 00:00:00 2001 From: tangjie <122778500@qq.com> Date: Tue, 25 Aug 2026 17:55:37 +0800 Subject: [PATCH] fix --- src/api/safetyEvalBusiness/index.js | 18 ++ src/enumerate/constant/index.js | 44 +++ .../EvalReportLibrary/index.less | 2 +- .../ProjectFlow/ArchiveContent.js | 255 +++++++++++------- .../ProjectFlow/ArchiveSupplementModal.js | 85 ++++++ .../SafetyEvalBusiness/ProjectFlow/index.js | 1 - .../SafetyEvalBusiness/ProjectFlow/index.less | 31 +++ .../EvalProjectDatabase/ArchiveModal.js | 185 +++++++++++++ .../Supervision/EvalProjectDatabase/index.js | 13 +- .../EvalProjectDatabase/index.less | 52 +++- 10 files changed, 591 insertions(+), 95 deletions(-) create mode 100644 src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveSupplementModal.js create mode 100644 src/pages/Container/Supervision/EvalProjectDatabase/ArchiveModal.js diff --git a/src/api/safetyEvalBusiness/index.js b/src/api/safetyEvalBusiness/index.js index dcff078..6316d17 100644 --- a/src/api/safetyEvalBusiness/index.js +++ b/src/api/safetyEvalBusiness/index.js @@ -301,6 +301,18 @@ export const evalProcessControlFiles = declareRequest( "processControlFiles: [] | res.data || []", ); +/** 项目档案文件列表-机构端分页(分页参数 pageIndex/pageSize,总数 totalCount) */ +export const evalProjectArchiveFileOrgPage = declareRequest( + "evalProjectArchiveFileOrgLoading", + "Get > /safetyEval/eval-project-archive-file/org/page", +); + +/** 新增项目档案文件(机构补充上传) */ +export const evalProjectArchiveFileAdd = declareRequest( + "evalProjectArchiveFileAddLoading", + "Post > @/safetyEval/eval-project-archive-file", +); + // ===== 监管端-安评项目实时监控 ===== export const evalProjectMonitorStat = declareRequest( @@ -346,6 +358,12 @@ export const evalProjectArchivePage = declareRequest( "Get > /safetyEval/institution/eval-project/archive-supervision-page", ); +/** 项目档案文件列表(监管端,分页参数为 pageIndex/pageSize,总数 totalCount) */ +export const evalProjectArchiveFilePage = declareRequest( + "evalProjectArchiveFileLoading", + "Get > /safetyEval/eval-project-archive-file/monitor/page", +); + // ===== 机构端-安评报告库 ===== export const evalReportSummary = declareRequest( diff --git a/src/enumerate/constant/index.js b/src/enumerate/constant/index.js index 1dd61db..7c00460 100644 --- a/src/enumerate/constant/index.js +++ b/src/enumerate/constant/index.js @@ -784,3 +784,47 @@ export const QUESTION_TYPE_MAP = QUESTION_TYPE_OPTIONS.reduce( (acc, cur) => ({ ...acc, [cur.value]: cur.label }), {}, ); + +/** 项目档案类型(eval_project_archive_file.archive_type) */ +export const ARCHIVE_TYPE_OPTIONS = [ + { label: "项目风险分析", value: "RISK_ANALYSIS" }, + { label: "技术服务合同", value: "TECH_SERVICE_CONTRACT" }, + { label: "项目组织文件", value: "PROJECT_ORG_FILE" }, + { label: "实施计划", value: "IMPLEMENT_PLAN" }, + { label: "从业告知", value: "PRACTICE_NOTICE" }, + { label: "现场记录", value: "SITE_RECORD" }, + { label: "现场勘察资料", value: "SITE_SURVEY" }, + { label: "现场检查资料", value: "SITE_CHECK" }, + { label: "整改复查资料", value: "RECTIFICATION_REVIEW" }, + { label: "评价报告", value: "EVALUATION_REPORT" }, + { label: "审核记录", value: "REVIEW_RECORD" }, + { label: "过程控制文件", value: "PROCESS_CONTROL" }, + { label: "签发文件", value: "SIGN_ISSUE" }, + { label: "专家评审材料", value: "EXPERT_REVIEW" }, + { label: "项目附图", value: "PROJECT_ATTACHMENT" }, + { label: "报告修改材料", value: "REPORT_MODIFICATION" }, + { label: "往来文件", value: "CORRESPONDENCE" }, + { label: "其他", value: "OTHER" }, +]; + +export const ARCHIVE_TYPE_MAP = ARCHIVE_TYPE_OPTIONS.reduce( + (acc, cur) => ({ ...acc, [cur.value]: cur.label }), + {}, +); + +/** 档案文件来源(record_source:auto_process_record流程自动记录 / upload_additional_files补充上传) */ +export const ARCHIVE_RECORD_SOURCE_MAP = { + auto_process_record: "系统形成", + upload_additional_files: "机构补充上传", +}; + +/** 档案文件来源选项与徽标文案(机构端档案内容列表) */ +export const ARCHIVE_RECORD_SOURCE_OPTIONS = [ + { label: "流程自动记录", value: "auto_process_record" }, + { label: "补充上传", value: "upload_additional_files" }, +]; + +export const ARCHIVE_RECORD_SOURCE_BADGE_MAP = ARCHIVE_RECORD_SOURCE_OPTIONS.reduce( + (acc, cur) => ({ ...acc, [cur.value]: cur.label }), + {}, +); diff --git a/src/pages/Container/SafetyEvalBusiness/EvalReportLibrary/index.less b/src/pages/Container/SafetyEvalBusiness/EvalReportLibrary/index.less index 09cd6cc..bf0fa71 100644 --- a/src/pages/Container/SafetyEvalBusiness/EvalReportLibrary/index.less +++ b/src/pages/Container/SafetyEvalBusiness/EvalReportLibrary/index.less @@ -249,7 +249,7 @@ border-radius: 4px; background: #eff6ff; color: #475569; - font-size: 13px; + font-size: 14px; line-height: 1.65; strong { diff --git a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveContent.js b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveContent.js index 091d65e..0a1b326 100644 --- a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveContent.js +++ b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveContent.js @@ -1,13 +1,10 @@ import React, { useState, useEffect } from "react"; import { - Tag, Button, - Card, Table, Input, Flex, - Popover, - Image, + Select, Row, Col, DatePicker, @@ -16,33 +13,43 @@ import { } from "antd"; import dayjs from "dayjs"; import { Connect } from "@cqsjjb/jjb-dva-runtime"; +import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction"; import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace"; import { tools } from "@cqsjjb/jjb-common-lib"; import LayoutFooterPortal from "~/components/LayoutFooterPortal"; +import PreviewUrlButton from "~/components/PreviewUrlButton"; +import ArchiveSupplementModal from "./ArchiveSupplementModal"; +import { + + ARCHIVE_RECORD_SOURCE_OPTIONS, + ARCHIVE_RECORD_SOURCE_BADGE_MAP, +} from "~/enumerate/constant"; const { router } = tools; const ArchiveContent = ({ readOnly, ...props }) => { const projectId = router.query?.id; - const { processControlDetail, processControlFiles, evalProjectDetailData } = + const { processControlDetail, evalProjectDetailData } = props.safetyEvalBusiness || {}; const { processControl, archiveFlag } = processControlDetail || {}; - const [files, setFiles] = useState([]); const [archiveForm] = Form.useForm(); + const [archiveFiles, setArchiveFiles] = useState([]); + const [archiveTotal, setArchiveTotal] = useState(0); + const [archiveQuery, setArchiveQuery] = useState({ + pageIndex: 1, + pageSize: 10, + recordSource: "", + }); + const [supplementOpen, setSupplementOpen] = useState(false); const fetchDetail = () => { props.evalProcessControlDetail({ projectId }); }; - const fetchFiles = () => { - props.evalProcessControlFiles({ projectId }); - }; - useEffect(() => { if (projectId) { fetchDetail(); - fetchFiles(); } }, [projectId]); @@ -59,11 +66,26 @@ const ArchiveContent = ({ readOnly, ...props }) => { } }, [processControlDetail]); + const fetchArchiveFiles = () => { + props + .evalProjectArchiveFileOrgPage({ + projectId, + pageIndex: archiveQuery.pageIndex, + pageSize: archiveQuery.pageSize, + recordSource: archiveQuery.recordSource || undefined, + }) + .then((res) => { + if (res?.success !== false) { + setArchiveFiles(res?.data || []); + setArchiveTotal(res?.totalCount || 0); + } + }); + }; + useEffect(() => { - if (processControlFiles) { - setFiles(processControlFiles); - } - }, [processControlFiles]); + if (!projectId) return; + fetchArchiveFiles(); + }, [projectId, archiveQuery]); const isSignatureCompleted = processControl?.reviewerSignatureTaskStatus === "completed"; @@ -80,91 +102,127 @@ const ArchiveContent = ({ readOnly, ...props }) => { } }; - const isImage = (name) => - /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i.test(name || ""); + /** 解析文件地址:相对路径拼接 window.fileUrl */ + const resolveFileUrl = (raw) => { + if (!raw) return ""; + const u = String(raw); + return /^https?:\/\//i.test(u) ? u : `${window.fileUrl || ""}${u}`; + }; - const fileColumns = [ - { title: "流程名称", dataIndex: "processName", ellipsis: true }, - { title: "条目名称", dataIndex: "itemName", ellipsis: true }, + const handleDownload = (file) => { + const url = resolveFileUrl(file.fileUrl); + if (!url) return; + const a = document.createElement("a"); + a.href = url; + a.download = file.fileName || ""; + a.target = "_blank"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + + const archiveColumns = [ { - title: "文件", - dataIndex: "projectDocUrl", - render: (val) => { - let fileList = []; - if (typeof val === "string") { - try { - fileList = JSON.parse(val); - } catch { - fileList = []; - } - } else if (Array.isArray(val)) { - fileList = val; - } - if (!fileList.length) return "-"; - return ( - - - {fileList.map((f, i) => { - const url = f.url || f.response?.url; - return isImage(f.name) ? ( - - {} - - ) : ( - window.open(url)} - > - {f.name || "查看文件"} - - ); - })} - - } - trigger="hover" - placement="topLeft" - > - e.preventDefault()} - style={{ cursor: "pointer" }} - > - {fileList.length}个附件 - - - - ); - }, + title: "序号", + width: 60, + render: (_, __, index) => + (archiveQuery.pageIndex - 1) * archiveQuery.pageSize + index + 1, + }, + { + title: "文件名称", + dataIndex: "fileName", + ellipsis: true, + render: (v) => v || "-", + }, + { + title: "档案类型", + dataIndex: "archiveType", + width: 130, + + }, + { + title: "来源/业务节点", + dataIndex: "recordSource", + width: 150, + render: (v, r) => ( + + + {ARCHIVE_RECORD_SOURCE_BADGE_MAP[v] || v || "-"} + + {r.businessNode || "-"} + + ), + }, + { + title: "形成/上传人员", + dataIndex: "createName", + width: 120, + render: (v) => v || "-", + }, + { + title: "形成时间", + dataIndex: "createTime", + width: 160, + align: "right", + render: (v) => v || "-", + }, + { + title: "操作", + width: 110, + render: (_, r) => ( + + 查看 + handleDownload(r)} + > + 下载 + + + ), }, ]; return ( - - - - 项目归档 - - - 项目过程文件清单,确认签字完成后归档入库 - - + + + + + setArchiveQuery((q) => ({ ...q, recordSource: v, pageIndex: 1 })) + } + options={[ + { label: "全部来源", value: "" }, + ...ARCHIVE_RECORD_SOURCE_OPTIONS, + ]} + className="pf-archive__source-select" + /> + - `${record.processName}-${record.materialName}-${record.itemName}` - } - pagination={false} + rowKey="id" size="small" + dataSource={archiveFiles} + columns={archiveColumns} + loading={props.safetyEvalBusiness?.evalProjectArchiveFileOrgLoading} + pagination={{ + total: archiveTotal, + current: archiveQuery.pageIndex, + pageSize: archiveQuery.pageSize, + showQuickJumper: true, + showTotal: (t) => `共 ${t} 条`, + onChange: (page, pageSize) => + setArchiveQuery((q) => ({ ...q, pageIndex: page, pageSize })), + }} /> @@ -197,18 +255,33 @@ const ArchiveContent = ({ readOnly, ...props }) => { {!readOnly && ( + setSupplementOpen(true)}> + 补充上传 + - {archiveFlag ? '已归档' : '双方签字并确认入库'} + {archiveFlag ? '已归档' : '确认归档入库'} )} - + + setSupplementOpen(false)} + onSuccess={() => { + setSupplementOpen(false); + fetchArchiveFiles(); + }} + /> + ); }; diff --git a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveSupplementModal.js b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveSupplementModal.js new file mode 100644 index 0000000..ac901e5 --- /dev/null +++ b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/ArchiveSupplementModal.js @@ -0,0 +1,85 @@ +import React from "react"; +import { Form, Input, Modal, message } from "antd"; +import AttachmentUpload from "~/components/AttachmentUpload"; + +const { TextArea } = Input; + +/** 补充上传项目档案弹窗(原型 modal-archive-supplement) */ +function ArchiveSupplementModal({ + open, + projectId, + loading, + onAdd, + onClose, + onSuccess, +}) { + const [form] = Form.useForm(); + + const handleOk = async () => { + const values = await form.validateFields(); + const fileList = values.file || []; + if (fileList.some((f) => f.status === "uploading")) { + message.warning("文件正在上传中,请等待上传完成"); + return; + } + const doneFiles = fileList.filter((f) => f.status === "done" && f.url); + if (!doneFiles.length) { + message.warning("请先上传资料文件"); + return; + } + const total = doneFiles.length; + const res = await onAdd({ + projectId, + archiveType: values.archiveType, + businessNode: "文档上传", + recordSource: "upload_additional_files", + remark: values.remark, + file: doneFiles, + }); + if (res?.success === false) return; + message.success("补充档案已上传"); + onSuccess?.(); + }; + + return ( + + + + + + + + + + + + + + + ); +} + +export default ArchiveSupplementModal; diff --git a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.js b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.js index 6eabb4c..5f127b0 100644 --- a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.js +++ b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.js @@ -173,7 +173,6 @@ const ProjectFlow = (props) => { }; const openReportEditor = async () => { - // 2026-08-18 前置拦截:报告文档 fileId 缺省(文档尚未生成/加载完成)时提示,不打开编辑器,避免 SDK 报错 if (!wpsDoc?.fileId) { message.warning("报告文档尚未生成,请先创建报告后再查看"); return; diff --git a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.less b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.less index 1dc8607..4c6c62f 100644 --- a/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.less +++ b/src/pages/Container/SafetyEvalBusiness/ProjectFlow/index.less @@ -290,4 +290,35 @@ &-hidden-control { display: none; } +} + +// 档案内容 - 档案文件列表 +.pf-archive { + &__toolbar { + margin-bottom: 12px; + } + + &__source-select { + width: 140px; + } + + &__source-tag { + display: inline-block; + width: fit-content; + padding: 2px 10px; + color: #fff; + font-size: 14px; + line-height: 20px; + background: #52c41a; + border-radius: 4px; + + &--upload { + background: #1677ff; + } + } + + &__node { + color: #94a3b8; + font-size: 14px; + } } \ No newline at end of file diff --git a/src/pages/Container/Supervision/EvalProjectDatabase/ArchiveModal.js b/src/pages/Container/Supervision/EvalProjectDatabase/ArchiveModal.js new file mode 100644 index 0000000..a91f867 --- /dev/null +++ b/src/pages/Container/Supervision/EvalProjectDatabase/ArchiveModal.js @@ -0,0 +1,185 @@ +import React, { useEffect, useState } from "react"; +import { Button, Input, Modal, Table, Tag } from "antd"; +import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction"; +import PreviewUrlButton from "~/components/PreviewUrlButton"; +import { + ARCHIVE_TYPE_MAP, + ARCHIVE_RECORD_SOURCE_MAP, +} from "~/enumerate/constant"; + +/** 解析文件地址:相对路径拼接 window.fileUrl(与 PreviewUrlButton 保持一致) */ +const resolveFileUrl = (raw) => { + if (!raw) return ""; + const u = String(raw); + return /^https?:\/\//i.test(u) ? u : `${window.fileUrl || ""}${u}`; +}; + +/** 项目档案查看弹窗(原型 modal-reg-project-archive) */ +function ArchiveModal({ record, loading, fetchFiles, onClose }) { + const [query, setQuery] = useState({ pageIndex: 1, pageSize: 10, fileName: "" }); + const [list, setList] = useState([]); + const [total, setTotal] = useState(0); + + + + useEffect(() => { + if (!record?.id) return; + fetchFiles({ projectId: record.id, ...query }).then((res) => { + if (res?.success !== false) { + setList(res?.data || []); + setTotal(res?.totalCount || 0); + } + }); + }, [record?.id, query]); + + const handleDownload = (file) => { + const url = resolveFileUrl(file.fileUrl); + if (!url) return; + const a = document.createElement("a"); + a.href = url; + a.download = file.fileName || ""; + a.target = "_blank"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + + const columns = [ + { + title: "序号", + width: 60, + render: (_, __, index) => + (query.pageIndex - 1) * query.pageSize + index + 1, + }, + { + title: "文件名称", + dataIndex: "fileName", + ellipsis: true, + render: (v, r) => ( + + {v || "-"} + + {r.recordSource === "upload_additional_files" + ? "评价机构补充上传" + : "业务节点自动归集"} + + + ), + }, + { + title: "档案类型", + dataIndex: "archiveType", + width: 130, + + }, + { + title: "来源", + dataIndex: "recordSource", + width: 120, + render: (v) => + v ? ( + + {ARCHIVE_RECORD_SOURCE_MAP[v]} + + ) : ( + "-" + ), + }, + { + title: "业务节点", + dataIndex: "businessNode", + width: 130, + render: (v) => v || "-", + }, + { + title: "操作", + width: 120, + render: (_, r) => ( + + 查看 + handleDownload(r)} + > + 下载 + + + ), + }, + ]; + + const processCount = record?.processFileCount ?? 0; + const additionalCount = record?.additionalFileCount ?? 0; + + return ( + + 项目档案查看 + + 查看项目执行过程中由系统形成及机构补充上传的档案资料 + + + } + width={1000} + footer={关闭} + destroyOnHidden + onCancel={onClose} + className="epd-archive" + > + + + 项目名称 + {record?.projectName || "-"} + {record?.projectNo} + + + 评价机构 + {record?.orgName || "-"} + + + 评价类型 + {record?.evalTypeName || "-"} + + + 档案数量 + {processCount + additionalCount} 份 + + 流程文档 {processCount} / 补充文件 {additionalCount} + + + + + setQuery((q) => ({ ...q, fileName: v, pageIndex: 1 }))} + className="epd-archive__search" + /> + + `共 ${t} 条`, + onChange: (page, pageSize) => + setQuery((q) => ({ ...q, pageIndex: page, pageSize })), + }} + /> + + ); +} + +export default ArchiveModal; diff --git a/src/pages/Container/Supervision/EvalProjectDatabase/index.js b/src/pages/Container/Supervision/EvalProjectDatabase/index.js index 065bd67..0084664 100644 --- a/src/pages/Container/Supervision/EvalProjectDatabase/index.js +++ b/src/pages/Container/Supervision/EvalProjectDatabase/index.js @@ -10,6 +10,7 @@ import { NS_SAFETY_EVAL_BUSINESS } from "~/enumerate/namespace"; import { EVAL_TYPE_OPTIONS, EVAL_TYPE_MAP } from "~/enumerate/constant"; import { tools } from "@cqsjjb/jjb-common-lib"; import TableAction from "@cqsjjb/jjb-react-admin-component/TableAction"; +import ArchiveModal from "./ArchiveModal"; import "./index.less"; @@ -27,6 +28,7 @@ function EvalProjectDatabase(props) { const [searchForm] = Form.useForm(); const [dataSource, setDataSource] = useState([]); const [total, setTotal] = useState(0); + const [archiveRecord, setArchiveRecord] = useState(null); const { safetyEvalBusiness, @@ -113,14 +115,16 @@ function EvalProjectDatabase(props) { { title: "最近更新", dataIndex: "updateTime", + width: 180, }, { title: "操作", dataIndex: "operate", - fix: 'right', + fixed: "right", width: 200, render: (_, record) => { return + setArchiveRecord(record)}>查看档案 { props.history.push(`/container/MonitorManage/EvalProjectMonitor/Detail?id=${record.id}`) }}>项目过程 @@ -189,6 +193,13 @@ function EvalProjectDatabase(props) { }} onChange={handlePageChange} /> + + {archiveRecord&& setArchiveRecord(null)} + />} ); } diff --git a/src/pages/Container/Supervision/EvalProjectDatabase/index.less b/src/pages/Container/Supervision/EvalProjectDatabase/index.less index ccdefbb..82519ee 100644 --- a/src/pages/Container/Supervision/EvalProjectDatabase/index.less +++ b/src/pages/Container/Supervision/EvalProjectDatabase/index.less @@ -3,9 +3,59 @@ margin: 12px 0 16px; padding: 10px 16px; color: rgba(0, 0, 0, 65%); - font-size: 13px; + font-size: 14px; line-height: 1.6; background: #fffbe6; border: 1px solid #ffe58f; border-radius: 6px; } + +/* 项目档案查看弹窗 */ +.epd-archive { + &__subtitle { + margin-top: 4px; + color: #64748b; + font-size: 14px; + font-weight: normal; + } + + &__meta { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 6px; + margin-bottom: 16px; + padding: 12px 16px; + background: #f8fafc; + border-radius: 6px; + + > div { + display: flex; + flex-direction: column; + + span { + color: #64748b; + font-size: 14px; + } + + strong { + color: #0f172a; + font-size: 14px; + } + + small { + color: #94a3b8; + font-size: 14px; + } + } + } + + &__search { + margin-bottom: 12px; + max-width: 320px; + } + + &__file-source { + color: #94a3b8; + font-size: 14px; + } +}