From a4bf0d8376962c922da90cd08781893a3658ecc2 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Thu, 6 Nov 2025 09:52:27 +0000 Subject: (최겸) 구매 보완 재실사 자동생성 삭제 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pq/pq-review-table-new/site-visit-dialog.tsx | 189 ++++++++--------------- lib/site-visit/service.ts | 41 ++--- lib/vendor-investigation/service.ts | 14 +- 3 files changed, 84 insertions(+), 160 deletions(-) diff --git a/lib/pq/pq-review-table-new/site-visit-dialog.tsx b/lib/pq/pq-review-table-new/site-visit-dialog.tsx index a7cc3313..55468499 100644 --- a/lib/pq/pq-review-table-new/site-visit-dialog.tsx +++ b/lib/pq/pq-review-table-new/site-visit-dialog.tsx @@ -1,7 +1,7 @@ "use client" import * as React from "react" -import { CalendarIcon, X, Plus, Trash2, Check, Search } from "lucide-react" +import { CalendarIcon, X, Plus, Trash2 } from "lucide-react" import { useForm, useFieldArray } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { format } from "date-fns" @@ -36,18 +36,9 @@ import { } from "@/components/ui/popover" import { Checkbox } from "@/components/ui/checkbox" import { Badge } from "@/components/ui/badge" -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from "@/components/ui/command" import { toast } from "sonner" import { getSiteVisitRequestAction, getUsersForSiteVisitAction } from "@/lib/site-visit/service" -import { cn } from "@/lib/utils" +import { UserCombobox } from "./user-combobox" import { Dropzone, DropzoneDescription, @@ -183,7 +174,7 @@ interface SiteVisitUser { id: number; name: string; email: string; - deptName: string | null; + department?: string; } // 참석자 섹션 컴포넌트 @@ -204,57 +195,55 @@ function AttendeeSection({ }); const isChecked = form.watch(`shiAttendees.${itemKey}.checked`); - const [isPopoverOpen, setIsPopoverOpen] = React.useState(false); - const [searchQuery, setSearchQuery] = React.useState(""); const [users, setUsers] = React.useState([]); const [isLoadingUsers, setIsLoadingUsers] = React.useState(false); + const [selectedUserId, setSelectedUserId] = React.useState(null); - const loadUsers = React.useCallback(async () => { - setIsLoadingUsers(true); - try { - const result = await getUsersForSiteVisitAction( - searchQuery.trim() || undefined - ); - if (result.success && result.data) { - setUsers(result.data); - } - } catch (error) { - console.error("사용자 목록 로드 오류:", error); - toast.error("사용자 목록을 불러오는데 실패했습니다."); - } finally { - setIsLoadingUsers(false); - } - }, [searchQuery]); - - // 사용자 목록 가져오기 - React.useEffect(() => { - if (isPopoverOpen && isChecked) { - loadUsers(); - } - }, [isPopoverOpen, isChecked, loadUsers]); - - // 검색 쿼리 변경 시 사용자 목록 다시 로드 (debounce) + // Dialog가 열릴 때 사용자 목록 로드 React.useEffect(() => { - if (!isPopoverOpen || !isChecked) return; + if (isChecked && users.length === 0) { + const loadUsers = async () => { + setIsLoadingUsers(true); + try { + const result = await getUsersForSiteVisitAction(); + if (result.success && result.data) { + setUsers(result.data.map((user: any) => ({ + id: user.id, + name: user.name, + email: user.email, + department: user.deptName || undefined, + }))); + } + } catch (error) { + console.error("사용자 목록 로드 오류:", error); + toast.error("사용자 목록을 불러오는데 실패했습니다."); + } finally { + setIsLoadingUsers(false); + } + }; - const timer = setTimeout(() => { loadUsers(); - }, 300); + } + }, [isChecked, users.length]); - return () => clearTimeout(timer); - }, [searchQuery, isPopoverOpen, isChecked, loadUsers]); + const handleUserSelect = (userId: number) => { + // 선택된 사용자 정보 찾기 + const selectedUser = users.find(user => user.id === userId); + if (!selectedUser) return; - const handleUserSelect = (user: SiteVisitUser) => { // 현재 폼의 attendees 값 가져오기 const currentAttendees = form.getValues(`shiAttendees.${itemKey}.attendees`) as Array<{ name: string; department?: string; email: string; - }>; + }> | undefined; - // 이미 선택된 사용자인지 확인 - const existingIndex = currentAttendees.findIndex( - (attendee) => attendee.email === user.email + // undefined이거나 배열이 아닌 경우 빈 배열로 처리 + const attendees = Array.isArray(currentAttendees) ? currentAttendees : []; + + // 이미 선택된 사용자인지 확인 (이메일 기준) + const existingIndex = attendees.findIndex( + (attendee) => attendee.email === selectedUser.email ); if (existingIndex >= 0) { @@ -263,20 +252,14 @@ function AttendeeSection({ } else { // 새로 추가 append({ - name: user.name, - department: user.deptName || "", - email: user.email, + name: selectedUser.name, + department: selectedUser.department || "", + email: selectedUser.email, }); } - }; - - const isUserSelected = (userEmail: string) => { - const currentAttendees = form.getValues(`shiAttendees.${itemKey}.attendees`) as Array<{ - name: string; - department?: string; - email: string; - }>; - return currentAttendees.some((attendee) => attendee.email === userEmail); + + // 선택 초기화 + setSelectedUserId(null); }; return ( @@ -296,7 +279,6 @@ function AttendeeSection({ // 체크 해제 시 참석자 목록 초기화 if (!checked) { form.setValue(`shiAttendees.${itemKey}.attendees` as any, []); - setIsPopoverOpen(false); } }} disabled={isPending} @@ -319,68 +301,27 @@ function AttendeeSection({ {isChecked && (
{/* 사용자 선택 UI */} - - - - - - - - - - {isLoadingUsers ? "로딩 중..." : "검색 결과가 없습니다."} - - - {users.map((user) => { - const selected = isUserSelected(user.email); - return ( - handleUserSelect(user)} - className="cursor-pointer" - > - -
-
- - {user.name} - - {user.deptName && ( - - ({user.deptName}) - - )} -
- - {user.email} - -
-
- ); - })} -
-
-
-
-
+
+
+ +
+ +
{/* 선택된 사용자 목록 */} {fields.length > 0 && ( diff --git a/lib/site-visit/service.ts b/lib/site-visit/service.ts index d78682b5..684e73f1 100644 --- a/lib/site-visit/service.ts +++ b/lib/site-visit/service.ts @@ -877,22 +877,9 @@ export async function getSiteVisitRequestAction(investigationId: number) { } // domain이 'partners'가 아닌 사용자 목록 가져오기 - export async function getUsersForSiteVisitAction(searchQuery?: string) { + export async function getUsersForSiteVisitAction() { try { - let whereCondition = ne(users.domain, "partners"); - - // 검색 쿼리가 있으면 이름 또는 이메일로 필터링 - if (searchQuery && searchQuery.trim()) { - const searchPattern = `%${searchQuery.trim()}%`; - whereCondition = and( - ne(users.domain, "partners"), - or( - ilike(users.name, searchPattern), - ilike(users.email, searchPattern) - ) - ) as any; - } - + // domain이 'partners'가 아니고, isActive가 true인 사용자만 조회 const userList = await db .select({ id: users.id, @@ -901,20 +888,24 @@ export async function getSiteVisitRequestAction(investigationId: number) { deptName: users.deptName, }) .from(users) - .where(whereCondition) - .orderBy(users.name) - .limit(100); // 최대 100명까지 - + .where( + and( + eq(users.isActive, true), + ne(users.domain, "partners") + ) + ) + .orderBy(users.name); + return { - success: true, data: userList, - }; + success: true + } } catch (error) { - console.error("사용자 목록 조회 오류:", error); + console.error("사용자 목록 조회 오류:", error) return { - success: false, - error: "사용자 목록 조회 중 오류가 발생했습니다.", data: [], - }; + success: false, + error: error instanceof Error ? error.message : "사용자 목록을 가져오는 중 오류가 발생했습니다." + } } } \ No newline at end of file diff --git a/lib/vendor-investigation/service.ts b/lib/vendor-investigation/service.ts index 39984661..cf37ad06 100644 --- a/lib/vendor-investigation/service.ts +++ b/lib/vendor-investigation/service.ts @@ -382,7 +382,7 @@ export async function updateVendorInvestigationResultAction(formData: FormData) .set(updateData) .where(eq(vendorInvestigations.id, parsed.investigationId)) /* - 현재 보완 프로세스는 자동으로 처리됨. 만약 dialog 필요하면 아래 서버액션 분기 필요.(1029/최겸) + 현재 보완-서류제출 프로세스는 자동으로 처리됨. 만약 dialog 필요하면 아래 서버액션 분기 필요.(1029/최겸) */ // 5-1) 보완 프로세스 자동 처리 (TO-BE) if (parsed.evaluationResult === "SUPPLEMENT_REINSPECT" || parsed.evaluationResult === "SUPPLEMENT_DOCUMENT") { @@ -396,16 +396,7 @@ export async function updateVendorInvestigationResultAction(formData: FormData) .then(rows => rows[0]); if (investigation?.investigationMethod === "PRODUCT_INSPECTION" || investigation?.investigationMethod === "SITE_VISIT_EVAL") { - if (parsed.evaluationResult === "SUPPLEMENT_REINSPECT") { - // 보완-재실사 요청 자동 생성 - await requestSupplementReinspectionAction({ - investigationId: parsed.investigationId, - siteVisitData: { - inspectionDuration: 1.0, // 기본 1일 - additionalRequests: "보완을 위한 재실사 요청입니다.", - } - }); - } else if (parsed.evaluationResult === "SUPPLEMENT_DOCUMENT") { + if (parsed.evaluationResult === "SUPPLEMENT_DOCUMENT") { // 보완-서류제출 요청 자동 생성 await requestSupplementDocumentAction({ investigationId: parsed.investigationId, @@ -421,6 +412,7 @@ export async function updateVendorInvestigationResultAction(formData: FormData) // 6) 캐시 무효화 revalidateTag("vendor-investigations") revalidatePath("/evcp/vendor-investigation") + revalidatePath("/evcp/pq_new") return { success: true } } catch (error) { -- cgit v1.2.3