master
tangjie 2026-07-06 16:22:59 +08:00
parent 995843f342
commit a495d366f2
16 changed files with 934 additions and 157 deletions

View File

@ -10,7 +10,7 @@ module.exports = {
javaGitBranch: "<branch-name>",
// 本地联调 safetyEval-servicecontext-path: /safetyEval默认端口 8095
// 可通过环境变量覆盖: SAFETY_EVAL_API_HOST=http://192.168.x.x:8095
API_HOST: "http://192.168.0.149",
API_HOST: "http://192.168.0.152",
},
production: {
// 应用后端分支名称,部署上线需要

View File

@ -11,3 +11,15 @@ export const registerAction = declareRequest(
"registerLoading",
"Post > @/account/save"
);
export const orgInfoSave = declareRequest(
"registerLoading",
"Post > @/safetyEval/org-info/save"
);
export const syncUserToGBS = declareRequest(
"syncUserToGBSLoading",
"Post > @/safetyEval/account/syncUserToGBS"
);

View File

@ -0,0 +1,77 @@
import { Form, Image, Upload } from "antd";
import { useState } from "react";
import { PlusOutlined } from "@ant-design/icons";
const isImage = (url) =>
/\.(png|jpe?g|gif|bmp|webp|svg)(\?.*)?$/i.test(url || "");
export default function AttachmentUpload({ name, label, disabled = false, maxCount, accept }) {
const [previewImage, setPreviewImage] = useState("");
return (
<>
<Form.Item
name={name}
label={label}
valuePropName="fileList"
getValueProps={(value) => {
if (Array.isArray(value)) {
return { fileList: value };
}
return {
fileList: value
? value.split(",").map((item) => ({
url: item,
uid: item,
status: "done",
name: "附件",
}))
: [],
};
}}
getValueFromEvent={({ fileList }) => {
return (
fileList?.map((file) => ({
url: file.response?.data?.url || file.url,
uid: file.uid,
status: file.status,
name: file.name,
percent: file.percent,
})) || []
);
}}
>
<Upload
disabled={disabled}
listType="picture-card"
maxCount={maxCount}
accept={accept}
action={`${window.process.env.app.API_HOST}/safetyEval/file/upload`}
onPreview={(file) => {
if (isImage(file.url || file.thumbUrl)) {
setPreviewImage(file.url || file.thumbUrl);
} else {
window.open(file.url || file.thumbUrl);
}
}}
>
<button style={{ border: 0, background: "none" }} type="button">
<PlusOutlined />
<div style={{ marginTop: 8 }}>上传附件</div>
</button>
</Upload>
</Form.Item>
<Image
style={{ display: "none" }}
preview={{
visible: !!previewImage,
src: previewImage,
onVisibleChange: (visible) => {
if (!visible) setPreviewImage("");
},
}}
/>
</>
);
}

View File

@ -0,0 +1,112 @@
/** 企业信息管理模块下拉选项 */
/** 重庆市辖区(区/县) */
export const CHONGQING_DISTRICTS = [
"万州区", "涪陵区", "渝中区", "大渡口区", "江北区", "沙坪坝区", "九龙坡区", "南岸区",
"北碚区", "綦江区", "大足区", "渝北区", "巴南区", "黔江区", "长寿区", "江津区",
"合川区", "永川区", "南川区", "璧山区", "铜梁区", "潼南区", "荣昌区", "开州区",
"梁平区", "武隆区", "城口县", "丰都县", "垫江县", "忠县", "云阳县", "奉节县",
"巫山县", "巫溪县", "石柱土家族自治县", "秀山土家族苗族自治县", "酉阳土家族苗族自治县",
"彭水苗族土家族自治县",
].map((label) => ({ label, value: label }));
/** 企业状态 */
export const ENTERPRISE_STATUS_OPTIONS = [
{ label: "正常", value: "正常" },
{ label: "停业", value: "停业" },
{ label: "注销", value: "注销" },
];
/** 企业规模 */
export const ENTERPRISE_SCALE_OPTIONS = [
{ label: "大", value: "大" },
{ label: "中", value: "中" },
{ label: "小", value: "小" },
{ label: "微型", value: "微型" },
];
/** 备案类型 */
export const FILING_TYPE_OPTIONS = [
{ label: "审核备案", value: "审核备案" },
{ label: "确认备案", value: "确认备案" },
];
/** 监管端已备案机构 - 备案类型搜索 */
export const REGISTERED_ORG_FILING_TYPE_SEARCH_OPTIONS = [
{ label: "全部", value: "" },
{ label: "审核备案", value: "1" },
{ label: "确认备案", value: "2" },
];
/** 监管端已备案机构 - 备案状态搜索1=已备案2=未备案) */
export const REGISTERED_ORG_FILING_RECORD_STATUS_OPTIONS = [
{ label: "全部", value: "" },
{ label: "已备案", value: "1" },
{ label: "未备案", value: "2" },
];
/** 备案状态(机构信息) */
export const FILING_RECORD_STATUS_OPTIONS = [
{ label: "已备案", value: "已备案" },
{ label: "未备案", value: "未备案" },
];
/** 监管端机构账号状态(后端 state0=启用1=禁用) */
export const ORG_ACCOUNT_STATE_OPTIONS = [
{ label: "全部", value: "" },
{ label: "启用", value: "0" },
{ label: "禁用", value: "1" },
];
/** 资质范围 / 证照类型(行业) */
export const QUALIFICATION_INDUSTRY_OPTIONS = [
{ label: "煤炭开采业", value: "煤炭开采业" },
{ label: "金属、非金属矿及其他矿采选业", value: "金属、非金属矿及其他矿采选业" },
{ label: "陆地石油和天然气开采业", value: "陆地石油和天然气开采业" },
{ label: "陆上油气管道运输业", value: "陆上油气管道运输业" },
{ label: "石油加工业,化学原料、化学品及医药制造业", value: "石油加工业,化学原料、化学品及医药制造业" },
{ label: "烟花爆竹制造业", value: "烟花爆竹制造业" },
{ label: "金属冶炼", value: "金属冶炼" },
];
/** 人员类型 */
export const PERSON_TYPE_OPTIONS = [
{ label: "基础人员", value: "基础人员" },
{ label: "专职评价师", value: "专职评价师" },
];
/** 职业等级 */
export const PROFESSIONAL_LEVEL_OPTIONS = [
{
label: "三级安全评价师(对应职业技能等级三级 / 高级工,入门级)",
value: "三级安全评价师(对应职业技能等级三级 / 高级工,入门级)",
},
{
label: "二级安全评价师(对应职业技能等级二级 / 技师,中级)",
value: "二级安全评价师(对应职业技能等级二级 / 技师,中级)",
},
{
label: "一级安全评价师(对应职业技能等级一级 / 高级技师,最高级)",
value: "一级安全评价师(对应职业技能等级一级 / 高级技师,最高级)",
},
];
/** 学历类型 */
export const EDUCATION_TYPE_OPTIONS = [
{ label: "全日制", value: "全日制" },
{ label: "在职教育", value: "在职教育" },
];
/** 学历层次 */
export const EDUCATION_LEVEL_OPTIONS = [
{ label: "专科", value: "专科" },
{ label: "本科", value: "本科" },
{ label: "硕士", value: "硕士" },
{ label: "博士", value: "博士" },
];
/** 是否注册安全工程师 */
export const REGISTER_ENGINEER_OPTIONS = [
{ label: "是", value: 1 },
{ label: "否", value: 2 },
];

BIN
src/enumerate/img/audit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 KiB

BIN
src/enumerate/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -8,6 +8,10 @@ import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, Input, message } from "antd";
import React, { useState } from "react";
import { NS_REGISTER } from "~/enumerate/namespace";
import loginbg from "~/enumerate/img/loginbg.jpg";
import logo from "~/enumerate/img/logo.png";
import leftIcon from "~/enumerate/img/left-img.jpg";
import "./index.less";
function Register({ sendMessageAction, registerAction, registerLoading }) {
@ -57,172 +61,26 @@ function Register({ sendMessageAction, registerAction, registerLoading }) {
};
const res = await registerAction(payload);
if (res.success) {
message.success("注册成功");
message.success("操作成功");
form.resetFields();
props.history.push(`registerMore?account=${values.account}`);
}
};
return (
<div className="register-page">
<div className="register-page" style={{ backgroundImage: `url(${loginbg})` }}>
<div className="register-top-bar">
<div className="register-top-logo">
<svg
className="register-top-icon"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="2"
y="12"
width="6"
height="18"
rx="1"
fill="#fff"
opacity="0.9"
/>
<rect
x="10"
y="6"
width="6"
height="24"
rx="1"
fill="#fff"
opacity="0.7"
/>
<rect
x="18"
y="10"
width="6"
height="20"
rx="1"
fill="#fff"
opacity="0.8"
/>
<rect
x="26"
y="4"
width="4"
height="26"
rx="1"
fill="#fff"
opacity="0.6"
/>
<path
d="M4 8 L10 2 L16 8 L22 2 L28 8"
stroke="#fff"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
opacity="0.5"
/>
</svg>
<img src={logo} alt="logo" />
<span className="register-top-title">
巫溪县安全评价在线监管一件事
重庆市安全评价在线监管一件事
</span>
<span className="register-top-subtitle">安全评价机构服务系统</span>
</div>
</div>
<div className="register-card">
<div className="register-left">
<svg
className="register-logo-icon"
viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient
id="shieldGrad"
x1="0%"
y1="0%"
x2="100%"
y2="100%"
>
<stop offset="0%" stopColor="#4a9eff" />
<stop offset="100%" stopColor="#1677ff" />
</linearGradient>
<linearGradient id="ringGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="#a8d4ff" />
<stop offset="100%" stopColor="#4a9eff" />
</linearGradient>
</defs>
<ellipse
cx="100"
cy="160"
rx="70"
ry="15"
fill="#e0e0e0"
opacity="0.4"
/>
<ellipse
cx="100"
cy="150"
rx="55"
ry="10"
fill="#c0d8f0"
opacity="0.5"
/>
<path
d="M100 45 L145 60 L145 110 Q145 140 100 160 Q55 140 55 110 L55 60 Z"
fill="url(#shieldGrad)"
opacity="0.15"
/>
<path
d="M100 50 L140 64 L140 108 Q140 136 100 154 Q60 136 60 108 L60 64 Z"
fill="url(#shieldGrad)"
opacity="0.25"
/>
<path
d="M100 55 L135 68 L135 106 Q135 132 100 148 Q65 132 65 106 L65 68 Z"
fill="url(#shieldGrad)"
/>
<path
d="M88 95 L96 105 L114 82"
stroke="#fff"
strokeWidth="5"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
/>
<ellipse
cx="100"
cy="148"
rx="45"
ry="8"
fill="none"
stroke="url(#ringGrad)"
strokeWidth="3"
/>
<ellipse
cx="100"
cy="148"
rx="35"
ry="6"
fill="none"
stroke="#a8d4ff"
strokeWidth="2"
/>
<rect
x="85"
y="155"
width="8"
height="20"
rx="2"
fill="#4a9eff"
opacity="0.6"
/>
<rect
x="107"
y="155"
width="8"
height="20"
rx="2"
fill="#4a9eff"
opacity="0.6"
/>
</svg>
<div className="register-left-title">安全评价机构服务系统</div>
<div className="register-left-subtitle">创造更值得信赖的世界</div>
<div className="register-left" >
<img src={leftIcon} className="register-left-icon" />
</div>
<div className="register-right">
@ -314,7 +172,7 @@ function Register({ sendMessageAction, registerAction, registerLoading }) {
loading={registerLoading}
onClick={() => window.location.href = "https://gbs-gateway.qhdsafety.com/login/client/72cf4f659dc54dcfaeecd32eabf483b5"}
>
登录
登录
</Button>
</Form.Item>
</Form>

View File

@ -50,13 +50,18 @@
}
.register-left {
flex: 1;
width: 460px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, #e8f4ff 0%, #d0e8ff 100%);
padding: 40px;
.register-left-icon {
width: 100%;
height: 100%;
}
.register-logo-icon {
width: 180px;

View File

@ -0,0 +1,487 @@
import React, { useEffect, useState } from "react";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { tools } from "@cqsjjb/jjb-common-lib";
import dayjs from "dayjs";
import {
Button,
Form,
Input,
message,
Steps,
Flex,
Row,
Col,
Select,
InputNumber,
DatePicker,
Space,
} from "antd";
import { NS_REGISTER } from "~/enumerate/namespace";
import AttachmentUpload from "~/components/AttachmentUpload";
import headerImage from "~/enumerate/img/header.png";
import auditLookImage from "~/enumerate/img/auditLook.png";
import auditBkImage from "~/enumerate/img/audit.png";
import successIcon from "~/enumerate/img/successIcon.png";
import {
creditCodeRule,
latitudeRule,
longitudeRule,
nonNegativeIntegerRule,
phoneRule,
positiveNumberRule,
urlRule,
} from "~/utils/validators";
import {
QUALIFICATION_INDUSTRY_OPTIONS,
ENTERPRISE_SCALE_OPTIONS,
ENTERPRISE_STATUS_OPTIONS,
FILING_RECORD_STATUS_OPTIONS,
FILING_TYPE_OPTIONS,
} from "~/enumerate/enterpriseOptions";
import "./index.less";
const {router} = tools;
const RegisterMore = (props) => {
const { orgInfoSave, register, syncUserToGBS } = props;
const [current, setCurrent] = useState(0);
const [form] = Form.useForm();
const { registerLoading, syncUserToGBSLoading } = register;
const handleSave = async (type) => {
const formValues = await form.validateFields();
const values = {
...formValues,
productionDate: formValues.productionDate
? dayjs(formValues.productionDate).format("YYYY-MM-DD")
: undefined,
attachmentUrls: formValues.attachmentUrls
? JSON.stringify(formValues.attachmentUrls)
: null,
authStatusCode: type === "draft" ? 0 : 1,
authStatusName: type === "draft" ? "草稿" : "已提交",
};
const result = await orgInfoSave(values);
if (result.success) {
const syncResult = await syncUserToGBS({account: router.query.account});
if (syncResult.success) {
message.success("保存成功");
setCurrent(1);
}
}
};
useEffect(() => {
if (current === 1) {
window.setTimeout(() => {
setCurrent(2);
}, 3000);
}
}, [current]);
return (
<div className="register-more">
<div className="register-more-header">
<img
src={headerImage}
alt=""
style={{ width: "100%", height: "100%" }}
/>
<div className="register-more-header-content">
<div className="register-more-header-title">认证信息</div>
</div>
</div>
<div className="register-more-content">
<Flex justify="center">
<Steps
style={{
width: "600px",
marginBottom: "20px",
}}
current={current}
onChange={setCurrent}
items={[
{
title: "填写信息",
},
{
title: "认证审核中",
},
{
title: "认证通过",
},
]}
/>
</Flex>
{current === 0 && (
<div>
<Form form={form} labelCol={{ span: 10 }} >
<Row gutter={[16, 16]}>
<Col span={12}>
<Form.Item
name="unitName"
label="生产经营单位名称"
rules={[
{ required: true, message: "请输入生产经营单位名称" },
]}
>
<Input placeholder="请输入生产经营单位名称" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="creditCode"
label="统一社会信用代码"
rules={[creditCodeRule(true)]}
>
<Input placeholder="请输入统一社会信用代码" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="safetyIndustryCategoryName"
label="安全生产监管行业类别"
rules={[
{ required: true, message: "请输入安全生产监管行业类别" },
]}
>
<Input
placeholder="请输入安全生产监管行业类别"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="districtName"
label="属地"
rules={[{ required: true, message: "请选择属地" }]}
>
<Select
options={QUALIFICATION_INDUSTRY_OPTIONS}
placeholder="请选择属地"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="townStreet"
label="所属镇、街道"
rules={[{ required: true, message: "请输入所属镇街道" }]}
>
<Input placeholder="请输入所属镇街道" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="villageCommunity" label="属村(社区)">
<Input placeholder="请输入属村(社区)" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="longitude"
label="所在地坐标经度"
rules={[longitudeRule(false)]}
>
<InputNumber
style={{ width: "100%" }}
min={-180}
max={180}
precision={6}
placeholder="请输入经度"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="latitude"
label="所在地坐标纬度"
rules={[latitudeRule(false)]}
>
<InputNumber
style={{ width: "100%" }}
min={-90}
max={90}
precision={6}
placeholder="请输入纬度"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="registerAddress"
label="注册地址"
rules={[{ required: true, message: "请输入注册地址" }]}
>
<Input.TextArea rows={3} placeholder="请输入注册地址" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="businessAddress"
label="经营地址"
rules={[{ required: true, message: "请输入经营地址" }]}
>
<Input.TextArea rows={3} placeholder="请输入经营地址" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="ownershipTypeName" label="归属类型">
<Input placeholder="请输入归属类型" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="economyIndustryCode"
label="国民经济行业分类(GB/T4754-2017)"
>
<Input placeholder="请输入国民经济行业分类" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="legalRepresentative"
label="法定代表人"
rules={[{ required: true, message: "请输入法定代表人" }]}
>
<Input placeholder="请输入法定代表人" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="legalRepresentativePhone"
label="法定代表人联系电话"
rules={[phoneRule("法定代表人联系电话", false)]}
>
<Input placeholder="请输入法定代表人联系电话" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="principalName"
label="主要负责人"
rules={[{ required: true, message: "请输入主要负责人" }]}
>
<Input placeholder="请输入主要负责人" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="principalPhone"
label="主要负责人联系电话"
rules={[phoneRule("主要负责人联系电话", true)]}
>
<Input placeholder="请输入主要负责人联系电话" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="safetyDeptManager"
label="安全管理部门负责人"
>
<Input placeholder="请输入安全管理部门负责人" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="safetyDeptManagerPhone"
label="安全管理部门负责人联系电话"
rules={[phoneRule("安全管理部门负责人联系电话", false)]}
>
<Input
placeholder="请输入安全管理部门负责人联系电话"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="safetyDeputyManager" label="主管安全副总">
<Input placeholder="请输入主管安全副总" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="safetyDeputyPhone"
label="主管安全副总联系电话"
rules={[phoneRule("主管安全副总联系电话", false)]}
>
<Input
placeholder="请输入主管安全副总联系电话"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="productionDate" label="投产日期">
<DatePicker
style={{ width: "100%" }}
placeholder="请选择投产日期"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="businessStatusName" label="企业经营状态">
<Input placeholder="请输入企业经营状态" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="infoDisclosureUrl"
label="信息公开网址"
rules={[urlRule("信息公开网址", false)]}
>
<Input placeholder="请输入信息公开网址" allowClear />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="workplaceArea"
label="工作场所建筑面积"
rules={[positiveNumberRule("工作场所建筑面积", false)]}
>
<InputNumber
style={{ width: "100%" }}
min={0}
precision={2}
placeholder="请输入工作场所建筑面积"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="archiveRoomArea"
label="档案室面积"
rules={[positiveNumberRule("档案室面积", false)]}
>
<InputNumber
style={{ width: "100%" }}
min={0}
precision={2}
placeholder="请输入档案室面积"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="fulltimeEvaluatorCount"
label="专职安全评价师数量"
rules={[
nonNegativeIntegerRule("专职安全评价师数量", false),
]}
>
<InputNumber
style={{ width: "100%" }}
min={0}
precision={0}
placeholder="请输入专职安全评价师数量"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="registeredEngineerCount"
label="注册安全工程师数量"
rules={[
nonNegativeIntegerRule("注册安全工程师数量", false),
]}
>
<InputNumber
style={{ width: "100%" }}
min={0}
precision={0}
placeholder="请输入注册安全工程师数量"
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="enterpriseStatusName" label="企业状态">
<Select
options={ENTERPRISE_STATUS_OPTIONS}
placeholder="请选择企业状态"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="enterpriseScaleName" label="企业规模">
<Select
options={ENTERPRISE_SCALE_OPTIONS}
placeholder="请选择企业规模"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="filingTypeName" label="备案类型">
<Select
options={FILING_TYPE_OPTIONS}
placeholder="请选择备案类型"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item name="filingRecordStatusName" label="备案状态">
<Select
options={FILING_RECORD_STATUS_OPTIONS}
placeholder="请选择备案状态"
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<AttachmentUpload name="attachmentUrls" label="上传附件" />
</Col>
</Row>
</Form>
<Flex justify="center">
<Space size={16}>
{/* <Button
loading={registerLoading || syncUserToGBSLoading}
onClick={() => handleSave("draft")}
>
暂存
</Button> */}
<Button
loading={registerLoading || syncUserToGBSLoading}
type="primary"
onClick={() => handleSave("submit")}
>
提交
</Button>
</Space>
</Flex>
</div>
)}
{current === 1 && (
<div>
<Flex justify="center" vertical align="center">
<div
className="audit-look"
style={{
backgroundImage: `url(${auditBkImage})`,
}}
>
<img src={auditLookImage} className="audit-look-img" />
</div>
<div>认证审核中请耐心等待···</div>
</Flex>
</div>
)}
{current === 2 && (
<div>
<Flex justify="center" vertical align="center">
<img src={successIcon} />
<div>审核通过</div>
</Flex>
</div>
)}
</div>
</div>
);
};
export default Connect([NS_REGISTER], true)(RegisterMore);

View File

@ -0,0 +1,48 @@
.register-more {
position: relative;
padding-bottom: 20px;
.audit-look {
background-repeat: no-repeat;
height: 175px;
width: 171px;
position: relative;
}
.audit-look-img{
position: absolute;
width: 45px;
height: 45px;
top: 50%;
left: 63%;
margin-top: -22.5px;
margin-left: -22.5px;
animation: orbit-clockwise 2s linear infinite;
}
@keyframes orbit-clockwise {
from {
transform: rotate(0deg) translateX(8px) rotate(0deg);
}
to {
transform: rotate(360deg) translateX(8px) rotate(-360deg);
}
}
.register-more-header {
height: 250px;
position: relative;
.register-more-header-content {
width: 1200px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.register-more-header-title {
font-size: 24px;
font-weight: bold;
}
}
.register-more-content {
width: 1200px;
margin: 30px auto 20px;
}
}

178
src/utils/validators.js Normal file
View File

@ -0,0 +1,178 @@
/** 统一社会信用代码18 位,不含 I/O/S/V/Z */
export const CREDIT_CODE_PATTERN = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/;
/** 18 位身份证号 */
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})$/;
/** 经度 */
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\-._~:/?#[\]@!$&'()*+,;=.]*$/;
export function creditCodeRule(required = true) {
return {
required,
message: required ? "请输入统一社会信用代码" : undefined,
pattern: CREDIT_CODE_PATTERN,
...(required ? {} : { validateTrigger: "onBlur" }),
validator: (_, value) => {
if (!value) {
return required ? Promise.reject(new Error("请输入统一社会信用代码")) : Promise.resolve();
}
if (!CREDIT_CODE_PATTERN.test(value.trim())) {
return Promise.reject(new Error("统一社会信用代码格式不正确"));
}
return Promise.resolve();
},
};
}
export function idCardRule(required = true) {
return {
required,
validator: (_, value) => {
if (!value) {
return required ? Promise.reject(new Error("请输入身份证号")) : Promise.resolve();
}
const id = String(value).trim();
if (!ID_CARD_PATTERN.test(id)) {
return Promise.reject(new Error("身份证号格式不正确"));
}
return Promise.resolve();
},
};
}
export function phoneRule(label = "联系电话", required = true) {
return {
required,
validator: (_, value) => {
if (!value) {
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}格式不正确`));
}
return Promise.resolve();
},
};
}
export function mobileRule(label = "账号", required = true) {
return {
required,
validator: (_, value) => {
if (!value) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
}
const str = String(value).replace(/\s+/g, "");
if (!MOBILE_PHONE_PATTERN.test(str)) {
return Promise.reject(new Error(`${label}应为11位手机号`));
}
return Promise.resolve();
},
};
}
export function longitudeRule(required = false) {
return {
required,
validator: (_, value) => {
if (value === undefined || value === null || 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"));
}
return Promise.resolve();
},
};
}
export function latitudeRule(required = false) {
return {
required,
validator: (_, value) => {
if (value === undefined || value === null || 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"));
}
return Promise.resolve();
},
};
}
export function urlRule(label = "网址", required = false) {
return {
required,
validator: (_, value) => {
if (!value) {
return required ? Promise.reject(new Error(`请输入${label}`)) : Promise.resolve();
}
if (!URL_PATTERN.test(String(value).trim())) {
return Promise.reject(new Error(`${label}格式不正确`));
}
return Promise.resolve();
},
};
}
export function positiveNumberRule(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.isNaN(num) || num < 0) {
return Promise.reject(new Error(`${label}应为非负数字`));
}
return Promise.resolve();
},
};
}
/** 非负整数(人员数量等) */
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 = "证书有效期") {
return {
validator: (_, value) => {
const allEmpty = Array.isArray(value) && value.every(item => item === "" || item == null);
if (allEmpty || !value || !value[0] || !value[1]) {
return Promise.reject(new Error(`请选择${label}`));
}
return Promise.resolve();
},
};
}