refactor: simplify product copy
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent
248078113c
commit
b9fbd4c6af
+50
-50
@@ -738,7 +738,7 @@ const contracts = {
|
||||
key: "JOB-SIGNAL",
|
||||
title: "外部招聘岗位信号标准",
|
||||
version: "V3.0.0",
|
||||
description: "统一商业招聘平台、公共就业平台和活动聚合平台的岗位、企业、薪资、技能与来源证据,用于产教供需分析。",
|
||||
description: "规定商业招聘平台、公共就业平台和招聘活动数据中的岗位、企业、薪资、技能与来源字段,供产教分析使用。",
|
||||
schemaPath: "./schemas/external-job-source.schema.json",
|
||||
fields: 39,
|
||||
required: 19,
|
||||
@@ -748,7 +748,7 @@ const contracts = {
|
||||
compatibility: "向后兼容 V2.6",
|
||||
fieldsPreview: [
|
||||
["record_id", "string/uuid", "是", "平台记录唯一标识", "UUID v4"],
|
||||
["source_platform", "string", "是", "来源平台代码", "受控代码表"],
|
||||
["source_platform", "string", "是", "来源平台代码", "固定代码表"],
|
||||
["source_record_id", "string", "是", "来源记录标识", "同平台唯一"],
|
||||
["source_url", "string/uri", "是", "来源页面或接口定位", "http/https"],
|
||||
["collected_at", "datetime", "是", "实际采集时间", "ISO-8601 +08:00"],
|
||||
@@ -767,14 +767,14 @@ const contracts = {
|
||||
["来源证据", "必须保留 source_url、collected_at、content_hash 和采集任务编号。"],
|
||||
["薪资口径", "统一折算为税前月薪;面议、日薪、时薪保留原文并标注换算状态。"],
|
||||
["时效与失效", "岗位状态和最后发现时间分开记录;失效采用版本化软删除。"],
|
||||
["文本治理", "岗位职责原文进入原始层,分析层只保留去标记、去联系方式后的业务文本。"],
|
||||
["文本处理", "岗位职责原文保存在原始层,分析层只保留去标记、去联系方式后的业务文本。"],
|
||||
],
|
||||
},
|
||||
"school-employment": {
|
||||
key: "SCHOOL-EMPLOYMENT",
|
||||
title: "校内就业事实数据标准",
|
||||
title: "校内就业数据标准",
|
||||
version: "V2.2.0",
|
||||
description: "统一学校毕业生就业状态、岗位、企业、薪资、专业相关度和去向确认事实,支持租户隔离和敏感字段最小化。",
|
||||
description: "规定学校毕业生就业状态、岗位、企业、薪资、专业相关度和去向确认字段,并要求租户隔离,只保留业务必需的敏感字段。",
|
||||
schemaPath: "./schemas/school-employment.schema.json",
|
||||
fields: 32,
|
||||
required: 16,
|
||||
@@ -787,7 +787,7 @@ const contracts = {
|
||||
["student_token", "string", "是", "学生不可逆令牌", "禁止明文学号"],
|
||||
["cohort", "integer", "是", "毕业届次", "YYYY"],
|
||||
["program_code", "string", "是", "专业代码", "教育部专业目录"],
|
||||
["employment_status", "string", "是", "就业状态", "受控枚举"],
|
||||
["employment_status", "string", "是", "就业状态", "固定选项"],
|
||||
["job_title", "string", "否", "就业岗位", "业务原文"],
|
||||
["enterprise_token", "string", "否", "企业统一标识", "信用代码令牌化"],
|
||||
["salary_monthly", "number", "否", "税前月薪", "元/月"],
|
||||
@@ -806,9 +806,9 @@ const contracts = {
|
||||
},
|
||||
"school-internship": {
|
||||
key: "SCHOOL-INTERNSHIP",
|
||||
title: "校内实习事实数据标准",
|
||||
title: "校内实习数据标准",
|
||||
version: "V2.1.0",
|
||||
description: "统一学生实习岗位、企业、起止日期、状态、工资、岗位任务和评价事实,支持租户隔离和敏感身份最小化。",
|
||||
description: "规定学生实习岗位、企业、起止日期、状态、工资、岗位任务和评价字段,并要求租户隔离,只保留业务必需的身份字段。",
|
||||
schemaPath: "./schemas/school-internship.schema.json",
|
||||
fields: 30,
|
||||
required: 14,
|
||||
@@ -826,7 +826,7 @@ const contracts = {
|
||||
["job_tasks", "array<string>", "否", "实习岗位任务", "学校确认"],
|
||||
["start_date", "date", "是", "开始日期", "YYYY-MM-DD"],
|
||||
["end_date", "date", "否", "结束日期", "YYYY-MM-DD"],
|
||||
["status", "string", "是", "实习状态", "受控枚举"],
|
||||
["status", "string", "是", "实习状态", "固定选项"],
|
||||
["salary_monthly", "number", "否", "税前月实习工资", "元/月"],
|
||||
["evidence_reference", "string", "否", "校内证据引用", "不传附件"],
|
||||
["source_updated_at", "datetime", "否", "业务更新时间", "增量水位"],
|
||||
@@ -837,7 +837,7 @@ const contracts = {
|
||||
["身份最小化", "平台只接收 student_token,拒绝姓名、身份证、手机号、邮箱和明文学号。"],
|
||||
["企业要求", "进行中或已完成实习必须提供企业令牌或企业名称。"],
|
||||
["证据引用", "敏感附件保留在学校系统,平台只保存 evidence_reference。"],
|
||||
["增量幂等", "tenant_id + source_record_id + source_updated_at 形成增量与幂等边界。"],
|
||||
["增量重复处理", "使用 tenant_id + source_record_id + source_updated_at 判断增量更新,并确保重复提交不会重复写入。"],
|
||||
],
|
||||
},
|
||||
"package-manifest": {
|
||||
@@ -1381,7 +1381,7 @@ const operationsStatusLabels = {
|
||||
INVESTIGATING: "排障中",
|
||||
QUALITY_REVIEW_PENDING: "待质量复核",
|
||||
VERIFIED: "复核通过",
|
||||
REVIEWED_BLOCKED: "复核后仍阻断",
|
||||
REVIEWED_BLOCKED: "复核后仍不能发布",
|
||||
RESOLVED: "已解决",
|
||||
CLOSED: "已关闭",
|
||||
OPEN: "已建单",
|
||||
@@ -1401,7 +1401,7 @@ const operationsStatusLabels = {
|
||||
PENDING_REVIEW: "待复核",
|
||||
RECORDED: "已记录",
|
||||
PASS: "通过",
|
||||
BLOCKED: "阻断",
|
||||
BLOCKED: "不能继续",
|
||||
ROLLBACK_PENDING_APPROVAL: "回滚待审批",
|
||||
ROLLBACK_APPROVED: "回滚已批准",
|
||||
ROLLBACK_REJECTED: "回滚已驳回",
|
||||
@@ -1537,7 +1537,7 @@ function renderOperationsMetrics() {
|
||||
const deliveryAttention = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status)).length;
|
||||
const acknowledged = operationsStore.deliveries.filter((delivery) => delivery.status === "ACKNOWLEDGED").length;
|
||||
document.getElementById("operationsMetrics").innerHTML = `
|
||||
<article><span>未闭环问题</span><strong>${openIssues}</strong><small>确认、指派、排障与质量处置</small></article>
|
||||
<article><span>未处理完问题</span><strong>${openIssues}</strong><small>确认、指派、排障与质量处置</small></article>
|
||||
<article><span>审批待办</span><strong>${pendingApprovals}</strong><small>申请人与审批人强制分离</small></article>
|
||||
<article><span>交付待办 / 异常</span><strong>${deliveryAttention}</strong><small>按租户隔离,不重复发送成功学校</small></article>
|
||||
<article><span>已核验回执</span><strong>${acknowledged}</strong><small>记录数与 SHA-256 均一致</small></article>
|
||||
@@ -1552,8 +1552,8 @@ function renderOperationsMetrics() {
|
||||
const qualityDetail = document.getElementById("qualityReleaseDetail");
|
||||
if (overviewState) overviewState.textContent = release?.status === "PUBLISHED" ? "稳定版本已发布" : releaseReady ? "候选可提交审批" : "候选发布受阻";
|
||||
if (overviewDetail) overviewDetail.textContent = release?.qualityGate === "PASS" ? (release?.manifestGeneratedAt ? "质量与候选 Manifest 已就绪" : "质量通过,待生成候选 Manifest") : "杭州人才网修复重放尚未验证";
|
||||
if (qualityState) qualityState.textContent = release?.qualityGate === "PASS" ? "当前批次质量门禁已通过" : "当前批次仍需修复重放复核";
|
||||
if (qualityDetail) qualityDetail.textContent = release?.qualityGate === "PASS" ? "质量证据已通过独立复核,可继续生成候选包" : "质量分达标不等于门禁通过,稳定版本继续保持不变";
|
||||
if (qualityState) qualityState.textContent = release?.qualityGate === "PASS" ? "当前批次已满足发布质量要求" : "当前批次仍需修复重放复核";
|
||||
if (qualityDetail) qualityDetail.textContent = release?.qualityGate === "PASS" ? "质量记录已经另一名复核人确认,可继续生成候选包" : "仅质量分达标还不能发布,当前稳定版本保持不变";
|
||||
}
|
||||
|
||||
function renderOverviewIssues() {
|
||||
@@ -1571,7 +1571,7 @@ function renderOverviewIssues() {
|
||||
`,
|
||||
)
|
||||
.join("")
|
||||
: `<div class="info-note">当前没有待处理问题,所有事项均已闭环。</div>`;
|
||||
: `<div class="info-note">当前没有待处理问题。</div>`;
|
||||
const countBadge = list.closest(".alert-panel").querySelector(".panel-head > em");
|
||||
countBadge.textContent = `${issues.length} 项`;
|
||||
}
|
||||
@@ -1595,7 +1595,7 @@ function renderOperationsIssues() {
|
||||
.join("");
|
||||
document.getElementById("operationsIssueTable").innerHTML = rows;
|
||||
const openCount = operationsStore.issues.filter((issue) => !["RESOLVED", "CLOSED"].includes(issue.status)).length;
|
||||
document.getElementById("issueQueueSummary").textContent = `${openCount} 项未闭环 · 状态刷新后保留`;
|
||||
document.getElementById("issueQueueSummary").textContent = `${openCount} 项未处理完 · 状态刷新后保留`;
|
||||
}
|
||||
|
||||
function releaseNextAction(release, approval) {
|
||||
@@ -1606,7 +1606,7 @@ function releaseNextAction(release, approval) {
|
||||
if (release.status === "PENDING_APPROVAL") {
|
||||
return `
|
||||
<label class="approval-field"><span>独立审批人</span><select id="releaseApprover"><option value="林若溪">林若溪 · 数据产品负责人</option><option value="王海宁">王海宁 · 发布审批人</option><option value="陈致远">陈致远 · 当前申请人</option></select></label>
|
||||
<label class="approval-field approval-comment"><span>审批意见</span><input id="approvalComment" value="质量门禁与租户范围已复核" /></label>
|
||||
<label class="approval-field approval-comment"><span>审批意见</span><input id="approvalComment" value="质量检查结果与租户范围已复核" /></label>
|
||||
<button class="button secondary" data-release-reject>驳回</button>
|
||||
<button class="button primary" data-release-approve>批准</button>
|
||||
`;
|
||||
@@ -1654,7 +1654,7 @@ function renderReleaseWorkspace() {
|
||||
<span><small>上一稳定版本</small><strong>${h(release.previousStableVersion)}</strong></span>
|
||||
</div>
|
||||
<div class="release-facts">
|
||||
<span><small>质量门禁</small><strong class="${release.qualityGate === "PASS" ? "gate-pass" : "gate-blocked"}">${h(operationStatusLabel(release.qualityGate))} · ${release.qualityScore}</strong></span>
|
||||
<span><small>发布质量检查</small><strong class="${release.qualityGate === "PASS" ? "gate-pass" : "gate-blocked"}">${h(operationStatusLabel(release.qualityGate))} · ${release.qualityScore}</strong></span>
|
||||
<span><small>影响租户</small><strong>${release.impactTenants.length} 所学校</strong></span>
|
||||
<span><small>申请人</small><strong>${h(release.applicant)}</strong></span>
|
||||
<span><small>Manifest</small><strong>${release.publishedManifestGeneratedAt ? `发布版已生成 · ${h(operationTime(release.publishedManifestGeneratedAt))}` : release.manifestGeneratedAt ? `候选已生成 · ${h(operationTime(release.manifestGeneratedAt))}` : "尚未生成"}</strong></span>
|
||||
@@ -1662,11 +1662,11 @@ function renderReleaseWorkspace() {
|
||||
<div class="release-quality-note ${release.qualityGate === "PASS" ? "passed" : ""}">
|
||||
${
|
||||
release.status === "PUBLISHED"
|
||||
? "质量证据、候选 Manifest 与独立审批已冻结,正式发布 Manifest 已生成;当前尚未代表学校接收。"
|
||||
? "发布使用的质量记录、候选 Manifest 和审批结果均不可修改,正式发布 Manifest 已生成;这不表示学校已经接收。"
|
||||
: release.status === "ROLLED_BACK"
|
||||
? `稳定别名已回滚到 ${h(release.previousStableVersion)},原发布、审批和租户交付记录继续保留审计。`
|
||||
: release.status === "PENDING_APPROVAL"
|
||||
? "候选 Manifest 已冻结,正在等待不同于申请人的独立审批人处理。"
|
||||
? "候选 Manifest 已提交,审批完成前不能修改,正在等待另一名审批人处理。"
|
||||
: release.status === "APPROVED"
|
||||
? "独立审批已通过,可以执行稳定别名切换并生成正式发布 Manifest。"
|
||||
: release.status === "REJECTED"
|
||||
@@ -1675,7 +1675,7 @@ function renderReleaseWorkspace() {
|
||||
? release.manifestGeneratedAt
|
||||
? "修复重放证据与候选 Manifest 已就绪,可以提交独立发布审批。"
|
||||
: "修复重放已由独立复核人验证;还必须生成候选 Manifest 后才能提交审批。"
|
||||
: "质量门禁阻断:只有 FIX_REPLAY 的记录数、规则结果与复核签名全部验证通过才能解锁;豁免或丢弃均保持阻断。"
|
||||
: "当前不能发布:只有 FIX_REPLAY 的记录数、规则结果和复核签名全部通过检查才可继续;豁免或丢弃仍不能发布。"
|
||||
}
|
||||
</div>
|
||||
<div class="candidate-actions">
|
||||
@@ -1684,9 +1684,9 @@ function renderReleaseWorkspace() {
|
||||
? `<button class="button secondary" data-release-official-manifest>下载发布 Manifest</button>`
|
||||
: release.status === "DRAFT"
|
||||
? `<button class="button secondary" data-release-manifest ${release.qualityGate === "PASS" ? "" : "disabled"}>${release.qualityGate === "PASS" ? (release.manifestGeneratedAt ? "重新生成候选 Manifest" : "生成候选包 / Manifest") : "质量通过后生成 Manifest"}</button>`
|
||||
: `<span class="release-final-note">候选 Manifest 已冻结,审批中不可重建。</span>`
|
||||
: `<span class="release-final-note">候选 Manifest 已提交,审批中不能重建。</span>`
|
||||
}
|
||||
<button class="text-button" data-open-issue="ISSUE-HZRC-20260823-01">查看阻断问题</button>
|
||||
<button class="text-button" data-open-issue="ISSUE-HZRC-20260823-01">查看未解决问题</button>
|
||||
</div>
|
||||
</article>
|
||||
<article class="panel approval-card">
|
||||
@@ -1771,7 +1771,7 @@ function issueActionFooter(issue) {
|
||||
const qualityReviewAction =
|
||||
disposition?.action === "FIX_REPLAY"
|
||||
? `<button class="button primary" data-issue-action="verify">验证重放并通过</button>`
|
||||
: `<button class="button primary" data-issue-action="verify-blocked">完成复核并保持阻断</button>`;
|
||||
: `<button class="button primary" data-issue-action="verify-blocked">完成复核,仍不允许发布</button>`;
|
||||
const actions = {
|
||||
ALERTED: `<button class="button primary" data-issue-action="acknowledge">确认告警</button>`,
|
||||
ACKNOWLEDGED: `<label class="footer-field"><span>指派负责人</span><select id="issueAssignee"><option>周敏 · 区域源运维</option><option>赵亦辰 · 采集工程师</option><option>数据标准组</option></select></label><button class="button primary" data-issue-action="assign">确认指派</button>`,
|
||||
@@ -1782,7 +1782,7 @@ function issueActionFooter(issue) {
|
||||
QUALITY_REVIEW_PENDING: qualityReviewAction,
|
||||
VERIFIED: `<button class="button primary" data-issue-action="resolve">标记已解决</button>`,
|
||||
RESOLVED: `<button class="button primary" data-issue-action="close">关闭问题</button>`,
|
||||
CLOSED: `<span class="release-final-note">问题已闭环,所有动作与证据已保留。</span>`,
|
||||
CLOSED: `<span class="release-final-note">问题已完成处理,操作记录和附件已保留。</span>`,
|
||||
};
|
||||
return `<button class="button secondary" data-issue-close>关闭抽屉</button>${actions[issue.status] || ""}`;
|
||||
}
|
||||
@@ -2063,7 +2063,7 @@ function renderSourceMapping(source) {
|
||||
</article>
|
||||
<article class="drawer-card">
|
||||
<h3>样本回归</h3>
|
||||
<p>最近回归样本 1,000 条,结构通过率 100%,必填完整率 98.8%,岗位归一覆盖率 96.4%。未匹配岗位进入人工复核队列,不以模型推断覆盖原始事实。</p>
|
||||
<p>最近回归样本 1,000 条,结构通过率 100%,必填完整率 98.8%,岗位归一覆盖率 96.4%。未匹配岗位进入人工复核队列,不用模型推断替换原始记录。</p>
|
||||
</article>
|
||||
`;
|
||||
}
|
||||
@@ -2103,7 +2103,7 @@ function renderSourceAudit(source) {
|
||||
</article>
|
||||
<article class="drawer-card">
|
||||
<h3>数据使用边界</h3>
|
||||
<p>平台只向产教分析产品交付经契约治理的岗位信号、企业画像和统计结果。原始层与交付层分区存储,租户交付范围由 Manifest 和平台数据范围策略共同控制。</p>
|
||||
<p>平台只向产教分析产品交付符合数据契约的岗位信息、企业信息和统计结果。原始数据与交付数据分开存储,Manifest 和租户授权共同决定每所学校可收到的数据。</p>
|
||||
</article>
|
||||
`;
|
||||
}
|
||||
@@ -2461,7 +2461,7 @@ function openStandardRecord(recordId) {
|
||||
</dl>
|
||||
</article>
|
||||
<article class="drawer-card">
|
||||
<h3>全链路证据</h3>
|
||||
<h3>来源与处理记录</h3>
|
||||
<div class="record-lineage">
|
||||
<span><b>01</b><span><strong>采集任务</strong><small>${h(record.taskId)} · ${h(record.collectorVersion)}</small></span></span>
|
||||
<span><b>02</b><span><strong>原始快照</strong><small>${h(record.snapshotId)} · payload SHA-256 ${h(record.payloadHash)}</small></span></span>
|
||||
@@ -2843,8 +2843,8 @@ function buildPackageManifest(options = {}) {
|
||||
generated_by: "陈致远",
|
||||
approval_reference: approval ? `${approval.id}:${approvalStatus}` : null,
|
||||
notes: published
|
||||
? "该文件是独立审批通过后生成的发布 Manifest;静态原型只记录本地稳定版本状态,不会向学校真实发送。"
|
||||
: "该文件仅为候选包 Manifest;只有独立审批通过并执行发布后才成为稳定版本,静态原型不会向学校真实发送。",
|
||||
? "该文件是独立审批通过后生成的发布 Manifest;静态原型只记录本地稳定版本状态,不会向学校发送。"
|
||||
: "该文件仅为候选包 Manifest;只有独立审批通过并执行发布后才成为稳定版本,静态原型不会向学校发送。",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2852,11 +2852,11 @@ function generateCandidateManifest() {
|
||||
const release = currentRelease();
|
||||
updateReleaseQualityGate();
|
||||
if (!release || release.status !== "DRAFT") {
|
||||
showToast("候选已进入审批或发布流程,Manifest 已冻结;驳回后需返回草稿重建", "无法重建候选 Manifest");
|
||||
showToast("候选已提交审批或发布,当前 Manifest 不能修改;驳回后可返回草稿重建", "无法重建候选 Manifest");
|
||||
return;
|
||||
}
|
||||
if (release.qualityGate !== "PASS") {
|
||||
showToast("只有 FIX_REPLAY 的完整验证证据通过后才能生成候选 Manifest", "质量门禁阻断");
|
||||
showToast("只有 FIX_REPLAY 的记录数、规则结果和复核签名全部通过检查后,才能生成候选 Manifest", "当前不能生成候选");
|
||||
return;
|
||||
}
|
||||
const inputFingerprint = candidateManifestInputFingerprint();
|
||||
@@ -3428,7 +3428,7 @@ function setupAudit() {
|
||||
openInfoModal(
|
||||
"AUDIT POLICY",
|
||||
"生产审计与留存策略",
|
||||
`<div class="info-grid"><span>关键事件留存<strong>36个月</strong></span><span>审计存储<strong>WORM</strong></span><span>每日完整性校验<strong>SHA-256</strong></span><span>追踪覆盖率<strong>100%</strong></span></div><div class="info-note">采集请求、连接器版本、原始快照、映射规则、质量结果、审批和租户交付都写入统一 trace_id。敏感配置只记录密钥引用和变更摘要,不在日志中保存明文凭据。</div>`,
|
||||
`<div class="info-grid"><span>关键事件留存<strong>36个月</strong></span><span>审计存储<strong>WORM</strong></span><span>每日完整性校验<strong>SHA-256</strong></span><span>追踪覆盖率<strong>100%</strong></span></div><div class="info-note">采集请求、连接器版本、原始快照、映射规则、质量结果、审批和租户交付都使用同一个 trace_id。敏感配置只记录密钥引用和变更摘要,不在日志中保存明文凭据。</div>`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -3482,7 +3482,7 @@ function setupOperations() {
|
||||
return;
|
||||
}
|
||||
if (action === "investigate" && issue.status === "ASSIGNED") {
|
||||
transitionIssue(issue, "INVESTIGATING", "已锁定源端时延与解析隔离记录,开始执行排障。", ["排障工作区快照", issue.relatedTask]);
|
||||
transitionIssue(issue, "INVESTIGATING", "已确认问题来自源端延迟,并找到对应的解析隔离记录,开始排障。", ["排障工作区快照", issue.relatedTask]);
|
||||
return;
|
||||
}
|
||||
if (action === "submit-quality" && issue.status === "INVESTIGATING") {
|
||||
@@ -3548,7 +3548,7 @@ function setupOperations() {
|
||||
renderOperations();
|
||||
renderAudit();
|
||||
openIssueDrawer(issue.id);
|
||||
showToast("处置动作已固化并写入审计,等待独立质量复核", "质量处置已提交");
|
||||
showToast("处置动作已保存且不能修改,等待另一名质量复核人处理", "质量处置已提交");
|
||||
return;
|
||||
}
|
||||
if (action === "verify-blocked" && issue.status === "QUALITY_REVIEW_PENDING") {
|
||||
@@ -3574,8 +3574,8 @@ function setupOperations() {
|
||||
evidence: [...metadata.evidence],
|
||||
note:
|
||||
disposition.action === "WAIVE"
|
||||
? "风险豁免不等同于质量验证通过;候选门禁保持阻断,必须另行提交风险审批。"
|
||||
: "丢弃可能改变数据完整性;候选门禁保持阻断,必须重建候选并重新执行质量验证。",
|
||||
? "风险豁免不等同于质量验证通过;候选版本仍不能发布,必须另行提交风险审批。"
|
||||
: "丢弃可能改变数据完整性;候选版本仍不能发布,必须重建候选并重新执行质量检查。",
|
||||
});
|
||||
const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id);
|
||||
if (workOrder) migrateOperationsEntity(workOrder, "INVESTIGATING", metadata);
|
||||
@@ -3584,13 +3584,13 @@ function setupOperations() {
|
||||
renderOperations();
|
||||
renderAudit();
|
||||
openIssueDrawer(issue.id);
|
||||
showToast(`${actionLabel}已复核,但不能解除发布门禁`, "质量门禁仍阻断");
|
||||
showToast(`${actionLabel}已复核,但当前候选版本仍不能发布`, "仍不满足发布条件");
|
||||
return;
|
||||
}
|
||||
if (action === "verify" && issue.status === "QUALITY_REVIEW_PENDING") {
|
||||
const disposition = latestQualityDisposition(issue.id);
|
||||
if (!disposition || disposition.action !== "FIX_REPLAY") {
|
||||
showToast("只有修复并重放可以进入质量验证通过状态", "质量门禁仍阻断");
|
||||
showToast("只有修复并重放可以进入质量检查通过状态", "仍不满足发布条件");
|
||||
return;
|
||||
}
|
||||
const metadata = addOperationsAudit({
|
||||
@@ -3616,7 +3616,7 @@ function setupOperations() {
|
||||
time: metadata.time,
|
||||
trace: metadata.trace,
|
||||
evidence: [...metadata.evidence],
|
||||
note: "记录数、质量规则与重放证据已复核,候选版本质量门禁解除。",
|
||||
note: "记录数、质量规则和重放记录已复核,候选版本可以继续提交审批。",
|
||||
});
|
||||
const workOrder = operationsStore.workOrders.find((item) => item.issueId === issue.id);
|
||||
if (workOrder) migrateOperationsEntity(workOrder, "VERIFIED", metadata);
|
||||
@@ -3625,7 +3625,7 @@ function setupOperations() {
|
||||
renderOperations();
|
||||
renderAudit();
|
||||
openIssueDrawer(issue.id);
|
||||
showToast("质量处置已 VERIFIED,候选版本现在可提交审批", "质量门禁已通过");
|
||||
showToast("质量处置已 VERIFIED,候选版本现在可提交审批", "已满足发布质量要求");
|
||||
return;
|
||||
}
|
||||
if (action === "resolve" && (issue.status === "VERIFIED" || (issue.status === "INVESTIGATING" && !issue.qualityRequired))) {
|
||||
@@ -3645,7 +3645,7 @@ function setupOperations() {
|
||||
}
|
||||
if (event.target.closest("[data-release-official-manifest]")) {
|
||||
if (!release.publishedManifest) {
|
||||
showToast("尚未形成发布 Manifest", "下载不可用");
|
||||
showToast("尚未生成发布 Manifest", "下载不可用");
|
||||
return;
|
||||
}
|
||||
downloadJson(`${release.packageId}-published-manifest.json`, release.publishedManifest);
|
||||
@@ -3656,7 +3656,7 @@ function setupOperations() {
|
||||
updateReleaseQualityGate();
|
||||
if (!releaseReadyForApproval(release)) {
|
||||
showToast(
|
||||
release.qualityGate === "PASS" ? "质量门禁已通过,但必须先生成并冻结候选 Manifest" : "只有验证通过的 FIX_REPLAY 才能解除候选版本门禁",
|
||||
release.qualityGate === "PASS" ? "质量检查已通过,但必须先生成候选 Manifest 并提交审批" : "只有通过检查的 FIX_REPLAY 才能让候选版本继续提交",
|
||||
"候选尚不可提交",
|
||||
);
|
||||
return;
|
||||
@@ -3666,7 +3666,7 @@ function setupOperations() {
|
||||
event: "候选版本提交独立审批",
|
||||
object: release.id,
|
||||
result: "待审批",
|
||||
evidence: ["候选 Manifest", "质量门禁 PASS", "影响租户清单"],
|
||||
evidence: ["候选 Manifest", "发布质量检查 PASS", "影响租户清单"],
|
||||
});
|
||||
migrateOperationsEntity(release, "PENDING_APPROVAL", metadata);
|
||||
migrateOperationsEntity(approval, "PENDING_APPROVAL", metadata);
|
||||
@@ -3794,7 +3794,7 @@ function setupOperations() {
|
||||
rejectEvent: "全局版本回滚独立审批驳回",
|
||||
object: `${release.id} → ${release.previousStableVersion}`,
|
||||
evidence: ["回滚审批意见", "审批人身份", "四眼规则校验", "影响租户清单"],
|
||||
defaultApproveComment: "同意在受控窗口执行回滚",
|
||||
defaultApproveComment: "同意在已安排的时间窗口执行回滚",
|
||||
defaultRejectComment: "回滚依据不足",
|
||||
successMessage: (actor, passed) => `${actor} 已${passed ? "批准" : "驳回"}全局回滚`,
|
||||
successTitle: (passed) => (passed ? "回滚审批通过" : "回滚审批驳回"),
|
||||
@@ -3807,7 +3807,7 @@ function setupOperations() {
|
||||
rollbackApproval?.status !== "ROLLBACK_APPROVED" ||
|
||||
!isIndependentApproval(rollbackApproval)
|
||||
) {
|
||||
showToast("全局版本回滚必须先完成职责分离的独立审批", "回滚执行被阻断");
|
||||
showToast("全局版本回滚必须先由另一名审批人批准", "当前不能执行回滚");
|
||||
return;
|
||||
}
|
||||
const metadata = addOperationsAudit({
|
||||
@@ -3846,7 +3846,7 @@ function setupOperations() {
|
||||
saveOperationsStore();
|
||||
renderOperations();
|
||||
renderAudit();
|
||||
showToast(`${pending.length} 所待发送学校已进入原型队列,未发生真实网络发送`, "交付队列已启动");
|
||||
showToast(`${pending.length} 所待发送学校已进入原型队列,没有发出网络请求`, "交付队列已启动");
|
||||
});
|
||||
document.getElementById("deliveryTable").addEventListener("click", (event) => {
|
||||
const button =
|
||||
@@ -3949,7 +3949,7 @@ function setupGlobalActions() {
|
||||
const deliveryTodos = operationsStore.deliveries.filter((delivery) => ["PENDING", "SENDING", "FAILED", "RETRYING"].includes(delivery.status));
|
||||
openInfoModal(
|
||||
"OPERATIONS NOTIFICATIONS",
|
||||
"真实运营待办",
|
||||
"运营待办",
|
||||
`<div class="runtime-list notification-list">
|
||||
${openIssues
|
||||
.map(
|
||||
@@ -3963,7 +3963,7 @@ function setupGlobalActions() {
|
||||
: ""
|
||||
}
|
||||
${deliveryTodos.length ? `<button data-operations-jump="deliveries"><strong>${deliveryTodos.length} 所学校交付待处理</strong><small>包含待发送、发送中、失败或重试状态</small></button>` : ""}
|
||||
${!openIssues.length && !pendingApproval && !deliveryTodos.length ? `<span><strong>当前没有运营待办</strong><small>问题、审批和交付均已闭环</small></span>` : ""}
|
||||
${!openIssues.length && !pendingApproval && !deliveryTodos.length ? `<span><strong>当前没有运营待办</strong><small>问题、审批和交付均已处理完成</small></span>` : ""}
|
||||
</div>`,
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user