[as] feat: 체크리스트 전체선택 기능 추가
This commit is contained in:
@@ -2,6 +2,7 @@ import type { Dispatch, SetStateAction } from "react";
|
||||
|
||||
import type { CklstRvwRsltTreeDto } from "@/entities/fnrs-cnsltn";
|
||||
import {
|
||||
Button,
|
||||
cn,
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -36,6 +37,24 @@ function ChecklistTaskPanel({
|
||||
const currentUserReviewStep = userRoleCode ? ROLE_TO_REVIEW_STEP[userRoleCode] : undefined;
|
||||
const isStepEditable = currentUserReviewStep === selectedReviewStep;
|
||||
|
||||
function handleSelectAll(value: "Y" | "N") {
|
||||
if (!isStepEditable) return;
|
||||
setFormState((prev) => {
|
||||
const nextResults = { ...prev.results };
|
||||
selectedRows
|
||||
.filter((row) => row.bchckUseYn === "Y")
|
||||
.forEach((row) => {
|
||||
nextResults[buildChecklistRowKey(row, selectedReviewStep)] = value;
|
||||
});
|
||||
return patchChecklistFormState(
|
||||
prev,
|
||||
{ results: nextResults },
|
||||
allRows,
|
||||
selectedReviewStep,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="overflow-x-auto">
|
||||
@@ -54,8 +73,27 @@ function ChecklistTaskPanel({
|
||||
) : null}
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead className="w-[9rem]">예</TableHead>
|
||||
<TableHead className="w-[9rem]">아니오</TableHead>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("Y")}
|
||||
>
|
||||
전체 예
|
||||
</Button>
|
||||
</TableHead>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("N")}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -131,7 +169,7 @@ function ChecklistTaskPanel({
|
||||
<TableCell className="text-left">
|
||||
<Textarea
|
||||
className={cn(
|
||||
"min-h-[6rem] !text-xl",
|
||||
"min-h-[6rem] w-[32rem] !text-xl",
|
||||
isStepEditable ? "cursor-pointer" : "cursor-not-allowed",
|
||||
)}
|
||||
value={formState.comments[key] ?? ""}
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Dispatch, SetStateAction } from "react";
|
||||
|
||||
import type { CklstRvwRsltTreeDto, ReviewStepCode } from "@/entities/instl-sncn";
|
||||
import {
|
||||
Button,
|
||||
cn,
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -35,6 +36,24 @@ function ChecklistTaskPanel({
|
||||
const currentUserReviewStep = userRoleCode ? ROLE_TO_REVIEW_STEP[userRoleCode] : undefined;
|
||||
const isStepEditable = currentUserReviewStep === selectedReviewStep;
|
||||
|
||||
function handleSelectAll(value: "Y" | "N") {
|
||||
if (!isStepEditable) return;
|
||||
setFormState((prev) => {
|
||||
const nextResults = { ...prev.results };
|
||||
selectedRows
|
||||
.filter((row) => row.bchckUseYn === "Y")
|
||||
.forEach((row) => {
|
||||
nextResults[buildChecklistRowKey(row, selectedReviewStep)] = value;
|
||||
});
|
||||
return patchChecklistFormState(
|
||||
prev,
|
||||
{ results: nextResults },
|
||||
allRows,
|
||||
selectedReviewStep,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="overflow-x-auto">
|
||||
@@ -53,8 +72,27 @@ function ChecklistTaskPanel({
|
||||
) : null}
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead className="w-[9rem]">예</TableHead>
|
||||
<TableHead className="w-[9rem]">아니오</TableHead>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("Y")}
|
||||
>
|
||||
전체 예
|
||||
</Button>
|
||||
</TableHead>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
disabled={!isStepEditable}
|
||||
onClick={() => handleSelectAll("N")}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -130,7 +168,7 @@ function ChecklistTaskPanel({
|
||||
<TableCell className="text-left">
|
||||
<Textarea
|
||||
className={cn(
|
||||
"min-h-[6rem] !text-xl",
|
||||
"min-h-[6rem] w-[32rem] !text-xl",
|
||||
isStepEditable ? "cursor-pointer" : "cursor-not-allowed",
|
||||
)}
|
||||
value={formState.comments[key] ?? ""}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { Field, FieldLabel } from "@/shared/ui/field";
|
||||
import { cklstMngService, type CklstTreeNode } from "@/entities/cklst";
|
||||
import { useCodeList } from "@/entities/code";
|
||||
import {
|
||||
@@ -196,31 +196,33 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
|
||||
검토항목
|
||||
</TableHead>
|
||||
<TableHead rowSpan={2}>주요 검토내용</TableHead>
|
||||
<TableHead className="w-[16rem]">검토</TableHead>
|
||||
<TableHead colSpan={2}>검토 결과</TableHead>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "Y");
|
||||
}}
|
||||
>
|
||||
전체 예
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "N");
|
||||
}}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
</div>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "Y");
|
||||
}}
|
||||
>
|
||||
전체 예
|
||||
</Button>
|
||||
</TableHead>
|
||||
<TableHead className="w-[12rem]">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelectAll(tab.code, "N");
|
||||
}}
|
||||
className="!bg-destructive"
|
||||
>
|
||||
전체 아니오
|
||||
</Button>
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -236,64 +238,72 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
|
||||
style={{
|
||||
paddingLeft: `${Math.max(0, item.treeLevel - 1) * 16 + 8}px`,
|
||||
}}
|
||||
colSpan={showRadios ? 0 : 2}
|
||||
colSpan={showRadios ? 0 : 3}
|
||||
>
|
||||
{item.treeLevel > 1 ? "└ " : ""}
|
||||
{item.content}
|
||||
</TableCell>
|
||||
{showRadios && resultIdx >= 0 ? (
|
||||
<TableCell>
|
||||
<Controller
|
||||
name={`cklstResultList.${resultIdx}.selected`}
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<FieldSet>
|
||||
<Controller
|
||||
name={`cklstResultList.${resultIdx}.selected`}
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<>
|
||||
<TableCell className="text-center">
|
||||
<RadioGroup
|
||||
name={field.name}
|
||||
value={field.value || undefined}
|
||||
value={field.value === "Y" ? "Y" : undefined}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<div className="flex w-full justify-center gap-6">
|
||||
<FieldLabel
|
||||
htmlFor={`check-${item.cklstRvwSn}-Y`}
|
||||
className="!w-auto border-none"
|
||||
<FieldLabel
|
||||
htmlFor={`check-${item.cklstRvwSn}-Y`}
|
||||
className="!w-auto justify-center border-none"
|
||||
>
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-invalid={fieldState.invalid}
|
||||
className="w-auto"
|
||||
>
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-invalid={fieldState.invalid}
|
||||
className="w-auto"
|
||||
>
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`check-${item.cklstRvwSn}-Y`}
|
||||
aria-invalid={fieldState.invalid}
|
||||
/>
|
||||
<span className="font-normal">예</span>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel
|
||||
htmlFor={`check-${item.cklstRvwSn}-N`}
|
||||
className="!w-auto border-none"
|
||||
>
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-invalid={fieldState.invalid}
|
||||
className="w-auto"
|
||||
>
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`check-${item.cklstRvwSn}-N`}
|
||||
aria-invalid={fieldState.invalid}
|
||||
/>
|
||||
<span className="font-normal">아니오</span>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</div>
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`check-${item.cklstRvwSn}-Y`}
|
||||
aria-invalid={fieldState.invalid}
|
||||
aria-label="예"
|
||||
/>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableCell>
|
||||
<TableCell className="text-center">
|
||||
<RadioGroup
|
||||
name={field.name}
|
||||
value={field.value === "N" ? "N" : undefined}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<FieldLabel
|
||||
htmlFor={`check-${item.cklstRvwSn}-N`}
|
||||
className="!w-auto justify-center border-none"
|
||||
>
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-invalid={fieldState.invalid}
|
||||
className="w-auto"
|
||||
>
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`check-${item.cklstRvwSn}-N`}
|
||||
aria-invalid={fieldState.invalid}
|
||||
aria-label="아니오"
|
||||
/>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</TableCell>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user