From e79c48cf3a6901e313195f4f96ba0528a4bb29a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B2=91=E6=BA=AA?= <1015733727@qq.com>
Date: Fri, 26 Jun 2026 17:28:06 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9B=91=E7=AE=A1=E7=AB=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/index.html | 49 ++-
src/api/enterpriseInfo/adapter.js | 160 ++++++-
src/api/enterpriseInfo/http.js | 8 +-
src/api/orgInfo/index.js | 12 +
src/api/regulatorOrgInfo/index.js | 108 +++++
src/api/staffCertificate/index.js | 18 +
src/components/FilePreviewModal/index.js | 106 +++++
src/enumerate/enterpriseOptions.js | 21 +
src/main.js | 9 +-
src/mock/regulator/basicInfo.js | 391 ++++++++++++++++++
src/mock/regulator/institution.js | 363 ++++++++++++++++
.../EnterpriseInfo/OrgInfo/formOptions.js | 198 +++++++++
.../Container/EnterpriseInfo/OrgInfo/index.js | 197 +--------
.../PersonnelInfo/List/index.js | 82 +---
.../PersonnelInfo/StaffViewModal.js | 220 ++++++++++
src/pages/Container/Layout/menuConfig.js | 29 ++
.../BasicInfo/EnterprisePortrait/index.js | 205 +++++++++
.../BasicInfo/EvaluatorInfo/index.js | 208 ++++++++++
.../Supervision/BasicInfo/OrgAccount/index.js | 346 ++++++++++++++++
.../BasicInfo/RegisteredOrg/Detail/index.js | 274 ++++++++++++
.../BasicInfo/RegisteredOrg/List/index.js | 101 +++++
.../BasicInfo/RegisteredOrg/index.js | 5 +
.../Container/Supervision/BasicInfo/index.js | 5 +
src/utils/dateFormat.js | 33 +-
24 files changed, 2864 insertions(+), 284 deletions(-)
create mode 100644 src/api/regulatorOrgInfo/index.js
create mode 100644 src/components/FilePreviewModal/index.js
create mode 100644 src/mock/regulator/basicInfo.js
create mode 100644 src/mock/regulator/institution.js
create mode 100644 src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
create mode 100644 src/pages/Container/EnterpriseInfo/PersonnelInfo/StaffViewModal.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/EnterprisePortrait/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/EvaluatorInfo/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/RegisteredOrg/Detail/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/RegisteredOrg/List/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/RegisteredOrg/index.js
create mode 100644 src/pages/Container/Supervision/BasicInfo/index.js
diff --git a/public/index.html b/public/index.html
index bb7e4c9..1a8b3ef 100644
--- a/public/index.html
+++ b/public/index.html
@@ -27,7 +27,14 @@
basename: '<%= $basename %>',
API_HOST: '<%= $API_HOST %>'
};
- APP_ENV.API_HOST = sessionStorage.API_HOST || APP_ENV.API_HOST || window.location.origin;
+ const injectedApiHost = APP_ENV.API_HOST;
+ const isDev = '<%= $mode %>' === 'development';
+ // 开发环境优先 jjb.config 注入的 API_HOST,避免 sessionStorage 残留网关地址导致 Network Error
+ if (isDev && injectedApiHost && injectedApiHost.indexOf('http') === 0) {
+ APP_ENV.API_HOST = injectedApiHost;
+ } else {
+ APP_ENV.API_HOST = sessionStorage.API_HOST || injectedApiHost || window.location.origin;
+ }
window.process = {
env: { app: APP_ENV },
NODE_ENV: '<%= $mode %>'
@@ -38,6 +45,46 @@
FRAMEWORK: APP_ENV.antd
};
})();
+
+ // 抑制 ResizeObserver 在页面/标签切换时的无害告警,避免 dev overlay 误报
+ (function () {
+ if (typeof window.ResizeObserver !== 'undefined') {
+ var NativeResizeObserver = window.ResizeObserver;
+ window.ResizeObserver = class extends NativeResizeObserver {
+ constructor(callback) {
+ super(function (entries, observer) {
+ window.requestAnimationFrame(function () {
+ callback(entries, observer);
+ });
+ });
+ }
+ };
+ }
+
+ function isResizeObserverLoopError(message) {
+ return typeof message === 'string' && message.indexOf('ResizeObserver loop') !== -1;
+ }
+
+ function isAxiosNetworkError(reason) {
+ if (!reason) return false;
+ var msg = typeof reason === 'string' ? reason : (reason.message || '');
+ return msg === 'Network Error' || (reason.isAxiosError && msg === 'Network Error');
+ }
+
+ window.addEventListener('error', function (event) {
+ if (isResizeObserverLoopError(event.message)) {
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ }
+ });
+
+ window.addEventListener('unhandledrejection', function (event) {
+ if (isAxiosNetworkError(event.reason)) {
+ console.warn('[dev] API unreachable:', event.reason?.config?.url || event.reason?.message);
+ event.preventDefault();
+ }
+ });
+ })();
<% for (const item of $scripts) { %>
diff --git a/src/api/enterpriseInfo/adapter.js b/src/api/enterpriseInfo/adapter.js
index 7caf1d8..fa5d6cd 100644
--- a/src/api/enterpriseInfo/adapter.js
+++ b/src/api/enterpriseInfo/adapter.js
@@ -1,6 +1,6 @@
/** 企业信息管理:前后端字段与分页格式适配 */
-import { formatDate, formatDateTime, toApiDate, toApiDateTime } from "../../utils/dateFormat";
+import { formatDate, formatDateTime, normalizeDateValue, toApiDate, toApiDateTime } from "../../utils/dateFormat";
import { resolveUploadFileIds } from "../../utils/mockUpload";
import { asId, isIdFieldName, normalizeQueryIds } from "./idUtil";
import { withOrgId } from "./orgContext";
@@ -162,6 +162,102 @@ export function fromOrgInfoForm(values = {}, options = {}) {
};
}
+/** 监管端机构账号:后端 state 0=启用,1=禁用 */
+export function isOrgAccountEnabled(record = {}) {
+ return Number(record.state) === 0;
+}
+
+export function toOrgAccountRow(data = {}) {
+ return {
+ id: asId(data.id),
+ orgName: data.unitName,
+ district: data.districtName,
+ state: data.state,
+ createTime: formatDate(normalizeDateValue(data.createTime)),
+ };
+}
+
+/** 监管端分页查询(不带 orgInfoId;部分筛选项需后端 OrgInfoPageQuery 扩展后生效) */
+export function toRegulatorOrgAccountPageQuery(params = {}) {
+ const query = {
+ current: params.pageIndex ?? params.current ?? 1,
+ size: params.pageSize ?? params.size ?? 10,
+ };
+ if (params.orgName) {
+ query.unitName = params.orgName;
+ }
+ if (params.district) {
+ query.districtName = params.district;
+ }
+ const state = params.state;
+ if (state !== undefined && state !== null && state !== "" && state !== "全部") {
+ query.state = Number(state);
+ }
+ const range = params.openTimeRange;
+ if (Array.isArray(range) && range.length === 2 && range[0] && range[1]) {
+ query.createTimeStart = range[0].format ? range[0].format("YYYY-MM-DD") : range[0];
+ query.createTimeEnd = range[1].format ? range[1].format("YYYY-MM-DD") : range[1];
+ }
+ return normalizeQueryIds(query);
+}
+
+/** 监管端已备案机构列表行 */
+export function toRegisteredOrgRow(data = {}) {
+ return {
+ id: asId(data.id),
+ orgName: data.unitName,
+ registerAddress: data.registerAddress,
+ serviceEnterpriseCount: 0,
+ evalProjectCount: 0,
+ filingType: data.filingTypeName,
+ filingRecordStatusCode: data.filingRecordStatusCode,
+ filingRecordStatusName: data.filingRecordStatusName,
+ };
+}
+
+/** 监管端已备案机构分页查询 */
+export function toRegisteredOrgPageQuery(params = {}) {
+ const query = {
+ current: params.pageIndex ?? params.current ?? 1,
+ size: params.pageSize ?? params.size ?? 10,
+ };
+ if (params.orgName) {
+ query.unitName = params.orgName;
+ }
+ if (params.registerAddress) {
+ query.registerAddress = params.registerAddress;
+ }
+ const filingTypeCode = params.filingType;
+ if (filingTypeCode !== undefined && filingTypeCode !== null && filingTypeCode !== "") {
+ query.filingTypeCode = String(filingTypeCode);
+ }
+ const filingRecordStatusCode = params.filingRecordStatus;
+ if (filingRecordStatusCode !== undefined && filingRecordStatusCode !== null && filingRecordStatusCode !== "") {
+ query.filingRecordStatusCode = Number(filingRecordStatusCode);
+ }
+ return normalizeQueryIds(query);
+}
+
+export function fromRegulatorOrgInfoModify(values = {}, existing = {}) {
+ const merged = {
+ ...toOrgInfoForm(existing),
+ ...values,
+ id: asId(values.id ?? existing.id),
+ };
+ const payload = fromOrgInfoForm(merged, { isDraft: false });
+ return {
+ ...payload,
+ id: asId(values.id ?? existing.id),
+ authStatusCode: existing.authStatusCode ?? payload.authStatusCode,
+ authStatusName: existing.authStatusName ?? payload.authStatusName,
+ tenantId: existing.tenantId ?? payload.tenantId,
+ filingTypeCode: existing.filingTypeCode ?? payload.filingTypeCode,
+ filingTypeName: existing.filingTypeName ?? payload.filingTypeName,
+ filingRecordStatusCode: existing.filingRecordStatusCode ?? payload.filingRecordStatusCode,
+ filingRecordStatusName: existing.filingRecordStatusName ?? payload.filingRecordStatusName,
+ };
+}
+
// ─── 部门 / 岗位 ───
export function toDepartmentForm(data = {}) {
@@ -411,6 +507,68 @@ export function fromQualificationForm(values = {}) {
};
}
+function isQualificationExpireWarning(dateStr) {
+ if (!dateStr) {
+ return false;
+ }
+ const end = new Date(String(dateStr).replace(/-/g, "/"));
+ if (Number.isNaN(end.getTime())) {
+ return false;
+ }
+ const diff = end.getTime() - Date.now();
+ return diff > 0 && diff < 90 * 24 * 3600 * 1000;
+}
+
+/** classGet 分组 Map → 已备案机构详情「申请清单材料」结构 */
+export function fromQualificationClassGetResponse(res) {
+ const map = res?.data;
+ if (!map || typeof map !== "object") {
+ return [];
+ }
+ return Object.entries(map).map(([code, list], index) => {
+ const items = (Array.isArray(list) ? list : []).map(toQualificationForm);
+ const scopeName = items[0]?.certType || code || `资质${index + 1}`;
+ const expireDate = items.reduce((latest, item) => {
+ const d = item.validEndDate;
+ if (!d) {
+ return latest;
+ }
+ return !latest || d > latest ? d : latest;
+ }, "");
+ return {
+ id: code || String(index),
+ scopeName,
+ expireDate: expireDate || "-",
+ expireWarning: isQualificationExpireWarning(expireDate),
+ materials: items.map((item, idx) => {
+ const previewUrl = item.certImgFiles?.[0]?.url || item.certImgs?.[0]?.url;
+ return {
+ id: item.id || `${code}-${idx}`,
+ name: item.certName || item.certType || "-",
+ required: true,
+ status: previewUrl ? "uploaded" : "pending",
+ previewUrl,
+ raw: item,
+ };
+ }),
+ };
+ });
+}
+
+/** 已备案机构详情人员列表行 */
+export function toRegisteredOrgPersonnelRow(data = {}) {
+ const form = toStaffForm(data);
+ return {
+ id: form.id,
+ name: form.staffName,
+ gender: GENDER_NAME[form.gender] || "-",
+ position: form.positionName,
+ qualScope: form.qualScope,
+ education: form.education || form.educationLevel,
+ registerEngineer: form.registerEngineerFlag === 1 ? 1 : 0,
+ };
+}
+
// ─── 装备 ───
/** 装备 enableFlag(1启用/2禁用) ↔ 前端 enableStatus(1启用/0禁用) */
diff --git a/src/api/enterpriseInfo/http.js b/src/api/enterpriseInfo/http.js
index 7f17b50..5d5d441 100644
--- a/src/api/enterpriseInfo/http.js
+++ b/src/api/enterpriseInfo/http.js
@@ -45,20 +45,20 @@ export async function apiGet(path, params = {}, headers = {}, options = {}) {
}
/** @ 前缀表示 Post 请求体不包裹 request 字段 */
-export async function apiPost(path, data = {}, headers = {}) {
+export async function apiPost(path, data = {}, headers = {}, options = {}) {
const url = path.startsWith("@") ? path : `@${path}`;
try {
- return await Post(url, withIds(data), buildRequestHeaders(headers));
+ return await Post(url, withIds(data), buildRequestHeaders(headers, options));
}
catch (err) {
return parseHttpError(err);
}
}
-export async function apiPostDelete(path, id) {
+export async function apiPostDelete(path, id, options = {}) {
const url = `${path}?id=${encodeURIComponent(asId(id) ?? "")}`;
try {
- return await Post(url, {}, buildRequestHeaders());
+ return await Post(url, {}, buildRequestHeaders({}, options));
}
catch (err) {
return parseHttpError(err);
diff --git a/src/api/orgInfo/index.js b/src/api/orgInfo/index.js
index f08f65b..967c986 100644
--- a/src/api/orgInfo/index.js
+++ b/src/api/orgInfo/index.js
@@ -52,3 +52,15 @@ export const orgInfoDraft = declareRequest("orgInfoLoading", safeAction(async (v
persistOrgInfoId(result, res?.data);
return result;
}));
+
+export {
+ orgAccountList,
+ orgAccountGet,
+ orgAccountModify,
+ orgAccountDelete,
+ orgAccountUpdateState,
+ orgAccountResetPassword,
+ registeredOrgList,
+ registeredOrgGet,
+ fetchRegisteredOrgDetail,
+} from "../regulatorOrgInfo";
diff --git a/src/api/regulatorOrgInfo/index.js b/src/api/regulatorOrgInfo/index.js
new file mode 100644
index 0000000..1ccd012
--- /dev/null
+++ b/src/api/regulatorOrgInfo/index.js
@@ -0,0 +1,108 @@
+import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
+import {
+ fromPageResponse,
+ fromQualificationClassGetResponse,
+ fromRegulatorOrgInfoModify,
+ fromSingleResponse,
+ toOrgAccountRow,
+ toOrgInfoForm,
+ toRegisteredOrgPageQuery,
+ toRegisteredOrgPersonnelRow,
+ toRegisteredOrgRow,
+ toRegulatorOrgAccountPageQuery,
+ toStaffCertForm,
+ toStaffForm,
+} from "../enterpriseInfo/adapter";
+import { apiGet, apiPost, apiPostDelete, safeAction, safePageResult } from "../enterpriseInfo/http";
+
+const NO_ORG_CONTEXT = { includeOrgContext: false };
+
+export const orgAccountList = declareRequest("orgInfoLoading", safePageResult(async (params) => {
+ const query = toRegulatorOrgAccountPageQuery(params);
+ const res = await apiGet("/safety-eval/org-info/page", query, {}, NO_ORG_CONTEXT);
+ return fromPageResponse(res, toOrgAccountRow);
+}));
+
+export const orgAccountGet = declareRequest("orgInfoLoading", safeAction(async ({ id }) => {
+ const res = await apiGet("/safety-eval/org-info/get", { id }, {}, NO_ORG_CONTEXT);
+ const result = fromSingleResponse(res, toOrgInfoForm);
+ return {
+ ...result,
+ raw: res?.data ?? null,
+ };
+}));
+
+export const orgAccountModify = declareRequest("orgInfoLoading", safeAction(async (values) => {
+ const { raw, ...formValues } = values;
+ const payload = fromRegulatorOrgInfoModify(formValues, raw || {});
+ const res = await apiPost("/safety-eval/org-info/modify", payload, {}, NO_ORG_CONTEXT);
+ return fromSingleResponse(res, toOrgInfoForm);
+}));
+
+export const orgAccountDelete = declareRequest("orgInfoLoading", safeAction(async ({ id }) => {
+ return apiPostDelete("/safety-eval/org-info/delete", id, NO_ORG_CONTEXT);
+}));
+
+export const orgAccountUpdateState = declareRequest("orgInfoLoading", safeAction(async ({ id, state }) => {
+ return apiPost("/safety-eval/org-info/update-state", { id, state }, {}, NO_ORG_CONTEXT);
+}));
+
+export const orgAccountResetPassword = declareRequest("orgInfoLoading", safeAction(async ({ id }) => {
+ const url = `/safety-eval/org-info/reset-password?id=${encodeURIComponent(id)}`;
+ return apiPost(url, {}, {}, NO_ORG_CONTEXT);
+}));
+
+export const registeredOrgList = declareRequest("orgInfoLoading", safePageResult(async (params) => {
+ const query = toRegisteredOrgPageQuery(params);
+ const res = await apiGet("/safety-eval/org-info/page", query, {}, NO_ORG_CONTEXT);
+ return fromPageResponse(res, toRegisteredOrgRow);
+}));
+
+export const registeredOrgGet = declareRequest("orgInfoLoading", safeAction(async ({ id }) => {
+ const res = await apiGet("/safety-eval/org-info/get", { id }, {}, NO_ORG_CONTEXT);
+ return fromSingleResponse(res, toOrgInfoForm);
+}));
+
+/** 详情页直调 HTTP,避免 DVA loading 与 useEffect 依赖 dispatch 函数导致反复取消 */
+export async function fetchRegisteredOrgDetail(id) {
+ const res = await apiGet("/safety-eval/org-info/get", { id }, {}, NO_ORG_CONTEXT);
+ return fromSingleResponse(res, toOrgInfoForm);
+}
+
+export async function fetchRegisteredOrgQualificationGroups(orgInfoId) {
+ const res = await apiGet("/safety-eval/org-qualification/classGet", { id: orgInfoId }, {}, NO_ORG_CONTEXT);
+ if (res?.success === false) {
+ throw new Error(res?.message || "加载申请材料失败");
+ }
+ return fromQualificationClassGetResponse(res);
+}
+
+export async function fetchRegisteredOrgPersonnelList(orgInfoId) {
+ const res = await apiGet("/safety-eval/org-personnel/page", {
+ orgId: orgInfoId,
+ current: 1,
+ size: 999,
+ }, {}, NO_ORG_CONTEXT);
+ const page = fromPageResponse(res, toRegisteredOrgPersonnelRow);
+ return page?.data || [];
+}
+
+export async function fetchRegisteredOrgPersonnelDetail({ id }) {
+ const res = await apiGet("/safety-eval/org-personnel/get", { id }, {}, NO_ORG_CONTEXT);
+ return fromSingleResponse(res, toStaffForm);
+}
+
+export async function fetchRegisteredOrgPersonnelCertList(personnelId) {
+ const res = await apiGet("/safety-eval/org-personnel-cert/page", {
+ personnelId,
+ current: 1,
+ size: 999,
+ }, {}, NO_ORG_CONTEXT);
+ const page = fromPageResponse(res, toStaffCertForm);
+ return page?.data || [];
+}
+
+export async function fetchRegisteredOrgPersonnelCertDetail({ id }) {
+ const res = await apiGet("/safety-eval/org-personnel-cert/get", { id }, {}, NO_ORG_CONTEXT);
+ return fromSingleResponse(res, toStaffCertForm);
+}
diff --git a/src/api/staffCertificate/index.js b/src/api/staffCertificate/index.js
index f52c526..cd43b33 100644
--- a/src/api/staffCertificate/index.js
+++ b/src/api/staffCertificate/index.js
@@ -35,3 +35,21 @@ export const staffCertificateEdit = declareRequest("staffCertificateLoading", sa
export const staffCertificateRemove = declareRequest("staffCertificateLoading", safeAction(async ({ id }) => {
return apiPostDelete("/safety-eval/org-personnel-cert/delete", id);
}));
+
+export async function fetchStaffCertListByPersonnelId(personnelId) {
+ const query = toPageQuery({
+ pageIndex: 1,
+ pageSize: 999,
+ eqStaffId: personnelId,
+ }, {
+ eqStaffId: "personnelId",
+ });
+ const res = await apiGet("/safety-eval/org-personnel-cert/page", query);
+ const page = fromPageResponse(res, toStaffCertForm);
+ return page?.data || [];
+}
+
+export async function fetchStaffCertDetail({ id }) {
+ const res = await apiGet("/safety-eval/org-personnel-cert/get", { id });
+ return fromSingleResponse(res, toStaffCertForm);
+}
diff --git a/src/components/FilePreviewModal/index.js b/src/components/FilePreviewModal/index.js
new file mode 100644
index 0000000..55198a4
--- /dev/null
+++ b/src/components/FilePreviewModal/index.js
@@ -0,0 +1,106 @@
+import { Image, Modal } from "antd";
+
+export function getFilePreviewType(url = "", fileName = "") {
+ const hint = `${fileName || ""} ${url || ""}`.toLowerCase();
+ if (/\.(jpe?g|png|gif|webp|bmp)(\?|#|$)/i.test(hint)) {
+ return "image";
+ }
+ if (/\.pdf(\?|#|$)/i.test(hint)) {
+ return "pdf";
+ }
+ return "unknown";
+}
+
+export function FilePreviewContent({ url, fileName, style }) {
+ if (!url) {
+ return (
+
+ 暂无上传文件
+
+ );
+ }
+
+ const type = getFilePreviewType(url, fileName);
+ if (type === "image") {
+ return ;
+ }
+ if (type === "pdf") {
+ return (
+
+ );
+ }
+
+ return (
+
+ 暂不支持在线预览,请使用「新窗口打开」
+
+ );
+}
+
+export default function FilePreviewModal({
+ open,
+ title = "文件预览",
+ fileName,
+ url,
+ width = 720,
+ onCancel,
+}) {
+ return (
+ {
+ if (url) {
+ window.open(url, "_blank");
+ }
+ onCancel?.();
+ }}
+ >
+ {open && (
+
+ {fileName && (
+
+ {fileName}
+
+ )}
+
+
+ )}
+
+ );
+}
diff --git a/src/enumerate/enterpriseOptions.js b/src/enumerate/enterpriseOptions.js
index 2f15fc0..2b2c127 100644
--- a/src/enumerate/enterpriseOptions.js
+++ b/src/enumerate/enterpriseOptions.js
@@ -31,12 +31,33 @@ export const FILING_TYPE_OPTIONS = [
{ 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: "煤炭开采业" },
diff --git a/src/main.js b/src/main.js
index 2fb5044..f05c88b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -13,7 +13,14 @@ dayjs.locale("zh-cn");
setJJBCommonAntdMessage(message);
const app = setup();
-getFileUrlFromServer();
+
+// jjb.config contextInject.fileUrl 优先,避免启动时请求网关附件接口失败触发 dev overlay
+if (process.env.app?.fileUrl) {
+ window.fileUrl = process.env.app.fileUrl;
+}
+getFileUrlFromServer().catch((err) => {
+ console.warn("[getFileUrlFromServer] failed:", err?.message || err);
+});
// 非底座环境运行
if (!window.__POWERED_BY_QIANKUN__) {
// 云组件默认依赖
diff --git a/src/mock/regulator/basicInfo.js b/src/mock/regulator/basicInfo.js
new file mode 100644
index 0000000..8ba188c
--- /dev/null
+++ b/src/mock/regulator/basicInfo.js
@@ -0,0 +1,391 @@
+/** 监管端 - 基础信息管理 mock 数据(暂不对接后端) */
+
+const EVALUATOR_DETAILS = {
+ 1: {
+ id: 1,
+ name: "张建国",
+ gender: "男",
+ birthDate: "1985-03-15",
+ idCard: "500***********1234",
+ education: "全日制 · 本科",
+ graduateSchool: "重庆大学",
+ major: "安全工程",
+ orgName: "重庆安评技术研究院有限公司",
+ deptName: "评价一部",
+ positionName: "高级评价师",
+ account: "138****5678",
+ employmentStatus: 1,
+ registerEngineerFlag: 1,
+ status: "normal",
+ statusTip: "",
+ certificatesSummary: "安全评价师一级, 注册安全工程师",
+ certificates: [
+ {
+ id: 101,
+ certName: "安全评价师一级",
+ certNo: "SJP-2020-****",
+ issueDate: "2020-06-01",
+ expireDate: "2026-06-01",
+ status: "expired",
+ statusLabel: "已过期",
+ statusTip: "证书已过期",
+ },
+ {
+ id: 102,
+ certName: "注册安全工程师",
+ certNo: "ZGAQ-2018-****",
+ issueDate: "2018-09-15",
+ expireDate: "2027-09-15",
+ status: "normal",
+ statusLabel: "正常",
+ statusTip: "",
+ },
+ {
+ id: 103,
+ certName: "安全评价师二级",
+ certNo: "SJP-2023-****",
+ issueDate: "2023-05-01",
+ expireDate: "2026-08-01",
+ status: "expiring",
+ statusLabel: "临期",
+ statusTip: "证书即将到期(不足3月)",
+ },
+ ],
+ },
+ 2: {
+ id: 2,
+ name: "李明华",
+ gender: "男",
+ birthDate: "1988-07-22",
+ idCard: "500***********5678",
+ education: "全日制 · 硕士",
+ graduateSchool: "中国矿业大学",
+ major: "安全技术及工程",
+ orgName: "重庆安评技术研究院有限公司",
+ deptName: "评价二部",
+ positionName: "评价师",
+ account: "139****1234",
+ employmentStatus: 1,
+ registerEngineerFlag: 1,
+ status: "normal",
+ statusTip: "",
+ certificatesSummary: "安全评价师二级, 注册安全工程师",
+ certificates: [
+ {
+ id: 201,
+ certName: "安全评价师二级",
+ certNo: "SJP-2021-****",
+ issueDate: "2021-03-10",
+ expireDate: "2027-03-10",
+ status: "normal",
+ statusLabel: "正常",
+ statusTip: "",
+ },
+ {
+ id: 202,
+ certName: "注册安全工程师",
+ certNo: "ZGAQ-2019-****",
+ issueDate: "2019-11-20",
+ expireDate: "2028-11-20",
+ status: "normal",
+ statusLabel: "正常",
+ statusTip: "",
+ },
+ ],
+ },
+ 3: {
+ id: 3,
+ name: "王丽萍",
+ gender: "女",
+ birthDate: "1990-11-08",
+ idCard: "500***********9012",
+ education: "全日制 · 本科",
+ graduateSchool: "西南大学",
+ major: "化学工程",
+ orgName: "重庆恒安安全评价有限公司",
+ deptName: "评价部",
+ positionName: "评价师",
+ account: "137****8899",
+ employmentStatus: 1,
+ registerEngineerFlag: 0,
+ status: "abnormal",
+ statusTip: "此评价师的社保存在多处缴纳",
+ certificatesSummary: "安全评价师三级",
+ certificates: [
+ {
+ id: 301,
+ certName: "安全评价师三级",
+ certNo: "SJP-2022-****",
+ issueDate: "2022-08-01",
+ expireDate: "2028-08-01",
+ status: "normal",
+ statusLabel: "正常",
+ statusTip: "",
+ },
+ ],
+ },
+ 4: {
+ id: 4,
+ name: "陈华",
+ gender: "男",
+ birthDate: "1987-04-18",
+ idCard: "500***********3456",
+ education: "在职教育 · 本科",
+ graduateSchool: "重庆理工大学",
+ major: "安全工程",
+ orgName: "重庆渝安风险评估中心",
+ deptName: "技术部",
+ positionName: "评价师",
+ account: "136****7788",
+ employmentStatus: 1,
+ registerEngineerFlag: 1,
+ status: "abnormal",
+ statusTip: "评价师证书临期(不足3月)",
+ certificatesSummary: "安全评价师二级",
+ certificates: [
+ {
+ id: 401,
+ certName: "安全评价师二级",
+ certNo: "SJP-2020-****",
+ issueDate: "2020-04-15",
+ expireDate: "2026-08-15",
+ status: "expiring",
+ statusLabel: "临期",
+ statusTip: "证书即将到期(不足3月)",
+ },
+ ],
+ },
+ 5: {
+ id: 5,
+ name: "赵敏",
+ gender: "女",
+ birthDate: "1992-01-30",
+ idCard: "500***********7890",
+ education: "全日制 · 本科",
+ graduateSchool: "重庆科技学院",
+ major: "安全工程",
+ orgName: "重庆安环检测技术有限公司",
+ deptName: "评价中心",
+ positionName: "评价师",
+ account: "135****6677",
+ employmentStatus: 0,
+ registerEngineerFlag: 0,
+ status: "abnormal",
+ statusTip: "此评价师的社保存在多处缴纳;证书临期(不足3月)",
+ certificatesSummary: "安全评价师三级",
+ certificates: [
+ {
+ id: 501,
+ certName: "安全评价师三级",
+ certNo: "SJP-2023-****",
+ issueDate: "2023-06-01",
+ expireDate: "2026-07-01",
+ status: "expiring",
+ statusLabel: "临期",
+ statusTip: "证书即将到期(不足3月)",
+ },
+ ],
+ },
+};
+
+const EVALUATOR_LIST = Object.values(EVALUATOR_DETAILS).map((item) => ({
+ id: item.id,
+ orgName: item.orgName,
+ evaluatorName: item.name,
+ registerEngineerFlag: item.registerEngineerFlag,
+ registerEngineerLabel: item.registerEngineerFlag === 1 ? "是" : "否",
+ employmentStatus: item.employmentStatus,
+ employmentLabel: item.employmentStatus === 1 ? "是" : "否",
+ certificatesSummary: item.certificatesSummary,
+ status: item.status,
+ statusLabel: item.status === "normal" ? "正常" : "异常",
+ statusTip: item.statusTip,
+}));
+
+const ENTERPRISE_PORTRAIT_DETAILS = {
+ 1: {
+ id: 1,
+ enterpriseName: "重庆华安安全科技有限公司",
+ creditCode: "91500112MA******",
+ industry: "化工行业",
+ district: "渝北区",
+ accountSource: "企业注册",
+ projectOnTime: "12/15",
+ projectOnTimeRate: "80%",
+ reportQuality: "合格",
+ complaintCount: 0,
+ penaltyCount: 0,
+ infoLevel: "一级",
+ infoLevelCode: "level1",
+ scoreGrade: "A级",
+ evalCount: 15,
+ reportQualityDesc: "近6个月无不合格报告",
+ penaltyDesc: "无不良记录",
+ evalCountDesc: "累计安全评价",
+ },
+ 2: {
+ id: 2,
+ enterpriseName: "重庆鼎信安全咨询有限公司",
+ creditCode: "91500105MA******",
+ industry: "建筑施工",
+ district: "江北区",
+ accountSource: "机构注册",
+ projectOnTime: "8/10",
+ projectOnTimeRate: "80%",
+ reportQuality: "合格",
+ complaintCount: 1,
+ penaltyCount: 0,
+ infoLevel: "二级",
+ infoLevelCode: "level2",
+ scoreGrade: "B级",
+ evalCount: 10,
+ reportQualityDesc: "近6个月1份需整改",
+ penaltyDesc: "无行政处罚",
+ evalCountDesc: "累计安全评价",
+ },
+ 3: {
+ id: 3,
+ enterpriseName: "重庆安环检测技术有限公司",
+ creditCode: "91500108MA******",
+ industry: "仓储物流",
+ district: "南岸区",
+ accountSource: "监管注册",
+ projectOnTime: "5/8",
+ projectOnTimeRate: "62.5%",
+ reportQuality: "不合格",
+ complaintCount: 2,
+ penaltyCount: 1,
+ infoLevel: "三级",
+ infoLevelCode: "level3",
+ scoreGrade: "C级",
+ evalCount: 8,
+ reportQualityDesc: "近6个月存在不合格报告",
+ penaltyDesc: "1次行政处罚",
+ evalCountDesc: "累计安全评价",
+ },
+ 4: {
+ id: 4,
+ enterpriseName: "重庆恒安安全评价有限公司",
+ creditCode: "91500106MA******",
+ industry: "矿山",
+ district: "九龙坡区",
+ accountSource: "企业注册",
+ projectOnTime: "20/22",
+ projectOnTimeRate: "91%",
+ reportQuality: "合格",
+ complaintCount: 0,
+ penaltyCount: 0,
+ infoLevel: "一级",
+ infoLevelCode: "level1",
+ scoreGrade: "A级",
+ evalCount: 22,
+ reportQualityDesc: "近6个月无不合格报告",
+ penaltyDesc: "无不良记录",
+ evalCountDesc: "累计安全评价",
+ },
+ 5: {
+ id: 5,
+ enterpriseName: "重庆渝安风险评估中心",
+ creditCode: "91500107MA******",
+ industry: "石油加工",
+ district: "渝中区",
+ accountSource: "机构注册",
+ projectOnTime: "6/9",
+ projectOnTimeRate: "67%",
+ reportQuality: "合格",
+ complaintCount: 0,
+ penaltyCount: 0,
+ infoLevel: "二级",
+ infoLevelCode: "level2",
+ scoreGrade: "B级",
+ evalCount: 9,
+ reportQualityDesc: "近6个月无不合格报告",
+ penaltyDesc: "无不良记录",
+ evalCountDesc: "累计安全评价",
+ },
+};
+
+const ENTERPRISE_PORTRAIT_LIST = Object.values(ENTERPRISE_PORTRAIT_DETAILS).map((item) => ({
+ id: item.id,
+ enterpriseName: item.enterpriseName,
+ district: item.district,
+ accountSource: item.accountSource,
+ projectOnTime: item.projectOnTime,
+ reportQuality: item.reportQuality,
+ complaintCount: item.complaintCount,
+ penaltyCount: item.penaltyCount,
+ infoLevel: item.infoLevel,
+ infoLevelCode: item.infoLevelCode,
+}));
+
+function paginate(list, params = {}) {
+ const pageIndex = Number(params.pageIndex ?? params.current ?? 1);
+ const pageSize = Number(params.pageSize ?? params.size ?? 10);
+ const start = (pageIndex - 1) * pageSize;
+ return {
+ success: true,
+ data: list.slice(start, start + pageSize),
+ totalCount: list.length,
+ };
+}
+
+function includesKeyword(value, keyword) {
+ if (!keyword) return true;
+ return String(value || "").includes(String(keyword).trim());
+}
+
+export function queryEvaluatorPage(params = {}) {
+ let list = [...EVALUATOR_LIST];
+ if (params.evaluatorName) {
+ list = list.filter((item) => includesKeyword(item.evaluatorName, params.evaluatorName));
+ }
+ if (params.orgName) {
+ list = list.filter((item) => includesKeyword(item.orgName, params.orgName));
+ }
+ if (params.employmentStatus !== undefined && params.employmentStatus !== null && params.employmentStatus !== "") {
+ list = list.filter((item) => item.employmentStatus === Number(params.employmentStatus));
+ }
+ if (params.registerEngineerFlag !== undefined && params.registerEngineerFlag !== null && params.registerEngineerFlag !== "") {
+ list = list.filter((item) => item.registerEngineerFlag === Number(params.registerEngineerFlag));
+ }
+ if (params.status) {
+ list = list.filter((item) => item.status === params.status);
+ }
+ return Promise.resolve(paginate(list, params));
+}
+
+export function getEvaluatorDetail(id) {
+ const detail = EVALUATOR_DETAILS[id];
+ return Promise.resolve({
+ success: !!detail,
+ data: detail || null,
+ });
+}
+
+export function queryEnterprisePortraitPage(params = {}) {
+ let list = [...ENTERPRISE_PORTRAIT_LIST];
+ if (params.enterpriseName) {
+ list = list.filter((item) => includesKeyword(item.enterpriseName, params.enterpriseName));
+ }
+ if (params.district) {
+ list = list.filter((item) => item.district === params.district);
+ }
+ if (params.accountSource) {
+ list = list.filter((item) => item.accountSource === params.accountSource);
+ }
+ return Promise.resolve(paginate(list, params));
+}
+
+export function getEnterprisePortraitDetail(id) {
+ const detail = ENTERPRISE_PORTRAIT_DETAILS[id];
+ return Promise.resolve({
+ success: !!detail,
+ data: detail || null,
+ });
+}
+
+export const ACCOUNT_SOURCE_OPTIONS = [
+ { label: "企业注册", value: "企业注册" },
+ { label: "机构注册", value: "机构注册" },
+ { label: "监管注册", value: "监管注册" },
+];
diff --git a/src/mock/regulator/institution.js b/src/mock/regulator/institution.js
new file mode 100644
index 0000000..4590b90
--- /dev/null
+++ b/src/mock/regulator/institution.js
@@ -0,0 +1,363 @@
+/** 监管端 - 机构账号 / 已备案机构 mock 数据 */
+
+import { FILING_TYPE_OPTIONS } from "~/enumerate/enterpriseOptions";
+
+function paginate(list, params = {}) {
+ const pageIndex = Number(params.pageIndex ?? params.current ?? 1);
+ const pageSize = Number(params.pageSize ?? params.size ?? 10);
+ const start = (pageIndex - 1) * pageSize;
+ return {
+ success: true,
+ data: list.slice(start, start + pageSize),
+ totalCount: list.length,
+ };
+}
+
+function includesKeyword(value, keyword) {
+ if (!keyword) return true;
+ return String(value || "").includes(String(keyword).trim());
+}
+
+function inDateRange(dateStr, start, end) {
+ if (!dateStr) return false;
+ if (start && dateStr < start) return false;
+ if (end && dateStr > end) return false;
+ return true;
+}
+
+export const ORG_ACCOUNT_SOURCE_OPTIONS = [
+ { label: "机构注册", value: "机构注册" },
+ { label: "监管注册", value: "监管注册" },
+];
+
+export const ORG_ACCOUNT_STATUS_OPTIONS = [
+ { label: "启用", value: 1 },
+ { label: "禁用", value: 0 },
+];
+
+const ORG_ACCOUNT_DETAILS = {
+ 1: {
+ id: 1,
+ orgName: "重庆安评技术研究院有限公司",
+ creditCode: "91500112MA7******",
+ district: "渝北区",
+ industries: ["化学原料/危化品生产、储存、经营、医药化工"],
+ businessAddress: "重庆市渝北区龙山街道100号",
+ enterpriseStatus: "正常",
+ longitude: "106.532",
+ latitude: "29.612",
+ principalName: "刘强",
+ principalPhone: "138****5678",
+ legalPerson: "刘强",
+ legalPhone: "023-6789****",
+ enterpriseScale: "中型",
+ aboveScaleFlag: 0,
+ accountSource: "机构注册",
+ enableStatus: 1,
+ openTime: "2025-09-01",
+ },
+ 2: {
+ id: 2,
+ orgName: "重庆恒安安全评价有限公司",
+ creditCode: "91500105MA6******",
+ district: "南岸区",
+ industries: ["石油天然气开采、油气管道、石油加工"],
+ businessAddress: "重庆市南岸区南坪西路200号",
+ enterpriseStatus: "正常",
+ longitude: "106.571",
+ latitude: "29.523",
+ principalName: "王芳",
+ principalPhone: "139****2345",
+ legalPerson: "王芳",
+ legalPhone: "023-6288****",
+ enterpriseScale: "小型",
+ aboveScaleFlag: 0,
+ accountSource: "监管注册",
+ enableStatus: 1,
+ openTime: "2025-10-15",
+ },
+ 3: {
+ id: 3,
+ orgName: "重庆渝安风险评估中心",
+ creditCode: "91500107MA5******",
+ district: "九龙坡区",
+ industries: ["建筑施工、建材"],
+ businessAddress: "重庆市九龙坡区石桥铺300号",
+ enterpriseStatus: "正常",
+ longitude: "106.480",
+ latitude: "29.502",
+ principalName: "陈明",
+ principalPhone: "137****8899",
+ legalPerson: "陈明",
+ legalPhone: "023-6866****",
+ enterpriseScale: "微型",
+ aboveScaleFlag: 0,
+ accountSource: "机构注册",
+ enableStatus: 0,
+ openTime: "2025-06-20",
+ },
+};
+
+let orgAccountStore = Object.values(ORG_ACCOUNT_DETAILS).map((item) => ({
+ id: item.id,
+ orgName: item.orgName,
+ district: item.district,
+ accountSource: item.accountSource,
+ enableStatus: item.enableStatus,
+ openTime: item.openTime,
+}));
+
+const REGISTERED_ORG_DETAILS = {
+ 1: {
+ id: 1,
+ orgName: "重庆安评技术研究院有限公司",
+ registerAddress: "渝北区龙山街道100号",
+ serviceEnterpriseCount: 12,
+ evalProjectCount: 45,
+ filingType: "审核备案",
+ filingStatus: "filed",
+ filingStatusLabel: "已备案",
+ filingInfo: {
+ filingDistrict: "重庆市沙坪坝区",
+ filingUnit: "重庆市安全生产科学研究有限公司",
+ filingUnitType: "本地单位",
+ registerAddress: "重庆市沙坪坝区大学城东路20号重庆科技学院第39栋西南角实习用房三楼",
+ officeAddress: "重庆市沙坪坝区大学城东路20号重庆科技学院第39栋西南角实习用房三楼",
+ qualCertNo: "API-2026-001",
+ creditCode: "91500112MA7******",
+ legalPersonPhone: "刘强 / 138****5678",
+ infoUrl: "www.cqap.com",
+ fixedAssetTotal: "1200",
+ contactPhone: "陈芳 / 139****9012",
+ archiveArea: "80 ㎡",
+ workplaceArea: "1200 ㎡",
+ fullTimeEvaluatorCount: "25 人",
+ registerEngineerCount: "12 人",
+ intro: "重庆安全生产科学研究有限公司成立于2015年,是一家专业从事安全评价、安全咨询、安全技术开发与转让的综合性安全技术服务机构。",
+ attachments: ["资质申请书.pdf", "营业执照副本.pdf", "社保缴纳证明.pdf"],
+ },
+ materialGroups: [
+ {
+ id: 1,
+ scopeName: "化工",
+ expireDate: "2029-01-14",
+ materials: [
+ { id: 11, name: "化工领域安全评价机构资质申请书", required: true, status: "uploaded" },
+ { id: 12, name: "化工领域技术人员资质证书", required: true, status: "uploaded" },
+ { id: 13, name: "化工领域业绩证明材料", required: false, status: "uploaded" },
+ ],
+ },
+ {
+ id: 2,
+ scopeName: "矿山",
+ expireDate: "2028-06-30",
+ materials: [
+ { id: 21, name: "矿山领域安全评价机构资质申请书", required: true, status: "uploaded" },
+ { id: 22, name: "矿山领域技术人员资质证书", required: true, status: "uploaded" },
+ { id: 23, name: "矿山领域安全管理制度文件", required: true, status: "pending" },
+ { id: 24, name: "矿山领域业绩证明材料", required: false, status: "uploaded" },
+ ],
+ },
+ {
+ id: 3,
+ scopeName: "建筑施工",
+ expireDate: "2026-05-31",
+ expireWarning: true,
+ materials: [
+ { id: 31, name: "建筑施工领域安全评价机构资质申请书", required: true, status: "uploaded" },
+ { id: 32, name: "建筑施工领域技术人员资质证书", required: true, status: "uploaded" },
+ { id: 33, name: "建筑施工领域设备清单及检定报告", required: true, status: "pending" },
+ ],
+ },
+ ],
+ personnel: [
+ { id: 1, name: "张建国", gender: "男", personType: "专职评价师", qualScope: "化工", education: "本科", registerEngineer: 1 },
+ { id: 2, name: "李明华", gender: "男", personType: "专职评价师", qualScope: "矿山", education: "硕士", registerEngineer: 1 },
+ { id: 3, name: "王丽萍", gender: "女", personType: "基础人员", qualScope: "建筑施工", education: "本科", registerEngineer: 0 },
+ { id: 4, name: "陈志强", gender: "男", personType: "专职评价师", qualScope: "化工", education: "本科", registerEngineer: 1 },
+ { id: 5, name: "赵磊", gender: "男", personType: "管理人员", qualScope: "—", education: "专科", registerEngineer: 0 },
+ ],
+ evalProjects: [
+ { id: 1, projectType: "安全预评价", projectNo: "YP-2026-0012", projectName: "华安化工园区安全预评价项目", projectStatus: "待现场勘查" },
+ { id: 2, projectType: "安全验收评价", projectNo: "YS-2026-0008", projectName: "鼎信建设安全验收评价", projectStatus: "过程管控" },
+ { id: 3, projectType: "安全现状评价", projectNo: "XZ-2026-0003", projectName: "安环检测年度安全现状评价", projectStatus: "归档" },
+ ],
+ },
+ 2: {
+ id: 2,
+ orgName: "重庆恒安安全评价有限公司",
+ registerAddress: "南岸区南坪西路200号",
+ serviceEnterpriseCount: 8,
+ evalProjectCount: 32,
+ filingType: "确认备案",
+ filingStatus: "filing",
+ filingStatusLabel: "备案中",
+ filingInfo: {
+ filingDistrict: "重庆市南岸区",
+ filingUnit: "重庆恒安安全评价有限公司",
+ filingUnitType: "本地单位",
+ registerAddress: "重庆市南岸区南坪西路200号",
+ officeAddress: "重庆市南岸区南坪西路200号",
+ qualCertNo: "API-2026-002",
+ creditCode: "91500105MA6******",
+ legalPersonPhone: "王芳 / 139****2345",
+ infoUrl: "www.ha-anping.com",
+ fixedAssetTotal: "800",
+ contactPhone: "李强 / 136****5566",
+ archiveArea: "50 ㎡",
+ workplaceArea: "600 ㎡",
+ fullTimeEvaluatorCount: "15 人",
+ registerEngineerCount: "6 人",
+ intro: "重庆恒安安全评价有限公司专注于矿山、化工行业安全评价服务。",
+ attachments: ["资质申请书.pdf", "营业执照副本.pdf"],
+ },
+ materialGroups: [
+ {
+ id: 1,
+ scopeName: "矿山",
+ expireDate: "2028-12-31",
+ materials: [
+ { id: 11, name: "矿山领域安全评价机构资质申请书", required: true, status: "uploaded" },
+ { id: 12, name: "矿山领域技术人员资质证书", required: true, status: "uploaded" },
+ ],
+ },
+ ],
+ personnel: [
+ { id: 1, name: "李明华", gender: "男", personType: "专职评价师", qualScope: "矿山", education: "硕士", registerEngineer: 1 },
+ ],
+ evalProjects: [
+ { id: 1, projectType: "安全现状评价", projectNo: "XZ-2026-0010", projectName: "恒安矿山安全现状评价", projectStatus: "过程管控" },
+ ],
+ },
+};
+
+const REGISTERED_ORG_LIST = Object.values(REGISTERED_ORG_DETAILS).map((item) => ({
+ id: item.id,
+ orgName: item.orgName,
+ registerAddress: item.registerAddress,
+ serviceEnterpriseCount: item.serviceEnterpriseCount,
+ evalProjectCount: item.evalProjectCount,
+ filingType: item.filingType,
+ filingStatus: item.filingStatus,
+ filingStatusLabel: item.filingStatusLabel,
+}));
+
+export const FILING_STATUS_OPTIONS = [
+ { label: "待备案", value: "pending" },
+ { label: "备案中", value: "filing" },
+ { label: "已备案", value: "filed" },
+];
+
+export function queryOrgAccountPage(params = {}) {
+ let list = [...orgAccountStore];
+ if (params.orgName) {
+ list = list.filter((item) => includesKeyword(item.orgName, params.orgName));
+ }
+ if (params.district) {
+ list = list.filter((item) => item.district === params.district);
+ }
+ if (params.enableStatus !== undefined && params.enableStatus !== null && params.enableStatus !== "") {
+ list = list.filter((item) => item.enableStatus === Number(params.enableStatus));
+ }
+ if (params.accountSource) {
+ list = list.filter((item) => item.accountSource === params.accountSource);
+ }
+ const range = params.openTimeRange;
+ if (Array.isArray(range) && range.length === 2 && range[0] && range[1]) {
+ const start = range[0].format ? range[0].format("YYYY-MM-DD") : range[0];
+ const end = range[1].format ? range[1].format("YYYY-MM-DD") : range[1];
+ list = list.filter((item) => inDateRange(item.openTime, start, end));
+ }
+ return Promise.resolve(paginate(list, params));
+}
+
+export function getOrgAccountDetail(id) {
+ const detail = ORG_ACCOUNT_DETAILS[id];
+ if (!detail) {
+ return Promise.resolve({ success: false, data: null });
+ }
+ const current = orgAccountStore.find((item) => item.id === Number(id));
+ return Promise.resolve({
+ success: true,
+ data: { ...detail, enableStatus: current?.enableStatus ?? detail.enableStatus },
+ });
+}
+
+export function updateOrgAccount(id, values) {
+ const numId = Number(id);
+ const detail = ORG_ACCOUNT_DETAILS[numId];
+ if (!detail) {
+ return Promise.resolve({ success: false, message: "记录不存在" });
+ }
+ Object.assign(detail, values);
+ const row = orgAccountStore.find((item) => item.id === numId);
+ if (row) {
+ row.orgName = values.orgName ?? row.orgName;
+ row.district = values.district ?? row.district;
+ }
+ return Promise.resolve({ success: true, data: detail });
+}
+
+export function toggleOrgAccountStatus(id) {
+ const numId = Number(id);
+ const row = orgAccountStore.find((item) => item.id === numId);
+ if (!row) {
+ return Promise.resolve({ success: false, message: "记录不存在" });
+ }
+ row.enableStatus = row.enableStatus === 1 ? 0 : 1;
+ if (ORG_ACCOUNT_DETAILS[numId]) {
+ ORG_ACCOUNT_DETAILS[numId].enableStatus = row.enableStatus;
+ }
+ return Promise.resolve({ success: true, data: row });
+}
+
+export function deleteOrgAccount(id) {
+ const numId = Number(id);
+ orgAccountStore = orgAccountStore.filter((item) => item.id !== numId);
+ return Promise.resolve({ success: true });
+}
+
+export function resetOrgAccountPassword(id) {
+ return Promise.resolve({
+ success: true,
+ message: "密码已重置为初始密码 Ap@123456",
+ data: { id: Number(id), initialPassword: "Ap@123456" },
+ });
+}
+
+export function queryRegisteredOrgPage(params = {}) {
+ let list = [...REGISTERED_ORG_LIST];
+ if (params.orgName) {
+ list = list.filter((item) => includesKeyword(item.orgName, params.orgName));
+ }
+ if (params.registerAddress) {
+ list = list.filter((item) => includesKeyword(item.registerAddress, params.registerAddress));
+ }
+ if (params.filingType) {
+ list = list.filter((item) => item.filingType === params.filingType);
+ }
+ if (params.filingStatus) {
+ list = list.filter((item) => item.filingStatus === params.filingStatus);
+ }
+ return Promise.resolve(paginate(list, params));
+}
+
+export function getRegisteredOrgDetail(id) {
+ const detail = REGISTERED_ORG_DETAILS[id];
+ return Promise.resolve({ success: !!detail, data: detail || null });
+}
+
+/** 详情页 Mock 扩展数据(申请清单材料、人员信息,后端暂无接口) */
+export function getRegisteredOrgDetailMockExtras(id) {
+ const detail = REGISTERED_ORG_DETAILS[id] || REGISTERED_ORG_DETAILS[1];
+ const personnel = (detail?.personnel || []).map((item) => ({
+ ...item,
+ position: item.position || item.personType,
+ }));
+ return Promise.resolve({
+ materialGroups: detail?.materialGroups || [],
+ personnel,
+ });
+}
+
+export { FILING_TYPE_OPTIONS };
diff --git a/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js b/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
new file mode 100644
index 0000000..77e1843
--- /dev/null
+++ b/src/pages/Container/EnterpriseInfo/OrgInfo/formOptions.js
@@ -0,0 +1,198 @@
+import React from "react";
+import Upload from "zy-react-library/components/Upload";
+import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
+import {
+ CHONGQING_DISTRICTS,
+ ENTERPRISE_SCALE_OPTIONS,
+ ENTERPRISE_STATUS_OPTIONS,
+ FILING_RECORD_STATUS_OPTIONS,
+ FILING_TYPE_OPTIONS,
+} from "~/enumerate/enterpriseOptions";
+import { formSelectField } from "~/utils/enterpriseForm";
+import {
+ creditCodeRule,
+ latitudeRule,
+ longitudeRule,
+ nonNegativeIntegerRule,
+ phoneRule,
+ positiveNumberRule,
+ urlRule,
+} from "~/utils/validators";
+
+const numberFieldProps = { style: { width: "100%" } };
+
+/** 机构信息管理 / 备案信息详情 共用表单字段配置 */
+export function buildOrgInfoFormOptions() {
+ return [
+ {
+ name: "orgName",
+ label: "生产经营单位名称",
+ rules: [{ required: true, message: "请输入生产经营单位名称" }],
+ },
+ {
+ name: "creditCode",
+ label: "统一社会信用代码",
+ rules: [creditCodeRule(true)],
+ },
+ {
+ name: "safetyIndustryCategory",
+ label: "安全生产监管行业类别",
+ rules: [{ required: true, message: "请输入安全生产监管行业类别" }],
+ },
+ {
+ ...formSelectField("regionCountyName", "属地", CHONGQING_DISTRICTS, {
+ rules: [{ required: true, message: "请选择属地" }],
+ colProps: { span: 12 },
+ }),
+ },
+ {
+ name: "regionStreetName",
+ label: "所属镇、街道",
+ rules: [{ required: true, message: "请输入所属镇街道" }],
+ },
+ {
+ name: "regionCommunityName",
+ label: "属村(社区)",
+ required: false,
+ },
+ {
+ name: "longitude",
+ label: "所在地坐标经度",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 },
+ rules: [longitudeRule(false)],
+ },
+ {
+ name: "latitude",
+ label: "所在地坐标纬度",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 },
+ rules: [latitudeRule(false)],
+ },
+ {
+ name: "registerAddress",
+ label: "注册地址",
+ rules: [{ required: true, message: "请输入注册地址" }],
+ render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
+ },
+ {
+ name: "businessAddress",
+ label: "经营地址",
+ rules: [{ required: true, message: "请输入经营地址" }],
+ render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
+ },
+ {
+ name: "ownershipType",
+ label: "归属类型",
+ required: false,
+ },
+ {
+ name: "gbIndustryCode",
+ label: "国民经济行业分类(GB/T4754-2017)",
+ required: false,
+ },
+ {
+ name: "legalRepresentative",
+ label: "法定代表人",
+ rules: [{ required: true, message: "请输入法定代表人" }],
+ },
+ {
+ name: "legalRepPhone",
+ label: "法定代表人联系电话",
+ rules: [phoneRule("法定代表人联系电话", false)],
+ },
+ {
+ name: "principal",
+ label: "主要负责人",
+ rules: [{ required: true, message: "请输入主要负责人" }],
+ },
+ {
+ name: "principalPhone",
+ label: "主要负责人联系电话",
+ rules: [phoneRule("主要负责人联系电话", true)],
+ },
+ {
+ name: "safetyDeptHead",
+ label: "安全管理部门负责人",
+ required: false,
+ },
+ {
+ name: "safetyDeptPhone",
+ label: "安全管理部门负责人联系电话",
+ rules: [phoneRule("安全管理部门负责人联系电话", false)],
+ },
+ {
+ name: "safetyVp",
+ label: "主管安全副总",
+ required: false,
+ },
+ {
+ name: "safetyVpPhone",
+ label: "主管安全副总联系电话",
+ rules: [phoneRule("主管安全副总联系电话", false)],
+ },
+ {
+ name: "productionDate",
+ label: "投产日期",
+ required: false,
+ render: FORM_ITEM_RENDER_ENUM.DATE,
+ },
+ {
+ name: "businessStatus",
+ label: "企业经营状态",
+ required: false,
+ },
+ {
+ name: "disclosureUrl",
+ label: "信息公开网址",
+ useConstraints: false,
+ rules: [urlRule("信息公开网址", false)],
+ },
+ {
+ name: "workplaceArea",
+ label: "工作场所建筑面积",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: 0, precision: 2 },
+ rules: [positiveNumberRule("工作场所建筑面积", false)],
+ },
+ {
+ name: "archiveRoomArea",
+ label: "档案室面积",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: 0, precision: 2 },
+ rules: [positiveNumberRule("档案室面积", false)],
+ },
+ {
+ name: "fullTimeEvaluatorCount",
+ label: "专职安全评价师数量",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: 0, precision: 0 },
+ rules: [nonNegativeIntegerRule("专职安全评价师数量", false)],
+ },
+ {
+ name: "registeredSafetyEngineerCount",
+ label: "注册安全工程师数量",
+ render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
+ useConstraints: false,
+ componentProps: { ...numberFieldProps, min: 0, precision: 0 },
+ rules: [nonNegativeIntegerRule("注册安全工程师数量", false)],
+ },
+ formSelectField("enterpriseStatus", "企业状态", ENTERPRISE_STATUS_OPTIONS, { required: false }),
+ formSelectField("enterpriseScale", "企业规模", ENTERPRISE_SCALE_OPTIONS, { required: false }),
+ formSelectField("filingType", "备案类型", FILING_TYPE_OPTIONS, { required: false }),
+ formSelectField("filingRecordStatus", "备案状态", FILING_RECORD_STATUS_OPTIONS, { required: false }),
+ {
+ name: "attachments",
+ label: "上传附件",
+ required: false,
+ render: (
+
+ ),
+ },
+ ];
+}
diff --git a/src/pages/Container/EnterpriseInfo/OrgInfo/index.js b/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
index c3705a7..5a0de35 100644
--- a/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
+++ b/src/pages/Container/EnterpriseInfo/OrgInfo/index.js
@@ -3,31 +3,11 @@ import { Button, Form, message, Space } from "antd";
import { useEffect, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder";
import Page from "zy-react-library/components/Page";
-import Upload from "zy-react-library/components/Upload";
-import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { getOrgInfoDetail } from "~/api/enterpriseInfo/orgBootstrap";
import PageHeader from "../components/PageHeader";
import { NS_ORG_INFO } from "~/enumerate/namespace";
-import {
- CHONGQING_DISTRICTS,
- ENTERPRISE_SCALE_OPTIONS,
- ENTERPRISE_STATUS_OPTIONS,
- FILING_RECORD_STATUS_OPTIONS,
- FILING_TYPE_OPTIONS,
-} from "~/enumerate/enterpriseOptions";
-import { formSelectField } from "~/utils/enterpriseForm";
import { mockUploadFileList } from "~/utils/mockUpload";
-import {
- creditCodeRule,
- latitudeRule,
- longitudeRule,
- nonNegativeIntegerRule,
- phoneRule,
- positiveNumberRule,
- urlRule,
-} from "~/utils/validators";
-
-const numberFieldProps = { style: { width: "100%" } };
+import { buildOrgInfoFormOptions } from "./formOptions";
function OrgInfoPage(props) {
const [form] = Form.useForm();
@@ -37,6 +17,8 @@ function OrgInfoPage(props) {
/** 是否已存在机构数据(有 id 视为已入库,只能修改) */
const [hasExistingData, setHasExistingData] = useState(false);
+ const formOptions = buildOrgInfoFormOptions();
+
const loadDetail = async () => {
try {
const res = getOrgInfoDetail();
@@ -117,179 +99,6 @@ function OrgInfoPage(props) {
}
};
- const formOptions = [
- {
- name: "orgName",
- label: "生产经营单位名称",
- rules: [{ required: true, message: "请输入生产经营单位名称" }],
- },
- {
- name: "creditCode",
- label: "统一社会信用代码",
- rules: [creditCodeRule(true)],
- },
- {
- name: "safetyIndustryCategory",
- label: "安全生产监管行业类别",
- rules: [{ required: true, message: "请输入安全生产监管行业类别" }],
- },
- {
- ...formSelectField("regionCountyName", "属地", CHONGQING_DISTRICTS, {
- rules: [{ required: true, message: "请选择属地" }],
- colProps: { span: 12 },
- }),
- },
- {
- name: "regionStreetName",
- label: "所属镇、街道",
- rules: [{ required: true, message: "请输入所属镇街道" }],
- },
- {
- name: "regionCommunityName",
- label: "属村(社区)",
- required: false,
- },
- {
- name: "longitude",
- label: "所在地坐标经度",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: -180, max: 180, precision: 6 },
- rules: [longitudeRule(false)],
- },
- {
- name: "latitude",
- label: "所在地坐标纬度",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: -90, max: 90, precision: 6 },
- rules: [latitudeRule(false)],
- },
- {
- name: "registerAddress",
- label: "注册地址",
- rules: [{ required: true, message: "请输入注册地址" }],
- render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
- },
- {
- name: "businessAddress",
- label: "经营地址",
- rules: [{ required: true, message: "请输入经营地址" }],
- render: FORM_ITEM_RENDER_ENUM.TEXTAREA,
- },
- {
- name: "ownershipType",
- label: "归属类型",
- required: false,
- },
- {
- name: "gbIndustryCode",
- label: "国民经济行业分类(GB/T4754-2017)",
- required: false,
- },
- {
- name: "legalRepresentative",
- label: "法定代表人",
- rules: [{ required: true, message: "请输入法定代表人" }],
- },
- {
- name: "legalRepPhone",
- label: "法定代表人联系电话",
- rules: [phoneRule("法定代表人联系电话", false)],
- },
- {
- name: "principal",
- label: "主要负责人",
- rules: [{ required: true, message: "请输入主要负责人" }],
- },
- {
- name: "principalPhone",
- label: "主要负责人联系电话",
- rules: [phoneRule("主要负责人联系电话", true)],
- },
- {
- name: "safetyDeptHead",
- label: "安全管理部门负责人",
- required: false,
- },
- {
- name: "safetyDeptPhone",
- label: "安全管理部门负责人联系电话",
- rules: [phoneRule("安全管理部门负责人联系电话", false)],
- },
- {
- name: "safetyVp",
- label: "主管安全副总",
- required: false,
- },
- {
- name: "safetyVpPhone",
- label: "主管安全副总联系电话",
- rules: [phoneRule("主管安全副总联系电话", false)],
- },
- {
- name: "productionDate",
- label: "投产日期",
- required: false,
- render: FORM_ITEM_RENDER_ENUM.DATE,
- },
- {
- name: "businessStatus",
- label: "企业经营状态",
- required: false,
- },
- {
- name: "disclosureUrl",
- label: "信息公开网址",
- useConstraints: false,
- rules: [urlRule("信息公开网址", false)],
- },
- {
- name: "workplaceArea",
- label: "工作场所建筑面积",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: 0, precision: 2 },
- rules: [positiveNumberRule("工作场所建筑面积", false)],
- },
- {
- name: "archiveRoomArea",
- label: "档案室面积",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: 0, precision: 2 },
- rules: [positiveNumberRule("档案室面积", false)],
- },
- {
- name: "fullTimeEvaluatorCount",
- label: "专职安全评价师数量",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: 0, precision: 0 },
- rules: [nonNegativeIntegerRule("专职安全评价师数量", false)],
- },
- {
- name: "registeredSafetyEngineerCount",
- label: "注册安全工程师数量",
- render: FORM_ITEM_RENDER_ENUM.INPUT_NUMBER,
- useConstraints: false,
- componentProps: { ...numberFieldProps, min: 0, precision: 0 },
- rules: [nonNegativeIntegerRule("注册安全工程师数量", false)],
- },
- formSelectField("enterpriseStatus", "企业状态", ENTERPRISE_STATUS_OPTIONS, { required: false }),
- formSelectField("enterpriseScale", "企业规模", ENTERPRISE_SCALE_OPTIONS, { required: false }),
- formSelectField("filingType", "备案类型", FILING_TYPE_OPTIONS, { required: false }),
- formSelectField("filingRecordStatus", "备案状态", FILING_RECORD_STATUS_OPTIONS, { required: false }),
- {
- name: "attachments",
- label: "上传附件",
- required: false,
- render: (
-
- ),
- },
- ];
-
return (
({
@@ -501,80 +499,4 @@ function StaffFormModal({
);
}
-function StaffViewModal({ open, currentId, requestDetails, onCancel }) {
- const [info, setInfo] = useState({});
- const [detailLoading, setDetailLoading] = useState(false);
-
- useEffect(() => {
- if (!open || !currentId) {
- setInfo({});
- return;
- }
- let cancelled = false;
- setDetailLoading(true);
- safeRequest(requestDetails, { id: currentId }).then((res) => {
- if (!cancelled) {
- setInfo(res?.data || {});
- }
- }).finally(() => {
- if (!cancelled) {
- setDetailLoading(false);
- }
- });
- return () => {
- cancelled = true;
- };
- }, [open, currentId]);
-
- return (
-
-
- {info.staffName}
- {GENDER_MAP[info.gender]}
- {info.birthDate}
- {info.account}
- {info.deptName}
- {info.positionName}
- {info.personType || "基础人员"}
- {info.qualScope || "-"}
- {info.professionalLevel || "-"}
- {info.evaluatorCertNo || "-"}
- {info.educationType || "-"}
- {info.educationLevel || "-"}
- {info.titleName || "-"}
-
- {REGISTER_ENGINEER_MAP[info.registerEngineerFlag] ?? "-"}
-
- {info.idCardNo}
- {info.education || "-"}
- {info.homeAddress}
- {info.officeAddress}
- {info.graduateSchool}
- {info.major}
-
- {info.publications || "-"}
-
-
- {info.abilityDeclaration || "-"}
-
-
- {info.workExperience || "-"}
-
-
- {(info.proofMaterials || []).map((file) => file.name || file.fileName).join("、") || "-"}
-
-
-
- );
-}
-
export default Connect([NS_STAFF_INFO, NS_ORG_DEPARTMENT, NS_ORG_POSITION], true)(PersonnelInfoPage);
diff --git a/src/pages/Container/EnterpriseInfo/PersonnelInfo/StaffViewModal.js b/src/pages/Container/EnterpriseInfo/PersonnelInfo/StaffViewModal.js
new file mode 100644
index 0000000..fb84f93
--- /dev/null
+++ b/src/pages/Container/EnterpriseInfo/PersonnelInfo/StaffViewModal.js
@@ -0,0 +1,220 @@
+import { Button, Descriptions, Modal, Space, Table } from "antd";
+import { useEffect, useState } from "react";
+import FilePreviewModal, { FilePreviewContent } from "~/components/FilePreviewModal";
+import { fetchStaffCertDetail, fetchStaffCertListByPersonnelId } from "~/api/staffCertificate";
+import { safeRequest } from "~/utils";
+
+const GENDER_MAP = { 1: "男", 2: "女" };
+const REGISTER_ENGINEER_MAP = { 1: "是", 2: "否" };
+
+export default function StaffViewModal({
+ open,
+ currentId,
+ requestDetails,
+ requestCertList = fetchStaffCertListByPersonnelId,
+ requestCertDetails = fetchStaffCertDetail,
+ onCancel,
+}) {
+ const [info, setInfo] = useState({});
+ const [certificates, setCertificates] = useState([]);
+ const [detailLoading, setDetailLoading] = useState(false);
+ const [attachmentPreview, setAttachmentPreview] = useState(null);
+ const [certPreview, setCertPreview] = useState(null);
+ const [certPreviewLoading, setCertPreviewLoading] = useState(false);
+ const [certPreviewInfo, setCertPreviewInfo] = useState(null);
+
+ useEffect(() => {
+ if (!open || !currentId) {
+ setInfo({});
+ setCertificates([]);
+ return;
+ }
+ let cancelled = false;
+ setDetailLoading(true);
+ Promise.all([
+ safeRequest(requestDetails, { id: currentId }),
+ typeof requestCertList === "function"
+ ? Promise.resolve(requestCertList(currentId)).catch((err) => {
+ console.warn("[StaffViewModal] load certificates failed:", err);
+ return [];
+ })
+ : Promise.resolve([]),
+ ]).then(([detailRes, certList]) => {
+ if (!cancelled) {
+ setInfo(detailRes?.data || {});
+ setCertificates(Array.isArray(certList) ? certList : []);
+ }
+ }).finally(() => {
+ if (!cancelled) {
+ setDetailLoading(false);
+ }
+ });
+ return () => {
+ cancelled = true;
+ };
+ }, [open, currentId, requestDetails, requestCertList]);
+
+ const openCertPreview = async (record) => {
+ setCertPreview(record);
+ setCertPreviewInfo(null);
+ if (typeof requestCertDetails !== "function") {
+ setCertPreviewInfo(record);
+ return;
+ }
+ setCertPreviewLoading(true);
+ try {
+ const res = await safeRequest(requestCertDetails, { id: record.id });
+ setCertPreviewInfo(res?.data || record);
+ }
+ finally {
+ setCertPreviewLoading(false);
+ }
+ };
+
+ const proofFiles = info.proofMaterials || [];
+ const certPreviewFiles = certPreviewInfo?.certImgs?.length
+ ? certPreviewInfo.certImgs
+ : certPreviewInfo?.certImgFiles || [];
+ const certPreviewUrl = certPreviewFiles[0]?.url;
+ const certPreviewName = certPreviewFiles[0]?.fileName || certPreviewFiles[0]?.name || certPreviewInfo?.certName;
+
+ return (
+ <>
+
+
+ {info.staffName}
+ {GENDER_MAP[info.gender]}
+ {info.birthDate}
+ {info.account}
+ {info.deptName}
+ {info.positionName}
+ {info.personType || "基础人员"}
+ {info.qualScope || "-"}
+ {info.professionalLevel || "-"}
+ {info.evaluatorCertNo || "-"}
+ {info.educationType || "-"}
+ {info.educationLevel || "-"}
+ {info.titleName || "-"}
+
+ {REGISTER_ENGINEER_MAP[info.registerEngineerFlag] ?? "-"}
+
+ {info.idCardNo}
+ {info.education || "-"}
+ {info.homeAddress}
+ {info.officeAddress}
+ {info.graduateSchool}
+ {info.major}
+
+ {info.publications || "-"}
+
+
+ {info.abilityDeclaration || "-"}
+
+
+ {info.workExperience || "-"}
+
+
+ {proofFiles.length ? (
+
+ {proofFiles.map((file, index) => {
+ const fileName = file.name || file.fileName || `专业能力证明${index + 1}.pdf`;
+ return (
+
+
+ {fileName}
+
+ );
+ })}
+
+ ) : "-"}
+
+
+
+ 证照信息
+ (
+
+ ),
+ },
+ ]}
+ />
+
+
+ setAttachmentPreview(null)}
+ />
+
+ {
+ setCertPreview(null);
+ setCertPreviewInfo(null);
+ }}
+ onOk={() => {
+ if (certPreviewUrl) {
+ window.open(certPreviewUrl, "_blank");
+ }
+ setCertPreview(null);
+ setCertPreviewInfo(null);
+ }}
+ >
+ {certPreviewInfo && (
+
+
+ {certPreviewInfo.certName}
+ {certPreviewInfo.certNo}
+ {certPreviewInfo.certCategory || "-"}
+ {certPreviewInfo.issueOrg || "-"}
+ {certPreviewInfo.validStartDate || "-"}
+ {certPreviewInfo.validEndDate || "-"}
+
+
+
+ )}
+
+ >
+ );
+}
diff --git a/src/pages/Container/Layout/menuConfig.js b/src/pages/Container/Layout/menuConfig.js
index 77a98e2..af84429 100644
--- a/src/pages/Container/Layout/menuConfig.js
+++ b/src/pages/Container/Layout/menuConfig.js
@@ -16,6 +16,8 @@ import {
ApartmentOutlined,
SwapOutlined,
LogoutOutlined,
+ FileTextOutlined,
+ KeyOutlined,
} from "@ant-design/icons";
const menuItems = [
@@ -29,6 +31,33 @@ const menuItems = [
label: "Test2 测试",
icon: ,
},
+ {
+ key: "/certificate/container/Supervision/BasicInfo",
+ label: "基础信息管理",
+ icon: ,
+ children: [
+ {
+ key: "/certificate/container/Supervision/BasicInfo/OrgAccount",
+ label: "机构账号管理",
+ icon: ,
+ },
+ {
+ key: "/certificate/container/Supervision/BasicInfo/RegisteredOrg/List",
+ label: "已备案机构管理",
+ icon: ,
+ },
+ {
+ key: "/certificate/container/Supervision/BasicInfo/EvaluatorInfo",
+ label: "评价师信息管理",
+ icon: ,
+ },
+ {
+ key: "/certificate/container/Supervision/BasicInfo/EnterprisePortrait",
+ label: "企业画像管理",
+ icon: ,
+ },
+ ],
+ },
{
key: "/certificate/container/Supervision/EnterpriseLicense",
label: "企业证照",
diff --git a/src/pages/Container/Supervision/BasicInfo/EnterprisePortrait/index.js b/src/pages/Container/Supervision/BasicInfo/EnterprisePortrait/index.js
new file mode 100644
index 0000000..4ef22ea
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/EnterprisePortrait/index.js
@@ -0,0 +1,205 @@
+import { Button, Card, Col, Descriptions, Form, Modal, Row, Statistic, Tag } from "antd";
+import { useEffect, useState } from "react";
+import Page from "zy-react-library/components/Page";
+import Search from "zy-react-library/components/Search";
+import Table from "zy-react-library/components/Table";
+import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
+import useTable from "zy-react-library/hooks/useTable";
+import { CHONGQING_DISTRICTS } from "~/enumerate/enterpriseOptions";
+import {
+ ACCOUNT_SOURCE_OPTIONS,
+ getEnterprisePortraitDetail,
+ queryEnterprisePortraitPage,
+} from "~/mock/regulator/basicInfo";
+import PageHeader from "../../../EnterpriseInfo/components/PageHeader";
+
+const INFO_LEVEL_COLOR = {
+ level1: "success",
+ level2: "processing",
+ level3: "warning",
+};
+
+const SCORE_RING_COLOR = {
+ "A级": "#52c41a",
+ "B级": "#1677ff",
+ "C级": "#faad14",
+};
+
+function EnterprisePortraitPage() {
+ const [searchForm] = Form.useForm();
+ const [viewOpen, setViewOpen] = useState(false);
+ const [detail, setDetail] = useState(null);
+ const [detailLoading, setDetailLoading] = useState(false);
+
+ const { tableProps, getData } = useTable(queryEnterprisePortraitPage, { form: searchForm });
+
+ useEffect(() => {
+ getData();
+ }, []);
+
+ const openProfile = async (id) => {
+ setViewOpen(true);
+ setDetailLoading(true);
+ const res = await getEnterprisePortraitDetail(id);
+ setDetail(res?.data || null);
+ setDetailLoading(false);
+ };
+
+ const closeProfile = () => {
+ setViewOpen(false);
+ setDetail(null);
+ };
+
+ return (
+
+
+
+ (
+
+ {record.infoLevel}
+
+ ),
+ },
+ {
+ title: "操作",
+ width: 100,
+ render: (_, record) => (
+
+ ),
+ },
+ ]}
+ />
+
+
+ {detail && (
+ <>
+
+
+ {detail.scoreGrade}
+
+
+
{detail.enterpriseName}
+
+ 统一社会信用代码:
+ {detail.creditCode}
+ {" "}
+ |
+ {detail.industry}
+ {" "}
+ |
+ {detail.district}
+
+
+
+
+
+
+
+
+ ↑
+ {" "}
+ {detail.projectOnTime}
+
+
+
+
+
+
+
+ {detail.reportQualityDesc}
+
+
+
+
+
+
+
+ {detail.penaltyDesc}
+
+
+
+
+
+
+
+ {detail.evalCountDesc}
+
+
+
+
+
+
+
+ {detail.infoLevel}
+
+
+ {detail.accountSource}
+ {detail.complaintCount}
+ {detail.penaltyCount}
+
+ >
+ )}
+
+
+ );
+}
+
+export default EnterprisePortraitPage;
diff --git a/src/pages/Container/Supervision/BasicInfo/EvaluatorInfo/index.js b/src/pages/Container/Supervision/BasicInfo/EvaluatorInfo/index.js
new file mode 100644
index 0000000..233527f
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/EvaluatorInfo/index.js
@@ -0,0 +1,208 @@
+import { Button, Descriptions, Form, Modal, Table, Tag, Tooltip } from "antd";
+import { useEffect, useState } from "react";
+import Page from "zy-react-library/components/Page";
+import Search from "zy-react-library/components/Search";
+import TableList from "zy-react-library/components/Table";
+import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
+import useTable from "zy-react-library/hooks/useTable";
+import { getEvaluatorDetail, queryEvaluatorPage } from "~/mock/regulator/basicInfo";
+import PageHeader from "../../../EnterpriseInfo/components/PageHeader";
+
+const YES_NO_OPTIONS = [
+ { label: "是", value: 1 },
+ { label: "否", value: 0 },
+];
+
+const STATUS_OPTIONS = [
+ { label: "正常", value: "normal" },
+ { label: "异常", value: "abnormal" },
+];
+
+const CERT_STATUS_COLOR = {
+ normal: "success",
+ expiring: "warning",
+ expired: "error",
+};
+
+function EvaluatorInfoPage() {
+ const [searchForm] = Form.useForm();
+ const [viewOpen, setViewOpen] = useState(false);
+ const [detail, setDetail] = useState(null);
+ const [detailLoading, setDetailLoading] = useState(false);
+ const [certPreview, setCertPreview] = useState(null);
+
+ const { tableProps, getData } = useTable(queryEvaluatorPage, { form: searchForm });
+
+ useEffect(() => {
+ getData();
+ }, []);
+
+ const openDetail = async (id) => {
+ setViewOpen(true);
+ setDetailLoading(true);
+ const res = await getEvaluatorDetail(id);
+ setDetail(res?.data || null);
+ setDetailLoading(false);
+ };
+
+ const closeDetail = () => {
+ setViewOpen(false);
+ setDetail(null);
+ setCertPreview(null);
+ };
+
+ return (
+
+
+
+ {
+ const tag = (
+
+ {record.statusLabel}
+
+ );
+ return record.statusTip ? {tag} : tag;
+ },
+ },
+ {
+ title: "操作",
+ width: 80,
+ render: (_, record) => (
+
+ ),
+ },
+ ]}
+ />
+
+
+ {detail && (
+ <>
+
+ {detail.name}
+ {detail.gender}
+ {detail.birthDate}
+ {detail.idCard}
+ {detail.education}
+ {detail.graduateSchool}
+ {detail.major}
+
+
+ {detail.orgName}
+ {detail.deptName}
+ {detail.positionName}
+ {detail.account}
+
+ 资质证照
+ {
+ const tag = (
+
+ {record.statusLabel}
+
+ );
+ return record.statusTip ? {tag} : tag;
+ },
+ },
+ {
+ title: "操作",
+ width: 90,
+ render: (_, record) => (
+
+ ),
+ },
+ ]}
+ />
+ >
+ )}
+
+
+ setCertPreview(null)}
+ >
+ {certPreview && (
+
+ {certPreview.certName}
+ {certPreview.certNo}
+ {certPreview.issueDate}
+ {certPreview.expireDate}
+ {certPreview.statusLabel}
+
+ )}
+
+
+ );
+}
+
+export default EvaluatorInfoPage;
diff --git a/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js b/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js
new file mode 100644
index 0000000..d082274
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/OrgAccount/index.js
@@ -0,0 +1,346 @@
+import {
+ Button, Descriptions, Form, Input, InputNumber, message, Modal, Row, Col, Select, Space, Tag,
+} from "antd";
+import { Connect } from "@cqsjjb/jjb-dva-runtime";
+import { useEffect, useState } from "react";
+import Page from "zy-react-library/components/Page";
+import Search from "zy-react-library/components/Search";
+import Table from "zy-react-library/components/Table";
+import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
+import useTable from "zy-react-library/hooks/useTable";
+import { isOrgAccountEnabled } from "~/api/enterpriseInfo/adapter";
+import {
+ CHONGQING_DISTRICTS,
+ ENTERPRISE_SCALE_OPTIONS,
+ ENTERPRISE_STATUS_OPTIONS,
+ ORG_ACCOUNT_STATE_OPTIONS,
+} from "~/enumerate/enterpriseOptions";
+import { NS_ORG_INFO } from "~/enumerate/namespace";
+import { safeListRequest, safeRequest } from "~/utils";
+import { formSelectField } from "~/utils/enterpriseForm";
+import PageHeader from "../../../EnterpriseInfo/components/PageHeader";
+
+const SEARCH_COL = { xs: 24, sm: 12, md: 8, lg: 6 };
+const SEARCH_DEFAULT_VALUES = { state: "" };
+
+function OrgAccountPage(props) {
+ const [searchForm] = Form.useForm();
+ const [editForm] = Form.useForm();
+ const [viewOpen, setViewOpen] = useState(false);
+ const [editOpen, setEditOpen] = useState(false);
+ const [currentId, setCurrentId] = useState(null);
+ const [detail, setDetail] = useState(null);
+ const [rawDetail, setRawDetail] = useState(null);
+ const [detailLoading, setDetailLoading] = useState(false);
+ const [editLoading, setEditLoading] = useState(false);
+
+ const { tableProps, getData } = useTable(safeListRequest(props.orgAccountList), { form: searchForm });
+
+ useEffect(() => {
+ getData();
+ }, []);
+
+ const loadDetail = async (id) => {
+ setDetailLoading(true);
+ const res = await safeRequest(props.orgAccountGet, { id });
+ setDetail(res?.data || null);
+ setRawDetail(res?.raw || null);
+ setDetailLoading(false);
+ return res;
+ };
+
+ const openView = async (id) => {
+ setCurrentId(id);
+ setViewOpen(true);
+ await loadDetail(id);
+ };
+
+ const openEdit = async (id) => {
+ setCurrentId(id);
+ setEditOpen(true);
+ const res = await loadDetail(id);
+ if (res?.data) {
+ editForm.setFieldsValue(res.data);
+ }
+ };
+
+ const onToggleStatus = (record) => {
+ const enabled = isOrgAccountEnabled(record);
+ Modal.confirm({
+ title: "确认操作",
+ content: enabled ? `确认禁用「${record.orgName}」账号?` : `确认启用「${record.orgName}」账号?`,
+ okText: "确认",
+ cancelText: "取消",
+ onOk: async () => {
+ const nextState = enabled ? 1 : 0;
+ const res = await props.orgAccountUpdateState({ id: record.id, state: nextState });
+ if (res?.success !== false) {
+ message.success("操作成功");
+ await getData();
+ }
+ else {
+ message.error(res?.message || "操作失败");
+ }
+ },
+ });
+ };
+
+ const onResetPassword = (record) => {
+ Modal.confirm({
+ title: "重置密码",
+ content: (
+
+
+ 确认将
+ {record.orgName}
+ 的密码重置为初始密码?
+
+
初始密码:Ap@123456
+
+ ),
+ okText: "确认重置",
+ cancelText: "取消",
+ onOk: async () => {
+ const res = await props.orgAccountResetPassword({ id: record.id });
+ if (res?.success !== false) {
+ message.success("密码已重置");
+ }
+ else {
+ message.error(res?.message || "重置失败");
+ }
+ },
+ });
+ };
+
+ const onDelete = (record) => {
+ Modal.confirm({
+ title: "确认删除",
+ content: (
+
+
+ 确认删除
+ {record.orgName}
+ 的账号?
+
+
此操作不可恢复,请谨慎操作。
+
+ ),
+ okText: "确认删除",
+ okButtonProps: { danger: true },
+ cancelText: "取消",
+ onOk: async () => {
+ const res = await props.orgAccountDelete({ id: record.id });
+ if (res?.success !== false) {
+ message.success("删除成功");
+ await getData();
+ }
+ else {
+ message.error(res?.message || "删除失败");
+ }
+ },
+ });
+ };
+
+ const onEditSubmit = async () => {
+ const values = await editForm.validateFields();
+ setEditLoading(true);
+ const res = await props.orgAccountModify({
+ ...values,
+ id: currentId,
+ raw: rawDetail,
+ });
+ setEditLoading(false);
+ if (res?.success !== false) {
+ message.success("保存成功");
+ setEditOpen(false);
+ setCurrentId(null);
+ setRawDetail(null);
+ editForm.resetFields();
+ await getData();
+ }
+ else {
+ message.error(res?.message || "保存失败");
+ }
+ };
+
+ return (
+
+
+
+ (
+
+ {isOrgAccountEnabled(record) ? "启用" : "禁用"}
+
+ ),
+ },
+ { title: "开户时间", dataIndex: "createTime", width: 110 },
+ {
+ title: "操作",
+ width: 320,
+ fixed: "right",
+ render: (_, record) => (
+
+
+
+
+
+
+
+ ),
+ },
+ ]}
+ />
+
+ { setViewOpen(false); setDetail(null); setRawDetail(null); }}
+ >
+ {detail && (
+
+ {detail.orgName}
+ {detail.creditCode}
+ {detail.regionCountyName}
+ {detail.safetyIndustryCategory}
+ {detail.businessAddress}
+ {detail.enterpriseStatus}
+ {detail.longitude}, {detail.latitude}
+ {detail.principal}
+ {detail.principalPhone}
+ {detail.legalRepresentative}
+ {detail.legalRepPhone}
+ {detail.enterpriseScale}
+
+ )}
+
+
+ {
+ setEditOpen(false);
+ setCurrentId(null);
+ setRawDetail(null);
+ editForm.resetFields();
+ }}
+ onOk={onEditSubmit}
+ >
+
+
+
+ );
+}
+
+export default Connect([NS_ORG_INFO], true)(OrgAccountPage);
diff --git a/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/Detail/index.js b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/Detail/index.js
new file mode 100644
index 0000000..9a8a65b
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/Detail/index.js
@@ -0,0 +1,274 @@
+import { Button, Card, Form, Spin, Table, Tabs, Tag, message } from "antd";
+import { useEffect, useMemo, useState } from "react";
+import FormBuilder from "zy-react-library/components/FormBuilder";
+import Page from "zy-react-library/components/Page";
+import FilePreviewModal from "~/components/FilePreviewModal";
+import {
+ fetchRegisteredOrgDetail,
+ fetchRegisteredOrgPersonnelCertDetail,
+ fetchRegisteredOrgPersonnelCertList,
+ fetchRegisteredOrgPersonnelDetail,
+ fetchRegisteredOrgPersonnelList,
+ fetchRegisteredOrgQualificationGroups,
+} from "~/api/regulatorOrgInfo";
+import { buildOrgInfoFormOptions } from "../../../../EnterpriseInfo/OrgInfo/formOptions";
+import PageHeader from "../../../../EnterpriseInfo/components/PageHeader";
+import StaffViewModal from "../../../../EnterpriseInfo/PersonnelInfo/StaffViewModal";
+
+const LIST_PATH = "/container/supervision/basicInfo/registeredOrg/list";
+const ORG_INFO_FORM_OPTIONS = buildOrgInfoFormOptions();
+
+function parseQueryId(location) {
+ const search = location?.search || window.location.search || "";
+ return new URLSearchParams(search).get("id");
+}
+
+function MaterialsTab({ materialGroups, loading, onPreview }) {
+ if (loading) {
+ return ;
+ }
+ return (
+
+
+ 该机构共申请
+ {materialGroups.length}
+ 个业务范围资质,以下为各范围对应的申请材料清单
+
+ {materialGroups.map((group) => (
+
+ 证书有效期:
+
+ {group.expireDate}
+ {group.expireWarning ? "(即将到期)" : ""}
+
+
+ )}
+ >
+ (
+
+ ),
+ },
+ ]}
+ />
+
+ ))}
+
+ );
+}
+
+function PersonnelTab({ personnel, loading, onView }) {
+ if (loading) {
+ return ;
+ }
+ return (
+ index + 1 },
+ { title: "姓名", dataIndex: "name", width: 90 },
+ { title: "性别", dataIndex: "gender", width: 60 },
+ { title: "岗位", dataIndex: "position", width: 110 },
+ { title: "资质范围", dataIndex: "qualScope", width: 90 },
+ { title: "学历", dataIndex: "education", width: 80 },
+ {
+ title: "注册安全工程师",
+ width: 120,
+ render: (_, record) => (
+
+ {record.registerEngineer === 1 ? "是" : "否"}
+
+ ),
+ },
+ {
+ title: "操作",
+ width: 80,
+ render: (_, record) => (
+
+ ),
+ },
+ ]}
+ />
+ );
+}
+
+function RegisteredOrgDetailPage(props) {
+ const id = useMemo(() => parseQueryId(props.location), [props.location?.search]);
+ const [form] = Form.useForm();
+ const [orgLoading, setOrgLoading] = useState(Boolean(parseQueryId(props.location)));
+ const [extrasLoading, setExtrasLoading] = useState(Boolean(parseQueryId(props.location)));
+ const [orgName, setOrgName] = useState("");
+ const [materialGroups, setMaterialGroups] = useState([]);
+ const [personnel, setPersonnel] = useState([]);
+ const [filePreview, setFilePreview] = useState(null);
+ const [viewPersonnelId, setViewPersonnelId] = useState("");
+
+ useEffect(() => {
+ if (!id) {
+ setOrgLoading(false);
+ setExtrasLoading(false);
+ return;
+ }
+
+ let cancelled = false;
+ setOrgLoading(true);
+ setExtrasLoading(true);
+
+ (async () => {
+ try {
+ const [orgRes, groups, staffList] = await Promise.all([
+ fetchRegisteredOrgDetail(id),
+ fetchRegisteredOrgQualificationGroups(id).catch((err) => {
+ console.warn("[RegisteredOrgDetail] qualification load failed:", err);
+ message.error(err?.message || "加载申请材料失败");
+ return [];
+ }),
+ fetchRegisteredOrgPersonnelList(id).catch((err) => {
+ console.warn("[RegisteredOrgDetail] personnel load failed:", err);
+ message.error(err?.message || "加载人员信息失败");
+ return [];
+ }),
+ ]);
+ if (cancelled) {
+ return;
+ }
+ if (orgRes?.data) {
+ form.setFieldsValue(orgRes.data);
+ setOrgName(orgRes.data.orgName || "");
+ }
+ setMaterialGroups(groups || []);
+ setPersonnel(staffList || []);
+ }
+ catch (err) {
+ if (!cancelled) {
+ console.warn("[RegisteredOrgDetail] load failed:", err);
+ message.error("加载机构详情失败");
+ }
+ }
+ finally {
+ if (!cancelled) {
+ setOrgLoading(false);
+ setExtrasLoading(false);
+ }
+ }
+ })();
+
+ return () => {
+ cancelled = true;
+ };
+ }, [id]);
+
+ const goBack = () => {
+ if (props.history?.goBack && props.history.length > 1) {
+ props.history.goBack();
+ return;
+ }
+ if (props.history?.push) {
+ props.history.push(LIST_PATH);
+ return;
+ }
+ window.location.href = `/certificate${LIST_PATH}`;
+ };
+
+ if (!id) {
+ return (
+
+ 返回} />
+
+ );
+ }
+
+ const tabItems = [
+ {
+ key: "info",
+ label: "备案信息",
+ children: (
+
+
+
+ ),
+ },
+ {
+ key: "materials",
+ label: "申请清单材料",
+ children: (
+
+ ),
+ },
+ {
+ key: "personnel",
+ label: "人员信息",
+ children: (
+ setViewPersonnelId(record.id)}
+ />
+ ),
+ },
+ ];
+
+ return (
+
+ ← 返回}
+ />
+
+
+ setFilePreview(null)}
+ />
+
+ {viewPersonnelId && (
+ setViewPersonnelId("")}
+ />
+ )}
+
+ );
+}
+
+export default RegisteredOrgDetailPage;
diff --git a/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/List/index.js b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/List/index.js
new file mode 100644
index 0000000..6c67039
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/List/index.js
@@ -0,0 +1,101 @@
+import { Button, Form, Tag } from "antd";
+import { Connect } from "@cqsjjb/jjb-dva-runtime";
+import { useEffect } from "react";
+import Page from "zy-react-library/components/Page";
+import Search from "zy-react-library/components/Search";
+import TableList from "zy-react-library/components/Table";
+import useTable from "zy-react-library/hooks/useTable";
+import {
+ REGISTERED_ORG_FILING_RECORD_STATUS_OPTIONS,
+ REGISTERED_ORG_FILING_TYPE_SEARCH_OPTIONS,
+} from "~/enumerate/enterpriseOptions";
+import { NS_ORG_INFO } from "~/enumerate/namespace";
+import { safeListRequest } from "~/utils";
+import { formSelectField } from "~/utils/enterpriseForm";
+import PageHeader from "../../../../EnterpriseInfo/components/PageHeader";
+
+const FILING_RECORD_STATUS_COLOR = {
+ 1: "success",
+ 2: "default",
+};
+
+const SEARCH_COL = { xs: 24, sm: 12, md: 8, lg: 6 };
+const SEARCH_DEFAULT_VALUES = { filingType: "", filingRecordStatus: "" };
+/** 约定式路由首字母小写:registeredOrg/detail */
+const DETAIL_PATH = "/container/supervision/basicInfo/registeredOrg/detail";
+
+function RegisteredOrgListPage(props) {
+ const [searchForm] = Form.useForm();
+
+ const { tableProps, getData } = useTable(safeListRequest(props.registeredOrgList), { form: searchForm });
+
+ useEffect(() => {
+ getData();
+ }, []);
+
+ const goDetail = (id) => {
+ if (!id) {
+ return;
+ }
+ const query = `${DETAIL_PATH}?id=${encodeURIComponent(id)}`;
+ if (props.history?.push) {
+ props.history.push(query);
+ return;
+ }
+ window.location.href = `/certificate${query}`;
+ };
+
+ return (
+
+
+
+ (
+
+ {record.filingRecordStatusName || "-"}
+
+ ),
+ },
+ {
+ title: "操作",
+ width: 120,
+ render: (_, record) => (
+
+ ),
+ },
+ ]}
+ />
+
+ );
+}
+
+export default Connect([NS_ORG_INFO], true)(RegisteredOrgListPage);
diff --git a/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/index.js b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/index.js
new file mode 100644
index 0000000..b7e4343
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/RegisteredOrg/index.js
@@ -0,0 +1,5 @@
+function RegisteredOrg(props) {
+ return props.children || null;
+}
+
+export default RegisteredOrg;
diff --git a/src/pages/Container/Supervision/BasicInfo/index.js b/src/pages/Container/Supervision/BasicInfo/index.js
new file mode 100644
index 0000000..9632cf4
--- /dev/null
+++ b/src/pages/Container/Supervision/BasicInfo/index.js
@@ -0,0 +1,5 @@
+function BasicInfo(props) {
+ return {props.children}
;
+}
+
+export default BasicInfo;
diff --git a/src/utils/dateFormat.js b/src/utils/dateFormat.js
index e28e6fe..60e093c 100644
--- a/src/utils/dateFormat.js
+++ b/src/utils/dateFormat.js
@@ -11,11 +11,38 @@ export function formatDateTime(value) {
/** 展示:2026-01-23 */
export function formatDate(value) {
- if (value == null || value === "") {
+ const normalized = normalizeDateValue(value);
+ if (normalized == null || normalized === "") {
return "-";
}
- const d = dayjs(value);
- return d.isValid() ? d.format("YYYY-MM-DD") : String(value);
+ const d = dayjs(normalized);
+ return d.isValid() ? d.format("YYYY-MM-DD") : String(normalized);
+}
+
+/** 兼容 Jackson LocalDateTime 数组 / 对象 / 字符串 */
+export function normalizeDateValue(value) {
+ if (value == null || value === "") {
+ return null;
+ }
+ if (typeof value === "string" || typeof value === "number") {
+ return value;
+ }
+ if (dayjs.isDayjs(value)) {
+ return value;
+ }
+ if (Array.isArray(value)) {
+ const [y, mo, d, h = 0, mi = 0, s = 0] = value;
+ return new Date(y, mo - 1, d, h, mi, s);
+ }
+ if (typeof value === "object") {
+ const y = value.year ?? value.y;
+ const mo = value.monthValue ?? value.month ?? value.m;
+ const d = value.dayOfMonth ?? value.day ?? value.d;
+ if (y != null && mo != null && d != null) {
+ return new Date(y, mo - 1, d);
+ }
+ }
+ return null;
}
/** 提交 API:日期 */