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;
|
||||
}, {});
|
||||
|
||||
/** 业务范围与所需专业能力配备标准对照(依据《安全评价机构资质条件》应急〔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 = [
|
||||
{ label: "安全工程", value: "SAFETY_ENGINEERING" },
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|||
import useIndustryOptions from "~/hooks/useIndustryOptions";
|
||||
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
||||
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 { renderCapabilityList } from "~/utils";
|
||||
import StaffPickerModal from "./StaffPickerModal";
|
||||
|
|
@ -29,6 +29,7 @@ import StaffPickerModal from "./StaffPickerModal";
|
|||
import {
|
||||
EVAL_TYPE_OPTIONS,
|
||||
CHECKIN_RADIUS_OPTIONS,
|
||||
INDUSTRY_REQUIRED_CAPABILITIES,
|
||||
} from "~/enumerate/constant";
|
||||
|
||||
const { router } = tools;
|
||||
|
|
@ -102,9 +103,26 @@ const EvalProjectCreate = (props) => {
|
|||
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 = () => {
|
||||
form.validateFields().then(async (values) => {
|
||||
const { planStartDate, planEndDate, ...rest } = values;
|
||||
const industryCodes = String(values.industryCode || "").split(",");
|
||||
const params = {
|
||||
...rest,
|
||||
planStartDate: planStartDate?.format("YYYY-MM-DD"),
|
||||
|
|
@ -114,9 +132,7 @@ const EvalProjectCreate = (props) => {
|
|||
name: item.userName,
|
||||
deptName: item.deptName,
|
||||
posName: item.postName,
|
||||
capacity: item.capabilityAssessment
|
||||
? renderCapabilityList(item.capabilityAssessment)
|
||||
: item.capacity,
|
||||
capacity: filterCapacityByIndustry(item, industryCodes),
|
||||
})),
|
||||
};
|
||||
if (projectId) {
|
||||
|
|
@ -357,18 +373,18 @@ const EvalProjectCreate = (props) => {
|
|||
}
|
||||
>
|
||||
<Select
|
||||
mode="multiple"
|
||||
|
||||
placeholder="请选择"
|
||||
allowClear
|
||||
options={isStatutory?industryOptions:REGISTER_ENGINEER_CATEGORY_OPTIONS}
|
||||
options={isStatutory?industryOptions:QUALIFICATION_INDUSTRY_OPTIONS}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
{/* <Col span={12}>
|
||||
<Form.Item name="controlledNumber" label="受控编号" rules={[{ required: true, message: "请选择受控编号" }]}>
|
||||
<Input placeholder="请输入" maxLength={20} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Col> */}
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ const RiskAnalysisContent = ({ readOnly, ...props }) => {
|
|||
Array.isArray(value) ? value.join(",") : value
|
||||
}
|
||||
>
|
||||
<Select mode="multiple" placeholder="请选择所属行业" allowClear>
|
||||
<Select placeholder="请选择所属行业" allowClear>
|
||||
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
||||
<Select.Option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@ import { fillDocxTemplate } from "~/utils/fillDocxTemplate";
|
|||
|
||||
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 {
|
||||
|
|
@ -268,28 +270,57 @@ const TeamContent = ({ readOnly, ...props }) => {
|
|||
setSigners((prev) => prev.filter((s) => s.personnelId !== personnelId));
|
||||
};
|
||||
|
||||
// 导出Word:按当前项目组配置填充模板(聘请所需技术专家、备注事项、部门经理或负责人、年月日保留空白)
|
||||
// 导出Word:按当前项目组配置填充模板(任命语句用"姓名(能力)",表格姓名/专业分列展示;聘用专家、评价部经理、年月日留白)
|
||||
const handleExport = async () => {
|
||||
/** 人员展示文本:姓名后追加能力,如"张三(化工)" */
|
||||
const personText = (m) =>
|
||||
`${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) =>
|
||||
teamMembers
|
||||
.filter((m) => m.roles.some((r) => r.role === role))
|
||||
.map(personText)
|
||||
.join("、");
|
||||
roleMembers(role).map((m) => m.personnelName).join("、");
|
||||
const capsByRole = (role) =>
|
||||
roleMembers(role).map((m) => m.capacity).filter(Boolean).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 = {
|
||||
projectName: evalProjectDetailData?.projectName || "",
|
||||
evalTypeText: EVAL_TYPE_MAP[evalProjectDetailData?.evalTypeCode] || "",
|
||||
projectLeader: namesByRole("PROJECT_LEAD"),
|
||||
membersText: teamMembers
|
||||
.filter((m) => !m.roles.some((r) => r.role === "PROJECT_LEAD"))
|
||||
.map(personText)
|
||||
.join("、"),
|
||||
compiler: namesByRole("REPORT_COMPILER"),
|
||||
auditor: namesByRole("INTERNAL_AUDITOR"),
|
||||
techLead: namesByRole("TECHNICAL_LEAD"),
|
||||
processControlLead: namesByRole("PROCESS_CONTROL_LEAD"),
|
||||
projectLeader: sentenceByRole("PROJECT_LEAD"),
|
||||
compiler: sentenceByRole("REPORT_COMPILER"),
|
||||
projectLeaderName: namesByRole("PROJECT_LEAD"),
|
||||
projectLeaderCapacity: capsByRole("PROJECT_LEAD"),
|
||||
// 标签合并分组:首行固定放第一人,循环行(continue)逐人一行
|
||||
firstAuditorName: auditorList[0]?.auditorName || "",
|
||||
firstAuditorCapacity: auditorList[0]?.auditorCapacity || "",
|
||||
auditorRows: auditorList.slice(1),
|
||||
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 {
|
||||
await fillDocxTemplate(
|
||||
|
|
@ -613,7 +644,9 @@ const TeamContent = ({ readOnly, ...props }) => {
|
|||
{ (
|
||||
<LayoutFooterPortal slotId="pf-footer-slot">
|
||||
<Flex justify="flex-end" gap={8}>
|
||||
<Button onClick={handleExport}>导出《人员任命书》</Button>
|
||||
<Button onClick={handleExport}>
|
||||
导出《人员任命书》
|
||||
</Button>
|
||||
{!readOnly &&<Button
|
||||
type="primary"
|
||||
loading={memberSaveLoading || memberParticipantSaveLoading}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,23 @@ import { CAPABILITY_MAP } from "~/enumerate/constant";
|
|||
import { QUALIFICATION_INDUSTRY_OPTIONS_MAP } from "~/enumerate/enterpriseOptions";
|
||||
|
||||
/** 渲染专业能力列表,供表格 column render 使用 */
|
||||
export function renderCapabilityList(list) {
|
||||
export function renderCapabilityList(list, option) {
|
||||
if (!Array.isArray(list) || !list.length) return "-";
|
||||
return (
|
||||
list
|
||||
.map((item) => {
|
||||
const cap = CAPABILITY_MAP[item.professionalCapabilityCode];
|
||||
if (!cap) return null;
|
||||
if(option.capFlag){
|
||||
return cap;
|
||||
}
|
||||
const industry = item.industryCode
|
||||
? QUALIFICATION_INDUSTRY_OPTIONS_MAP[item.industryCode]
|
||||
: null;
|
||||
return industry ? `${industry}【${cap}】` : cap;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join("、") || "-"
|
||||
.join(";") || "-"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue