safety-eval-service-frontend/docs/test-reports/测试用例/test-qual-filing-full-e2e.mjs

411 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 资质申请管理 — 三模块完整流程联调(模拟前端 persist 链路)
*
* 运行: node docs/test-reports/测试用例/test-qual-filing-full-e2e.mjs
*/
import path from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, "../../..");
const API_BASE = process.env.API_BASE || "http://127.0.0.1:8095/safety-eval";
const ORG_INFO_ID = process.env.ORG_INFO_ID || "1";
const DEFAULT_URL =
"https://s1.aigei.com/prevfiles/6f2754563be2491bad7c957904cd7d2a.jpg?e=2051020800&token=P7S2Xpzfz11vAkASLTkfHN7Fw-oOZBecqeJaxypL:CR60zg7VKDp-jUWyYls_rdvyQMM=";
const issues = [];
let passed = 0;
let failed = 0;
const ctx = {};
function log(step, msg) {
console.log(`[${step}] ${msg}`);
}
function pass(name, detail = "") {
passed += 1;
console.log(`${name}${detail ? `${detail}` : ""}`);
}
function fail(name, detail = "") {
failed += 1;
console.log(`${name}${detail ? `${detail}` : ""}`);
}
function recordIssue(module, severity, title, detail) {
issues.push({ module, severity, title, detail });
}
async function api(method, apiPath, body) {
const res = await fetch(`${API_BASE}${apiPath}`, {
method,
headers: { "Content-Type": "application/json", orgInfoId: ORG_INFO_ID },
body: body !== undefined ? JSON.stringify(body) : undefined,
});
const text = await res.text();
try {
return { httpStatus: res.status, ...JSON.parse(text) };
}
catch {
return { httpStatus: res.status, success: false, raw: text };
}
}
async function uploadAllMaterials(filingId) {
const detail = await api("GET", `/qual-filing/detail?id=${filingId}`);
for (const m of detail.data?.materials || []) {
if (!m.attachmentUrl) {
await api("POST", "/qual-filing-material/upload", { id: m.id, attachmentUrl: DEFAULT_URL });
}
}
}
const FORMAL_BASIC = {
filingTerritoryName: "渝北区",
filingTerritoryCode: "渝北区",
filingUnitName: "重庆渝安安全评价技术有限公司",
filingUnitTypeCode: "本地单位",
filingUnitTypeName: "本地单位",
businessScope: "石油加工业,化学原料、化学品及医药制造业",
registerAddress: "重庆市渝北区黄山大道中段88号",
officeAddress: "重庆市渝北区黄山大道中段88号安全评价大厦12层",
creditCode: "91500000MA5U8K9X2L",
qualCertNo: "AQPJ-渝-2024-0018",
legalPersonPhone: "王建国 / 023-67891234",
contactPhone: "陈晓明 / 13912345678",
infoDisclosureUrl: "https://www.yuan-an-safety.com/disclosure",
fixedAssetAmount: 1580,
workplaceArea: 1860,
archiveRoomArea: 120,
fulltimeEvaluatorCount: 32,
registeredEngineerCount: 12,
unitIntro: "本公司成立于2018年主要从事安全评价、安全技术服务具备独立法人资格。",
attachmentUrl: DEFAULT_URL,
};
async function persistLikeFrontend(filingId, mode = "application") {
const saveRes = await api("POST", "/qual-filing/save-draft", { id: filingId, ...FORMAL_BASIC });
if (!saveRes.success) {
throw new Error(saveRes.message || "save-draft failed");
}
await api("POST", `/qual-filing-material/init-template?filingId=${filingId}`);
await uploadAllMaterials(filingId);
const commitmentContent =
"本人是王建国是重庆渝安安全评价技术有限公司法定代表人,现代表我单位承诺如下:本单位提交的资质备案申请材料真实、准确、完整。";
await api("POST", "/qual-filing-commitment/save-or-update", {
filingId,
signDate: "2026-06-30",
legalRepSignatureUrl: DEFAULT_URL,
commitmentContent,
});
const personnelPage = await api("GET", "/org-personnel/page?current=1&size=20");
const personnelIds = (personnelPage.data || []).map((p) => p.id).filter(Boolean);
if (personnelIds.length) {
await api("POST", "/qual-filing-personnel/batch-add-from-org", {
filingId,
sourcePersonnelIds: personnelIds,
});
}
const equipPage = await api("GET", "/org-equipment/page?current=1&size=20");
const equipIds = (equipPage.data || []).map((e) => e.id).filter(Boolean);
if (equipIds.length) {
await api("POST", "/qual-filing-equipment/batch-add-from-org", {
filingId,
sourceEquipmentIds: equipIds,
});
}
return api("GET", `/qual-filing/detail?id=${filingId}`);
}
// ── 模块1资质备案申请 ──
async function testModule1Application() {
console.log("\n=== 模块1资质备案申请 ===");
const existingPage = await api("GET", "/qual-filing/page?current=1&size=5&applyTypeCode=1&filingStatusCode=5");
let filingId = existingPage.data?.[0]?.id;
if (filingId) {
pass("复用已有暂存记录", `id=${filingId}`);
}
else {
const draft = await api("POST", "/qual-filing/draft?applyTypeCode=1");
filingId = draft.data?.id;
if (draft.success && filingId) {
pass("新建申请草稿", `id=${filingId}`);
}
else {
fail("新建申请草稿", draft.message);
return;
}
}
ctx.applicationId = filingId;
const detailRes = await persistLikeFrontend(filingId);
const detail = detailRes.data || {};
pass("暂存-基本信息", detail.filingUnitName);
pass("暂存-材料10项已上传", (detail.materials || []).every((m) => m.uploadStatusCode === 2));
pass("暂存-承诺书", !!detail.commitment?.commitmentContent);
pass("暂存-人员", `count=${(detail.personnelList || []).length}`);
pass("暂存-装备", `count=${(detail.equipmentList || []).length}`);
const listRes = await api("GET", "/qual-filing/page?current=1&size=20&applyTypeCode=1");
const inList = (listRes.data || []).some((r) => String(r.id) === String(filingId));
if (inList && detail.filingStatusCode === 5) {
pass("列表-暂存记录可见", detail.filingStatusName);
}
else {
fail("列表-暂存记录可见", `status=${detail.filingStatusCode}`);
}
const reload = await api("GET", `/qual-filing/detail?id=${filingId}`);
if (reload.data?.businessScope?.includes("化学")) {
pass("回显-修改后业务范围");
}
else {
fail("回显-修改后业务范围");
}
const verifyMod = await import(path.join(ROOT, "src/pages/Container/QualApplication/filingVerify.js"));
const verifyResult = verifyMod.verifyFilingPrerequisites({
...FORMAL_BASIC,
materials: reload.data?.materials || [],
personnelList: reload.data?.personnelList || [],
equipmentList: reload.data?.equipmentList || [],
});
if (!verifyResult.passed) {
const failedItems = verifyResult.items.filter((i) => !i.passed).map((i) => i.label);
recordIssue(
"资质备案申请",
"阻塞",
"前端提交核验:人员数量/结构未通过",
`当前机构人员 ${(reload.data?.personnelList || []).length} 人,核验失败项:${failedItems.join("、")}。用户要求测试阶段暂不判断此项,但前端「提交申请」确认按钮仍被禁用。`,
);
pass("前端核验-预期失败(人员不足)", failedItems.join(","));
}
else {
pass("前端核验-全部通过");
}
const submit = await api("POST", `/qual-filing/submit?id=${filingId}`);
if (submit.success && submit.data?.filingStatusCode === 2) {
pass("后端提交-进入审核中", submit.data.filingStatusName);
}
else {
fail("后端提交", submit.message);
recordIssue("资质备案申请", "阻塞", "后端提交失败", submit.message || JSON.stringify(submit));
return;
}
const approve = await api("POST", `/qual-filing/approve?id=${filingId}`);
if (approve.success && approve.data?.filingStatusCode === 1) {
pass("审核通过-已备案", approve.data.filingStatusName);
ctx.approvedApplicationId = filingId;
}
else {
fail("审核通过", approve.message || approve.data?.filingStatusName);
}
}
// ── 模块2已备案资质管理 ──
async function testModule2FiledManage() {
console.log("\n=== 模块2已备案资质管理 ===");
const filedPage = await api("GET", "/qual-filing/filed/page?current=1&size=20");
const filedList = filedPage.data || [];
if (filedList.length > 0) {
pass("已备案列表有数据", `count=${filedList.length}`);
ctx.originFiledId = filedList[0].id;
}
else {
fail("已备案列表有数据", "审核通过后应出现 applyType=3 记录");
recordIssue("已备案资质管理", "阻塞", "审核通过后已备案列表为空", "需确认 approve 是否创建 filed 记录");
return;
}
const origin = filedList[0];
if (origin.applyTypeCode === 3) {
pass("已备案记录类型", origin.applyTypeName);
}
else {
fail("已备案记录类型", `applyTypeCode=${origin.applyTypeCode}`);
}
const filedDraft = await api("POST", "/qual-filing/filed/draft");
const filedDraftId = filedDraft.data?.id;
if (!filedDraft.success || !filedDraftId) {
fail("资质备案填报-创建草稿", filedDraft.message);
return;
}
pass("资质备案填报-创建草稿", `id=${filedDraftId}`);
ctx.filedDraftId = filedDraftId;
const saveRes = await persistLikeFrontend(filedDraftId);
const detail = saveRes.data || {};
if (detail.filingStatusCode === 5 && detail.applyTypeCode === 3) {
pass("填报暂存", `${detail.filingStatusName} applyType=${detail.applyTypeCode}`);
}
else {
fail("填报暂存", `status=${detail.filingStatusCode} type=${detail.applyTypeCode}`);
}
const filedPageDefault = await api("GET", "/qual-filing/filed/page?current=1&size=20");
const draftInDefaultList = (filedPageDefault.data || []).some((r) => String(r.id) === String(filedDraftId));
if (!draftInDefaultList) {
pass("已备案列表-默认不含填报暂存");
}
else {
fail("已备案列表-默认不含填报暂存");
recordIssue("已备案资质管理", "一般", "填报暂存不应出现在默认已备案列表", `draftId=${filedDraftId}`);
}
const filedPageDraftFilter = await api("GET", "/qual-filing/filed/page?current=1&size=20&filingStatusCode=5");
const draftInFilteredList = (filedPageDraftFilter.data || []).some((r) => String(r.id) === String(filedDraftId));
if (draftInFilteredList) {
pass("已备案列表-显式筛选暂存可见");
}
else {
fail("已备案列表-显式筛选暂存可见", `draftId=${filedDraftId}`);
}
}
// ── 模块3备案变更管理 ──
async function testModule3FilingChange() {
console.log("\n=== 模块3备案变更管理 ===");
const originId = ctx.originFiledId;
if (!originId) {
fail("发起变更", "无已备案 origin 记录");
return;
}
const changePage = await api("GET", "/qual-filing/change/page?current=1&size=20");
const changeList = changePage.data || [];
if (changeList.length > 0) {
pass("变更列表有数据", `count=${changeList.length}`);
}
else {
fail("变更列表有数据", "应有已备案记录");
}
const origin = changeList.find((r) => String(r.id) === String(originId)) || changeList[0];
if (!origin) {
fail("变更源记录", "未找到");
return;
}
if (origin.filingStatusCode === 4) {
recordIssue("备案变更管理", "阻塞", "已备案记录处于变更审核中", "无法再次发起变更");
fail("可发起变更", "状态=变更审核中");
return;
}
pass("可发起变更", origin.filingStatusName);
const start = await api("POST", `/qual-filing-change/start?originFilingId=${originId}`);
const draftId = start.data?.draftFilingId || start.data;
if (!start.success || !draftId) {
fail("发起变更", start.message);
return;
}
pass("发起变更", `draftId=${draftId}`);
ctx.changeDraftId = draftId;
const changeBasic = {
...FORMAL_BASIC,
businessScope: "石油加工业,化学原料、化学品及医药制造业;金属、非金属矿及其他矿采选业",
unitIntro: "变更后:新增矿山采选业安全评价业务范围。",
};
await api("POST", "/qual-filing/save-draft", { id: draftId, ...changeBasic });
await uploadAllMaterials(draftId);
await api("POST", "/qual-filing-commitment/save-or-update", {
filingId: draftId,
signDate: "2026-06-30",
legalRepSignatureUrl: DEFAULT_URL,
commitmentContent: "变更备案承诺书",
});
const changeDetail = await api("GET", `/qual-filing/detail?id=${draftId}`);
if (changeDetail.data?.businessScope?.includes("矿采选业")) {
pass("变更草稿-业务范围已修改");
}
else {
fail("变更草稿-业务范围已修改", changeDetail.data?.businessScope);
}
const changeSubmit = await api("POST", "/qual-filing-change/submit", { draftFilingId: draftId });
if (changeSubmit.success) {
pass("提交变更", "success");
}
else {
fail("提交变更", changeSubmit.message);
recordIssue("备案变更管理", "阻塞", "变更提交失败", changeSubmit.message);
return;
}
const history = await api("GET", `/qual-filing-change/history?originFilingId=${originId}`);
const changeCount = history.data?.changeCount ?? 0;
if (history.success && changeCount > 0) {
pass("变更历史", `changeCount=${changeCount}`);
}
else {
fail("变更历史", `count=${changeCount}`);
}
const changeAfter = await api("GET", "/qual-filing/change/page?current=1&size=20");
const updated = (changeAfter.data || []).find((r) => String(r.id) === String(originId));
if (updated?.changeCount > 0) {
pass("变更列表-变更次数更新", `${updated.filingStatusName} count=${updated.changeCount}`);
}
else {
fail("变更列表-变更次数更新");
recordIssue("备案变更管理", "一般", "变更列表变更次数未更新", `originId=${originId}`);
}
}
async function checkDataQuality() {
console.log("\n=== 数据质量检查 ===");
const personnelPage = await api("GET", "/org-personnel/page?current=1&size=10");
const missingName = (personnelPage.data || []).filter((p) => !p.personName && !p.staffName);
if (missingName.length) {
recordIssue(
"通用",
"一般",
"机构人员主数据姓名为空",
`${missingName.length} 条人员记录 personName/staffName 为空,表单人员列表可能显示空白。`,
);
pass("人员主数据-姓名缺失(已知)", `count=${missingName.length}`);
}
}
async function main() {
console.log("资质申请管理 — 三模块完整流程联调");
console.log(`API=${API_BASE} orgInfoId=${ORG_INFO_ID}\n`);
await checkDataQuality();
await testModule1Application();
await testModule2FiledManage();
await testModule3FilingChange();
console.log(`\n=== 结果: ${passed} 通过, ${failed} 失败 ===`);
console.log(`=== 问题记录: ${issues.length} 条 ===\n`);
for (const [i, issue] of issues.entries()) {
console.log(`${i + 1}. [${issue.module}] [${issue.severity}] ${issue.title}`);
console.log(` ${issue.detail}\n`);
}
return { passed, failed, issues, ctx };
}
const result = await main();
if (result.failed > 0) {
process.exitCode = 1;
}
export default result;