[as] feat: 결재선 관리 페이지 구현

This commit is contained in:
2026-05-18 17:40:21 +09:00
parent 0e067bb5fc
commit 25affc06b9
43 changed files with 2071 additions and 236 deletions
@@ -0,0 +1,29 @@
import { client } from "@/shared/api/client";
import { ENDPOINT } from "@/shared/config";
import type { Code, CodeService } from "../model/code-interface";
async function getList(upCd: string): Promise<Code[]> {
const response = await client.get<Code[]>(`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}`);
return response.data;
}
async function getListByUseYn(upCd: string, useYn: string): Promise<Code[]> {
const response = await client.get<Code[]>(
`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}/${useYn}`,
);
return response.data;
}
async function getCodeName(upCd: string, lwpoCd: string): Promise<string> {
const response = await client.get<string>(
`${ENDPOINT.CMS_SERVICE.CODE}/${upCd}/lwpoCd/${lwpoCd}`,
);
return response.data;
}
export const codeService = {
getList,
getListByUseYn,
getCodeName,
} satisfies CodeService;
+36
View File
@@ -0,0 +1,36 @@
import { useQuery } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import { codeService } from "./code-service";
const codeBaseKey = [ENDPOINT.CMS_SERVICE.CODE] as const;
const CODE_STALE_TIME = 1000 * 60 * 10;
export function useCodeList(upCd: string | undefined) {
return useQuery({
queryKey: [...codeBaseKey, upCd],
queryFn: () => codeService.getList(upCd!),
enabled: Boolean(upCd),
staleTime: CODE_STALE_TIME,
});
}
export function useCodeListByUseYn(upCd: string | undefined, useYn: string) {
return useQuery({
queryKey: [...codeBaseKey, upCd, useYn],
queryFn: () => codeService.getListByUseYn(upCd!, useYn),
enabled: Boolean(upCd && useYn),
staleTime: CODE_STALE_TIME,
});
}
export function useCodeName(upCd: string | undefined, lwpoCd: string | undefined) {
return useQuery({
queryKey: [...codeBaseKey, upCd, "name", lwpoCd],
queryFn: () => codeService.getCodeName(upCd!, lwpoCd!),
enabled: Boolean(upCd && lwpoCd),
staleTime: CODE_STALE_TIME,
});
}
+6
View File
@@ -0,0 +1,6 @@
export { codeService } from "./api/code-service";
export { useCodeList, useCodeListByUseYn, useCodeName } from "./api/queries";
export { findCodeLabel } from "./lib/find-code-label";
export { UP_CD } from "./lib/up-cd-constants";
export { CodeSelect } from "./ui/code-select";
export type { Code, CodeService } from "./model/code-interface";
@@ -0,0 +1,7 @@
import type { Code } from "../model/code-interface";
export function findCodeLabel(codes: Code[] | undefined, lwpoCd?: string): string {
if (!lwpoCd) return "";
if (!codes?.length) return lwpoCd;
return codes.find((c) => c.lwpoCd === lwpoCd)?.lwpoCdNm ?? lwpoCd;
}
@@ -0,0 +1,5 @@
/** 결재선 관리 SPEC 상위코드 */
export const UP_CD = {
DOC_SE: "ASDOCSECD",
ATRZ_SE: "ATRZSECD",
} as const;
@@ -0,0 +1,14 @@
/** cms-service CodeResponseDto */
export interface Code {
lwpoCd: string;
upCd: string;
lwpoCdNm: string;
unit?: string;
prntLwpoCd?: string;
}
export interface CodeService {
getList(upCd: string): Promise<Code[]>;
getListByUseYn(upCd: string, useYn: string): Promise<Code[]>;
getCodeName(upCd: string, lwpoCd: string): Promise<string>;
}
@@ -0,0 +1,50 @@
"use client";
import {
cn,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@common/components";
import { useCodeList, useCodeListByUseYn } from "../api/queries";
interface CodeSelectProps extends React.ComponentPropsWithoutRef<typeof Select> {
upCd: string;
useYn?: string;
placeholder?: string;
className?: string;
}
function CodeSelect({
upCd,
useYn,
placeholder = "선택",
className,
...props
}: CodeSelectProps) {
const listQuery = useCodeList(useYn ? undefined : upCd);
const listByUseYnQuery = useCodeListByUseYn(useYn ? upCd : undefined, useYn ?? "");
const codes = useYn ? listByUseYnQuery.data : listQuery.data;
const isLoading = useYn ? listByUseYnQuery.isPending : listQuery.isPending;
return (
<Select {...props} disabled={props.disabled || isLoading}>
<SelectTrigger className={cn("w-[12rem]", className)}>
<SelectValue placeholder={isLoading ? "로딩 중…" : placeholder} />
</SelectTrigger>
<SelectContent>
{codes?.map((item) => (
<SelectItem key={item.lwpoCd} value={item.lwpoCd}>
{item.lwpoCdNm}
</SelectItem>
))}
</SelectContent>
</Select>
);
}
export { CodeSelect };
@@ -0,0 +1,51 @@
import { client } from "@/shared/api/client";
import { ENDPOINT } from "@/shared/config";
import type { PageResponse } from "@/shared/model";
import type {
ElaprApln,
ElaprAplnListParams,
ElaprAplnSaveRequest,
ElaprAplnService,
ElaprAplnUpdateRequest,
} 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 },
);
return response.data;
}
async function findById(aplnId: string): Promise<ElaprApln> {
const response = await client.get<ElaprApln>(
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN}/${aplnId}`,
);
return response.data;
}
async function create(body: ElaprAplnSaveRequest): Promise<ElaprApln> {
const response = await client.post<ElaprApln>(ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN, body);
return response.data;
}
async function update(aplnId: string, body: ElaprAplnUpdateRequest): Promise<ElaprApln> {
const response = await client.put<ElaprApln>(
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN}/${aplnId}`,
body,
);
return response.data;
}
async function remove(aplnId: string): Promise<void> {
await client.delete(`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN}/${aplnId}`);
}
export const elaprAplnService = {
findPage,
findById,
create,
update,
remove,
} satisfies ElaprAplnService;
@@ -0,0 +1,57 @@
import { client } from "@/shared/api/client";
import { ENDPOINT } from "@/shared/config";
import type { PageResponse } from "@/shared/model";
import type {
ElaprTmplt,
ElaprTmpltSaveRequest,
ElaprTmpltSearchParams,
ElaprTmpltService,
ElaprTmpltUpdateRequest,
} from "../model/elapr-tmplt-interface";
async function findPage(params: ElaprTmpltSearchParams): Promise<PageResponse<ElaprTmplt>> {
const response = await client.get<PageResponse<ElaprTmplt>>(
ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT,
{ params },
);
return response.data;
}
async function findById(elaprTmpltId: string): Promise<ElaprTmplt> {
const response = await client.get<ElaprTmplt>(
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT}/${elaprTmpltId}`,
);
return response.data;
}
async function create(body: ElaprTmpltSaveRequest): Promise<ElaprTmplt> {
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> {
const response = await client.put<ElaprTmplt>(
`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT}/${elaprTmpltId}`,
body,
);
return response.data;
}
async function remove(elaprTmpltId: string): Promise<void> {
await client.delete(`${ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT}/${elaprTmpltId}`);
}
export const elaprTmpltService = {
findPage,
findById,
create,
update,
remove,
} satisfies ElaprTmpltService;
+151
View File
@@ -0,0 +1,151 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ENDPOINT } from "@/shared/config";
import type {
ElaprAplnListParams,
ElaprAplnSaveRequest,
ElaprAplnUpdateRequest,
} from "../model/elapr-apln-interface";
import type {
ElaprTmpltSaveRequest,
ElaprTmpltSearchParams,
ElaprTmpltUpdateRequest,
} from "../model/elapr-tmplt-interface";
import { elaprAplnService } from "./elapr-apln-service";
import { elaprTmpltService } from "./elapr-tmplt-service";
const elaprTmpltBaseKey = [ENDPOINT.AS_ELAPR_SERVICE.ELAPR_TMPLT] as const;
const elaprAplnBaseKey = [ENDPOINT.AS_ELAPR_SERVICE.ELAPR_APLN] as const;
export function useElaprTmpltPage(params: ElaprTmpltSearchParams) {
return useQuery({
queryKey: [...elaprTmpltBaseKey, "page", params],
queryFn: () => elaprTmpltService.findPage(params),
});
}
export function useElaprTmplt(elaprTmpltId: string | null | undefined) {
return useQuery({
queryKey: [...elaprTmpltBaseKey, elaprTmpltId],
queryFn: () => elaprTmpltService.findById(elaprTmpltId!),
enabled: Boolean(elaprTmpltId),
});
}
export function useCreateElaprTmplt() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (body: ElaprTmpltSaveRequest) => elaprTmpltService.create(body),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: elaprTmpltBaseKey });
},
});
}
export function useUpdateElaprTmplt() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
elaprTmpltId,
body,
}: {
elaprTmpltId: string;
body: ElaprTmpltUpdateRequest;
}) => elaprTmpltService.update(elaprTmpltId, body),
onSuccess: (_data, { elaprTmpltId }) => {
queryClient.invalidateQueries({ queryKey: elaprTmpltBaseKey });
queryClient.invalidateQueries({
queryKey: [...elaprTmpltBaseKey, elaprTmpltId],
});
},
});
}
export function useDeleteElaprTmplt() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (elaprTmpltId: string) => elaprTmpltService.remove(elaprTmpltId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: elaprTmpltBaseKey });
},
});
}
export function useElaprAplnPage(params: ElaprAplnListParams) {
const { elaprTmpltId } = params;
return useQuery({
queryKey: [...elaprAplnBaseKey, "page", params],
queryFn: () => elaprAplnService.findPage(params),
enabled: Boolean(elaprTmpltId),
});
}
export function useElaprApln(aplnId: string | null | undefined) {
return useQuery({
queryKey: [...elaprAplnBaseKey, aplnId],
queryFn: () => elaprAplnService.findById(aplnId!),
enabled: Boolean(aplnId),
});
}
export function useCreateElaprApln() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (body: ElaprAplnSaveRequest) => elaprAplnService.create(body),
onSuccess: (_data, { elaprTmpltId }) => {
queryClient.invalidateQueries({ queryKey: elaprAplnBaseKey });
queryClient.invalidateQueries({
queryKey: [...elaprAplnBaseKey, "page", { elaprTmpltId }],
});
},
});
}
export function useUpdateElaprApln() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
aplnId,
body,
}: {
aplnId: string;
body: ElaprAplnUpdateRequest;
}) => elaprAplnService.update(aplnId, body),
onSuccess: (_data, { body, aplnId }) => {
queryClient.invalidateQueries({ queryKey: elaprAplnBaseKey });
queryClient.invalidateQueries({
queryKey: [...elaprAplnBaseKey, aplnId],
});
queryClient.invalidateQueries({
queryKey: [...elaprAplnBaseKey, "page", { elaprTmpltId: body.elaprTmpltId }],
});
},
});
}
export function useDeleteElaprApln() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
aplnId,
}: {
aplnId: string;
elaprTmpltId: string;
}) => elaprAplnService.remove(aplnId),
onSuccess: (_data, { elaprTmpltId }) => {
queryClient.invalidateQueries({ queryKey: elaprAplnBaseKey });
queryClient.invalidateQueries({
queryKey: [...elaprAplnBaseKey, "page", { elaprTmpltId }],
});
},
});
}
+28
View File
@@ -0,0 +1,28 @@
export { elaprAplnService } from "./api/elapr-apln-service";
export { elaprTmpltService } from "./api/elapr-tmplt-service";
export {
useCreateElaprApln,
useCreateElaprTmplt,
useDeleteElaprApln,
useDeleteElaprTmplt,
useElaprApln,
useElaprAplnPage,
useElaprTmplt,
useElaprTmpltPage,
useUpdateElaprApln,
useUpdateElaprTmplt,
} from "./api/queries";
export type {
ElaprApln,
ElaprAplnListParams,
ElaprAplnSaveRequest,
ElaprAplnService,
ElaprAplnUpdateRequest,
} from "./model/elapr-apln-interface";
export type {
ElaprTmplt,
ElaprTmpltSaveRequest,
ElaprTmpltSearchParams,
ElaprTmpltService,
ElaprTmpltUpdateRequest,
} from "./model/elapr-tmplt-interface";
@@ -0,0 +1,41 @@
import type { PageableParams, PageResponse } from "@/shared/model";
export interface ElaprApln {
aplnId: string;
elaprTmpltId: string;
aprvrUuid?: string;
atrzSeComCd?: string;
atrzSeComNm?: string;
atrzSeqNo?: number;
regDt?: string;
rgtrUuid?: string;
mdfcnDt?: string;
mdfrUuid?: string;
}
export interface ElaprAplnListParams extends PageableParams {
elaprTmpltId?: string;
}
export interface ElaprAplnSaveRequest {
aplnId: string;
elaprTmpltId: string;
aprvrUuid?: string;
atrzSeComCd?: string;
atrzSeqNo?: number;
}
export interface ElaprAplnUpdateRequest {
elaprTmpltId: string;
aprvrUuid?: string;
atrzSeComCd?: string;
atrzSeqNo?: number;
}
export interface ElaprAplnService {
findPage(params: ElaprAplnListParams): Promise<PageResponse<ElaprApln>>;
findById(aplnId: string): Promise<ElaprApln>;
create(body: ElaprAplnSaveRequest): Promise<ElaprApln>;
update(aplnId: string, body: ElaprAplnUpdateRequest): Promise<ElaprApln>;
remove(aplnId: string): Promise<void>;
}
@@ -0,0 +1,41 @@
import type { PageableParams, PageResponse } from "@/shared/model";
export interface ElaprTmplt {
elaprTmpltId: string;
elaprTmpltNm: string;
elaprTmpltExpln?: string;
docSeComCd?: string;
docSeComNm?: string;
regDt?: string;
rgtrUuid?: string;
mdfcnDt?: string;
mdfrUuid?: string;
}
export interface ElaprTmpltSearchParams extends PageableParams {
elaprTmpltNm?: string;
docSeComCd?: string;
regDtStart?: string;
regDtEnd?: string;
}
export interface ElaprTmpltSaveRequest {
elaprTmpltId: string;
elaprTmpltNm: string;
elaprTmpltExpln?: string;
docSeComCd?: string;
}
export interface ElaprTmpltUpdateRequest {
elaprTmpltNm: string;
elaprTmpltExpln?: string;
docSeComCd?: string;
}
export interface ElaprTmpltService {
findPage(params: ElaprTmpltSearchParams): Promise<PageResponse<ElaprTmplt>>;
findById(elaprTmpltId: string): Promise<ElaprTmplt>;
create(body: ElaprTmpltSaveRequest): Promise<ElaprTmplt>;
update(elaprTmpltId: string, body: ElaprTmpltUpdateRequest): Promise<ElaprTmplt>;
remove(elaprTmpltId: string): Promise<void>;
}