fix
parent
6f19e24df4
commit
a3e796831d
|
|
@ -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}
|
||||||
|
聘用专家组成员
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
评价部经理:
|
||||||
|
年 月 日
|
||||||
|
|
||||||
|
|
@ -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,26 @@ const EvalProjectCreate = (props) => {
|
||||||
setMapPickerVisible(false);
|
setMapPickerVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 按所选业务范围(配备标准)筛选人员能力,仅提交范围内所需的专业能力条目 */
|
||||||
|
const filterCapacityByIndustry = (item, industryCodes) => {
|
||||||
|
const requiredCaps = industryCodes.flatMap(
|
||||||
|
(code) => INDUSTRY_REQUIRED_CAPABILITIES[code] || [],
|
||||||
|
);
|
||||||
|
if (!requiredCaps.length || !Array.isArray(item.capabilityAssessment)) {
|
||||||
|
return item.capabilityAssessment?.length
|
||||||
|
? renderCapabilityList(item.capabilityAssessment, {capFlag: true})
|
||||||
|
: item.capacity;
|
||||||
|
}
|
||||||
|
const matched = item.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 +132,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 +373,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}
|
||||||
|
|
|
||||||
|
|
@ -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