dev_1.0.1
tangjie 2026-07-01 11:55:19 +08:00
parent 8ec2de142b
commit 6cc9b9d47f
6 changed files with 160 additions and 211 deletions

View File

@ -20,7 +20,7 @@ module.exports = {
},
},
// 应用唯一标识符
appIdentifier: "certificate",
appIdentifier: "safety",
// 应用上下文注入全局变量
contextInject: {
// 应用Key

View File

@ -3,7 +3,8 @@ import { CHONGQING_DISTRICTS, QUALIFICATION_INDUSTRY_OPTIONS } from "~/enumerate
import { FILING_UNIT_TYPE_OPTIONS } from "~/enumerate/qualFilingOptions";
import FilingUpload, { resolveFilingUploadUrl } from "./FilingUpload";
export default function BasicInfoStep({ form, disabled, onAttachmentChange }) {
export default function
BasicInfoStep({ form, disabled, onAttachmentChange }) {
return (
<Form form={form} layout="vertical" disabled={disabled}>
<Row gutter={16}>

View File

@ -1,6 +1,7 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { tools } from "@cqsjjb/jjb-common-lib";
import { Button, Form, message, Modal, Space, Spin, Tabs } from "antd";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { fetchQualFilingDetail } from "~/api/qualFiling";
import { NS_QUAL_FILING } from "~/enumerate/namespace";
@ -25,7 +26,7 @@ import {
import { verifyFilingPrerequisites } from "../filingVerify";
import { toDayjs } from "~/utils/dateFormat";
import { resolveUploadFileId } from "~/utils/mockUpload";
import { goFilingList, parseFilingFormQuery } from "../filingPaths";
import { goFilingList } from "../filingPaths";
import BasicInfoStep from "./components/BasicInfoStep";
import CommitmentStep from "./components/CommitmentStep";
import EquipmentStep from "./components/EquipmentStep";
@ -48,26 +49,12 @@ const MODE_TITLE = {
};
function syncForms(detail, basicForm, commitmentForm) {
if (!detail) {
return;
}
basicForm.setFieldsValue(detail);
commitmentForm.setFieldsValue({
...detail.commitment,
filingUnitName: detail.commitment?.filingUnitName || detail.filingUnitName,
signDate: toDayjs(detail.commitment?.signDate),
});
}
function FilingFormPage(props) {
const query = useMemo(
() => parseFilingFormQuery(window.location.search),
[],
);
const query = tools.router.query;
const filingId = query.id;
const mode = query.mode;
const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [activeStep, setActiveStep] = useState("basic");
const [detail, setDetail] = useState(null);
@ -79,32 +66,21 @@ function FilingFormPage(props) {
const [activeFilingId] = useState(filingId);
const detailRef = useRef(null);
const readOnly = query.readOnly || (detail ? !isQualFilingEditable(detail.filingStatusCode) : false);
const readOnly =
query.readOnly ||
(detail ? !isQualFilingEditable(detail.filingStatusCode) : false);
const listMode = mode === FILING_FORM_MODE.FILED ? "filed" : mode === FILING_FORM_MODE.CHANGE ? "change" : "application";
const listMode =
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application";
const goBackList = useCallback(() => goFilingList(listMode), [listMode]);
const saveActionHint = mode === FILING_FORM_MODE.FILED ? "请点击提交后保存" : "请点击暂存或提交后保存";
const loadInitialDetail = useCallback(async () => {
if (activeFilingId) {
const res = await fetchQualFilingDetail(activeFilingId);
if (res?.success === false) {
message.error(res.message || "加载备案详情失败");
return null;
}
const data = res?.data || null;
if (data && !(data.materials || []).length) {
data.materials = createLocalMaterials();
}
return data;
}
const cached = loadLocalDraft(mode);
if (cached) {
return cached;
}
return createEmptyFilingDetail();
}, [activeFilingId, mode]);
const saveActionHint =
mode === FILING_FORM_MODE.FILED
? "请点击提交后保存"
: "请点击暂存或提交后保存";
const loadPersonnelOptions = useCallback(async () => {
if (personnelOptions.length) {
@ -120,45 +96,36 @@ function FilingFormPage(props) {
}, [detail]);
useEffect(() => {
let cancelled = false;
(async () => {
setLoading(true);
try {
const data = await loadInitialDetail();
if (cancelled || !data) {
return;
}
setDetail(data);
detailRef.current = data;
syncForms(data, basicForm, commitmentForm);
}
finally {
if (!cancelled) {
setLoading(false);
}
}
})();
return () => {
cancelled = true;
};
}, [basicForm, commitmentForm, loadInitialDetail]);
useEffect(() => {
if (!detail?.commitment?.legalRepPersonnelId && !detail?.commitment?.legalRepName) {
if (
!detail?.commitment?.legalRepPersonnelId &&
!detail?.commitment?.legalRepName
) {
return;
}
loadPersonnelOptions();
}, [detail?.commitment?.legalRepPersonnelId, detail?.commitment?.legalRepName, loadPersonnelOptions]);
}, [
detail?.commitment?.legalRepPersonnelId,
detail?.commitment?.legalRepName,
loadPersonnelOptions,
]);
useEffect(() => {
if (activeStep !== "commitment" && !detail?.commitment?.legalRepPersonnelId) {
if (
activeStep !== "commitment" &&
!detail?.commitment?.legalRepPersonnelId
) {
return;
}
if (personnelOptions.length) {
return;
}
loadPersonnelOptions();
}, [activeStep, detail?.commitment?.legalRepPersonnelId, loadPersonnelOptions, personnelOptions.length]);
}, [
activeStep,
detail?.commitment?.legalRepPersonnelId,
loadPersonnelOptions,
personnelOptions.length,
]);
useEffect(() => {
if (!personnelOptions.length) {
@ -167,11 +134,16 @@ function FilingFormPage(props) {
const data = detailRef.current;
const commitment = data?.commitment || {};
if (commitment.legalRepPersonnelId) {
commitmentForm.setFieldValue("legalRepPersonnelId", String(commitment.legalRepPersonnelId));
commitmentForm.setFieldValue(
"legalRepPersonnelId",
String(commitment.legalRepPersonnelId),
);
return;
}
if (commitment.legalRepName) {
const matched = personnelOptions.find((item) => item.staffName === commitment.legalRepName);
const matched = personnelOptions.find(
(item) => item.staffName === commitment.legalRepName,
);
if (matched) {
commitmentForm.setFieldsValue({
legalRepPersonnelId: matched.value,
@ -181,16 +153,22 @@ function FilingFormPage(props) {
}
}, [commitmentForm, personnelOptions]);
const updateDetail = useCallback((updater) => {
setDetail((prev) => {
const next = typeof updater === "function" ? updater(prev) : { ...prev, ...updater };
detailRef.current = next;
if (!activeFilingId && !readOnly) {
saveLocalDraft(mode, next);
}
return next;
});
}, [activeFilingId, mode, readOnly]);
const updateDetail = useCallback(
(updater) => {
setDetail((prev) => {
const next =
typeof updater === "function"
? updater(prev)
: { ...prev, ...updater };
detailRef.current = next;
if (!activeFilingId && !readOnly) {
saveLocalDraft(mode, next);
}
return next;
});
},
[activeFilingId, mode, readOnly],
);
const collectCurrentDetail = useCallback(() => {
const current = detailRef.current || detail;
@ -211,11 +189,9 @@ function FilingFormPage(props) {
clearLocalDraft(mode);
message.success("已暂存");
goBackList();
}
catch (err) {
} catch (err) {
message.error(err?.message || "暂存失败");
}
finally {
} finally {
setSubmitting(false);
}
};
@ -241,13 +217,14 @@ function FilingFormPage(props) {
clearLocalDraft(mode);
if (mode === FILING_FORM_MODE.CHANGE) {
const res = await props.qualFilingChangeSubmit({ draftFilingId: saved.id });
const res = await props.qualFilingChangeSubmit({
draftFilingId: saved.id,
});
if (res?.success === false) {
message.error(res.message || "提交失败");
return;
}
}
else {
} else {
const res = await props.qualFilingSubmit({ id: saved.id });
if (res?.success === false) {
message.error(res.message || "提交失败");
@ -257,11 +234,9 @@ function FilingFormPage(props) {
setVerifyOpen(false);
message.success("提交成功");
goBackList();
}
catch (err) {
} catch (err) {
message.error(err?.message || "提交失败");
}
finally {
} finally {
setSubmitting(false);
}
};
@ -270,16 +245,16 @@ function FilingFormPage(props) {
const attachmentUrl = url || resolveUploadFileId([]);
updateDetail((prev) => ({
...prev,
materials: (prev.materials || []).map((item) => (
materials: (prev.materials || []).map((item) =>
item.id === record.id || item.sortOrder === record.sortOrder
? {
...item,
attachmentUrl,
uploadStatusCode: 2,
uploadStatusName: "已上传",
}
: item
)),
...item,
attachmentUrl,
uploadStatusCode: 2,
uploadStatusName: "已上传",
}
: item,
),
}));
message.success(`材料已选择,${saveActionHint}`);
};
@ -289,7 +264,10 @@ function FilingFormPage(props) {
};
const handleSignatureChange = (url, files) => {
commitmentForm.setFieldsValue({ signatureFiles: files, legalRepSignatureUrl: url });
commitmentForm.setFieldsValue({
signatureFiles: files,
legalRepSignatureUrl: url,
});
updateDetail((prev) => ({
...prev,
commitment: {
@ -302,16 +280,22 @@ function FilingFormPage(props) {
const handlePersonnelAdd = (sourcePersonnelIds, rows = []) => {
const existing = new Set(
(detailRef.current?.personnelList || []).map((item) => String(item.sourcePersonnelId)),
(detailRef.current?.personnelList || []).map((item) =>
String(item.sourcePersonnelId),
),
);
const idsToAdd = sourcePersonnelIds.filter(
(id) => !existing.has(String(id)),
);
const idsToAdd = sourcePersonnelIds.filter((id) => !existing.has(String(id)));
if (!idsToAdd.length) {
return;
}
const rowMap = new Map((rows || []).map((row) => [String(row.id), row]));
const newRows = idsToAdd.map((id) => {
const row = rowMap.get(String(id));
return row ? mapStaffRowToFilingPersonnel(row) : mapStaffRowToFilingPersonnel({ id });
return row
? mapStaffRowToFilingPersonnel(row)
: mapStaffRowToFilingPersonnel({ id });
});
updateDetail((prev) => ({
...prev,
@ -327,7 +311,9 @@ function FilingFormPage(props) {
onOk: () => {
updateDetail((prev) => ({
...prev,
personnelList: (prev.personnelList || []).filter((item) => item.id !== record.id),
personnelList: (prev.personnelList || []).filter(
(item) => item.id !== record.id,
),
}));
},
});
@ -335,16 +321,22 @@ function FilingFormPage(props) {
const handleEquipmentAdd = (sourceEquipmentIds, rows = []) => {
const existing = new Set(
(detailRef.current?.equipmentList || []).map((item) => String(item.sourceEquipmentId)),
(detailRef.current?.equipmentList || []).map((item) =>
String(item.sourceEquipmentId),
),
);
const idsToAdd = sourceEquipmentIds.filter(
(id) => !existing.has(String(id)),
);
const idsToAdd = sourceEquipmentIds.filter((id) => !existing.has(String(id)));
if (!idsToAdd.length) {
return;
}
const rowMap = new Map((rows || []).map((row) => [String(row.id), row]));
const newRows = idsToAdd.map((id) => {
const row = rowMap.get(String(id));
return row ? mapEquipRowToFilingEquipment(row) : mapEquipRowToFilingEquipment({ id });
return row
? mapEquipRowToFilingEquipment(row)
: mapEquipRowToFilingEquipment({ id });
});
updateDetail((prev) => ({
...prev,
@ -360,7 +352,9 @@ function FilingFormPage(props) {
onOk: () => {
updateDetail((prev) => ({
...prev,
equipmentList: (prev.equipmentList || []).filter((item) => item.id !== record.id),
equipmentList: (prev.equipmentList || []).filter(
(item) => item.id !== record.id,
),
}));
},
});
@ -369,9 +363,9 @@ function FilingFormPage(props) {
const handleEquipmentCalibration = (record, url) => {
updateDetail((prev) => ({
...prev,
equipmentList: (prev.equipmentList || []).map((item) => (
item.id === record.id ? { ...item, calibrationReportUrl: url } : item
)),
equipmentList: (prev.equipmentList || []).map((item) =>
item.id === record.id ? { ...item, calibrationReportUrl: url } : item,
),
}));
};
@ -381,14 +375,23 @@ function FilingFormPage(props) {
return (
<PageLayout
title={MODE_TITLE[mode] || "资质备案表单"}
extra={(
<Button onClick={() => goFilingList(
mode === FILING_FORM_MODE.FILED ? "filed" : mode === FILING_FORM_MODE.CHANGE ? "change" : "application",
)}
history={props.history}
previous
extra={
<Button
onClick={() =>
goFilingList(
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application",
)
}
>
返回列表
</Button>
)}
}
>
<Spin spinning={loading || submitting}>
<Tabs
@ -397,7 +400,9 @@ function FilingFormPage(props) {
onChange={(key) => {
if (key === "commitment") {
commitmentForm.setFieldsValue({
filingUnitName: basicForm.getFieldValue("filingUnitName") || detail?.filingUnitName,
filingUnitName:
basicForm.getFieldValue("filingUnitName") ||
detail?.filingUnitName,
});
loadPersonnelOptions();
}
@ -445,28 +450,45 @@ function FilingFormPage(props) {
/>
)}
</div>
<div style={{
display: "flex",
justifyContent: "space-between",
marginTop: 24,
paddingTop: 16,
borderTop: "1px solid #f0f0f0",
}}
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: 24,
paddingTop: 16,
borderTop: "1px solid #f0f0f0",
}}
>
<Space>
<Button onClick={() => goFilingList(
mode === FILING_FORM_MODE.FILED ? "filed" : mode === FILING_FORM_MODE.CHANGE ? "change" : "application",
)}
<Button
onClick={() =>
goFilingList(
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application",
)
}
>
取消
</Button>
</Space>
<Space>
{stepIndex > 0 && (
<Button onClick={() => setActiveStep(STEP_ITEMS[stepIndex - 1].key)}>上一步</Button>
<Button
onClick={() => setActiveStep(STEP_ITEMS[stepIndex - 1].key)}
>
上一步
</Button>
)}
{!isLastStep && (
<Button type="primary" onClick={() => setActiveStep(STEP_ITEMS[stepIndex + 1].key)}>下一步</Button>
<Button
type="primary"
onClick={() => setActiveStep(STEP_ITEMS[stepIndex + 1].key)}
>
下一步
</Button>
)}
{!readOnly && isLastStep && (
<>

View File

@ -139,7 +139,7 @@ export default function FilingListTable({
<Form.Item key="filingTerritoryName" name="filingTerritoryName">
<ControlWrapper.Select
label="备案属地"
placeholder="全部"
placeholder="请输入"
allowClear
style={{ width: "100%" }}
>

View File

@ -24,12 +24,4 @@ export function goFilingList(mode) {
window.location.href = FILING_LIST_PATH[mode] || FILING_LIST_PATH.application;
}
export function parseFilingFormQuery(search = "") {
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
return {
mode: params.get("mode") || "application",
id: params.get("id") || "",
originFilingId: params.get("originFilingId") || "",
readOnly: params.get("readOnly") === "1",
};
}

View File

@ -1,74 +1,8 @@
import { Button, message, Spin } from "antd";
import { useEffect, useState } from "react";
import {
ensureOrgContext,
ORG_INFO_PAGE_PATH,
} from "~/api/enterpriseInfo/orgBootstrap";
import { getOrgInfoId, setOrgInfoId } from "~/api/enterpriseInfo/orgContext";
/** 本地联调默认机构 id与后端 application-local.yml public-api.org-id 一致) */
const LOCAL_DEV_ORG_INFO_ID = "1";
import React from "react";
/** 资质申请管理模块入口:需先有机构信息 */
function QualApplication(props) {
const [checking, setChecking] = useState(true);
const [blocked, setBlocked] = useState(false);
useEffect(() => {
let cancelled = false;
// 本地独立运行时,优先恢复 session / 默认 orgInfoId避免 getInfo 无用户关联导致卡死
if (!getOrgInfoId() && !window.__POWERED_BY_QIANKUN__) {
setOrgInfoId(LOCAL_DEV_ORG_INFO_ID);
}
ensureOrgContext({ force: true })
.then((ctx) => {
if (cancelled) {
return;
}
if (ctx?.networkError) {
message.warning("机构信息加载失败,请确认后端服务已启动");
setChecking(false);
return;
}
if (!ctx?.hasOrg) {
message.warning("请先完善机构信息");
setBlocked(true);
setChecking(false);
return;
}
setChecking(false);
})
.catch((err) => {
console.warn("[QualApplication] ensureOrgContext failed:", err);
if (!cancelled) {
message.warning("机构信息加载失败,请确认后端服务已启动");
setChecking(false);
}
});
return () => {
cancelled = true;
};
}, []);
if (checking) {
return <Spin fullscreen tip="正在加载机构信息..." />;
}
if (blocked) {
return (
<div style={{ padding: 48, textAlign: "center" }}>
<p style={{ marginBottom: 16, color: "rgba(0,0,0,0.65)" }}>
资质申请管理需先完善机构信息请前往企业信息管理 机构信息管理录入并保存
</p>
<Button type="primary" href={ORG_INFO_PAGE_PATH}>
去完善机构信息
</Button>
</div>
);
}
return (
<div style={{ height: "100%" }}>