dev-1.3
tangjie 2026-08-08 16:44:49 +08:00
parent 043dc53da7
commit ca9919149e
6 changed files with 244 additions and 91 deletions

View File

@ -10,6 +10,7 @@ import {
import {
CERT_LEVEL_LABEL_BY_TYPE,
CAPABILITY_MAP,
PROFESSIONAL_MAJOR_MAP,
} from "~/enumerate/constant";
const GENDER_MAP = { 1: "男", 2: "女" };
@ -71,6 +72,8 @@ export default function StaffViewModal({
const titleInfo = Array.isArray(info.titleCodeArr)
? info.titleCodeArr.map((item) => ({
titleName: TITLE_LEVEL_MAP[item.titleCode] || item.titleCode || "-",
industryName:
PROFESSIONAL_MAJOR_MAP[item.industryCode] || item.industryCode || "-",
proveUrlList: parseFileList(item.proveUrl),
}))
: [];
@ -228,6 +231,7 @@ export default function StaffViewModal({
dataSource={titleInfo}
columns={[
{ title: "职称", dataIndex: "titleName", width: 120 },
{ title: "专业", dataIndex: "industryName", width: 150 },
{
title: "证明材料",
dataIndex: "proveUrlList",

View File

@ -515,4 +515,29 @@ export const CAPABILITY_MAP = CAPABILITY_OPTIONS.reduce((acc, cur) => {
return acc;
}, {});
/** 专业(职称信息) */
export const PROFESSIONAL_MAJOR_OPTIONS = [
{ label: "安全工程", value: "SAFETY_ENGINEERING" },
{ label: "机械工程", value: "MECHANICAL_ENGINEERING" },
{ label: "化工机械", value: "CHEMICAL_MACHINERY" },
{ label: "化学工程", value: "CHEMICAL_ENGINEERING" },
{ label: "自动化/测控技术", value: "AUTOMATION" },
{ label: "电气工程", value: "ELECTRICAL_ENGINEERING" },
{ label: "采矿工程", value: "MINING_ENGINEERING" },
{ label: "通风工程", value: "VENTILATION_ENGINEERING" },
{ label: "地质工程", value: "GEOLOGICAL_ENGINEERING" },
{ label: "矿建工程", value: "MINE_CONSTRUCTION_ENGINEERING" },
{ label: "石油工程", value: "PETROLEUM_ENGINEERING" },
{ label: "油气储运工程", value: "OIL_GAS_STORAGE_TRANSPORT" },
{ label: "腐蚀与防护", value: "CORROSION_PROTECTION" },
{ label: "冶金工程", value: "METALLURGY_ENGINEERING" },
{ label: "有色金属冶金", value: "NONFERROUS_METALLURGY" },
{ label: "火炸药/爆炸技术", value: "EXPLOSIVES" },
{ label: "土木工程", value: "CIVIL_ENGINEERING" },
];
export const PROFESSIONAL_MAJOR_MAP = PROFESSIONAL_MAJOR_OPTIONS.reduce(
(acc, cur) => ({ ...acc, [cur.value]: cur.label }),
{},
);

View File

@ -14,7 +14,7 @@ import {
Table,
TreeSelect,
Upload,
Divider,
Tag,
} from "antd";
import { InboxOutlined } from "@ant-design/icons";
import { Get } from "@cqsjjb/jjb-common-lib/http";
@ -36,8 +36,15 @@ import {
ABILITY_SOURCE_OPTIONS,
EVALUATOR_OPTIONS,
TITLE_LEVEL_OPTIONS,
TITLE_LEVEL_MAP
} from "~/enumerate/enterpriseOptions";
import { CERT_LEVEL_OPTIONS_BY_TYPE, CAPABILITY_OPTIONS } from "~/enumerate/constant";
import {
CERT_LEVEL_OPTIONS_BY_TYPE,
CAPABILITY_OPTIONS,
PROFESSIONAL_MAJOR_OPTIONS,
CAPABILITY_MAP,
CERT_LEVEL_LABEL_BY_TYPE
} from "~/enumerate/constant";
import { getBirthDateFromIdCard } from "~/utils";
import { idCardRule, mobileRule } from "~/utils/validators";
import AttachmentUpload from "~/components/AttachmentUpload";
@ -46,6 +53,7 @@ import "./index.less";
const { router } = tools;
const API_HOST = window.process?.env?.app?.API_HOST || "";
const evalCertLevelMap = CERT_LEVEL_LABEL_BY_TYPE.evaluator;
function PersonnelInfoPage(props) {
const [formModalOpen, setFormModalOpen] = useState(false);
@ -209,26 +217,40 @@ function PersonnelInfoPage(props) {
<Table
rowKey="id"
columns={[
{ title: "用户名称", dataIndex: "userName", ellipsis: true },
{ title: "姓名", dataIndex: "userName", ellipsis: true, width: 150 },
{ title: "账号", dataIndex: "account" },
{ title: "部门", dataIndex: "deptName" },
{ title: "岗位", dataIndex: "postName" },
{
title: "证照名称",
dataIndex: "certNames",
ellipsis: true,
render: (text) => text || "-",
},
{
title: "能力",
width: 260,
dataIndex: "abilityNames",
ellipsis: true,
render: (text) => text || "暂无",
title: "专业能力",
dataIndex: "capabilityAssessment",
render: (list) => {
if (!Array.isArray(list) || !list.length) return "-";
return list
.map((item) => CAPABILITY_MAP[item.professionalCapabilityCode])
.join("、");
},
},
{
title: "证照名称",
dataIndex: "personnelCertFilingPageCOList",
width: 280,
render: (_, record) => {
const arr = [];
if(record.registeredSafetyEngineerCert){
arr.push(<Tag color="blue">{TITLE_LEVEL_MAP[record.registeredSafetyEngineerCert.certLevel]}注册安全工程师</Tag>);
}
if(record.evaluatorCert){
arr.push(<Tag color="green">{evalCertLevelMap[record.evaluatorCert.certLevel]}注册安全评价师</Tag>);
}
return <Space size={4}>{arr}</Space>;
},
},
{
title: "操作",
width: 200,
fixed: "right",
render: (_, record) => (
<TableAction>
<Button
@ -251,7 +273,7 @@ function PersonnelInfoPage(props) {
>
编辑
</Button>
<Button
type="link"
size="small"
@ -272,7 +294,7 @@ function PersonnelInfoPage(props) {
},
]}
dataSource={dataSource}
scroll={{ y: props.scrollY }}
scroll={{ y: props.scrollY, x: 1300 }}
loading={loading}
pagination={{
total,
@ -456,9 +478,13 @@ function StaffFormModal({
parseCertAttachment(setFields.evaluatorCert);
}
if (Array.isArray(setFields.titleCodeArr) && setFields.titleCodeArr[0]) {
if (
Array.isArray(setFields.titleCodeArr) &&
setFields.titleCodeArr[0]
) {
const first = setFields.titleCodeArr[0];
setFields.titleCode = first.titleCode;
setFields.industryCode = first.industryCode;
if (first.proveUrl) {
try {
setFields.proveUrl = JSON.parse(first.proveUrl);
@ -527,6 +553,7 @@ function StaffFormModal({
: undefined,
titleCodeArr: [
{
industryCode: values.industryCode,
titleCode: values.titleCode,
proveUrl: Array.isArray(values.proveUrl)
? JSON.stringify(values.proveUrl)
@ -812,9 +839,14 @@ function StaffFormModal({
<>
<Col span={12}>
<Form.Item
name={["registeredSafetyEngineerCert", "certCategoryCode"]}
name={[
"registeredSafetyEngineerCert",
"certCategoryCode",
]}
label="注安专业类别"
rules={[{ required: true, message: "请选择注安专业类别" }]}
rules={[
{ required: true, message: "请选择注安专业类别" },
]}
>
<Select
placeholder="请选择注安专业类别"
@ -850,7 +882,10 @@ function StaffFormModal({
</Col>
<Col span={24}>
<AttachmentUpload
name={["registeredSafetyEngineerCert", "certAttachmentUrl"]}
name={[
"registeredSafetyEngineerCert",
"certAttachmentUrl",
]}
label="注安证书"
extra="最多上传10个pdf,doc,docx,图片格式文件"
accept=".pdf,.doc,.docx,.png,.jpg,.jpeg,.bmp,.webp"
@ -867,9 +902,7 @@ function StaffFormModal({
<Row gutter={16}>
<Col span={24}>
<div className="register-engineer-section">
<div className="register-engineer-section-title">
评价师信息
</div>
<div className="register-engineer-section-title">评价师信息</div>
<Row gutter={16}>
<Col span={12}>
<Form.Item
@ -877,10 +910,7 @@ function StaffFormModal({
label="是否评价师"
initialValue={2}
>
<Select
placeholder="请选择"
options={EVALUATOR_OPTIONS}
/>
<Select placeholder="请选择" options={EVALUATOR_OPTIONS} />
</Form.Item>
</Col>
{watchedEvaluatorFlag === 1 && (
@ -889,7 +919,9 @@ function StaffFormModal({
<Form.Item
name={["evaluatorCert", "certLevel"]}
label="评价师等级"
rules={[{ required: true, message: "请选择评价师等级" }]}
rules={[
{ required: true, message: "请选择评价师等级" },
]}
>
<Select
placeholder="请选择评价师等级"
@ -917,7 +949,9 @@ function StaffFormModal({
extra="最多上传10个pdf,doc,docx,图片格式文件"
accept=".pdf,.doc,.docx,.png,.jpg,.jpeg,.bmp,.webp"
maxCount={10}
rules={[{ required: true, message: "请上传评价师证书" }]}
rules={[
{ required: true, message: "请上传评价师证书" },
]}
/>
</Col>
</>
@ -926,13 +960,11 @@ function StaffFormModal({
</div>
</Col>
</Row>
<Row gutter={16}>
<Col span={24}>
<div className="register-engineer-section">
<div className="register-engineer-section-title">
职称信息
</div>
<div className="register-engineer-section-title">职称信息</div>
<Row gutter={16}>
<Col span={12}>
<Form.Item
@ -947,6 +979,19 @@ function StaffFormModal({
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="industryCode"
label="专业"
rules={[{ required: true, message: "请选择专业" }]}
>
<Select
placeholder="请选择专业"
allowClear
options={PROFESSIONAL_MAJOR_OPTIONS}
/>
</Form.Item>
</Col>
<Col span={12}>
<AttachmentUpload
name="proveUrl"
@ -962,10 +1007,7 @@ function StaffFormModal({
</Col>
<Col span={24}>
<Form.Item label="专业能力信息">
<Form.List
name="capabilityAssessment"
initialValue={[{}]}
>
<Form.List name="capabilityAssessment" initialValue={[{}]}>
{(fields, { add, remove }) => (
<>
<Table
@ -995,7 +1037,10 @@ function StaffFormModal({
width: 280,
render: (_, field) => (
<Form.Item
name={[field.name, "professionalCapabilitySourceCode"]}
name={[
field.name,
"professionalCapabilitySourceCode",
]}
style={{ marginBottom: 0 }}
>
<Select

View File

@ -1,4 +1,4 @@
import { Form, Input, InputNumber, Row, Col, Select } from "antd";
import { Form, Input, InputNumber, Row, Col, Select, Checkbox } from "antd";
import {
CHONGQING_DISTRICTS,
QUALIFICATION_INDUSTRY_OPTIONS,
@ -13,13 +13,11 @@ export default function BasicInfoStep({ form, disabled, mode }) {
<Col span={24}>
<Form.Item
name="businessScope"
label={mode === 'filed' ? "已有资质备案" : "申请的业务范围"}
label={mode === 'filed' ? "拟备案的法定安全评价业务范围" : "拟申请的法定安全评价业务范围"}
rules={[{ required: !disabled, message: "请选择业务范围" }]}
>
<Select
<Checkbox.Group
options={QUALIFICATION_INDUSTRY_OPTIONS}
mode="multiple"
placeholder="请选择证照类型"
/>
</Form.Item>
</Col>
@ -52,21 +50,16 @@ export default function BasicInfoStep({ form, disabled, mode }) {
<Input placeholder="统一社会信用代码" maxLength={18} />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="officeAddress" label="办公地址" rules={[{ required: !disabled, message: "请输入办公地址" }]}>
<Input placeholder="办公地址" maxLength={128} />
</Form.Item>
</Col>
<Col span={24}>
<Form.Item name="registerAddress" label="注册地址" rules={[{ required: !disabled, message: "请输入注册地址" }]}>
<Input placeholder="注册地址" maxLength={128} />
</Form.Item>
</Col>
{mode!=='application' &&<Col span={12}>
<Form.Item name="qualCertNo" label="资质证书编号" rules={[{ required: !disabled, message: "请输入资质证书编号" }]}>
<Input placeholder="资质证书编号" maxLength={32} />
<Col span={24}>
<Form.Item name="officeAddress" label="办公地址" rules={[{ required: !disabled, message: "请输入办公地址" }]}>
<Input placeholder="办公地址" maxLength={128} />
</Form.Item>
</Col>}
</Col>
<Col span={12}>
<Form.Item
name="infoDisclosureUrl"
@ -82,19 +75,57 @@ export default function BasicInfoStep({ form, disabled, mode }) {
<Input placeholder="信息公开网址" maxLength={128} />
</Form.Item>
</Col>
{mode!=='application' &&<Col span={12}>
<Form.Item name="qualCertNo" label="资质证书编号" rules={[{ required: !disabled, message: "请输入资质证书编号" }]}>
<Input placeholder="资质证书编号" maxLength={32} />
</Form.Item>
</Col>}
<Col span={12}>
<Form.Item
name="legalRepresentative"
label="法定代表人"
rules={[{ required: !disabled, message: "请输入法定代表人" }]}
>
<Input placeholder="请输入法定代表人" maxLength={50} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="legalPersonPhone"
label="法人代表电话"
label="法定代表人电话"
rules={[
{ required: !disabled, message: "请输入法人代表电话" },
{ required: !disabled, message: "请输入法定代表人电话" },
{
pattern: /^(1\d{10}|0\d{2,3}-?\d{7,8})$/,
message: "请输入正确的手机号或座机号",
},
]}
>
<Input placeholder="请输入法人代表电话" maxLength={11} />
<Input placeholder="请输入法定代表人电话" maxLength={11} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="fax"
label="传真"
rules={[
{ required: !disabled, message: "请输入传真" },
{
pattern: /^(1\d{10}|0\d{2,3}-?\d{7,8})$/,
message: "请输入正确的手机号或座机号",
},
]}
>
<Input placeholder="请输入传真" maxLength={20} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="contactName"
label="联系人"
rules={[{ required: !disabled, message: "请输入联系人" }]}
>
<Input placeholder="请输入联系人" maxLength={50} />
</Form.Item>
</Col>
<Col span={12}>
@ -190,7 +221,7 @@ export default function BasicInfoStep({ form, disabled, mode }) {
<AttachmentUpload
name="attachmentUrl"
rules={[{ required: !disabled, message: "请上传附件" }]}
label="上传附件"
label="营业执照"
disabled={disabled}
extra={'最多上传12个PDF、DOC、DOCX格式文件'}
maxCount={12}

View File

@ -1,20 +1,9 @@
import { Button, Form, Input, Modal, Table } from "antd";
import { Button, Form, Input, Modal, Table, Tag, Space } from "antd";
import { useEffect, useState } from "react";
import { apiGet } from "~/utils/enterpriseInfo/http";
import { CAPABILITY_MAP, GENDER_MAP } from "~/enumerate/constant";
import { CAPABILITY_MAP, CERT_TYPE_MAP } from "~/enumerate/constant";
import StaffViewModal from "~/components/StaffViewModal";
function calcAge(birthDate) {
if (!birthDate) return "-";
const birth = new Date(birthDate);
if (isNaN(birth.getTime())) return "-";
const now = new Date();
let age = now.getFullYear() - birth.getFullYear();
const m = now.getMonth() - birth.getMonth();
if (m < 0 || (m === 0 && now.getDate() < birth.getDate())) age--;
return age >= 0 ? age : "-";
}
export default function OrgPersonnelSelectModal(props) {
const { open, onCancel, onConfirm, existingIds = [] } = props;
const [searchForm] = Form.useForm();
@ -23,7 +12,11 @@ export default function OrgPersonnelSelectModal(props) {
const [viewId, setViewId] = useState("");
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
total: 0,
});
const getData = async (page = 1, pageSize = 10) => {
setLoading(true);
@ -35,8 +28,13 @@ export default function OrgPersonnelSelectModal(props) {
personName: values.personName || undefined,
});
if (res?.success !== false) {
setDataSource((res?.data || []).map((item) => ({ ...item, age: calcAge(item.birthDate) })));
setPagination((prev) => ({ ...prev, current: page, pageSize, total: res?.total || 0 }));
setDataSource(res?.data || []);
setPagination((prev) => ({
...prev,
current: page,
pageSize,
total: res?.total || 0,
}));
}
} catch (err) {
console.warn("[OrgPersonnelSelectModal] list failed:", err);
@ -59,7 +57,9 @@ export default function OrgPersonnelSelectModal(props) {
};
const handleOk = () => {
const ids = selectedRowKeys.filter((id) => !existingIds.includes(String(id)));
const ids = selectedRowKeys.filter(
(id) => !existingIds.includes(String(id)),
);
if (!ids.length) {
Modal.warning({ title: "提示", content: "请选择至少一名未添加的人员" });
return;
@ -84,8 +84,18 @@ export default function OrgPersonnelSelectModal(props) {
<Input placeholder="人员姓名搜索" allowClear />
</Form.Item>
<Form.Item>
<Button type="primary" onClick={handleSearch}>搜索</Button>
<Button style={{ marginLeft: 8 }} onClick={() => { searchForm.resetFields(); getData(); }}>重置</Button>
<Button type="primary" onClick={handleSearch}>
搜索
</Button>
<Button
style={{ marginLeft: 8 }}
onClick={() => {
searchForm.resetFields();
getData();
}}
>
重置
</Button>
</Form.Item>
</Form>
<Table
@ -110,22 +120,54 @@ export default function OrgPersonnelSelectModal(props) {
showTotal: (t) => `${t}`,
onChange: (page, pageSize) => getData(page, pageSize),
}}
scroll={{ x: 1100, y: 400 }}
scroll={{ x: 800, y: 400 }}
columns={[
{ title: "人员姓名", dataIndex: "personName", ellipsis: true, width: 100 },
{ title: "部门", dataIndex: "deptName", ellipsis: true, width: 150 },
{ title: "岗位", dataIndex: "positionName", ellipsis: true, width: 120 },
{ title: "性别", dataIndex: "genderCode", width: 70, render: (v) => GENDER_MAP[v] || "-" },
{ title: "年龄", dataIndex: "age", width: 70 },
{ title: "注册安全工程师", dataIndex: "registerEngineerFlag", width: 130, render: (v) => v === 1 ? "是" : "否" },
{ title: "评价师", dataIndex: "evaluatorCertNo", width: 80, render: (v) => v ? "是" : "否" },
{
title: "能力",
render: (_, record) => {
const codes = record.professionalCapabilityCodeList || [];
return codes.length
? codes.map((code) => CAPABILITY_MAP[code] || code).join("、")
: "-";
title: "姓名",
dataIndex: "personName",
ellipsis: true,
width: 100,
},
{
title: "部门",
dataIndex: "deptName",
ellipsis: true,
width: 150,
},
{
title: "岗位",
dataIndex: "positionName",
ellipsis: true,
width: 120,
},
{
title: "专业能力",
dataIndex: "capabilityAssessment",
render: (list) => {
if (!Array.isArray(list) || !list.length) return "-";
return list.map((item) => CAPABILITY_MAP[item.professionalCapabilityCode] ).join("、");
},
},
{
title: "证照名称",
dataIndex: "personnelCertFilingPageCOList",
width: 200,
render: (list) => {
if (!Array.isArray(list) || !list.length) return "-";
const colorMap = {
registered_safety_engineer: "blue",
evaluator: "green",
};
return (
<Space size={4}>
{list.map((item) => (
<Tag key={item.id} color={colorMap[item.certTypeCode]}>
{CERT_TYPE_MAP[item.certTypeCode] || item.certTypeCode}
</Tag>
))}
</Space>
);
},
},
{
@ -133,7 +175,13 @@ export default function OrgPersonnelSelectModal(props) {
width: 80,
fixed: "right",
render: (_, record) => (
<Button type="link" size="small" onClick={() => setViewId(record.id)}>查看</Button>
<Button
type="link"
size="small"
onClick={() => setViewId(record.id)}
>
查看
</Button>
),
},
]}

View File

@ -82,7 +82,7 @@ const PersonnelStep=({
{ title: "注册安全工程师", dataIndex: "registerEngineerFlag", width: 120, render: (v) => v === 1 ? "是" : "否" },
{ title: "评价师", dataIndex: "evaluatorCertNo", width: 80, render: (v) => v ? "是" : "否" },
{
title: "能力",
title: "专业能力",
render: (_, record) => {
const codes = record.professionalCapabilityCodeList || [];
return codes.length