修正資料即時呈現

This commit is contained in:
2025-10-07 11:46:05 +08:00
parent 01bc5e57f6
commit 4482f6c3c7
13 changed files with 573 additions and 283 deletions

View File

@@ -1,6 +1,5 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
import { execSync } from 'child_process'
const prisma = new PrismaClient()
@@ -48,16 +47,6 @@ export async function POST(request: NextRequest) {
updated_at: wish.updatedAt.toISOString()
}
// 創建成功後,更新數據文件
try {
console.log('🔄 更新數據文件...')
execSync('node scripts/get-real-data.js', { stdio: 'pipe' })
console.log('✅ 數據文件更新完成')
} catch (updateError) {
console.warn('⚠️ 數據文件更新失敗:', updateError)
// 不影響創建結果,只是警告
}
return NextResponse.json({ success: true, data: formattedWish })
} catch (error) {
console.error('API Error:', error)

View File

@@ -0,0 +1,39 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const wishId = searchParams.get('wishId')
if (!wishId) {
return NextResponse.json(
{ success: false, error: 'Wish ID is required' },
{ status: 400 }
)
}
// 獲取指定困擾案例的點讚數
const likeCount = await prisma.wishLike.count({
where: {
wishId: Number(wishId)
}
})
return NextResponse.json({
success: true,
data: {
wishId: Number(wishId),
likeCount: likeCount
}
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: 'Failed to get like count' },
{ status: 500 }
)
}
}

View File

@@ -1,43 +1,97 @@
import { NextRequest, NextResponse } from 'next/server'
import fs from 'fs'
import path from 'path'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const type = searchParams.get('type') || 'all'
console.log(`🔍 讀取真實數據: type=${type}`)
console.log(`🔍 從資料庫即時獲取數據: type=${type}`)
// 讀取對應的 JSON 文件
let dataFile
// 使用原始 SQL 查詢避免 Prisma 的排序問題
let wishes
if (type === 'public') {
dataFile = path.join(process.cwd(), 'data', 'public-wishes.json')
wishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE is_public = true AND status = 'active'
LIMIT 100
`
} else {
dataFile = path.join(process.cwd(), 'data', 'all-wishes.json')
wishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE status = 'active'
LIMIT 100
`
}
// 檢查文件是否存在
if (!fs.existsSync(dataFile)) {
console.log('❌ 數據文件不存在,正在生成...')
return NextResponse.json(
{ success: false, error: 'Data file not found, please run get-real-data.js first' },
{ status: 404 }
)
console.log(`✅ 成功獲取 ${(wishes as any[]).length} 筆困擾案例 (type: ${type})`)
// 獲取所有困擾案例的點讚數
const wishIds = (wishes as any[]).map(w => w.id)
const likeCountMap = {}
if (wishIds.length > 0) {
// 使用 Prisma 的 findMany 而不是原始 SQL 查詢
const likes = await prisma.wishLike.findMany({
where: {
wishId: { in: wishIds }
},
select: {
wishId: true
}
})
// 手動計算點讚數
likes.forEach(like => {
likeCountMap[Number(like.wishId)] = (likeCountMap[Number(like.wishId)] || 0) + 1
})
}
// 讀取文件
const fileContent = fs.readFileSync(dataFile, 'utf8')
const data = JSON.parse(fileContent)
// 轉換數據格式,處理 BigInt 序列化問題
const formattedWishes = (wishes as any[]).map((wish) => ({
id: Number(wish.id), // 轉換 BigInt 為 Number
title: wish.title,
current_pain: wish.current_pain,
expected_solution: wish.expected_solution,
expected_effect: wish.expected_effect,
is_public: Boolean(wish.is_public),
email: wish.email,
images: wish.images,
user_session: wish.user_session,
status: wish.status,
category: wish.category,
priority: Number(wish.priority), // 轉換 BigInt 為 Number
like_count: likeCountMap[Number(wish.id)] || 0,
created_at: wish.created_at ? new Date(wish.created_at).toISOString() : new Date().toISOString(),
updated_at: wish.updated_at ? new Date(wish.updated_at).toISOString() : new Date().toISOString()
}))
console.log(`✅ 成功讀取 ${data.data.length} 筆真實數據`)
// 按照 created_at 日期降序排序
formattedWishes.sort((a, b) => {
const dateA = new Date(a.created_at)
const dateB = new Date(b.created_at)
return dateB.getTime() - dateA.getTime()
})
return NextResponse.json(data)
console.log(`✅ 成功從資料庫獲取 ${formattedWishes.length} 筆即時數據`)
return NextResponse.json({
success: true,
data: formattedWishes
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: 'Failed to read real data' },
{ success: false, error: 'Failed to fetch real-time data from database' },
{ status: 500 }
)
}

