diff --git a/jjb.config.js b/jjb.config.js index 8a02c16..7474445 100644 --- a/jjb.config.js +++ b/jjb.config.js @@ -10,7 +10,7 @@ module.exports = { javaGitBranch: "", // 本地联调 safetyEval-service(context-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: { // 应用后端分支名称,部署上线需要 diff --git a/src/api/register/index.js b/src/api/register/index.js index 1c3b8de..1c648bf 100644 --- a/src/api/register/index.js +++ b/src/api/register/index.js @@ -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" +); \ No newline at end of file diff --git a/src/components/AttachmentUpload/index.js b/src/components/AttachmentUpload/index.js new file mode 100644 index 0000000..0b4947a --- /dev/null +++ b/src/components/AttachmentUpload/index.js @@ -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 ( + <> + { + + 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, + })) || [] + ); + }} + > + { + if (isImage(file.url || file.thumbUrl)) { + setPreviewImage(file.url || file.thumbUrl); + } else { + window.open(file.url || file.thumbUrl); + } + }} + > + + + + { + if (!visible) setPreviewImage(""); + }, + }} + /> + + ); +} diff --git a/src/enumerate/enterpriseOptions.js b/src/enumerate/enterpriseOptions.js new file mode 100644 index 0000000..2b2c127 --- /dev/null +++ b/src/enumerate/enterpriseOptions.js @@ -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: "未备案" }, +]; + +/** 监管端机构账号状态(后端 state:0=启用,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 }, +]; diff --git a/src/enumerate/img/audit.png b/src/enumerate/img/audit.png new file mode 100644 index 0000000..b251bb6 Binary files /dev/null and b/src/enumerate/img/audit.png differ diff --git a/src/enumerate/img/auditLook.png b/src/enumerate/img/auditLook.png new file mode 100644 index 0000000..4491a10 Binary files /dev/null and b/src/enumerate/img/auditLook.png differ diff --git a/src/enumerate/img/header.png b/src/enumerate/img/header.png new file mode 100644 index 0000000..f899f7b Binary files /dev/null and b/src/enumerate/img/header.png differ diff --git a/src/enumerate/img/left-img.jpg b/src/enumerate/img/left-img.jpg new file mode 100644 index 0000000..8855293 Binary files /dev/null and b/src/enumerate/img/left-img.jpg differ diff --git a/src/enumerate/img/loginbg.jpg b/src/enumerate/img/loginbg.jpg new file mode 100644 index 0000000..017d3f6 Binary files /dev/null and b/src/enumerate/img/loginbg.jpg differ diff --git a/src/enumerate/img/logo.png b/src/enumerate/img/logo.png new file mode 100644 index 0000000..7707377 Binary files /dev/null and b/src/enumerate/img/logo.png differ diff --git a/src/enumerate/img/successIcon.png b/src/enumerate/img/successIcon.png new file mode 100644 index 0000000..9fbbe08 Binary files /dev/null and b/src/enumerate/img/successIcon.png differ diff --git a/src/pages/Container/Register/index.js b/src/pages/Container/Register/index.js index 852b69c..924f87d 100644 --- a/src/pages/Container/Register/index.js +++ b/src/pages/Container/Register/index.js @@ -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 ( -
+
- - - - - - - + logo - 巫溪县安全评价在线监管一件事 + 重庆市安全评价在线监管一件事 安全评价机构服务系统
-
- - - - - - - - - - - - - - - - - - - - - - -
安全评价机构服务系统
-
创造更值得信赖的世界
+
+
@@ -314,7 +172,7 @@ function Register({ sendMessageAction, registerAction, registerLoading }) { loading={registerLoading} onClick={() => window.location.href = "https://gbs-gateway.qhdsafety.com/login/client/72cf4f659dc54dcfaeecd32eabf483b5"} > - 登录 + 去登录 diff --git a/src/pages/Container/Register/index.less b/src/pages/Container/Register/index.less index dbdb8aa..3d33265 100644 --- a/src/pages/Container/Register/index.less +++ b/src/pages/Container/Register/index.less @@ -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; diff --git a/src/pages/Container/RegisterMore/index.js b/src/pages/Container/RegisterMore/index.js new file mode 100644 index 0000000..988d81a --- /dev/null +++ b/src/pages/Container/RegisterMore/index.js @@ -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 ( +
+
+ +
+
认证信息
+
+
+
+ + + + {current === 0 && ( +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + {/* */} + + + + +
+ )} + {current === 1 && ( +
+ +
+ +
+
认证审核中,请耐心等待···
+
+
+ )} + {current === 2 && ( +
+ + +
审核通过
+
+
+ )} +
+
+ ); +}; + +export default Connect([NS_REGISTER], true)(RegisterMore); diff --git a/src/pages/Container/RegisterMore/index.less b/src/pages/Container/RegisterMore/index.less new file mode 100644 index 0000000..ea874ad --- /dev/null +++ b/src/pages/Container/RegisterMore/index.less @@ -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; + } +} diff --git a/src/utils/validators.js b/src/utils/validators.js new file mode 100644 index 0000000..78351f4 --- /dev/null +++ b/src/utils/validators.js @@ -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(); + }, + }; +}