safety-eval-service-frontend/src/pages/Container/QualApplication/FilingForm/index.js

483 lines
14 KiB
JavaScript
Raw Normal View History

2026-06-30 17:32:29 +08:00
import { Connect } from "@cqsjjb/jjb-dva-runtime";
2026-07-01 11:55:19 +08:00
import { tools } from "@cqsjjb/jjb-common-lib";
2026-06-30 17:32:29 +08:00
import { Button, Form, message, Modal, Space, Spin, Tabs } from "antd";
2026-07-01 11:55:19 +08:00
import { useCallback, useEffect, useRef, useState } from "react";
2026-06-30 17:32:29 +08:00
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
import { fetchQualFilingDetail } from "~/api/qualFiling";
import { NS_QUAL_FILING } from "~/enumerate/namespace";
import {
FILING_FORM_MODE,
isQualFilingEditable,
} from "~/enumerate/qualFilingOptions";
2026-07-01 15:07:58 +08:00
import { createLocalMaterials, FILING_MATERIAL_TEMPLATE } from "../filingMaterialTemplate";
2026-06-30 17:32:29 +08:00
import {
clearLocalDraft,
2026-07-01 15:07:58 +08:00
2026-06-30 17:32:29 +08:00
saveLocalDraft,
} from "../filingLocalDraft";
import {
fetchOrgPersonnelOptions,
mapEquipRowToFilingEquipment,
mapStaffRowToFilingPersonnel,
mergeDetailFromForms,
persistFilingToBackend,
} from "../filingPersist";
import { verifyFilingPrerequisites } from "../filingVerify";
import { resolveUploadFileId } from "~/utils/mockUpload";
2026-07-01 11:55:19 +08:00
import { goFilingList } from "../filingPaths";
2026-06-30 17:32:29 +08:00
import BasicInfoStep from "./components/BasicInfoStep";
import CommitmentStep from "./components/CommitmentStep";
import EquipmentStep from "./components/EquipmentStep";
import MaterialStep from "./components/MaterialStep";
import PersonnelStep from "./components/PersonnelStep";
import PrerequisiteVerifyModal from "./components/PrerequisiteVerifyModal";
const STEP_ITEMS = [
{ key: "basic", label: "1. 备案基本信息" },
{ key: "materials", label: "2. 备案材料上传" },
{ key: "commitment", label: "3. 法定代表人承诺书" },
{ key: "personnel", label: "4. 备案人员管理" },
{ key: "equipment", label: "5. 装备清单" },
];
const MODE_TITLE = {
[FILING_FORM_MODE.APPLICATION]: "资质备案申请",
[FILING_FORM_MODE.FILED]: "资质备案填报",
[FILING_FORM_MODE.CHANGE]: "修改备案信息",
};
function FilingFormPage(props) {
2026-07-01 11:55:19 +08:00
const query = tools.router.query;
2026-06-30 17:32:29 +08:00
const mode = query.mode;
2026-07-01 11:55:19 +08:00
const [loading, setLoading] = useState(false);
2026-06-30 17:32:29 +08:00
const [submitting, setSubmitting] = useState(false);
const [activeStep, setActiveStep] = useState("basic");
const [detail, setDetail] = useState(null);
const [personnelOptions, setPersonnelOptions] = useState([]);
const [verifyOpen, setVerifyOpen] = useState(false);
const [verifyResult, setVerifyResult] = useState(null);
const [basicForm] = Form.useForm();
const [commitmentForm] = Form.useForm();
const detailRef = useRef(null);
2026-07-01 11:55:19 +08:00
const readOnly =
2026-07-01 15:21:13 +08:00
query.readOnly
2026-07-01 11:55:19 +08:00
const listMode =
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application";
2026-06-30 17:32:29 +08:00
const goBackList = useCallback(() => goFilingList(listMode), [listMode]);
2026-07-01 11:55:19 +08:00
const saveActionHint =
mode === FILING_FORM_MODE.FILED
? "请点击提交后保存"
: "请点击暂存或提交后保存";
2026-06-30 17:32:29 +08:00
const loadPersonnelOptions = useCallback(async () => {
if (personnelOptions.length) {
return personnelOptions;
}
const options = await fetchOrgPersonnelOptions().catch(() => []);
setPersonnelOptions(options);
return options;
}, [personnelOptions.length]);
useEffect(() => {
detailRef.current = detail;
}, [detail]);
useEffect(() => {
loadPersonnelOptions();
2026-07-01 15:29:53 +08:00
if(query.id){
2026-07-01 17:57:42 +08:00
fetchQualFilingDetail(query.id).then((res) => {
setDetail((prev) => ({ ...prev, ...res?.data || {} }));
console.log(res?.data, 'res.data');
basicForm.setFieldsValue(res?.data || {});
2026-07-01 15:29:53 +08:00
});
}
else{
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({ ...prev, materials: FILING_MATERIAL_TEMPLATE }));
2026-07-01 15:29:53 +08:00
}
2026-07-01 15:07:58 +08:00
}, []);
2026-06-30 17:32:29 +08:00
2026-07-01 15:07:58 +08:00
2026-06-30 17:32:29 +08:00
useEffect(() => {
if (!personnelOptions.length) {
return;
}
const data = detailRef.current;
const commitment = data?.commitment || {};
if (commitment.legalRepPersonnelId) {
2026-07-01 11:55:19 +08:00
commitmentForm.setFieldValue(
"legalRepPersonnelId",
String(commitment.legalRepPersonnelId),
);
2026-06-30 17:32:29 +08:00
return;
}
if (commitment.legalRepName) {
2026-07-01 11:55:19 +08:00
const matched = personnelOptions.find(
(item) => item.staffName === commitment.legalRepName,
);
2026-06-30 17:32:29 +08:00
if (matched) {
commitmentForm.setFieldsValue({
legalRepPersonnelId: matched.value,
legalRepName: matched.staffName || matched.label,
});
}
}
}, [commitmentForm, personnelOptions]);
2026-07-01 15:07:58 +08:00
2026-06-30 17:32:29 +08:00
const collectCurrentDetail = useCallback(() => {
const current = detailRef.current || detail;
return mergeDetailFromForms(current, {
basicValues: basicForm.getFieldsValue(true),
commitmentValues: commitmentForm.getFieldsValue(true),
});
}, [basicForm, commitmentForm, detail]);
const handleSaveDraft = async () => {
if (readOnly) {
return;
}
setSubmitting(true);
try {
const currentDetail = collectCurrentDetail();
await persistFilingToBackend(props, currentDetail, mode);
clearLocalDraft(mode);
message.success("已暂存");
goBackList();
2026-07-01 11:55:19 +08:00
} catch (err) {
2026-06-30 17:32:29 +08:00
message.error(err?.message || "暂存失败");
2026-07-01 11:55:19 +08:00
} finally {
2026-06-30 17:32:29 +08:00
setSubmitting(false);
}
};
2026-07-01 17:57:42 +08:00
2026-06-30 17:32:29 +08:00
const handleSubmitRequest = () => {
if (readOnly) {
return;
}
const currentDetail = collectCurrentDetail();
const result = verifyFilingPrerequisites(currentDetail);
setVerifyResult(result);
setVerifyOpen(true);
};
const handleVerifyConfirm = async () => {
if (!verifyResult?.passed) {
return;
}
setSubmitting(true);
try {
const currentDetail = collectCurrentDetail();
2026-07-01 17:57:42 +08:00
debugger
2026-06-30 17:32:29 +08:00
const saved = await persistFilingToBackend(props, currentDetail, mode);
2026-07-01 17:57:42 +08:00
2026-06-30 17:32:29 +08:00
if (mode === FILING_FORM_MODE.CHANGE) {
2026-07-01 11:55:19 +08:00
const res = await props.qualFilingChangeSubmit({
draftFilingId: saved.id,
});
2026-06-30 17:32:29 +08:00
if (res?.success === false) {
message.error(res.message || "提交失败");
return;
}
2026-07-01 11:55:19 +08:00
} else {
2026-06-30 17:32:29 +08:00
const res = await props.qualFilingSubmit({ id: saved.id });
if (res?.success === false) {
message.error(res.message || "提交失败");
return;
}
}
setVerifyOpen(false);
message.success("提交成功");
goBackList();
2026-07-01 11:55:19 +08:00
} catch (err) {
2026-06-30 17:32:29 +08:00
message.error(err?.message || "提交失败");
2026-07-01 11:55:19 +08:00
} finally {
2026-06-30 17:32:29 +08:00
setSubmitting(false);
}
};
const handleMaterialUpload = (record, url) => {
const attachmentUrl = url || resolveUploadFileId([]);
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
2026-07-01 11:55:19 +08:00
materials: (prev.materials || []).map((item) =>
2026-07-01 17:57:42 +08:00
{
return item.id === record.id
2026-06-30 17:32:29 +08:00
? {
2026-07-01 11:55:19 +08:00
...item,
attachmentUrl,
uploadStatusCode: 2,
uploadStatusName: "已上传",
}
2026-07-01 17:57:42 +08:00
: item
}
2026-07-01 11:55:19 +08:00
),
2026-06-30 17:32:29 +08:00
}));
message.success(`材料已选择,${saveActionHint}`);
};
const handleSignatureChange = (url, files) => {
2026-07-01 11:55:19 +08:00
commitmentForm.setFieldsValue({
signatureFiles: files,
legalRepSignatureUrl: url,
});
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
commitment: {
...prev.commitment,
legalRepSignatureUrl: url,
signatureFiles: files,
},
}));
};
const handlePersonnelAdd = (sourcePersonnelIds, rows = []) => {
const existing = new Set(
2026-07-01 11:55:19 +08:00
(detailRef.current?.personnelList || []).map((item) =>
String(item.sourcePersonnelId),
),
);
const idsToAdd = sourcePersonnelIds.filter(
(id) => !existing.has(String(id)),
2026-06-30 17:32:29 +08:00
);
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));
2026-07-01 11:55:19 +08:00
return row
? mapStaffRowToFilingPersonnel(row)
: mapStaffRowToFilingPersonnel({ id });
2026-06-30 17:32:29 +08:00
});
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
personnelList: [...(prev.personnelList || []), ...newRows],
}));
message.success(`已添加至列表,${saveActionHint}`);
};
const handlePersonnelRemove = (record) => {
Modal.confirm({
title: "提示",
content: `确认删除人员「${record.personName}」?`,
onOk: () => {
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
2026-07-01 11:55:19 +08:00
personnelList: (prev.personnelList || []).filter(
(item) => item.id !== record.id,
),
2026-06-30 17:32:29 +08:00
}));
},
});
};
const handleEquipmentAdd = (sourceEquipmentIds, rows = []) => {
const existing = new Set(
2026-07-01 11:55:19 +08:00
(detailRef.current?.equipmentList || []).map((item) =>
String(item.sourceEquipmentId),
),
);
const idsToAdd = sourceEquipmentIds.filter(
(id) => !existing.has(String(id)),
2026-06-30 17:32:29 +08:00
);
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));
2026-07-01 11:55:19 +08:00
return row
? mapEquipRowToFilingEquipment(row)
: mapEquipRowToFilingEquipment({ id });
2026-06-30 17:32:29 +08:00
});
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
equipmentList: [...(prev.equipmentList || []), ...newRows],
}));
message.success(`已添加至列表,${saveActionHint}`);
};
const handleEquipmentRemove = (record) => {
Modal.confirm({
title: "提示",
content: `确认移除装备「${record.deviceName}」?`,
onOk: () => {
2026-07-01 17:57:42 +08:00
setDetail((prev) => ({
2026-06-30 17:32:29 +08:00
...prev,
2026-07-01 11:55:19 +08:00
equipmentList: (prev.equipmentList || []).filter(
(item) => item.id !== record.id,
),
2026-06-30 17:32:29 +08:00
}));
},
});
};
const handleEquipmentCalibration = (record, url) => {
updateDetail((prev) => ({
...prev,
2026-07-01 11:55:19 +08:00
equipmentList: (prev.equipmentList || []).map((item) =>
item.id === record.id ? { ...item, calibrationReportUrl: url } : item,
),
2026-06-30 17:32:29 +08:00
}));
};
const stepIndex = STEP_ITEMS.findIndex((item) => item.key === activeStep);
const isLastStep = stepIndex === STEP_ITEMS.length - 1;
return (
<PageLayout
title={MODE_TITLE[mode] || "资质备案表单"}
2026-07-01 11:55:19 +08:00
history={props.history}
previous
extra={
<Button
onClick={() =>
goFilingList(
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application",
)
}
2026-06-30 17:32:29 +08:00
>
返回列表
</Button>
2026-07-01 11:55:19 +08:00
}
2026-06-30 17:32:29 +08:00
>
<Spin spinning={loading || submitting}>
<Tabs
activeKey={activeStep}
items={STEP_ITEMS}
onChange={(key) => {
if (key === "commitment") {
commitmentForm.setFieldsValue({
2026-07-01 11:55:19 +08:00
filingUnitName:
basicForm.getFieldValue("filingUnitName") ||
detail?.filingUnitName,
2026-06-30 17:32:29 +08:00
});
2026-07-01 15:07:58 +08:00
2026-06-30 17:32:29 +08:00
}
setActiveStep(key);
}}
/>
<div style={{ marginTop: 16 }}>
{activeStep === "basic" && (
<BasicInfoStep
form={basicForm}
disabled={readOnly}
/>
)}
{activeStep === "materials" && (
<MaterialStep
materials={detail?.materials || []}
disabled={readOnly}
onUpload={handleMaterialUpload}
/>
)}
{activeStep === "commitment" && (
<CommitmentStep
form={commitmentForm}
disabled={readOnly}
personnelOptions={personnelOptions}
onSignatureChange={handleSignatureChange}
/>
)}
{activeStep === "personnel" && (
<PersonnelStep
personnelList={detail?.personnelList || []}
disabled={readOnly}
onAdd={handlePersonnelAdd}
onRemove={handlePersonnelRemove}
/>
)}
{activeStep === "equipment" && (
<EquipmentStep
equipmentList={detail?.equipmentList || []}
disabled={readOnly}
onAdd={handleEquipmentAdd}
onRemove={handleEquipmentRemove}
onUploadCalibration={handleEquipmentCalibration}
/>
)}
</div>
2026-07-01 11:55:19 +08:00
<div
style={{
display: "flex",
justifyContent: "space-between",
marginTop: 24,
paddingTop: 16,
borderTop: "1px solid #f0f0f0",
}}
2026-06-30 17:32:29 +08:00
>
<Space>
2026-07-01 11:55:19 +08:00
<Button
onClick={() =>
goFilingList(
mode === FILING_FORM_MODE.FILED
? "filed"
: mode === FILING_FORM_MODE.CHANGE
? "change"
: "application",
)
}
2026-06-30 17:32:29 +08:00
>
取消
</Button>
</Space>
<Space>
{stepIndex > 0 && (
2026-07-01 11:55:19 +08:00
<Button
onClick={() => setActiveStep(STEP_ITEMS[stepIndex - 1].key)}
>
上一步
</Button>
2026-06-30 17:32:29 +08:00
)}
{!isLastStep && (
2026-07-01 11:55:19 +08:00
<Button
type="primary"
2026-07-01 17:57:42 +08:00
onClick={() => {
console.log(basicForm.getFieldsValue());
setActiveStep(STEP_ITEMS[stepIndex + 1].key)
}}
2026-07-01 11:55:19 +08:00
>
下一步
</Button>
2026-06-30 17:32:29 +08:00
)}
{!readOnly && isLastStep && (
<>
{mode !== FILING_FORM_MODE.FILED && (
<Button onClick={handleSaveDraft}>暂存</Button>
)}
<Button type="primary" onClick={handleSubmitRequest}>
{mode === FILING_FORM_MODE.FILED ? "提交填报" : "提交申请"}
</Button>
</>
)}
</Space>
</div>
</Spin>
<PrerequisiteVerifyModal
open={verifyOpen}
result={verifyResult}
loading={submitting}
onCancel={() => setVerifyOpen(false)}
onConfirm={handleVerifyConfirm}
/>
</PageLayout>
);
}
export default Connect([NS_QUAL_FILING], true)(FilingFormPage);