[cs] feat: 게시판 통계 페이지 데이터 바인딩 작업

This commit is contained in:
2026-02-03 10:47:23 +09:00
parent 2947fb1524
commit 8a160dc97c
7 changed files with 887 additions and 79 deletions
@@ -1,53 +1,22 @@
// import { client } from "@/shared/api";
// import { ENDPOINT } from "@/shared/config";
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import {
type BoardStatisticsParams,
type BoardStatistics,
type BoardStatisticsService,
} from "../model/board-statistics-interface";
// 임시 모의 데이터
const mockBoardStatisticsData: BoardStatistics = {
totalPosts: 2456,
totalComments: 156,
averageRating: 4.2,
totalViews: 45678,
dayList: [
{ date: "1월", posts: 10, comments: 5, views: 800 },
{ date: "2월", posts: 15, comments: 8, views: 1200 },
{ date: "3월", posts: 12, comments: 10, views: 1000 },
{ date: "4월", posts: 18, comments: 15, views: 1500 },
{ date: "5월", posts: 22, comments: 20, views: 1800 },
{ date: "6월", posts: 20, comments: 18, views: 1600 },
{ date: "7월", posts: 25, comments: 22, views: 2000 },
],
boardList: [
{ boardType: "notice", boardName: "공지사항", count: 45 },
{ boardType: "faq", boardName: "FAQ", count: 120 },
{ boardType: "qna", boardName: "Q&A", count: 180 },
{ boardType: "free", boardName: "자유게시판", count: 95 },
],
statusList: [
{ status: "completed", statusName: "답변완료", count: 75 },
{ status: "waiting", statusName: "답변대기", count: 25 },
],
};
class BoardStatisticsApiService implements BoardStatisticsService {
async getBoardStatistics(
params: BoardStatisticsParams,
): Promise<BoardStatistics> {
console.log("params: ", params);
try {
// 실제 API 연동 시 아래 코드 사용
// const response = await client.get<BoardStatistics>(
// `${ENDPOINT.CMS_SERVICE.BOARD_STATISTICS}`,
// { params },
// );
// return response.data;
// 임시 모의 데이터 반환
return Promise.resolve(mockBoardStatisticsData);
const response = await client.get<BoardStatistics>(
`${ENDPOINT.BOARD_SERVICE.STATISTICS}`,
{ params },
);
return response.data;
} catch (error) {
console.error("게시판 통계 데이터 조회 실패:", error);
throw error;
@@ -12,32 +12,36 @@ export interface BoardStatisticsParams extends PageableParams {
}
export interface BoardStatistics {
totalPosts: number;
totalComments: number;
averageRating: number;
totalViews: number;
dayList: DayStatistics[];
boardList: BoardTypeStatistics[];
statusList: StatusStatistics[];
bbsTotalDto: BbsTotalDto; // 게시판 전체 통계
pstAnsList: PstAnswerStatistics[]; // 게시물 답변 상태별 통계 목록
bbsDailyList: BbsDailyStatistics[]; // 게시판 일별 통계 목록
bbsPstCntList: BbsPostCountStatistics[]; // 게시판별 게시물 건수 통계 목록
}
interface DayStatistics {
date: string;
posts: number;
comments: number;
views: number;
interface BbsTotalDto {
pstInqCnt: number; // 게시물 조회 건수
pstEvlAvg: number; // 게시물 평가 평균
pstTotCnt: number; // 게시물 총 건수
pstAnsWaitCnt: number; // 게시물 답변 대기 건수
}
interface BoardTypeStatistics {
boardType: string;
boardName: string;
count: number;
interface PstAnswerStatistics {
answerNm: string; // 답변 명
answerYn: string; // 답변 여부 (Y/N)
ansCnt: number; // 답변 건수
}
interface StatusStatistics {
status: string;
statusName: string;
count: number;
interface BbsDailyStatistics {
dayYmd: string; // 일자 (YYYY-MM-DD)
pstInqCnt: number; // 게시물 조회 건수
pstCmntCnt: number; // 게시물 댓글 건수
pstNewCnt: number; // 게시물 신규 건수
}
interface BbsPostCountStatistics {
bbsId: number; // 게시판 ID
bbsNm: string; // 게시판 명
pstCnt: number; // 게시물 건수
}
export interface BoardStatisticsService {
@@ -11,20 +11,20 @@ export const chartData = {
} => {
return {
data: {
labels: data.dayList.map((item) => item.date),
labels: data.bbsDailyList.map((item) => item.dayYmd),
datasets: [
{
type: "line",
label: "신규게시물",
data: data.dayList.map((item) => item.posts),
data: data.bbsDailyList.map((item) => item.pstNewCnt),
borderColor: getCssVariableValue("--chart-1"),
backgroundColor: "rgba(59, 130, 246, 0.1)",
tension: 0.4,
},
{
type: "line",
label: "답변대기",
data: data.dayList.map((item) => item.comments),
label: "댓글수",
data: data.bbsDailyList.map((item) => item.pstCmntCnt),
borderColor: getCssVariableValue("--chart-2"),
backgroundColor: "rgba(236, 72, 153, 0.1)",
tension: 0.4,
@@ -32,11 +32,10 @@ export const chartData = {
{
type: "line",
label: "조회수",
data: data.dayList.map((item) => item.views),
data: data.bbsDailyList.map((item) => item.pstInqCnt),
borderColor: getCssVariableValue("--chart-3"),
backgroundColor: "rgba(168, 85, 247, 0.1)",
tension: 0.4,
hidden: true,
},
],
},
@@ -67,13 +66,13 @@ export const chartData = {
} => {
return {
data: {
labels: data.boardList.map((item) => item.boardName),
labels: data.bbsPstCntList.map((item) => item.bbsNm),
datasets: [
{
type: "bar",
label: "게시판별 분포",
data: data.boardList.map((item) => item.count),
backgroundColor: data.boardList.map((_, index) =>
data: data.bbsPstCntList.map((item) => item.pstCnt),
backgroundColor: data.bbsPstCntList.map((_, index) =>
getCssVariableValue(`--chart-${(index % 5) + 1}`),
),
},
@@ -106,12 +105,12 @@ export const chartData = {
} => {
return {
data: {
labels: data.statusList.map((item) => item.statusName),
labels: data.pstAnsList.map((item) => item.answerNm),
datasets: [
{
type: "doughnut",
data: data.statusList.map((item) => item.count),
backgroundColor: data.statusList.map((_, index) =>
data: data.pstAnsList.map((item) => item.ansCnt),
backgroundColor: data.pstAnsList.map((_, index) =>
getCssVariableValue(`--chart-${(index % 5) + 1}`),
),
},
@@ -26,7 +26,7 @@ import {
SelectValue,
} from "@common/components";
import { SiteSelect } from "@/entities/site";
// import { ENDPOINT } from "@/shared/config";
import { ENDPOINT } from "@/shared/config";
import { NoData } from "@/shared/ui/no-data";
import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker";
import { BoardStatisticsApi } from "../api/board-statistics-service";
@@ -66,7 +66,7 @@ function BoardStatisticsPage() {
});
const { data: boardStatisticsData } = useQuery({
queryKey: ["board-statistics", searchParams],
queryKey: [ENDPOINT.BOARD_SERVICE.STATISTICS, searchParams],
queryFn: () =>
BoardStatisticsApi.getBoardStatistics({
...searchParams,
@@ -176,7 +176,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">총 게시물</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalPosts.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstTotCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -210,7 +211,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">답변대기</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalComments.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstAnsWaitCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -244,7 +246,7 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">평균평점</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.averageRating.toFixed(1) || 0}
{boardStatisticsData?.bbsTotalDto?.pstEvlAvg?.toFixed(1) || 0}
</div>
<div className="h-16 w-24">
<Line
@@ -278,7 +280,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">총 조회수</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalViews.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstInqCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -315,7 +318,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">일별 게시물 현황</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.dayList?.length ? (
{boardStatisticsData?.bbsDailyList?.length ? (
<Line {...chartData.day(boardStatisticsData)} />
) : (
<NoData />
@@ -329,7 +332,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">답변상태</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.statusList?.length ? (
{boardStatisticsData?.pstAnsList?.length ? (
<Doughnut {...chartData.status(boardStatisticsData)} />
) : (
<NoData />
@@ -342,7 +345,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">게시판별 분포</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.boardList?.length ? (
{boardStatisticsData?.bbsPstCntList?.length ? (
<Bar {...chartData.board(boardStatisticsData)} />
) : (
<NoData />
+1
View File
@@ -63,6 +63,7 @@ export const ENDPOINT = {
POSTS: "/board-service/api/v1/posts",
POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts",
POST_EVALUATION: "/board-service/api/v1/pstEvl",
STATISTICS: "/board-service/api/v1/stat/bbs",
},
};