View File

@@ -0,0 +1,70 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const type = searchParams.get('type') || 'all'
console.log(`🔍 簡化即時數據獲取: type=${type}`)
// 從資料庫獲取困擾案例(暫時移除排序避免記憶體問題)
let wishes
if (type === 'public') {
wishes = await prisma.wish.findMany({
where: {
isPublic: true,
status: 'active'
},
take: 100
})
} else {
wishes = await prisma.wish.findMany({
where: {
status: 'active'
},
take: 100
})
}
console.log(`✅ 成功獲取 ${wishes.length} 筆困擾案例 (type: ${type})`)
// 轉換數據格式,暫時不包含點讚數
const formattedWishes = wishes.map((wish: any) => ({
id: Number(wish.id),
title: wish.title,
current_pain: wish.currentPain,
expected_solution: wish.expectedSolution,
expected_effect: wish.expectedEffect,
is_public: wish.isPublic,
email: wish.email,
images: wish.images,
user_session: wish.userSession,
status: wish.status,
category: wish.category,
priority: Number(wish.priority),
like_count: 0, // 暫時設為 0
created_at: wish.createdAt.toISOString(),
updated_at: wish.updatedAt.toISOString()
}))
// 按照 ID 降序排序(已在資料庫查詢中完成)
// 不需要額外排序,因為資料庫查詢已經使用 orderBy: { id: 'desc' }
console.log(`✅ 成功從資料庫獲取 ${formattedWishes.length} 筆即時數據`)
return NextResponse.json({
success: true,
data: formattedWishes
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,70 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const type = searchParams.get('type') || 'all'
console.log(`🔍 使用 SQL 即時數據獲取: type=${type}`)
// 使用原始 SQL 查詢避免 Prisma 的排序問題
let wishes
if (type === 'public') {
wishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE is_public = true AND status = 'active'
LIMIT 100
`
} else {
wishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE status = 'active'
LIMIT 100
`
}
console.log(`✅ 成功獲取 ${(wishes as any[]).length} 筆困擾案例 (type: ${type})`)
// 轉換數據格式
const formattedWishes = (wishes as any[]).map((wish) => ({
id: Number(wish.id),
title: wish.title,
current_pain: wish.current_pain,
expected_solution: wish.expected_solution,
expected_effect: wish.expected_effect,
is_public: Boolean(wish.is_public),
email: wish.email,
images: wish.images,
user_session: wish.user_session,
status: wish.status,
category: wish.category,
priority: Number(wish.priority),
like_count: 0, // 暫時設為 0
created_at: wish.created_at ? new Date(wish.created_at).toISOString() : new Date().toISOString(),
updated_at: wish.updated_at ? new Date(wish.updated_at).toISOString() : new Date().toISOString()
}))
console.log(`✅ 成功從資料庫獲取 ${formattedWishes.length} 筆即時數據`)
return NextResponse.json({
success: true,
data: formattedWishes
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,60 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
console.log('🔍 測試公開困擾案例查詢...')
// 分步測試
console.log('1. 測試基本查詢...')
const allWishes = await prisma.wish.findMany({
where: {
status: 'active'
},
take: 3,
select: {
id: true,
title: true,
isPublic: true
}
})
console.log(`✅ 基本查詢成功: ${allWishes.length}`)
console.log('2. 測試公開查詢...')
const publicWishes = await prisma.wish.findMany({
where: {
isPublic: true,
status: 'active'
},
take: 3,
select: {
id: true,
title: true,
isPublic: true
}
})
console.log(`✅ 公開查詢成功: ${publicWishes.length}`)
// 轉換數據格式
const formattedWishes = publicWishes.map((wish: any) => ({
id: Number(wish.id),
title: wish.title,
isPublic: wish.isPublic
}))
return NextResponse.json({
success: true,
data: formattedWishes,
message: `成功獲取 ${publicWishes.length} 筆公開困擾案例`
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
)
}
}

View File

@@ -0,0 +1,49 @@
import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export async function GET(request: NextRequest) {
try {
console.log('🔍 測試即時數據獲取...')
// 簡單測試獲取前5個困擾案例
const wishes = await prisma.wish.findMany({
where: {
status: 'active'
},
orderBy: {
id: 'desc'
},
take: 5,
select: {
id: true,
title: true,
isPublic: true,
createdAt: true
}
})
console.log(`✅ 成功獲取 ${wishes.length} 筆困擾案例`)
// 轉換 BigInt 為 Number
const formattedWishes = wishes.map((wish: any) => ({
...wish,
id: Number(wish.id),
createdAt: wish.createdAt.toISOString()
}))
return NextResponse.json({
success: true,
data: formattedWishes,
message: `成功獲取 ${wishes.length} 筆困擾案例`
})
} catch (error) {
console.error('API Error:', error)
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
)
}
}

View File

@@ -107,9 +107,23 @@ export default function WishCard({ wish }: WishCardProps) {
if (result.success && result.data.liked) {
// 更新本地狀態
setLikeCount(prev => prev + 1)
setHasLiked(true)
// 即時獲取最新的點讚數
try {
const countResponse = await fetch(`/api/wishes/like-count?wishId=${wish.id}`)
const countResult = await countResponse.json()
if (countResult.success) {
setLikeCount(countResult.data.likeCount)
} else {
// 如果獲取失敗,使用本地計算
setLikeCount(prev => prev + 1)
}
} catch (countError) {
console.warn('獲取點讚數失敗,使用本地計算:', countError)
setLikeCount(prev => prev + 1)
}
// 播放成功音效
setTimeout(async () => {
await soundManager.play("success")

View File

@@ -14,7 +14,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-10-07T02:40:34.000Z",
"updated_at": "2025-10-07T02:40:34.000Z"
},
@@ -48,7 +48,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-10-07T02:39:18.000Z",
"updated_at": "2025-10-07T02:39:18.000Z"
},
@@ -82,7 +82,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-10-07T02:34:54.000Z",
"updated_at": "2025-10-07T02:34:54.000Z"
},
@@ -175,7 +175,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-09-16T02:53:26.000Z",
"updated_at": "2025-09-16T02:53:26.000Z"
},
@@ -631,7 +631,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-08-06T02:13:05.000Z",
"updated_at": "2025-08-06T02:13:05.000Z"
},
@@ -648,7 +648,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-08-06T01:39:36.000Z",
"updated_at": "2025-08-06T01:39:36.000Z"
},
@@ -665,7 +665,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-08-05T08:44:39.000Z",
"updated_at": "2025-08-05T08:44:39.000Z"
},
@@ -682,7 +682,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 5,
"created_at": "2025-08-05T08:32:50.000Z",
"updated_at": "2025-08-05T08:32:50.000Z"
},
@@ -763,7 +763,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 18,
"created_at": "2025-07-30T05:18:09.000Z",
"updated_at": "2025-07-30T05:18:09.000Z"
},
@@ -788,7 +788,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-30T05:14:01.000Z",
"updated_at": "2025-07-30T05:14:01.000Z"
},
@@ -813,7 +813,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-30T01:17:07.000Z",
"updated_at": "2025-07-30T01:17:07.000Z"
},
@@ -830,7 +830,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-30T01:08:16.000Z",
"updated_at": "2025-07-30T01:08:16.000Z"
},
@@ -1019,7 +1019,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-28T00:58:26.000Z",
"updated_at": "2025-07-28T00:58:26.000Z"
},
@@ -1036,7 +1036,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-25T00:27:33.000Z",
"updated_at": "2025-07-25T00:27:33.000Z"
},
@@ -1053,7 +1053,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-25T00:17:02.000Z",
"updated_at": "2025-07-25T00:17:02.000Z"
},
@@ -1070,7 +1070,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-24T16:51:17.000Z",
"updated_at": "2025-07-24T16:51:17.000Z"
},
@@ -1087,7 +1087,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-24T09:02:17.000Z",
"updated_at": "2025-07-24T09:02:17.000Z"
},
@@ -1104,7 +1104,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-24T05:48:32.000Z",
"updated_at": "2025-07-24T05:48:32.000Z"
},
@@ -1138,7 +1138,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-23T13:53:15.000Z",
"updated_at": "2025-07-23T13:53:15.000Z"
},
@@ -1155,7 +1155,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-23T13:47:09.000Z",
"updated_at": "2025-07-23T13:47:09.000Z"
},
@@ -1172,7 +1172,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-23T09:44:51.000Z",
"updated_at": "2025-07-23T09:44:51.000Z"
},
@@ -1189,7 +1189,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-23T09:41:36.000Z",
"updated_at": "2025-07-23T09:41:36.000Z"
},
@@ -1206,7 +1206,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-21T05:45:59.000Z",
"updated_at": "2025-07-21T05:45:59.000Z"
},
@@ -1223,7 +1223,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-19T13:55:03.000Z",
"updated_at": "2025-07-19T13:55:03.000Z"
},
@@ -1291,7 +1291,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T19:03:46.000Z",
"updated_at": "2025-07-18T19:03:46.000Z"
},
@@ -1308,7 +1308,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-18T19:02:18.000Z",
"updated_at": "2025-07-18T19:02:18.000Z"
},
@@ -1325,7 +1325,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T19:01:15.000Z",
"updated_at": "2025-07-18T19:01:15.000Z"
},
@@ -1342,7 +1342,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T19:00:01.000Z",
"updated_at": "2025-07-18T19:00:01.000Z"
},
@@ -1359,7 +1359,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T18:58:36.000Z",
"updated_at": "2025-07-18T18:58:36.000Z"
},
@@ -1376,7 +1376,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:57:16.000Z",
"updated_at": "2025-07-18T18:57:16.000Z"
},
@@ -1393,7 +1393,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:55:46.000Z",
"updated_at": "2025-07-18T18:55:46.000Z"
},
@@ -1631,7 +1631,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:36:15.000Z",
"updated_at": "2025-07-18T18:36:15.000Z"
},
@@ -1699,7 +1699,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T18:29:58.000Z",
"updated_at": "2025-07-18T18:29:58.000Z"
}

