From 7d4cdb095d5c2494c697b98fd80bf3fa8f96c9ca Mon Sep 17 00:00:00 2001 From: bicochan Date: Wed, 16 Apr 2025 17:53:40 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=AA=A8=EB=93=88API=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=EA=B4=80=EB=A6=AC=20=EB=8B=A4=EC=9D=B4=EC=96=BC?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/api/role-authorization-service.ts | 44 +++++++ .../module/model/authorizations-interface.ts | 23 ++-- .../model/role-authorizations-interface.ts | 44 +++++++ .../role-authorizations-table-columns.tsx | 39 ++++++ .../src/pages/module/model/table-columns.tsx | 19 +++ .../module/ui/management-authority-dialog.tsx | 114 ++++++++++++++++++ apps/cs/src/pages/module/ui/module-page.tsx | 20 +-- 7 files changed, 285 insertions(+), 18 deletions(-) create mode 100644 apps/cs/src/pages/module/api/role-authorization-service.ts create mode 100644 apps/cs/src/pages/module/model/role-authorizations-interface.ts create mode 100644 apps/cs/src/pages/module/model/role-authorizations-table-columns.tsx create mode 100644 apps/cs/src/pages/module/ui/management-authority-dialog.tsx diff --git a/apps/cs/src/pages/module/api/role-authorization-service.ts b/apps/cs/src/pages/module/api/role-authorization-service.ts new file mode 100644 index 000000000..41dc3585b --- /dev/null +++ b/apps/cs/src/pages/module/api/role-authorization-service.ts @@ -0,0 +1,44 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { + RoleAuthorizationsService, + RoleAuthorizationsParams, + RoleAuthorizationsList, + RoleAuthorizationsData, + RoleAuthorizations, +} from "../model/role-authorizations-interface"; + +export class RoleAuthorizationsApiService implements RoleAuthorizationsService { + public async getRoleAuthorizationsList( + params: RoleAuthorizationsParams, + ): Promise { + const response = await client.get( + `${ENDPOINT.USER_SERVICE.ROLE_AUTHORIZATIONS}/api`, + { params }, + ); + return response.data; + } + + public async createRoleAuthorizations( + data: RoleAuthorizationsData, + ): Promise { + const response = await client.post( + `${ENDPOINT.USER_SERVICE.ROLE_AUTHORIZATIONS}`, + data, + ); + return response.data; + } + + public async updateRoleAuthorizations( + authorizationNo: string, + data: RoleAuthorizationsData, + ): Promise { + const response = await client.put( + `${ENDPOINT.USER_SERVICE.ROLE_AUTHORIZATIONS}/${authorizationNo}`, + data, + ); + return response.data; + } +} + +export const RoleAuthorizationsApi = new RoleAuthorizationsApiService(); diff --git a/apps/cs/src/pages/module/model/authorizations-interface.ts b/apps/cs/src/pages/module/model/authorizations-interface.ts index 114d5cb10..e34d150e0 100644 --- a/apps/cs/src/pages/module/model/authorizations-interface.ts +++ b/apps/cs/src/pages/module/model/authorizations-interface.ts @@ -4,6 +4,9 @@ import type { PageableList, PageableParams } from "@/shared/model"; export interface AuthorizationsParams extends PageableParams { keywordType?: string; keyword?: string; + authorizationName?: string; + httpMethodCode?: string; + useYn?: string; } export interface Authorizations { @@ -17,16 +20,18 @@ export interface Authorizations { mdfcnDt: string; } +export interface RoleAuthorizations { + roleId: string; + authorizationNo: number; + authorizationName: string; + urlPatternValue: string; + httpMethodCode: string; + sortSeq: number; + createdAt: string; +} + export interface WithRoleAuthorizations extends Authorizations { - roleAuthorizations: { - roleId: string; - authorizationNo: number; - authorizationName: string; - urlPatternValue: string; - httpMethodCode: string; - sortSeq: number; - createdAt: string; - }[]; + roleAuthorizations: RoleAuthorizations[]; } export const authorizationFormSchema = z.object({ diff --git a/apps/cs/src/pages/module/model/role-authorizations-interface.ts b/apps/cs/src/pages/module/model/role-authorizations-interface.ts new file mode 100644 index 000000000..5405eb3ac --- /dev/null +++ b/apps/cs/src/pages/module/model/role-authorizations-interface.ts @@ -0,0 +1,44 @@ +import { z } from "zod"; +import type { PageableList, PageableParams } from "@/shared/model"; + +export interface RoleAuthorizationsParams extends PageableParams { + keywordType?: string; + keyword?: string; + authorizationNo?: string; +} + +export interface RoleAuthorizations { + roleId: string; + roleName: string; + roleContent: string; + useYn: string; + authorizationNo: number; +} + +export const roleAuthorizationsSchema = z.object({ + roleId: z.string(), + authorizationNo: z.number(), +}); + +export const roleAuthorizationsFormSchema = z.object({ + roleAuthorizations: z.array(roleAuthorizationsSchema), +}); + +export type RoleAuthorizationsList = PageableList; +export type RoleAuthorizationsData = z.infer[]; +export type RoleAuthorizationsFormData = z.infer< + typeof roleAuthorizationsFormSchema +>; + +export interface RoleAuthorizationsService { + getRoleAuthorizationsList: ( + params: RoleAuthorizationsParams, + ) => Promise; + createRoleAuthorizations: ( + data: RoleAuthorizationsData, + ) => Promise; + updateRoleAuthorizations: ( + authorizationNo: string, + data: RoleAuthorizationsData, + ) => Promise; +} diff --git a/apps/cs/src/pages/module/model/role-authorizations-table-columns.tsx b/apps/cs/src/pages/module/model/role-authorizations-table-columns.tsx new file mode 100644 index 000000000..24198d4a1 --- /dev/null +++ b/apps/cs/src/pages/module/model/role-authorizations-table-columns.tsx @@ -0,0 +1,39 @@ +import { type ColumnDef } from "@tanstack/react-table"; +import type { RoleAuthorizations } from "./role-authorizations-interface"; +import { Checkbox } from "@common/components/ui"; + +export const columns: ColumnDef[] = [ + { + id: "select", + header: ({ table }) => ( + e.stopPropagation()} + onCheckedChange={(checked) => + table.toggleAllPageRowsSelected(!!checked) + } + className="h-4 w-4 rounded border-gray-300" + /> + ), + cell: ({ row }) => ( + e.stopPropagation()} + onCheckedChange={(checked) => row.toggleSelected(!!checked)} + className="h-4 w-4 rounded border-gray-300" + /> + ), + }, + { + accessorKey: "roleId", + header: "권한ID", + }, + { + accessorKey: "roleName", + header: "권한명", + }, + { + accessorKey: "roleContent", + header: "권한설명", + }, +]; diff --git a/apps/cs/src/pages/module/model/table-columns.tsx b/apps/cs/src/pages/module/model/table-columns.tsx index cd6bb0d06..a2ccb2a88 100644 --- a/apps/cs/src/pages/module/model/table-columns.tsx +++ b/apps/cs/src/pages/module/model/table-columns.tsx @@ -1,6 +1,7 @@ import dayjs from "dayjs"; import { type ColumnDef } from "@tanstack/react-table"; import type { Authorizations } from "./authorizations-interface"; +import { ManagementAuthorityDialog } from "../ui/management-authority-dialog"; export const columns: ColumnDef[] = [ { @@ -36,4 +37,22 @@ export const columns: ColumnDef[] = [ return date.format("YYYY-MM-DD"); }, }, + { + id: "action", + header: "권한관리", + cell: ({ row }) => { + return ( +
{ + e.stopPropagation(); + }} + > + +
+ ); + }, + }, ]; diff --git a/apps/cs/src/pages/module/ui/management-authority-dialog.tsx b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx new file mode 100644 index 000000000..ce13ffbe7 --- /dev/null +++ b/apps/cs/src/pages/module/ui/management-authority-dialog.tsx @@ -0,0 +1,114 @@ +import { useState } from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + useReactTable, + type RowSelectionState, +} from "@tanstack/react-table"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { + Button, + DataTable, + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@common/components/ui"; +import { ENDPOINT } from "@/shared/config"; +import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { + roleAuthorizationFormSchema, + type RoleAuthorizationFormData, + type RoleAuthorizationData, +} from "../model/role-authorizations-interface"; +import { columns } from "../model/role-authorizations-table-columns"; +import type { Authorizations } from "../model/authorizations-interface"; +import { RoleAuthorizationsApi } from "../api/role-authorization-service"; + +type ManagementAuthorityDialogProps = { + authorizationNo?: string; + rowData?: Authorizations; +} & React.ComponentProps; + +function ManagementAuthorityDialog({ + authorizationNo, + ...props +}: ManagementAuthorityDialogProps) { + const { confirm } = useConfirm(); + const { setMessage: alert } = useAlertStore((state) => state); + + const [isOpened, setIsOpened] = useState(false); + const [rowSelection, setRowSelection] = useState({}); + + const { data: roleAuthorizationList } = useQuery({ + queryKey: [ENDPOINT.USER_SERVICE.ROLE_AUTHORIZATIONS, authorizationNo], + queryFn: () => + RoleAuthorizationsApi.getRoleAuthorizationsList({ authorizationNo }), + enabled: !!authorizationNo && isOpened, + }); + + const { mutateAsync: saveRoleAuthorization } = useMutation({ + mutationFn: (data: RoleAuthorizationData) => + RoleAuthorizationsApi.createRoleAuthorization(data), + onSuccess: () => { + alert("저장되었습니다."); + }, + }); + + const form = useForm({ + resolver: zodResolver(roleAuthorizationFormSchema), + values: { + roleAuthorizations: roleAuthorizationList?.content ?? [], + }, + }); + + const table = useReactTable({ + data: roleAuthorizationList?.content ?? [], + columns, + state: { + rowSelection, + }, + getCoreRowModel: getCoreRowModel(), + onRowSelectionChange: setRowSelection, + }); + + const handleSave = async () => { + if (await confirm("선택한 권한을 허용하시겠습니까?")) { + const data = form.getValues("roleAuthorizations"); + await saveRoleAuthorization(data); + } + }; + + return ( + + + + + + + 모듈API 권한관리 + + + + + + + + + + + ); +} + +export { ManagementAuthorityDialog }; diff --git a/apps/cs/src/pages/module/ui/module-page.tsx b/apps/cs/src/pages/module/ui/module-page.tsx index 6f0ebee43..9401941d7 100644 --- a/apps/cs/src/pages/module/ui/module-page.tsx +++ b/apps/cs/src/pages/module/ui/module-page.tsx @@ -23,8 +23,8 @@ function ModulePage() { const [authorizationQuery, setAuthorizationQuery] = useState({ - keywordType: "", - keyword: "", + authorizationName: "", + httpMethodCode: "", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -32,7 +32,7 @@ function ModulePage() { }); const { data: authorizationsList, refetch } = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS], + queryKey: [ENDPOINT.USER_SERVICE.AUTHORIZATIONS], queryFn: () => AuthorizationsApi.getAuthorizationsList({ ...authorizationQuery, @@ -79,24 +79,26 @@ function ModulePage() {
-
-
@@ -111,7 +113,7 @@ function ModulePage() {

모듈API 목록

-
+