summaryrefslogtreecommitdiff
path: root/lib/qna/table/qna-export-actions.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qna/table/qna-export-actions.tsx')
-rw-r--r--lib/qna/table/qna-export-actions.tsx261
1 files changed, 261 insertions, 0 deletions
diff --git a/lib/qna/table/qna-export-actions.tsx b/lib/qna/table/qna-export-actions.tsx
new file mode 100644
index 00000000..07b692c0
--- /dev/null
+++ b/lib/qna/table/qna-export-actions.tsx
@@ -0,0 +1,261 @@
+"use server"
+
+import { QnaViewSelect } from "@/db/schema"
+
+interface ExportQnaDataParams {
+ format: "csv" | "excel"
+ data: QnaViewSelect[]
+ fields: string[]
+}
+
+/**
+ * Q&A 데이터 내보내기
+ */
+export async function exportQnaData({
+ format,
+ data,
+ fields
+}: ExportQnaDataParams) {
+ try {
+ // 필드 매핑
+ const fieldMapping: Record<string, string> = {
+ title: "제목",
+ authorName: "작성자",
+ companyName: "회사명",
+ authorDomain: "도메인",
+ vendorType: "벤더타입",
+ totalAnswers: "답변수",
+ totalComments: "댓글수",
+ createdAt: "작성일",
+ lastActivityAt: "최근활동",
+ hasAnswers: "답변여부",
+ isPopular: "인기질문",
+ }
+
+ // 데이터 변환
+ const exportData = data.map(qna => {
+ const row: Record<string, any> = {}
+
+ fields.forEach(field => {
+ const label = fieldMapping[field] || field
+
+ switch (field) {
+ case "createdAt":
+ case "lastActivityAt":
+ row[label] = qna[field as keyof QnaViewSelect]
+ ? new Date(qna[field as keyof QnaViewSelect] as string).toLocaleDateString("ko-KR")
+ : ""
+ break
+ case "hasAnswers":
+ row[label] = qna.hasAnswers ? "예" : "아니오"
+ break
+ case "isPopular":
+ row[label] = qna.isPopular ? "예" : "아니오"
+ break
+ case "authorDomain":
+ const domainLabels: Record<string, string> = {
+ partners: "협력업체",
+ tech: "기술업체",
+ admin: "관리자"
+ }
+ row[label] = domainLabels[qna.authorDomain as string] || qna.authorDomain
+ break
+ case "vendorType":
+ const typeLabels: Record<string, string> = {
+ vendor: "일반벤더",
+ techVendor: "기술벤더"
+ }
+ row[label] = typeLabels[qna.vendorType as string] || qna.vendorType || ""
+ break
+ default:
+ row[label] = qna[field as keyof QnaViewSelect] || ""
+ }
+ })
+
+ return row
+ })
+
+ if (format === "csv") {
+ return generateCSV(exportData)
+ } else {
+ return generateExcel(exportData)
+ }
+ } catch (error) {
+ console.error("내보내기 오류:", error)
+ return {
+ success: false,
+ error: "데이터 내보내기 중 오류가 발생했습니다."
+ }
+ }
+}
+
+/**
+ * CSV 파일 생성
+ */
+function generateCSV(data: Record<string, any>[]) {
+ try {
+ if (data.length === 0) {
+ return {
+ success: false,
+ error: "내보낼 데이터가 없습니다."
+ }
+ }
+
+ const headers = Object.keys(data[0])
+ const csvContent = [
+ headers.join(","), // 헤더
+ ...data.map(row =>
+ headers.map(header => {
+ const value = row[header]
+ // CSV에서 쉼표와 따옴표 이스케이프
+ if (typeof value === "string" && (value.includes(",") || value.includes('"'))) {
+ return `"${value.replace(/"/g, '""')}"`
+ }
+ return value
+ }).join(",")
+ )
+ ].join("\n")
+
+ // BOM 추가 (한글 인코딩을 위해)
+ const csvWithBOM = "\uFEFF" + csvContent
+ const blob = new Blob([csvWithBOM], { type: "text/csv;charset=utf-8;" })
+
+ // 파일 다운로드 처리는 클라이언트에서 수행
+ const url = URL.createObjectURL(blob)
+ const fileName = `qna_export_${new Date().toISOString().split('T')[0]}.csv`
+
+ // 클라이언트에서 다운로드 처리
+ if (typeof window !== "undefined") {
+ const link = document.createElement("a")
+ link.href = url
+ link.download = fileName
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ URL.revokeObjectURL(url)
+ }
+
+ return {
+ success: true,
+ message: "CSV 파일이 다운로드되었습니다."
+ }
+ } catch (error) {
+ return {
+ success: false,
+ error: "CSV 생성 중 오류가 발생했습니다."
+ }
+ }
+}
+
+/**
+ * Excel 파일 생성
+ */
+function generateExcel(data: Record<string, any>[]) {
+ try {
+ if (data.length === 0) {
+ return {
+ success: false,
+ error: "내보낼 데이터가 없습니다."
+ }
+ }
+
+ // Excel 생성을 위해 SheetJS 라이브러리 사용
+ // 실제 구현에서는 xlsx 라이브러리를 사용해야 함
+
+ const headers = Object.keys(data[0])
+ const worksheet = [
+ headers, // 헤더 행
+ ...data.map(row => headers.map(header => row[header])) // 데이터 행들
+ ]
+
+ // 간단한 CSV 형태로 반환 (실제로는 xlsx 라이브러리 사용 권장)
+ const csvContent = worksheet.map(row =>
+ row.map(cell => {
+ if (typeof cell === "string" && (cell.includes(",") || cell.includes('"'))) {
+ return `"${cell.replace(/"/g, '""')}"`
+ }
+ return cell
+ }).join(",")
+ ).join("\n")
+
+ const csvWithBOM = "\uFEFF" + csvContent
+ const blob = new Blob([csvWithBOM], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ })
+
+ const url = URL.createObjectURL(blob)
+ const fileName = `qna_export_${new Date().toISOString().split('T')[0]}.xlsx`
+
+ // 클라이언트에서 다운로드 처리
+ if (typeof window !== "undefined") {
+ const link = document.createElement("a")
+ link.href = url
+ link.download = fileName
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ URL.revokeObjectURL(url)
+ }
+
+ return {
+ success: true,
+ message: "Excel 파일이 다운로드되었습니다."
+ }
+ } catch (error) {
+ return {
+ success: false,
+ error: "Excel 생성 중 오류가 발생했습니다."
+ }
+ }
+}
+
+/**
+ * Q&A 통계 내보내기
+ */
+export async function exportQnaStats(data: QnaViewSelect[]) {
+ try {
+ const stats = {
+ 총질문수: data.length,
+ 답변된질문: data.filter(q => q.hasAnswers).length,
+ 답변대기질문: data.filter(q => !q.hasAnswers).length,
+ 인기질문: data.filter(q => q.isPopular).length,
+ 평균답변수: data.reduce((sum, q) => sum + (q.totalAnswers || 0), 0) / data.length,
+ 평균댓글수: data.reduce((sum, q) => sum + (q.totalComments || 0), 0) / data.length,
+ }
+
+ // 도메인별 통계
+ const domainStats = data.reduce((acc, q) => {
+ const domain = q.authorDomain || "기타"
+ acc[domain] = (acc[domain] || 0) + 1
+ return acc
+ }, {} as Record<string, number>)
+
+ // 회사별 통계 (상위 10개)
+ const companyStats = data.reduce((acc, q) => {
+ const company = q.companyName || "미지정"
+ acc[company] = (acc[company] || 0) + 1
+ return acc
+ }, {} as Record<string, number>)
+
+ const topCompanies = Object.entries(companyStats)
+ .sort(([,a], [,b]) => b - a)
+ .slice(0, 10)
+
+ const exportData = [
+ { 구분: "전체 통계", ...stats },
+ { 구분: "도메인별", ...domainStats },
+ ...topCompanies.map(([company, count]) => ({
+ 구분: "회사별",
+ 회사명: company,
+ 질문수: count
+ }))
+ ]
+
+ return generateCSV(exportData)
+ } catch (error) {
+ return {
+ success: false,
+ error: "통계 내보내기 중 오류가 발생했습니다."
+ }
+ }
+} \ No newline at end of file