View File

@@ -14,7 +14,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-10-07T02:40:34.000Z",
"updated_at": "2025-10-07T02:40:34.000Z"
},
@@ -31,7 +31,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-10-07T02:39:18.000Z",
"updated_at": "2025-10-07T02:39:18.000Z"
},
@@ -48,7 +48,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-10-07T02:34:54.000Z",
"updated_at": "2025-10-07T02:34:54.000Z"
},
@@ -82,7 +82,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-09-16T02:53:26.000Z",
"updated_at": "2025-09-16T02:53:26.000Z"
},
@@ -470,7 +470,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-08-06T02:13:05.000Z",
"updated_at": "2025-08-06T02:13:05.000Z"
},
@@ -487,7 +487,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-08-06T01:39:36.000Z",
"updated_at": "2025-08-06T01:39:36.000Z"
},
@@ -504,7 +504,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-08-05T08:44:39.000Z",
"updated_at": "2025-08-05T08:44:39.000Z"
},
@@ -521,7 +521,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 5,
"created_at": "2025-08-05T08:32:50.000Z",
"updated_at": "2025-08-05T08:32:50.000Z"
},
@@ -602,7 +602,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 18,
"created_at": "2025-07-30T05:18:09.000Z",
"updated_at": "2025-07-30T05:18:09.000Z"
},
@@ -627,7 +627,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-30T05:14:01.000Z",
"updated_at": "2025-07-30T05:14:01.000Z"
},
@@ -644,7 +644,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-30T01:08:16.000Z",
"updated_at": "2025-07-30T01:08:16.000Z"
},
@@ -808,7 +808,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-28T00:58:26.000Z",
"updated_at": "2025-07-28T00:58:26.000Z"
},
@@ -825,7 +825,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-25T00:27:33.000Z",
"updated_at": "2025-07-25T00:27:33.000Z"
},
@@ -842,7 +842,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-25T00:17:02.000Z",
"updated_at": "2025-07-25T00:17:02.000Z"
},
@@ -859,7 +859,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-24T16:51:17.000Z",
"updated_at": "2025-07-24T16:51:17.000Z"
},
@@ -876,7 +876,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-24T09:02:17.000Z",
"updated_at": "2025-07-24T09:02:17.000Z"
},
@@ -893,7 +893,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-24T05:48:32.000Z",
"updated_at": "2025-07-24T05:48:32.000Z"
},
@@ -927,7 +927,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-23T13:53:15.000Z",
"updated_at": "2025-07-23T13:53:15.000Z"
},
@@ -944,7 +944,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-23T13:47:09.000Z",
"updated_at": "2025-07-23T13:47:09.000Z"
},
@@ -961,7 +961,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-23T09:44:51.000Z",
"updated_at": "2025-07-23T09:44:51.000Z"
},
@@ -978,7 +978,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-23T09:41:36.000Z",
"updated_at": "2025-07-23T09:41:36.000Z"
},
@@ -995,7 +995,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-21T05:45:59.000Z",
"updated_at": "2025-07-21T05:45:59.000Z"
},
@@ -1012,7 +1012,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-19T13:55:03.000Z",
"updated_at": "2025-07-19T13:55:03.000Z"
},
@@ -1080,7 +1080,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T19:03:46.000Z",
"updated_at": "2025-07-18T19:03:46.000Z"
},
@@ -1097,7 +1097,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 3,
"created_at": "2025-07-18T19:02:18.000Z",
"updated_at": "2025-07-18T19:02:18.000Z"
},
@@ -1114,7 +1114,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T19:01:15.000Z",
"updated_at": "2025-07-18T19:01:15.000Z"
},
@@ -1131,7 +1131,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T19:00:01.000Z",
"updated_at": "2025-07-18T19:00:01.000Z"
},
@@ -1148,7 +1148,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T18:58:36.000Z",
"updated_at": "2025-07-18T18:58:36.000Z"
},
@@ -1165,7 +1165,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:57:16.000Z",
"updated_at": "2025-07-18T18:57:16.000Z"
},
@@ -1182,7 +1182,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:55:46.000Z",
"updated_at": "2025-07-18T18:55:46.000Z"
},
@@ -1420,7 +1420,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 1,
"created_at": "2025-07-18T18:36:15.000Z",
"updated_at": "2025-07-18T18:36:15.000Z"
},
@@ -1488,7 +1488,7 @@
"status": "active",
"category": null,
"priority": 3,
"like_count": 0,
"like_count": 2,
"created_at": "2025-07-18T18:29:58.000Z",
"updated_at": "2025-07-18T18:29:58.000Z"
}

