R7E-16E/R7E-16F 高风险操作确认统一
这个提交包含在:
@@ -13,6 +13,7 @@ import { SectionPanel } from "../components/patterns/SectionPanel";
|
||||
import { isApiError } from "../api/types";
|
||||
import { StatusBadge } from "../components/common/StatusBadge";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../components/ui/dialog";
|
||||
import { Input } from "../components/ui/input";
|
||||
import { Label } from "../components/ui/label";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../components/ui/table";
|
||||
@@ -173,6 +174,8 @@ export function ProjectDetailPage() {
|
||||
nextFollowUpDate: "",
|
||||
});
|
||||
const [editingCommunicationLogId, setEditingCommunicationLogId] = useState<string | null>(null);
|
||||
const [waiveChecklistTarget, setWaiveChecklistTarget] = useState<{ itemId: string; currentNote: string | null } | null>(null);
|
||||
const [waiveChecklistNote, setWaiveChecklistNote] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!detail) return;
|
||||
@@ -452,15 +455,8 @@ export function ProjectDetailPage() {
|
||||
|
||||
const handleChecklistStatusChange = (itemId: string, status: ProjectClosureChecklistStatus, currentNote: string | null) => {
|
||||
if (status === "waived") {
|
||||
const note = window.prompt("请填写豁免理由", currentNote ?? "");
|
||||
if (note == null) {
|
||||
return;
|
||||
}
|
||||
if (!note.trim()) {
|
||||
toast.error("豁免必须填写说明");
|
||||
return;
|
||||
}
|
||||
patchClosureChecklistMutation.mutate({ itemId, status, note: note.trim() });
|
||||
setWaiveChecklistTarget({ itemId, currentNote });
|
||||
setWaiveChecklistNote(currentNote ?? "");
|
||||
return;
|
||||
}
|
||||
patchClosureChecklistMutation.mutate({ itemId, status });
|
||||
@@ -491,6 +487,7 @@ export function ProjectDetailPage() {
|
||||
const riskItems = risksQuery.data?.items ?? detail.risks;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageScaffold>
|
||||
<EntityOverviewHero
|
||||
title={`${detail.projectNo} · ${detail.name}`}
|
||||
@@ -1061,6 +1058,70 @@ export function ProjectDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
</PageScaffold>
|
||||
<Dialog
|
||||
open={Boolean(waiveChecklistTarget)}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
setWaiveChecklistTarget(null);
|
||||
setWaiveChecklistNote("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogContent className="max-w-md" data-testid="action-confirm-dialog">
|
||||
<DialogHeader>
|
||||
<DialogTitle>确认豁免收口项</DialogTitle>
|
||||
<DialogDescription>
|
||||
豁免后该收口项会标记为已豁免,并写入项目收口记录。必须填写可理解说明。
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-zinc-900" htmlFor="project-closure-waive-note">
|
||||
豁免理由
|
||||
</label>
|
||||
<Textarea
|
||||
id="project-closure-waive-note"
|
||||
data-testid="project-closure-waive-note"
|
||||
value={waiveChecklistNote}
|
||||
onChange={(event) => setWaiveChecklistNote(event.target.value)}
|
||||
placeholder="说明为什么该收口项可以豁免"
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
data-testid="action-confirm-cancel"
|
||||
disabled={patchClosureChecklistMutation.isPending}
|
||||
onClick={() => {
|
||||
setWaiveChecklistTarget(null);
|
||||
setWaiveChecklistNote("");
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
data-testid="action-confirm-submit"
|
||||
disabled={!waiveChecklistTarget || !waiveChecklistNote.trim() || patchClosureChecklistMutation.isPending}
|
||||
onClick={() => {
|
||||
if (!waiveChecklistTarget) return;
|
||||
patchClosureChecklistMutation.mutate({
|
||||
itemId: waiveChecklistTarget.itemId,
|
||||
status: "waived",
|
||||
note: waiveChecklistNote.trim(),
|
||||
});
|
||||
setWaiveChecklistTarget(null);
|
||||
setWaiveChecklistNote("");
|
||||
}}
|
||||
>
|
||||
{patchClosureChecklistMutation.isPending ? "处理中..." : "确认豁免"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户