150 lines
4.3 KiB
TypeScript
150 lines
4.3 KiB
TypeScript
import dayjs from "dayjs";
|
|
import type { ColumnDef } from "@tanstack/react-table";
|
|
import { Badge, Button, Checkbox } from "@common/components";
|
|
import { AttachmentApi } from "@/entities/attachment";
|
|
import type { Post } from "@/entities/post";
|
|
|
|
export const columns: ColumnDef<Post & { isUpndFixPost?: boolean }>[] = [
|
|
{
|
|
id: "select",
|
|
header: ({ table }) => (
|
|
<Checkbox
|
|
aria-label="전체 선택"
|
|
title="전체 선택"
|
|
checked={table.getIsAllPageRowsSelected()}
|
|
onClick={(e) => e.stopPropagation()}
|
|
onCheckedChange={(checked) =>
|
|
table.toggleAllPageRowsSelected(!!checked)
|
|
}
|
|
className="h-4 w-4 rounded border-gray-300"
|
|
/>
|
|
),
|
|
cell: ({ row }) => (
|
|
<Checkbox
|
|
aria-label="행 선택"
|
|
title="행 선택"
|
|
checked={row.getIsSelected()}
|
|
onClick={(e) => e.stopPropagation()}
|
|
onCheckedChange={(checked) => row.toggleSelected(!!checked)}
|
|
className="h-4 w-4 rounded border-gray-300"
|
|
/>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: "rowNo",
|
|
header: "NO",
|
|
cell: ({ row, table }) => {
|
|
if (row.original.isUpndFixPost) {
|
|
return (
|
|
<Badge
|
|
color="orange"
|
|
className="flex size-8 items-center justify-center"
|
|
>
|
|
<i className="diveicon di-volume-up-fill" />
|
|
</Badge>
|
|
);
|
|
}
|
|
const totalRows = table.getRowCount();
|
|
const currentPage = table.getState().pagination.pageIndex;
|
|
const pageSize = table.getState().pagination.pageSize;
|
|
return totalRows - (currentPage * pageSize + row.index);
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "pstTtl",
|
|
header: "제목",
|
|
cell: ({ row }) => {
|
|
const { ansPstn = 0, pstTtl, inqNocs, cmntCnt } = row.original;
|
|
const indentPadding = ansPstn > 0 ? (ansPstn - 1) * 20 : 0;
|
|
|
|
return (
|
|
<div
|
|
className="flex min-w-[20vw] items-center gap-2 text-left"
|
|
style={{ paddingInlineStart: `${indentPadding}px` }}
|
|
>
|
|
{ansPstn > 0 && (
|
|
<div className="flex items-center gap-1">
|
|
<div className="-rotate-90">
|
|
<i className="diveicon di-arrow-90left-down rotate-90" />
|
|
</div>
|
|
<Badge color="smokyBlue">답변</Badge>
|
|
</div>
|
|
)}
|
|
{inqNocs >= 100 && <Badge color="red">HOT</Badge>}
|
|
{dayjs().diff(dayjs(row.original.regDt), "hour") < 24 && (
|
|
<Badge color="blue">NEW</Badge>
|
|
)}
|
|
{pstTtl}
|
|
{cmntCnt > 0 && (
|
|
<div className="ml-4 flex items-end gap-2">
|
|
<i className="diveicon di-chat-box-left-text text-gray-400" />
|
|
<span className="text-gray-400">{cmntCnt}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "inqNocs",
|
|
header: "조회수",
|
|
},
|
|
{
|
|
accessorKey: "atflCd",
|
|
header: "첨부파일",
|
|
cell: ({ row }) => {
|
|
const atflCd = row.original.atflCd;
|
|
if (!atflCd) return null;
|
|
return <AttachmentButton atflCd={atflCd} />;
|
|
},
|
|
},
|
|
{
|
|
accessorKey: "rgtrNm",
|
|
header: "작성자",
|
|
},
|
|
{
|
|
accessorKey: "regDt",
|
|
header: "등록일",
|
|
cell: ({ row }) => dayjs(row.original.regDt).format("YYYY-MM-DD"),
|
|
},
|
|
];
|
|
|
|
const AttachmentButton = ({ atflCd }: { atflCd: string }) => {
|
|
const handleDownload = async (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
e.stopPropagation();
|
|
try {
|
|
let filename = "";
|
|
const response = await AttachmentApi.downloadAttachmentByAtflCd(atflCd);
|
|
const contentDisposition = response.headers["content-disposition"];
|
|
if (contentDisposition) {
|
|
const filenameMatch = contentDisposition.match(
|
|
/filename\*=UTF-8''([^;]+)/,
|
|
);
|
|
if (filenameMatch) {
|
|
filename = decodeURIComponent(filenameMatch[1]);
|
|
}
|
|
}
|
|
|
|
const blob = new Blob([response.data]);
|
|
const url = window.URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
|
|
link.href = url;
|
|
link.download = filename;
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(link);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Button size="icon" color="white" onClick={handleDownload}>
|
|
<i className="diveicon di-download" />
|
|
</Button>
|
|
);
|
|
};
|