feat: 前端-机构信息表单校验
parent
4e4f59d288
commit
62d3ffab08
|
|
@ -10,31 +10,41 @@ import {
|
||||||
creditCodeRule,
|
creditCodeRule,
|
||||||
latitudeRule,
|
latitudeRule,
|
||||||
longitudeRule,
|
longitudeRule,
|
||||||
|
nonNegativeIntegerRule,
|
||||||
phoneRule,
|
phoneRule,
|
||||||
positiveNumberRule,
|
positiveNumberRule,
|
||||||
urlRule,
|
urlRule,
|
||||||
} from "~/utils/validators";
|
} from "~/utils/validators";
|
||||||
|
|
||||||
|
const numberFieldProps = { style: { width: "100%" } };
|
||||||
|
|
||||||
function OrgInfoPage(props) {
|
function OrgInfoPage(props) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
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({});
|
||||||
|
/** 是否已存在机构数据(有 id 视为已入库,只能修改) */
|
||||||
|
const [hasExistingData, setHasExistingData] = useState(false);
|
||||||
|
|
||||||
const loadDetail = async () => {
|
const loadDetail = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await props.orgInfoGet().catch(() => null);
|
const res = await props.orgInfoGet().catch(() => null);
|
||||||
if (res?.data) {
|
if (res?.data?.id) {
|
||||||
setDetail(res.data);
|
setDetail(res.data);
|
||||||
form.setFieldsValue(res.data);
|
form.setFieldsValue(res.data);
|
||||||
|
setHasExistingData(true);
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
setDetail({});
|
||||||
|
setHasExistingData(false);
|
||||||
setEditing(true);
|
setEditing(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
console.warn("[OrgInfo] loadDetail failed:", err);
|
console.warn("[OrgInfo] loadDetail failed:", err);
|
||||||
|
setDetail({});
|
||||||
|
setHasExistingData(false);
|
||||||
setEditing(true);
|
setEditing(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -43,14 +53,39 @@ function OrgInfoPage(props) {
|
||||||
loadDetail();
|
loadDetail();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleCancelEdit = () => {
|
||||||
|
if (hasExistingData) {
|
||||||
|
form.setFieldsValue(detail);
|
||||||
|
setEditing(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
form.resetFields();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSave = async (submitType) => {
|
const handleSave = async (submitType) => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
const request = submitType === "draft" ? props.orgInfoDraft : props.orgInfoSave;
|
|
||||||
|
let request;
|
||||||
|
if (hasExistingData) {
|
||||||
|
// 已有数据:仅走修改接口
|
||||||
|
request = props.orgInfoSave;
|
||||||
|
values.id = detail.id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 无数据:暂存、提交均走保存接口(草稿/已提交由 authStatusCode 区分)
|
||||||
|
request = submitType === "draft" ? props.orgInfoDraft : props.orgInfoSave;
|
||||||
|
}
|
||||||
|
|
||||||
const res = await request(values);
|
const res = await request(values);
|
||||||
if (res?.success !== false) {
|
if (res?.success !== false) {
|
||||||
message.success(submitType === "draft" ? "暂存成功" : "提交成功");
|
message.success(
|
||||||
|
hasExistingData
|
||||||
|
? "修改成功"
|
||||||
|
: (submitType === "draft" ? "暂存成功" : "提交成功"),
|
||||||
|
);
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
loadDetail();
|
loadDetail();
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +94,7 @@ function OrgInfoPage(props) {
|
||||||
if (err?.errorFields) {
|
if (err?.errorFields) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.error("保存失败,请稍后重试");
|
message.error(hasExistingData ? "修改失败,请稍后重试" : "保存失败,请稍后重试");
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
|
|
@ -95,15 +130,22 @@ function OrgInfoPage(props) {
|
||||||
{
|
{
|
||||||
name: "regionCommunityName",
|
name: "regionCommunityName",
|
||||||
label: "属村(社区)",
|
label: "属村(社区)",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "longitude",
|
name: "longitude",
|
||||||
label: "所在地坐标经度",
|
label: "所在地坐标经度",
|
||||||
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 },
|
||||||
rules: [longitudeRule(false)],
|
rules: [longitudeRule(false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "latitude",
|
name: "latitude",
|
||||||
label: "所在地坐标纬度",
|
label: "所在地坐标纬度",
|
||||||
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 },
|
||||||
rules: [latitudeRule(false)],
|
rules: [latitudeRule(false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -121,10 +163,12 @@ function OrgInfoPage(props) {
|
||||||
{
|
{
|
||||||
name: "ownershipType",
|
name: "ownershipType",
|
||||||
label: "归属类型",
|
label: "归属类型",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "gbIndustryCode",
|
name: "gbIndustryCode",
|
||||||
label: "国民经济行业分类(GB/T4754-2017)",
|
label: "国民经济行业分类(GB/T4754-2017)",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "legalRepresentative",
|
name: "legalRepresentative",
|
||||||
|
|
@ -149,6 +193,7 @@ function OrgInfoPage(props) {
|
||||||
{
|
{
|
||||||
name: "safetyDeptHead",
|
name: "safetyDeptHead",
|
||||||
label: "安全管理部门负责人",
|
label: "安全管理部门负责人",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "safetyDeptPhone",
|
name: "safetyDeptPhone",
|
||||||
|
|
@ -158,6 +203,7 @@ function OrgInfoPage(props) {
|
||||||
{
|
{
|
||||||
name: "safetyVp",
|
name: "safetyVp",
|
||||||
label: "主管安全副总",
|
label: "主管安全副总",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "safetyVpPhone",
|
name: "safetyVpPhone",
|
||||||
|
|
@ -167,36 +213,51 @@ function OrgInfoPage(props) {
|
||||||
{
|
{
|
||||||
name: "productionDate",
|
name: "productionDate",
|
||||||
label: "投产日期",
|
label: "投产日期",
|
||||||
|
required: false,
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE,
|
render: FORM_ITEM_RENDER_ENUM.DATE,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "businessStatus",
|
name: "businessStatus",
|
||||||
label: "企业经营状态",
|
label: "企业经营状态",
|
||||||
|
required: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disclosureUrl",
|
name: "disclosureUrl",
|
||||||
label: "信息公开网址",
|
label: "信息公开网址",
|
||||||
|
useConstraints: false,
|
||||||
rules: [urlRule("信息公开网址", false)],
|
rules: [urlRule("信息公开网址", false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "workplaceArea",
|
name: "workplaceArea",
|
||||||
label: "工作场所建筑面积",
|
label: "工作场所建筑面积",
|
||||||
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: 0, precision: 2 },
|
||||||
rules: [positiveNumberRule("工作场所建筑面积", false)],
|
rules: [positiveNumberRule("工作场所建筑面积", false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "archiveRoomArea",
|
name: "archiveRoomArea",
|
||||||
label: "档案室面积",
|
label: "档案室面积",
|
||||||
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: 0, precision: 2 },
|
||||||
rules: [positiveNumberRule("档案室面积", false)],
|
rules: [positiveNumberRule("档案室面积", false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fullTimeEvaluatorCount",
|
name: "fullTimeEvaluatorCount",
|
||||||
label: "专职安全评价师数量",
|
label: "专职安全评价师数量",
|
||||||
rules: [positiveNumberRule("专职安全评价师数量", false)],
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: 0, precision: 0 },
|
||||||
|
rules: [nonNegativeIntegerRule("专职安全评价师数量", false)],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "registeredSafetyEngineerCount",
|
name: "registeredSafetyEngineerCount",
|
||||||
label: "注册安全工程师数量",
|
label: "注册安全工程师数量",
|
||||||
rules: [positiveNumberRule("注册安全工程师数量", false)],
|
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
|
||||||
|
useConstraints: false,
|
||||||
|
componentProps: { ...numberFieldProps, min: 0, precision: 0 },
|
||||||
|
rules: [nonNegativeIntegerRule("注册安全工程师数量", false)],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -205,7 +266,7 @@ function OrgInfoPage(props) {
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="机构信息管理"
|
title="机构信息管理"
|
||||||
subTitle="新成立或首次使用系统的安全评价机构,可通过系统提供的引导页面,详细填写机构的基本信息。"
|
subTitle="新成立或首次使用系统的安全评价机构,可通过系统提供的引导页面,详细填写机构的基本信息。"
|
||||||
extra={!editing && (
|
extra={hasExistingData && !editing && (
|
||||||
<Button type="primary" onClick={() => setEditing(true)}>
|
<Button type="primary" onClick={() => setEditing(true)}>
|
||||||
修改
|
修改
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -215,6 +276,7 @@ function OrgInfoPage(props) {
|
||||||
form={form}
|
form={form}
|
||||||
span={12}
|
span={12}
|
||||||
disabled={!editing}
|
disabled={!editing}
|
||||||
|
useAutoGenerateRequired={false}
|
||||||
options={formOptions}
|
options={formOptions}
|
||||||
labelCol={{ span: 10 }}
|
labelCol={{ span: 10 }}
|
||||||
showActionButtons={false}
|
showActionButtons={false}
|
||||||
|
|
@ -222,22 +284,14 @@ function OrgInfoPage(props) {
|
||||||
{editing && (
|
{editing && (
|
||||||
<div style={{ marginTop: 24, textAlign: "center" }}>
|
<div style={{ marginTop: 24, textAlign: "center" }}>
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button onClick={handleCancelEdit}>
|
||||||
onClick={() => {
|
|
||||||
if (detail && Object.keys(detail).length) {
|
|
||||||
form.setFieldsValue(detail);
|
|
||||||
setEditing(false);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
form.resetFields();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button loading={submitting} onClick={() => handleSave("draft")}>
|
{!hasExistingData && (
|
||||||
暂存
|
<Button loading={submitting} onClick={() => handleSave("draft")}>
|
||||||
</Button>
|
暂存
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<Button type="primary" loading={submitting} onClick={() => handleSave("submit")}>
|
<Button type="primary" loading={submitting} onClick={() => handleSave("submit")}>
|
||||||
提交
|
提交
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,8 @@ export function longitudeRule(required = false) {
|
||||||
if (value === undefined || value === null || value === "") {
|
if (value === undefined || value === null || value === "") {
|
||||||
return required ? Promise.reject(new Error("请输入经度")) : Promise.resolve();
|
return required ? Promise.reject(new Error("请输入经度")) : Promise.resolve();
|
||||||
}
|
}
|
||||||
const str = String(value).trim();
|
const num = Number(value);
|
||||||
if (!LONGITUDE_PATTERN.test(str)) {
|
if (Number.isNaN(num) || num < -180 || num > 180) {
|
||||||
return Promise.reject(new Error("经度格式不正确(-180 ~ 180)"));
|
return Promise.reject(new Error("经度格式不正确(-180 ~ 180)"));
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
@ -108,8 +108,8 @@ export function latitudeRule(required = false) {
|
||||||
if (value === undefined || value === null || value === "") {
|
if (value === undefined || value === null || value === "") {
|
||||||
return required ? Promise.reject(new Error("请输入纬度")) : Promise.resolve();
|
return required ? Promise.reject(new Error("请输入纬度")) : Promise.resolve();
|
||||||
}
|
}
|
||||||
const str = String(value).trim();
|
const num = Number(value);
|
||||||
if (!LATITUDE_PATTERN.test(str)) {
|
if (Number.isNaN(num) || num < -90 || num > 90) {
|
||||||
return Promise.reject(new Error("纬度格式不正确(-90 ~ 90)"));
|
return Promise.reject(new Error("纬度格式不正确(-90 ~ 90)"));
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
@ -148,6 +148,23 @@ export function positiveNumberRule(label, required = false) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 非负整数(人员数量等) */
|
||||||
|
export function nonNegativeIntegerRule(label, required = false) {
|
||||||
|
return {
|
||||||
|
required,
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (value === undefined || value === null || value === "") {
|
||||||
|
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
|
||||||
|
}
|
||||||
|
const num = Number(value);
|
||||||
|
if (!Number.isInteger(num) || num < 0) {
|
||||||
|
return Promise.reject(new Error(`${label}应为非负整数`));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function dateRangeRule(label = "证书有效期") {
|
export function dateRangeRule(label = "证书有效期") {
|
||||||
return {
|
return {
|
||||||
validator: (_, value) => {
|
validator: (_, value) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue