基础信息修改
parent
9908a0093a
commit
36dec6aa92
|
|
@ -0,0 +1,17 @@
|
||||||
|
E:\works\projects\safety-eval-service-frontend\node_modules\@cqsjjb\scripts\node_modules\@rspack\dev-server\dist\server.js:1658
|
||||||
|
throw error;
|
||||||
|
^
|
||||||
|
|
||||||
|
Error: listen EADDRINUSE: address already in use 0.0.0.0:8081
|
||||||
|
at Server.setupListenHandle [as _listen2] (node:net:1941:16)
|
||||||
|
at listenInCluster (node:net:1998:12)
|
||||||
|
at node:net:2207:7
|
||||||
|
at process.processTicksAndRejections (node:internal/process/task_queues:89:21) {
|
||||||
|
code: 'EADDRINUSE',
|
||||||
|
errno: -4091,
|
||||||
|
syscall: 'listen',
|
||||||
|
address: '0.0.0.0',
|
||||||
|
port: 8081
|
||||||
|
}
|
||||||
|
|
||||||
|
Node.js v22.23.1
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
> micro-app@2.0.0 serve:development
|
||||||
|
> cross-env NODE_ENV=development npm run serve
|
||||||
|
|
||||||
|
|
||||||
|
> micro-app@2.0.0 serve
|
||||||
|
> node node_modules/@cqsjjb/scripts/rspack.dev.server.js
|
||||||
|
|
||||||
|
[90m14:19:46[39m [Module] [34m[INFO][39m [90mBabel 配置文件已加载: [37mE:\works\projects\safety-eval-service-frontend//jjb.babel.js[90m[39m
|
||||||
|
[90m14:19:46[39m [Config] [34m[INFO][39m [36m正在加载配置文件...[39m
|
||||||
|
[90m14:19:46[39m [Config] [34m[INFO][39m [90m配置文件已加载: [37mE:\works\projects\safety-eval-service-frontend//jjb.config.js[90m[39m
|
||||||
|
[90m14:19:46[39m [Config] [32m[SUCCESS][39m [32m配置验证通过[39m
|
||||||
|
[90m14:19:46[39m [Config] [34m[INFO][39m [90m运行模式: [32mdevelopment[90m[39m
|
||||||
|
[90m14:19:46[39m [DevServer] [34m[INFO][39m [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[39m
|
||||||
|
[90m14:19:46[39m [DevServer] [34m[INFO][39m [90m运行模式: [32mdevelopment[90m[39m
|
||||||
|
[90m14:19:47[39m [DevServer] [34m[INFO][39m [36m正在启动 开发服务器...[39m
|
||||||
|
[90m14:19:47[39m [DevServer] [34m[INFO][39m [36m正在编译...[39m
|
||||||
|
|
@ -1,39 +1,26 @@
|
||||||
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
Checkbox,
|
||||||
Col,
|
Col,
|
||||||
DatePicker,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
message,
|
message,
|
||||||
Row,
|
Row,
|
||||||
Select,
|
|
||||||
Space,
|
Space,
|
||||||
Flex,
|
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import AttachmentUpload from "~/components/AttachmentUpload";
|
|
||||||
import BaiduMapPicker from "~/components/BaiduMapPicker";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
||||||
import { NATIONAL_COUNTIES } from "~/enumerate/constant";
|
|
||||||
|
|
||||||
import {
|
// 2026-08-08 变更:按原型 V1.6 institution.html 的 #mod-org-info 模块 1:1 还原机构基础信息表单。
|
||||||
ENTERPRISE_SCALE_OPTIONS,
|
// 复用既有「安全生产监管行业类别」枚举作为「拟申请的法定安全评价业务范围」候选项,
|
||||||
ENTERPRISE_STATUS_OPTIONS,
|
// 二者取值集合完全一致(煤矿/金属非金属矿/陆地油气/油气管道/石油化工医药/烟花爆竹/金属冶炼),无需新增枚举。
|
||||||
REGISTERED_ORG_FILING_RECORD_STATUS_OPTIONS,
|
import { QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate/enterpriseOptions";
|
||||||
REGISTERED_ORG_FILING_TYPE_SEARCH_OPTIONS,
|
|
||||||
QUALIFICATION_INDUSTRY_OPTIONS,
|
|
||||||
ECONOMY_INDUSTRY_OPTIONS,
|
|
||||||
} from "~/enumerate/enterpriseOptions";
|
|
||||||
import { NS_ORG_INFO } from "~/enumerate/namespace";
|
import { NS_ORG_INFO } from "~/enumerate/namespace";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
coordinatePairRule,
|
|
||||||
creditCodeRule,
|
creditCodeRule,
|
||||||
latitudeRule,
|
|
||||||
longitudeRule,
|
|
||||||
nonNegativeIntegerRule,
|
nonNegativeIntegerRule,
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
phoneRule,
|
phoneRule,
|
||||||
|
|
@ -41,13 +28,59 @@ import {
|
||||||
urlRule,
|
urlRule,
|
||||||
} from "~/utils/validators";
|
} from "~/utils/validators";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2026-08-08 新增:业务范围在后端为 varchar(500) 的「逗号分隔字符串」(apply_business_scope),
|
||||||
|
* 而原型要求多选交互,故在页面出入口做数组/字符串互转。
|
||||||
|
* 不做字段名映射,仅做同名字段的值形态转换,保持前后端字段名一致。
|
||||||
|
*/
|
||||||
|
const splitBusinessScope = (value) => {
|
||||||
|
if (Array.isArray(value)) return value;
|
||||||
|
if (!value) return undefined;
|
||||||
|
return String(value)
|
||||||
|
.split(",")
|
||||||
|
.map((item) => item.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
};
|
||||||
|
|
||||||
|
const joinBusinessScope = (value) =>
|
||||||
|
Array.isArray(value) ? value.join(",") : value || undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2026-08-08 联系人及电话合并/拆分工具(交互约定见下方说明):
|
||||||
|
* 录入:单输入框,值格式「联系人/电话」,用 / 分隔。
|
||||||
|
* 提交前:按首个 / 拆为 contactName(/前)+ contactPhone(/后)两字段,传给后端。
|
||||||
|
* 回显:后端 contactName/contactPhone 用 / 合并回单输入框。
|
||||||
|
* 后端落库:contact_name varchar(50)、contact_phone varchar(20);原 contact_name_phone 列保留不删、不再写入。
|
||||||
|
* 复用要点:其他页面如需同样交互,保持「单输入框 + / 分隔 + 提交拆分存两列 + 回显合并」即可。
|
||||||
|
* 注意:分隔符为单斜杠「/」(无空格),与录入示例"张三/13800138000"一致。
|
||||||
|
*/
|
||||||
|
const CONTACT_SEP = "/";
|
||||||
|
|
||||||
|
const mergeContactNamePhone = (name, phone) => {
|
||||||
|
if (!name && !phone) return undefined;
|
||||||
|
return [name, phone].filter(Boolean).join(CONTACT_SEP);
|
||||||
|
};
|
||||||
|
|
||||||
|
const splitContactNamePhone = (value) => {
|
||||||
|
if (!value) return { contactName: undefined, contactPhone: undefined };
|
||||||
|
const idx = String(value).indexOf(CONTACT_SEP);
|
||||||
|
if (idx >= 0) {
|
||||||
|
return {
|
||||||
|
// 按首个 / 拆分;/后全部作为电话(剔除首尾空白),多余字符交给校验/提交时处理
|
||||||
|
contactName: String(value).slice(0, idx).trim(),
|
||||||
|
contactPhone: String(value).slice(idx + 1).trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 无分隔符:整体作为联系人姓名,电话置空(由校验拦截)
|
||||||
|
return { contactName: String(value).trim(), contactPhone: undefined };
|
||||||
|
};
|
||||||
|
|
||||||
function OrgInfoPage(props) {
|
function OrgInfoPage(props) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { orgInfoLoading } = props.orgInfo;
|
const { orgInfoLoading } = props.orgInfo;
|
||||||
const [editing, setEditing] = useState(true);
|
const [editing, setEditing] = useState(true);
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [detail, setDetail] = useState({});
|
const [detail, setDetail] = useState({});
|
||||||
const [mapPickerVisible, setMapPickerVisible] = useState(false);
|
|
||||||
/** 是否已存在机构数据(有 id 视为已入库,只能修改) */
|
/** 是否已存在机构数据(有 id 视为已入库,只能修改) */
|
||||||
const [hasExistingData, setHasExistingData] = useState(false);
|
const [hasExistingData, setHasExistingData] = useState(false);
|
||||||
|
|
||||||
|
|
@ -58,12 +91,13 @@ function OrgInfoPage(props) {
|
||||||
setDetail(res.data);
|
setDetail(res.data);
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...res.data,
|
...res.data,
|
||||||
productionDate: res.data.productionDate
|
// 2026-08-08 业务范围回填为数组以适配多选控件
|
||||||
? dayjs(res.data.productionDate)
|
applyBusinessScope: splitBusinessScope(res.data.applyBusinessScope),
|
||||||
: undefined,
|
// 2026-08-08 联系人及电话:后端 contactName/contactPhone 两列合并为单字段展示
|
||||||
attachmentUrls: res.data.attachmentUrls
|
contactNamePhone: mergeContactNamePhone(
|
||||||
? JSON.parse(res.data.attachmentUrls)
|
res.data.contactName,
|
||||||
: null,
|
res.data.contactPhone,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
setHasExistingData(true);
|
setHasExistingData(true);
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
|
|
@ -91,14 +125,23 @@ function OrgInfoPage(props) {
|
||||||
const handleSave = async (submitType) => {
|
const handleSave = async (submitType) => {
|
||||||
try {
|
try {
|
||||||
const formValues = await form.validateFields();
|
const formValues = await form.validateFields();
|
||||||
|
// 2026-08-08 联系人及电话:单字段拆分为后端 contactName / contactPhone 两列提交
|
||||||
|
const split = splitContactNamePhone(formValues.contactNamePhone);
|
||||||
|
// 剔除多余字符:姓名/电话做 trim 与空白清理(校验已保证格式,此处仅兜底)
|
||||||
|
const contactName = split.contactName
|
||||||
|
? split.contactName.replace(/\s+/g, "")
|
||||||
|
: undefined;
|
||||||
|
const contactPhone = split.contactPhone
|
||||||
|
? split.contactPhone.replace(/\s+/g, "")
|
||||||
|
: undefined;
|
||||||
const values = {
|
const values = {
|
||||||
...formValues,
|
...formValues,
|
||||||
productionDate: formValues.productionDate
|
contactName,
|
||||||
? dayjs(formValues.productionDate).format("YYYY-MM-DD")
|
contactPhone,
|
||||||
: undefined,
|
// 移除仅用于展示的合并字段,避免提交冗余
|
||||||
attachmentUrls: formValues.attachmentUrls
|
contactNamePhone: undefined,
|
||||||
? JSON.stringify(formValues.attachmentUrls)
|
// 2026-08-08 多选业务范围按后端 varchar(500) 约定以逗号拼接提交
|
||||||
: null,
|
applyBusinessScope: joinBusinessScope(formValues.applyBusinessScope),
|
||||||
infoDisclosureUrl: formValues.infoDisclosureUrl
|
infoDisclosureUrl: formValues.infoDisclosureUrl
|
||||||
? normalizeUrl(formValues.infoDisclosureUrl)
|
? normalizeUrl(formValues.infoDisclosureUrl)
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|
@ -132,18 +175,14 @@ function OrgInfoPage(props) {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleMapConfirm = ({ lng, lat }) => {
|
|
||||||
form.setFieldsValue({ longitude: lng, latitude: lat });
|
|
||||||
setMapPickerVisible(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
title={
|
title={
|
||||||
<div>
|
<div>
|
||||||
|
{/* 2026-08-08 标题/副标题对齐原型 institution.html #mod-org-info */}
|
||||||
<span>基础信息管理</span>
|
<span>基础信息管理</span>
|
||||||
<div className="pageLayout-extra">
|
<div className="pageLayout-extra">
|
||||||
新成立或首次使用系统的安全评价机构,可通过系统提供的引导页面,详细填写机构的基本信息。
|
机构注册认证信息,可在此持续维护并提交审核。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -160,19 +199,33 @@ function OrgInfoPage(props) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Form form={form} labelCol={{ span: 10 }} disabled={!editing}>
|
{/*
|
||||||
|
2026-08-08 布局对齐原型 institution.html:
|
||||||
|
原型 .form-grid 为两列网格、label 在控件上方(纵向),gap 1rem。
|
||||||
|
此处使用 antd Form layout="vertical" + Row/Col 两列还原,整行字段 span=24。
|
||||||
|
2026-08-08 按原型 .info-card 增加带边框容器并整体居中(border-radius 8px、padding 1.25rem、maxWidth 960px 居中)。
|
||||||
|
*/}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "94%",
|
||||||
|
maxWidth: "100%",
|
||||||
|
margin: "0 auto",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: "1.25rem",
|
||||||
|
background: "#fff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form form={form} layout="vertical" disabled={!editing}>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
|
{/* 2026-08-08 字段顺序严格对齐原型 institution.html 434-450 行 */}
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="unitName"
|
name="unitName"
|
||||||
label="生产经营单位名称"
|
label="单位名称"
|
||||||
rules={[{ required: true, message: "请输入生产经营单位名称" }]}
|
rules={[{ required: true, message: "请输入单位名称" }]}
|
||||||
>
|
>
|
||||||
<Input
|
<Input placeholder="请输入单位名称" allowClear maxLength={200} />
|
||||||
placeholder="请输入生产经营单位名称"
|
|
||||||
allowClear
|
|
||||||
maxLength={200}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
|
|
@ -188,180 +241,59 @@ function OrgInfoPage(props) {
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
{/* 原型:注册地址占整行(full) */}
|
||||||
<Form.Item
|
<Col span={24}>
|
||||||
name="safetyIndustryCategoryCode"
|
|
||||||
label="安全生产监管行业类别"
|
|
||||||
rules={[
|
|
||||||
{ required: true, message: "请选择安全生产监管行业类别" },
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
options={QUALIFICATION_INDUSTRY_OPTIONS}
|
|
||||||
mode="multiple"
|
|
||||||
placeholder="请选择安全生产监管行业类别"
|
|
||||||
allowClear
|
|
||||||
onChange={(value, option) => {
|
|
||||||
form.setFieldValue(
|
|
||||||
"safetyIndustryCategoryName",
|
|
||||||
option?.map((item) => item.label).join(",") || "",
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="safetyIndustryCategoryName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="districtCode"
|
|
||||||
label="属地"
|
|
||||||
rules={[{ required: true, message: "请选择属地" }]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
options={NATIONAL_COUNTIES}
|
|
||||||
placeholder="请选择属地"
|
|
||||||
allowClear
|
|
||||||
showSearch
|
|
||||||
optionFilterProp="label"
|
|
||||||
onChange={(value, option) => {
|
|
||||||
form.setFieldValue("districtName", option?.label || "");
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="districtName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="townStreet"
|
|
||||||
label="所属镇、街道"
|
|
||||||
rules={[{ required: true, message: "请输入所属镇街道" }]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
placeholder="请输入所属镇街道"
|
|
||||||
allowClear
|
|
||||||
maxLength={100}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="villageCommunity" label="属村(社区)">
|
|
||||||
<Input
|
|
||||||
placeholder="请输入属村(社区)"
|
|
||||||
allowClear
|
|
||||||
maxLength={100}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item label="所在地坐标经度">
|
|
||||||
<Flex>
|
|
||||||
<Form.Item
|
|
||||||
name="longitude"
|
|
||||||
noStyle
|
|
||||||
dependencies={["latitude"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
validator(_, value) {
|
|
||||||
const latitude = form.getFieldValue("latitude");
|
|
||||||
if (
|
|
||||||
value !== undefined &&
|
|
||||||
value !== null &&
|
|
||||||
value !== "" &&
|
|
||||||
(latitude === undefined ||
|
|
||||||
latitude === null ||
|
|
||||||
latitude === "")
|
|
||||||
) {
|
|
||||||
return Promise.reject(
|
|
||||||
new Error("填写经度后,纬度必填"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputNumber
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
min={-180}
|
|
||||||
max={180}
|
|
||||||
precision={6}
|
|
||||||
placeholder="请输入经度"
|
|
||||||
allowClear
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Button onClick={() => setMapPickerVisible(true)}>选择</Button>
|
|
||||||
</Flex>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="latitude"
|
|
||||||
label="所在地坐标纬度"
|
|
||||||
dependencies={["longitude"]}
|
|
||||||
rules={[
|
|
||||||
latitudeRule(false),
|
|
||||||
coordinatePairRule("longitude", "纬度", "经度"),
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputNumber
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
min={-90}
|
|
||||||
max={90}
|
|
||||||
precision={6}
|
|
||||||
placeholder="请输入纬度"
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="registerAddress"
|
name="registerAddress"
|
||||||
label="注册地址"
|
label="注册地址"
|
||||||
rules={[{ required: true, message: "请输入注册地址" }]}
|
rules={[{ required: true, message: "请输入注册地址" }]}
|
||||||
>
|
>
|
||||||
<Input.TextArea
|
<Input placeholder="请输入注册地址" maxLength={500} />
|
||||||
rows={3}
|
|
||||||
placeholder="请输入注册地址"
|
|
||||||
maxLength={200}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
{/* 原型:办公地址占整行(full),TextArea rows=3 */}
|
||||||
|
<Col span={24}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="businessAddress"
|
name="businessAddress"
|
||||||
label="经营地址"
|
label="办公地址"
|
||||||
rules={[{ required: true, message: "请输入经营地址" }]}
|
rules={[{ required: true, message: "请输入办公地址" }]}
|
||||||
>
|
>
|
||||||
<Input.TextArea
|
<Input.TextArea
|
||||||
rows={3}
|
rows={3}
|
||||||
placeholder="请输入经营地址"
|
placeholder="请输入办公地址"
|
||||||
maxLength={200}
|
maxLength={500}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="ownershipTypeName" label="归属类型">
|
|
||||||
<Input placeholder="请输入归属类型" allowClear maxLength={50} />
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="economyIndustryCode"
|
name="infoDisclosureUrl"
|
||||||
label="国民经济行业分类(GB/T4754-2017)"
|
label="信息公开网址"
|
||||||
|
rules={[urlRule("信息公开网址", true)]}
|
||||||
|
normalize={(value) =>
|
||||||
|
typeof value === "string" ? value.trim() : value
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Select
|
<Input
|
||||||
options={ECONOMY_INDUSTRY_OPTIONS}
|
placeholder="请输入信息公开网址"
|
||||||
placeholder="请选择国民经济行业分类"
|
|
||||||
allowClear
|
allowClear
|
||||||
onChange={(value, option) => {
|
maxLength={500}
|
||||||
form.setFieldValue(
|
/>
|
||||||
"economyIndustryName",
|
</Form.Item>
|
||||||
option?.label || "",
|
</Col>
|
||||||
);
|
{/* 原型:资质证书编号非必填,带"非必填,初次申请无需填写"提示 */}
|
||||||
}}
|
<Col span={12}>
|
||||||
|
<Form.Item
|
||||||
|
name="qualificationCertNo"
|
||||||
|
label="资质证书编号"
|
||||||
|
extra="非必填,初次申请无需填写"
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="初次申请无需填写"
|
||||||
|
allowClear
|
||||||
|
maxLength={100}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="economyIndustryName" noStyle />
|
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|
@ -372,127 +304,117 @@ function OrgInfoPage(props) {
|
||||||
<Input placeholder="请输入法定代表人" allowClear maxLength={50} />
|
<Input placeholder="请输入法定代表人" allowClear maxLength={50} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
{/* 2026-08-08 标签对齐原型「法定代表人电话」 */}
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="legalRepresentativePhone"
|
name="legalRepresentativePhone"
|
||||||
label="法定代表人联系电话"
|
label="法定代表人电话"
|
||||||
rules={[phoneRule("法定代表人联系电话", false)]}
|
rules={[phoneRule("法定代表人电话", true)]}
|
||||||
normalize={(value) =>
|
normalize={(value) =>
|
||||||
typeof value === "string" ? value.trim() : value
|
typeof value === "string" ? value.trim() : value
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder="请输入法定代表人联系电话"
|
placeholder="请输入法定代表人电话"
|
||||||
allowClear
|
allowClear
|
||||||
maxLength={11}
|
maxLength={20}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item name="fax" label="传真" rules={[{ required: true, message: "请输入传真" }]}>
|
||||||
name="principalName"
|
<Input placeholder="请输入传真" allowClear maxLength={20} />
|
||||||
label="主要负责人"
|
|
||||||
rules={[{ required: true, message: "请输入主要负责人" }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="请输入主要负责人" allowClear maxLength={50} />
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
|
{/*
|
||||||
|
2026-08-08 联系人及电话(交互约定):
|
||||||
|
单输入框录入,格式「联系人/电话」(用 / 分隔),如:张三/13800138000;
|
||||||
|
提交前按首个 / 拆为 contactName(/前)+ contactPhone(/后)存两列;
|
||||||
|
回显时后端 contactName/contactPhone 用 / 合并回填。
|
||||||
|
校验:拆分后 contactName 非空且≤50、contactPhone 非空且匹配手机/座机格式且≤20。
|
||||||
|
*/}
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="principalPhone"
|
name="contactNamePhone"
|
||||||
label="主要负责人联系电话"
|
label="联系人及电话"
|
||||||
rules={[phoneRule("主要负责人联系电话", true)]}
|
validateFirst
|
||||||
normalize={(value) =>
|
rules={[
|
||||||
typeof value === "string" ? value.trim() : value
|
{ required: true, message: "请输入联系人及电话" },
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
const { contactName, contactPhone } =
|
||||||
|
splitContactNamePhone(value);
|
||||||
|
if (!contactName) {
|
||||||
|
return Promise.reject(new Error("联系人不能为空"));
|
||||||
}
|
}
|
||||||
|
if (contactName.length > 50) {
|
||||||
|
return Promise.reject(new Error("联系人不能超过50字"));
|
||||||
|
}
|
||||||
|
if (!contactPhone) {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error("请使用/分隔联系人和电话,并填写电话"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 复用既有 PHONE_PATTERN:手机11位 / 固话10~12位(去空白后)
|
||||||
|
if (
|
||||||
|
!/^(1[3-9]\d{9}|\d{10,12})$/.test(
|
||||||
|
String(contactPhone).replace(/\s+/g, ""),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error("电话格式不正确(手机11位或固话区号+号码)"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (contactPhone.length > 20) {
|
||||||
|
return Promise.reject(new Error("电话不能超过20字"));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
extra="请使用/分隔联系人和电话,如:张三/13800138000"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder="请输入主要负责人联系电话"
|
placeholder="如:张三/13800138000"
|
||||||
allowClear
|
allowClear
|
||||||
maxLength={11}
|
maxLength={73}
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="safetyDeptManager" label="安全管理部门负责人">
|
|
||||||
<Input
|
|
||||||
placeholder="请输入安全管理部门负责人"
|
|
||||||
allowClear
|
|
||||||
maxLength={50}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="safetyDeptManagerPhone"
|
name="fixedAssetsTotal"
|
||||||
label="安全管理部门负责人联系电话"
|
label="固定资产总值(万元)"
|
||||||
rules={[phoneRule("安全管理部门负责人联系电话", false)]}
|
rules={[
|
||||||
normalize={(value) =>
|
{ required: true, message: "请输入固定资产总值" },
|
||||||
typeof value === "string" ? value.trim() : value
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (value === undefined || value === null || value === "") {
|
||||||
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
>
|
if (Number(value) < 0) {
|
||||||
<Input
|
return Promise.reject(
|
||||||
placeholder="请输入安全管理部门负责人联系电话"
|
new Error("固定资产总值应为非负数字"),
|
||||||
allowClear
|
);
|
||||||
maxLength={11}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="safetyDeputyPhone"
|
|
||||||
label="主管安全副总联系电话"
|
|
||||||
rules={[phoneRule("主管安全副总联系电话", false)]}
|
|
||||||
normalize={(value) =>
|
|
||||||
typeof value === "string" ? value.trim() : value
|
|
||||||
}
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input
|
<InputNumber
|
||||||
placeholder="请输入主管安全副总联系电话"
|
|
||||||
allowClear
|
|
||||||
maxLength={11}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="productionDate" label="投产日期">
|
|
||||||
<DatePicker
|
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
placeholder="请选择投产日期"
|
min={0}
|
||||||
/>
|
precision={4}
|
||||||
</Form.Item>
|
placeholder="请输入固定资产总值"
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="businessStatusName" label="企业经营状态">
|
|
||||||
<Input
|
|
||||||
placeholder="请输入企业经营状态"
|
|
||||||
allowClear
|
|
||||||
maxLength={50}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item
|
|
||||||
name="infoDisclosureUrl"
|
|
||||||
label="信息公开网址"
|
|
||||||
rules={[urlRule("信息公开网址", false)]}
|
|
||||||
normalize={(value) =>
|
|
||||||
typeof value === "string" ? value.trim() : value
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
placeholder="请输入信息公开网址"
|
|
||||||
allowClear
|
|
||||||
maxLength={200}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="workplaceArea"
|
name="workplaceArea"
|
||||||
label="工作场所建筑面积"
|
label="工作场所建筑面积(㎡)"
|
||||||
rules={[positiveNumberRule("工作场所建筑面积", false)]}
|
rules={[positiveNumberRule("工作场所建筑面积", true)]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
|
|
@ -506,8 +428,8 @@ function OrgInfoPage(props) {
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="archiveRoomArea"
|
name="archiveRoomArea"
|
||||||
label="档案室面积"
|
label="档案室面积(㎡)"
|
||||||
rules={[positiveNumberRule("档案室面积", false)]}
|
rules={[positiveNumberRule("档案室面积", true)]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
|
|
@ -522,7 +444,7 @@ function OrgInfoPage(props) {
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="fulltimeEvaluatorCount"
|
name="fulltimeEvaluatorCount"
|
||||||
label="专职安全评价师数量"
|
label="专职安全评价师数量"
|
||||||
rules={[nonNegativeIntegerRule("专职安全评价师数量", false)]}
|
rules={[nonNegativeIntegerRule("专职安全评价师数量", true)]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
|
|
@ -537,7 +459,7 @@ function OrgInfoPage(props) {
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="registeredEngineerCount"
|
name="registeredEngineerCount"
|
||||||
label="注册安全工程师数量"
|
label="注册安全工程师数量"
|
||||||
rules={[nonNegativeIntegerRule("注册安全工程师数量", false)]}
|
rules={[nonNegativeIntegerRule("注册安全工程师数量", true)]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
|
|
@ -548,84 +470,56 @@ function OrgInfoPage(props) {
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
{/*
|
||||||
<Form.Item name="enterpriseStatusCode" label="企业状态">
|
2026-08-08 业务范围:
|
||||||
<Select
|
原型为 checkbox 网格(2列、灰底 #f8fafc、边框容器),此处用 Checkbox.Group + Row/Col 还原视觉。
|
||||||
options={ENTERPRISE_STATUS_OPTIONS}
|
*/}
|
||||||
placeholder="请选择企业状态"
|
<Col span={24}>
|
||||||
allowClear
|
<Form.Item
|
||||||
onChange={(value, option) => {
|
name="applyBusinessScope"
|
||||||
console.log(value, option);
|
label="拟申请的法定安全评价业务范围"
|
||||||
form.setFieldValue(
|
rules={[
|
||||||
"enterpriseStatusName",
|
{
|
||||||
option?.label || "",
|
required: true,
|
||||||
);
|
message: "请选择拟申请的法定安全评价业务范围",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Checkbox.Group
|
||||||
|
style={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
|
||||||
|
gap: "0.65rem 1rem",
|
||||||
|
padding: "1rem",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
borderRadius: 8,
|
||||||
|
background: "#f8fafc",
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
{QUALIFICATION_INDUSTRY_OPTIONS.map((opt) => (
|
||||||
|
<Checkbox key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</Checkbox>
|
||||||
|
))}
|
||||||
|
</Checkbox.Group>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
{/* 原型:单位基本情况介绍(可附页),TextArea rows=7 */}
|
||||||
|
<Col span={24}>
|
||||||
|
<Form.Item
|
||||||
|
name="orgIntro"
|
||||||
|
label="单位基本情况介绍(可附页)"
|
||||||
|
rules={[{ required: true, message: "请输入单位基本情况介绍" }]}
|
||||||
|
>
|
||||||
|
<Input.TextArea
|
||||||
|
rows={7}
|
||||||
|
placeholder="请简要介绍单位基本情况,如成立时间、人员构成、技术力量、业绩等"
|
||||||
|
maxLength={2000}
|
||||||
|
showCount
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="enterpriseStatusName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="enterpriseScaleCode" label="企业规模">
|
|
||||||
<Select
|
|
||||||
options={ENTERPRISE_SCALE_OPTIONS}
|
|
||||||
placeholder="请选择企业规模"
|
|
||||||
allowClear
|
|
||||||
onChange={(value, option) => {
|
|
||||||
form.setFieldValue(
|
|
||||||
"enterpriseScaleName",
|
|
||||||
option?.label || "",
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="enterpriseScaleName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="filingTypeCode" label="备案类型">
|
|
||||||
<Select
|
|
||||||
options={REGISTERED_ORG_FILING_TYPE_SEARCH_OPTIONS}
|
|
||||||
placeholder="请选择备案类型"
|
|
||||||
allowClear
|
|
||||||
onChange={(value, option) => {
|
|
||||||
form.setFieldValue("filingTypeName", option?.label);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="filingTypeName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<Form.Item name="filingRecordStatusCode" label="备案状态">
|
|
||||||
<Select
|
|
||||||
options={REGISTERED_ORG_FILING_RECORD_STATUS_OPTIONS}
|
|
||||||
placeholder="请选择备案状态"
|
|
||||||
allowClear
|
|
||||||
onChange={(value, option) => {
|
|
||||||
form.setFieldValue(
|
|
||||||
"filingRecordStatusName",
|
|
||||||
option?.label || "",
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="filingRecordStatusName" noStyle />
|
|
||||||
</Col>
|
|
||||||
<Col span={12}>
|
|
||||||
<AttachmentUpload
|
|
||||||
name="attachmentUrls"
|
|
||||||
label="上传附件"
|
|
||||||
extra={"最多上传10个PDF、DOC、DOCX格式文件"}
|
|
||||||
maxCount={10}
|
|
||||||
accept=".pdf,.doc,.docx"
|
|
||||||
/>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Form>
|
|
||||||
<BaiduMapPicker
|
|
||||||
visible={mapPickerVisible}
|
|
||||||
onCancel={() => setMapPickerVisible(false)}
|
|
||||||
onConfirm={handleMapConfirm}
|
|
||||||
/>
|
|
||||||
{editing && (
|
{editing && (
|
||||||
<div style={{ marginTop: 24, textAlign: "center" }}>
|
<div style={{ marginTop: 24, textAlign: "center" }}>
|
||||||
<Space>
|
<Space>
|
||||||
|
|
@ -645,6 +539,8 @@ function OrgInfoPage(props) {
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue