diff --git a/apps/cs/app/(without-base-layout)/user-survey-result/[srvySn]/page.tsx b/apps/cs/app/(without-base-layout)/user-survey-result/[srvySn]/page.tsx new file mode 100644 index 000000000..017d469dd --- /dev/null +++ b/apps/cs/app/(without-base-layout)/user-survey-result/[srvySn]/page.tsx @@ -0,0 +1,10 @@ +import { UserSurveyResult } from "@/pages/survey"; + +export default async function UserSurveyResultPage({ + params, +}: { + params: Promise<{ srvySn: string }>; +}) { + const { srvySn } = await params; + return ; +} diff --git a/apps/cs/src/entities/site/@x/posting.ts b/apps/cs/src/entities/site/@x/posting.ts index b44c10445..6470b3cb2 100644 --- a/apps/cs/src/entities/site/@x/posting.ts +++ b/apps/cs/src/entities/site/@x/posting.ts @@ -1,4 +1,2 @@ export { SiteApi } from "../api/site-service"; export type { Site } from "../model/site-interface"; - -export { SiteSelect } from "../ui/site-select"; diff --git a/apps/cs/src/entities/site/index.ts b/apps/cs/src/entities/site/index.ts index 998c13625..95a3ead10 100644 --- a/apps/cs/src/entities/site/index.ts +++ b/apps/cs/src/entities/site/index.ts @@ -5,5 +5,4 @@ export { type Site, type SiteFormData, } from "./model/site-interface"; - -export { SiteSelect } from "./ui/site-select"; \ No newline at end of file +export { SiteSelect } from "./ui/site-select"; diff --git a/apps/cs/src/entities/site/ui/site-select.tsx b/apps/cs/src/entities/site/ui/site-select.tsx index 61f412b4d..6c5a0d005 100644 --- a/apps/cs/src/entities/site/ui/site-select.tsx +++ b/apps/cs/src/entities/site/ui/site-select.tsx @@ -10,23 +10,29 @@ import { ENDPOINT } from "@/shared/config"; import { SiteApi } from "../api/site-service"; type SiteSelectProps = { - siteId: string; placeholder?: string; + enabledAllSite?: boolean; } & React.ComponentPropsWithoutRef; function SiteSelect({ defaultValue, placeholder = "선택", + enabledAllSite, ...props }: SiteSelectProps) { const { data: sites } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.SITES], queryFn: () => SiteApi.getSiteList(), - enabled: true, + select: (data) => { + if (enabledAllSite) { + return [{ siteId: "ALL", siteNm: "전체" }, ...data.content]; + } + return data.content; + }, }); const defaultValueText = - sites?.content.find((item) => item.siteId === defaultValue)?.siteNm ?? placeholder; + sites?.find((item) => item.siteId === defaultValue)?.siteNm ?? placeholder; return ( @@ -34,7 +40,7 @@ function SiteSelect({ - {sites?.content.map((item) => ( + {sites?.map((item) => ( {item.siteNm} diff --git a/apps/cs/src/pages/code/ui/upcode-dialog.tsx b/apps/cs/src/pages/code/ui/upcode-dialog.tsx index 1b9aea8fa..28f483c5f 100644 --- a/apps/cs/src/pages/code/ui/upcode-dialog.tsx +++ b/apps/cs/src/pages/code/ui/upcode-dialog.tsx @@ -212,7 +212,6 @@ const UpCodeManagementDialog = memo( diff --git a/apps/cs/src/pages/survey/api/survey-service.ts b/apps/cs/src/pages/survey/api/survey-service.ts index 3a43d1d03..6db4ea52d 100644 --- a/apps/cs/src/pages/survey/api/survey-service.ts +++ b/apps/cs/src/pages/survey/api/survey-service.ts @@ -15,6 +15,8 @@ import type { ArticleParams, UserSurvey, UserSurveyFormData, + UserSurveyResultParams, + UserSurveyResult, } from "../model/survey-interface"; export class SurveyApiService implements SurveyService { @@ -102,6 +104,17 @@ export class SurveyApiService implements SurveyService { public async saveUserSurvey(data: UserSurveyFormData): Promise { await client.post(`${ENDPOINT.CMS_SERVICE.SURVEY}/user`, data); } + + public async getUserSurveyResult( + srvySn: number, + params: UserSurveyResultParams, + ): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.SURVEY}/rslt/stat/${srvySn}`, + { params }, + ); + return response.data; + } } export const SurveyApi = new SurveyApiService(); diff --git a/apps/cs/src/pages/survey/index.ts b/apps/cs/src/pages/survey/index.ts index 18297a746..0fc3a8f29 100644 --- a/apps/cs/src/pages/survey/index.ts +++ b/apps/cs/src/pages/survey/index.ts @@ -3,3 +3,4 @@ export { CreatePage } from "./ui/create-page"; export { DetailPage } from "./ui/detail-page"; export { ModifyPage } from "./ui/modify-page"; export { UserSurveyArticle } from "./ui/user-survey-article"; +export { UserSurveyResult } from "./ui/user-survey-result"; diff --git a/apps/cs/src/pages/survey/model/survey-interface.ts b/apps/cs/src/pages/survey/model/survey-interface.ts index ee1f082cb..52dab352f 100644 --- a/apps/cs/src/pages/survey/model/survey-interface.ts +++ b/apps/cs/src/pages/survey/model/survey-interface.ts @@ -38,6 +38,12 @@ export interface ArticleParams extends PageableParams { delYn?: string; } +export interface UserSurveyResultParams { + keywordType?: string; + keyword?: string; + siteId?: string; +} + export interface Survey { srvySn: number; srvyTtl: string; @@ -112,6 +118,48 @@ export const userSurveyFormSchema = z.object({ ), }); +const inputResultSchema = z.object({ + rspdntNm: z.string(), + ansCn: z.string(), + ansDt: z.string(), +}); + +const articleWithResultSchema = articleSchema.omit({ mode: true }).extend({ + inputRslts: z.array(inputResultSchema), + rspnsCount: z.number(), + rspnsRate: z.number(), +}); + +const questionWithArticlesSchema = questionFormSchema.extend({ + srvyQitemNo: z.number(), + articles: z.array(articleWithResultSchema), +}); + +const respondentStateSchema = z.object({ + ageN20대: z.number(), + ageN30대: z.number(), + ageN40대: z.number(), + ageN50대: z.number(), + ageN60대이상: z.number(), + job학생: z.number(), + job대학생: z.number(), + job회사원: z.number(), + job공단직원: z.number(), + job공무원: z.number(), + job기타: z.number(), + mf남성: z.number(), + mf여성: z.number(), + 구분: z.string(), +}); + +export const userSurveyResultSchema = surveyFormSchema.extend({ + srvySn: z.number(), + srvyPeriodFrTo: z.string(), + qitems: z.array(questionWithArticlesSchema), + srvyRspntStatList: z.array(respondentStateSchema), + totalRspdnt: z.number(), +}); + export type SurveyList = PageableList; export type SurveyFormData = z.infer; export type QuestionList = PageableList; @@ -124,6 +172,7 @@ export type UserSurvey = SurveyDetail & { })[]; }; export type UserSurveyFormData = z.infer; +export type UserSurveyResult = z.infer; export interface SurveyService { getSurveyList(params: SurveyParams): Promise; @@ -139,4 +188,8 @@ export interface SurveyService { saveArticleList(data: Article[]): Promise; getUserSurvey(srvySn: number): Promise; saveUserSurvey(data: UserSurveyFormData): Promise; + getUserSurveyResult( + srvySn: number, + params: UserSurveyResultParams, + ): Promise; } diff --git a/apps/cs/src/pages/survey/model/survey-table-columns.tsx b/apps/cs/src/pages/survey/model/survey-table-columns.tsx index 08213020b..a1689e38a 100644 --- a/apps/cs/src/pages/survey/model/survey-table-columns.tsx +++ b/apps/cs/src/pages/survey/model/survey-table-columns.tsx @@ -81,8 +81,24 @@ export const columns: ColumnDef[] = [ { id: "result", header: "설문 결과", - cell: () => ( - + cell: ({ row }) => ( + { + e.stopPropagation(); + + const width = 767; + const height = 900; + const left = window.screen.width / 2 - width / 2 + window.screenX; + const top = window.screen.height / 2 - height / 2 + window.screenY; + window.open( + `/user-survey-result/${row.original.srvySn}`, + "", + `width=${width},height=${height},left=${left},top=${top}`, + ); + }} + > 설문 결과 ), diff --git a/apps/cs/src/pages/survey/ui/user-survey-result.tsx b/apps/cs/src/pages/survey/ui/user-survey-result.tsx new file mode 100644 index 000000000..e79c57eb2 --- /dev/null +++ b/apps/cs/src/pages/survey/ui/user-survey-result.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { useState } from "react"; +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + Button, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@common/components"; +import { ENDPOINT } from "@/shared/config"; +import { SurveyApi } from "../api/survey-service"; +import type { UserSurveyResultParams } from "../model/survey-interface"; +import { SiteSelect } from "@/entities/site"; + +function UserSurveyResult({ srvySn }: { srvySn: string }) { + const [params, setParams] = useState({ + siteId: "ALL", + }); + + const { data } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, srvySn, params.siteId], + queryFn: () => SurveyApi.getUserSurveyResult(parseInt(srvySn), params), + placeholderData: keepPreviousData, + }); + + return ( + + + + + {data?.srvyTtl} + + + setParams({ siteId })} + enabledAllSite + /> + 인쇄 + window.close()}> + 닫기 + + + + + + 응답자 통계 + + + ( 총 응답자 수: {data?.totalRspdnt}명 / 설문 기간:{" "} + {data?.srvyPeriodFrTo} ) + + + + + + + 구분 + 성별 + 직업 + 나이 + + + 남성 + 여성 + 학생 + 대학생 + 회사원 + 공단직원 + 공무원 + 기타 + 20대 + 30대 + 40대 + 50대 + 60대 이상 + + + + {data?.srvyRspntStatList.map((item) => ( + + {item.구분} + {item.mf남성} + {item.mf여성} + {item.job학생} + {item.job대학생} + {item.job회사원} + {item.job공단직원} + {item.job공무원} + {item.job기타} + {item.ageN20대} + {item.ageN30대} + {item.ageN40대} + {item.ageN50대} + {item.ageN60대이상} + + ))} + + + + + + ); +} + +export { UserSurveyResult };
+ ( 총 응답자 수: {data?.totalRspdnt}명 / 설문 기간:{" "} + {data?.srvyPeriodFrTo} ) +