feat: 관리자 관리 페이지 생성
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
},
|
||||
];
|
||||
@@ -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 };
|
||||
Reference in New Issue
Block a user