feat: 관리자 관리 페이지 생성

This commit is contained in:
2025-06-19 11:15:58 +09:00
parent cb38462164
commit b79f6ea603
7 changed files with 230 additions and 0 deletions
@@ -0,0 +1,2 @@
import { AdminPage } from "@/pages/admin";
export default AdminPage;
@@ -16,6 +16,7 @@ import type {
UserVerifyData,
UserEmailData,
UserIdData,
AdminUserList,
} from "../model/user-interface";
export class UserApiService implements UserService {
@@ -208,6 +209,17 @@ export class UserApiService implements UserService {
);
return response.data;
}
// 관리자 목록 조회
public async findPageAdminUser(
params: UserSearchParams,
): Promise<AdminUserList> {
const response = await client.get<AdminUserList>(
`${ENDPOINT.USER_SERVICE.USERS}/admin/list`,
{ params },
);
return response.data;
}
}
export const UserApi = new UserApiService();
+2
View File
@@ -10,4 +10,6 @@ export {
type UserDetailResponse,
type UserPasswordUpdateData,
type UserUpdateData,
type AdminUserList,
type AdminUserListResponse,
} from "./model/user-interface";
@@ -103,6 +103,28 @@ export interface UserSttsStatsResponse {
cnt: number;
}
// 관리자 목록 응답 인터페이스
export interface AdminUserListResponse {
userUnqId: string;
userId: string;
userName: string;
groupId: string;
groupNm: string;
userStateCode: string;
userStateCodeName: string;
laeSeCd: string;
laeSeNm: string;
ogdpSeCd: string;
ogdpSeNm: string;
instSeCd: string;
instSeNm: string;
dtlInstCd: string;
dtlInstNm: string;
mdfr: string;
mdfrNm: string;
mdfcnDt: string;
}
// 사용자 수정 요청 스키마
export const userUpdateSchema = z.object({
userId: z.string().optional(),
@@ -264,6 +286,7 @@ export type UserIdData = z.infer<typeof userIdSchema>;
// 페이지네이션 타입 정의
export type UserList = PageableList<UserListResponse>;
export type UserSttsStatsList = UserSttsStatsResponse[];
export type AdminUserList = PageableList<AdminUserListResponse>;
// 사용자 서비스 인터페이스
export interface UserService {
@@ -332,4 +355,7 @@ export interface UserService {
// 사용자 아이디 중복 체크
existsUserId: (data: UserIdData) => Promise<boolean>;
// 관리자 목록 조회
findPageAdminUser: (params: UserSearchParams) => Promise<AdminUserList>;
}
+1
View File
@@ -0,0 +1 @@
export { AdminPage } from "./ui/admin-page";
@@ -0,0 +1,41 @@
import dayjs from "dayjs";
import type { ColumnDef } from "@tanstack/react-table";
import type { AdminUserList } from "@/entities/user";
export const columns: ColumnDef<AdminUserList["content"][number]>[] = [
{
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: "userId",
header: "관리자ID",
},
{
accessorKey: "userName",
header: "관리자명",
},
{
accessorKey: "userStateCodeName",
header: "관리자구분",
},
{
accessorKey: "groupNm",
header: "소속",
},
{
accessorKey: "mdfrNm",
header: "최종수정자",
},
{
accessorKey: "mdfcnDt",
header: "최종수정일",
cell: ({ row }) => dayjs(row.original.mdfcnDt).format("YYYY-MM-DD"),
},
];
+146
View File
@@ -0,0 +1,146 @@
"use client";
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { getCoreRowModel, type PaginationState } from "@tanstack/react-table";
import {
Button,
Input,
Label,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@common/components";
import { UserApi, type UserSearchParams } from "@/entities/user";
import { ENDPOINT } from "@/shared/config";
import { useDataTable } from "@/shared/lib";
import { columns } from "../model/table-columns";
import { GroupApi } from "@/entities/group";
function AdminPage() {
const [adminQuery, setAdminQuery] = useState<UserSearchParams>({
keywordType: "",
keyword: "",
grpId: "",
});
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const { data: groupOptions } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.GROUPS],
queryFn: () =>
GroupApi.findPageGroup({
delYn: "N",
mngrYn: "Y",
page: 0,
size: 99,
}),
select: (data) =>
data.content.map((item) => ({
groupId: item.groupId,
groupNm: item.groupNm,
})),
});
const query = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.USERS, pagination],
queryFn: () =>
UserApi.findPageAdminUser({
...adminQuery,
page: pagination.pageIndex,
size: pagination.pageSize,
}),
});
const { tableComponent } = useDataTable({
query,
tableOptions: {
columns,
state: {
pagination,
},
manualPagination: true,
getCoreRowModel: getCoreRowModel(),
onPaginationChange: setPagination,
},
dataTableOptions: {
viewPagination: true,
},
});
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
query.refetch();
};
return (
<div className="card card-border !mt-6">
<div className="card card-border">
<form onSubmit={handleSubmit} className="flex items-center gap-6 p-2">
<div className="flex items-center gap-2">
<Label className="mr-2 text-label">관리자구분</Label>
<Select
onValueChange={(value) =>
setAdminQuery({ ...adminQuery, grpId: value })
}
>
<SelectTrigger className="h-[3.2rem] w-[16rem] !text-[1.3rem]">
<SelectValue placeholder="그룹 선택" />
</SelectTrigger>
<SelectContent>
{groupOptions?.map((item) => (
<SelectItem key={item.groupId} value={item.groupId}>
{item.groupNm}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex items-center gap-2">
<Label htmlFor="" className="mr-2 text-label">
관리자
</Label>
<Select
onValueChange={(value) =>
setAdminQuery({ ...adminQuery, keywordType: value })
}
>
<SelectTrigger className="h-[3.2rem] w-[12rem] !text-[1.3rem]">
<SelectValue placeholder="선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="userId">아이디</SelectItem>
<SelectItem value="userName">이름</SelectItem>
</SelectContent>
</Select>
<Input
className="h-[3.2rem] w-[20rem] rounded-sm !text-[1.3rem]"
value={adminQuery.keyword}
onChange={(e) =>
setAdminQuery({ ...adminQuery, keyword: e.target.value })
}
placeholder="검색어 입력"
/>
</div>
<Button className="h-[3.2rem]" type="submit">
조회
</Button>
</form>
</div>
<div className="card card-border">
<div className="card-header">
<div className="flex w-full items-center justify-between">
<h3 className="text-2xl font-medium text-label">관리자 목록</h3>
</div>
</div>
<div className="card !m-[1.2rem] !p-0">{tableComponent}</div>
</div>
</div>
);
}
export { AdminPage };