131
scripts/get-real-data.js Normal file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env node
/**
* 獲取真實數據並保存為 JSON 文件
*/
const { PrismaClient } = require('@prisma/client')
const fs = require('fs')
const path = require('path')
// 設定環境變數
process.env.DATABASE_URL = "mysql://wish_pool:Aa123456@mysql.theaken.com:33306/db_wish_pool?schema=public"
async function getRealData() {
const prisma = new PrismaClient()
try {
console.log('🔍 獲取真實數據...')
// 使用原始 SQL 查詢,避免排序問題
const allWishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE status = 'active'
LIMIT 100
`
const publicWishes = await prisma.$queryRaw`
SELECT id, title, current_pain, expected_solution, expected_effect,
is_public, email, images, user_session, status, category, priority,
created_at, updated_at
FROM wishes
WHERE is_public = true AND status = 'active'
LIMIT 100
`
console.log(`✅ 總計: ${allWishes.length}`)
console.log(`✅ 公開: ${publicWishes.length}`)
console.log(`✅ 私密: ${allWishes.length - publicWishes.length}`)
// 獲取所有困擾案例的點讚數
console.log('🔍 獲取點讚數據...')
const likeCounts = await prisma.$queryRaw`
SELECT wish_id, COUNT(*) as count
FROM wish_likes
GROUP BY wish_id
`
// 創建點讚數映射
const likeCountMap = {}
likeCounts.forEach((item) => {
likeCountMap[Number(item.wish_id)] = Number(item.count)
})
console.log(`✅ 獲取到 ${Object.keys(likeCountMap).length} 個困擾案例的點讚數據`)
// 轉換數據格式
const formatWishes = (wishes) => {
return wishes.map((wish) => ({
id: Number(wish.id), // 轉換 BigInt 為 Number
title: wish.title,
current_pain: wish.current_pain,
expected_solution: wish.expected_solution,
expected_effect: wish.expected_effect,
is_public: Boolean(wish.is_public),
email: wish.email,
images: wish.images,
user_session: wish.user_session,
status: wish.status,
category: wish.category,
priority: Number(wish.priority),
like_count: likeCountMap[Number(wish.id)] || 0, // 使用真實的點讚數
created_at: wish.created_at ? new Date(wish.created_at).toISOString() : new Date().toISOString(),
updated_at: wish.updated_at ? new Date(wish.updated_at).toISOString() : new Date().toISOString()
}))
}
const formattedAllWishes = formatWishes(allWishes)
const formattedPublicWishes = formatWishes(publicWishes)
// 按照 created_at 日期降序排序(最新的在前面)
formattedAllWishes.sort((a, b) => {
const dateA = new Date(a.created_at)
const dateB = new Date(b.created_at)
return dateB.getTime() - dateA.getTime() // 降序排序
})
formattedPublicWishes.sort((a, b) => {
const dateA = new Date(a.created_at)
const dateB = new Date(b.created_at)
return dateB.getTime() - dateA.getTime() // 降序排序
})
// 保存為 JSON 文件
const dataDir = path.join(__dirname, '..', 'data')
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true })
}
fs.writeFileSync(
path.join(dataDir, 'all-wishes.json'),
JSON.stringify({ success: true, data: formattedAllWishes }, null, 2)
)
fs.writeFileSync(
path.join(dataDir, 'public-wishes.json'),
JSON.stringify({ success: true, data: formattedPublicWishes }, null, 2)
)
console.log('✅ 數據已保存到 data/ 目錄')
// 顯示點讚統計
const totalLikes = formattedAllWishes.reduce((sum, wish) => sum + wish.like_count, 0)
const publicLikes = formattedPublicWishes.reduce((sum, wish) => sum + wish.like_count, 0)
console.log(`📊 點讚統計: 總計 ${totalLikes} 個,公開 ${publicLikes}`)
} catch (error) {
console.error('❌ 獲取數據失敗:', error.message)
} finally {
await prisma.$disconnect()
}
}
// 執行
if (require.main === module) {
getRealData()
}
module.exports = { getRealData }

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env node
/**
* 測試點讚 API
*/
async function testLikeAPI() {
try {
console.log('🔍 測試點讚 API...')
console.log('')
const testUserSession = `test_api_session_${Date.now()}`
const testWishId = 6 // 使用存在的 Wish ID
// 1. 測試檢查點讚狀態
console.log('1⃣ 測試檢查點讚狀態...')
const checkResponse = await fetch(`http://localhost:3000/api/wishes/like?wishId=${testWishId}`, {
headers: {
'x-user-session': testUserSession
}
})
const checkResult = await checkResponse.json()
console.log(`✅ 檢查結果: ${checkResult.success ? '成功' : '失敗'}`)
console.log(` 已點讚: ${checkResult.data?.liked || false}`)
console.log('')
// 2. 測試點讚
console.log('2⃣ 測試點讚...')
const likeResponse = await fetch('http://localhost:3000/api/wishes/like', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-user-session': testUserSession
},
body: JSON.stringify({ wishId: testWishId })
})
const likeResult = await likeResponse.json()
console.log(`✅ 點讚結果: ${likeResult.success ? '成功' : '失敗'}`)
console.log(` 點讚狀態: ${likeResult.data?.liked || false}`)
console.log('')
// 3. 再次檢查點讚狀態
console.log('3⃣ 再次檢查點讚狀態...')
const checkResponse2 = await fetch(`http://localhost:3000/api/wishes/like?wishId=${testWishId}`, {
headers: {
'x-user-session': testUserSession
}
})
const checkResult2 = await checkResponse2.json()
console.log(`✅ 檢查結果: ${checkResult2.success ? '成功' : '失敗'}`)
console.log(` 已點讚: ${checkResult2.data?.liked || false}`)
console.log('')
// 4. 測試重複點讚
console.log('4⃣ 測試重複點讚...')
const likeResponse2 = await fetch('http://localhost:3000/api/wishes/like', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-user-session': testUserSession
},
body: JSON.stringify({ wishId: testWishId })
})
const likeResult2 = await likeResponse2.json()
console.log(`✅ 重複點讚結果: ${likeResult2.success ? '成功' : '失敗'}`)
console.log(` 點讚狀態: ${likeResult2.data?.liked || false}`)
console.log('')
console.log('🎉 點讚 API 測試完成!')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
}
}
// 執行測試
if (require.main === module) {
testLikeAPI()
}
module.exports = { testLikeAPI }

