From e390026bfec7f18d89072433dcf2d144f8bd9d05 Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 16 Jun 2025 11:08:18 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EA=B7=B8=EB=A3=B9=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=B0=8F=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/groups/api/group-users-service.ts | 69 +++++++++++ .../cs/src/pages/groups/api/groups-service.ts | 58 ++++++++++ apps/cs/src/pages/groups/api/index.ts | 2 + .../groups/model/group-users-interface.ts | 107 ++++++++++++++++++ .../pages/groups/model/groups-interface.ts | 101 +++++++++++++++++ apps/cs/src/pages/groups/model/index.ts | 2 + apps/cs/src/shared/config/api.ts | 2 + 7 files changed, 341 insertions(+) create mode 100644 apps/cs/src/pages/groups/api/group-users-service.ts create mode 100644 apps/cs/src/pages/groups/api/groups-service.ts create mode 100644 apps/cs/src/pages/groups/api/index.ts create mode 100644 apps/cs/src/pages/groups/model/group-users-interface.ts create mode 100644 apps/cs/src/pages/groups/model/groups-interface.ts create mode 100644 apps/cs/src/pages/groups/model/index.ts diff --git a/apps/cs/src/pages/groups/api/group-users-service.ts b/apps/cs/src/pages/groups/api/group-users-service.ts new file mode 100644 index 000000000..69a81e366 --- /dev/null +++ b/apps/cs/src/pages/groups/api/group-users-service.ts @@ -0,0 +1,69 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { + GroupUserService, + GroupUserSearchParams, + GroupUserList, + GroupUserDetailResponse, + GroupUserSaveData, + GroupUserUpdateData, +} from "../model/group-users-interface"; + +export class GroupUsersApiService implements GroupUserService { + // 그룹 사용자 목록 조회 + public async findPageGroupUser( + params: GroupUserSearchParams, + ): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.GROUP_USERS}`, + { params }, + ); + return response.data; + } + + // 그룹 사용자 단건 조회 + public async findByGroupAndUserId( + grpSn: number, + userUnqId: string, + ): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.GROUP_USERS}/${grpSn}/${userUnqId}`, + ); + return response.data; + } + + // 그룹 사용자 저장 + public async saveGroupUser( + data: GroupUserSaveData, + ): Promise { + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.GROUP_USERS}`, + data, + ); + return response.data; + } + + // 그룹 사용자 수정 + public async updateGroupUser( + grpSn: number, + userUnqId: string, + data: GroupUserUpdateData, + ): Promise { + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.GROUP_USERS}/${grpSn}/${userUnqId}`, + data, + ); + return response.data; + } + + // 그룹 사용자 삭제 + public async deleteGroupUser( + grpSn: number, + userUnqId: string, + ): Promise { + const response = await client.delete( + `${ENDPOINT.CMS_SERVICE.GROUP_USERS}/${grpSn}/${userUnqId}`, + ); + return response.data; + } +} diff --git a/apps/cs/src/pages/groups/api/groups-service.ts b/apps/cs/src/pages/groups/api/groups-service.ts new file mode 100644 index 000000000..2b570c3cb --- /dev/null +++ b/apps/cs/src/pages/groups/api/groups-service.ts @@ -0,0 +1,58 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { + GroupService, + GroupSearchParams, + GroupList, + GroupDetailResponse, + GroupSaveData, + GroupUpdateData, +} from "../model/groups-interface"; + +export class GroupsApiService implements GroupService { + // 그룹 목록 조회 + public async findPageGroup(params: GroupSearchParams): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.GROUPS}`, + { params }, + ); + return response.data; + } + + // 그룹 단건 조회 + public async findById(id: number): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.GROUPS}/${id}`, + ); + return response.data; + } + + // 그룹 저장 + public async saveGroup(data: GroupSaveData): Promise { + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.GROUPS}`, + data, + ); + return response.data; + } + + // 그룹 수정 + public async updateGroup( + id: number, + data: GroupUpdateData, + ): Promise { + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.GROUPS}/${id}`, + data, + ); + return response.data; + } + + // 그룹 삭제 + public async deleteGroup(id: number): Promise { + const response = await client.delete( + `${ENDPOINT.CMS_SERVICE.GROUPS}/${id}`, + ); + return response.data; + } +} diff --git a/apps/cs/src/pages/groups/api/index.ts b/apps/cs/src/pages/groups/api/index.ts new file mode 100644 index 000000000..3d10f342e --- /dev/null +++ b/apps/cs/src/pages/groups/api/index.ts @@ -0,0 +1,2 @@ +export * from "./groups-service"; +export * from "./group-users-service"; diff --git a/apps/cs/src/pages/groups/model/group-users-interface.ts b/apps/cs/src/pages/groups/model/group-users-interface.ts new file mode 100644 index 000000000..e26f1fa09 --- /dev/null +++ b/apps/cs/src/pages/groups/model/group-users-interface.ts @@ -0,0 +1,107 @@ +// 그룹 사용자 검색 파라미터 인터페이스 +export interface GroupUserSearchParams { + page?: number; + size?: number; + sort?: string; + grpSn?: number; + userId?: string; + userName?: string; +} + +// 그룹 사용자 목록 응답 인터페이스 +export interface GroupUserListResponseDto { + grpSn: number; + userUnqId: string; + userId: string; + userName: string; + email: string; + mphn: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; + rgtrNm: string; + mdfrNm: string; +} + +// 그룹 사용자 페이지 응답 인터페이스 +export interface GroupUserList { + content: GroupUserListResponseDto[]; + pageable: { + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + offset: number; + pageSize: number; + pageNumber: number; + paged: boolean; + unpaged: boolean; + }; + last: boolean; + totalPages: number; + totalElements: number; + size: number; + number: number; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + first: boolean; + numberOfElements: number; + empty: boolean; +} + +// 그룹 사용자 상세 응답 인터페이스 +export interface GroupUserDetailResponse { + grpSn: number; + userUnqId: string; + userId: string; + userName: string; + email: string; + mphn: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; + rgtrNm: string; + mdfrNm: string; +} + +// 그룹 사용자 저장 데이터 인터페이스 +export interface GroupUserSaveData { + grpSn: number; + userUnqId: string; +} + +// 그룹 사용자 수정 데이터 인터페이스 +export interface GroupUserUpdateData { + userUnqId: string; +} + +// 그룹 사용자 서비스 인터페이스 +export interface GroupUserService { + // 그룹 사용자 목록 조회 + findPageGroupUser: (params: GroupUserSearchParams) => Promise; + + // 그룹 사용자 단건 조회 + findByGroupAndUserId: ( + grpSn: number, + userUnqId: string, + ) => Promise; + + // 그룹 사용자 저장 + saveGroupUser: (data: GroupUserSaveData) => Promise; + + // 그룹 사용자 수정 + updateGroupUser: ( + grpSn: number, + userUnqId: string, + data: GroupUserUpdateData, + ) => Promise; + + // 그룹 사용자 삭제 + deleteGroupUser: (grpSn: number, userUnqId: string) => Promise; +} diff --git a/apps/cs/src/pages/groups/model/groups-interface.ts b/apps/cs/src/pages/groups/model/groups-interface.ts new file mode 100644 index 000000000..c8d2c35fb --- /dev/null +++ b/apps/cs/src/pages/groups/model/groups-interface.ts @@ -0,0 +1,101 @@ +// 그룹 검색 파라미터 인터페이스 +export interface GroupSearchParams { + page?: number; + size?: number; + sort?: string; + grpNm?: string; + useYn?: string; +} + +// 그룹 목록 응답 인터페이스 +export interface GroupListResponseDto { + grpSn: number; + grpNm: string; + grpExpln: string; + useYn: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; + rgtrNm: string; + mdfrNm: string; +} + +// 그룹 페이지 응답 인터페이스 +export interface GroupList { + content: GroupListResponseDto[]; + pageable: { + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + offset: number; + pageSize: number; + pageNumber: number; + paged: boolean; + unpaged: boolean; + }; + last: boolean; + totalPages: number; + totalElements: number; + size: number; + number: number; + sort: { + empty: boolean; + sorted: boolean; + unsorted: boolean; + }; + first: boolean; + numberOfElements: number; + empty: boolean; +} + +// 그룹 상세 응답 인터페이스 +export interface GroupDetailResponse { + grpSn: number; + grpNm: string; + grpExpln: string; + useYn: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; + rgtrNm: string; + mdfrNm: string; +} + +// 그룹 저장 데이터 인터페이스 +export interface GroupSaveData { + grpNm: string; + grpExpln: string; + useYn: string; +} + +// 그룹 수정 데이터 인터페이스 +export interface GroupUpdateData { + grpNm: string; + grpExpln: string; + useYn: string; +} + +// 그룹 서비스 인터페이스 +export interface GroupService { + // 그룹 목록 조회 + findPageGroup: (params: GroupSearchParams) => Promise; + + // 그룹 단건 조회 + findById: (id: number) => Promise; + + // 그룹 저장 + saveGroup: (data: GroupSaveData) => Promise; + + // 그룹 수정 + updateGroup: ( + id: number, + data: GroupUpdateData, + ) => Promise; + + // 그룹 삭제 + deleteGroup: (id: number) => Promise; +} diff --git a/apps/cs/src/pages/groups/model/index.ts b/apps/cs/src/pages/groups/model/index.ts new file mode 100644 index 000000000..0852eb491 --- /dev/null +++ b/apps/cs/src/pages/groups/model/index.ts @@ -0,0 +1,2 @@ +export * from "./groups-interface"; +export * from "./group-users-interface"; diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index da5edaea1..54d038dbf 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -45,6 +45,8 @@ export const ENDPOINT = { SURVEY_QUESTION: "/cms-service/api/v1/srvy-qitem", SURVEY_ARTICLE: "/cms-service/api/v1/srvy-artcl", ZIPS: "/cms-service/api/v1/zips", + GROUPS: "/cms-service/api/v1/groups", + GROUP_USERS: "/cms-service/api/v1/group-users", }, BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs", From 318bae3a1e417d9ae268d3cf7a9ddb8c5efcc917 Mon Sep 17 00:00:00 2001 From: bicochan Date: Tue, 17 Jun 2025 11:06:33 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EA=B7=B8=EB=A3=B9=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cs/app/(with-base-layout)/groups/page.tsx | 2 + .../api/menu-authority-service.ts | 10 + apps/cs/src/entities/menu-authority/index.ts | 7 + .../model/menu-authority-interface.ts | 3 + .../role/api/role-service.ts | 2 +- apps/cs/src/entities/role/index.ts | 8 + .../role/model/role-interface.ts | 2 +- apps/cs/src/entities/site/ui/site-select.tsx | 5 +- .../pages/groups/api/group-users-service.ts | 6 +- .../cs/src/pages/groups/api/groups-service.ts | 21 +- apps/cs/src/pages/groups/api/index.ts | 2 - apps/cs/src/pages/groups/index.ts | 1 + .../group-menu-authority-table-columns.tsx | 117 ++++++++++ .../groups/model/group-users-interface.ts | 13 +- .../model/group-users-table-columns.tsx | 57 +++++ .../pages/groups/model/groups-interface.ts | 105 ++++----- .../groups/model/groups-table-columns.tsx | 27 +++ apps/cs/src/pages/groups/model/index.ts | 2 - apps/cs/src/pages/groups/ui/group-form.tsx | 204 ++++++++++++++++++ .../pages/groups/ui/group-users-section.tsx | 92 ++++++++ apps/cs/src/pages/groups/ui/groups-dialog.tsx | 112 ++++++++++ apps/cs/src/pages/groups/ui/groups-page.tsx | 18 ++ .../cs/src/pages/groups/ui/groups-section.tsx | 68 ++++++ apps/cs/src/pages/groups/ui/index.ts | 1 + .../pages/groups/ui/menu-authority-dialog.tsx | 110 ++++++++++ apps/cs/src/pages/groups/ui/role-select.tsx | 41 ++++ apps/cs/src/pages/role/ui/create-page.tsx | 3 +- apps/cs/src/pages/role/ui/modify-page.tsx | 3 +- apps/cs/src/pages/role/ui/role-form.tsx | 3 +- apps/cs/src/pages/role/ui/role-page.tsx | 3 +- 30 files changed, 952 insertions(+), 96 deletions(-) create mode 100644 apps/cs/app/(with-base-layout)/groups/page.tsx rename apps/cs/src/{pages => entities}/role/api/role-service.ts (95%) create mode 100644 apps/cs/src/entities/role/index.ts rename apps/cs/src/{pages => entities}/role/model/role-interface.ts (94%) delete mode 100644 apps/cs/src/pages/groups/api/index.ts create mode 100644 apps/cs/src/pages/groups/index.ts create mode 100644 apps/cs/src/pages/groups/model/group-menu-authority-table-columns.tsx create mode 100644 apps/cs/src/pages/groups/model/group-users-table-columns.tsx create mode 100644 apps/cs/src/pages/groups/model/groups-table-columns.tsx delete mode 100644 apps/cs/src/pages/groups/model/index.ts create mode 100644 apps/cs/src/pages/groups/ui/group-form.tsx create mode 100644 apps/cs/src/pages/groups/ui/group-users-section.tsx create mode 100644 apps/cs/src/pages/groups/ui/groups-dialog.tsx create mode 100644 apps/cs/src/pages/groups/ui/groups-page.tsx create mode 100644 apps/cs/src/pages/groups/ui/groups-section.tsx create mode 100644 apps/cs/src/pages/groups/ui/index.ts create mode 100644 apps/cs/src/pages/groups/ui/menu-authority-dialog.tsx create mode 100644 apps/cs/src/pages/groups/ui/role-select.tsx diff --git a/apps/cs/app/(with-base-layout)/groups/page.tsx b/apps/cs/app/(with-base-layout)/groups/page.tsx new file mode 100644 index 000000000..8491e59bb --- /dev/null +++ b/apps/cs/app/(with-base-layout)/groups/page.tsx @@ -0,0 +1,2 @@ +import { GroupsPage } from "@/pages/groups"; +export default GroupsPage; diff --git a/apps/cs/src/entities/menu-authority/api/menu-authority-service.ts b/apps/cs/src/entities/menu-authority/api/menu-authority-service.ts index 14988eee0..ec07d88ad 100644 --- a/apps/cs/src/entities/menu-authority/api/menu-authority-service.ts +++ b/apps/cs/src/entities/menu-authority/api/menu-authority-service.ts @@ -35,6 +35,16 @@ export class MenuAuthorityApiService implements MenuAuthorityService { ); return response.data; } + + public async getGroupMenuAuthorityList( + params: MenuAuthorityParams, + ): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.MENU_AUTHRTS}/group`, + { params }, + ); + return response.data; + } } export const MenuAuthorityApi = new MenuAuthorityApiService(); diff --git a/apps/cs/src/entities/menu-authority/index.ts b/apps/cs/src/entities/menu-authority/index.ts index 2a555b77e..5a1b11606 100644 --- a/apps/cs/src/entities/menu-authority/index.ts +++ b/apps/cs/src/entities/menu-authority/index.ts @@ -1,2 +1,9 @@ +export { MenuAuthorityApi } from "./api/menu-authority-service"; +export { + menuAuthorityFormSchema, + type MenuAuthority, + type MenuAuthorityPayload, + type MenuAuthorityFormData, +} from "./model/menu-authority-interface"; export { AuthorityButton } from "./ui/authority-button"; export { ManagementAuthorityDialog } from "./ui/management-authority-dialog"; diff --git a/apps/cs/src/entities/menu-authority/model/menu-authority-interface.ts b/apps/cs/src/entities/menu-authority/model/menu-authority-interface.ts index b59574c2f..7f5401872 100644 --- a/apps/cs/src/entities/menu-authority/model/menu-authority-interface.ts +++ b/apps/cs/src/entities/menu-authority/model/menu-authority-interface.ts @@ -43,6 +43,9 @@ export type MenuAuthorityFormData = z.infer; export interface MenuAuthorityService { getMenuAuthorityList(params: MenuAuthorityParams): Promise; + getGroupMenuAuthorityList( + params: MenuAuthorityParams, + ): Promise; getPageMenuAuthority(menuCd: number): Promise; saveMenuAuthority(data: MenuAuthorityPayload[]): Promise; } diff --git a/apps/cs/src/pages/role/api/role-service.ts b/apps/cs/src/entities/role/api/role-service.ts similarity index 95% rename from apps/cs/src/pages/role/api/role-service.ts rename to apps/cs/src/entities/role/api/role-service.ts index d2db7e5bc..95aac330f 100644 --- a/apps/cs/src/pages/role/api/role-service.ts +++ b/apps/cs/src/entities/role/api/role-service.ts @@ -9,7 +9,7 @@ import type { } from "../model/role-interface"; export class RoleApiService implements RoleService { - public async getRoles(params: RoleParams): Promise { + public async getRoles(params?: RoleParams): Promise { const response = await client.get(ENDPOINT.USER_SERVICE.ROLES, { params, }); diff --git a/apps/cs/src/entities/role/index.ts b/apps/cs/src/entities/role/index.ts new file mode 100644 index 000000000..28fe5f7fb --- /dev/null +++ b/apps/cs/src/entities/role/index.ts @@ -0,0 +1,8 @@ +export { RoleApi } from "./api/role-service"; +export { + roleFormSchema, + type Role, + type RoleParams, + type RoleFormData, + type RoleList, +} from "./model/role-interface"; diff --git a/apps/cs/src/pages/role/model/role-interface.ts b/apps/cs/src/entities/role/model/role-interface.ts similarity index 94% rename from apps/cs/src/pages/role/model/role-interface.ts rename to apps/cs/src/entities/role/model/role-interface.ts index 1b9b8eea2..065d89259 100644 --- a/apps/cs/src/pages/role/model/role-interface.ts +++ b/apps/cs/src/entities/role/model/role-interface.ts @@ -28,7 +28,7 @@ export type RoleList = PageableList; export type RoleFormData = z.infer; export interface RoleService { - getRoles: (params: RoleParams) => Promise; + getRoles: (params?: RoleParams) => Promise; getRoleInfo: (roleId: string) => Promise; createRole: (data: RoleFormData) => Promise; updateRole: (roleId: string, data: RoleFormData) => Promise; diff --git a/apps/cs/src/entities/site/ui/site-select.tsx b/apps/cs/src/entities/site/ui/site-select.tsx index 6c5a0d005..3d56a5658 100644 --- a/apps/cs/src/entities/site/ui/site-select.tsx +++ b/apps/cs/src/entities/site/ui/site-select.tsx @@ -1,5 +1,6 @@ import { useQuery } from "@tanstack/react-query"; import { + cn, Select, SelectContent, SelectItem, @@ -12,12 +13,14 @@ import { SiteApi } from "../api/site-service"; type SiteSelectProps = { placeholder?: string; enabledAllSite?: boolean; + className?: string; } & React.ComponentPropsWithoutRef; function SiteSelect({ defaultValue, placeholder = "선택", enabledAllSite, + className, ...props }: SiteSelectProps) { const { data: sites } = useQuery({ @@ -36,7 +39,7 @@ function SiteSelect({ return ( + + + + )} + /> + + + + 그룹명 + + ( + + + + + + + )} + /> + + + + 그룹구분 + + ( + + + + + + + )} + /> + + + + 그룹설명 + + ( + + +