[as] rename: steiger 적용
This commit is contained in:
@@ -239,27 +239,27 @@ END
|
||||
|
||||
#### 인라인 편집 정책
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| **단일 행 편집** | **행 추가 또는 한 행 수정 중에는 다른 행을 편집할 수 없다.** `editingRowId` 로 현재 편집 행 1건만 허용. |
|
||||
| 편집 잠금 시 비활성 | 다른 행: 셀·[수정]·[삭제] 비활성 · `[행 추가]` 비활성 · 행 드래그 비활성 · (선택) `[결재선 저장]` 비활성 |
|
||||
| 편집 해제 | 행별 **[저장]** 성공 또는 **[취소]** 시 `editingRowId` 초기화 후 전체 조회 모드 복귀 |
|
||||
| 조회 행 | 편집 중이 아닐 때 읽기 전용. **[수정]** 클릭 시 해당 행만 편집 모드 진입 |
|
||||
| 신규 행 | `[행 추가]` 시 맨 아래 편집 행 1건 생성 (`editingRowId` = 임시 키) |
|
||||
| 필수값 | `atrzSeComCd`, `aprvrUuid`, `atrzSeqNo` |
|
||||
| 순서 중복 | 동일 서식 내 `atrzSeqNo` 중복 시 저장 전 검증·안내 |
|
||||
| 결재구분 코드 | `ATRZSECD` — 예: `ATRZ01` 검토자, `ATRZ02` 승인자, `ATRZ03` 최종승인자 |
|
||||
| 항목 | 내용 |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **단일 행 편집** | **행 추가 또는 한 행 수정 중에는 다른 행을 편집할 수 없다.** `editingRowId` 로 현재 편집 행 1건만 허용. |
|
||||
| 편집 잠금 시 비활성 | 다른 행: 셀·[수정]·[삭제] 비활성 · `[행 추가]` 비활성 · 행 드래그 비활성 · (선택) `[결재선 저장]` 비활성 |
|
||||
| 편집 해제 | 행별 **[저장]** 성공 또는 **[취소]** 시 `editingRowId` 초기화 후 전체 조회 모드 복귀 |
|
||||
| 조회 행 | 편집 중이 아닐 때 읽기 전용. **[수정]** 클릭 시 해당 행만 편집 모드 진입 |
|
||||
| 신규 행 | `[행 추가]` 시 맨 아래 편집 행 1건 생성 (`editingRowId` = 임시 키) |
|
||||
| 필수값 | `atrzSeComCd`, `aprvrUuid`, `atrzSeqNo` |
|
||||
| 순서 중복 | 동일 서식 내 `atrzSeqNo` 중복 시 저장 전 검증·안내 |
|
||||
| 결재구분 코드 | `ATRZSECD` — 예: `ATRZ01` 검토자, `ATRZ02` 승인자, `ATRZ03` 최종승인자 |
|
||||
| **순서 제약** | `ATRZ01`은 최상단 블록, `ATRZ03`은 최하단 블록. 드래그·결재구분 변경·저장 시 `validateAtrzOrder`로 검증, 위반 시 적용/저장 불가 |
|
||||
| 저장 단위 | 행별 **[저장]** (단건 POST/PUT) 또는 툴바 **[결재선 저장]** (일괄) |
|
||||
| 저장 단위 | 행별 **[저장]** (단건 POST/PUT) 또는 툴바 **[결재선 저장]** (일괄) |
|
||||
|
||||
#### 행 드래그 정렬 (`@dnd-kit` + `useSortable`)
|
||||
|
||||
| 항목 | 내용 |
|
||||
| ---------- | ------------------------------------------------------------------------------------------- |
|
||||
| 목적 | 결재 단계 순서를 그리드에서 직접 변경 |
|
||||
| 라이브러리 | `@dnd-kit/core`, `@dnd-kit/sortable` — 테이블 행 POC 후 확정 |
|
||||
| 저장 시점 | 드래그는 클라이언트 상태만 변경 → **[결재선 저장]** 또는 행별 **[저장]** 시 `atrzSeqNo` PUT |
|
||||
| 편집 중 | `editingRowKey != null` 이면 드래그 **불가** |
|
||||
| 항목 | 내용 |
|
||||
| ---------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| 목적 | 결재 단계 순서를 그리드에서 직접 변경 |
|
||||
| 라이브러리 | `@dnd-kit/core`, `@dnd-kit/sortable` — 테이블 행 POC 후 확정 |
|
||||
| 저장 시점 | 드래그는 클라이언트 상태만 변경 → **[결재선 저장]** 또는 행별 **[저장]** 시 `atrzSeqNo` PUT |
|
||||
| 편집 중 | `editingRowKey != null` 이면 드래그 **불가** |
|
||||
| 순서 제약 | 드래그 종료 시 `validateAtrzOrder` — 실패하면 순서 변경 미적용 + 안내. 결재구분 미선택 행은 드래그 불가 |
|
||||
|
||||
### 5-3. 보조 다이얼로그 (검토인력만)
|
||||
@@ -371,13 +371,14 @@ END
|
||||
|
||||
### 7-2. 모듈·파일 배치(제안)
|
||||
|
||||
| 구분 | 경로 |
|
||||
| ------ | ------------------------------------------------------------------ |
|
||||
| 라우트 | `apps/as/app/(with-base-layout)/approval-line-management/page.tsx` |
|
||||
| 페이지 | `apps/as/src/pages/approval-line-management/` |
|
||||
| 위젯 | `widgets/elapr-tmplt-list/`, `widgets/elapr-apln-grid/` |
|
||||
| 피처 | `features/aprvr-picker/` (검토인력 [선택]만) |
|
||||
| 엔티티 | `apps/as/src/entities/elapr/` |
|
||||
| 구분 | 경로 |
|
||||
| ------ | -------------------------------------------------------------------------------------- |
|
||||
| 라우트 | `apps/as/app/(with-base-layout)/approval-line-management/page.tsx` |
|
||||
| 페이지 | `apps/as/src/pages/approval-line-management/` (Public API: page만 export) |
|
||||
| UI | `.../ui/elapr-tmplt-list.tsx`, `elapr-tmplt-form-dialog.tsx`, `elapr-apln-grid.tsx` 등 |
|
||||
| model | `.../model/columns.tsx`, `apln-row-types.ts`, `mock-reviewers.ts` |
|
||||
| lib | `.../lib/use-apln-rows.ts`, `validators.ts`, `use-dnd-sensors.ts` |
|
||||
| 엔티티 | `apps/as/src/entities/elapr/` |
|
||||
|
||||
### 7-3. 영역별 UI 매핑
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
import type { Code, CodeService } from "../model/code-interface";
|
||||
@@ -9,9 +9,7 @@ async function getList(upCd: string): Promise<Code[]> {
|
||||
}
|
||||
|
||||
async function getListByUseYn(upCd: string, useYn: string): Promise<Code[]> {
|
||||
const response = await client.get<Code[]>(
|
||||
`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}/${useYn}`,
|
||||
);
|
||||
const response = await client.get<Code[]>(`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}/${useYn}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type { PageResponse } from "@/shared/model";
|
||||
|
||||
@@ -11,17 +11,14 @@ import type {
|
||||
} from "../model/elapr-apln-interface";
|
||||
|
||||
async function findPage(params: ElaprAplnListParams): Promise<PageResponse<ElaprApln>> {
|
||||
const response = await client.get<PageResponse<ElaprApln>>(
|
||||
ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN,
|
||||
{ params },
|
||||
);
|
||||
const response = await client.get<PageResponse<ElaprApln>>(ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN, {
|
||||
params,
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function findById(aplnId: string): Promise<ElaprApln> {
|
||||
const response = await client.get<ElaprApln>(
|
||||
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN}/${aplnId}`,
|
||||
);
|
||||
const response = await client.get<ElaprApln>(`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN}/${aplnId}`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type { PageResponse } from "@/shared/model";
|
||||
|
||||
@@ -26,17 +26,11 @@ async function findById(elaprTmpltId: string): Promise<ElaprTmplt> {
|
||||
}
|
||||
|
||||
async function create(body: ElaprTmpltSaveRequest): Promise<ElaprTmplt> {
|
||||
const response = await client.post<ElaprTmplt>(
|
||||
ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT,
|
||||
body,
|
||||
);
|
||||
const response = await client.post<ElaprTmplt>(ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT, body);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function update(
|
||||
elaprTmpltId: string,
|
||||
body: ElaprTmpltUpdateRequest,
|
||||
): Promise<ElaprTmplt> {
|
||||
async function update(elaprTmpltId: string, body: ElaprTmpltUpdateRequest): Promise<ElaprTmplt> {
|
||||
const response = await client.put<ElaprTmplt>(
|
||||
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT}/${elaprTmpltId}`,
|
||||
body,
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export { AprvrPickerDialog } from "./ui/aprvr-picker-dialog";
|
||||
export type { ReviewerOption } from "./model/mock-reviewers";
|
||||
@@ -1,2 +0,0 @@
|
||||
export { ElaprTmpltFormDialog } from "./ui/elapr-tmplt-form-dialog";
|
||||
export type { ElaprTmpltFormValues } from "./ui/elapr-tmplt-form-dialog";
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { arrayMove } from "@dnd-kit/sortable";
|
||||
|
||||
import type { ElaprApln } from "@/entities/elapr";
|
||||
|
||||
import type { ElaprAplnRow } from "../model/types";
|
||||
import type { ElaprAplnRow } from "../model/apln-row-types";
|
||||
|
||||
import { validateAtrzOrder } from "./validators";
|
||||
|
||||
+1
-6
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from "@dnd-kit/core";
|
||||
import { KeyboardSensor, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
|
||||
import { sortableKeyboardCoordinates } from "@dnd-kit/sortable";
|
||||
|
||||
export function useDndSensors() {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import type { ElaprAplnRow } from "../model/types";
|
||||
import type { ElaprAplnRow } from "../model/apln-row-types";
|
||||
|
||||
export const ATRZ_REVIEWER_CD = "ATRZ01";
|
||||
export const ATRZ_FINAL_CD = "ATRZ03";
|
||||
@@ -3,8 +3,9 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import type { ElaprTmplt } from "@/entities/elapr";
|
||||
import { ElaprAplnGrid } from "@/widgets/elapr-apln-grid";
|
||||
import { ElaprTmpltList } from "@/widgets/elapr-tmplt-list";
|
||||
|
||||
import { ElaprAplnGrid } from "./elapr-apln-grid";
|
||||
import { ElaprTmpltList } from "./elapr-tmplt-list";
|
||||
|
||||
function ApprovalLineManagementPage() {
|
||||
const [selectedTmplt, setSelectedTmplt] = useState<ElaprTmplt | null>(null);
|
||||
|
||||
+4
-7
@@ -1,6 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
|
||||
import { createColumnHelper, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
|
||||
import {
|
||||
Button,
|
||||
DataTable,
|
||||
@@ -11,11 +14,6 @@ import {
|
||||
DialogTitle,
|
||||
Input,
|
||||
} from "@common/components";
|
||||
import {
|
||||
createColumnHelper,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
|
||||
import type { ReviewerOption } from "../model/mock-reviewers";
|
||||
import { createMockReviewers } from "../model/mock-reviewers";
|
||||
@@ -36,8 +34,7 @@ function AprvrPickerDialog({ open, onOpenChange, onSelect }: AprvrPickerDialogPr
|
||||
const q = keyword.trim().toLowerCase();
|
||||
if (!q) return reviewers;
|
||||
return reviewers.filter(
|
||||
(r) =>
|
||||
r.name.toLowerCase().includes(q) || r.deptNm.toLowerCase().includes(q),
|
||||
(r) => r.name.toLowerCase().includes(q) || r.deptNm.toLowerCase().includes(q),
|
||||
);
|
||||
}, [keyword, reviewers]);
|
||||
|
||||
+4
-7
@@ -12,7 +12,6 @@ import {
|
||||
useElaprAplnPage,
|
||||
useUpdateElaprApln,
|
||||
} from "@/entities/elapr";
|
||||
import { AprvrPickerDialog, type ReviewerOption } from "@/features/aprvr-picker";
|
||||
import {
|
||||
Button,
|
||||
Skeleton,
|
||||
@@ -26,8 +25,10 @@ import {
|
||||
import { useAplnRows } from "../lib/use-apln-rows";
|
||||
import { useDndSensors } from "../lib/use-dnd-sensors";
|
||||
import { validateAplnRow, validateAtrzOrder, validateUniqueSeqNo } from "../lib/validators";
|
||||
import type { ElaprAplnRow } from "../model/types";
|
||||
import type { ElaprAplnRow } from "../model/apln-row-types";
|
||||
import type { ReviewerOption } from "../model/mock-reviewers";
|
||||
|
||||
import { AprvrPickerDialog } from "./aprvr-picker-dialog";
|
||||
import { SortableAplnRow } from "./sortable-apln-row";
|
||||
|
||||
interface ElaprAplnGridProps {
|
||||
@@ -74,13 +75,9 @@ function ElaprAplnGrid({ elaprTmpltId }: ElaprAplnGridProps) {
|
||||
const { active, over } = event;
|
||||
if (!over || active.id === over.id) return;
|
||||
|
||||
const { payloadRows, orderError } = reorderRows(String(active.id), String(over.id));
|
||||
const { orderError } = reorderRows(String(active.id), String(over.id));
|
||||
if (orderError) {
|
||||
alert(orderError);
|
||||
return;
|
||||
}
|
||||
if (payloadRows) {
|
||||
// TODO: 결재선 순서 변경 API 호출
|
||||
}
|
||||
};
|
||||
|
||||
+2
-1
@@ -12,11 +12,12 @@ import {
|
||||
useElaprTmpltPage,
|
||||
useUpdateElaprTmplt,
|
||||
} from "@/entities/elapr";
|
||||
import { ElaprTmpltFormDialog, type ElaprTmpltFormValues } from "@/features/elapr-tmplt-dialog";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { createTmpltColumns } from "../model/columns";
|
||||
|
||||
import { ElaprTmpltFormDialog, type ElaprTmpltFormValues } from "./elapr-tmplt-form-dialog";
|
||||
|
||||
interface ElaprTmpltListProps {
|
||||
selectedTmpltId: string | null;
|
||||
onSelectTmplt: (tmplt: ElaprTmplt | null) => void;
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { Equal } from "lucide-react";
|
||||
import { CodeSelect, findCodeLabel, useCodeList } from "@/entities/code";
|
||||
import { Button, Input, TableCell, TableRow } from "@common/components";
|
||||
|
||||
import type { ElaprAplnRow } from "../model/types";
|
||||
import type { ElaprAplnRow } from "../model/apln-row-types";
|
||||
|
||||
interface SortableAplnRowProps {
|
||||
row: ElaprAplnRow;
|
||||
@@ -1 +0,0 @@
|
||||
export { ElaprAplnGrid } from "./ui/elapr-apln-grid";
|
||||
@@ -1 +0,0 @@
|
||||
export { ElaprTmpltList } from "./ui/elapr-tmplt-list";
|
||||
Reference in New Issue
Block a user