feat: 파일관리 페이지 작업

This commit is contained in:
2025-04-17 13:28:24 +09:00
parent 9fb4f6aad9
commit b05d407304
8 changed files with 220 additions and 4 deletions
@@ -0,0 +1,2 @@
import { FilePage } from "@/pages/file";
export default FilePage;
@@ -2,11 +2,23 @@ import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type {
Attachment,
AttachmentList,
AttachmentParams,
AttachmentService,
} from "../model/attachment-interface";
export class AttachmentApiService implements AttachmentService {
public async getAttachments(atflCd: string): Promise<Attachment[]> {
public async getAttachmentsList(
params: AttachmentParams,
): Promise<AttachmentList> {
const response = await client.get<AttachmentList>(
`${ENDPOINT.ATTACH_SERVICE.ATTACHMENTS}`,
{ params },
);
return response.data;
}
public async getAttachmentsInfo(atflCd: string): Promise<Attachment[]> {
const response = await client.get<Attachment[]>(
`${ENDPOINT.ATTACH_SERVICE.ATTACHMENTS}/${atflCd}`,
);
@@ -1,3 +1,20 @@
import type { PageableList, PageableParams } from "@/shared/model";
export interface AttachmentParams extends PageableParams {
keywordType?: string;
keyword?: string;
atflCd?: string;
atflSn?: number;
atflId?: string;
orgnlFileNm?: string;
atflFlieSz?: number;
atflType?: string;
dwnldNocs?: number;
delYn?: string;
lnkgDmnId?: string;
lnkgDmnNm?: string;
}
export interface Attachment {
atflCd: string;
atflSn: number;
@@ -13,8 +30,11 @@ export interface Attachment {
regDt: string;
}
export type AttachmentList = PageableList<Attachment>;
export interface AttachmentService {
getAttachments: (atflCd: string) => Promise<Attachment[]>;
getAttachmentsList: (params: AttachmentParams) => Promise<AttachmentList>;
getAttachmentsInfo: (atflCd: string) => Promise<Attachment[]>;
deleteAttachment: (atflId: string) => Promise<void>;
deleteAttachmentByAtflCd: (atflCd: string) => Promise<void>;
getImageUrl: (atflId: string) => Promise<string>;
+1 -1
View File
@@ -44,7 +44,7 @@ function BannerForm({ form, bnrSn, ...props }: BannerFormProps) {
const { data: attachmentData } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, atflCd],
queryFn: () => AttachmentApi.getAttachments(atflCd!),
queryFn: () => AttachmentApi.getAttachmentsInfo(atflCd!),
select: (data) => data?.[data.length - 1],
enabled: !!atflCd,
});
+1
View File
@@ -0,0 +1 @@
export { FilePage } from "./ui/file-page";
@@ -0,0 +1,62 @@
"use client";
import dayjs from "dayjs";
import { type ColumnDef } from "@tanstack/react-table";
import { Button } from "@common/components";
import type { Attachment } from "@/entities/attachment/model/attachment-interface";
export const columns = (
handleDeleteAttachment: (atflId: string) => void,
): ColumnDef<Attachment>[] => [
{
id: "no",
header: "NO",
cell: (info) => info.row.index + 1,
},
{
accessorKey: "atflId",
header: "파일ID",
},
{
accessorKey: "atflSn",
header: "파일순번",
},
{
accessorKey: "orgnlFileNm",
header: "파일명",
},
{
accessorKey: "atflFlieSz",
header: "파일크기",
},
{
accessorKey: "dwnldNocs",
header: "다운로드수",
},
{
accessorKey: "regDt",
header: "등록일시",
cell: ({ row }) => {
const date = row.getValue("regDt") as string;
return date ? dayjs(date).format("YYYY-MM-DD") : "";
},
},
{
accessorKey: "delYn",
header: "삭제여부",
},
{
id: "delete",
header: "삭제",
cell: ({ row }) => (
<Button
size="sm"
color="red"
onClick={() => handleDeleteAttachment(row.original.atflId)}
>
삭제
</Button>
),
},
];
+119
View File
@@ -0,0 +1,119 @@
"use client";
import { useEffect, useState } from "react";
import { keepPreviousData, useMutation, useQuery } from "@tanstack/react-query";
import {
getCoreRowModel,
useReactTable,
type PaginationState,
} from "@tanstack/react-table";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { Button, DataTable, Input, Label } from "@common/components";
import type { AttachmentParams } from "@/entities/attachment/model/attachment-interface";
import { AttachmentApi } from "@/entities/attachment/api/attachment-service";
import { useAlertStore } from "@/shared/lib/use-alert-store";
import { ENDPOINT } from "@/shared/config";
import { columns } from "../model/table-columns";
function FilePage() {
const { confirm } = useConfirm();
const { setMessage: alert } = useAlertStore((state) => state);
const [attachmentQuery, setAttachmentQuery] = useState<AttachmentParams>({
keyword: "",
});
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
});
const { data: attachmentsList, refetch } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS],
queryFn: () =>
AttachmentApi.getAttachmentsList({
...attachmentQuery,
page: pagination.pageIndex,
size: pagination.pageSize,
}),
placeholderData: keepPreviousData,
enabled: false,
});
const { mutate: deleteAttachment } = useMutation({
mutationFn: (atflId: string) => AttachmentApi.deleteAttachment(atflId),
onSuccess: () => {
refetch();
alert("삭제되었습니다.");
},
});
const handleDeleteAttachment = async (atflId: string) => {
if (await confirm("삭제하시겠습니까?")) {
deleteAttachment(atflId);
}
};
const table = useReactTable({
data: attachmentsList?.content ?? [],
columns: columns(handleDeleteAttachment),
rowCount: attachmentsList?.totalElements ?? 0,
state: {
pagination,
},
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
});
const handleAttachmentQueryChange =
(key: keyof AttachmentParams) => (value: string) => {
setAttachmentQuery({ ...attachmentQuery, [key]: value });
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
refetch();
};
useEffect(() => {
refetch();
}, [pagination]);
return (
<div className="card card-border !mt-6">
<div className="card card-border">
<form onSubmit={handleSubmit} className="flex gap-2 p-2">
<div className="flex space-x-6">
<div className="flex items-center gap-2">
<Label htmlFor="keyword" className="text-label">
파일명
</Label>
<Input
id="keyword"
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
value={attachmentQuery.keyword || ""}
onChange={(e) =>
handleAttachmentQueryChange("keyword")(e.target.value)
}
placeholder="파일명을 입력하세요"
/>
</div>
</div>
<Button className="h-[3.2rem]" type="submit">
조회
</Button>
</form>
</div>
<div className="card card-border">
<div className="card-header">
<h3 className="text-2xl font-medium text-label">파일 목록</h3>
</div>
<div className="card !m-[1.2rem] overflow-auto !p-0">
<DataTable table={table} viewPagination />
</div>
</div>
</div>
);
}
export { FilePage };
+1 -1
View File
@@ -49,7 +49,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
const { data: attachmentData } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, atflCd],
queryFn: () => AttachmentApi.getAttachments(atflCd!),
queryFn: () => AttachmentApi.getAttachmentsInfo(atflCd!),
select: (data) => data?.[data.length - 1],
enabled: !!atflCd,
});