From 213224cf83feb99e966d29a0e0baa8b42840e9cc Mon Sep 17 00:00:00 2001
From: huwei <3313749341@qq.com>
Date: Thu, 9 Jul 2026 09:43:00 +0800
Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E6=8A=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../EnterpriseInfo/OrgInfo/formOptions.js | 13 ++-
.../Container/EnterpriseInfo/OrgInfo/index.js | 22 +++-
src/utils/validators.js | 101 ++++++++++++++----
3 files changed, 114 insertions(+), 22 deletions(-)
diff --git a/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js b/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
index 77e1843..62d070a 100644
--- a/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
+++ b/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
@@ -10,6 +10,7 @@ import {
} from "~/enumerate/enterpriseOptions";
import { formSelectField } from "~/utils/enterpriseForm";
import {
+ coordinatePairRule,
creditCodeRule,
latitudeRule,
longitudeRule,
@@ -61,7 +62,11 @@ export function buildOrgInfoFormOptions() {
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
useConstraints: false,
componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 },
- rules: [longitudeRule(false)],
+ dependencies: ["latitude"],
+ rules: [
+ longitudeRule(false),
+ coordinatePairRule("latitude", "经度", "纬度"),
+ ],
},
{
name: "latitude",
@@ -69,7 +74,11 @@ export function buildOrgInfoFormOptions() {
render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
useConstraints: false,
componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 },
- rules: [latitudeRule(false)],
+ dependencies: ["longitude"],
+ rules: [
+ latitudeRule(false),
+ coordinatePairRule("longitude", "纬度", "经度"),
+ ],
},
{
name: "registerAddress",
diff --git a/src/pages/Container/EnterpriseInfo/OrgInfo/index.js b/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
index c970826..e16b250 100644
--- a/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
+++ b/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
@@ -27,10 +27,12 @@ import {
import { NS_ORG_INFO } from "~/enumerate/namespace";
import { mockUploadFileList } from "~/utils/mockUpload";
import {
+ coordinatePairRule,
creditCodeRule,
latitudeRule,
longitudeRule,
nonNegativeIntegerRule,
+ normalizeUrl,
phoneRule,
positiveNumberRule,
urlRule,
@@ -89,6 +91,9 @@ function OrgInfoPage(props) {
? dayjs(formValues.productionDate).format("YYYY-MM-DD")
: undefined,
attachmentUrls: formValues.attachmentUrls? JSON.stringify(formValues.attachmentUrls) :null,
+ infoDisclosureUrl: formValues.infoDisclosureUrl
+ ? normalizeUrl(formValues.infoDisclosureUrl)
+ : undefined,
authStatusCode: submitType === "draft" ? 0 : 1,
authStatusName: submitType === "draft" ? "草稿" : "已提交",
};
@@ -205,7 +210,11 @@ function OrgInfoPage(props) {
(typeof value === "string" ? value.trim() : value)}
>
@@ -294,6 +308,7 @@ function OrgInfoPage(props) {
name="principalPhone"
label="主要负责人联系电话"
rules={[phoneRule("主要负责人联系电话", true)]}
+ normalize={(value) => (typeof value === "string" ? value.trim() : value)}
>
@@ -308,6 +323,7 @@ function OrgInfoPage(props) {
name="safetyDeptManagerPhone"
label="安全管理部门负责人联系电话"
rules={[phoneRule("安全管理部门负责人联系电话", false)]}
+ normalize={(value) => (typeof value === "string" ? value.trim() : value)}
>
(typeof value === "string" ? value.trim() : value)}
>
@@ -347,6 +364,7 @@ function OrgInfoPage(props) {
name="infoDisclosureUrl"
label="信息公开网址"
rules={[urlRule("信息公开网址", false)]}
+ normalize={(value) => (typeof value === "string" ? value.trim() : value)}
>
diff --git a/src/utils/validators.js b/src/utils/validators.js
index 78351f4..fa90501 100644
--- a/src/utils/validators.js
+++ b/src/utils/validators.js
@@ -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 PHONE_PATTERN = /^(\d{3,4}-?\d{7,8}|1[3-9]\d{9})$/;
+/** 固话或手机(去格式符后:手机 11 位 / 固话 10~12 位) */
+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+)?$/;
@@ -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+)?)$/;
-/** URL */
-export const URL_PATTERN = /^(https?:\/\/)[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]*$/;
+/** URL(需含协议或合法域名) */
+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) {
return {
required,
- message: required ? "请输入统一社会信用代码" : undefined,
- pattern: CREDIT_CODE_PATTERN,
- ...(required ? {} : { validateTrigger: "onBlur" }),
+ validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => {
if (!value) {
return required ? Promise.reject(new Error("请输入统一社会信用代码")) : Promise.resolve();
}
- if (!CREDIT_CODE_PATTERN.test(value.trim())) {
- return Promise.reject(new Error("统一社会信用代码格式不正确"));
+ if (!CREDIT_CODE_PATTERN.test(String(value).trim().toUpperCase())) {
+ return Promise.reject(new Error("统一社会信用代码格式不正确(18位)"));
}
return Promise.resolve();
},
@@ -56,13 +83,15 @@ export function idCardRule(required = true) {
export function phoneRule(label = "联系电话", required = true) {
return {
required,
+ validateTrigger: FORMAT_VALIDATE_TRIGGER,
+ whitespace: true,
validator: (_, value) => {
- if (!value) {
+ if (!value || !String(value).trim()) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
}
- const str = String(value).replace(/\s+/g, "");
- if (!PHONE_PATTERN.test(str)) {
- return Promise.reject(new Error(`${label}格式不正确`));
+ const normalized = normalizePhone(value);
+ if (!PHONE_PATTERN.test(normalized)) {
+ return Promise.reject(new Error(`${label}格式不正确(手机11位或固话区号+号码)`));
}
return Promise.resolve();
},
@@ -88,14 +117,18 @@ export function mobileRule(label = "账号", required = true) {
export function longitudeRule(required = false) {
return {
required,
+ validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => {
- if (value === undefined || value === null || value === "") {
+ if (isEmptyValue(value)) {
return required ? Promise.reject(new Error("请输入经度")) : Promise.resolve();
}
const num = Number(value);
if (Number.isNaN(num) || num < -180 || num > 180) {
return Promise.reject(new Error("经度格式不正确(-180 ~ 180)"));
}
+ if (hasTooManyDecimals(value)) {
+ return Promise.reject(new Error("经度最多保留6位小数"));
+ }
return Promise.resolve();
},
};
@@ -104,28 +137,60 @@ export function longitudeRule(required = false) {
export function latitudeRule(required = false) {
return {
required,
+ validateTrigger: FORMAT_VALIDATE_TRIGGER,
validator: (_, value) => {
- if (value === undefined || value === null || value === "") {
+ if (isEmptyValue(value)) {
return required ? Promise.reject(new Error("请输入纬度")) : Promise.resolve();
}
const num = Number(value);
if (Number.isNaN(num) || num < -90 || num > 90) {
return Promise.reject(new Error("纬度格式不正确(-90 ~ 90)"));
}
+ if (hasTooManyDecimals(value)) {
+ return Promise.reject(new Error("纬度最多保留6位小数"));
+ }
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) {
return {
required,
+ validateTrigger: FORMAT_VALIDATE_TRIGGER,
+ whitespace: true,
validator: (_, value) => {
- if (!value) {
+ if (!value || !String(value).trim()) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
}
- if (!URL_PATTERN.test(String(value).trim())) {
- return Promise.reject(new Error(`${label}格式不正确`));
+ const normalized = normalizeUrl(value);
+ 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();
},