競賽資訊完整版 ( 只剩評分、競賽得獎 )

This commit is contained in:
2025-09-16 17:19:20 +08:00
parent b4386dc481
commit 6ce0b250cb
4 changed files with 67 additions and 22 deletions

View File

@@ -77,8 +77,8 @@ export async function GET(request: NextRequest, { params }: { params: { id: stri
likes_count: app.likes_count || 0, likes_count: app.likes_count || 0,
views_count: app.views_count || 0, views_count: app.views_count || 0,
rating: Math.round(avgRating * 10) / 10, // 四捨五入到小數點後一位 rating: Math.round(avgRating * 10) / 10, // 四捨五入到小數點後一位
creator_name: "未知作者", creator_name: app.creator_name || "未知作者",
creator_department: "未知部門", creator_department: app.creator_department || "未知部門",
team_name: team.name, team_name: team.name,
created_at: app.created_at created_at: app.created_at
}; };

View File

@@ -39,6 +39,11 @@ import {
Trophy, Trophy,
Award, Award,
Medal, Medal,
Bot,
Code,
Database,
Palette,
Volume2,
} from "lucide-react" } from "lucide-react"
import { FavoriteButton } from "./favorite-button" import { FavoriteButton } from "./favorite-button"
import { ReviewSystem } from "./reviews/review-system" import { ReviewSystem } from "./reviews/review-system"
@@ -48,15 +53,21 @@ interface AppDetailDialogProps {
open: boolean open: boolean
onOpenChange: (open: boolean) => void onOpenChange: (open: boolean) => void
app: { app: {
id: number id: string
name: string name: string
type: string type: string
department: string department: string
description: string description: string
icon: any icon: any
iconColor?: string
creator: string creator: string
featured: boolean featured: boolean
judgeScore: number judgeScore: number
likesCount?: number
viewsCount?: number
rating?: number
reviewsCount?: number
createdAt?: string
} }
} }
@@ -112,11 +123,17 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
// 圖標映射函數 // 圖標映射函數
const getIconComponent = (iconName: string) => { const getIconComponent = (iconName: string) => {
const iconMap: { [key: string]: any } = { const iconMap: { [key: string]: any } = {
'Bot': Brain, 'Brain': Brain,
'ImageIcon': ImageIcon, 'Bot': Bot,
'Code': Code,
'Database': Database,
'Palette': Palette,
'Volume2': Volume2,
'Search': Search,
'BarChart3': BarChart3,
'Mic': Mic, 'Mic': Mic,
'ImageIcon': ImageIcon,
'MessageSquare': MessageSquare, 'MessageSquare': MessageSquare,
'Settings': Settings,
'Zap': Zap, 'Zap': Zap,
'TrendingUp': TrendingUp, 'TrendingUp': TrendingUp,
'Star': Star, 'Star': Star,
@@ -128,21 +145,23 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
'Target': Target, 'Target': Target,
'Users': Users, 'Users': Users,
'Lightbulb': Lightbulb, 'Lightbulb': Lightbulb,
'Search': Search,
'Plus': Plus, 'Plus': Plus,
'X': X, 'X': X,
'ChevronLeft': ChevronLeft, 'ChevronLeft': ChevronLeft,
'ChevronRight': ChevronRight, 'ChevronRight': ChevronRight,
'ArrowLeft': ArrowLeft 'ArrowLeft': ArrowLeft,
'Settings': Settings
} }
return iconMap[iconName] || Brain // 預設使用 Brain 圖標 return iconMap[iconName] || Brain // 預設使用 Brain 圖標
} }
const IconComponent = getIconComponent(app.icon || 'Bot') const IconComponent = getIconComponent(app.icon || 'Bot')
const likes = (app as any).likesCount || 0 // 優先使用從 API 載入的實際數據,如果沒有則使用 app 對象的數據
const views = (app as any).viewsCount || 0 const likes = appStats.basic?.likes || (app as any).likesCount || 0
const rating = (app as any).rating || 0 const views = appStats.basic?.views || (app as any).viewsCount || 0
const reviewsCount = (app as any).reviewsCount || 0 const rating = appStats.basic?.rating || (app as any).rating || 0
const reviewsCount = appStats.basic?.reviewCount || (app as any).reviewsCount || 0
const favorites = appStats.basic?.favorites || 0
// 使用從 API 載入的實際數據 // 使用從 API 載入的實際數據
const usageStats = appStats.usage const usageStats = appStats.usage
@@ -169,13 +188,27 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
if (department) params.append('department', department) if (department) params.append('department', department)
const url = `/api/apps/${app.id}/stats${params.toString() ? `?${params.toString()}` : ''}` const url = `/api/apps/${app.id}/stats${params.toString() ? `?${params.toString()}` : ''}`
console.log('🔍 調用統計 API:', url)
console.log('🔍 應用 ID:', app.id)
const response = await fetch(url) const response = await fetch(url)
console.log('🔍 API 響應狀態:', response.status, response.statusText)
if (!response.ok) {
console.error('❌ API 響應錯誤:', response.status, response.statusText)
return
}
const data = await response.json() const data = await response.json()
console.log('🔍 API 響應數據:', data)
if (data.success) { if (data.success) {
console.log('📊 應用統計數據加載成功:', data.data)
setAppStats(data.data) setAppStats(data.data)
setCurrentRating(data.data.basic.rating) setCurrentRating(data.data.basic.rating)
setReviewCount(data.data.basic.reviewCount) setReviewCount(data.data.basic.reviewCount)
} else {
console.error('❌ 應用統計數據加載失敗:', data)
} }
} catch (error) { } catch (error) {
console.error('載入應用統計數據錯誤:', error) console.error('載入應用統計數據錯誤:', error)
@@ -489,7 +522,7 @@ export function AppDetailDialog({ open, onOpenChange, app }: AppDetailDialogProp
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold text-purple-600"> <div className="text-2xl font-bold text-purple-600">
{isLoadingStats ? '...' : (appStats.basic as any).favorites || 0} {isLoadingStats ? '...' : favorites}
</div> </div>
<p className="text-xs text-muted-foreground"></p> <p className="text-xs text-muted-foreground"></p>
</CardContent> </CardContent>

View File

@@ -70,16 +70,19 @@ const getAppDetails = (appId: string, team: any) => {
type: appDetail.type || "未知類型", type: appDetail.type || "未知類型",
description: appDetail.description || "無描述", description: appDetail.description || "無描述",
icon: getIconComponent(appDetail.icon) || Brain, icon: getIconComponent(appDetail.icon) || Brain,
iconColor: appDetail.icon_color || "from-blue-500 to-purple-500",
fullDescription: appDetail.description || "無描述", fullDescription: appDetail.description || "無描述",
features: [], features: [],
author: appDetail.creator_name || "未知作者", author: appDetail.creator_name || "未知作者",
department: appDetail.creator_department || "未知部門",
category: appDetail.category || "未分類", category: appDetail.category || "未分類",
tags: [], tags: [],
demoUrl: "", demoUrl: "",
sourceUrl: "", sourceUrl: "",
likes: appDetail.likes_count || 0, likes: appDetail.likes_count || 0,
views: appDetail.views_count || 0, views: appDetail.views_count || 0,
rating: Number(appDetail.rating) || 0 rating: Number(appDetail.rating) || 0,
createdAt: appDetail.created_at
}; };
} }
@@ -126,17 +129,22 @@ export function TeamDetailDialog({ open, onOpenChange, team }: TeamDetailDialogP
const appDetails = getAppDetails(appId, team) const appDetails = getAppDetails(appId, team)
// Create app object that matches AppDetailDialog interface // Create app object that matches AppDetailDialog interface
const app = { const app = {
id: Number.parseInt(appId), id: appId, // 保持為字符串API 期望字符串 ID
name: appDetails.name, name: appDetails.name,
type: appDetails.type, type: appDetails.type,
department: team.department, // Use team's department department: appDetails.department, // Use app's creator department
description: appDetails.description, description: appDetails.description,
icon: appDetails.icon, icon: appDetails.icon,
iconColor: appDetails.iconColor, // Pass icon color
creator: appDetails.author, creator: appDetails.author,
featured: false, featured: false,
judgeScore: appDetails.rating || 0, judgeScore: appDetails.rating || 0,
likes: appDetails.likes || 0, // 使用 AppDetailDialog 期望的屬性名
views: appDetails.views || 0, likesCount: appDetails.likes || 0,
viewsCount: appDetails.views || 0,
rating: appDetails.rating || 0,
reviewsCount: 0, // 可以從 API 獲取,暫時設為 0
createdAt: appDetails.createdAt, // Pass creation date
} }
setSelectedApp(app) setSelectedApp(app)
setAppDetailOpen(true) setAppDetailOpen(true)

View File

@@ -1151,10 +1151,14 @@ export class TeamService {
static async getTeamApps(teamId: string): Promise<any[]> { static async getTeamApps(teamId: string): Promise<any[]> {
console.log('🔍 TeamService.getTeamApps 被調用, teamId:', teamId); console.log('🔍 TeamService.getTeamApps 被調用, teamId:', teamId);
const sql = ` const sql = `
SELECT id, name, description, category, type, icon, icon_color, app_url, likes_count, views_count, rating SELECT
FROM apps a.id, a.name, a.description, a.category, a.type, a.icon, a.icon_color,
WHERE team_id = ? AND is_active = TRUE a.app_url, a.likes_count, a.views_count, a.rating, a.created_at,
ORDER BY created_at DESC u.name as creator_name, u.department as creator_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
WHERE a.team_id = ? AND a.is_active = TRUE
ORDER BY a.created_at DESC
`; `;
console.log('📝 getTeamApps SQL:', sql); console.log('📝 getTeamApps SQL:', sql);
console.log('📝 getTeamApps 參數:', [teamId]); console.log('📝 getTeamApps 參數:', [teamId]);