From ea17bd0ca2c230d521e9883f60f35571adcea916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B3=E4=BD=A9=E5=BA=AD?= Date: Fri, 19 Sep 2025 03:12:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=82=80=E8=AB=8B=E7=A2=BC?= =?UTF-8?q?=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++++- components/admin/competition-management.tsx | 3 +- components/admin/scoring-link-dialog.tsx | 5 +-- components/admin/user-management.tsx | 5 +-- lib/services/database-service.ts | 2 +- scripts/test-invitation-link.js | 47 +++++++++++++++++++++ 6 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 scripts/test-invitation-link.js diff --git a/README.md b/README.md index 597a9a1..8b1e000 100644 --- a/README.md +++ b/README.md @@ -71,13 +71,23 @@ pnpm install cp env.example .env.local ``` -編輯 `.env.local` 文件,填入您的數據庫配置: +編輯 `.env.local` 文件,填入您的配置: ```env +# 數據庫配置 DB_HOST=your-database-host DB_PORT=3306 DB_USER=your-username DB_PASSWORD=your-password DB_NAME=your-database-name + +# 應用配置 +NEXT_PUBLIC_APP_URL=https://your-domain.com +NEXT_PUBLIC_APP_NAME=強茂集團 AI 展示平台 +NEXT_PUBLIC_APP_DESCRIPTION=企業內部 AI 應用展示與競賽管理系統 + +# JWT 配置 +JWT_SECRET=your-jwt-secret +JWT_EXPIRES_IN=7d ``` ### 4. 數據庫設置 diff --git a/components/admin/competition-management.tsx b/components/admin/competition-management.tsx index 16a838d..2f299a7 100644 --- a/components/admin/competition-management.tsx +++ b/components/admin/competition-management.tsx @@ -2336,7 +2336,8 @@ export function CompetitionManagement() { }) } - const judgeScoringUrl = typeof window !== "undefined" ? `${window.location.origin}/judge-scoring` : "/judge-scoring" + const baseUrl = process.env.NEXT_PUBLIC_APP_URL || (typeof window !== "undefined" ? window.location.origin : 'http://localhost:3000') + const judgeScoringUrl = `${baseUrl}/judge-scoring` // Filter out proposal competitions from display const displayCompetitions = competitions.filter((competition) => competition.type !== "proposal") diff --git a/components/admin/scoring-link-dialog.tsx b/components/admin/scoring-link-dialog.tsx index c9fd242..2628ff4 100644 --- a/components/admin/scoring-link-dialog.tsx +++ b/components/admin/scoring-link-dialog.tsx @@ -20,9 +20,8 @@ export function ScoringLinkDialog({ open, onOpenChange, currentCompetition }: Sc const { toast } = useToast() // 生成評分連結URL - const scoringUrl = typeof window !== 'undefined' - ? `${window.location.origin}/judge-scoring` - : "https://preview-fork-of-ai-app-design-ieqe9ld0z64vdugqt.vusercontent.net/judge-scoring" + const baseUrl = process.env.NEXT_PUBLIC_APP_URL || (typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000') + const scoringUrl = `${baseUrl}/judge-scoring` const accessCode = "judge2024" const competitionName = currentCompetition?.name || "2024年第四季綜合AI競賽" diff --git a/components/admin/user-management.tsx b/components/admin/user-management.tsx index d0a50db..f7560f5 100644 --- a/components/admin/user-management.tsx +++ b/components/admin/user-management.tsx @@ -457,9 +457,8 @@ export function UserManagement() { const newToken = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) const user = users.find((u) => u.id === userId) const role = (user as any)?.invitedRole || "user" - const newInvitationLink = isClient - ? `${window.location.origin}/register?token=${newToken}&email=${encodeURIComponent(email)}&role=${role}` - : `/register?token=${newToken}&email=${encodeURIComponent(email)}&role=${role}` + const baseUrl = process.env.NEXT_PUBLIC_APP_URL || (isClient ? window.location.origin : 'http://localhost:3000') + const newInvitationLink = `${baseUrl}/register?token=${newToken}&email=${encodeURIComponent(email)}&role=${role}` setUsers( users.map((user) => diff --git a/lib/services/database-service.ts b/lib/services/database-service.ts index e1446d1..c0c26c8 100644 --- a/lib/services/database-service.ts +++ b/lib/services/database-service.ts @@ -511,7 +511,7 @@ export class UserService { } // 生成邀請連結 - const invitationLink = `${process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'}/register?token=${invitationToken}&email=${encodeURIComponent(email)}&role=${role}` + const invitationLink = `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/register?token=${invitationToken}&email=${encodeURIComponent(email)}&role=${role}` return { success: true, diff --git a/scripts/test-invitation-link.js b/scripts/test-invitation-link.js new file mode 100644 index 0000000..2cca5a1 --- /dev/null +++ b/scripts/test-invitation-link.js @@ -0,0 +1,47 @@ +// 測試邀請連結生成 +console.log('🧪 測試邀請連結生成...\n'); + +// 模擬環境變數 +process.env.NEXT_PUBLIC_APP_URL = 'https://ai-showcase.company.com'; + +// 測試不同的環境變數設置 +const testCases = [ + { + name: '使用 NEXT_PUBLIC_APP_URL', + env: { NEXT_PUBLIC_APP_URL: 'https://ai-showcase.company.com' } + }, + { + name: '未設置 NEXT_PUBLIC_APP_URL (使用 fallback)', + env: {} + }, + { + name: '設置為空字符串 (使用 fallback)', + env: { NEXT_PUBLIC_APP_URL: '' } + } +]; + +testCases.forEach((testCase, index) => { + console.log(`${index + 1}. ${testCase.name}`); + + // 設置環境變數 + Object.keys(testCase.env).forEach(key => { + process.env[key] = testCase.env[key]; + }); + + // 生成邀請連結 + const invitationToken = 'test123456789'; + const email = 'test@company.com'; + const role = 'developer'; + + const invitationLink = `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/register?token=${invitationToken}&email=${encodeURIComponent(email)}&role=${role}`; + + console.log(` 邀請連結: ${invitationLink}`); + console.log(` 環境變數: NEXT_PUBLIC_APP_URL = ${process.env.NEXT_PUBLIC_APP_URL || 'undefined'}`); + console.log(''); +}); + +console.log('✅ 測試完成!'); +console.log('\n📝 說明:'); +console.log('- 如果設置了 NEXT_PUBLIC_APP_URL,將使用該值'); +console.log('- 如果未設置或為空,將使用 fallback: http://localhost:3000'); +console.log('- 在生產環境中,請確保設置正確的 NEXT_PUBLIC_APP_URL');