summaryrefslogtreecommitdiff
path: root/lib/docu-list-rule/combo-box-settings
diff options
context:
space:
mode:
author0-Zz-ang <s1998319@gmail.com>2025-08-25 09:23:30 +0900
committer0-Zz-ang <s1998319@gmail.com>2025-08-25 09:23:30 +0900
commitb12a06766e32e3c76544b1d12bec91653e1fe9db (patch)
tree57ca1ddff3342677d132e07b78fc03873a960255 /lib/docu-list-rule/combo-box-settings
parentd38877eef87917087a4a217bea32ae84d6738a7d (diff)
docu-list-rule페이지 수정
Diffstat (limited to 'lib/docu-list-rule/combo-box-settings')
-rw-r--r--lib/docu-list-rule/combo-box-settings/service.ts119
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx80
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns.tsx13
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table-columns.tsx14
-rw-r--r--lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table.tsx7
-rw-r--r--lib/docu-list-rule/combo-box-settings/validation.ts1
6 files changed, 201 insertions, 33 deletions
diff --git a/lib/docu-list-rule/combo-box-settings/service.ts b/lib/docu-list-rule/combo-box-settings/service.ts
index c733f978..d2f7d0f7 100644
--- a/lib/docu-list-rule/combo-box-settings/service.ts
+++ b/lib/docu-list-rule/combo-box-settings/service.ts
@@ -19,6 +19,7 @@ export async function getComboBoxCodeGroups(input: {
groupId?: string
description?: string
isActive?: string
+ projectId?: string
}) {
unstable_noStore()
@@ -29,10 +30,15 @@ export async function getComboBoxCodeGroups(input: {
// Control Type이 combobox이고 plant 타입 프로젝트인 조건
let whereConditions = sql`${codeGroups.controlType} = 'combobox' AND ${projects.type} = 'plant'`
+ // 프로젝트 ID 필터링
+ if (input.projectId) {
+ whereConditions = sql`${whereConditions} AND ${codeGroups.projectId} = ${parseInt(input.projectId)}`
+ }
+
// 검색 조건
if (search) {
const searchTerm = `%${search}%`
- whereConditions = sql`${codeGroups.controlType} = 'combobox' AND ${projects.type} = 'plant' AND (
+ whereConditions = sql`${whereConditions} AND (
${codeGroups.groupId} ILIKE ${searchTerm} OR
${codeGroups.description} ILIKE ${searchTerm} OR
${codeGroups.codeFormat} ILIKE ${searchTerm} OR
@@ -168,7 +174,7 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
}
// 정렬 (안전한 필드 체크 적용)
- let orderBy = sql`${comboBoxSettings.code} ASC`
+ let orderBy = sql`${comboBoxSettings.sdq} ASC`
if (sort && sort.length > 0) {
const sortField = sort[0]
// 안전성 체크: 필드가 실제 테이블에 존재하는지 확인
@@ -193,6 +199,7 @@ export async function getComboBoxOptions(codeGroupId: number, input?: {
code: comboBoxSettings.code,
description: comboBoxSettings.description,
remark: comboBoxSettings.remark,
+ sdq: comboBoxSettings.sdq,
createdAt: comboBoxSettings.createdAt,
updatedAt: comboBoxSettings.updatedAt,
projectCode: projects.code,
@@ -274,6 +281,14 @@ export async function createComboBoxOption(input: {
}
}
+ // 다음 순서 번호 계산
+ const maxSdqResult = await db
+ .select({ maxSdq: sql<number>`COALESCE(MAX(sdq), 0)` })
+ .from(comboBoxSettings)
+ .where(eq(comboBoxSettings.codeGroupId, input.codeGroupId))
+
+ const nextSdq = (maxSdqResult[0]?.maxSdq || 0) + 1
+
const [newOption] = await db
.insert(comboBoxSettings)
.values({
@@ -281,6 +296,7 @@ export async function createComboBoxOption(input: {
code: input.code,
description: input.description || "-",
remark: input.remark,
+ sdq: nextSdq,
})
.returning({ id: comboBoxSettings.id })
@@ -308,6 +324,7 @@ export async function updateComboBoxOption(input: {
code: string
description: string
remark?: string
+ sdq?: number
}) {
try {
// 현재 수정 중인 항목의 codeGroupId 가져오기
@@ -346,6 +363,7 @@ export async function updateComboBoxOption(input: {
code: input.code,
description: input.description,
remark: input.remark,
+ ...(input.sdq !== undefined && { sdq: input.sdq }),
updatedAt: new Date(),
})
.where(eq(comboBoxSettings.id, input.id))
@@ -421,4 +439,99 @@ export async function clearComboBoxOptions(codeGroupId: number) {
}
}
- \ No newline at end of file
+// Combo Box 옵션 순서 업데이트 (드래그 앤 드롭)
+export async function updateComboBoxOptionOrder(codeGroupId: number, reorderedOptions: { id: number; sdq: number }[]) {
+ try {
+ console.log("Updating combo box option order:", { codeGroupId, reorderedOptions })
+
+ // 유니크 제약조건 때문에 임시로 큰 값으로 업데이트 후 실제 값으로 업데이트
+ await db.transaction(async (tx) => {
+ // 1단계: 모든 옵션을 임시 큰 값으로 업데이트
+ for (const option of reorderedOptions) {
+ console.log("Step 1 - Setting temporary value for option:", option.id)
+ await tx
+ .update(comboBoxSettings)
+ .set({
+ sdq: option.sdq + 1000, // 임시로 큰 값 설정
+ updatedAt: new Date(),
+ })
+ .where(eq(comboBoxSettings.id, option.id))
+ }
+
+ // 2단계: 실제 값으로 업데이트
+ for (const option of reorderedOptions) {
+ console.log("Step 2 - Setting final value for option:", option.id, "sdq:", option.sdq)
+ const result = await tx
+ .update(comboBoxSettings)
+ .set({
+ sdq: option.sdq,
+ updatedAt: new Date(),
+ })
+ .where(eq(comboBoxSettings.id, option.id))
+ .returning({ id: comboBoxSettings.id, sdq: comboBoxSettings.sdq })
+
+ console.log("Update result:", result)
+ }
+ })
+
+ revalidatePath("/evcp/docu-list-rule/combo-box-settings")
+
+ return {
+ success: true,
+ message: "Combo Box options reordered successfully"
+ }
+ } catch (error) {
+ console.error("Error updating combo box option order:", error)
+ return {
+ success: false,
+ error: "Failed to update combo box option order"
+ }
+ }
+}
+
+// 기존 데이터에 기본 순서값 설정 (마이그레이션 후 한 번만 실행)
+export async function initializeComboBoxOptionOrder() {
+ try {
+ // sdq가 null인 모든 옵션들을 찾아서 순서대로 업데이트
+ const codeGroupsWithOptions = await db
+ .select({
+ codeGroupId: comboBoxSettings.codeGroupId,
+ id: comboBoxSettings.id,
+ })
+ .from(comboBoxSettings)
+ .orderBy(comboBoxSettings.codeGroupId, comboBoxSettings.createdAt)
+
+ // codeGroupId별로 그룹화하여 순서 설정
+ const groupedOptions = codeGroupsWithOptions.reduce((acc, option) => {
+ if (!acc[option.codeGroupId]) {
+ acc[option.codeGroupId] = []
+ }
+ acc[option.codeGroupId].push(option.id)
+ return acc
+ }, {} as Record<number, number[]>)
+
+ // 각 그룹별로 순서 업데이트
+ for (const [codeGroupId, optionIds] of Object.entries(groupedOptions)) {
+ for (let i = 0; i < optionIds.length; i++) {
+ await db
+ .update(comboBoxSettings)
+ .set({
+ sdq: i + 1,
+ updatedAt: new Date(),
+ })
+ .where(eq(comboBoxSettings.id, optionIds[i]))
+ }
+ }
+
+ return {
+ success: true,
+ message: "Combo Box option order initialized successfully"
+ }
+ } catch (error) {
+ console.error("Error initializing combo box option order:", error)
+ return {
+ success: false,
+ error: "Failed to initialize combo box option order"
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
index 286acfbf..7e81fdab 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-detail-sheet.tsx
@@ -4,12 +4,16 @@ import * as React from "react"
import { useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel } from "@tanstack/react-table"
import { DataTableDetail } from "@/components/data-table/data-table-detail"
import { DataTableAdvancedToolbarDetail } from "@/components/data-table/data-table-advanced-toolbar-detail"
+import { DragDropTable } from "@/lib/docu-list-rule/number-type-configs/table/drag-drop-table"
import type { DataTableAdvancedFilterField, DataTableRowAction } from "@/types/table"
+import { DragEndEvent } from '@dnd-kit/core'
+import { arrayMove } from '@dnd-kit/sortable'
+import { toast } from "sonner"
import {
Sheet,
SheetContent,
} from "@/components/ui/sheet"
-import { getComboBoxOptions } from "@/lib/docu-list-rule/combo-box-settings/service"
+import { getComboBoxOptions, updateComboBoxOption } from "@/lib/docu-list-rule/combo-box-settings/service"
import { getColumns } from "@/lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns"
import { ComboBoxOptionsEditSheet } from "@/lib/docu-list-rule/combo-box-settings/table/combo-box-options-edit-sheet"
import { DeleteComboBoxOptionsDialog } from "@/lib/docu-list-rule/combo-box-settings/table/delete-combo-box-options-dialog"
@@ -21,6 +25,7 @@ type ComboBoxOption = {
code: string
description: string
remark: string | null
+ sdq: number
isActive: boolean
createdAt: Date
updatedAt: Date
@@ -57,7 +62,7 @@ export function ComboBoxOptionsDetailSheet({
page: 1,
perPage: 10,
search: "",
- sort: [{ id: "createdAt", desc: true }],
+ sort: [{ id: "sdq", desc: false }],
filters: [],
joinOperator: "and",
})
@@ -90,6 +95,7 @@ export function ComboBoxOptionsDetailSheet({
const result = await getComboBoxOptions(codeGroup.id, {
page: 1,
perPage: 10,
+ sort: [{ id: "sdq", desc: false }],
})
if (result.success && result.data) {
const optionsWithIsActive = result.data.map(option => ({
@@ -123,7 +129,7 @@ export function ComboBoxOptionsDetailSheet({
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
initialState: {
- sorting: [{ id: "code", desc: false }],
+ sorting: [{ id: "sdq", desc: false }],
pagination: {
pageSize: 10,
},
@@ -131,6 +137,66 @@ export function ComboBoxOptionsDetailSheet({
getRowId: (originalRow) => String((originalRow as any).id),
})
+ // 드래그 종료 핸들러
+ const handleDragEnd = React.useCallback(async (event: DragEndEvent) => {
+ const { active, over } = event
+ console.log("Drag end event:", { active, over })
+
+ if (active.id !== over?.id) {
+ const oldIndex = rawData.data.findIndex((item) => String(item.id) === active.id)
+ const newIndex = rawData.data.findIndex((item) => String(item.id) === over?.id)
+ console.log("Indices:", { oldIndex, newIndex })
+
+ if (oldIndex !== -1 && newIndex !== -1) {
+ const reorderedData = arrayMove(rawData.data, oldIndex, newIndex)
+
+ // 새로운 순서로 sdq 값 업데이트
+ const updatedOptions = reorderedData.map((item, index) => ({
+ ...item,
+ sdq: index + 1
+ }))
+
+ // 로컬 상태 먼저 업데이트
+ setRawData(prev => ({ ...prev, data: updatedOptions }))
+
+ // 서버에 순서 업데이트 (Number Type Config와 같은 방식)
+ try {
+ // 모든 항목을 임시 값으로 먼저 업데이트
+ for (let i = 0; i < updatedOptions.length; i++) {
+ const option = updatedOptions[i]
+ await updateComboBoxOption({
+ id: option.id,
+ codeGroupId: option.codeGroupId,
+ code: option.code,
+ description: option.description,
+ remark: option.remark,
+ sdq: -(i + 1), // 임시 음수 값
+ })
+ }
+
+ // 최종 순서로 업데이트
+ for (const option of updatedOptions) {
+ await updateComboBoxOption({
+ id: option.id,
+ codeGroupId: option.codeGroupId,
+ code: option.code,
+ description: option.description,
+ remark: option.remark,
+ sdq: option.sdq,
+ })
+ }
+
+ toast.success("순서가 성공적으로 변경되었습니다.")
+ } catch (error) {
+ console.error("Error updating order:", error)
+ toast.error("순서 변경 중 오류가 발생했습니다.")
+ // 에러 시 원래 데이터로 복원
+ await refreshData()
+ }
+ }
+ }
+ }, [rawData.data, codeGroup, refreshData])
+
if (!codeGroup) return null
return (
@@ -151,12 +217,16 @@ export function ComboBoxOptionsDetailSheet({
onSuccess={refreshData}
/>
- <DataTableDetail table={table as any}>
+ <DragDropTable
+ table={table as any}
+ data={rawData.data}
+ onDragEnd={handleDragEnd}
+ >
<DataTableAdvancedToolbarDetail
table={table as any}
filterFields={advancedFilterFields}
/>
- </DataTableDetail>
+ </DragDropTable>
<DeleteComboBoxOptionsDialog
open={rowAction?.type === "delete"}
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns.tsx
index 17754331..cf770c33 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-options-table-columns.tsx
@@ -25,6 +25,7 @@ interface ComboBoxOption {
code: string
description: string
remark: string | null
+ sdq: number
isActive?: boolean
createdAt: Date
updatedAt: Date
@@ -114,17 +115,17 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<ComboBo
// ----------------------------------------------------------------
const dataColumns: ColumnDef<ComboBoxOption>[] = [
{
- accessorKey: "projectCode",
+ accessorKey: "sdq",
enableResizing: true,
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="프로젝트 코드" />
+ <DataTableColumnHeaderSimple column={column} title="순서" />
),
meta: {
- excelHeader: "프로젝트 코드",
- type: "text",
+ excelHeader: "순서",
+ type: "number",
},
- cell: ({ row }) => row.getValue("projectCode") ?? "",
- minSize: 120
+ cell: ({ row }) => row.getValue("sdq") ?? "",
+ minSize: 50
},
{
accessorKey: "code",
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table-columns.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table-columns.tsx
index d41fe5ec..0775c1d2 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table-columns.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table-columns.tsx
@@ -91,19 +91,7 @@ export function getColumns({ onDetail }: GetColumnsProps): ColumnDef<typeof code
// 3) 데이터 컬럼들
// ----------------------------------------------------------------
const dataColumns: ColumnDef<typeof codeGroups.$inferSelect>[] = [
- {
- accessorKey: "projectCode",
- enableResizing: true,
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="프로젝트 코드" />
- ),
- meta: {
- excelHeader: "프로젝트 코드",
- type: "text",
- },
- cell: ({ row }) => row.getValue("projectCode") ?? "",
- minSize: 120
- },
+
{
accessorKey: "groupId",
enableResizing: true,
diff --git a/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table.tsx b/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table.tsx
index 8e469149..fef4cf8e 100644
--- a/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table.tsx
+++ b/lib/docu-list-rule/combo-box-settings/table/combo-box-settings-table.tsx
@@ -66,12 +66,7 @@ export function ComboBoxSettingsTable({ promises }: ComboBoxSettingsTableProps)
clearOnDefault: true,
})
- // 컴포넌트 마운트 후 그룹핑 설정
- React.useEffect(() => {
- if (rawData[0]?.data && table.getState().grouping.length === 0) {
- table.setGrouping(["projectCode"])
- }
- }, [table, rawData])
+
// 정렬 시 펼쳐진 상태 유지
React.useEffect(() => {
diff --git a/lib/docu-list-rule/combo-box-settings/validation.ts b/lib/docu-list-rule/combo-box-settings/validation.ts
index ca8e9192..51671fb2 100644
--- a/lib/docu-list-rule/combo-box-settings/validation.ts
+++ b/lib/docu-list-rule/combo-box-settings/validation.ts
@@ -24,6 +24,7 @@ export const searchParamsComboBoxSettingsCache = createSearchParamsCache({
description: parseAsString.withDefault(""),
controlType: parseAsString.withDefault(""),
isActive: parseAsString.withDefault(""),
+ projectId: parseAsString.withDefault(""),
// advanced filter
filters: getFiltersStateParser().withDefault([]),