bug修护

dev_1.0.1
huwei 2026-07-09 09:43:00 +08:00
parent f3d9291fdb
commit 213224cf83
3 changed files with 114 additions and 22 deletions

View File

@ -10,6 +10,7 @@ import {
} from "~/enumerate/enterpriseOptions"; } from "~/enumerate/enterpriseOptions";
import { formSelectField } from "~/utils/enterpriseForm"; import { formSelectField } from "~/utils/enterpriseForm";
import { import {
coordinatePairRule,
creditCodeRule, creditCodeRule,
latitudeRule, latitudeRule,
longitudeRule, longitudeRule,
@ -61,7 +62,11 @@ export function buildOrgInfoFormOptions() {
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER, render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
useConstraints: false, useConstraints: false,
componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 }, componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 },
rules: [longitudeRule(false)], dependencies: ["latitude"],
rules: [
longitudeRule(false),
coordinatePairRule("latitude", "经度", "纬度"),
],
}, },
{ {
name: "latitude", name: "latitude",
@ -69,7 +74,11 @@ export function buildOrgInfoFormOptions() {
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER, render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
useConstraints: false, useConstraints: false,
componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 }, componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 },
rules: [latitudeRule(false)], dependencies: ["longitude"],
rules: [
latitudeRule(false),
coordinatePairRule("longitude", "纬度", "经度"),
],
}, },
{ {
name: "registerAddress", name: "registerAddress",

View File

@ -27,10 +27,12 @@ import {
import { NS_ORG_INFO } from "~/enumerate/namespace"; import { NS_ORG_INFO } from "~/enumerate/namespace";
import { mockUploadFileList } from "~/utils/mockUpload"; import { mockUploadFileList } from "~/utils/mockUpload";
import { import {
coordinatePairRule,
creditCodeRule, creditCodeRule,
latitudeRule, latitudeRule,
longitudeRule, longitudeRule,
nonNegativeIntegerRule, nonNegativeIntegerRule,
normalizeUrl,
phoneRule, phoneRule,
positiveNumberRule, positiveNumberRule,
urlRule, urlRule,
@ -89,6 +91,9 @@ function OrgInfoPage(props) {
? dayjs(formValues.productionDate).format("YYYY-MM-DD") ? dayjs(formValues.productionDate).format("YYYY-MM-DD")
: undefined, : undefined,
attachmentUrls: formValues.attachmentUrls? JSON.stringify(formValues.attachmentUrls) :null, attachmentUrls: formValues.attachmentUrls? JSON.stringify(formValues.attachmentUrls) :null,
infoDisclosureUrl: formValues.infoDisclosureUrl
? normalizeUrl(formValues.infoDisclosureUrl)
: undefined,
authStatusCode: submitType === "draft" ? 0 : 1, authStatusCode: submitType === "draft" ? 0 : 1,
authStatusName: submitType === "draft" ? "草稿" : "已提交", authStatusName: submitType === "draft" ? "草稿" : "已提交",
}; };
@ -205,7 +210,11 @@ function OrgInfoPage(props) {
<Form.Item <Form.Item
name="longitude" name="longitude"
label="所在地坐标经度" label="所在地坐标经度"
rules={[longitudeRule(false)]} dependencies={["latitude"]}
rules={[
longitudeRule(false),
coordinatePairRule("latitude", "经度", "纬度"),
]}
> >
<InputNumber <InputNumber
style={{ width: "100%" }} style={{ width: "100%" }}
@ -220,7 +229,11 @@ function OrgInfoPage(props) {
<Form.Item <Form.Item
name="latitude" name="latitude"
label="所在地坐标纬度" label="所在地坐标纬度"
rules={[latitudeRule(false)]} dependencies={["longitude"]}
rules={[
latitudeRule(false),
coordinatePairRule("longitude", "纬度", "经度"),
]}
> >
<InputNumber <InputNumber
style={{ width: "100%" }} style={{ width: "100%" }}
@ -276,6 +289,7 @@ function OrgInfoPage(props) {
name="legalRepresentativePhone" name="legalRepresentativePhone"
label="法定代表人联系电话" label="法定代表人联系电话"
rules={[phoneRule("法定代表人联系电话", false)]} rules={[phoneRule("法定代表人联系电话", false)]}
normalize={(value) => (typeof value === "string" ? value.trim() : value)}
> >
<Input placeholder="请输入法定代表人联系电话" allowClear /> <Input placeholder="请输入法定代表人联系电话" allowClear />
</Form.Item> </Form.Item>
@ -294,6 +308,7 @@ function OrgInfoPage(props) {
name="principalPhone" name="principalPhone"
label="主要负责人联系电话" label="主要负责人联系电话"
rules={[phoneRule("主要负责人联系电话", true)]} rules={[phoneRule("主要负责人联系电话", true)]}
normalize={(value) => (typeof value === "string" ? value.trim() : value)}
> >
<Input placeholder="请输入主要负责人联系电话" allowClear /> <Input placeholder="请输入主要负责人联系电话" allowClear />
</Form.Item> </Form.Item>
@ -308,6 +323,7 @@ function OrgInfoPage(props) {
name="safetyDeptManagerPhone" name="safetyDeptManagerPhone"
label="安全管理部门负责人联系电话" label="安全管理部门负责人联系电话"
rules={[phoneRule("安全管理部门负责人联系电话", false)]} rules={[phoneRule("安全管理部门负责人联系电话", false)]}
normalize={(value) => (typeof value === "string" ? value.trim() : value)}
> >
<Input <Input
placeholder="请输入安全管理部门负责人联系电话" placeholder="请输入安全管理部门负责人联系电话"
@ -325,6 +341,7 @@ function OrgInfoPage(props) {
name="safetyDeputyPhone" name="safetyDeputyPhone"
label="主管安全副总联系电话" label="主管安全副总联系电话"
rules={[phoneRule("主管安全副总联系电话", false)]} rules={[phoneRule("主管安全副总联系电话", false)]}
normalize={(value) => (typeof value === "string" ? value.trim() : value)}
> >
<Input placeholder="请输入主管安全副总联系电话" allowClear /> <Input placeholder="请输入主管安全副总联系电话" allowClear />
</Form.Item> </Form.Item>
@ -347,6 +364,7 @@ function OrgInfoPage(props) {
name="infoDisclosureUrl" name="infoDisclosureUrl"
label="信息公开网址" label="信息公开网址"
rules={[urlRule("信息公开网址", false)]} rules={[urlRule("信息公开网址", false)]}
normalize={(value) => (typeof value === "string" ? value.trim() : value)}
> >
<Input placeholder="请输入信息公开网址" allowClear /> <Input placeholder="请输入信息公开网址" allowClear />
</Form.Item> </Form.Item>

View File

@ -7,8 +7,8 @@ export const ID_CARD_PATTERN = /^\d{17}[\dX]$/i;
/** 手机号 */ /** 手机号 */
export const MOBILE_PHONE_PATTERN = /^1[3-9]\d{9}$/; export const MOBILE_PHONE_PATTERN = /^1[3-9]\d{9}$/;
/** 固话或手机 */ /** 固话或手机(去格式符后:手机 11 位 / 固话 10~12 位) */
export const PHONE_PATTERN = /^(\d{3,4}-?\d{7,8}|1[3-9]\d{9})$/; export const PHONE_PATTERN = /^(1[3-9]\d{9}|\d{10,12})$/;
/** 经度 */ /** 经度 */
export const LONGITUDE_PATTERN = /^-?((1[0-7]\d)|(\d{1,2}))(\.\d+)?$|^180(\.0+)?$/; export const LONGITUDE_PATTERN = /^-?((1[0-7]\d)|(\d{1,2}))(\.\d+)?$|^180(\.0+)?$/;
@ -16,21 +16,48 @@ export const LONGITUDE_PATTERN = /^-?((1[0-7]\d)|(\d{1,2}))(\.\d+)?$|^180(\.0+)?
/** 纬度 */ /** 纬度 */
export const LATITUDE_PATTERN = /^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/; export const LATITUDE_PATTERN = /^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$/;
/** URL */ /** URL需含协议或合法域名 */
export const URL_PATTERN = /^(https?:\/\/)[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]*$/; export const URL_PATTERN = /^(https?:\/\/)([\w-]+\.)+[\w-]+([\w\-._~:/?#[\]@!$&'()*+,;=.]*)?$/i;
const FORMAT_VALIDATE_TRIGGER = ["onBlur", "onChange"];
function isEmptyValue(value) {
return value === undefined || value === null || value === "";
}
/** 电话去空格、括号、横线,并剥离 +86 前缀 */
export function normalizePhone(value) {
return String(value).replace(/[\s()-]/g, "").replace(/^(\+?86)/, "");
}
/** URL 补全协议后校验 */
export function normalizeUrl(value) {
const trimmed = String(value).trim();
if (!trimmed) {
return "";
}
return /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
}
function hasTooManyDecimals(value, maxDecimals = 6) {
const str = String(value);
const dotIndex = str.indexOf(".");
if (dotIndex === -1) {
return false;
}
return str.slice(dotIndex + 1).length > maxDecimals;
}
export function creditCodeRule(required = true) { export function creditCodeRule(required = true) {
return { return {
required, required,
message: required ? "请输入统一社会信用代码" : undefined, validateTrigger: FORMAT_VALIDATE_TRIGGER,
pattern: CREDIT_CODE_PATTERN,
...(required ? {} : { validateTrigger: "onBlur" }),
validator: (_, value) => { validator: (_, value) => {
if (!value) { if (!value) {
return required ? Promise.reject(new Error("请输入统一社会信用代码")) : Promise.resolve(); return required ? Promise.reject(new Error("请输入统一社会信用代码")) : Promise.resolve();
} }
if (!CREDIT_CODE_PATTERN.test(value.trim())) { if (!CREDIT_CODE_PATTERN.test(String(value).trim().toUpperCase())) {
return Promise.reject(new Error("统一社会信用代码格式不正确")); return Promise.reject(new Error("统一社会信用代码格式不正确18位"));
} }
return Promise.resolve(); return Promise.resolve();
}, },
@ -56,13 +83,15 @@ export function idCardRule(required = true) {
export function phoneRule(label = "联系电话", required = true) { export function phoneRule(label = "联系电话", required = true) {
return { return {
required, required,
validateTrigger: FORMAT_VALIDATE_TRIGGER,
whitespace: true,
validator: (_, value) => { validator: (_, value) => {
if (!value) { if (!value || !String(value).trim()) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve(); return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
} }
const str = String(value).replace(/\s+/g, ""); const normalized = normalizePhone(value);
if (!PHONE_PATTERN.test(str)) { if (!PHONE_PATTERN.test(normalized)) {
return Promise.reject(new Error(`${label}格式不正确`)); return Promise.reject(new Error(`${label}格式不正确手机11位或固话区号+号码)`));
} }
return Promise.resolve(); return Promise.resolve();
}, },
@ -88,14 +117,18 @@ export function mobileRule(label = "账号", required = true) {
export function longitudeRule(required = false) { export function longitudeRule(required = false) {
return { return {
required, required,
validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => { validator: (_, value) => {
if (value === undefined || value === null || value === "") { if (isEmptyValue(value)) {
return required ? Promise.reject(new Error("请输入经度")) : Promise.resolve(); return required ? Promise.reject(new Error("请输入经度")) : Promise.resolve();
} }
const num = Number(value); const num = Number(value);
if (Number.isNaN(num) || num < -180 || num > 180) { if (Number.isNaN(num) || num < -180 || num > 180) {
return Promise.reject(new Error("经度格式不正确(-180 ~ 180")); return Promise.reject(new Error("经度格式不正确(-180 ~ 180"));
} }
if (hasTooManyDecimals(value)) {
return Promise.reject(new Error("经度最多保留6位小数"));
}
return Promise.resolve(); return Promise.resolve();
}, },
}; };
@ -104,28 +137,60 @@ export function longitudeRule(required = false) {
export function latitudeRule(required = false) { export function latitudeRule(required = false) {
return { return {
required, required,
validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => { validator: (_, value) => {
if (value === undefined || value === null || value === "") { if (isEmptyValue(value)) {
return required ? Promise.reject(new Error("请输入纬度")) : Promise.resolve(); return required ? Promise.reject(new Error("请输入纬度")) : Promise.resolve();
} }
const num = Number(value); const num = Number(value);
if (Number.isNaN(num) || num < -90 || num > 90) { if (Number.isNaN(num) || num < -90 || num > 90) {
return Promise.reject(new Error("纬度格式不正确(-90 ~ 90")); return Promise.reject(new Error("纬度格式不正确(-90 ~ 90"));
} }
if (hasTooManyDecimals(value)) {
return Promise.reject(new Error("纬度最多保留6位小数"));
}
return Promise.resolve(); return Promise.resolve();
}, },
}; };
} }
/** 经纬度成对填写:填了其中一个则另一个必填 */
export function coordinatePairRule(peerField, selfLabel, peerLabel) {
return ({ getFieldValue }) => ({
validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => {
const peerValue = getFieldValue(peerField);
const hasSelf = !isEmptyValue(value);
const hasPeer = !isEmptyValue(peerValue);
if (hasSelf && !hasPeer) {
return Promise.reject(new Error(`请同时填写${peerLabel}`));
}
if (!hasSelf && hasPeer) {
return Promise.reject(new Error(`请填写${selfLabel}`));
}
return Promise.resolve();
},
});
}
export function urlRule(label = "网址", required = false) { export function urlRule(label = "网址", required = false) {
return { return {
required, required,
validateTrigger: FORMAT_VALIDATE_TRIGGER,
whitespace: true,
validator: (_, value) => { validator: (_, value) => {
if (!value) { if (!value || !String(value).trim()) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve(); return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
} }
if (!URL_PATTERN.test(String(value).trim())) { const normalized = normalizeUrl(value);
return Promise.reject(new Error(`${label}格式不正确`)); if (!URL_PATTERN.test(normalized)) {
return Promise.reject(new Error(`${label}格式不正确(如 https://example.com`));
}
try {
// eslint-disable-next-line no-new
new URL(normalized);
} catch {
return Promise.reject(new Error(`${label}格式不正确(如 https://example.com`));
} }
return Promise.resolve(); return Promise.resolve();
}, },