diff --git a/jjb.config.js b/jjb.config.js index 054f850..b95671a 100644 --- a/jjb.config.js +++ b/jjb.config.js @@ -10,9 +10,9 @@ module.exports = { javaGitBranch: "dev", // 本地联调 safetyEval-service(context-path: /safetyEval,默认端口 8095) // 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095 - API_HOST: "https://gbs-gateway.qhdsafety.com", + // API_HOST: "https://gbs-gateway.qhdsafety.com", - //API_HOST: "http://192.168.0.152", + API_HOST: "http://192.168.0.134", //API_HOST: "http://192.168.0.150", //太浅 // API_HOST: "http://192.168.0.152", //API_HOST: "http://192.168.0.103", //huwei diff --git a/src/components/StaffViewModal/index.js b/src/components/StaffViewModal/index.js index da5246b..5eb3290 100644 --- a/src/components/StaffViewModal/index.js +++ b/src/components/StaffViewModal/index.js @@ -9,7 +9,10 @@ import { fetchStaffCertListByPersonnelId, } from "~/api/staffCertificate"; import { fetchOrgPersonnelDetail } from "~/utils/qualFiling/personnelHelper"; -import { QUALIFICATION_INDUSTRY_OPTIONS_MAP, TITLE_LEVEL_MAP } from "~/enumerate/enterpriseOptions"; +import { + QUALIFICATION_INDUSTRY_OPTIONS_MAP, + TITLE_LEVEL_MAP, +} from "~/enumerate/enterpriseOptions"; const GENDER_MAP = { 1: "男", 2: "女" }; const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" }; @@ -99,6 +102,54 @@ export default function StaffViewModal({ ? JSON.parse(info.proofMaterialUrl) : []; + const titleCodeArr = Array.isArray(info.titleCodeArr) + ? info.titleCodeArr.map((item) => { + let proveUrlList = []; + if (item.proveUrl) { + try { + proveUrlList = + typeof item.proveUrl === "string" + ? JSON.parse(item.proveUrl) + : item.proveUrl; + } catch { + proveUrlList = []; + } + } + return { + industryName: + QUALIFICATION_INDUSTRY_OPTIONS_MAP[item.industryCode] || + item.industryCode || + "-", + titleName: TITLE_LEVEL_MAP[item.titleCode] || item.titleCode || "-", + proveUrlList, + }; + }) + : []; + + const renderFileList = (files) => { + if (!files?.length) return "-"; + return files.map((item) => { + const isImage = /\.(jpg|jpeg|png|gif|webp|bmp|svg)(\?.*)?$/i.test( + item.url, + ); + return ( +
+ {isImage ? ( + + ) : ( + + )} +
+ ); + }); + }; + const certPreviewFiles = certPreviewInfo?.certImgs?.length ? certPreviewInfo.certImgs : certPreviewInfo?.certImgFiles || []; @@ -134,35 +185,30 @@ export default function StaffViewModal({ {info.account} {info.deptName} {info.postName} - - {info.personTypeName || "基础人员"} - - - {QUALIFICATION_INDUSTRY_OPTIONS_MAP[info.qualScope] || info.qualScope || "-"} - - - {info.professionalLevelName || "-"} - - - {info.evaluatorCertNo || "-"} - + {info.educationTypeName || "-"} {info.educationLevelName || "-"} - - {TITLE_LEVEL_MAP[info.titleCode] ?? (info.titleCode || "-")} - + {REGISTER_ENGINEER_MAP[info.registerEngineerFlag] ?? "-"} - {info.technicalDirectorFlag === true ? "是" : info.technicalDirectorFlag === false ? "否" : "-"} + {info.technicalDirectorFlag === true + ? "是" + : info.technicalDirectorFlag === false + ? "否" + : "-"} - {info.processControlLeaderFlag === true ? "是" : info.processControlLeaderFlag === false ? "否" : "-"} + {info.processControlLeaderFlag === true + ? "是" + : info.processControlLeaderFlag === false + ? "否" + : "-"} {info.idCardNo} @@ -177,7 +223,7 @@ export default function StaffViewModal({ {info.graduateSchool} - {info.major} + {info.workExperience || "-"} - + {proofMaterialUrl.length ? proofMaterialUrl.map((item) => { const isImage = @@ -219,6 +265,25 @@ export default function StaffViewModal({ : "-"} +
+ 职称信息 +
+ idx} + dataSource={titleCodeArr} + columns={[ + { title: "行业", dataIndex: "industryName", width: 150 }, + { title: "职称", dataIndex: "titleName", width: 100 }, + { + title: "证明材料", + dataIndex: "proveUrlList", + render: renderFileList, + }, + ]} + />
证照信息 @@ -231,10 +296,10 @@ export default function StaffViewModal({ dataSource={certificates} locale={{ emptyText: "暂无证照信息" }} columns={[ - { title: "证照名称", dataIndex: "certName",ellipsis: true }, - { title: "证书编号", dataIndex: "certNo",ellipsis: true }, - { title: "证书类别", dataIndex: "certTypeName",ellipsis: true }, - { title: "发证机关", dataIndex: "issueOrg",ellipsis: true }, + { title: "证照名称", dataIndex: "certName", ellipsis: true }, + { title: "证书编号", dataIndex: "certNo", ellipsis: true }, + { title: "证书类别", dataIndex: "certTypeName", ellipsis: true }, + { title: "发证机关", dataIndex: "issueOrg", ellipsis: true }, { title: "有效开始日期", dataIndex: "validStartDate", width: 120 }, { title: "有效结束日期", dataIndex: "validEndDate", width: 120 }, { @@ -314,11 +379,16 @@ export default function StaffViewModal({ {certPreviewInfo.certAttachmentUrl && certPreviewInfo.certAttachmentUrl.split(",").map((item) => { - const isImage = /\.(png|jpe?g|gif|bmp|webp|svg)(\?|#|$)/i.test(item); + const isImage = + /\.(png|jpe?g|gif|bmp|webp|svg)(\?|#|$)/i.test(item); return (
{isImage ? ( - + ) : ( window.open(item)}>{item} )} diff --git a/src/enumerate/constant/index.js b/src/enumerate/constant/index.js index f7c2d23..74d8704 100644 --- a/src/enumerate/constant/index.js +++ b/src/enumerate/constant/index.js @@ -481,3 +481,5 @@ export const NATIONAL_COUNTIES = (() => { }); return result; })(); + + diff --git a/src/enumerate/enterpriseOptions.js b/src/enumerate/enterpriseOptions.js index abe601b..c052f16 100644 --- a/src/enumerate/enterpriseOptions.js +++ b/src/enumerate/enterpriseOptions.js @@ -138,27 +138,7 @@ export const PERSON_TYPE_OPTIONS = [ { label: "专职评价师", value: "专职评价师" }, ]; -/** 职业等级 */ -export const PROFESSIONAL_LEVEL_OPTIONS = [ - { - label: "三级安全评价师(对应职业技能等级三级 / 高级工,入门级)", - value: "三级安全评价师(对应职业技能等级三级 / 高级工,入门级)", - }, - { - label: "二级安全评价师(对应职业技能等级二级 / 技师,中级)", - value: "二级安全评价师(对应职业技能等级二级 / 技师,中级)", - }, - { - label: "一级安全评价师(对应职业技能等级一级 / 高级技师,最高级)", - value: "一级安全评价师(对应职业技能等级一级 / 高级技师,最高级)", - }, -]; -export const PROFESSIONAL_LEVEL_OPTIONS_MAP = - PROFESSIONAL_LEVEL_OPTIONS.reduce( - (acc, cur) => ({ ...acc, [cur.value]: cur.label }), - {}, - ); /** 学历类型 */ export const EDUCATION_TYPE_OPTIONS = [ diff --git a/src/pages/Container/EnterpriseInfo/PersonnelInfo/List/index.js b/src/pages/Container/EnterpriseInfo/PersonnelInfo/List/index.js index b4d32b2..c6a35c1 100644 --- a/src/pages/Container/EnterpriseInfo/PersonnelInfo/List/index.js +++ b/src/pages/Container/EnterpriseInfo/PersonnelInfo/List/index.js @@ -1,5 +1,6 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { + Alert, Button, DatePicker, Form, @@ -9,9 +10,12 @@ import { Row, Col, Select, + Space, Table, TreeSelect, + Upload, } from "antd"; +import { InboxOutlined } from "@ant-design/icons"; import { Get } from "@cqsjjb/jjb-common-lib/http"; import { useEffect, useRef, useState } from "react"; import dayjs from "dayjs"; @@ -25,8 +29,6 @@ import { NS_STAFF_INFO, NS_ORG_DEPARTMENT } from "~/enumerate/namespace"; import { EDUCATION_LEVEL_OPTIONS, EDUCATION_TYPE_OPTIONS, - PERSON_TYPE_OPTIONS, - PROFESSIONAL_LEVEL_OPTIONS, QUALIFICATION_INDUSTRY_OPTIONS, REGISTER_ENGINEER_OPTIONS, TITLE_LEVEL_OPTIONS, @@ -37,10 +39,12 @@ import AttachmentUpload from "~/components/AttachmentUpload"; import StaffViewModal from "~/components/StaffViewModal"; const { router } = tools; +const API_HOST = window.process?.env?.app?.API_HOST || ""; function PersonnelInfoPage(props) { const [formModalOpen, setFormModalOpen] = useState(false); const [viewModalOpen, setViewModalOpen] = useState(false); + const [importModalOpen, setImportModalOpen] = useState(false); const [currentId, setCurrentId] = useState(""); const [searchForm] = Form.useForm(); const [deptOptions, setDeptOptions] = useState([]); @@ -136,15 +140,18 @@ function PersonnelInfoPage(props) {
} extra={ - + + + + } > text || "-", + }, + { + title: "能力", + width: 80, + dataIndex: "abilityNames", + ellipsis: true, + render: (text) => '暂无', }, { title: "操作", @@ -248,7 +262,7 @@ function PersonnelInfoPage(props) { goCertificate(record.id, record.userName); }} > - 证书 + 证书能力
- + @@ -544,12 +591,9 @@ function StaffFormModal({ - + @@ -601,27 +645,7 @@ function StaffFormModal({ - - - - - + { - form.setFieldValue("professionalLevelName", option?.label || undefined); - }} - /> - - - - - - - - + - + + - - - + + + + + + {(fields, { add, remove }) => ( + <> +
field.key} + pagination={false} + size="small" + bordered + locale={{ emptyText: "暂无职称信息,点击下方按钮添加" }} + columns={[ + { + title: "行业", + width: 200, + render: (_, field) => ( + + + + ), + }, + { + title: "证明材料", + render: (_, field) => ( + + ), + }, + { + title: "操作", + width: 80, + render: (_, field) => ( + + ), + }, + ]} + /> + + + )} + @@ -726,7 +851,12 @@ function StaffFormModal({ label="出版学术专著、专利、获奖、发表学术论文等" rules={[{ max: 500, message: "不能超过1000个字符" }]} > - + @@ -735,27 +865,25 @@ function StaffFormModal({ label="自我申报的专业能力及认定方式" rules={[{ max: 500, message: "不能超过1000个字符" }]} > - + - - + + - - - + - - - - - ); } +function StaffImportModal({ open, onCancel, onSuccess }) { + const [result, setResult] = useState(null); + const [errorMsg, setErrorMsg] = useState(""); + const [uploading, setUploading] = useState(false); + + const handleDownloadTemplate = async () => { + try { + const res = await Get("/safetyEval/org-personnel/import/template"); + const url = res?.data ; + if (!url) { + message.warning("未获取到模板下载地址"); + return; + } + const resolved = /^https?:\/\//i.test(url) + ? url + : `${window.fileUrl || API_HOST}${url}`; + const response = await fetch(resolved); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + const blob = await response.blob(); + const blobUrl = window.URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = blobUrl; + link.download = "人员导入模板.xlsx"; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(blobUrl); + } catch (err) { + message.error(err?.message || "下载模板失败"); + } + }; + + const customRequest = async (options) => { + const { file, onSuccess: onDone, onError } = options; + setUploading(true); + setResult(null); + setErrorMsg(""); + try { + const formData = new FormData(); + formData.append("file", file); + const headers = { token: sessionStorage.getItem("token") || "" }; + const orgInfoId = sessionStorage.getItem("orgInfoId"); + if (orgInfoId) headers.orgInfoId = String(orgInfoId); + const resp = await fetch( + `${API_HOST}/safetyEval/org-personnel/import`, + { method: "POST", headers, body: formData }, + ); + const json = await resp.json(); + if (json && json.success !== false) { + onDone(json.data, file); + setResult(json.data || {}); + if ((json.data?.successCount || 0) > 0) onSuccess?.(); + } else { + onError(new Error(json?.errMessage || json?.message || "导入失败")); + setErrorMsg(json?.errMessage || json?.message || "导入失败"); + } + } catch (err) { + onError(err); + setErrorMsg(err?.message || "导入失败"); + } finally { + setUploading(false); + } + }; + + const errorList = result?.errors || []; + + return ( + 关闭} + > +
+ +
+ { + const ext = + "." + (file.name.split(".").pop() || "").toLowerCase(); + if (![".xlsx", ".xls"].includes(ext)) { + message.error("仅支持 .xlsx / .xls 格式文件"); + return Upload.LIST_IGNORE; + } + return true; + }} + onRemove={() => { + setResult(null); + setErrorMsg(""); + return true; + }} + > +

+ +

+

点击或拖拽文件到此区域上传

+

仅支持 .xlsx / .xls 格式文件

+
+ + {errorMsg && ( + + )} + {result && ( + 0 ? "warning" : "success"} + showIcon + message={`成功导入 ${result.successCount || 0} 条,失败 ${result.failCount || 0} 条`} + /> + )} + {errorList.length > 0 && ( +
i} + pagination={false} + scroll={{ y: 240 }} + dataSource={errorList} + columns={[ + { title: "行号", dataIndex: "rowIndex", width: 70 }, + { title: "账号", dataIndex: "account", ellipsis: true }, + { title: "姓名", dataIndex: "userName", ellipsis: true }, + { title: "异常原因", dataIndex: "errorMessage", ellipsis: true }, + ]} + /> + )} + + ); +} + export default Connect( [NS_STAFF_INFO, NS_ORG_DEPARTMENT], true, diff --git a/src/pages/Container/SafetyEvalBusiness/EvalProject/Create/StaffPickerModal.js b/src/pages/Container/SafetyEvalBusiness/EvalProject/Create/StaffPickerModal.js index ca9d64b..a6ef2d9 100644 --- a/src/pages/Container/SafetyEvalBusiness/EvalProject/Create/StaffPickerModal.js +++ b/src/pages/Container/SafetyEvalBusiness/EvalProject/Create/StaffPickerModal.js @@ -13,7 +13,7 @@ import { import { CloseOutlined } from "@ant-design/icons"; import { NS_STAFF_INFO, NS_ORG_DEPARTMENT } from "~/enumerate/namespace"; import { Connect } from "@cqsjjb/jjb-dva-runtime"; -import { QUALIFICATION_INDUSTRY_OPTIONS_MAP, PROFESSIONAL_LEVEL_OPTIONS_MAP, TITLE_LEVEL_MAP } from "~/enumerate/enterpriseOptions"; +import { QUALIFICATION_INDUSTRY_OPTIONS_MAP, TITLE_LEVEL_MAP } from "~/enumerate/enterpriseOptions"; @@ -129,15 +129,7 @@ const StaffPickerModal = (props) => { return status || "-"; }, }, - { - title: "职业等级", - dataIndex: "professionalLevelCode", - ellipsis: true, - render: (code) => { - const status = PROFESSIONAL_LEVEL_OPTIONS_MAP[code]; - return status || "-"; - }, - }, + { title: "职称", dataIndex: "titleCode", diff --git a/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js b/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js index 1b983fe..c5e31cc 100644 --- a/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js +++ b/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js @@ -372,7 +372,7 @@ function OrgAccountPage(props) { {detail.districtName} - + {detail.safetyIndustryCategoryName} @@ -449,7 +449,7 @@ function OrgAccountPage(props) {