Merge remote-tracking branch 'origin/dev-tmp1' into dev-tmp1
commit
c2d83f6adf
|
|
@ -0,0 +1,49 @@
|
||||||
|
评价人员任命及专家聘用书
|
||||||
|
|
||||||
|
根据市场部下达的评价项目为: {projectName} {evalTypeText} 评价任务,结合项目的特性,现任命 {projectLeader} 担任该安全评价项目组长(负责人), {compiler} 担任该项目报告编制人。
|
||||||
|
根据评价部项目组组建原则及风险分析记录情况,项目组成员如下:
|
||||||
|
|
||||||
|
人员组成
|
||||||
|
姓名
|
||||||
|
专业
|
||||||
|
项目负责人
|
||||||
|
{projectLeaderName}
|
||||||
|
{projectLeaderCapacity}
|
||||||
|
|
||||||
|
项目组成员
|
||||||
|
{firstMemberName}
|
||||||
|
{firstMemberMajor}
|
||||||
|
|
||||||
|
{#memberRows}{name}
|
||||||
|
{major}{/memberRows}
|
||||||
|
报告编制人
|
||||||
|
{firstCompilerName}
|
||||||
|
{firstCompilerCapacity}
|
||||||
|
|
||||||
|
{#compilerRows}{compilerName}
|
||||||
|
{compilerCapacity}{/compilerRows}
|
||||||
|
内审人员
|
||||||
|
{firstAuditorName}
|
||||||
|
{firstAuditorCapacity}
|
||||||
|
|
||||||
|
{#auditorRows}{auditorName}
|
||||||
|
{auditorCapacity}{/auditorRows}
|
||||||
|
技术负责人
|
||||||
|
{firstTechLeadName}
|
||||||
|
{firstTechLeadCapacity}
|
||||||
|
|
||||||
|
{#techLeadRows}{techLeadName}
|
||||||
|
{techLeadCapacity}{/techLeadRows}
|
||||||
|
过程控制负责人
|
||||||
|
{processControlLeadName}
|
||||||
|
{processControlLeadCapacity}
|
||||||
|
聘用专家组成员
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
评价部经理:
|
||||||
|
年 月 日
|
||||||
|
|
||||||
|
|
@ -181,7 +181,7 @@ export const evalProjectMemberPage = declareRequest(
|
||||||
|
|
||||||
export const evalProjectEstablishedAttachSave = declareRequest(
|
export const evalProjectEstablishedAttachSave = declareRequest(
|
||||||
"projectEstablishedAttachSaveLoading",
|
"projectEstablishedAttachSaveLoading",
|
||||||
"Post > /safetyEval/institution/eval-project-member/saveProjectEstablishedAttach",
|
"Post > @/safetyEval/institution/eval-project-member/saveProjectEstablishedAttach",
|
||||||
);
|
);
|
||||||
|
|
||||||
export const evalProjectEstablishedAttachGet = declareRequest(
|
export const evalProjectEstablishedAttachGet = declareRequest(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,12 @@ export const staffInfoList = declareRequest(
|
||||||
"staffInfoList: [] | res.data || [] & staffInfoTotal: 0 | res.total || 0",
|
"staffInfoList: [] | res.data || [] & staffInfoTotal: 0 | res.total || 0",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const staffInfoRegulationPage = declareRequest(
|
||||||
|
"staffInfoLoading",
|
||||||
|
"Get > /safetyEval/org-personnel/regulationPage",
|
||||||
|
"staffInfoList: [] | res.data || [] & staffInfoTotal: 0 | res.total || 0",
|
||||||
|
);
|
||||||
|
|
||||||
export const staffInfoDeptPersonCount = declareRequest(
|
export const staffInfoDeptPersonCount = declareRequest(
|
||||||
"staffInfoLoading",
|
"staffInfoLoading",
|
||||||
"Get > /safetyEval/org-personnel/deptPersonCount",
|
"Get > /safetyEval/org-personnel/deptPersonCount",
|
||||||
|
|
|
||||||
|
|
@ -600,6 +600,17 @@ export const CAPABILITY_MAP = CAPABILITY_OPTIONS.reduce((acc, cur) => {
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
/** 业务范围与所需专业能力配备标准对照(依据《安全评价机构资质条件》应急〔2026〕60号附件) */
|
||||||
|
export const INDUSTRY_REQUIRED_CAPABILITIES = {
|
||||||
|
COAL_MINING: ["SAFETY", "MECHANICAL", "ELECTRICAL", "MINING", "VENTILATION", "GEOLOGY", "MINE_CONSTRUCTION"],
|
||||||
|
METAL_NONMETAL_MINING: ["SAFETY", "MECHANICAL", "ELECTRICAL", "MINING", "VENTILATION", "GEOLOGY", "HYDRAULIC_STRUCTURE"],
|
||||||
|
ONSHORE_OIL_GAS: ["SAFETY", "MECHANICAL", "ELECTRICAL", "OIL_PRODUCTION", "STORAGE_AND_TRANSPORT"],
|
||||||
|
ONSHORE_OIL_GAS_PIPELINE: ["OIL_GAS_STORAGE_TRANSPORT", "EQUIPMENT", "INSTRUMENT", "ELECTRICAL", "ANTICORROSION", "SAFETY"],
|
||||||
|
PETROCHEMICAL_CHEMICAL_PHARMACEUTICAL: ["CHEMICAL_PROCESS", "CHEMICAL_MECHANICAL", "AUTOMATION_INSTRUMENT", "ELECTRICAL", "SAFETY"],
|
||||||
|
FIREWORKS_FIRECRACKERS: ["EXPLOSIVES", "EXPLOSION_TECHNOLOGY", "MECHANICAL", "ELECTRICAL", "SAFETY"],
|
||||||
|
METAL_SMELTING: ["SAFETY", "MECHANICAL", "ELECTRICAL", "METALLURGY", "NONFERROUS_METAL"],
|
||||||
|
};
|
||||||
|
|
||||||
/** 专业(职称信息) */
|
/** 专业(职称信息) */
|
||||||
export const PROFESSIONAL_MAJOR_OPTIONS = [
|
export const PROFESSIONAL_MAJOR_OPTIONS = [
|
||||||
{ label: "安全工程", value: "SAFETY_ENGINEERING" },
|
{ label: "安全工程", value: "SAFETY_ENGINEERING" },
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import useIndustryOptions from "~/hooks/useIndustryOptions";
|
import useIndustryOptions from "~/hooks/useIndustryOptions";
|
||||||
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
||||||
import { district } from "~/enumerate/constant";
|
import { district } from "~/enumerate/constant";
|
||||||
import {REGISTER_ENGINEER_CATEGORY_OPTIONS} from '~/enumerate/enterpriseOptions';
|
import {QUALIFICATION_INDUSTRY_OPTIONS} from '~/enumerate/enterpriseOptions';
|
||||||
import { phoneRule } from "~/utils/validators";
|
import { phoneRule } from "~/utils/validators";
|
||||||
import { renderCapabilityList } from "~/utils";
|
import { renderCapabilityList } from "~/utils";
|
||||||
import StaffPickerModal from "./StaffPickerModal";
|
import StaffPickerModal from "./StaffPickerModal";
|
||||||
|
|
@ -29,6 +29,7 @@ import StaffPickerModal from "./StaffPickerModal";
|
||||||
import {
|
import {
|
||||||
EVAL_TYPE_OPTIONS,
|
EVAL_TYPE_OPTIONS,
|
||||||
CHECKIN_RADIUS_OPTIONS,
|
CHECKIN_RADIUS_OPTIONS,
|
||||||
|
INDUSTRY_REQUIRED_CAPABILITIES,
|
||||||
} from "~/enumerate/constant";
|
} from "~/enumerate/constant";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
@ -102,9 +103,27 @@ const EvalProjectCreate = (props) => {
|
||||||
setMapPickerVisible(false);
|
setMapPickerVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 按所选业务范围(配备标准)筛选人员能力,仅提交范围内所需的专业能力条目 */
|
||||||
|
const filterCapacityByIndustry = (item, industryCodes) => {
|
||||||
|
const requiredCaps = industryCodes.flatMap(
|
||||||
|
(code) => INDUSTRY_REQUIRED_CAPABILITIES[code] || [],
|
||||||
|
);
|
||||||
|
const capabilityAssessment= (item.capabilityAssessment || []).filter(item=>item.industryCode === industryCodes[0]) || [];
|
||||||
|
if (!requiredCaps.length || !Array.isArray(capabilityAssessment)) {
|
||||||
|
return capabilityAssessment?.length
|
||||||
|
? renderCapabilityList(capabilityAssessment, {capFlag: true})
|
||||||
|
: item.capacity;
|
||||||
|
}
|
||||||
|
const matched = capabilityAssessment.filter((cap) =>
|
||||||
|
requiredCaps.includes(cap.professionalCapabilityCode),
|
||||||
|
);
|
||||||
|
return matched.length ? renderCapabilityList(matched, {capFlag: true}) : item.capacity;
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
form.validateFields().then(async (values) => {
|
form.validateFields().then(async (values) => {
|
||||||
const { planStartDate, planEndDate, ...rest } = values;
|
const { planStartDate, planEndDate, ...rest } = values;
|
||||||
|
const industryCodes = String(values.industryCode || "").split(",");
|
||||||
const params = {
|
const params = {
|
||||||
...rest,
|
...rest,
|
||||||
planStartDate: planStartDate?.format("YYYY-MM-DD"),
|
planStartDate: planStartDate?.format("YYYY-MM-DD"),
|
||||||
|
|
@ -114,9 +133,7 @@ const EvalProjectCreate = (props) => {
|
||||||
name: item.userName,
|
name: item.userName,
|
||||||
deptName: item.deptName,
|
deptName: item.deptName,
|
||||||
posName: item.postName,
|
posName: item.postName,
|
||||||
capacity: item.capabilityAssessment
|
capacity: filterCapacityByIndustry(item, industryCodes),
|
||||||
? renderCapabilityList(item.capabilityAssessment)
|
|
||||||
: item.capacity,
|
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
@ -357,18 +374,18 @@ const EvalProjectCreate = (props) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
mode="multiple"
|
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
allowClear
|
allowClear
|
||||||
options={isStatutory?industryOptions:REGISTER_ENGINEER_CATEGORY_OPTIONS}
|
options={isStatutory?industryOptions:QUALIFICATION_INDUSTRY_OPTIONS}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
{/* <Col span={12}>
|
||||||
<Form.Item name="controlledNumber" label="受控编号" rules={[{ required: true, message: "请选择受控编号" }]}>
|
<Form.Item name="controlledNumber" label="受控编号" rules={[{ required: true, message: "请选择受控编号" }]}>
|
||||||
<Input placeholder="请输入" maxLength={20} />
|
<Input placeholder="请输入" maxLength={20} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col> */}
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,7 @@ const RiskAnalysisContent = ({ readOnly, ...props }) => {
|
||||||
Array.isArray(value) ? value.join(",") : value
|
Array.isArray(value) ? value.join(",") : value
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Select mode="multiple" placeholder="请选择所属行业" allowClear>
|
<Select placeholder="请选择所属行业" allowClear>
|
||||||
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
||||||
<Select.Option key={opt.value} value={opt.value}>
|
<Select.Option key={opt.value} value={opt.value}>
|
||||||
{opt.label}
|
{opt.label}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,9 @@ import { fillDocxTemplate } from "~/utils/fillDocxTemplate";
|
||||||
|
|
||||||
const { router } = tools;
|
const { router } = tools;
|
||||||
|
|
||||||
const TEAM_TEMPLATE_URL = "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/6a86d2b2e4b072649bfb8a93.docx";
|
const TEAM_TEMPLATE_URL = encodeURI(
|
||||||
|
"https://gbs-cqaqpj.oss-cn-beijing.aliyuncs.com/jjb/6a9165e2e4b0b3767a786858.docx",
|
||||||
|
);
|
||||||
|
|
||||||
const TeamContent = ({ readOnly, ...props }) => {
|
const TeamContent = ({ readOnly, ...props }) => {
|
||||||
const {
|
const {
|
||||||
|
|
@ -268,28 +270,57 @@ const TeamContent = ({ readOnly, ...props }) => {
|
||||||
setSigners((prev) => prev.filter((s) => s.personnelId !== personnelId));
|
setSigners((prev) => prev.filter((s) => s.personnelId !== personnelId));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 导出Word:按当前项目组配置填充模板(聘请所需技术专家、备注事项、部门经理或负责人、年月日保留空白)
|
// 导出Word:按当前项目组配置填充模板(任命语句用"姓名(能力)",表格姓名/专业分列展示;聘用专家、评价部经理、年月日留白)
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
/** 人员展示文本:姓名后追加能力,如"张三(化工)" */
|
/** 人员展示文本:姓名后追加能力,如"张三(化工)" */
|
||||||
const personText = (m) =>
|
const personText = (m) =>
|
||||||
`${m.personnelName}${m.capacity ? `(${m.capacity})` : ""}`;
|
`${m.personnelName}${m.capacity ? `(${m.capacity})` : ""}`;
|
||||||
|
const roleMembers = (role) =>
|
||||||
|
teamMembers.filter((m) => m.roles.some((r) => r.role === role));
|
||||||
|
const sentenceByRole = (role) =>
|
||||||
|
roleMembers(role).map(personText).join("、");
|
||||||
const namesByRole = (role) =>
|
const namesByRole = (role) =>
|
||||||
teamMembers
|
roleMembers(role).map((m) => m.personnelName).join("、");
|
||||||
.filter((m) => m.roles.some((r) => r.role === role))
|
const capsByRole = (role) =>
|
||||||
.map(personText)
|
roleMembers(role).map((m) => m.capacity).filter(Boolean).join("、");
|
||||||
.join("、");
|
const auditorList = roleMembers("INTERNAL_AUDITOR").map((m) => ({
|
||||||
|
auditorName: m.personnelName,
|
||||||
|
auditorCapacity: m.capacity || "",
|
||||||
|
}));
|
||||||
|
const techLeadList = roleMembers("TECHNICAL_LEAD").map((m) => ({
|
||||||
|
techLeadName: m.personnelName,
|
||||||
|
techLeadCapacity: m.capacity || "",
|
||||||
|
}));
|
||||||
|
const compilerList = roleMembers("REPORT_COMPILER").map((m) => ({
|
||||||
|
compilerName: m.personnelName,
|
||||||
|
compilerCapacity: m.capacity || "",
|
||||||
|
}));
|
||||||
|
const memberList = teamMembers
|
||||||
|
.filter((m) => !m.roles.some((r) => r.role === "PROJECT_LEAD"))
|
||||||
|
.map((m) => ({ name: m.personnelName, major: m.capacity || "" }));
|
||||||
const data = {
|
const data = {
|
||||||
projectName: evalProjectDetailData?.projectName || "",
|
projectName: evalProjectDetailData?.projectName || "",
|
||||||
evalTypeText: EVAL_TYPE_MAP[evalProjectDetailData?.evalTypeCode] || "",
|
evalTypeText: EVAL_TYPE_MAP[evalProjectDetailData?.evalTypeCode] || "",
|
||||||
projectLeader: namesByRole("PROJECT_LEAD"),
|
projectLeader: sentenceByRole("PROJECT_LEAD"),
|
||||||
membersText: teamMembers
|
compiler: sentenceByRole("REPORT_COMPILER"),
|
||||||
.filter((m) => !m.roles.some((r) => r.role === "PROJECT_LEAD"))
|
projectLeaderName: namesByRole("PROJECT_LEAD"),
|
||||||
.map(personText)
|
projectLeaderCapacity: capsByRole("PROJECT_LEAD"),
|
||||||
.join("、"),
|
// 标签合并分组:首行固定放第一人,循环行(continue)逐人一行
|
||||||
compiler: namesByRole("REPORT_COMPILER"),
|
firstAuditorName: auditorList[0]?.auditorName || "",
|
||||||
auditor: namesByRole("INTERNAL_AUDITOR"),
|
firstAuditorCapacity: auditorList[0]?.auditorCapacity || "",
|
||||||
techLead: namesByRole("TECHNICAL_LEAD"),
|
auditorRows: auditorList.slice(1),
|
||||||
processControlLead: namesByRole("PROCESS_CONTROL_LEAD"),
|
firstTechLeadName: techLeadList[0]?.techLeadName || "",
|
||||||
|
firstTechLeadCapacity: techLeadList[0]?.techLeadCapacity || "",
|
||||||
|
techLeadRows: techLeadList.slice(1),
|
||||||
|
processControlLeadName: namesByRole("PROCESS_CONTROL_LEAD"),
|
||||||
|
processControlLeadCapacity: capsByRole("PROCESS_CONTROL_LEAD"),
|
||||||
|
// 模板中标签列已纵向合并:restart 行放第一名成员,循环行(continue)逐人一行
|
||||||
|
firstMemberName: memberList[0]?.name || "",
|
||||||
|
firstMemberMajor: memberList[0]?.major || "",
|
||||||
|
memberRows: memberList.slice(1),
|
||||||
|
firstCompilerName: compilerList[0]?.compilerName || "",
|
||||||
|
firstCompilerCapacity: compilerList[0]?.compilerCapacity || "",
|
||||||
|
compilerRows: compilerList.slice(1),
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await fillDocxTemplate(
|
await fillDocxTemplate(
|
||||||
|
|
@ -613,7 +644,9 @@ const TeamContent = ({ readOnly, ...props }) => {
|
||||||
{ (
|
{ (
|
||||||
<LayoutFooterPortal slotId="pf-footer-slot">
|
<LayoutFooterPortal slotId="pf-footer-slot">
|
||||||
<Flex justify="flex-end" gap={8}>
|
<Flex justify="flex-end" gap={8}>
|
||||||
<Button onClick={handleExport}>导出《人员任命书》</Button>
|
<Button onClick={handleExport}>
|
||||||
|
导出《人员任命书》
|
||||||
|
</Button>
|
||||||
{!readOnly &&<Button
|
{!readOnly &&<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
loading={memberSaveLoading || memberParticipantSaveLoading}
|
loading={memberSaveLoading || memberParticipantSaveLoading}
|
||||||
|
|
|
||||||
|
|
@ -1,82 +1,86 @@
|
||||||
import { Button, Descriptions, Form, Modal, Tag, Tooltip, Table } from "antd";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
import { Button, Form, Space, Table, Tag } from "antd";
|
||||||
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
||||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
import SearchForm from "~/components/SearchForm";
|
import SearchForm from "~/components/SearchForm";
|
||||||
|
import StaffResumeModal from "~/components/StaffResumeModal";
|
||||||
|
import { NS_ORG_INFO, NS_STAFF_INFO } from "~/enumerate/namespace";
|
||||||
|
import {
|
||||||
|
REGISTER_ENGINEER_OPTIONS,
|
||||||
|
TITLE_LEVEL_MAP,
|
||||||
|
} from "~/enumerate/enterpriseOptions";
|
||||||
|
import { CERT_LEVEL_LABEL_BY_TYPE } from "~/enumerate/constant";
|
||||||
|
|
||||||
import { getEvaluatorDetail, queryEvaluatorPage } from "~/mock/regulator/basicInfo";
|
const EMPLOYMENT_STATUS_OPTIONS = [
|
||||||
|
{ label: "在职", value: 1 },
|
||||||
const YES_NO_OPTIONS = [
|
{ label: "离职", value: 2 },
|
||||||
{ label: "是", value: 1 },
|
|
||||||
{ label: "否", value: 0 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const STATUS_OPTIONS = [
|
const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" };
|
||||||
{ label: "正常", value: "normal" },
|
const PERSONNEL_STATUS_MAP = { 1: "正常", 2: "异常" };
|
||||||
{ label: "异常", value: "abnormal" },
|
const evalCertLevelMap = CERT_LEVEL_LABEL_BY_TYPE.evaluator;
|
||||||
];
|
|
||||||
|
|
||||||
const CERT_STATUS_COLOR = {
|
|
||||||
normal: "success",
|
|
||||||
expiring: "warning",
|
|
||||||
expired: "error",
|
|
||||||
};
|
|
||||||
|
|
||||||
function EvaluatorInfoPage(props) {
|
function EvaluatorInfoPage(props) {
|
||||||
const [searchForm] = Form.useForm();
|
const [searchForm] = Form.useForm();
|
||||||
const [viewOpen, setViewOpen] = useState(false);
|
const [resumeOpen, setResumeOpen] = useState(false);
|
||||||
const [detail, setDetail] = useState(null);
|
const [currentId, setCurrentId] = useState("");
|
||||||
const [detailLoading, setDetailLoading] = useState(false);
|
const [orgOptions, setOrgOptions] = useState([]);
|
||||||
const [certPreview, setCertPreview] = useState(null);
|
|
||||||
const [dataSource, setDataSource] = useState([]);
|
const [dataSource, setDataSource] = useState([]);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [pageIndex, setPageIndex] = useState(1);
|
const [pageIndex, setPageIndex] = useState(1);
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(10);
|
||||||
|
|
||||||
|
const loading = props.staffInfo?.staffInfoLoading;
|
||||||
|
|
||||||
const fetchData = async (page = 1, size = 10) => {
|
const fetchData = async (page = 1, size = 10) => {
|
||||||
setLoading(true);
|
const formData = searchForm.getFieldsValue();
|
||||||
try {
|
const res = await props.staffInfoRegulationPage({
|
||||||
const formData = searchForm.getFieldsValue();
|
...formData,
|
||||||
const res = await queryEvaluatorPage({ ...formData, pageIndex: page, pageSize: size });
|
current: page,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
if (res?.success !== false) {
|
||||||
setDataSource(res?.data || []);
|
setDataSource(res?.data || []);
|
||||||
setTotal(res?.totalCount || 0);
|
setTotal(res?.total || 0);
|
||||||
|
setPageIndex(page);
|
||||||
|
setPageSize(size);
|
||||||
}
|
}
|
||||||
catch {
|
};
|
||||||
setDataSource([]);
|
|
||||||
setTotal(0);
|
const loadOrgOptions = async () => {
|
||||||
}
|
try {
|
||||||
finally {
|
const res = await props.registeredOrgList({ current: 1, size: 200 });
|
||||||
setLoading(false);
|
const list = res?.data || [];
|
||||||
|
setOrgOptions(
|
||||||
|
list.map((item) => ({
|
||||||
|
label:
|
||||||
|
item.unitName ||
|
||||||
|
item.orgName ||
|
||||||
|
item.name ||
|
||||||
|
item.enterpriseName ||
|
||||||
|
String(item.id),
|
||||||
|
value: String(item.id),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
setOrgOptions([]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
|
loadOrgOptions();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const openDetail = async (id) => {
|
|
||||||
setViewOpen(true);
|
|
||||||
setDetailLoading(true);
|
|
||||||
const res = await getEvaluatorDetail(id);
|
|
||||||
setDetail(res?.data || null);
|
|
||||||
setDetailLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeDetail = () => {
|
|
||||||
setViewOpen(false);
|
|
||||||
setDetail(null);
|
|
||||||
setCertPreview(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
title={
|
title={
|
||||||
<div>
|
<div>
|
||||||
<span>评价师信息管理</span>
|
<span>评价师信息管理</span>
|
||||||
<div className="pageLayout-extra">
|
<div className="pageLayout-extra">
|
||||||
监管端查看辖区内评价师备案及资质状态(当前为 Mock 数据)。
|
监管端查看辖区内评价师备案及资质状态。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -85,28 +89,44 @@ function EvaluatorInfoPage(props) {
|
||||||
form={searchForm}
|
form={searchForm}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
formLine={[
|
formLine={[
|
||||||
<Form.Item key="evaluatorName" name="evaluatorName">
|
<Form.Item key="userName" name="userName">
|
||||||
<ControlWrapper.Input label="评价师名称" allowClear placeholder="关键字搜索" />
|
<ControlWrapper.Input label="评价师名称" allowClear placeholder="关键字搜索" />
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
<Form.Item key="orgName" name="orgName">
|
<Form.Item key="orgId" name="orgId">
|
||||||
<ControlWrapper.Input label="机构名称" allowClear placeholder="关键字搜索" />
|
<ControlWrapper.Select
|
||||||
|
label="机构名称"
|
||||||
|
allowClear
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
placeholder="请选择"
|
||||||
|
options={orgOptions}
|
||||||
|
/>
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
<Form.Item key="employmentStatus" name="employmentStatus">
|
<Form.Item key="employmentStatusCode" name="employmentStatusCode">
|
||||||
<ControlWrapper.Select label="是否在职" allowClear placeholder="请选择" options={YES_NO_OPTIONS} />
|
<ControlWrapper.Select
|
||||||
|
label="是否在职"
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择"
|
||||||
|
options={EMPLOYMENT_STATUS_OPTIONS}
|
||||||
|
/>
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
<Form.Item key="registerEngineerFlag" name="registerEngineerFlag">
|
<Form.Item key="registerEngineerFlag" name="registerEngineerFlag">
|
||||||
<ControlWrapper.Select label="是否注册安全工程师" allowClear placeholder="请选择" options={YES_NO_OPTIONS} />
|
<ControlWrapper.Select
|
||||||
</Form.Item>,
|
label="是否注册安全工程师"
|
||||||
<Form.Item key="status" name="status">
|
allowClear
|
||||||
<ControlWrapper.Select label="状态" allowClear placeholder="请选择" options={STATUS_OPTIONS} />
|
placeholder="请选择"
|
||||||
|
options={REGISTER_ENGINEER_OPTIONS}
|
||||||
|
/>
|
||||||
</Form.Item>,
|
</Form.Item>,
|
||||||
]}
|
]}
|
||||||
onFinish={() => fetchData(1, 10)}
|
onFinish={() => fetchData(1, pageSize)}
|
||||||
|
onReset={() => fetchData(1, pageSize)}
|
||||||
style={{
|
style={{
|
||||||
marginBottom: '16px'
|
marginBottom: "16px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Table
|
<Table
|
||||||
|
rowKey="id"
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
pagination={{
|
pagination={{
|
||||||
|
|
@ -117,129 +137,86 @@ function EvaluatorInfoPage(props) {
|
||||||
showTotal: (t) => `共 ${t} 条`,
|
showTotal: (t) => `共 ${t} 条`,
|
||||||
}}
|
}}
|
||||||
onChange={(pag) => {
|
onChange={(pag) => {
|
||||||
setPageIndex(pag.current);
|
|
||||||
setPageSize(pag.pageSize);
|
|
||||||
fetchData(pag.current, pag.pageSize);
|
fetchData(pag.current, pag.pageSize);
|
||||||
}}
|
}}
|
||||||
scroll={{ y: props.scrollY }}
|
scroll={{ y: props.scrollY }}
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "机构名称", dataIndex: "orgName", ellipsis: true },
|
{ title: "机构名称", dataIndex: "orgName", ellipsis: true },
|
||||||
{ title: "评价师名称", dataIndex: "evaluatorName", width: 120 },
|
{ title: "评价师名称", dataIndex: "userName", width: 120 },
|
||||||
{
|
{
|
||||||
title: "是否注册安全工程师",
|
title: "是否注册安全工程师",
|
||||||
dataIndex: "registerEngineerLabel",
|
dataIndex: "registerEngineerFlag",
|
||||||
width: 160,
|
width: 160,
|
||||||
|
render: (val) => REGISTER_ENGINEER_MAP[val] || "-",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "证照名称",
|
||||||
|
dataIndex: "personnelCertFilingPageCOList",
|
||||||
|
width: 280,
|
||||||
|
render: (_, record) => {
|
||||||
|
const arr = [];
|
||||||
|
if (record.registeredSafetyEngineerCert) {
|
||||||
|
arr.push(
|
||||||
|
<Tag color="blue" key="reg">
|
||||||
|
{TITLE_LEVEL_MAP[record.registeredSafetyEngineerCert.certLevel]}
|
||||||
|
注册安全工程师
|
||||||
|
</Tag>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (record.evaluatorCert) {
|
||||||
|
arr.push(
|
||||||
|
<Tag color="green" key="eval">
|
||||||
|
{evalCertLevelMap[record.evaluatorCert.certLevel]}
|
||||||
|
注册安全评价师
|
||||||
|
</Tag>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return arr.length ? <Space size={4}>{arr}</Space> : "-";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{ title: "资格证书", dataIndex: "certificatesSummary", ellipsis: true },
|
|
||||||
{
|
{
|
||||||
title: "状态",
|
title: "状态",
|
||||||
|
dataIndex: "personnelStatus",
|
||||||
width: 90,
|
width: 90,
|
||||||
render: (_, record) => {
|
render: (val) => (
|
||||||
const tag = (
|
<Tag color={val === 2 ? "error" : "success"}>
|
||||||
<Tag color={record.status === "normal" ? "success" : "error"}>
|
{PERSONNEL_STATUS_MAP[val] || "正常"}
|
||||||
{record.statusLabel}
|
</Tag>
|
||||||
</Tag>
|
),
|
||||||
);
|
|
||||||
return record.statusTip ? <Tooltip title={record.statusTip}>{tag}</Tooltip> : tag;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "操作",
|
title: "操作",
|
||||||
width: 80,
|
width: 80,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Button type="link" onClick={() => openDetail(record.id)}>查看</Button>
|
<Button
|
||||||
|
type="link"
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentId(record.id);
|
||||||
|
setResumeOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</Button>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
{resumeOpen && (
|
||||||
open={viewOpen}
|
<StaffResumeModal
|
||||||
destroyOnHidden
|
open={resumeOpen}
|
||||||
title="评价师详细信息"
|
currentId={currentId}
|
||||||
width={900}
|
onCancel={() => {
|
||||||
loading={detailLoading}
|
setResumeOpen(false);
|
||||||
cancelText="关闭"
|
setCurrentId("");
|
||||||
okButtonProps={{ style: { display: "none" } }}
|
}}
|
||||||
onCancel={closeDetail}
|
/>
|
||||||
>
|
)}
|
||||||
{detail && (
|
|
||||||
<>
|
|
||||||
<Descriptions title="个人信息" bordered column={2} size="small" style={{ marginBottom: 16 }}>
|
|
||||||
<Descriptions.Item label="姓名">{detail.name}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="性别">{detail.gender}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="出生日期">{detail.birthDate}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="身份证号">{detail.idCard}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="学历">{detail.education}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="毕业院校">{detail.graduateSchool}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="专业">{detail.major}</Descriptions.Item>
|
|
||||||
</Descriptions>
|
|
||||||
<Descriptions title="机构信息" bordered column={2} size="small" style={{ marginBottom: 16 }}>
|
|
||||||
<Descriptions.Item label="所在机构">{detail.orgName}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="部门">{detail.deptName}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="岗位">{detail.positionName}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="账号">{detail.account}</Descriptions.Item>
|
|
||||||
</Descriptions>
|
|
||||||
<div style={{ marginBottom: 8, fontWeight: 600 }}>资质证照</div>
|
|
||||||
<Table
|
|
||||||
size="small"
|
|
||||||
bordered
|
|
||||||
rowKey="id"
|
|
||||||
pagination={false}
|
|
||||||
dataSource={detail.certificates || []}
|
|
||||||
columns={[
|
|
||||||
{ title: "证书名称", dataIndex: "certName" },
|
|
||||||
{ title: "证书编号", dataIndex: "certNo" },
|
|
||||||
{ title: "发证日期", dataIndex: "issueDate", width: 110 },
|
|
||||||
{ title: "有效期至", dataIndex: "expireDate", width: 110 },
|
|
||||||
{
|
|
||||||
title: "状态",
|
|
||||||
width: 90,
|
|
||||||
render: (_, record) => {
|
|
||||||
const tag = (
|
|
||||||
<Tag color={CERT_STATUS_COLOR[record.status] || "default"}>
|
|
||||||
{record.statusLabel}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
return record.statusTip ? <Tooltip title={record.statusTip}>{tag}</Tooltip> : tag;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "操作",
|
|
||||||
width: 90,
|
|
||||||
render: (_, record) => (
|
|
||||||
<Button type="link" size="small" onClick={() => setCertPreview(record)}>
|
|
||||||
查看证书
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal
|
|
||||||
open={!!certPreview}
|
|
||||||
destroyOnHidden
|
|
||||||
title="证书预览"
|
|
||||||
width={520}
|
|
||||||
cancelText="关闭"
|
|
||||||
okButtonProps={{ style: { display: "none" } }}
|
|
||||||
onCancel={() => setCertPreview(null)}
|
|
||||||
>
|
|
||||||
{certPreview && (
|
|
||||||
<Descriptions bordered column={1} size="small">
|
|
||||||
<Descriptions.Item label="证书名称">{certPreview.certName}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="证书编号">{certPreview.certNo}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="发证日期">{certPreview.issueDate}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="有效期至">{certPreview.expireDate}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label="状态">{certPreview.statusLabel}</Descriptions.Item>
|
|
||||||
</Descriptions>
|
|
||||||
)}
|
|
||||||
</Modal>
|
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AntdTableFuncControl(EvaluatorInfoPage);
|
export default Connect(
|
||||||
|
[NS_STAFF_INFO, NS_ORG_INFO],
|
||||||
|
true,
|
||||||
|
)(AntdTableFuncControl(EvaluatorInfoPage));
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,23 @@ import { CAPABILITY_MAP } from "~/enumerate/constant";
|
||||||
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP } from "~/enumerate/enterpriseOptions";
|
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP } from "~/enumerate/enterpriseOptions";
|
||||||
|
|
||||||
/** 渲染专业能力列表,供表格 column render 使用 */
|
/** 渲染专业能力列表,供表格 column render 使用 */
|
||||||
export function renderCapabilityList(list) {
|
export function renderCapabilityList(list, option) {
|
||||||
if (!Array.isArray(list) || !list.length) return "-";
|
if (!Array.isArray(list) || !list.length) return "-";
|
||||||
return (
|
return (
|
||||||
list
|
list
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
const cap = CAPABILITY_MAP[item.professionalCapabilityCode];
|
const cap = CAPABILITY_MAP[item.professionalCapabilityCode];
|
||||||
if (!cap) return null;
|
if (!cap) return null;
|
||||||
|
if(option.capFlag){
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
const industry = item.industryCode
|
const industry = item.industryCode
|
||||||
? QUALIFICATION_INDUSTRY_OPTIONS_MAP[item.industryCode]
|
? QUALIFICATION_INDUSTRY_OPTIONS_MAP[item.industryCode]
|
||||||
: null;
|
: null;
|
||||||
return industry ? `${industry}【${cap}】` : cap;
|
return industry ? `${industry}【${cap}】` : cap;
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("、") || "-"
|
.join(";") || "-"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue