{project.customer}
{project.id} · {project.industry} · {project.stage} · {project.data_domain === "demo" ? "演示数据" : "正式数据"}
diff --git a/scripts/test_reviewer_workspace.cjs b/scripts/test_reviewer_workspace.cjs index 8171ccf..fee343b 100644 --- a/scripts/test_reviewer_workspace.cjs +++ b/scripts/test_reviewer_workspace.cjs @@ -10,6 +10,9 @@ assert.match(component, /aria-label=\{`\$\{topic\.title\}评审意见`\}/, "每 assert.match(component, /onChange=\{\(event\)=>setDraft\(event\.target\.value\)\}/, "输入框应允许修改节点意见"); assert.match(component, /draft\.trim\(\)\|\|"已复核本章节数据来源和AI检查结果"/, "正常节点应保存人工输入或明确的默认复核说明"); assert.match(component, /disabled=\{busy\|\|requiredOpinion\}/, "需要说明依据的评审动作不应允许空意见提交"); +assert.match(component, /aria-label="退回补充材料原因"/, "退回操作旁应直接提供原因输入框"); +assert.match(component, /disabled=\{busy\|\|!hasRun\|\|!returnReason\.trim\(\)\}/, "未填写退回原因时不应允许退回"); +assert.match(component, /onComplete\("退回",returnReason\.trim\(\)\)/, "退回原因应随退回决定一并保存"); assert.match(page, /setReviewOpinion\]=useState\(""\)/, "常用模板默认不应冒充人工意见"); console.log("Reviewer workspace input behavior checks passed"); diff --git a/src/app/data-access/workspace.css b/src/app/data-access/workspace.css index 321851a..13ec3a9 100644 --- a/src/app/data-access/workspace.css +++ b/src/app/data-access/workspace.css @@ -10,3 +10,4 @@ .xb-pool-card{cursor:default}.xb-pool-card:hover{border-color:#dfe7e2;box-shadow:none}.xb-pool-card.just-submitted{border-color:#55a778;box-shadow:0 0 0 3px #55a7781f}.xb-pool-card.just-submitted>span{background:#dcf3e5;color:#17633f}.xb-pool-actions{display:flex;gap:8px;margin-top:14px}.xb-pool-actions .ra-button{display:inline-flex;align-items:center;gap:6px;text-decoration:none}.xb-pool-card footer b{display:flex;align-items:center;gap:5px;font-size:11px} .ra-heading-actions{display:flex;gap:10px;align-items:center}.ra-folder-input{display:none}@media(max-width:760px){.ra-heading-actions{width:100%;flex-wrap:wrap}} .xb-decision-editor{display:block;margin-top:10px}.xb-decision-editor>span{display:block;margin-bottom:6px;color:#51675a;font-size:10px;font-weight:700}.xb-decision-editor textarea{box-sizing:border-box;width:100%;min-height:82px;padding:10px 11px;resize:vertical;border:1px solid #d9e2dc;border-radius:7px;background:#fff;color:#273c30;font:inherit;line-height:1.6;outline:none}.xb-decision-editor textarea:focus{border-color:#3b8d64;box-shadow:0 0 0 3px #3b8d6418}.xb-decision-editor>small{display:block;margin-top:4px;text-align:right;color:#8a958e;font-size:9px} +.xb-return-reason{display:block;width:min(360px,100%)}.xb-return-reason>span{display:block;margin-bottom:5px;color:#587063;font-size:9px;font-weight:700}.xb-return-reason textarea{box-sizing:border-box;width:100%;min-height:58px;padding:8px 10px;resize:vertical;border:1px solid #ccdcd2;border-radius:7px;background:#fff;color:#273c30;font:inherit;line-height:1.5;outline:none}.xb-return-reason textarea:focus{border-color:#3b8d64;box-shadow:0 0 0 3px #3b8d6418}@media(max-width:900px){.xb-return-reason{width:100%}} diff --git a/src/app/xingbang-workbench/page.tsx b/src/app/xingbang-workbench/page.tsx index befcdf0..020507c 100644 --- a/src/app/xingbang-workbench/page.tsx +++ b/src/app/xingbang-workbench/page.tsx @@ -80,7 +80,7 @@ export default function XingbangWorkspace() { } async function reportAction(action: string, payload: any = {}) {if (["regenerate", "finalize", "submit"].includes(action) && Object.keys(sectionEdits).length) {setError("请先保存尚未提交的章节修改"); return;} if(action === "submit" && !window.confirm("确认提交正式评审?提交后当前AI预审报告将作为不可覆盖的送审版本保留。")) return; const saved = await act(`${base}/reports/${chosenReport.id}/actions`, {action, revision: chosenReport.revision, payload}, action === "submit" ? "AI预审报告已提交正式评审。" : "报告操作已记录"); if(saved&&action==="submit"){location.href=`/review-pool?submitted=${encodeURIComponent(project.id)}`;return;} if (saved && payload.section_id) setSectionEdits(previous => {const next = {...previous}; delete next[payload.section_id]; return next;});} async function reviewDecision(findingId:string|null,decision:string,nodeId?:string,opinion?:string){return act(`${base}/review-decisions`,{finding_id:findingId,node_id:nodeId||null,decision,opinion:opinion??reviewOpinion},findingId||nodeId?"本项评审意见已保存。":decision==="批准"?"评审已批准,正在形成评审报告。":"项目已退回客户经理补件。");} - async function completeReview(decision:string){const saved=await reviewDecision(null,decision);if(!saved)return;if(decision==="批准"&&reportSourceRun){const report=await act(`${base}/reports`,{run_id:reportSourceRun.id,template_id:"template.independent-review"},"独立评审报告已生成,请确认后定稿。");if(report)setReportId(report.id);setTab("report");}} + async function completeReview(decision:string,opinion?:string){const saved=await reviewDecision(null,decision,undefined,opinion);if(!saved)return;if(decision==="批准"&&reportSourceRun){const report=await act(`${base}/reports`,{run_id:reportSourceRun.id,template_id:"template.independent-review"},"独立评审报告已生成,请确认后定稿。");if(report)setReportId(report.id);setTab("report");}} return
{project.id} · {project.industry} · {project.stage} · {project.data_domain === "demo" ? "演示数据" : "正式数据"}