diff --git a/apps/common/features/src/entities/site/@x/posting.ts b/apps/common/features/src/entities/site/@x/posting.ts index 6470b3cb2..355f41e4d 100644 --- a/apps/common/features/src/entities/site/@x/posting.ts +++ b/apps/common/features/src/entities/site/@x/posting.ts @@ -1,2 +1,3 @@ export { SiteApi } from "../api/site-service"; export type { Site } from "../model/site-interface"; +export { SiteSelect } from "../ui/site-select"; \ No newline at end of file diff --git a/apps/common/features/src/entities/site/index.ts b/apps/common/features/src/entities/site/index.ts index c7b437a64..998c13625 100644 --- a/apps/common/features/src/entities/site/index.ts +++ b/apps/common/features/src/entities/site/index.ts @@ -5,3 +5,5 @@ export { type Site, type SiteFormData, } from "./model/site-interface"; + +export { SiteSelect } from "./ui/site-select"; \ No newline at end of file diff --git a/apps/common/features/src/entities/site/ui/site-select.tsx b/apps/common/features/src/entities/site/ui/site-select.tsx new file mode 100644 index 000000000..b7500d0e7 --- /dev/null +++ b/apps/common/features/src/entities/site/ui/site-select.tsx @@ -0,0 +1,48 @@ +import { useQuery } from "@tanstack/react-query"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@common/components"; +import { ENDPOINT } from "@/shared/config"; +import { SiteApi } from "../api/site-service"; + +type SiteSelectProps = { + siteId: string; + placeholder?: string; +} & React.ComponentPropsWithoutRef; + +function SiteSelect({ + siteId, + defaultValue, + placeholder = "선택", + ...props +}: SiteSelectProps) { + const { data: sites } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.SITES], + queryFn: () => SiteApi.getSiteList(), + enabled: !!siteId, + }); + + const defaultValueText = + sites?.content.find((item) => item.siteId === defaultValue)?.siteNm ?? placeholder; + + return ( + + ); +} + +export { SiteSelect }; diff --git a/apps/cs/app/(with-base-layout)/code/page.tsx b/apps/cs/app/(with-base-layout)/code/page.tsx new file mode 100644 index 000000000..3ac19ec1c --- /dev/null +++ b/apps/cs/app/(with-base-layout)/code/page.tsx @@ -0,0 +1,2 @@ +import { CodePage } from "@/pages/code"; +export default CodePage; diff --git a/apps/cs/src/entities/code/api/lwpocode-service.ts b/apps/cs/src/entities/code/api/lwpocode-service.ts new file mode 100644 index 000000000..045a6ee6d --- /dev/null +++ b/apps/cs/src/entities/code/api/lwpocode-service.ts @@ -0,0 +1,61 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import { + LwpoCodeFormSchema, + type LwpoCodeService, + type LwpoCodeList, + type LwpoCodeDetail, + type LwpoCodeParams, + type LwpoCodeFormData, +} from "../model/lwpocode-interface"; + +export class LwpoCodeApiService implements LwpoCodeService { + public async getLwpoCodeList(params?: LwpoCodeParams): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}`, + { params }, + ); + return response.data; + } + + public async getUpCodeLwpoCodeList(upCd: string): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}/up-cd/${upCd}`, + ); + return response.data; + } + + public async LwpoCodeDetail(upCd: string, LwpoCd: string): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}/${LwpoCd}/up-cd/${upCd}`, + ); + return response.data; + } + + public async createLwpoCode(data: LwpoCodeFormData): Promise { + const validatedData = LwpoCodeFormSchema.parse(data); + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}`, + validatedData, + ); + return response.data; + } + + public async updateLwpoCode(upCd: string, LwpoCd: string, data: LwpoCodeFormData): Promise { + const validatedData = LwpoCodeFormSchema.parse(data); + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}/${LwpoCd}/up-cd/${upCd}`, + validatedData, + ); + return response.data; + } + + public async deleteLwpoCode(upCd: string, LwpoCd: string): Promise { + await client.delete( + `${ENDPOINT.CMS_SERVICE.LWPO_CODE}/${LwpoCd}/up-cd/${upCd}`, + ); + } + +} + +export const lwpoCodeApi = new LwpoCodeApiService(); diff --git a/apps/cs/src/entities/code/api/upcode-service.ts b/apps/cs/src/entities/code/api/upcode-service.ts new file mode 100644 index 000000000..86c936a1f --- /dev/null +++ b/apps/cs/src/entities/code/api/upcode-service.ts @@ -0,0 +1,48 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import { + upCodeFormSchema, + type UpCodeService, + type UpCodeList, + type UpCodeDetail, + type UpCodeParams, + type UpCodeFormData, +} from "../model/upcode-interface"; + +export class UpCodeApiService implements UpCodeService { + public async getUpCodeList(params?: UpCodeParams): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.UP_CODE}`, + { params }, + ); + return response.data; + } + + public async upCodeDetail(upCd: string): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.UP_CODE}/${upCd}`, + ); + return response.data; + } + + public async createUpCode(data: UpCodeFormData): Promise { + const validatedData = upCodeFormSchema.parse(data); + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.UP_CODE}`, + validatedData, + ); + return response.data; + } + + public async updateUpCode(upCd: string, data: UpCodeFormData): Promise { + const validatedData = upCodeFormSchema.parse(data); + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.UP_CODE}/${upCd}`, + validatedData, + ); + return response.data; + } + +} + +export const upCodeApi = new UpCodeApiService(); diff --git a/apps/cs/src/entities/code/index.ts b/apps/cs/src/entities/code/index.ts index dc74bbc47..4cb1c1547 100644 --- a/apps/cs/src/entities/code/index.ts +++ b/apps/cs/src/entities/code/index.ts @@ -1,3 +1,14 @@ export { CodeApi } from "./api/code-service"; export type { ICode } from "./model/code-interface"; export { CodeSelect } from "./ui/code-select"; + + +export { upCodeApi } from "./api/upcode-service"; +export type { UpCode } from "./model/upcode-interface"; +export { upCodeFormSchema, type UpCodeFormData } from "./model/upcode-interface"; + +export { lwpoCodeApi} from "./api/lwpocode-service"; +export type { LwpoCode } from "./model/lwpocode-interface"; +export { LwpoCodeFormSchema, type LwpoCodeFormData } from "./model/lwpocode-interface"; + + diff --git a/apps/cs/src/entities/code/model/lwpocode-interface.ts b/apps/cs/src/entities/code/model/lwpocode-interface.ts new file mode 100644 index 000000000..eec2b82d2 --- /dev/null +++ b/apps/cs/src/entities/code/model/lwpocode-interface.ts @@ -0,0 +1,61 @@ +import { z } from "zod"; +import type { PageableParams, PageableList } from "@/shared/model"; + +export interface LwpoCodeParams extends PageableParams { + upCd?: string; + lwpoCd?: string; + lwpoCdNm?: string; + useYn?: string; +} + +export interface LwpoCode { + lwpoCd: string; + upCd: string; + lwpoCdNm: string; + lwpoCdExpln: string; + unit: string; + prntLwpoCd: string; + useYn: string; + sortSeq: number; + regDt: string; + rgTr: string; + rgTrNm: string; + mdfcnDt: string; + mdFr: string; +} + +export interface LwpoCodeDetail extends LwpoCodeFormData { + lwpoCd: string; + upCd: string; + lwpoCdNm: string; + lwpoCdExpln: string; + unit: string; + prntLwpoCd: string; + useYn: string; + sortSeq: 0; +} + +export const LwpoCodeFormSchema = z.object({ + lwpoCd: z.string().max(10).nonempty(), + upCd: z.string().max(10).nonempty(), + lwpoCdNm: z.string().max(100).nonempty(), + lwpoCdExpln: z.string().max(1000).nullish(), + unit: z.string().max(20).nullish(), + prntLwpoCd: z.string().max(10).nullish(), + useYn: z.string(), + sortSeq: z.number(), + delYn: z.string(), +}); + +export type LwpoCodeFormData = z.infer; +export type LwpoCodeList = PageableList; + +export interface LwpoCodeService { + getLwpoCodeList(params: LwpoCodeParams): Promise; + getUpCodeLwpoCodeList(upCd: string): Promise; + LwpoCodeDetail(upCd: string, LwpoCode: string): Promise; + updateLwpoCode(upCd: string, LwpoCode: string, data: LwpoCodeFormData): Promise; + createLwpoCode(data: LwpoCodeFormData): Promise; + deleteLwpoCode(upCd: string, LwpoCode: string, data: LwpoCodeFormData): Promise; +} + \ No newline at end of file diff --git a/apps/cs/src/entities/code/model/upcode-interface.ts b/apps/cs/src/entities/code/model/upcode-interface.ts new file mode 100644 index 000000000..d3e9680c1 --- /dev/null +++ b/apps/cs/src/entities/code/model/upcode-interface.ts @@ -0,0 +1,53 @@ +import { z } from "zod"; +import type { PageableParams, PageableList } from "@/shared/model"; + +export interface UpCodeParams extends PageableParams { + keyword?: string; + upCd?: string; + cdSe?: string; + useYn?: string; + siteId?: string; +} + +export interface UpCode { + upCd: string; + upCdNm: string; + upCdExpln: string; + cdSe: string; + siteId: string; + useYn: string; + regDt: string; +} + +export interface UpCodeDetail extends UpCodeFormData { + upCd: string; + upCdNm: string; + upCdExpln: string; + cdSe: string; + siteId: string; + useYn: string; + delYn: string; + regDt: string; + rgTrNm: string; +} + +export const upCodeFormSchema = z.object({ + upCd: z.string().max(10).nonempty(), + upCdNm: z.string().max(100).nonempty(), + upCdExpln: z.string().max(1000).nullish(), + cdSe: z.string().max(10).nonempty(), + siteId: z.string().max(2).nullish(), + useYn: z.string(), + delYn: z.string(), +}); + +export type UpCodeFormData = z.infer; +export type UpCodeList = PageableList; + +export interface UpCodeService { + getUpCodeList(params: UpCodeParams): Promise; + upCodeDetail(upCodeId: string): Promise; + updateUpCode(upCodeId: string, data: UpCodeFormData): Promise; + createUpCode(data: UpCodeFormData): Promise; +} + \ No newline at end of file diff --git a/apps/cs/src/entities/site/@x/posting.ts b/apps/cs/src/entities/site/@x/posting.ts index 6470b3cb2..b44c10445 100644 --- a/apps/cs/src/entities/site/@x/posting.ts +++ b/apps/cs/src/entities/site/@x/posting.ts @@ -1,2 +1,4 @@ export { SiteApi } from "../api/site-service"; export type { Site } from "../model/site-interface"; + +export { SiteSelect } from "../ui/site-select"; diff --git a/apps/cs/src/entities/site/index.ts b/apps/cs/src/entities/site/index.ts index c7b437a64..998c13625 100644 --- a/apps/cs/src/entities/site/index.ts +++ b/apps/cs/src/entities/site/index.ts @@ -5,3 +5,5 @@ export { type Site, type SiteFormData, } from "./model/site-interface"; + +export { SiteSelect } from "./ui/site-select"; \ No newline at end of file diff --git a/apps/cs/src/entities/site/ui/site-select.tsx b/apps/cs/src/entities/site/ui/site-select.tsx new file mode 100644 index 000000000..af2773958 --- /dev/null +++ b/apps/cs/src/entities/site/ui/site-select.tsx @@ -0,0 +1,48 @@ +import { useQuery } from "@tanstack/react-query"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@common/components"; +import { ENDPOINT } from "@/shared/config"; +import { SiteApi } from "../api/site-service"; + +type SiteSelectProps = { + siteId: string; + placeholder?: string; +} & React.ComponentPropsWithoutRef; + +function SiteSelect({ + siteId, + defaultValue, + placeholder = "선택", + ...props +}: SiteSelectProps) { + const { data: sites } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.SITES], + queryFn: () => SiteApi.getSiteList(), + enabled: true, + }); + + const defaultValueText = + sites?.content.find((item) => item.siteId === defaultValue)?.siteNm ?? placeholder; + + return ( + + ); +} + +export { SiteSelect }; diff --git a/apps/cs/src/pages/bbs/model/table-columns.tsx b/apps/cs/src/pages/bbs/model/table-columns.tsx index f3975aca2..5a6cb62f8 100644 --- a/apps/cs/src/pages/bbs/model/table-columns.tsx +++ b/apps/cs/src/pages/bbs/model/table-columns.tsx @@ -10,7 +10,12 @@ export const columns: ColumnDef[] = [ { id: "no", header: "NO", - cell: ({ row }) => row.index + 1, + cell: ({ row, table }) => { + const totalRows = table.getRowCount(); + const currentPage = table.getState().pagination.pageIndex; + const pageSize = table.getState().pagination.pageSize; + return totalRows - (currentPage * pageSize + row.index); + }, }, { accessorKey: "bbsNm", diff --git a/apps/cs/src/pages/code/index.ts b/apps/cs/src/pages/code/index.ts new file mode 100644 index 000000000..37c2c776a --- /dev/null +++ b/apps/cs/src/pages/code/index.ts @@ -0,0 +1 @@ +export { CodePage } from "./ui/code-page"; \ No newline at end of file diff --git a/apps/cs/src/pages/code/model/table-columns.tsx b/apps/cs/src/pages/code/model/table-columns.tsx new file mode 100644 index 000000000..1a486bd5a --- /dev/null +++ b/apps/cs/src/pages/code/model/table-columns.tsx @@ -0,0 +1,123 @@ +import dayjs from "dayjs"; +import { type ColumnDef} from "@tanstack/react-table"; +import { Button } from "@common/components"; +import type { UpCode } from "@/entities/code/model/upcode-interface"; +import type { LwpoCode } from "@/entities/code/model/lwpocode-interface"; + +type UpCodeTableMeta = { + onManagementClick?: (row: UpCode) => void; +}; + +type LwpoCodeTableMeta = { + onManagementClick?: (row: LwpoCode) => void; +}; + +export const upCodecolumns: ColumnDef[] = [ + { + id: "no", + header: "NO", + cell: ({ row, table }) => { + const isSelected = row.getIsSelected(); + if (isSelected) { + return "▶"; + } + const totalRows = table.getRowCount(); + const currentPage = table.getState().pagination.pageIndex; + const pageSize = table.getState().pagination.pageSize; + return totalRows - (currentPage * pageSize + row.index); + }, + }, + { + accessorKey: "upCd", + header: "상위코드", + }, + { + accessorKey: "upCdNm", + header: "상위코드명", + }, + { + accessorKey: "cdSe", + header: "코드구분", + }, + { + accessorKey: "useYn", + header: "사용여부", + }, + { + accessorKey: "regDt", + header: "등록일", + cell: ({ row }) => { + const date = dayjs(row.original.regDt); + return date.format("YYYY-MM-DD"); + }, + }, + { + id: "management", + header: "관리", + cell: ({ row, table }) => { + const onManagementClick = (table.options.meta as UpCodeTableMeta)?.onManagementClick; + return ( + + ); + }, + }, +]; + +export const lowCodecolumns: ColumnDef[] = [ + { + id: "no", + header: "NO", + cell: ({ row, table }) => { + const totalRows = table.getRowCount(); + const currentPage = table.getState().pagination.pageIndex; + const pageSize = table.getState().pagination.pageSize; + return totalRows - (currentPage * pageSize + row.index); + }, + }, + { + accessorKey: "lwpoCd", + header: "하위코드", + }, + { + accessorKey: "lwpoCdNm", + header: "하위코드명", + }, + { + accessorKey: "useYn", + header: "사용 여부", + }, + { + accessorKey: "regDt", + header: "등록일", + cell: ({ row }) => { + const date = dayjs(row.original.regDt); + return date.format("YYYY-MM-DD"); + }, + }, + { + id: "management", + header: "관리", + cell: ({ row, table }) => { + const onManagementClick = (table.options.meta as LwpoCodeTableMeta)?.onManagementClick; + return ( + + ); + }, + }, +]; diff --git a/apps/cs/src/pages/code/ui/code-page.tsx b/apps/cs/src/pages/code/ui/code-page.tsx new file mode 100644 index 000000000..4a4fa74da --- /dev/null +++ b/apps/cs/src/pages/code/ui/code-page.tsx @@ -0,0 +1,248 @@ +"use client"; + +import "@common/assets/styles/grid.css"; + +import { useEffect, useState } from "react"; +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + useReactTable, + type PaginationState, +} from "@tanstack/react-table"; +import { Button, DataTable, Input, Label } from "@common/components"; +import { upCodeApi } from "@/entities/code/api/upcode-service"; +import { type UpCode, type UpCodeParams } from "@/entities/code/model/upcode-interface"; +import { type LwpoCode, type LwpoCodeParams } from "@/entities/code/model/lwpocode-interface"; +import { ENDPOINT } from "@/shared/config"; +import { upCodecolumns, lowCodecolumns } from "../model/table-columns"; +import { lwpoCodeApi } from "@/entities/code/api/lwpocode-service"; +import { ManagementUpCodeDialog } from "./upcode-dialog"; +import { ManagementLwpoCodeDialog } from "./lowcode-dialog"; + +function CodePage() { + const [selectedUpCode, setSelectedUpCode] = useState(null); + const [isManagementDialogOpen, setIsManagementDialogOpen] = useState(false); + + const [isRegistrationMode, setIsRegistrationMode] = useState(false); + const [isLwpoCodeRegistrationMode, setIsLwpoCodeRegistrationMode] = useState(false); + + const [selectedLwpoCode, setSelectedLwpoCode] = useState(null); + const [isLwpoCodeManagementDialogOpen, setIsLwpoCodeManagementDialogOpen] = useState(false); + + const [upCodeQuery, setUpCodeQuery] = useState({ + upCd: "", + }); + const [lwpoCodeQuery, setLwpoCodeQuery] = useState({ + upCd: "", + lwpoCd: "", + }); + const [upCodePagination, setUpCodePagination] = useState({ + pageIndex: 0, + pageSize: 10, + }); + + const [lwpoCodePagination, setLwpoCodePagination] = useState({ + pageIndex: 0, + pageSize: 1000, + }); + + const { data: upCodeList, refetch: refetchUpCode } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE], + queryFn: () => + upCodeApi.getUpCodeList({ + ...upCodeQuery, + page: upCodePagination.pageIndex, + size: upCodePagination.pageSize, + }), + placeholderData: keepPreviousData, + }); + + const { data: lwpoCodeList, refetch: refetchLwpoCode } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, lwpoCodeQuery], + queryFn: () => + lwpoCodeApi.getLwpoCodeList({ + ...lwpoCodeQuery, + page: lwpoCodePagination.pageIndex, + size: lwpoCodePagination.pageSize, + }), + enabled: !!lwpoCodeQuery.upCd, + }); + + + const upCodehandleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + refetchUpCode(); + }; + + const upCodehandleRowClick = (row: UpCode) => { + setSelectedUpCode(row); + setLwpoCodeQuery({ ...lwpoCodeQuery, upCd: row.upCd }); + refetchLwpoCode(); + }; + + const handleManagementClick = (row: UpCode) => { + setSelectedUpCode(row); + setIsRegistrationMode(false); + setIsManagementDialogOpen(true); + }; + + const handleRegistrationClick = () => { + setSelectedUpCode(null); + setIsRegistrationMode(true); + setIsManagementDialogOpen(true); + }; + + const handleLwpoCodeManagementClick = (row: LwpoCode) => { + setSelectedLwpoCode(row); + setIsLwpoCodeRegistrationMode(false); + setIsLwpoCodeManagementDialogOpen(true); + }; + + const handleLwpoCodeRegistrationClick = () => { + if (!selectedUpCode?.upCd) { + alert("상위코드를 선택해주세요."); + return; + } + setSelectedLwpoCode(null); + setIsLwpoCodeRegistrationMode(true); + setIsLwpoCodeManagementDialogOpen(true); + }; + + + const upCodeTable = useReactTable({ + data: upCodeList?.content ?? [], + columns: upCodecolumns, + rowCount: upCodeList?.totalElements ?? 0, + state: { + pagination: upCodePagination, + rowSelection: selectedUpCode ? { [selectedUpCode.upCd]: true } : {}, + }, + onPaginationChange: setUpCodePagination, + getCoreRowModel: getCoreRowModel(), + manualPagination: true, + meta: { + onManagementClick: handleManagementClick, + }, + getRowId: (row) => row.upCd, + }); + + const lwpoCodeTable = useReactTable({ + data: lwpoCodeList?.content ?? [], + columns: lowCodecolumns, + rowCount: lwpoCodeList?.totalElements ?? 0, + state: { + pagination: lwpoCodePagination, + rowSelection: selectedLwpoCode ? { [selectedLwpoCode.lwpoCd]: true } : {}, + }, + onPaginationChange: setLwpoCodePagination, + getCoreRowModel: getCoreRowModel(), + manualPagination: true, + meta: { + onManagementClick: handleLwpoCodeManagementClick, + }, + getRowId: (row) => row.lwpoCd, + }); + + const lwpoCodehandleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + refetchLwpoCode(); + }; + + useEffect(() => { + refetchUpCode(); + }, [upCodePagination]); + + return ( +
+
+
+
+
+ + + setUpCodeQuery({ + ...upCodeQuery, + keyword: e.target.value, + }) + } + /> + +
+
+
+
+

