diff --git a/app/api/admin/apps/[id]/route.ts b/app/api/admin/apps/[id]/route.ts
index 30628b0..44c1066 100644
--- a/app/api/admin/apps/[id]/route.ts
+++ b/app/api/admin/apps/[id]/route.ts
@@ -45,7 +45,7 @@ export async function PUT(request: NextRequest, { params }: { params: { id: stri
try {
const { id: appId } = await params
const body = await request.json()
- const { name, description, category, type, app_url, icon, icon_color } = body
+ const { name, description, category, type, app_url, icon, icon_color, department } = body
// 更新應用
const result = await appService.updateApp(appId, {
@@ -55,7 +55,8 @@ export async function PUT(request: NextRequest, { params }: { params: { id: stri
type,
app_url,
icon,
- icon_color
+ icon_color,
+ department
})
if (result.success) {
diff --git a/app/api/admin/judges/[id]/route.ts b/app/api/admin/judges/[id]/route.ts
index db07d4f..d2ec25c 100644
--- a/app/api/admin/judges/[id]/route.ts
+++ b/app/api/admin/judges/[id]/route.ts
@@ -107,7 +107,7 @@ export async function PUT(request: NextRequest, { params }: { params: { id: stri
if (body.is_active !== undefined) updateData.is_active = body.is_active;
// 執行更新
- const success = await judgeservice.updateJudge(id, updateData);
+ const success = await JudgeService.updateJudge(id, updateData);
if (!success) {
return NextResponse.json({
diff --git a/app/api/competitions/[id]/teams/route.ts b/app/api/competitions/[id]/teams/route.ts
index 8be8165..4001257 100644
--- a/app/api/competitions/[id]/teams/route.ts
+++ b/app/api/competitions/[id]/teams/route.ts
@@ -135,10 +135,12 @@ export async function GET(request: NextRequest, { params }: { params: { id: stri
}
}
- // 強制將第一個成員設為隊長(因為隊長邏輯有問題)
- if (allMembers.length > 0) {
- allMembers[0].role = '隊長';
- }
+ // 確保其他成員的角色正確設置
+ allMembers.forEach(member => {
+ if (member.user_id !== team.leader_id && member.role !== '隊長') {
+ member.role = '成員';
+ }
+ });
return {
...team,
@@ -220,7 +222,9 @@ export async function GET(request: NextRequest, { params }: { params: { id: stri
id: member.id,
user_id: member.user_id,
name: member.name,
- role: member.role === '??????' ? '成員' : (member.role || '成員')
+ department: member.department,
+ email: member.email,
+ role: member.role || '成員'
})),
apps: team.apps.map(app => ({
id: app.id,
diff --git a/components/admin/app-management.tsx b/components/admin/app-management.tsx
index 80a9874..181ecab 100644
--- a/components/admin/app-management.tsx
+++ b/components/admin/app-management.tsx
@@ -517,7 +517,8 @@ export function AppManagement() {
type: newApp.type,
app_url: newApp.appUrl,
icon: newApp.icon,
- icon_color: newApp.iconColor
+ icon_color: newApp.iconColor,
+ department: newApp.department
})
})
diff --git a/components/admin/competition-management.tsx b/components/admin/competition-management.tsx
index e30e061..b2107aa 100644
--- a/components/admin/competition-management.tsx
+++ b/components/admin/competition-management.tsx
@@ -563,7 +563,13 @@ export function CompetitionManagement() {
contactEmail: teamDetails.contact_email || '',
leaderPhone: teamDetails.leader_phone || '',
description: teamDetails.description || '',
- members: teamDetails.members || [],
+ members: (teamDetails.members || []).map((member: any) => ({
+ id: member.user_id || member.id,
+ user_id: member.user_id || member.id,
+ name: member.name,
+ department: member.department,
+ role: member.role || '成員'
+ })),
apps: teamDetails.apps ? teamDetails.apps.map((app: any) => app.id || app) : [],
submittedAppCount: teamDetails.apps?.length || 0,
}
@@ -1142,7 +1148,7 @@ export function CompetitionManagement() {
contact_email: newTeam.contactEmail,
description: newTeam.description,
members: newTeam.members.map(member => ({
- user_id: member.id, // 現在 member.id 就是 user_id
+ user_id: member.user_id || member.id, // 確保使用正確的 user_id
role: member.role || 'member'
})),
apps: newTeam.apps // 添加應用 ID 列表
@@ -1164,7 +1170,7 @@ export function CompetitionManagement() {
contact_email: newTeam.contactEmail,
description: newTeam.description,
members: newTeam.members.map(member => ({
- user_id: member.id, // 現在 member.id 就是 user_id
+ user_id: member.user_id || member.id, // 確保使用正確的 user_id
role: member.role || 'member'
})),
apps: newTeam.apps // 添加應用 ID 列表
@@ -2136,6 +2142,19 @@ export function CompetitionManagement() {
}
}
+ const getCompetitionTypeColor = (type: string) => {
+ switch (type) {
+ case "individual":
+ return "bg-blue-100 text-blue-800 border-blue-200"
+ case "team":
+ return "bg-purple-100 text-purple-800 border-purple-200"
+ case "mixed":
+ return "bg-orange-100 text-orange-800 border-orange-200"
+ default:
+ return "bg-gray-100 text-gray-800 border-gray-200"
+ }
+ }
+
const getScoreLabelText = (key: string) => {
switch (key) {
case "innovation":
@@ -2464,13 +2483,13 @@ export function CompetitionManagement() {
- 競賽名稱
- 類型
- 時間
- 狀態
- 參賽項目
- 評分進度
- 操作
+ 競賽名稱
+ 類型
+ 時間
+ 狀態
+ 參賽項目
+ 評分進度
+ 操作
@@ -2506,9 +2525,9 @@ export function CompetitionManagement() {
-
+
{getCompetitionTypeIcon(competition.type)}
-
+
{getCompetitionTypeText(competition.type)}
@@ -2527,34 +2546,37 @@ export function CompetitionManagement() {
-
- {getStatusText(competition.status)}
-
-
-
-
- {getCompetitionTypeIcon(competition.type)}
-
{participantCount} 個
+
+
+ {getStatusText(competition.status)}
+
-
+
+ {getCompetitionTypeIcon(competition.type)}
+ {participantCount} 個
+
+
+
+
-
+
{scoringProgress.completed}/{scoringProgress.total}
-
{scoringProgress.percentage}% 完成
+
{scoringProgress.percentage}% 完成
-
-
-
-
+
+
+
+
+
handleViewCompetition(competition)}>
@@ -2598,7 +2620,8 @@ export function CompetitionManagement() {
刪除競賽
-
+
+
)
@@ -2771,7 +2794,7 @@ export function CompetitionManagement() {
- {team.submittedAppCount} 個應用
+ {team.app_count || 0} 個應用
@@ -6603,7 +6626,7 @@ export function CompetitionManagement() {
{member.name}
- {member.user_id === selectedTeam.leader_id && (
+ {member.role === '隊長' && (
隊長
diff --git a/components/admin/team-management.tsx b/components/admin/team-management.tsx
index bab8be6..71a2330 100644
--- a/components/admin/team-management.tsx
+++ b/components/admin/team-management.tsx
@@ -1,6 +1,6 @@
"use client"
-import { useState } from "react"
+import { useState, useEffect } from "react"
import { useCompetition } from "@/contexts/competition-context"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
@@ -43,6 +43,10 @@ export function TeamManagement() {
const [isLoading, setIsLoading] = useState(false)
const [success, setSuccess] = useState("")
const [error, setError] = useState("")
+
+ // 從 API 獲取的團隊數據
+ const [apiTeams, setApiTeams] = useState
([])
+ const [isLoadingTeams, setIsLoadingTeams] = useState(true)
const [newTeam, setNewTeam] = useState({
name: "",
@@ -60,10 +64,35 @@ export function TeamManagement() {
role: "成員",
})
- const filteredTeams = teams.filter((team) => {
+ // 獲取團隊數據
+ const fetchTeams = async () => {
+ try {
+ setIsLoadingTeams(true)
+ const response = await fetch('/api/admin/teams')
+ const data = await response.json()
+
+ if (data.success) {
+ setApiTeams(data.data)
+ } else {
+ console.error('獲取團隊數據失敗:', data.message)
+ setError('獲取團隊數據失敗')
+ }
+ } catch (error) {
+ console.error('獲取團隊數據失敗:', error)
+ setError('獲取團隊數據失敗')
+ } finally {
+ setIsLoadingTeams(false)
+ }
+ }
+
+ useEffect(() => {
+ fetchTeams()
+ }, [])
+
+ const filteredTeams = apiTeams.filter((team) => {
const matchesSearch =
team.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
- team.members.some((member) => member.name.toLowerCase().includes(searchTerm.toLowerCase()))
+ team.leader_name?.toLowerCase().includes(searchTerm.toLowerCase())
const matchesDepartment = selectedDepartment === "all" || team.department === selectedDepartment
return matchesSearch && matchesDepartment
})
@@ -73,16 +102,29 @@ export function TeamManagement() {
setShowTeamDetail(true)
}
- const handleEditTeam = (team: Team) => {
+ const handleEditTeam = (team: any) => {
setSelectedTeam(team)
+
+ // 確保成員數據結構正確
+ const members = team.members && Array.isArray(team.members)
+ ? team.members.map((member: any) => ({
+ id: member.user_id || member.id,
+ user_id: member.user_id || member.id,
+ name: member.name,
+ department: member.department,
+ role: member.role || '成員'
+ }))
+ : []
+
setNewTeam({
name: team.name,
department: team.department,
- contactEmail: team.contactEmail,
- members: [...team.members],
- leader: team.leader,
- apps: [...team.apps],
- totalLikes: team.totalLikes,
+ contactEmail: team.contact_email || team.contactEmail,
+ description: team.description || '',
+ members: members,
+ leader: team.leader_id || team.leader,
+ apps: team.apps || [],
+ totalLikes: team.total_likes || team.totalLikes || 0,
})
setShowEditTeam(true)
}
@@ -205,14 +247,49 @@ export function TeamManagement() {
}
setIsLoading(true)
- await new Promise((resolve) => setTimeout(resolve, 1000))
- updateTeam(selectedTeam.id, newTeam)
- setShowEditTeam(false)
- setSelectedTeam(null)
- setSuccess("團隊更新成功!")
- setIsLoading(false)
- setTimeout(() => setSuccess(""), 3000)
+ try {
+ // 準備更新數據
+ const updateData = {
+ name: newTeam.name,
+ department: newTeam.department,
+ contact_email: newTeam.contactEmail,
+ description: newTeam.description || null,
+ leader_id: newTeam.leader,
+ members: newTeam.members.map(member => ({
+ user_id: member.user_id || member.id,
+ role: member.role
+ }))
+ }
+
+ // 調用 API 更新團隊
+ const response = await fetch(`/api/admin/teams/${selectedTeam.id}`, {
+ method: 'PUT',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(updateData)
+ })
+
+ const data = await response.json()
+
+ if (data.success) {
+ // 更新成功,重新載入團隊數據
+ await fetchTeams()
+ setShowEditTeam(false)
+ setSelectedTeam(null)
+ setSuccess("團隊更新成功!")
+ } else {
+ setError(data.message || "更新團隊失敗")
+ }
+ } catch (error) {
+ console.error('更新團隊失敗:', error)
+ setError("更新團隊失敗")
+ } finally {
+ setIsLoading(false)
+ setTimeout(() => setError(""), 3000)
+ setTimeout(() => setSuccess(""), 3000)
+ }
}
return (
@@ -254,7 +331,7 @@ export function TeamManagement() {
總團隊數
-
{teams.length}
+
{apiTeams.length}
@@ -266,7 +343,7 @@ export function TeamManagement() {
總成員數
-
{teams.reduce((sum, team) => sum + team.members.length, 0)}
+
{apiTeams.reduce((sum, team) => sum + (team.member_count || 0), 0)}
@@ -279,8 +356,8 @@ export function TeamManagement() {
平均團隊規模
- {teams.length > 0
- ? Math.round((teams.reduce((sum, team) => sum + team.members.length, 0) / teams.length) * 10) / 10
+ {apiTeams.length > 0
+ ? Math.round((apiTeams.reduce((sum, team) => sum + (team.member_count || 0), 0) / apiTeams.length) * 10) / 10
: 0}
@@ -352,8 +429,6 @@ export function TeamManagement() {
{filteredTeams.map((team) => {
- const leader = team.members.find((m) => m.id === team.leader)
-
return (
@@ -363,7 +438,7 @@ export function TeamManagement() {
{team.name}
-
{team.contactEmail}
+
{team.contact_email}
@@ -371,10 +446,10 @@ export function TeamManagement() {
- {leader?.name[0] || "?"}
+ {team.leader_name?.[0] || "?"}
-
{leader?.name || "未設定"}
+
{team.leader_name || "未設定"}
@@ -385,11 +460,11 @@ export function TeamManagement() {
- {team.members.length}
+ {team.member_count || 0}
- {team.apps.length}
+ {team.app_count || 0}
{team.totalLikes}
@@ -807,16 +882,16 @@ export function TeamManagement() {
{selectedTeam.name}
-
{selectedTeam.contactEmail}
+
{selectedTeam.contact_email}
{selectedTeam.department}
- {selectedTeam.members.length} 名成員
+ {selectedTeam.member_count || 0} 名成員
- {selectedTeam.apps.length} 個應用
+ {selectedTeam.app_count || 0} 個應用
diff --git a/components/competition/competition-detail-dialog.tsx b/components/competition/competition-detail-dialog.tsx
index c9ca8d6..245463b 100644
--- a/components/competition/competition-detail-dialog.tsx
+++ b/components/competition/competition-detail-dialog.tsx
@@ -372,7 +372,7 @@ export function CompetitionDetailDialog({
@@ -383,7 +383,7 @@ export function CompetitionDetailDialog({
{member.name}
- {member.id === team.leader && (
+ {member.role === '隊長' && (
隊長
diff --git a/components/competition/popularity-rankings.tsx b/components/competition/popularity-rankings.tsx
index 594639d..dc38023 100644
--- a/components/competition/popularity-rankings.tsx
+++ b/components/competition/popularity-rankings.tsx
@@ -453,7 +453,7 @@ export function PopularityRankings() {
{currentTeams.map((team, index) => {
const globalRank = startIndex + index + 1
- const leader = team.members.find((m: any) => m.id === team.leader)
+ const leader = team.members.find((m: any) => m.role === '隊長')
return (
{team.name}
- 隊長:{leader?.name}
+ 隊長:{leader?.name || '未知隊長'}
團隊賽
@@ -496,7 +496,13 @@ export function PopularityRankings() {
{member.name[0]}
{member.name}
- ({member.role})
+
+ {member.role}
+
))}
{team.members.length > 3 && (
diff --git a/components/competition/team-detail-dialog.tsx b/components/competition/team-detail-dialog.tsx
index 117ec15..7527a72 100644
--- a/components/competition/team-detail-dialog.tsx
+++ b/components/competition/team-detail-dialog.tsx
@@ -71,7 +71,13 @@ const getIconComponent = (iconName: string) => {
// App data for team apps - get from team data
const getAppDetails = (appId: string, team: any) => {
- const appDetail = team.appsDetails?.find((app: any) => app.id === appId);
+ // 首先嘗試從 appsDetails 獲取
+ let appDetail = team.appsDetails?.find((app: any) => app.id === appId);
+
+ // 如果沒有找到,嘗試從 apps 獲取
+ if (!appDetail) {
+ appDetail = team.apps?.find((app: any) => app.id === appId);
+ }
if (appDetail) {
return {
@@ -311,7 +317,7 @@ export function TeamDetailDialog({ open, onOpenChange, team }: TeamDetailDialogP
{member.name}
- {member.id === team.leader && (
+ {member.role === '隊長' && (
隊長
@@ -334,19 +340,36 @@ export function TeamDetailDialog({ open, onOpenChange, team }: TeamDetailDialogP
- {team.apps.map((appId: string) => {
- const app = getAppDetails(appId, team)
+ {team.apps.map((app: any) => {
+ // 如果 app 是字符串 ID,使用 getAppDetails 獲取詳情
+ // 如果 app 是對象,直接使用
+ const appData = typeof app === 'string' ? getAppDetails(app, team) : {
+ id: app.id,
+ name: app.name || "未命名應用",
+ type: app.type || "未知類型",
+ description: app.description || "無描述",
+ icon: getIconComponent(app.icon) || Brain,
+ iconColor: app.icon_color || "from-blue-500 to-purple-500",
+ author: app.creator_name || "未知作者",
+ department: app.creator_department || "未知部門",
+ category: app.category || "未分類",
+ likes: app.likes_count || 0,
+ views: app.views_count || 0,
+ rating: Number(app.rating) || 0,
+ createdAt: app.created_at
+ }
+
// 如果沒有圖標,使用默認的 Brain 圖標
- const IconComponent = app.icon || Brain
- const likes = app.likes || 0
- const views = app.views || 0
- const rating = app.rating || 0
+ const IconComponent = appData.icon || Brain
+ const likes = appData.likes || 0
+ const views = appData.views || 0
+ const rating = appData.rating || 0
return (
handleAppClick(appId)}
+ onClick={() => handleAppClick(appData.id)}
>
@@ -356,16 +379,16 @@ export function TeamDetailDialog({ open, onOpenChange, team }: TeamDetailDialogP
- {app.name}
+ {appData.name}
-
- {app.type}
+
+ {appData.type}
- {app.description}
+ {appData.description}
@@ -379,7 +402,7 @@ export function TeamDetailDialog({ open, onOpenChange, team }: TeamDetailDialogP
e.stopPropagation()}>
0 ? results[0] : null;
@@ -1044,7 +1046,7 @@ export class TeamService extends DatabaseServiceBase {
u.phone as leader_phone
FROM teams t
LEFT JOIN users u ON t.leader_id = u.id
- WHERE t.name = ? AND t.is_active = TRUE
+ WHERE t.name = ? AND t.is_active = 1
`;
const results = await DatabaseServiceBase.safeQuery(sql, [name]);
return results.length > 0 ? results[0] : null;
@@ -1058,24 +1060,97 @@ export class TeamService extends DatabaseServiceBase {
contact_email: string;
description: string;
total_likes: number;
+ members?: Array<{
+ user_id: string;
+ role: string;
+ }>;
+ apps?: string[];
}>): Promise {
- const fields = Object.keys(updates).filter(key => key !== 'id' && key !== 'created_at');
-
- if (fields.length === 0) {
- console.log('沒有字段需要更新');
- return true;
- }
-
- const setClause = fields.map(field => `${field} = ?`).join(', ');
- const values = fields.map(field => updates[field as keyof typeof updates]);
+ try {
+ // 更新團隊基本信息
+ const teamFields = Object.keys(updates).filter(key =>
+ key !== 'id' &&
+ key !== 'created_at' &&
+ key !== 'members' &&
+ key !== 'apps'
+ );
+
+ if (teamFields.length > 0) {
+ const setClause = teamFields.map(field => `${field} = ?`).join(', ');
+ const values = teamFields.map(field => updates[field as keyof typeof updates]);
values.push(id);
const sql = `UPDATE teams SET ${setClause}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`;
- try {
- const result = await DatabaseServiceBase.safeUpdate(sql, values);
- console.log('團隊更新結果:', result);
- return result.affectedRows > 0;
+ const result = await DatabaseServiceBase.safeUpdate(sql, values);
+ console.log('團隊基本信息更新結果:', result);
+
+ if (result.affectedRows === 0) {
+ console.log('團隊基本信息更新失敗');
+ return false;
+ }
+ }
+
+ // 更新團隊成員(如果提供了成員信息)
+ if (updates.members && Array.isArray(updates.members)) {
+ try {
+ // 先刪除現有成員
+ console.log('刪除現有團隊成員...');
+ await DatabaseServiceBase.safeDelete('DELETE FROM team_members WHERE team_id = ?', [id]);
+
+ // 添加新成員(如果成員列表不為空)
+ if (updates.members.length > 0) {
+ console.log('添加新團隊成員...');
+ for (const member of updates.members) {
+ if (member.user_id && member.role) {
+ console.log(`添加成員: ${member.user_id} (${member.role})`);
+ await DatabaseServiceBase.safeInsert(
+ 'INSERT INTO team_members (team_id, user_id, role, joined_at) VALUES (?, ?, ?, NOW())',
+ [id, member.user_id, member.role]
+ );
+ }
+ }
+ console.log('團隊成員更新完成');
+ } else {
+ console.log('成員列表為空,只刪除現有成員');
+ }
+ } catch (memberError) {
+ console.error('更新團隊成員時發生錯誤:', memberError);
+ // 成員更新失敗不應該影響整個更新操作
+ // 可以選擇繼續或回滾
+ }
+ }
+
+ // 更新團隊應用(如果提供了應用信息)
+ if (updates.apps && Array.isArray(updates.apps)) {
+ try {
+ // 先移除現有應用的團隊關聯
+ console.log('移除現有應用的團隊關聯...');
+ await DatabaseServiceBase.safeUpdate('UPDATE apps SET team_id = NULL WHERE team_id = ?', [id]);
+
+ // 添加新應用的團隊關聯(如果應用列表不為空)
+ if (updates.apps.length > 0) {
+ console.log('添加新應用的團隊關聯...');
+ for (const appId of updates.apps) {
+ if (appId) {
+ console.log(`關聯應用: ${appId}`);
+ await DatabaseServiceBase.safeUpdate(
+ 'UPDATE apps SET team_id = ? WHERE id = ?',
+ [id, appId]
+ );
+ }
+ }
+ console.log('團隊應用更新完成');
+ } else {
+ console.log('應用列表為空,只移除現有關聯');
+ }
+ } catch (appError) {
+ console.error('更新團隊應用時發生錯誤:', appError);
+ // 應用更新失敗不應該影響整個更新操作
+ }
+ }
+
+ return true;
} catch (error) {
console.error('更新團隊錯誤:', error);
return false;
@@ -1165,7 +1240,7 @@ export class TeamService extends DatabaseServiceBase {
// 綁定應用到團隊
static async bindAppToTeam(teamId: string, appId: string): Promise {
try {
- const sql = 'UPDATE apps SET team_id = ? WHERE id = ? AND is_active = TRUE';
+ const sql = 'UPDATE apps SET team_id = ? WHERE id = ? AND is_active = 1';
const result = await DatabaseServiceBase.safeUpdate(sql, [teamId, appId]);
return result.affectedRows > 0;
} catch (error) {
@@ -1196,7 +1271,7 @@ export class TeamService extends DatabaseServiceBase {
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
+ WHERE a.team_id = ? AND a.is_active = 1
ORDER BY a.created_at DESC
`;
console.log('📝 getTeamApps SQL:', sql);
@@ -1211,7 +1286,7 @@ export class TeamService extends DatabaseServiceBase {
const sql = `
SELECT
COUNT(*) as totalTeams,
- COUNT(CASE WHEN is_active = TRUE THEN 1 END) as activeTeams,
+ COUNT(CASE WHEN is_active = 1 THEN 1 END) as activeTeams,
COUNT(CASE WHEN is_active = FALSE THEN 1 END) as inactiveTeams,
AVG(member_count) as avgMembersPerTeam
FROM (
@@ -1278,7 +1353,7 @@ export class CompetitionService extends DatabaseServiceBase {
// 根據名稱獲取競賽
static async getCompetitionByName(name: string): Promise {
- const sql = 'SELECT * FROM competitions WHERE name = ? AND is_active = TRUE';
+ const sql = 'SELECT * FROM competitions WHERE name = ? AND is_active = 1';
return await db.queryOne(sql, [name]);
}
@@ -1313,7 +1388,7 @@ export class CompetitionService extends DatabaseServiceBase {
// 獲取所有競賽
static async getAllCompetitions(): Promise {
- const sql = 'SELECT * FROM competitions WHERE is_active = TRUE ORDER BY year DESC, month DESC';
+ const sql = 'SELECT * FROM competitions WHERE is_active = 1 ORDER BY year DESC, month DESC';
const competitions = await db.query(sql);
// 轉換字段名稱以匹配前端期望的格式
@@ -1365,7 +1440,7 @@ export class CompetitionService extends DatabaseServiceBase {
// 獲取當前競賽
static async getCurrentCompetition(): Promise {
try {
- const sql = 'SELECT * FROM competitions WHERE is_current = TRUE AND is_active = TRUE LIMIT 1';
+ const sql = 'SELECT * FROM competitions WHERE is_current = 1 AND is_active = 1 LIMIT 1';
const competitions = await db.query(sql);
if (competitions.length > 0) {
@@ -1485,7 +1560,7 @@ export class CompetitionService extends DatabaseServiceBase {
SELECT j.*, cj.assigned_at
FROM competition_judges cj
JOIN judges j ON cj.judge_id = j.id
- WHERE cj.competition_id = ? AND j.is_active = TRUE
+ WHERE cj.competition_id = ? AND j.is_active = 1
ORDER BY cj.assigned_at ASC
`;
return await DatabaseServiceBase.safeQuery(sql, [competitionId]);
@@ -1546,7 +1621,7 @@ export class CompetitionService extends DatabaseServiceBase {
FROM competition_teams ct
JOIN teams t ON ct.team_id = t.id
LEFT JOIN users u ON t.leader_id = u.id
- WHERE ct.competition_id = ? AND t.is_active = TRUE
+ WHERE ct.competition_id = ? AND t.is_active = 1
ORDER BY ct.registered_at ASC
`;
return await DatabaseServiceBase.safeQuery(sql, [competitionId]);
@@ -1577,7 +1652,7 @@ export class CompetitionService extends DatabaseServiceBase {
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
LEFT JOIN teams t ON a.team_id = t.id
- WHERE a.team_id IN (${placeholders}) AND a.is_active = TRUE
+ WHERE a.team_id IN (${placeholders}) AND a.is_active = 1
ORDER BY a.created_at ASC
`;
apps = await DatabaseServiceBase.safeQuery(sql, teamIds);
@@ -1590,7 +1665,7 @@ export class CompetitionService extends DatabaseServiceBase {
FROM competition_apps ca
JOIN apps a ON ca.app_id = a.id
LEFT JOIN users u ON a.creator_id = u.id
- WHERE ca.competition_id = ? AND a.is_active = TRUE
+ WHERE ca.competition_id = ? AND a.is_active = 1
ORDER BY ca.submitted_at ASC
`;
apps = await DatabaseServiceBase.safeQuery(sql, [competitionId]);
@@ -1934,7 +2009,7 @@ export class AppService extends DatabaseServiceBase {
u.department as creator_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
- WHERE a.id = ? AND a.is_active = TRUE
+ WHERE a.id = ? AND a.is_active = 1
`;
return await this.queryOne(sql, [appId]);
}
@@ -1962,7 +2037,7 @@ export class AppService extends DatabaseServiceBase {
u.department as creator_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
- WHERE a.name = ? AND a.is_active = TRUE
+ WHERE a.name = ? AND a.is_active = 1
`;
return await this.queryOne(sql, [name]);
}
@@ -1986,7 +2061,7 @@ export class AppService extends DatabaseServiceBase {
// 根據狀態篩選
if (status && status !== 'all') {
if (status === 'active') {
- whereConditions.push('a.is_active = TRUE');
+ whereConditions.push('a.is_active = 1');
} else if (status === 'inactive') {
whereConditions.push('a.is_active = FALSE');
}
@@ -2058,6 +2133,7 @@ export class AppService extends DatabaseServiceBase {
app_url?: string;
icon?: string;
icon_color?: string;
+ department?: string;
}): Promise<{ success: boolean; app?: any; error?: string }> {
try {
const updateFields = [];
@@ -2092,20 +2168,41 @@ export class AppService extends DatabaseServiceBase {
params.push(updates.icon_color);
}
- if (updateFields.length === 0) {
+ // 如果沒有要更新的欄位,檢查是否需要更新部門
+ if (updateFields.length === 0 && !updates.department) {
return { success: false, error: '沒有要更新的欄位' };
}
+ // 如果需要更新部門,先更新創建者的部門
+ if (updates.department) {
+ // 先獲取應用的創建者 ID
+ const appSql = 'SELECT creator_id FROM apps WHERE id = ? AND is_active = 1';
+ const appResult = await this.query(appSql, [appId]);
+
+ if (appResult.length === 0) {
+ return { success: false, error: '應用不存在' };
+ }
+
+ const creatorId = appResult[0].creator_id;
+
+ // 更新創建者的部門
+ const userUpdateSql = 'UPDATE users SET department = ? WHERE id = ?';
+ await this.query(userUpdateSql, [updates.department, creatorId]);
+ }
+
+ // 如果有其他欄位需要更新
+ if (updateFields.length > 0) {
updateFields.push('updated_at = NOW()');
params.push(appId);
const sql = `
UPDATE apps
SET ${updateFields.join(', ')}
- WHERE id = ? AND is_active = TRUE
+ WHERE id = ? AND is_active = 1
`;
await this.query(sql, params);
+ }
// 獲取更新後的應用
const updatedApp = await this.getAppById(appId);
@@ -2173,7 +2270,7 @@ export class AppService extends DatabaseServiceBase {
const sql = `
SELECT
COUNT(*) as total_apps,
- COUNT(CASE WHEN is_active = TRUE THEN 1 END) as active_apps,
+ COUNT(CASE WHEN is_active = 1 THEN 1 END) as active_apps,
COUNT(CASE WHEN is_active = FALSE THEN 1 END) as inactive_apps,
COALESCE(SUM(views_count), 0) as total_views,
COALESCE(SUM(likes_count), 0) as total_likes,
@@ -2605,7 +2702,7 @@ export class AppService extends DatabaseServiceBase {
COUNT(DISTINCT a.id) as count
FROM apps a
JOIN users u ON a.creator_id = u.id
- WHERE a.is_active = TRUE
+ WHERE a.is_active = 1
GROUP BY u.department
ORDER BY count DESC, u.department ASC
`;
@@ -2629,7 +2726,7 @@ export class AppService extends DatabaseServiceBase {
type,
COUNT(*) as count
FROM apps
- WHERE is_active = TRUE
+ WHERE is_active = 1
GROUP BY type
ORDER BY count DESC, type ASC
`;
@@ -2653,7 +2750,7 @@ export class AppService extends DatabaseServiceBase {
category,
COUNT(*) as count
FROM apps
- WHERE is_active = TRUE
+ WHERE is_active = 1
GROUP BY category
ORDER BY count DESC, category ASC
`;
@@ -2847,7 +2944,7 @@ export class AppService extends DatabaseServiceBase {
const appStatsSql = `
SELECT
COUNT(*) as total_apps,
- COUNT(CASE WHEN is_active = TRUE THEN 1 END) as active_apps,
+ COUNT(CASE WHEN is_active = 1 THEN 1 END) as active_apps,
COUNT(CASE WHEN is_active = FALSE THEN 1 END) as inactive_apps,
COUNT(CASE WHEN created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) THEN 1 END) as new_apps_this_month,
COALESCE(SUM(views_count), 0) as total_views,
@@ -2997,7 +3094,7 @@ export class AppService extends DatabaseServiceBase {
SELECT COUNT(*) as total
FROM user_favorites uf
JOIN apps a ON uf.app_id = a.id
- WHERE uf.user_id = ? AND a.is_active = TRUE
+ WHERE uf.user_id = ? AND a.is_active = 1
`;
const countResult = await this.queryOne(countSql, [userId]);
const total = countResult?.total || 0;
@@ -3022,7 +3119,7 @@ export class AppService extends DatabaseServiceBase {
FROM user_favorites uf
JOIN apps a ON uf.app_id = a.id
LEFT JOIN users u ON a.creator_id = u.id
- WHERE uf.user_id = ? AND a.is_active = TRUE
+ WHERE uf.user_id = ? AND a.is_active = 1
ORDER BY uf.created_at DESC
LIMIT ${limit} OFFSET ${offset}
`;
@@ -3334,7 +3431,7 @@ export class AppService extends DatabaseServiceBase {
for (const activity of activities) {
try {
// 嘗試從應用表獲取類別
- const appSql = 'SELECT type FROM apps WHERE id = ? AND is_active = TRUE';
+ const appSql = 'SELECT type FROM apps WHERE id = ? AND is_active = 1';
const appResult = await this.query(appSql, [activity.resource_id]);
let category = '未分類';
diff --git a/scripts/manual-insert-virtual-apps.sql b/scripts/manual-insert-virtual-apps.sql
index 2cce547..92d3e0b 100644
--- a/scripts/manual-insert-virtual-apps.sql
+++ b/scripts/manual-insert-virtual-apps.sql
@@ -3,7 +3,7 @@
-- =====================================================
-- 首先查看現有的團隊數據
-SELECT id, name FROM teams WHERE is_active = TRUE;
+SELECT id, name FROM teams WHERE is_active = 1;
-- 為每個團隊創建對應的虛擬應用記錄
-- 格式:team_{teamId} 以便識別這是團隊評分
@@ -38,7 +38,7 @@ INSERT INTO apps (
0,
0,
0.00,
- TRUE,
+ 1,
NOW(),
NOW()
);