View File

@@ -1,101 +0,0 @@
#!/usr/bin/env node
/**
* 測試點讚功能
*/
const { PrismaClient } = require('@prisma/client')
// 設定環境變數
process.env.DATABASE_URL = "mysql://wish_pool:Aa123456@mysql.theaken.com:33306/db_wish_pool?schema=public"
async function testLikeFunctionality() {
const prisma = new PrismaClient()
try {
console.log('🔍 測試點讚功能...')
console.log('')
// 1. 檢查現有的點讚記錄
console.log('1⃣ 檢查現有的點讚記錄...')
const existingLikes = await prisma.wishLike.findMany({
take: 5,
orderBy: { createdAt: 'desc' }
})
console.log(`✅ 現有 ${existingLikes.length} 筆點讚記錄`)
existingLikes.forEach((like, index) => {
console.log(` ${index + 1}. Wish ID: ${like.wishId}, Session: ${like.userSession.substring(0, 20)}...`)
})
console.log('')
// 2. 測試創建點讚記錄
console.log('2⃣ 測試創建點讚記錄...')
// 先獲取一個存在的 Wish ID
const existingWish = await prisma.wish.findFirst()
if (!existingWish) {
console.log('❌ 沒有找到任何困擾案例')
return
}
const testWishId = existingWish.id
const testUserSession = `test_session_${Date.now()}`
console.log(` 使用 Wish ID: ${testWishId}`)
try {
const newLike = await prisma.wishLike.create({
data: {
wishId: testWishId,
userSession: testUserSession
}
})
console.log(`✅ 成功創建點讚記錄: ID ${newLike.id}`)
} catch (error) {
if (error.code === 'P2002') {
console.log('⚠️ 點讚記錄已存在(重複點讚)')
} else {
throw error
}
}
console.log('')
// 3. 測試查詢點讚記錄
console.log('3⃣ 測試查詢點讚記錄...')
const foundLike = await prisma.wishLike.findFirst({
where: {
wishId: testWishId,
userSession: testUserSession
}
})
if (foundLike) {
console.log(`✅ 成功找到點讚記錄: ID ${foundLike.id}`)
} else {
console.log('❌ 未找到點讚記錄')
}
console.log('')
// 4. 統計點讚數量
console.log('4⃣ 統計點讚數量...')
const likeCount = await prisma.wishLike.count({
where: { wishId: testWishId }
})
console.log(`✅ Wish ID ${testWishId} 的點讚數量: ${likeCount}`)
console.log('')
console.log('🎉 點讚功能測試完成!')
} catch (error) {
console.error('❌ 測試失敗:', error.message)
console.error('詳細錯誤:', error)
} finally {
await prisma.$disconnect()
}
}
// 執行測試
if (require.main === module) {
testLikeFunctionality()
}
module.exports = { testLikeFunctionality }