상위코드 목록

+ +
+
+ +
+
+
+
+
+
+ + setLwpoCodeQuery({ + ...lwpoCodeQuery, + lwpoCdNm: e.target.value + }) + } + /> + +
+
+
+
+

하위코드 목록

+ +
+
+ +
+
+
+
+ {isManagementDialogOpen && ( + + )} + {isLwpoCodeManagementDialogOpen && ( + + )} +
+ ); + } + + export { CodePage }; + \ No newline at end of file diff --git a/apps/cs/src/pages/code/ui/lowcode-dialog.tsx b/apps/cs/src/pages/code/ui/lowcode-dialog.tsx new file mode 100644 index 000000000..1c64c8ade --- /dev/null +++ b/apps/cs/src/pages/code/ui/lowcode-dialog.tsx @@ -0,0 +1,292 @@ +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { + Button, + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Input, + RadioGroup, + RadioGroupItem, + Label, +} from "@common/components"; +import { Form, FormField, FormItem, FormControl } from "@/shared/ui/form"; +import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { lwpoCodeApi } from "@/entities/code/api/lwpocode-service"; +import { LwpoCodeFormSchema, type LwpoCodeFormData } from "@/entities/code/model/lwpocode-interface"; +import { ENDPOINT } from "@/shared/config"; +import { upCodeApi } from "@/entities/code/api/upcode-service"; + +type ManagementLwpoCodeDialogProps = { + upCd?: string; + lwpoCd?: string; + open?: boolean; + onOpenChange?: (open: boolean) => void; + isRegistration?: boolean; +} & Omit, 'open' | 'onOpenChange'>; + +function ManagementLwpoCodeDialog({ + lwpoCd, + upCd, + open, + onOpenChange, + isRegistration = false, + ...props +}: ManagementLwpoCodeDialogProps) { + const { confirm } = useConfirm(); + const { setMessage: alert } = useAlertStore((state) => state); + + const { data: detailData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, lwpoCd], + queryFn: () => lwpoCodeApi.LwpoCodeDetail(upCd as string, lwpoCd as string), + enabled: !!upCd && !!lwpoCd && !isRegistration, + }); + + const { data: upCodeData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE, upCd], + queryFn: () => upCodeApi.upCodeDetail(upCd as string), + enabled: !!upCd, + }); + + const { mutateAsync: saveLwpoCode } = useMutation({ + mutationFn: (data: LwpoCodeFormData) => + isRegistration ? lwpoCodeApi.createLwpoCode(data) : lwpoCodeApi.updateLwpoCode(upCd as string, lwpoCd as string, data), + onSuccess: () => { + alert(isRegistration ? "등록되었습니다." : "수정되었습니다."); + onOpenChange?.(false); + }, + }); + + const form = useForm({ + resolver: zodResolver(LwpoCodeFormSchema), + values: { + upCd: upCd ?? "", + lwpoCd: detailData?.lwpoCd ?? "", + lwpoCdNm: detailData?.lwpoCdNm ?? "", + lwpoCdExpln: detailData?.lwpoCdExpln ?? "", + useYn: detailData?.useYn ?? "Y", + delYn: "N", + unit: detailData?.unit ?? "", + prntLwpoCd: detailData?.prntLwpoCd ?? "", + sortSeq: detailData?.sortSeq ?? 0, + }, + }); + + const handleSave = async () => { + if (await confirm(isRegistration ? "등록하시겠습니까?" : "수정하시겠습니까?")) { + const data = form.getValues(); + await saveLwpoCode(data); + } + }; + + return ( + + + + {isRegistration ? "하위코드 등록" : "하위코드 관리"} + +
+ { + e.preventDefault(); + handleSave(); + }} className="space-y-4"> + + + + + + + + 하위코드 + + ( + + + + + + )} + /> + + + + 하위코드명 + + ( + + + + + + )} + /> + + + + 하위코드설명 + + ( + + + + + + )} + /> + + + {upCodeData?.cdSe === "CODECLUNIT" && ( + + 단위 + + ( + + + + + + )} + /> + + + )} + {upCodeData?.cdSe === "CODECLTREE" && ( + + 상위하위코드 + + ( + + + + + + )} + /> + + + )} + + 정렬순서 + + ( + + + + + + )} + /> + + + + 사용여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+
+
+ + + + + + +
+ +
+
+ ); +} + +export { ManagementLwpoCodeDialog }; diff --git a/apps/cs/src/pages/code/ui/upcode-dialog.tsx b/apps/cs/src/pages/code/ui/upcode-dialog.tsx new file mode 100644 index 000000000..034ba6e56 --- /dev/null +++ b/apps/cs/src/pages/code/ui/upcode-dialog.tsx @@ -0,0 +1,256 @@ +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { ENDPOINT } from "@/shared/config"; +import { + Button, + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Input, + RadioGroup, + RadioGroupItem, + Label, +} from "@common/components"; +import { Form, FormField, FormItem, FormControl } from "@/shared/ui/form"; +import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { upCodeApi } from "@/entities/code/api/upcode-service"; +import { upCodeFormSchema, type UpCodeFormData } from "@/entities/code/model/upcode-interface"; +import { CodeSelect } from "@/entities/code"; +import { SiteSelect } from "@/entities/site"; + +type ManagementUpCodeDialogProps = { + upCd?: string; + open?: boolean; + onOpenChange?: (open: boolean) => void; + isRegistration?: boolean; +} & Omit, 'open' | 'onOpenChange'>; + + +function ManagementUpCodeDialog({ + upCd, + open, + onOpenChange, + isRegistration = false, + ...props +}: ManagementUpCodeDialogProps) { + const { confirm } = useConfirm(); + const { setMessage: alert } = useAlertStore((state) => state); + + const { data: detailData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE, upCd], + queryFn: () => upCodeApi.upCodeDetail(upCd as string), + enabled: !!upCd && !isRegistration, + }); + + const { mutateAsync: saveUpCode } = useMutation({ + mutationFn: (data: UpCodeFormData) => + isRegistration ? upCodeApi.createUpCode(data) : upCodeApi.updateUpCode(upCd as string, data), + onSuccess: () => { + alert(isRegistration ? "등록되었습니다." : "수정되었습니다."); + onOpenChange?.(false); + }, + }); + + const form = useForm({ + resolver: zodResolver(upCodeFormSchema), + values: { + upCd: detailData?.upCd ?? "", + upCdNm: detailData?.upCdNm ?? "", + cdSe: detailData?.cdSe ?? "", + siteId: detailData?.siteId ?? "", + upCdExpln: detailData?.upCdExpln ?? "", + useYn: detailData?.useYn ?? "Y", + delYn: "N", + }, + }); + + const handleSave = async () => { + if (await confirm(isRegistration ? "등록하시겠습니까?" : "수정하시겠습니까?")) { + const data = form.getValues(); + await saveUpCode(data); + } + }; + + return ( + + + + {isRegistration ? "상위코드 등록" : "상위코드 관리"} + +
+ { + e.preventDefault(); + handleSave(); + }} className="space-y-4"> + + + + + + + + 상위코드 + + ( + + + + + + )} + /> + + + + 상위코드명 + + ( + + + + + + )} + /> + + + + 상위코드설명 + + ( + + + + + + )} + /> + + + + 코드구분 + + ( + + + + + + )} + /> + + + + 사이트 + + ( + + + + + + )} + /> + + + + 사용여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+
+
+ + + + + + +
+ +
+
+ ); +} + +export { ManagementUpCodeDialog }; diff --git a/apps/cs/src/pages/site/ui/site-page.tsx b/apps/cs/src/pages/site/ui/site-page.tsx index 9ffd1294e..58978d068 100644 --- a/apps/cs/src/pages/site/ui/site-page.tsx +++ b/apps/cs/src/pages/site/ui/site-page.tsx @@ -23,7 +23,7 @@ function SitePage() { }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); const { data: siteList, refetch } = useQuery({ diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 0ff7efe42..094bb3776 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -36,6 +36,8 @@ export const ENDPOINT = { BANNERS: "/cms-service/api/v1/bnrs", TEMPLATE: "/cms-service/api/v1/tmplt", TERMS: "/cms-service/api/v1/trms", + LWPO_CODE: "/cms-service/api/v1/lwpo-cds", + UP_CODE: "/cms-service/api/v1/up-codes", }, BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs", diff --git a/apps/cs/tsconfig.json b/apps/cs/tsconfig.json index 17db758c4..cf5fa126f 100644 --- a/apps/cs/tsconfig.json +++ b/apps/cs/tsconfig.json @@ -42,6 +42,6 @@ "**/*.jsx", "**/*.json", ".next/types/**/*.ts" - ], +, "../common/features/src/entities/site/ui/site-select.tsx" ], "exclude": ["**/node_modules", "**/.*/*"] }