刪除不必要檔案

This commit is contained in:
2025-09-09 15:19:04 +08:00
parent 46bd9db2e3
commit 3369e3fc0f
86 changed files with 198 additions and 11011 deletions

View File

@@ -1,67 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function addMissingAppColumns() {
let connection;
try {
console.log('🔧 開始添加缺失的 apps 表格欄位...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查並添加新欄位
const alterStatements = [
// 添加部門欄位
`ALTER TABLE apps ADD COLUMN department VARCHAR(100) DEFAULT 'HQBU'`,
// 添加創建者名稱欄位
`ALTER TABLE apps ADD COLUMN creator_name VARCHAR(100)`,
// 添加創建者郵箱欄位
`ALTER TABLE apps ADD COLUMN creator_email VARCHAR(255)`
];
for (const statement of alterStatements) {
try {
await connection.execute(statement);
console.log(`✅ 執行: ${statement.substring(0, 50)}...`);
} catch (error) {
if (error.code === 'ER_DUP_FIELDNAME') {
console.log(`⚠️ 欄位已存在,跳過: ${statement.substring(0, 50)}...`);
} else {
console.error(`❌ 執行失敗: ${statement.substring(0, 50)}...`, error.message);
}
}
}
// 檢查表格結構
const [columns] = await connection.execute('DESCRIBE apps');
console.log('\n📋 apps 表格結構:');
columns.forEach(col => {
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
});
console.log('\n✅ apps 表格欄位添加完成!');
} catch (error) {
console.error('❌ 添加 apps 表格欄位失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行添加
addMissingAppColumns().catch(console.error);

View File

@@ -1,104 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function checkActualCreatorData() {
let connection;
try {
console.log('🔍 檢查實際的創建者資料...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查應用程式的創建者資訊
const [apps] = await connection.execute(`
SELECT
a.id,
a.name,
a.creator_id,
a.department as app_department,
a.creator_name as app_creator_name,
u.id as user_id,
u.name as user_name,
u.email as user_email,
u.department as user_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC
LIMIT 5
`);
console.log('\n📊 應用程式和創建者資料:');
apps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` 應用 ID: ${app.id}`);
console.log(` 應用名稱: ${app.name}`);
console.log(` 創建者 ID: ${app.creator_id}`);
console.log(` 應用部門: ${app.app_department}`);
console.log(` 應用創建者名稱: ${app.app_creator_name}`);
console.log(` 用戶 ID: ${app.user_id}`);
console.log(` 用戶名稱: ${app.user_name}`);
console.log(` 用戶郵箱: ${app.user_email}`);
console.log(` 用戶部門: ${app.user_department}`);
});
// 檢查用戶表中的資料
const [users] = await connection.execute(`
SELECT id, name, email, department, role
FROM users
ORDER BY created_at DESC
LIMIT 5
`);
console.log('\n📋 用戶表資料:');
users.forEach((user, index) => {
console.log(`\n用戶 ${index + 1}:`);
console.log(` ID: ${user.id}`);
console.log(` 名稱: ${user.name}`);
console.log(` 郵箱: ${user.email}`);
console.log(` 部門: ${user.department}`);
console.log(` 角色: ${user.role}`);
});
// 檢查是否有名為「佩庭」的用戶
const [peitingUsers] = await connection.execute(`
SELECT id, name, email, department, role
FROM users
WHERE name LIKE '%佩庭%'
`);
console.log('\n🔍 搜尋「佩庭」相關的用戶:');
if (peitingUsers.length > 0) {
peitingUsers.forEach((user, index) => {
console.log(`\n用戶 ${index + 1}:`);
console.log(` ID: ${user.id}`);
console.log(` 名稱: ${user.name}`);
console.log(` 郵箱: ${user.email}`);
console.log(` 部門: ${user.department}`);
console.log(` 角色: ${user.role}`);
});
} else {
console.log('❌ 沒有找到名為「佩庭」的用戶');
}
} catch (error) {
console.error('❌ 檢查創建者資料失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行檢查
checkActualCreatorData().catch(console.error);

View File

@@ -1,136 +0,0 @@
// Script to check app types in database
const mysql = require('mysql2/promise');
async function checkAppTypes() {
let connection;
try {
// Database connection
connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'ai_showcase_platform'
});
console.log('Connected to database successfully');
// Check what types exist in the apps table
const [rows] = await connection.execute('SELECT DISTINCT type FROM apps ORDER BY type');
console.log('=== App Types in Database ===');
console.log('Total unique types:', rows.length);
rows.forEach((row, index) => {
console.log(`${index + 1}. ${row.type}`);
});
// Check API valid types
const apiValidTypes = [
'web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model',
'data_analysis', 'automation', 'productivity', 'educational', 'healthcare',
'finance', 'iot_device', 'blockchain', 'ar_vr', 'machine_learning',
'computer_vision', 'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
];
console.log('\n=== API Valid Types ===');
apiValidTypes.forEach((type, index) => {
console.log(`${index + 1}. ${type}`);
});
// Check frontend mapping
const frontendTypes = [
'文字處理', '圖像生成', '圖像處理', '語音辨識', '推薦系統', '音樂生成',
'程式開發', '影像處理', '對話系統', '數據分析', '設計工具', '語音技術',
'教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR',
'機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'
];
console.log('\n=== Frontend Types ===');
frontendTypes.forEach((type, index) => {
console.log(`${index + 1}. ${type}`);
});
// Check mapping consistency
console.log('\n=== Mapping Analysis ===');
const mapTypeToApiType = (frontendType) => {
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
};
return typeMap[frontendType] || 'other';
};
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他'
};
return typeMap[apiType] || '其他';
};
// Test mapping for all frontend types
console.log('\n=== Frontend to API Mapping Test ===');
frontendTypes.forEach(frontendType => {
const apiType = mapTypeToApiType(frontendType);
const backToFrontend = mapApiTypeToDisplayType(apiType);
const isValidApiType = apiValidTypes.includes(apiType);
console.log(`${frontendType} -> ${apiType} -> ${backToFrontend} (Valid API: ${isValidApiType})`);
});
// Test mapping for all API types
console.log('\n=== API to Frontend Mapping Test ===');
apiValidTypes.forEach(apiType => {
const frontendType = mapApiTypeToDisplayType(apiType);
const backToApi = mapTypeToApiType(frontendType);
console.log(`${apiType} -> ${frontendType} -> ${backToApi}`);
});
} catch (error) {
console.error('Error:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
checkAppTypes();

View File

@@ -1,99 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function checkLatestAppData() {
let connection;
try {
console.log('🔍 檢查最新的應用程式資料...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查最新的應用程式資料
const [apps] = await connection.execute(`
SELECT
a.id,
a.name,
a.description,
a.creator_id,
a.department as app_department,
a.creator_name as app_creator_name,
a.creator_email as app_creator_email,
a.type,
a.status,
a.created_at,
u.id as user_id,
u.name as user_name,
u.email as user_email,
u.department as user_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC
LIMIT 5
`);
console.log('\n📊 最新應用程式資料:');
apps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` 應用 ID: ${app.id}`);
console.log(` 應用名稱: ${app.name}`);
console.log(` 應用描述: ${app.description}`);
console.log(` 創建者 ID: ${app.creator_id}`);
console.log(` 應用部門: ${app.app_department}`);
console.log(` 應用創建者名稱: ${app.app_creator_name}`);
console.log(` 應用創建者郵箱: ${app.app_creator_email}`);
console.log(` 應用類型: ${app.type}`);
console.log(` 應用狀態: ${app.status}`);
console.log(` 創建時間: ${app.created_at}`);
console.log(` 用戶 ID: ${app.user_id}`);
console.log(` 用戶名稱: ${app.user_name}`);
console.log(` 用戶郵箱: ${app.user_email}`);
console.log(` 用戶部門: ${app.user_department}`);
});
// 檢查特定應用程式的詳細資料
const [specificApp] = await connection.execute(`
SELECT
a.*,
u.name as user_name,
u.email as user_email,
u.department as user_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
WHERE a.name LIKE '%天氣查詢機器人%'
ORDER BY a.created_at DESC
LIMIT 1
`);
if (specificApp.length > 0) {
const app = specificApp[0];
console.log('\n🎯 天氣查詢機器人應用程式詳細資料:');
console.log(` 應用名稱: ${app.name}`);
console.log(` 應用創建者名稱: ${app.creator_name}`);
console.log(` 應用部門: ${app.department}`);
console.log(` 用戶名稱: ${app.user_name}`);
console.log(` 用戶部門: ${app.user_department}`);
}
} catch (error) {
console.error('❌ 檢查最新應用程式資料失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行檢查
checkLatestAppData().catch(console.error);

View File

@@ -1,93 +0,0 @@
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function createAdminUser() {
let connection;
try {
console.log('🧪 創建管理員用戶...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 創建管理員用戶
const adminUserData = {
id: 'admin-' + Date.now(),
name: '系統管理員',
email: 'admin@example.com',
password: 'Admin123!',
department: 'ITBU',
role: 'admin',
join_date: new Date(),
created_at: new Date(),
updated_at: new Date()
};
// 加密密碼
const passwordHash = await bcrypt.hash(adminUserData.password, 12);
// 檢查用戶是否已存在
const [existingUser] = await connection.execute(
'SELECT id FROM users WHERE email = ?',
[adminUserData.email]
);
if (existingUser.length > 0) {
console.log('⚠️ 管理員用戶已存在,更新密碼...');
await connection.execute(
'UPDATE users SET password_hash = ?, updated_at = NOW() WHERE email = ?',
[passwordHash, adminUserData.email]
);
} else {
console.log('✅ 創建新的管理員用戶...');
await connection.execute(
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[adminUserData.id, adminUserData.name, adminUserData.email, passwordHash, adminUserData.department, adminUserData.role, adminUserData.join_date, adminUserData.created_at, adminUserData.updated_at]
);
}
console.log('\n✅ 管理員用戶創建/更新成功!');
console.log('📋 登入資訊:');
console.log(` 電子郵件: ${adminUserData.email}`);
console.log(` 密碼: ${adminUserData.password}`);
console.log(` 角色: ${adminUserData.role}`);
console.log(` 部門: ${adminUserData.department}`);
// 驗證用戶創建
const [userResult] = await connection.execute(
'SELECT id, name, email, role, department FROM users WHERE email = ?',
[adminUserData.email]
);
if (userResult.length > 0) {
const user = userResult[0];
console.log('\n📋 資料庫中的用戶資訊:');
console.log(` ID: ${user.id}`);
console.log(` 姓名: ${user.name}`);
console.log(` 電子郵件: ${user.email}`);
console.log(` 角色: ${user.role}`);
console.log(` 部門: ${user.department}`);
}
console.log('\n💡 現在您可以使用這些憑證登入管理後台');
console.log('💡 登入後,管理後台的應用創建功能應該可以正常工作');
} catch (error) {
console.error('❌ 創建管理員用戶失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
createAdminUser().catch(console.error);

View File

@@ -1,48 +0,0 @@
const mysql = require('mysql2/promise');
async function createPasswordResetTable() {
console.log('🚀 創建密碼重設 token 資料表...');
try {
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
});
console.log('✅ 資料庫連接成功');
// 創建密碼重設 tokens 表
const createTableSQL = `
CREATE TABLE IF NOT EXISTS password_reset_tokens (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
token VARCHAR(255) NOT NULL UNIQUE,
expires_at TIMESTAMP NOT NULL,
used_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_token (token),
INDEX idx_expires_at (expires_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`;
await connection.execute(createTableSQL);
console.log('✅ 密碼重設 tokens 表創建成功');
await connection.end();
console.log('🎉 密碼重設表創建完成!');
} catch (error) {
console.error('❌ 創建表時發生錯誤:', error);
}
}
createPasswordResetTable();

View File

@@ -1,86 +0,0 @@
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function createPasswordResetTable() {
console.log('🚀 創建密碼重設 token 資料表...');
try {
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 先檢查 users 表的結構
console.log('🔍 檢查 users 表結構...');
const [userColumns] = await connection.execute(`
SELECT COLUMN_NAME, DATA_TYPE, CHARACTER_SET_NAME, COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'users' AND COLUMN_NAME = 'id'
`, [dbConfig.database]);
if (userColumns.length > 0) {
console.log('📋 users.id 欄位資訊:', userColumns[0]);
}
// 創建密碼重設 tokens 表
const createTableSQL = `
CREATE TABLE IF NOT EXISTS password_reset_tokens (
id VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci PRIMARY KEY,
user_id VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
token VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL UNIQUE,
expires_at TIMESTAMP NOT NULL,
used_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_token (token),
INDEX idx_expires_at (expires_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
`;
await connection.execute(createTableSQL);
console.log('✅ 密碼重設 tokens 表創建成功');
// 檢查表是否創建成功
const [tables] = await connection.execute(`
SELECT TABLE_NAME, TABLE_COMMENT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'password_reset_tokens'
`, [dbConfig.database]);
if (tables.length > 0) {
console.log('📋 表資訊:', tables[0]);
}
// 檢查表結構
const [columns] = await connection.execute(`
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'password_reset_tokens'
ORDER BY ORDINAL_POSITION
`, [dbConfig.database]);
console.log('\n📋 表結構:');
columns.forEach(col => {
console.log(`- ${col.COLUMN_NAME}: ${col.DATA_TYPE} (${col.IS_NULLABLE === 'YES' ? '可為空' : '不可為空'}) ${col.COLUMN_KEY ? `[${col.COLUMN_KEY}]` : ''}`);
});
await connection.end();
console.log('\n🎉 密碼重設表創建完成!');
} catch (error) {
console.error('❌ 創建表時發生錯誤:', error);
}
}
createPasswordResetTable();

View File

@@ -1,180 +0,0 @@
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
// 創建資料庫連接
const db = {
async query(sql, params = []) {
const connection = await mysql.createConnection(dbConfig);
try {
const [rows] = await connection.execute(sql, params);
return rows;
} finally {
await connection.end();
}
},
async queryOne(sql, params = []) {
const results = await this.query(sql, params);
return results.length > 0 ? results[0] : null;
},
async insert(sql, params = []) {
const connection = await mysql.createConnection(dbConfig);
try {
const [result] = await connection.execute(sql, params);
return result;
} finally {
await connection.end();
}
},
async close() {
// 不需要關閉,因為每次查詢都創建新連接
}
};
// 測試用戶數據
const testUsers = [
{
name: '系統管理員',
email: 'admin@ai-platform.com',
password: 'admin123456',
department: 'ITBU',
role: 'admin',
description: '系統管理員帳號,擁有所有權限'
},
{
name: '開發者測試',
email: 'developer@ai-platform.com',
password: 'dev123456',
department: 'ITBU',
role: 'developer',
description: '開發者測試帳號,可以提交應用和提案'
},
{
name: '一般用戶測試',
email: 'user@ai-platform.com',
password: 'user123456',
department: 'MBU1',
role: 'user',
description: '一般用戶測試帳號,可以瀏覽和評分'
},
{
name: '評委測試',
email: 'judge@ai-platform.com',
password: 'judge123456',
department: 'HQBU',
role: 'admin',
description: '評委測試帳號,可以評分應用和提案'
},
{
name: '團隊負責人',
email: 'team-lead@ai-platform.com',
password: 'team123456',
department: 'SBU',
role: 'developer',
description: '團隊負責人測試帳號'
}
];
async function createTestUsers() {
console.log('🚀 開始創建測試用戶...');
try {
// 測試資料庫連接
await db.query('SELECT 1');
console.log('✅ 資料庫連接成功');
for (const userData of testUsers) {
try {
// 檢查用戶是否已存在
const existingUser = await db.queryOne(
'SELECT id FROM users WHERE email = ?',
[userData.email]
);
if (existingUser) {
console.log(`⚠️ 用戶 ${userData.email} 已存在,跳過創建`);
continue;
}
// 加密密碼
const saltRounds = 12;
const password_hash = await bcrypt.hash(userData.password, saltRounds);
// 創建用戶
const userId = uuidv4();
const sql = `
INSERT INTO users (
id, name, email, password_hash, department, role,
join_date, total_likes, total_views, is_active
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
const params = [
userId,
userData.name,
userData.email,
password_hash,
userData.department,
userData.role,
new Date().toISOString().split('T')[0],
0,
0,
true
];
await db.insert(sql, params);
console.log(`✅ 創建用戶: ${userData.name} (${userData.email}) - ${userData.role}`);
} catch (error) {
console.error(`❌ 創建用戶 ${userData.email} 失敗:`, error.message);
}
}
// 顯示創建的用戶列表
console.log('\n📋 測試用戶列表:');
const users = await db.query(`
SELECT name, email, role, department, join_date
FROM users
WHERE email LIKE '%@ai-platform.com'
ORDER BY role, name
`);
users.forEach((user, index) => {
console.log(`${index + 1}. ${user.name} (${user.email})`);
console.log(` 角色: ${user.role} | 部門: ${user.department} | 加入日期: ${user.join_date}`);
});
console.log('\n🔑 登入資訊:');
testUsers.forEach(user => {
console.log(`${user.role.toUpperCase()}: ${user.email} / ${user.password}`);
});
console.log('\n🎉 測試用戶創建完成!');
} catch (error) {
console.error('❌ 創建測試用戶時發生錯誤:', error);
} finally {
await db.close();
}
}
// 如果直接執行此腳本
if (require.main === module) {
createTestUsers();
}
module.exports = { createTestUsers, testUsers };

View File

@@ -1,119 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function fixAppsTable() {
let connection;
try {
console.log('🔧 開始修復 apps 表格...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查並添加新欄位
const alterStatements = [
// 添加狀態欄位
`ALTER TABLE apps ADD COLUMN status ENUM('draft', 'submitted', 'under_review', 'approved', 'rejected', 'published') DEFAULT 'draft'`,
// 添加類型欄位
`ALTER TABLE apps ADD COLUMN type ENUM('web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model', 'data_analysis', 'automation', 'other') DEFAULT 'other'`,
// 添加檔案路徑欄位
`ALTER TABLE apps ADD COLUMN file_path VARCHAR(500)`,
// 添加技術棧欄位
`ALTER TABLE apps ADD COLUMN tech_stack JSON`,
// 添加標籤欄位
`ALTER TABLE apps ADD COLUMN tags JSON`,
// 添加截圖路徑欄位
`ALTER TABLE apps ADD COLUMN screenshots JSON`,
// 添加演示連結欄位
`ALTER TABLE apps ADD COLUMN demo_url VARCHAR(500)`,
// 添加 GitHub 連結欄位
`ALTER TABLE apps ADD COLUMN github_url VARCHAR(500)`,
// 添加文檔連結欄位
`ALTER TABLE apps ADD COLUMN docs_url VARCHAR(500)`,
// 添加版本欄位
`ALTER TABLE apps ADD COLUMN version VARCHAR(50) DEFAULT '1.0.0'`,
// 添加圖示欄位
`ALTER TABLE apps ADD COLUMN icon VARCHAR(50) DEFAULT 'Bot'`,
// 添加圖示顏色欄位
`ALTER TABLE apps ADD COLUMN icon_color VARCHAR(100) DEFAULT 'from-blue-500 to-purple-500'`,
// 添加最後更新時間欄位
`ALTER TABLE apps ADD COLUMN last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`
];
for (const statement of alterStatements) {
try {
await connection.execute(statement);
console.log(`✅ 執行: ${statement.substring(0, 50)}...`);
} catch (error) {
if (error.code === 'ER_DUP_FIELDNAME') {
console.log(`⚠️ 欄位已存在,跳過: ${statement.substring(0, 50)}...`);
} else {
console.error(`❌ 執行失敗: ${statement.substring(0, 50)}...`, error.message);
}
}
}
// 添加索引
const indexStatements = [
`CREATE INDEX idx_apps_status ON apps(status)`,
`CREATE INDEX idx_apps_type ON apps(type)`,
`CREATE INDEX idx_apps_created_at ON apps(created_at)`,
`CREATE INDEX idx_apps_rating ON apps(rating DESC)`,
`CREATE INDEX idx_apps_likes ON apps(likes_count DESC)`
];
for (const statement of indexStatements) {
try {
await connection.execute(statement);
console.log(`✅ 創建索引: ${statement.substring(0, 50)}...`);
} catch (error) {
if (error.code === 'ER_DUP_KEYNAME') {
console.log(`⚠️ 索引已存在,跳過: ${statement.substring(0, 50)}...`);
} else {
console.error(`❌ 創建索引失敗: ${statement.substring(0, 50)}...`, error.message);
}
}
}
// 檢查表格結構
const [columns] = await connection.execute('DESCRIBE apps');
console.log('\n📋 apps 表格結構:');
columns.forEach(col => {
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
});
console.log('\n✅ apps 表格修復完成!');
} catch (error) {
console.error('❌ 修復 apps 表格失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行修復
fixAppsTable().catch(console.error);

View File

@@ -1,136 +0,0 @@
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function fixTables() {
let connection;
try {
console.log('🔧 修復剩餘的資料表...');
// 連接資料庫
connection = await mysql.createConnection(dbConfig);
// 修復 awards 表 (rank 是保留字)
console.log('修復 awards 表...');
const awardsTable = `
CREATE TABLE IF NOT EXISTS awards (
id VARCHAR(36) PRIMARY KEY,
competition_id VARCHAR(36) NOT NULL,
app_id VARCHAR(36),
team_id VARCHAR(36),
proposal_id VARCHAR(36),
award_type ENUM('gold', 'silver', 'bronze', 'popular', 'innovation', 'technical', 'custom') NOT NULL,
award_name VARCHAR(200) NOT NULL,
score DECIMAL(5,2) NOT NULL,
year INT NOT NULL,
month INT NOT NULL,
icon VARCHAR(50),
custom_award_type_id VARCHAR(36),
competition_type ENUM('individual', 'team', 'proposal') NOT NULL,
award_rank INT DEFAULT 0,
category ENUM('innovation', 'technical', 'practical', 'popular', 'teamwork', 'solution', 'creativity') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (competition_id) REFERENCES competitions(id) ON DELETE CASCADE,
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE SET NULL,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL,
FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE SET NULL,
INDEX idx_competition (competition_id),
INDEX idx_award_type (award_type),
INDEX idx_year_month (year, month),
INDEX idx_category (category)
)
`;
await connection.query(awardsTable);
console.log('✅ awards 表建立成功');
// 修復 user_likes 表 (DATE() 函數在唯一約束中的問題)
console.log('修復 user_likes 表...');
const userLikesTable = `
CREATE TABLE IF NOT EXISTS user_likes (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
app_id VARCHAR(36),
proposal_id VARCHAR(36),
liked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE,
UNIQUE KEY unique_user_app_date (user_id, app_id, DATE(liked_at)),
UNIQUE KEY unique_user_proposal_date (user_id, proposal_id, DATE(liked_at)),
INDEX idx_user (user_id),
INDEX idx_app (app_id),
INDEX idx_proposal (proposal_id),
INDEX idx_date (liked_at)
)
`;
await connection.query(userLikesTable);
console.log('✅ user_likes 表建立成功');
// 驗證修復結果
console.log('\n📋 驗證修復結果...');
const [tables] = await connection.query(`
SELECT TABLE_NAME, TABLE_ROWS
FROM information_schema.tables
WHERE table_schema = '${dbConfig.database}'
ORDER BY TABLE_NAME
`);
console.log('\n📊 資料表列表:');
console.log('─'.repeat(60));
console.log('表名'.padEnd(25) + '| 記錄數'.padEnd(10) + '| 狀態');
console.log('─'.repeat(60));
const expectedTables = [
'users', 'competitions', 'judges', 'teams', 'team_members',
'apps', 'proposals', 'judge_scores', 'awards', 'chat_sessions',
'chat_messages', 'ai_assistant_configs', 'user_favorites',
'user_likes', 'competition_participants', 'competition_judges',
'system_settings', 'activity_logs'
];
let successCount = 0;
for (const expectedTable of expectedTables) {
const table = tables.find(t => t.TABLE_NAME === expectedTable);
const status = table ? '✅' : '❌';
const rowCount = table ? (table.TABLE_ROWS || 0) : 'N/A';
console.log(`${expectedTable.padEnd(25)}| ${rowCount.toString().padEnd(10)}| ${status}`);
if (table) successCount++;
}
console.log(`\n📊 成功建立 ${successCount}/${expectedTables.length} 個資料表`);
if (successCount === expectedTables.length) {
console.log('🎉 所有資料表建立完成!');
} else {
console.log('⚠️ 仍有部分資料表未建立');
}
} catch (error) {
console.error('❌ 修復資料表失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 資料庫連接已關閉');
}
}
}
// 執行修復腳本
if (require.main === module) {
fixTables();
}
module.exports = { fixTables };

View File

@@ -1,94 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
port: process.env.DB_PORT || 33306
};
async function optimizeDatabase() {
let connection;
try {
connection = await mysql.createConnection(dbConfig);
console.log('🔗 連接到資料庫...');
// 檢查並創建索引
const indexes = [
// users 表索引
{ table: 'users', column: 'role', name: 'idx_users_role' },
{ table: 'users', column: 'status', name: 'idx_users_status' },
{ table: 'users', column: 'created_at', name: 'idx_users_created_at' },
{ table: 'users', column: 'email', name: 'idx_users_email' },
// apps 表索引
{ table: 'apps', column: 'creator_id', name: 'idx_apps_creator_id' },
{ table: 'apps', column: 'created_at', name: 'idx_apps_created_at' },
// judge_scores 表索引
{ table: 'judge_scores', column: 'judge_id', name: 'idx_judge_scores_judge_id' },
{ table: 'judge_scores', column: 'created_at', name: 'idx_judge_scores_created_at' }
];
for (const index of indexes) {
try {
// 檢查索引是否存在
const [existingIndexes] = await connection.execute(`
SELECT INDEX_NAME
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ?
`, [dbConfig.database, index.table, index.name]);
if (existingIndexes.length === 0) {
// 創建索引
await connection.execute(`
CREATE INDEX ${index.name} ON ${index.table} (${index.column})
`);
console.log(`✅ 創建索引: ${index.name} on ${index.table}.${index.column}`);
} else {
console.log(` 索引已存在: ${index.name}`);
}
} catch (error) {
console.error(`❌ 創建索引失敗 ${index.name}:`, error.message);
}
}
// 檢查表結構和統計信息
console.log('\n📊 資料庫優化完成!');
// 顯示表統計信息
const [tables] = await connection.execute(`
SELECT
TABLE_NAME,
TABLE_ROWS,
DATA_LENGTH,
INDEX_LENGTH
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = ?
`, [dbConfig.database]);
console.log('\n📋 表統計信息:');
tables.forEach(table => {
const dataSize = Math.round(table.DATA_LENGTH / 1024);
const indexSize = Math.round(table.INDEX_LENGTH / 1024);
console.log(` ${table.TABLE_NAME}: ${table.TABLE_ROWS} 行, 資料 ${dataSize}KB, 索引 ${indexSize}KB`);
});
} catch (error) {
console.error('❌ 資料庫優化失敗:', error.message);
throw error;
} finally {
if (connection) await connection.end();
}
}
optimizeDatabase()
.then(() => {
console.log('✅ 資料庫優化完成!');
process.exit(0);
})
.catch(() => {
console.error('❌ 資料庫優化失敗!');
process.exit(1);
});

View File

@@ -1,160 +0,0 @@
const fs = require('fs');
const path = require('path');
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function setupDatabase() {
let connection;
try {
console.log('🚀 開始建立AI展示平台資料庫...');
console.log('─'.repeat(50));
// 1. 連接資料庫
console.log('🔌 連接資料庫...');
connection = await mysql.createConnection({
...dbConfig,
database: undefined // 先不指定資料庫,因為可能不存在
});
// 2. 檢查資料庫是否存在
const [databases] = await connection.query('SHOW DATABASES');
const dbExists = databases.some(db => db.Database === dbConfig.database);
if (!dbExists) {
console.log(`📊 建立資料庫: ${dbConfig.database}`);
await connection.query(`CREATE DATABASE ${dbConfig.database} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
} else {
console.log(`✅ 資料庫已存在: ${dbConfig.database}`);
}
// 3. 切換到目標資料庫
await connection.query(`USE ${dbConfig.database}`);
// 4. 讀取並執行SQL腳本
console.log('📝 執行資料庫建立腳本...');
const sqlScript = fs.readFileSync(path.join(__dirname, '../database_setup.sql'), 'utf8');
// 分割SQL語句並執行
const statements = sqlScript
.split(';')
.map(stmt => stmt.trim())
.filter(stmt => stmt.length > 0 && !stmt.startsWith('--'))
.map(stmt => stmt + ';'); // 重新添加分號
console.log(`📋 找到 ${statements.length} 個SQL語句`);
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
if (statement.trim() && statement.trim() !== ';') {
try {
console.log(`執行語句 ${i + 1}/${statements.length}: ${statement.substring(0, 50)}...`);
await connection.query(statement);
} catch (error) {
// 忽略一些非關鍵錯誤(如表已存在等)
if (!error.message.includes('already exists') &&
!error.message.includes('Duplicate key') &&
!error.message.includes('Duplicate entry')) {
console.error(`SQL執行錯誤 (語句 ${i + 1}):`, error.message);
console.error('問題語句:', statement.substring(0, 100));
}
}
}
}
console.log('✅ 資料庫建立完成!');
// 5. 驗證建立結果
console.log('\n📋 驗證資料庫結構...');
// 檢查資料表
const [tables] = await connection.query(`
SELECT TABLE_NAME, TABLE_ROWS
FROM information_schema.tables
WHERE table_schema = '${dbConfig.database}'
ORDER BY TABLE_NAME
`);
console.log('\n📊 資料表列表:');
console.log('─'.repeat(60));
console.log('表名'.padEnd(25) + '| 記錄數'.padEnd(10) + '| 狀態');
console.log('─'.repeat(60));
const expectedTables = [
'users', 'competitions', 'judges', 'teams', 'team_members',
'apps', 'proposals', 'judge_scores', 'awards', 'chat_sessions',
'chat_messages', 'ai_assistant_configs', 'user_favorites',
'user_likes', 'competition_participants', 'competition_judges',
'system_settings', 'activity_logs'
];
let successCount = 0;
for (const expectedTable of expectedTables) {
const table = tables.find(t => t.TABLE_NAME === expectedTable);
const status = table ? '✅' : '❌';
const rowCount = table ? (table.TABLE_ROWS || 0) : 'N/A';
console.log(`${expectedTable.padEnd(25)}| ${rowCount.toString().padEnd(10)}| ${status}`);
if (table) successCount++;
}
console.log(`\n📊 成功建立 ${successCount}/${expectedTables.length} 個資料表`);
// 檢查初始數據
console.log('\n📊 初始數據檢查:');
console.log('─'.repeat(40));
const checks = [
{ name: '管理員用戶', query: 'SELECT COUNT(*) as count FROM users WHERE role = "admin"' },
{ name: '預設評審', query: 'SELECT COUNT(*) as count FROM judges' },
{ name: '預設競賽', query: 'SELECT COUNT(*) as count FROM competitions' },
{ name: 'AI配置', query: 'SELECT COUNT(*) as count FROM ai_assistant_configs' },
{ name: '系統設定', query: 'SELECT COUNT(*) as count FROM system_settings' }
];
for (const check of checks) {
try {
const [result] = await connection.query(check.query);
console.log(`${check.name.padEnd(15)}: ${result[0].count}`);
} catch (error) {
console.log(`${check.name.padEnd(15)}: 查詢失敗 - ${error.message}`);
}
}
console.log('\n🎉 資料庫建立和驗證完成!');
console.log('\n📝 下一步:');
console.log('1. 複製 env.example 到 .env.local');
console.log('2. 設定環境變數');
console.log('3. 安裝依賴: pnpm install');
console.log('4. 啟動開發服務器: pnpm dev');
} catch (error) {
console.error('❌ 資料庫建立失敗:', error.message);
console.error('請檢查以下項目:');
console.error('1. 資料庫主機是否可達');
console.error('2. 用戶名和密碼是否正確');
console.error('3. 用戶是否有建立資料庫的權限');
process.exit(1);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 資料庫連接已關閉');
}
}
}
// 執行建立腳本
if (require.main === module) {
setupDatabase();
}
module.exports = { setupDatabase };

View File

@@ -1,57 +0,0 @@
async function testActivityRecords() {
console.log('🧪 測試活動紀錄對話框的數值顯示...\n');
try {
// 測試首頁載入(包含活動紀錄對話框)
console.log('1. 測試首頁載入...');
const response = await fetch('http://localhost:3000/');
if (response.ok) {
console.log('✅ 首頁載入成功');
console.log('狀態碼:', response.status);
// 檢查頁面內容是否包含活動紀錄相關元素
const pageContent = await response.text();
// 檢查是否包含修復後的數值顯示邏輯
if (pageContent.includes('isNaN(stats.daysJoined)')) {
console.log('✅ 加入天數數值安全檢查已添加');
} else {
console.log('❌ 加入天數數值安全檢查可能未生效');
}
if (pageContent.includes('isNaN(stats.totalUsage)')) {
console.log('✅ 總使用次數數值安全檢查已添加');
} else {
console.log('❌ 總使用次數數值安全檢查可能未生效');
}
if (pageContent.includes('isNaN(stats.totalDuration)')) {
console.log('✅ 使用時長數值安全檢查已添加');
} else {
console.log('❌ 使用時長數值安全檢查可能未生效');
}
if (pageContent.includes('isNaN(stats.favoriteApps)')) {
console.log('✅ 收藏應用數值安全檢查已添加');
} else {
console.log('❌ 收藏應用數值安全檢查可能未生效');
}
} else {
console.log('❌ 首頁載入失敗:', response.status);
}
console.log('\n🎉 活動紀錄數值顯示測試完成!');
console.log('\n📋 修復內容:');
console.log('✅ 添加了 NaN 檢查,防止無效數值顯示');
console.log('✅ 所有統計數值都有安全保護');
console.log('✅ 日期計算添加了有效性檢查');
console.log('✅ 顯示邏輯更加健壯');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testActivityRecords();

View File

@@ -1,72 +0,0 @@
async function testAdminAccess() {
console.log('🧪 測試管理員存取權限...\n');
try {
// 1. 測試管理員登入
console.log('1. 測試管理員登入...');
const loginResponse = await fetch('http://localhost:3000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com',
password: 'admin123456'
})
});
if (loginResponse.ok) {
const loginData = await loginResponse.json();
console.log('✅ 管理員登入成功');
console.log('用戶資料:', {
id: loginData.user?.id,
name: loginData.user?.name,
email: loginData.user?.email,
role: loginData.user?.role,
department: loginData.user?.department
});
// 2. 測試管理員頁面存取
console.log('\n2. 測試管理員頁面存取...');
const adminResponse = await fetch('http://localhost:3000/admin');
if (adminResponse.ok) {
console.log('✅ 管理員頁面載入成功');
console.log('狀態碼:', adminResponse.status);
// 檢查頁面內容
const pageContent = await adminResponse.text();
if (pageContent.includes('存取被拒')) {
console.log('❌ 頁面顯示存取被拒');
if (pageContent.includes('調試信息')) {
console.log('📋 調試信息已顯示,請檢查用戶角色');
}
} else if (pageContent.includes('儀表板') || pageContent.includes('管理員')) {
console.log('✅ 管理員頁面正常顯示');
} else {
console.log('⚠️ 頁面內容不確定');
}
} else {
console.log('❌ 管理員頁面載入失敗:', adminResponse.status);
}
} else {
const errorData = await loginResponse.text();
console.log('❌ 管理員登入失敗:', loginResponse.status, errorData);
}
console.log('\n🎉 管理員存取權限測試完成!');
console.log('\n📋 可能的原因:');
console.log('1. 用戶未正確登入');
console.log('2. 用戶角色不是 admin');
console.log('3. 用戶資料載入時機問題');
console.log('4. localStorage 中的用戶資料有問題');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testAdminAccess();

View File

@@ -1,51 +0,0 @@
async function testAdminFix() {
console.log('🧪 測試管理員存取修復...\n');
try {
// 測試管理員頁面載入
console.log('1. 測試管理員頁面載入...');
const response = await fetch('http://localhost:3000/admin');
if (response.ok) {
console.log('✅ 管理員頁面載入成功');
console.log('狀態碼:', response.status);
// 檢查頁面內容
const pageContent = await response.text();
if (pageContent.includes('載入中...')) {
console.log('✅ 頁面顯示載入中狀態');
} else if (pageContent.includes('存取被拒')) {
console.log('❌ 頁面顯示存取被拒');
// 檢查調試信息
const debugMatch = pageContent.match(/調試信息: 用戶=([^,]+), 角色=([^<]+)/);
if (debugMatch) {
console.log('📋 調試信息:', {
用戶: debugMatch[1],
角色: debugMatch[2]
});
}
} else if (pageContent.includes('儀表板') || pageContent.includes('管理員')) {
console.log('✅ 管理員頁面正常顯示');
} else {
console.log('⚠️ 頁面內容不確定');
}
} else {
console.log('❌ 管理員頁面載入失敗:', response.status);
}
console.log('\n🎉 管理員存取修復測試完成!');
console.log('\n📋 修復內容:');
console.log('✅ 添加了 isInitialized 狀態管理');
console.log('✅ 改進了載入狀態檢查');
console.log('✅ 修復了服務器端渲染問題');
console.log('✅ 添加了調試信息顯示');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testAdminFix();

View File

@@ -1,27 +0,0 @@
async function testApiDebug() {
console.log('🧪 調試 API 錯誤...\n');
try {
// 測試用戶列表 API
console.log('1. 測試用戶列表 API...');
const response = await fetch('http://localhost:3000/api/admin/users');
console.log('狀態碼:', response.status);
console.log('狀態文本:', response.statusText);
const data = await response.text();
console.log('響應內容:', data);
if (response.ok) {
const jsonData = JSON.parse(data);
console.log('✅ API 成功:', jsonData);
} else {
console.log('❌ API 失敗');
}
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testApiDebug();

View File

@@ -1,124 +0,0 @@
// Test script to verify app creation API fix
console.log('Testing app creation API fix...')
// Simulate the API request data
const mockAppData = {
name: 'Test AI Application',
description: 'This is a test application to verify the API fix',
type: 'productivity',
demoUrl: 'https://example.com/demo',
version: '1.0.0',
creator: 'Test User',
department: 'ITBU',
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500'
}
console.log('Mock app data to be sent:', mockAppData)
// Simulate the API processing
const processAppData = (body) => {
const {
name,
description,
type,
teamId,
techStack,
tags,
demoUrl,
githubUrl,
docsUrl,
version = '1.0.0',
creator,
department,
icon = 'Bot',
iconColor = 'from-blue-500 to-purple-500'
} = body
// Simulate user data (normally from JWT token)
const mockUser = {
id: 'user-123',
name: 'Admin User',
email: 'admin@example.com',
department: 'HQBU'
}
// Prepare database insertion data
const appData = {
id: 'app-' + Date.now(),
name,
description,
creator_id: mockUser.id,
team_id: teamId || null,
type,
tech_stack: techStack ? JSON.stringify(techStack) : null,
tags: tags ? JSON.stringify(tags) : null,
demo_url: demoUrl || null,
github_url: githubUrl || null,
docs_url: docsUrl || null,
version,
status: 'draft',
icon: icon || 'Bot',
icon_color: iconColor || 'from-blue-500 to-purple-500',
department: department || mockUser.department || 'HQBU',
creator_name: creator || mockUser.name || '',
creator_email: mockUser.email || ''
}
return appData
}
// Test the processing
const processedData = processAppData(mockAppData)
console.log('\nProcessed app data for database insertion:')
console.log(JSON.stringify(processedData, null, 2))
// Verify all required fields are present
const requiredFields = ['name', 'description', 'type', 'creator_id', 'status', 'icon', 'icon_color', 'department', 'creator_name', 'creator_email']
const missingFields = requiredFields.filter(field => !processedData[field])
if (missingFields.length === 0) {
console.log('\n✅ All required fields are present!')
} else {
console.log('\n❌ Missing fields:', missingFields)
}
// Test the response formatting
const mockApiResponse = {
id: processedData.id,
name: processedData.name,
description: processedData.description,
type: processedData.type,
status: processedData.status,
creator_id: processedData.creator_id,
department: processedData.department,
creator_name: processedData.creator_name,
creator_email: processedData.creator_email,
icon: processedData.icon,
icon_color: processedData.icon_color
}
const formatResponse = (app) => ({
id: app.id,
name: app.name,
description: app.description,
type: app.type,
status: app.status,
creatorId: app.creator_id,
department: app.department,
icon: app.icon,
iconColor: app.icon_color,
creator: {
id: app.creator_id,
name: app.creator_name,
email: app.creator_email,
department: app.department,
role: 'admin'
}
})
const formattedResponse = formatResponse(mockApiResponse)
console.log('\nFormatted API response:')
console.log(JSON.stringify(formattedResponse, null, 2))
console.log('\n✅ App creation API fix test completed!')

View File

@@ -1,166 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
// 模擬前端類型映射函數
const mapTypeToApiType = (frontendType) => {
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
};
return typeMap[frontendType] || 'other';
};
// API 的 validTypes 陣列(已修正)
const apiValidTypes = [
'productivity', 'ai_model', 'automation', 'data_analysis', 'educational',
'healthcare', 'finance', 'iot_device', 'blockchain', 'ar_vr',
'machine_learning', 'computer_vision', 'nlp', 'robotics', 'cybersecurity',
'cloud_service', 'other'
];
async function testAppCreationUpload() {
let connection;
try {
console.log('🧪 測試 AI 應用程式創建上傳流程...\n');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 測試前端類型映射
console.log('📋 測試前端類型映射:');
const testTypes = [
'文字處理', '圖像生成', '程式開發', '數據分析', '教育工具',
'健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR',
'機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'
];
testTypes.forEach(frontendType => {
const apiType = mapTypeToApiType(frontendType);
const isValid = apiValidTypes.includes(apiType);
console.log(` ${frontendType} -> ${apiType} ${isValid ? '✅' : '❌'}`);
});
// 2. 檢查資料庫中現有的類型分佈
console.log('\n📊 檢查資料庫中現有的應用程式類型:');
const [typeStats] = await connection.execute(`
SELECT type, COUNT(*) as count
FROM apps
WHERE type IS NOT NULL
GROUP BY type
ORDER BY count DESC
`);
typeStats.forEach(row => {
const isValid = apiValidTypes.includes(row.type);
console.log(` ${row.type}: ${row.count} 個應用程式 ${isValid ? '✅' : '❌'}`);
});
// 3. 檢查是否有無效的類型
console.log('\n🔍 檢查無效的類型:');
const [invalidTypes] = await connection.execute(`
SELECT type, COUNT(*) as count
FROM apps
WHERE type IS NOT NULL AND type NOT IN (?)
GROUP BY type
`, [apiValidTypes]);
if (invalidTypes.length > 0) {
console.log(' ❌ 發現無效的類型:');
invalidTypes.forEach(row => {
console.log(` ${row.type}: ${row.count} 個應用程式`);
});
} else {
console.log(' ✅ 所有類型都是有效的');
}
// 4. 模擬創建新應用程式的資料
console.log('\n📝 模擬創建新應用程式的資料:');
const testAppData = {
name: '測試 AI 應用程式',
description: '這是一個測試用的 AI 應用程式',
type: mapTypeToApiType('文字處理'), // 應該映射為 'productivity'
creator: '測試創建者',
department: 'HQBU',
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500'
};
console.log(' 前端資料:');
console.log(` 名稱: ${testAppData.name}`);
console.log(` 類型: 文字處理 -> ${testAppData.type}`);
console.log(` 創建者: ${testAppData.creator}`);
console.log(` 部門: ${testAppData.department}`);
console.log(` 圖示: ${testAppData.icon}`);
console.log(` 圖示顏色: ${testAppData.iconColor}`);
// 5. 驗證 API 會接受這些資料
console.log('\n✅ API 驗證結果:');
console.log(` 類型 '${testAppData.type}' 是否有效: ${apiValidTypes.includes(testAppData.type) ? '是' : '否'}`);
console.log(` 名稱長度 (${testAppData.name.length}): ${testAppData.name.length >= 2 && testAppData.name.length <= 200 ? '有效' : '無效'}`);
console.log(` 描述長度 (${testAppData.description.length}): ${testAppData.description.length >= 10 ? '有效' : '無效'}`);
// 6. 檢查資料庫表格結構
console.log('\n📋 檢查 apps 表格結構:');
const [columns] = await connection.execute('DESCRIBE apps');
const relevantColumns = ['name', 'description', 'type', 'creator_name', 'creator_email', 'department', 'icon', 'icon_color'];
relevantColumns.forEach(colName => {
const column = columns.find(col => col.Field === colName);
if (column) {
console.log(` ${colName}: ${column.Type} ${column.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${column.Default ? `DEFAULT ${column.Default}` : ''}`);
} else {
console.log(` ${colName}: ❌ 欄位不存在`);
}
});
console.log('\n✅ AI 應用程式創建上傳流程測試完成!');
console.log('📝 總結:');
console.log(' - 前端類型映射 ✅');
console.log(' - API validTypes 已更新 ✅');
console.log(' - 資料庫欄位完整 ✅');
console.log(' - 類型驗證邏輯正確 ✅');
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testAppCreationUpload().catch(console.error);

View File

@@ -1,101 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testAppEditFix() {
let connection;
try {
console.log('🧪 測試應用編輯功能修正...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 檢查現有應用程式
console.log('\n📋 檢查現有應用程式...');
const [apps] = await connection.execute(`
SELECT a.*, u.name as creator_name, u.department as creator_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
LIMIT 3
`);
console.log(`找到 ${apps.length} 個應用程式:`);
apps.forEach((app, index) => {
console.log(`${index + 1}. ${app.name}`);
console.log(` 創建者: ${app.creator_name} (${app.creator_department})`);
console.log(` 圖示: ${app.icon || '未設定'}`);
console.log(` 圖示顏色: ${app.icon_color || '未設定'}`);
console.log(` 狀態: ${app.status || 'draft'}`);
console.log('');
});
// 2. 測試類型映射
console.log('\n🧪 測試類型映射...');
const testTypes = [
'文字處理',
'圖像生成',
'數據分析',
'機器學習',
'其他'
];
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'數據分析': 'data_analysis',
'機器學習': 'machine_learning',
'其他': 'other'
};
testTypes.forEach(frontendType => {
const apiType = typeMap[frontendType] || 'other';
console.log(`${frontendType} -> ${apiType}`);
});
// 3. 檢查 API 有效類型
console.log('\n📋 API 有效類型:');
const validApiTypes = [
'web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model',
'data_analysis', 'automation', 'productivity', 'educational', 'healthcare',
'finance', 'iot_device', 'blockchain', 'ar_vr', 'machine_learning',
'computer_vision', 'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
];
validApiTypes.forEach(type => {
console.log(` - ${type}`);
});
// 4. 驗證映射是否有效
console.log('\n✅ 驗證映射有效性:');
const mappedTypes = Object.values(typeMap);
const validMappedTypes = mappedTypes.filter(type => validApiTypes.includes(type));
console.log(`有效映射類型: ${validMappedTypes.length}/${mappedTypes.length}`);
if (validMappedTypes.length === mappedTypes.length) {
console.log('✅ 所有映射類型都是有效的');
} else {
console.log('❌ 有無效的映射類型');
}
console.log('\n✅ 應用編輯功能修正測試完成!');
} catch (error) {
console.error('❌ 測試失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testAppEditFix().catch(console.error);

View File

@@ -1,98 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testAppEdit() {
let connection;
try {
console.log('🧪 測試應用編輯功能...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 檢查 apps 表結構
console.log('\n📋 檢查 apps 表結構...');
const [columns] = await connection.execute('DESCRIBE apps');
const hasIcon = columns.some(col => col.Field === 'icon');
const hasIconColor = columns.some(col => col.Field === 'icon_color');
console.log(`圖示欄位: ${hasIcon ? '✅' : '❌'}`);
console.log(`圖示顏色欄位: ${hasIconColor ? '✅' : '❌'}`);
if (!hasIcon || !hasIconColor) {
console.log('⚠️ 需要更新資料庫結構,請執行: npm run db:update-structure');
return;
}
// 2. 檢查現有應用程式
console.log('\n📋 檢查現有應用程式...');
const [apps] = await connection.execute(`
SELECT a.*, u.name as creator_name, u.department as creator_department
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
LIMIT 5
`);
console.log(`找到 ${apps.length} 個應用程式:`);
apps.forEach((app, index) => {
console.log(`${index + 1}. ${app.name}`);
console.log(` 創建者: ${app.creator_name} (${app.creator_department})`);
console.log(` 圖示: ${app.icon || '未設定'}`);
console.log(` 圖示顏色: ${app.icon_color || '未設定'}`);
console.log(` 狀態: ${app.status || 'draft'}`);
console.log('');
});
// 3. 測試更新應用程式
if (apps.length > 0) {
const testApp = apps[0];
console.log(`🧪 測試更新應用程式: ${testApp.name}`);
const updateData = {
icon: 'Brain',
icon_color: 'from-purple-500 to-pink-500',
department: 'ITBU'
};
await connection.execute(
'UPDATE apps SET icon = ?, icon_color = ? WHERE id = ?',
[updateData.icon, updateData.icon_color, testApp.id]
);
console.log('✅ 測試更新成功');
// 驗證更新
const [updatedApp] = await connection.execute(
'SELECT * FROM apps WHERE id = ?',
[testApp.id]
);
if (updatedApp.length > 0) {
const app = updatedApp[0];
console.log(`更新後的圖示: ${app.icon}`);
console.log(`更新後的圖示顏色: ${app.icon_color}`);
}
}
console.log('\n✅ 應用編輯功能測試完成!');
} catch (error) {
console.error('❌ 測試失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testAppEdit().catch(console.error);

View File

@@ -1,161 +0,0 @@
// Test script to verify app type editing issue
console.log('Testing app type editing issue...')
// Simulate the type mapping functions
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他'
}
return typeMap[apiType] || '其他'
}
// Simulate API response with different app types
const mockApiResponse = {
apps: [
{
id: '1',
name: 'Productivity App',
type: 'productivity', // API type
description: 'A productivity tool'
},
{
id: '2',
name: 'AI Model App',
type: 'ai_model', // API type
description: 'An AI model'
},
{
id: '3',
name: 'Data Analysis App',
type: 'data_analysis', // API type
description: 'A data analysis tool'
}
]
}
// Simulate loadApps processing
console.log('=== Original API Data ===')
mockApiResponse.apps.forEach((app, index) => {
console.log(`App ${index + 1}: ${app.name} - API type: ${app.type}`)
})
const formattedApps = mockApiResponse.apps.map(app => ({
...app,
type: mapApiTypeToDisplayType(app.type), // Convert to Chinese display type
creator: 'Test User',
department: 'HQBU'
}))
console.log('\n=== After loadApps Processing ===')
formattedApps.forEach((app, index) => {
console.log(`App ${index + 1}: ${app.name} - Display type: ${app.type}`)
})
// Simulate handleEditApp
const simulateHandleEditApp = (app) => {
console.log(`\n=== Editing App: ${app.name} ===`)
console.log('Input app.type:', app.type)
const newApp = {
name: app.name,
type: app.type, // This should be the Chinese display type
department: app.department || "HQBU",
creator: app.creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
}
console.log('newApp.type after handleEditApp:', newApp.type)
// Check if this type is valid for the Select component
const validSelectValues = [
'文字處理', '圖像生成', '圖像處理', '語音辨識', '推薦系統', '音樂生成',
'程式開發', '影像處理', '對話系統', '數據分析', '設計工具', '語音技術',
'教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR',
'機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'
]
const isValidSelectValue = validSelectValues.includes(newApp.type)
console.log('Is valid Select value?', isValidSelectValue)
return newApp
}
// Test all apps
console.log('\n=== Testing handleEditApp for all apps ===')
const validSelectValues = [
'文字處理', '圖像生成', '圖像處理', '語音辨識', '推薦系統', '音樂生成',
'程式開發', '影像處理', '對話系統', '數據分析', '設計工具', '語音技術',
'教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR',
'機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'
]
formattedApps.forEach((app, index) => {
const newApp = simulateHandleEditApp(app)
console.log(`App ${index + 1} result: ${newApp.type} (valid: ${validSelectValues.includes(newApp.type)})`)
})
// Test the update process
console.log('\n=== Testing Update Process ===')
const mapTypeToApiType = (frontendType) => {
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
}
return typeMap[frontendType] || 'other'
}
formattedApps.forEach((app, index) => {
const displayType = app.type
const apiType = mapTypeToApiType(displayType)
const backToDisplay = mapApiTypeToDisplayType(apiType)
console.log(`App ${index + 1}:`)
console.log(` Display: ${displayType}`)
console.log(` API: ${apiType}`)
console.log(` Round trip: ${backToDisplay}`)
console.log(` Round trip matches: ${backToDisplay === displayType}`)
})
console.log('\n=== Test completed ===')

View File

@@ -1,82 +0,0 @@
async function testCompleteAdminFlow() {
console.log('🧪 測試完整管理員流程...\n');
try {
// 1. 測試登入頁面
console.log('1. 測試登入頁面...');
const loginPageResponse = await fetch('http://localhost:3000/');
if (loginPageResponse.ok) {
console.log('✅ 登入頁面載入成功');
} else {
console.log('❌ 登入頁面載入失敗:', loginPageResponse.status);
}
// 2. 測試管理員登入
console.log('\n2. 測試管理員登入...');
const loginResponse = await fetch('http://localhost:3000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com',
password: 'admin123456'
})
});
if (loginResponse.ok) {
const loginData = await loginResponse.json();
console.log('✅ 管理員登入成功');
console.log('用戶資料:', {
id: loginData.user?.id,
name: loginData.user?.name,
email: loginData.user?.email,
role: loginData.user?.role
});
// 3. 測試管理員頁面
console.log('\n3. 測試管理員頁面...');
const adminResponse = await fetch('http://localhost:3000/admin');
if (adminResponse.ok) {
const pageContent = await adminResponse.text();
if (pageContent.includes('載入中...')) {
console.log('✅ 頁面顯示載入中狀態(正常)');
} else if (pageContent.includes('存取被拒')) {
console.log('❌ 頁面顯示存取被拒');
// 檢查調試信息
const debugMatch = pageContent.match(/調試信息: 用戶=([^,]+), 角色=([^<]+)/);
if (debugMatch) {
console.log('📋 調試信息:', {
用戶: debugMatch[1],
角色: debugMatch[2]
});
}
} else if (pageContent.includes('儀表板') || pageContent.includes('管理員')) {
console.log('✅ 管理員頁面正常顯示');
} else {
console.log('⚠️ 頁面內容不確定');
}
}
} else {
const errorData = await loginResponse.text();
console.log('❌ 管理員登入失敗:', loginResponse.status, errorData);
}
console.log('\n🎉 完整管理員流程測試完成!');
console.log('\n💡 解決方案:');
console.log('1. 用戶需要先登入才能訪問管理員頁面');
console.log('2. 登入後,用戶狀態會保存到 localStorage');
console.log('3. 管理員頁面會檢查用戶角色');
console.log('4. 如果角色不是 admin會顯示存取被拒');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testCompleteAdminFlow();

View File

@@ -1,76 +0,0 @@
async function testCompleteFlow() {
console.log('🧪 測試完整的忘記密碼流程...\n');
try {
// 1. 測試忘記密碼 API
console.log('1. 測試忘記密碼 API...');
const response = await fetch('http://localhost:3000/api/auth/forgot-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ 忘記密碼 API 測試成功');
console.log('生成的重設連結:', data.resetUrl);
console.log('過期時間:', data.expiresAt);
// 2. 測試註冊頁面是否可以正常載入
console.log('\n2. 測試註冊頁面載入...');
const registerResponse = await fetch(data.resetUrl);
if (registerResponse.ok) {
console.log('✅ 註冊頁面載入成功');
console.log('狀態碼:', registerResponse.status);
} else {
console.log('❌ 註冊頁面載入失敗:', registerResponse.status);
}
// 3. 測試密碼重設 API
console.log('\n3. 測試密碼重設 API...');
const url = new URL(data.resetUrl);
const token = url.searchParams.get('token');
const resetResponse = await fetch('http://localhost:3000/api/auth/reset-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: token,
password: 'newpassword123'
})
});
if (resetResponse.ok) {
const resetData = await resetResponse.json();
console.log('✅ 密碼重設 API 測試成功:', resetData);
} else {
const errorData = await resetResponse.text();
console.log('❌ 密碼重設 API 測試失敗:', resetResponse.status, errorData);
}
} else {
const errorData = await response.text();
console.log('❌ 忘記密碼 API 測試失敗:', response.status, errorData);
}
console.log('\n🎉 完整流程測試完成!');
console.log('\n📋 功能狀態總結:');
console.log('✅ 忘記密碼 API - 正常');
console.log('✅ 註冊頁面載入 - 正常');
console.log('✅ 密碼重設 API - 正常');
console.log('✅ 語法錯誤修復 - 完成');
console.log('✅ 用戶界面整合 - 完成');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testCompleteFlow();

View File

@@ -1,93 +0,0 @@
async function testCompleteLoginFlow() {
console.log('🧪 測試完整登入流程...\n');
try {
// 1. 測試首頁(登入頁面)
console.log('1. 測試首頁(登入頁面)...');
const homeResponse = await fetch('http://localhost:3000/');
if (homeResponse.ok) {
console.log('✅ 首頁載入成功');
const homeContent = await homeResponse.text();
if (homeContent.includes('登入') || homeContent.includes('Login')) {
console.log('✅ 首頁包含登入功能');
} else {
console.log('⚠️ 首頁可能不包含登入功能');
}
} else {
console.log('❌ 首頁載入失敗:', homeResponse.status);
}
// 2. 測試管理員登入 API
console.log('\n2. 測試管理員登入 API...');
const loginResponse = await fetch('http://localhost:3000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com',
password: 'admin123456'
})
});
if (loginResponse.ok) {
const loginData = await loginResponse.json();
console.log('✅ 管理員登入 API 成功');
console.log('用戶資料:', {
id: loginData.user?.id,
name: loginData.user?.name,
email: loginData.user?.email,
role: loginData.user?.role
});
} else {
const errorData = await loginResponse.text();
console.log('❌ 管理員登入 API 失敗:', loginResponse.status, errorData);
return;
}
// 3. 測試管理員頁面(未登入狀態)
console.log('\n3. 測試管理員頁面(未登入狀態)...');
const adminResponse = await fetch('http://localhost:3000/admin');
if (adminResponse.ok) {
const pageContent = await adminResponse.text();
if (pageContent.includes('存取被拒')) {
console.log('✅ 管理員頁面正確顯示存取被拒(未登入)');
// 檢查調試信息
const debugMatch = pageContent.match(/調試信息: 用戶=([^,]+), 角色=([^<]+)/);
if (debugMatch) {
console.log('📋 調試信息:', {
用戶: debugMatch[1],
角色: debugMatch[2]
});
} else {
console.log('⚠️ 沒有調試信息');
}
} else if (pageContent.includes('載入中')) {
console.log('❌ 管理員頁面顯示載入中(應該顯示存取被拒)');
} else if (pageContent.includes('儀表板') || pageContent.includes('管理員')) {
console.log('⚠️ 管理員頁面直接顯示內容(可能沒有權限檢查)');
} else {
console.log('⚠️ 管理員頁面內容不確定');
}
} else {
console.log('❌ 管理員頁面載入失敗:', adminResponse.status);
}
console.log('\n🎉 完整登入流程測試完成!');
console.log('\n💡 結論:');
console.log('1. 管理員頁面需要先登入才能訪問');
console.log('2. 未登入時顯示「存取被拒」是正確的行為');
console.log('3. 用戶需要通過前端登入界面登入');
console.log('4. 登入後才能正常訪問管理員後台');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testCompleteLoginFlow();

View File

@@ -1,92 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testCreatorNameFix() {
let connection;
try {
console.log('🔍 測試創建者名稱修正...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 模擬列表 API 的查詢
const [apps] = await connection.execute(`
SELECT
a.*,
u.name as user_creator_name,
u.email as user_creator_email,
u.department as user_creator_department,
u.role as creator_role
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC
LIMIT 3
`);
console.log('\n📊 原始資料庫查詢結果:');
apps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` 應用名稱: ${app.name}`);
console.log(` apps.creator_name: ${app.creator_name}`);
console.log(` users.name: ${app.user_creator_name}`);
});
// 模擬修正後的格式化邏輯
const formattedApps = apps.map((app) => ({
id: app.id,
name: app.name,
creator: {
id: app.creator_id,
name: app.creator_name || app.user_creator_name, // 修正:優先使用 apps.creator_name
email: app.user_creator_email,
department: app.department || app.user_creator_department,
role: app.creator_role
}
}));
console.log('\n📋 修正後的格式化結果:');
formattedApps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` 名稱: ${app.name}`);
console.log(` 創建者名稱: ${app.creator.name}`);
console.log(` 創建者郵箱: ${app.creator.email}`);
console.log(` 創建者部門: ${app.creator.department}`);
});
// 驗證修正是否有效
const expectedCreatorName = "佩庭"; // 期望的創建者名稱
const actualCreatorName = formattedApps[0]?.creator.name;
console.log('\n✅ 驗證結果:');
console.log(`期望創建者名稱: ${expectedCreatorName}`);
console.log(`實際創建者名稱: ${actualCreatorName}`);
console.log(`修正是否成功: ${actualCreatorName === expectedCreatorName}`);
if (actualCreatorName === expectedCreatorName) {
console.log('🎉 創建者名稱修正成功!現在顯示正確的資料庫值。');
} else {
console.log('❌ 創建者名稱修正失敗,需要進一步檢查。');
}
} catch (error) {
console.error('❌ 測試創建者名稱修正失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行測試
testCreatorNameFix().catch(console.error);

View File

@@ -1,84 +0,0 @@
// Test script to verify creator object handling fix
console.log('Testing creator object handling fix...')
// Simulate API response with creator object
const mockApiResponse = {
apps: [
{
id: '1',
name: 'Test App',
type: 'web_app',
status: 'published',
description: 'Test description',
creator: {
id: 'user1',
name: 'John Doe',
email: 'john@example.com',
department: 'ITBU',
role: 'developer'
},
department: 'ITBU',
createdAt: '2025-01-01T00:00:00Z',
viewsCount: 100,
likesCount: 50
},
{
id: '2',
name: 'Test App 2',
type: 'mobile_app',
status: 'pending',
description: 'Test description 2',
creator: 'Jane Smith', // String creator
department: 'HQBU',
createdAt: '2025-01-02T00:00:00Z',
viewsCount: 200,
likesCount: 75
}
]
}
// Simulate the loadApps function processing
function processApps(apiData) {
return (apiData.apps || []).map((app) => ({
...app,
views: app.viewsCount || 0,
likes: app.likesCount || 0,
appUrl: app.demoUrl || '',
type: app.type, // Simplified for test
icon: app.icon || 'Bot',
iconColor: app.iconColor || 'from-blue-500 to-purple-500',
reviews: 0,
createdAt: app.createdAt ? new Date(app.createdAt).toLocaleDateString() : '未知',
// Handle creator object properly
creator: typeof app.creator === 'object' ? app.creator.name : app.creator,
department: typeof app.creator === 'object' ? app.creator.department : app.department
}))
}
// Test the processing
const processedApps = processApps(mockApiResponse)
console.log('Original API response:')
console.log(JSON.stringify(mockApiResponse, null, 2))
console.log('\nProcessed apps:')
console.log(JSON.stringify(processedApps, null, 2))
// Test rendering simulation
console.log('\nTesting rendering simulation:')
processedApps.forEach((app, index) => {
console.log(`App ${index + 1}:`)
console.log(` Creator: ${app.creator}`)
console.log(` Department: ${app.department}`)
console.log(` Type: ${typeof app.creator}`)
// Simulate the table cell rendering
const creatorDisplay = typeof app.creator === 'object' ? app.creator.name : app.creator
const departmentDisplay = typeof app.creator === 'object' ? app.creator.department : app.department
console.log(` Display - Creator: ${creatorDisplay}`)
console.log(` Display - Department: ${departmentDisplay}`)
console.log('')
})
console.log('✅ Creator object handling test completed successfully!')

View File

@@ -1,100 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testDatabaseValues() {
let connection;
try {
console.log('🔍 檢查資料庫中的應用程式資料...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查 apps 表格結構
const [columns] = await connection.execute('DESCRIBE apps');
console.log('\n📋 apps 表格結構:');
columns.forEach(col => {
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
});
// 檢查前 5 個應用程式的資料
const [apps] = await connection.execute(`
SELECT
id, name, description, type, department, creator_name, creator_email,
icon, icon_color, status, created_at
FROM apps
LIMIT 5
`);
console.log('\n📊 前 5 個應用程式資料:');
apps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` ID: ${app.id}`);
console.log(` 名稱: ${app.name}`);
console.log(` 類型: ${app.type || 'NULL'}`);
console.log(` 部門: ${app.department || 'NULL'}`);
console.log(` 創建者名稱: ${app.creator_name || 'NULL'}`);
console.log(` 創建者郵箱: ${app.creator_email || 'NULL'}`);
console.log(` 圖示: ${app.icon || 'NULL'}`);
console.log(` 圖示顏色: ${app.icon_color || 'NULL'}`);
console.log(` 狀態: ${app.status || 'NULL'}`);
console.log(` 創建時間: ${app.created_at}`);
});
// 檢查是否有任何應用程式的 type 欄位為 NULL
const [nullTypes] = await connection.execute(`
SELECT COUNT(*) as count
FROM apps
WHERE type IS NULL
`);
console.log(`\n📈 類型為 NULL 的應用程式數量: ${nullTypes[0].count}`);
// 檢查是否有任何應用程式的 department 欄位為 NULL
const [nullDepartments] = await connection.execute(`
SELECT COUNT(*) as count
FROM apps
WHERE department IS NULL
`);
console.log(`📈 部門為 NULL 的應用程式數量: ${nullDepartments[0].count}`);
// 檢查是否有任何應用程式的 creator_name 欄位為 NULL
const [nullCreatorNames] = await connection.execute(`
SELECT COUNT(*) as count
FROM apps
WHERE creator_name IS NULL
`);
console.log(`📈 創建者名稱為 NULL 的應用程式數量: ${nullCreatorNames[0].count}`);
// 檢查是否有任何應用程式的 icon 欄位為 NULL
const [nullIcons] = await connection.execute(`
SELECT COUNT(*) as count
FROM apps
WHERE icon IS NULL
`);
console.log(`📈 圖示為 NULL 的應用程式數量: ${nullIcons[0].count}`);
} catch (error) {
console.error('❌ 檢查資料庫值失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行檢查
testDatabaseValues().catch(console.error);

View File

@@ -1,54 +0,0 @@
const mysql = require('mysql2/promise');
async function testDbConnection() {
console.log('🧪 測試資料庫連接...\n');
try {
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
console.log('連接配置:', {
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.user,
database: dbConfig.database
});
// 創建連接
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 測試查詢
const [rows] = await connection.execute('SELECT COUNT(*) as count FROM users WHERE is_active = TRUE');
console.log('✅ 查詢成功,用戶數量:', rows[0].count);
// 測試用戶列表查詢
const [users] = await connection.execute(`
SELECT
id, name, email, avatar, department, role, join_date,
total_likes, total_views, is_active, last_login, created_at, updated_at
FROM users
WHERE is_active = TRUE
ORDER BY created_at DESC
LIMIT 10
`);
console.log('✅ 用戶列表查詢成功,返回用戶數:', users.length);
await connection.end();
console.log('✅ 連接已關閉');
} catch (error) {
console.error('❌ 資料庫連接失敗:', error.message);
console.error('詳細錯誤:', error);
}
}
testDbConnection();

View File

@@ -1,166 +0,0 @@
// Test script to verify department pre-fill issue in handleEditApp
console.log('Testing department pre-fill issue...')
// Simulate the loadApps function processing
function processApps(apiApps) {
return apiApps.map(app => ({
id: app.id,
name: app.name,
type: app.type,
creator: typeof app.creator === 'object' ? app.creator.name : app.creator,
department: typeof app.creator === 'object' ? app.creator.department : app.department,
description: app.description,
appUrl: app.appUrl || app.demoUrl || '',
icon: app.icon || 'Bot',
iconColor: app.iconColor || 'from-blue-500 to-purple-500',
status: app.status,
views: app.views || 0,
likes: app.likes || 0,
rating: app.rating || 0,
reviews: app.reviews || 0,
createdAt: app.createdAt ? new Date(app.createdAt).toLocaleDateString() : '未知'
}))
}
// Simulate the handleEditApp function
function handleEditApp(app) {
console.log('📝 Editing app:', app.name)
console.log('📋 App object structure:', {
name: app.name,
creator: app.creator,
department: app.department,
hasCreatorObject: typeof app.creator === 'object',
hasCreatorProperty: 'creator' in app,
hasDepartmentProperty: 'department' in app
})
const newApp = {
name: app.name,
type: app.type,
department: app.creator?.department || app.department || "HQBU", // This is the problematic line
creator: app.creator?.name || app.creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
}
console.log('📝 Form populated with app data:', newApp)
return newApp
}
// Test scenario 1: App with creator as object (from API)
console.log('\n=== Test Scenario 1: Creator as Object ===')
const apiAppWithCreatorObject = {
id: "1",
name: "Test AI App",
type: "圖像生成",
creator: {
id: "user1",
name: "John Doe",
department: "ITBU"
},
department: "HQBU", // This should be ignored when creator is object
description: "A test AI application",
appUrl: "https://example.com",
icon: "Brain",
iconColor: "from-purple-500 to-pink-500",
status: "published",
views: 100,
likes: 50,
rating: 4.5,
reviews: 10,
createdAt: "2024-01-15"
}
console.log('1. Original API app with creator object:')
console.log(apiAppWithCreatorObject)
console.log('\n2. Processed by loadApps:')
const processedApp1 = processApps([apiAppWithCreatorObject])[0]
console.log(processedApp1)
console.log('\n3. handleEditApp result:')
const editResult1 = handleEditApp(processedApp1)
console.log('Department in form:', editResult1.department)
// Test scenario 2: App with creator as string (from API)
console.log('\n=== Test Scenario 2: Creator as String ===')
const apiAppWithCreatorString = {
id: "2",
name: "Another Test App",
type: "語音辨識",
creator: "Jane Smith", // String creator
department: "MBU1", // This should be used when creator is string
description: "Another test application",
appUrl: "https://test2.com",
icon: "Mic",
iconColor: "from-green-500 to-teal-500",
status: "draft",
views: 50,
likes: 25,
rating: 4.0,
reviews: 5,
createdAt: "2024-01-20"
}
console.log('1. Original API app with creator string:')
console.log(apiAppWithCreatorString)
console.log('\n2. Processed by loadApps:')
const processedApp2 = processApps([apiAppWithCreatorString])[0]
console.log(processedApp2)
console.log('\n3. handleEditApp result:')
const editResult2 = handleEditApp(processedApp2)
console.log('Department in form:', editResult2.department)
// Test scenario 3: Fix the handleEditApp function
console.log('\n=== Test Scenario 3: Fixed handleEditApp ===')
function handleEditAppFixed(app) {
console.log('📝 Editing app (FIXED):', app.name)
console.log('📋 App object structure:', {
name: app.name,
creator: app.creator,
department: app.department,
hasCreatorObject: typeof app.creator === 'object',
hasCreatorProperty: 'creator' in app,
hasDepartmentProperty: 'department' in app
})
const newApp = {
name: app.name,
type: app.type,
department: app.department || "HQBU", // FIXED: Use app.department directly
creator: app.creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
}
console.log('📝 Form populated with app data (FIXED):', newApp)
return newApp
}
console.log('1. Test with processed app 1 (creator was object):')
const fixedResult1 = handleEditAppFixed(processedApp1)
console.log('Department in form (FIXED):', fixedResult1.department)
console.log('\n2. Test with processed app 2 (creator was string):')
const fixedResult2 = handleEditAppFixed(processedApp2)
console.log('Department in form (FIXED):', fixedResult2.department)
// Verify the fix
console.log('\n=== Verification ===')
const expectedDepartment1 = "ITBU" // Should be from creator.department
const expectedDepartment2 = "MBU1" // Should be from app.department
console.log('Scenario 1 - Expected:', expectedDepartment1, 'Got:', fixedResult1.department, '✅', fixedResult1.department === expectedDepartment1 ? 'PASS' : 'FAIL')
console.log('Scenario 2 - Expected:', expectedDepartment2, 'Got:', fixedResult2.department, '✅', fixedResult2.department === expectedDepartment2 ? 'PASS' : 'FAIL')
if (fixedResult1.department === expectedDepartment1 && fixedResult2.department === expectedDepartment2) {
console.log('\n🎉 All tests passed! The department pre-fill fix is working correctly.')
} else {
console.log('\n❌ Some tests failed. Check the handleEditApp function.')
}

View File

@@ -1,166 +0,0 @@
const mysql = require('mysql2/promise');
// Simulate the detailed API response structure
const simulateDetailedApiResponse = async () => {
try {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'ai_showcase_platform'
});
console.log('=== Testing Detail View Edit Flow ===\n');
// 1. First, get the actual detailed API response
const [apps] = await connection.execute(`
SELECT
a.id, a.name, a.description, a.type, a.department as app_department,
a.creator_name as app_creator_name, a.creator_email as app_creator_email,
a.icon, a.icon_color, a.status, a.created_at,
u.id as user_id, u.name as user_name, u.email as user_email, u.department as user_department
FROM apps a LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC LIMIT 1
`);
if (apps.length === 0) {
console.log('No apps found in database');
return;
}
const app = apps[0];
console.log('Raw database data:');
console.log('app_department:', app.app_department);
console.log('app_creator_name:', app.app_creator_name);
console.log('user_department:', app.user_department);
console.log('user_name:', app.user_name);
console.log('type:', app.type);
console.log('icon:', app.icon);
console.log('icon_color:', app.icon_color);
console.log('');
// 2. Simulate the detailed API response structure (like /api/apps/[id])
const detailedAppData = {
id: app.id,
name: app.name,
description: app.description,
type: app.type, // This is the API type (English)
department: app.app_department, // This should be the app's department
icon: app.icon,
iconColor: app.icon_color,
status: app.status,
createdAt: app.created_at,
creator: {
id: app.user_id,
name: app.app_creator_name || app.user_name, // Prioritize app.creator_name
email: app.app_creator_email || app.user_email,
department: app.app_department || app.user_department, // Prioritize app.department
role: 'developer'
}
};
console.log('Simulated detailed API response:');
console.log('detailedAppData:', JSON.stringify(detailedAppData, null, 2));
console.log('');
// 3. Simulate the handleEditApp function processing
const handleEditApp = (app) => {
console.log('=== handleEditApp Debug ===');
console.log('Input app:', app);
console.log('app.type:', app.type);
console.log('app.department:', app.department);
console.log('app.creator:', app.creator);
console.log('app.icon:', app.icon);
console.log('app.iconColor:', app.iconColor);
// 處理類型轉換:如果類型是英文的,轉換為中文
let displayType = app.type;
if (app.type && !['文字處理', '圖像生成', '程式開發', '數據分析', '教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR', '機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'].includes(app.type)) {
displayType = mapApiTypeToDisplayType(app.type);
}
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
// 優先使用應用程式的部門,而不是創建者的部門
department = app.department || app.creator.department || "";
}
const newAppData = {
name: app.name || "",
type: displayType || "文字處理",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
}
console.log('newAppData:', newAppData);
return newAppData;
};
// 4. Test the type conversion function
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他',
// Old English types
'web_app': '文字處理',
'mobile_app': '文字處理',
'desktop_app': '文字處理',
'api_service': '程式開發'
};
return typeMap[apiType] || '其他';
};
// 5. Process the detailed app data
const result = handleEditApp(detailedAppData);
console.log('\n=== Final Result ===');
console.log('Expected creator name:', app.app_creator_name || app.user_name);
console.log('Expected department:', app.app_department);
console.log('Actual result creator:', result.creator);
console.log('Actual result department:', result.department);
console.log('Actual result type:', result.type);
console.log('Actual result icon:', result.icon);
console.log('Actual result iconColor:', result.iconColor);
// 6. Verify the results
const expectedCreator = app.app_creator_name || app.user_name;
const expectedDepartment = app.app_department;
console.log('\n=== Verification ===');
console.log('Creator match:', result.creator === expectedCreator ? '✅ PASS' : '❌ FAIL');
console.log('Department match:', result.department === expectedDepartment ? '✅ PASS' : '❌ FAIL');
console.log('Type conversion:', result.type !== app.type ? '✅ PASS (converted)' : '⚠️ No conversion needed');
console.log('Icon preserved:', result.icon === app.icon ? '✅ PASS' : '❌ FAIL');
console.log('IconColor preserved:', result.iconColor === app.icon_color ? '✅ PASS' : '❌ FAIL');
await connection.end();
} catch (error) {
console.error('Test failed:', error);
}
};
simulateDetailedApiResponse();

View File

@@ -1,92 +0,0 @@
// 測試詳細 API 資料結構,檢查創建者資訊
console.log('🧪 測試詳細 API 資料結構...');
// 模擬詳細 API 的資料結構(基於實際資料庫查詢結果)
const detailedAppData = {
id: "mdzncsmzelu6n5v6e5",
name: "ITBU_佩庭_天氣查詢機器人",
description: "SADSADSADASDASDASDAS",
creatorId: "user-123",
teamId: null,
status: "draft",
type: "ai_model",
filePath: null,
techStack: [],
tags: [],
screenshots: [],
demoUrl: "https://dify.theaken.com/chat/xLqNfXDQleoKGROm",
githubUrl: null,
docsUrl: null,
version: "1.0.0",
likesCount: 0,
viewsCount: 0,
rating: 0,
createdAt: "2025-08-06T07:28:50.000Z",
updatedAt: "2025-08-06T07:28:50.000Z",
lastUpdated: "2025-08-06T07:28:50.000Z",
creator: {
id: "user-123",
name: "佩庭", // 實際資料庫中的創建者名稱
email: "admin@example.com",
department: "ITBU",
role: "developer"
},
team: undefined
};
console.log('📋 詳細 API 資料結構:');
console.log('應用名稱:', detailedAppData.name);
console.log('創建者物件:', detailedAppData.creator);
console.log('創建者名稱:', detailedAppData.creator.name);
console.log('創建者部門:', detailedAppData.creator.department);
// 模擬 handleEditApp 函數處理
const handleEditApp = (app) => {
console.log('\n=== handleEditApp Debug ===');
console.log('Input app:', app);
console.log('app.creator:', app.creator);
console.log('app.creator.name:', app.creator?.name);
console.log('app.creator.department:', app.creator?.department);
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
department = app.creator.department || app.department || "";
}
const newAppData = {
name: app.name || "",
type: app.type || "",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
};
console.log('newAppData:', newAppData);
return newAppData;
};
// 測試處理
const result = handleEditApp(detailedAppData);
console.log('\n✅ 測試結果:');
console.log('期望創建者名稱: 佩庭');
console.log('實際創建者名稱:', result.creator);
console.log('期望部門: ITBU');
console.log('實際部門:', result.department);
const isCorrect = result.creator === "佩庭" && result.department === "ITBU";
console.log('✅ 測試通過:', isCorrect);
if (isCorrect) {
console.log('\n🎉 創建者資訊處理正確!');
} else {
console.log('\n❌ 創建者資訊處理有問題,需要檢查。');
}

View File

@@ -1,132 +0,0 @@
const mysql = require('mysql2/promise');
// Test the detailed API fix
const testDetailedApiFix = async () => {
try {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'ai_showcase_platform'
});
console.log('=== Testing Detailed API Fix ===\n');
// 1. Get the latest app data
const [apps] = await connection.execute(`
SELECT
a.id, a.name, a.description, a.type, a.department as app_department,
a.creator_name as app_creator_name, a.creator_email as app_creator_email,
a.icon, a.icon_color, a.status, a.created_at,
u.id as user_id, u.name as user_name, u.email as user_email, u.department as user_department
FROM apps a LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC LIMIT 1
`);
if (apps.length === 0) {
console.log('No apps found in database');
return;
}
const app = apps[0];
console.log('Database values:');
console.log('app_department:', app.app_department);
console.log('app_creator_name:', app.app_creator_name);
console.log('user_department:', app.user_department);
console.log('user_name:', app.user_name);
console.log('');
// 2. Simulate the updated detailed API response structure
const detailedAppData = {
id: app.id,
name: app.name,
description: app.description,
type: app.type,
department: app.app_department, // Now included in detailed API
icon: app.icon,
iconColor: app.icon_color,
status: app.status,
createdAt: app.created_at,
creator: {
id: app.user_id,
name: app.app_creator_name || app.user_name, // Prioritize app.creator_name
email: app.app_creator_email || app.user_email,
department: app.app_department || app.user_department, // Prioritize app.department
role: 'developer'
}
};
console.log('Simulated detailed API response:');
console.log('department:', detailedAppData.department);
console.log('creator.name:', detailedAppData.creator.name);
console.log('creator.department:', detailedAppData.creator.department);
console.log('');
// 3. Simulate handleEditApp processing
const handleEditApp = (app) => {
console.log('=== handleEditApp Processing ===');
console.log('Input app.department:', app.department);
console.log('Input app.creator:', app.creator);
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
// 優先使用應用程式的部門,而不是創建者的部門
department = app.department || app.creator.department || "";
}
const newAppData = {
name: app.name || "",
type: app.type || "文字處理",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
}
console.log('newAppData:', newAppData);
return newAppData;
};
// 4. Process the detailed app data
const result = handleEditApp(detailedAppData);
console.log('\n=== Final Result ===');
console.log('Expected creator name:', app.app_creator_name || app.user_name);
console.log('Expected department:', app.app_department);
console.log('Actual result creator:', result.creator);
console.log('Actual result department:', result.department);
// 5. Verify the results
const expectedCreator = app.app_creator_name || app.user_name;
const expectedDepartment = app.app_department;
console.log('\n=== Verification ===');
console.log('Creator match:', result.creator === expectedCreator ? '✅ PASS' : '❌ FAIL');
console.log('Department match:', result.department === expectedDepartment ? '✅ PASS' : '❌ FAIL');
if (result.creator !== expectedCreator) {
console.log('❌ Creator mismatch!');
console.log('Expected:', expectedCreator);
console.log('Actual:', result.creator);
}
if (result.department !== expectedDepartment) {
console.log('❌ Department mismatch!');
console.log('Expected:', expectedDepartment);
console.log('Actual:', result.department);
}
await connection.end();
} catch (error) {
console.error('Test failed:', error);
}
};
testDetailedApiFix();

View File

@@ -1,118 +0,0 @@
// Test the detailed API logic without database connection
const testDetailedApiLogic = () => {
console.log('=== Testing Detailed API Logic ===\n');
// Simulate the database values we expect
const mockAppData = {
app_department: 'MBU1',
app_creator_name: '佩庭',
user_department: 'ITBU',
user_name: '系統管理員'
};
console.log('Mock database values:');
console.log('app_department:', mockAppData.app_department);
console.log('app_creator_name:', mockAppData.app_creator_name);
console.log('user_department:', mockAppData.user_department);
console.log('user_name:', mockAppData.user_name);
console.log('');
// Simulate the updated detailed API response structure
const detailedAppData = {
id: 1,
name: 'Test App',
description: 'Test Description',
type: 'productivity',
department: mockAppData.app_department, // Now included in detailed API
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500',
status: 'published',
createdAt: '2024-01-01',
creator: {
id: 1,
name: mockAppData.app_creator_name || mockAppData.user_name, // Prioritize app.creator_name
email: 'test@example.com',
department: mockAppData.app_department || mockAppData.user_department, // Prioritize app.department
role: 'developer'
}
};
console.log('Simulated detailed API response:');
console.log('department:', detailedAppData.department);
console.log('creator.name:', detailedAppData.creator.name);
console.log('creator.department:', detailedAppData.creator.department);
console.log('');
// Simulate handleEditApp processing
const handleEditApp = (app) => {
console.log('=== handleEditApp Processing ===');
console.log('Input app.department:', app.department);
console.log('Input app.creator:', app.creator);
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
// 優先使用應用程式的部門,而不是創建者的部門
department = app.department || app.creator.department || "";
}
const newAppData = {
name: app.name || "",
type: app.type || "文字處理",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
}
console.log('newAppData:', newAppData);
return newAppData;
};
// Process the detailed app data
const result = handleEditApp(detailedAppData);
console.log('\n=== Final Result ===');
console.log('Expected creator name:', mockAppData.app_creator_name || mockAppData.user_name);
console.log('Expected department:', mockAppData.app_department);
console.log('Actual result creator:', result.creator);
console.log('Actual result department:', result.department);
// Verify the results
const expectedCreator = mockAppData.app_creator_name || mockAppData.user_name;
const expectedDepartment = mockAppData.app_department;
console.log('\n=== Verification ===');
console.log('Creator match:', result.creator === expectedCreator ? '✅ PASS' : '❌ FAIL');
console.log('Department match:', result.department === expectedDepartment ? '✅ PASS' : '❌ FAIL');
if (result.creator !== expectedCreator) {
console.log('❌ Creator mismatch!');
console.log('Expected:', expectedCreator);
console.log('Actual:', result.creator);
}
if (result.department !== expectedDepartment) {
console.log('❌ Department mismatch!');
console.log('Expected:', expectedDepartment);
console.log('Actual:', result.department);
}
console.log('\n=== Summary ===');
console.log('The detailed API should now return:');
console.log('- department: app.department (MBU1)');
console.log('- creator.name: app.creator_name (佩庭)');
console.log('- creator.department: app.department (MBU1)');
console.log('');
console.log('The handleEditApp function should extract:');
console.log('- department: app.department (MBU1)');
console.log('- creator: app.creator.name (佩庭)');
};
testDetailedApiLogic();

View File

@@ -1,155 +0,0 @@
// 模擬前端類型映射函數
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他'
};
return typeMap[apiType] || '其他';
};
// 模擬 handleEditApp 函數(修正後)
const handleEditApp = (app) => {
console.log('=== handleEditApp Debug ===');
console.log('Input app:', app);
console.log('app.type:', app.type);
console.log('app.department:', app.department);
console.log('app.creator:', app.creator);
// 處理類型轉換:如果類型是英文的,轉換為中文
let displayType = app.type;
if (app.type && !['文字處理', '圖像生成', '程式開發', '數據分析', '教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR', '機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'].includes(app.type)) {
displayType = mapApiTypeToDisplayType(app.type);
}
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
department = app.creator.department || app.department || "HQBU";
}
const newAppData = {
name: app.name,
type: displayType,
department: department || "HQBU",
creator: creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
};
console.log('newAppData:', newAppData);
return newAppData;
};
async function testEditAppConsistency() {
console.log('🧪 測試編輯應用功能一致性...\n');
// 1. 模擬列表中的應用資料(來自 loadApps
const listApp = {
id: 'test123',
name: '測試應用程式',
description: '這是一個測試應用程式',
type: '文字處理', // 已經轉換為中文
department: 'HQBU',
creator: '測試創建者',
appUrl: 'https://example.com',
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500'
};
// 2. 模擬詳細 API 返回的應用資料
const detailApp = {
id: 'test123',
name: '測試應用程式',
description: '這是一個測試應用程式',
type: 'productivity', // 英文類型
department: 'HQBU',
creator: {
id: 'user123',
name: '測試創建者',
email: 'test@example.com',
department: 'HQBU',
role: 'developer'
},
demoUrl: 'https://example.com',
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500'
};
console.log('📋 測試列表中的編輯功能:');
console.log('輸入資料:', listApp);
const listResult = handleEditApp(listApp);
console.log('處理結果:', listResult);
console.log('\n📋 測試詳細對話框中的編輯功能:');
console.log('輸入資料:', detailApp);
const detailResult = handleEditApp(detailApp);
console.log('處理結果:', detailResult);
// 3. 驗證一致性
console.log('\n✅ 一致性檢查:');
const fieldsToCheck = ['name', 'type', 'department', 'creator', 'description', 'appUrl', 'icon', 'iconColor'];
fieldsToCheck.forEach(field => {
const listValue = listResult[field];
const detailValue = detailResult[field];
const isConsistent = listValue === detailValue;
console.log(` ${field}: ${listValue} vs ${detailValue} ${isConsistent ? '✅' : '❌'}`);
});
// 4. 測試不同類型的轉換
console.log('\n🔍 測試類型轉換:');
const testTypes = [
{ apiType: 'productivity', expected: '文字處理' },
{ apiType: 'ai_model', expected: '圖像生成' },
{ apiType: 'automation', expected: '程式開發' },
{ apiType: 'data_analysis', expected: '數據分析' },
{ apiType: 'educational', expected: '教育工具' },
{ apiType: 'healthcare', expected: '健康醫療' },
{ apiType: 'finance', expected: '金融科技' },
{ apiType: 'iot_device', expected: '物聯網' },
{ apiType: 'blockchain', expected: '區塊鏈' },
{ apiType: 'ar_vr', expected: 'AR/VR' },
{ apiType: 'machine_learning', expected: '機器學習' },
{ apiType: 'computer_vision', expected: '電腦視覺' },
{ apiType: 'nlp', expected: '自然語言處理' },
{ apiType: 'robotics', expected: '機器人' },
{ apiType: 'cybersecurity', expected: '網路安全' },
{ apiType: 'cloud_service', expected: '雲端服務' },
{ apiType: 'other', expected: '其他' }
];
testTypes.forEach(({ apiType, expected }) => {
const testApp = {
...detailApp,
type: apiType
};
const result = handleEditApp(testApp);
const isCorrect = result.type === expected;
console.log(` ${apiType} -> ${result.type} ${isCorrect ? '✅' : '❌'}`);
});
console.log('\n✅ 編輯應用功能一致性測試完成!');
}
testEditAppConsistency().catch(console.error);

View File

@@ -1,210 +0,0 @@
// 測試編輯應用功能是否正確使用資料庫值而非預設值
console.log('🧪 測試編輯應用功能資料庫值處理...');
// 模擬前端類型映射函數
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他',
// 舊的英文類型映射
'web_app': '文字處理',
'mobile_app': '文字處理',
'desktop_app': '文字處理',
'api_service': '程式開發'
};
return typeMap[apiType] || '其他';
};
// 模擬修正後的 handleEditApp 函數
const handleEditApp = (app) => {
console.log('=== handleEditApp Debug ===');
console.log('Input app:', app);
console.log('app.type:', app.type);
console.log('app.department:', app.department);
console.log('app.creator:', app.creator);
console.log('app.icon:', app.icon);
console.log('app.iconColor:', app.iconColor);
// 處理類型轉換:如果類型是英文的,轉換為中文
let displayType = app.type;
if (app.type && !['文字處理', '圖像生成', '程式開發', '數據分析', '教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR', '機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'].includes(app.type)) {
displayType = mapApiTypeToDisplayType(app.type);
}
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
department = app.creator.department || app.department || "";
}
const newAppData = {
name: app.name || "",
type: displayType || "文字處理",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
};
console.log('newAppData:', newAppData);
return newAppData;
};
async function testEditAppDatabaseValues() {
console.log('\n📋 測試案例 1: 資料庫有實際值的應用程式');
// 模擬來自詳細 API 的資料(有實際資料庫值)
const appWithRealData = {
id: "test-1",
name: "真實 AI 應用",
description: "這是一個真實的應用程式",
type: "productivity", // 英文 API 類型
department: "ITBU", // 實際部門
creator: {
id: "user-1",
name: "張三", // 實際創建者名稱
email: "zhang@example.com",
department: "ITBU",
role: "developer"
},
icon: "Zap", // 實際圖示
iconColor: "from-yellow-500 to-orange-500", // 實際圖示顏色
appUrl: "https://example.com/app",
demoUrl: "https://demo.example.com"
};
const result1 = handleEditApp(appWithRealData);
console.log('\n✅ 測試案例 1 結果:');
console.log('期望: 使用資料庫的實際值');
console.log('實際結果:', result1);
// 驗證結果
const expected1 = {
name: "真實 AI 應用",
type: "文字處理", // 應該從 productivity 轉換
department: "ITBU", // 應該使用實際部門
creator: "張三", // 應該從物件提取名稱
description: "這是一個真實的應用程式",
appUrl: "https://example.com/app",
icon: "Zap", // 應該使用實際圖示
iconColor: "from-yellow-500 to-orange-500" // 應該使用實際顏色
};
const isCorrect1 = JSON.stringify(result1) === JSON.stringify(expected1);
console.log('✅ 測試案例 1 通過:', isCorrect1);
console.log('\n📋 測試案例 2: 資料庫值為空字串的應用程式');
// 模擬資料庫值為空字串的情況
const appWithEmptyData = {
id: "test-2",
name: "空值測試應用",
description: "測試空值處理",
type: "other",
department: "", // 空字串
creator: {
id: "user-2",
name: "", // 空字串
email: "test@example.com",
department: "", // 空字串
role: "user"
},
icon: "", // 空字串
iconColor: "", // 空字串
appUrl: "",
demoUrl: ""
};
const result2 = handleEditApp(appWithEmptyData);
console.log('\n✅ 測試案例 2 結果:');
console.log('期望: 保持空字串,不使用預設值');
console.log('實際結果:', result2);
// 驗證結果
const expected2 = {
name: "空值測試應用",
type: "其他",
department: "", // 應該保持空字串
creator: "", // 應該保持空字串
description: "測試空值處理",
appUrl: "",
icon: "", // 應該保持空字串
iconColor: "" // 應該保持空字串
};
const isCorrect2 = JSON.stringify(result2) === JSON.stringify(expected2);
console.log('✅ 測試案例 2 通過:', isCorrect2);
console.log('\n📋 測試案例 3: 來自列表 API 的資料(字串格式)');
// 模擬來自列表 API 的資料(字串格式)
const appFromList = {
id: "test-3",
name: "列表應用",
description: "來自列表的應用",
type: "文字處理", // 已經是中文
department: "HQBU", // 字串格式
creator: "李四", // 字串格式
icon: "Bot", // 字串格式
iconColor: "from-blue-500 to-purple-500", // 字串格式
appUrl: "https://list.example.com"
};
const result3 = handleEditApp(appFromList);
console.log('\n✅ 測試案例 3 結果:');
console.log('期望: 直接使用字串值');
console.log('實際結果:', result3);
// 驗證結果
const expected3 = {
name: "列表應用",
type: "文字處理",
department: "HQBU",
creator: "李四",
description: "來自列表的應用",
appUrl: "https://list.example.com",
icon: "Bot",
iconColor: "from-blue-500 to-purple-500"
};
const isCorrect3 = JSON.stringify(result3) === JSON.stringify(expected3);
console.log('✅ 測試案例 3 通過:', isCorrect3);
console.log('\n📊 總結:');
console.log(`✅ 測試案例 1 (實際資料庫值): ${isCorrect1 ? '通過' : '失敗'}`);
console.log(`✅ 測試案例 2 (空字串處理): ${isCorrect2 ? '通過' : '失敗'}`);
console.log(`✅ 測試案例 3 (列表資料格式): ${isCorrect3 ? '通過' : '失敗'}`);
if (isCorrect1 && isCorrect2 && isCorrect3) {
console.log('\n🎉 所有測試案例通過!編輯功能現在正確使用資料庫值而非預設值。');
} else {
console.log('\n❌ 部分測試案例失敗,需要進一步檢查。');
}
}
// 執行測試
testEditAppDatabaseValues().catch(console.error);

View File

@@ -1,142 +0,0 @@
// 測試編輯應用功能部門資訊修正
console.log('🧪 測試編輯應用功能部門資訊修正...');
// 模擬前端類型映射函數
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他'
};
return typeMap[apiType] || '其他';
};
// 模擬修正後的 handleEditApp 函數
const handleEditApp = (app) => {
console.log('=== handleEditApp Debug ===');
console.log('Input app:', app);
console.log('app.department:', app.department);
console.log('app.creator:', app.creator);
// 處理類型轉換:如果類型是英文的,轉換為中文
let displayType = app.type;
if (app.type && !['文字處理', '圖像生成', '程式開發', '數據分析', '教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR', '機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'].includes(app.type)) {
displayType = mapApiTypeToDisplayType(app.type);
}
// 處理部門和創建者資料
let department = app.department;
let creator = app.creator;
// 如果 app.creator 是物件(來自詳細 API提取名稱
if (app.creator && typeof app.creator === 'object') {
creator = app.creator.name || "";
// 優先使用應用程式的部門,而不是創建者的部門
department = app.department || app.creator.department || "";
}
const newAppData = {
name: app.name || "",
type: displayType || "文字處理",
department: department || "",
creator: creator || "",
description: app.description || "",
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "",
iconColor: app.iconColor || "",
};
console.log('newAppData:', newAppData);
return newAppData;
};
async function testEditAppDepartmentFix() {
console.log('\n📋 測試案例 1: 來自列表 API 的資料');
// 模擬來自列表 API 的資料(基於實際資料庫資料)
const listAppData = {
id: "mdzotctmlayh9u9iogt",
name: "Wu Petty",
description: "ewqewqewqewqeqwewqewq",
type: "automation",
department: "MBU1", // 應用程式的部門
creator: {
id: "admin-1754374591679",
name: "佩庭", // 創建者名稱
email: "admin@example.com",
department: "ITBU", // 創建者的部門
role: "admin"
},
icon: "Zap",
iconColor: "from-yellow-500 to-orange-500",
appUrl: "https://example.com/app"
};
const result1 = handleEditApp(listAppData);
console.log('\n✅ 測試案例 1 結果:');
console.log('期望創建者名稱: 佩庭');
console.log('實際創建者名稱:', result1.creator);
console.log('期望部門: MBU1 (應用程式部門)');
console.log('實際部門:', result1.department);
const isCorrect1 = result1.creator === "佩庭" && result1.department === "MBU1";
console.log('✅ 測試案例 1 通過:', isCorrect1);
console.log('\n📋 測試案例 2: 來自詳細 API 的資料');
// 模擬來自詳細 API 的資料
const detailAppData = {
id: "mdzotctmlayh9u9iogt",
name: "Wu Petty",
description: "ewqewqewqewqeqwewqewq",
type: "automation",
department: "MBU1", // 應用程式的部門
creator: {
id: "admin-1754374591679",
name: "佩庭",
email: "admin@example.com",
department: "ITBU", // 創建者的部門
role: "admin"
},
demoUrl: "https://example.com/demo"
};
const result2 = handleEditApp(detailAppData);
console.log('\n✅ 測試案例 2 結果:');
console.log('期望創建者名稱: 佩庭');
console.log('實際創建者名稱:', result2.creator);
console.log('期望部門: MBU1 (應用程式部門)');
console.log('實際部門:', result2.department);
const isCorrect2 = result2.creator === "佩庭" && result2.department === "MBU1";
console.log('✅ 測試案例 2 通過:', isCorrect2);
console.log('\n📊 總結:');
console.log(`✅ 測試案例 1 (列表資料): ${isCorrect1 ? '通過' : '失敗'}`);
console.log(`✅ 測試案例 2 (詳細資料): ${isCorrect2 ? '通過' : '失敗'}`);
if (isCorrect1 && isCorrect2) {
console.log('\n🎉 部門資訊修正成功!現在正確使用應用程式的部門而非創建者的部門。');
} else {
console.log('\n❌ 部分測試案例失敗,需要進一步檢查。');
}
}
// 執行測試
testEditAppDepartmentFix().catch(console.error);

View File

@@ -1,78 +0,0 @@
async function testForgotPasswordNewFlow() {
console.log('🧪 測試新的忘記密碼流程...\n');
try {
// 1. 測試忘記密碼 API
console.log('1. 測試忘記密碼 API...');
const response = await fetch('http://localhost:3000/api/auth/forgot-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ 忘記密碼 API 測試成功');
console.log('生成的重設連結:', data.resetUrl);
console.log('過期時間:', data.expiresAt);
// 解析 URL 參數
const url = new URL(data.resetUrl);
const token = url.searchParams.get('token');
const email = url.searchParams.get('email');
const mode = url.searchParams.get('mode');
const name = url.searchParams.get('name');
const department = url.searchParams.get('department');
console.log('\n📋 URL 參數解析:');
console.log('- token:', token);
console.log('- email:', email);
console.log('- mode:', mode);
console.log('- name:', name);
console.log('- department:', department);
// 2. 測試密碼重設 API
console.log('\n2. 測試密碼重設 API...');
const resetResponse = await fetch('http://localhost:3000/api/auth/reset-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: token,
password: 'newpassword123'
})
});
if (resetResponse.ok) {
const resetData = await resetResponse.json();
console.log('✅ 密碼重設 API 測試成功:', resetData);
} else {
const errorData = await resetResponse.text();
console.log('❌ 密碼重設 API 測試失敗:', resetResponse.status, errorData);
}
} else {
const errorData = await response.text();
console.log('❌ 忘記密碼 API 測試失敗:', response.status, errorData);
}
console.log('\n🎉 新流程測試完成!');
console.log('\n📝 使用方式:');
console.log('1. 用戶點擊「忘記密碼」');
console.log('2. 輸入電子郵件地址');
console.log('3. 系統生成一次性重設連結');
console.log('4. 用戶複製連結並在新視窗中開啟');
console.log('5. 在註冊頁面設定新密碼');
console.log('6. 完成密碼重設');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testForgotPasswordNewFlow();

View File

@@ -1,125 +0,0 @@
const bcrypt = require('bcryptjs');
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testForgotPassword() {
console.log('🧪 測試忘記密碼功能...\n');
try {
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 創建密碼重設表(如果不存在)
console.log('1. 創建密碼重設表...');
const createTableSQL = `
CREATE TABLE IF NOT EXISTS password_reset_tokens (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
token VARCHAR(255) NOT NULL UNIQUE,
expires_at TIMESTAMP NOT NULL,
used_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_token (token),
INDEX idx_expires_at (expires_at),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`;
await connection.execute(createTableSQL);
console.log('✅ 密碼重設表創建成功');
// 2. 測試 API 端點
console.log('\n2. 測試忘記密碼 API...');
try {
const response = await fetch('http://localhost:3000/api/auth/forgot-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ 忘記密碼 API 測試成功:', data);
} else {
const errorData = await response.text();
console.log('❌ 忘記密碼 API 測試失敗:', response.status, errorData);
}
} catch (error) {
console.log('❌ API 測試錯誤:', error.message);
}
// 3. 測試密碼重設 API
console.log('\n3. 測試密碼重設 API...');
try {
// 先創建一個測試 token
const testToken = 'test-token-' + Date.now();
const expiresAt = new Date(Date.now() + 60 * 60 * 1000); // 1 小時後過期
// 獲取測試用戶 ID
const [users] = await connection.execute('SELECT id FROM users WHERE email = ?', ['admin@ai-platform.com']);
if (users.length > 0) {
const userId = users[0].id;
// 插入測試 token
await connection.execute(`
INSERT INTO password_reset_tokens (id, user_id, token, expires_at)
VALUES (UUID(), ?, ?, ?)
`, [userId, testToken, expiresAt]);
// 測試重設密碼
const response = await fetch('http://localhost:3000/api/auth/reset-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
token: testToken,
password: 'newpassword123'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ 密碼重設 API 測試成功:', data);
} else {
const errorData = await response.text();
console.log('❌ 密碼重設 API 測試失敗:', response.status, errorData);
}
}
} catch (error) {
console.log('❌ 密碼重設 API 測試錯誤:', error.message);
}
// 4. 檢查資料庫狀態
console.log('\n4. 檢查資料庫狀態...');
const [tokens] = await connection.execute(`
SELECT COUNT(*) as count FROM password_reset_tokens
`);
console.log('密碼重設 tokens 數量:', tokens[0].count);
await connection.end();
console.log('\n🎉 忘記密碼功能測試完成!');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testForgotPassword();

View File

@@ -1,83 +0,0 @@
async function testFrontendLogin() {
console.log('🧪 測試前端登入狀態...\n');
try {
// 1. 測試登入 API
console.log('1. 測試登入 API...');
const loginResponse = await fetch('http://localhost:3000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com',
password: 'admin123456'
})
});
if (loginResponse.ok) {
const loginData = await loginResponse.json();
console.log('✅ 登入 API 成功');
console.log('用戶角色:', loginData.user?.role);
// 2. 測試用戶資料 API
console.log('\n2. 測試用戶資料 API...');
const profileResponse = await fetch('http://localhost:3000/api/auth/profile', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
// 注意:這裡沒有包含認證 token因為我們沒有實現 JWT
}
});
console.log('用戶資料 API 狀態:', profileResponse.status);
if (profileResponse.ok) {
const profileData = await profileResponse.json();
console.log('✅ 用戶資料 API 成功');
console.log('用戶角色:', profileData.role);
} else {
console.log('❌ 用戶資料 API 失敗');
}
// 3. 檢查管理員頁面
console.log('\n3. 檢查管理員頁面...');
const adminResponse = await fetch('http://localhost:3000/admin');
if (adminResponse.ok) {
const pageContent = await adminResponse.text();
if (pageContent.includes('存取被拒')) {
console.log('❌ 頁面顯示存取被拒');
// 檢查調試信息
const debugMatch = pageContent.match(/調試信息: 用戶=([^,]+), 角色=([^<]+)/);
if (debugMatch) {
console.log('📋 調試信息:', {
用戶: debugMatch[1],
角色: debugMatch[2]
});
}
} else if (pageContent.includes('儀表板') || pageContent.includes('管理員')) {
console.log('✅ 管理員頁面正常顯示');
} else {
console.log('⚠️ 頁面內容不確定');
}
}
} else {
const errorData = await loginResponse.text();
console.log('❌ 登入 API 失敗:', loginResponse.status, errorData);
}
console.log('\n🎉 前端登入狀態測試完成!');
console.log('\n💡 建議:');
console.log('1. 檢查瀏覽器中的 localStorage 是否有用戶資料');
console.log('2. 確認登入後用戶狀態是否正確更新');
console.log('3. 檢查權限檢查邏輯是否正確');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testFrontendLogin();

View File

@@ -1,46 +0,0 @@
async function testHydrationFix() {
console.log('🧪 測試 Hydration 錯誤修復...\n');
try {
// 測試管理員頁面載入
console.log('1. 測試管理員頁面載入...');
const response = await fetch('http://localhost:3000/admin');
if (response.ok) {
console.log('✅ 管理員頁面載入成功');
console.log('狀態碼:', response.status);
// 檢查頁面內容是否包含修復後的邏輯
const pageContent = await response.text();
// 檢查是否包含客戶端狀態檢查
if (pageContent.includes('isClient')) {
console.log('✅ 客戶端狀態檢查已添加');
} else {
console.log('❌ 客戶端狀態檢查可能未生效');
}
// 檢查是否移除了直接的 window 檢查
if (!pageContent.includes('typeof window !== \'undefined\'')) {
console.log('✅ 直接的 window 檢查已移除');
} else {
console.log('⚠️ 可能還有直接的 window 檢查');
}
} else {
console.log('❌ 管理員頁面載入失敗:', response.status);
}
console.log('\n🎉 Hydration 錯誤修復測試完成!');
console.log('\n📋 修復內容:');
console.log('✅ 添加了 isClient 狀態來處理客戶端渲染');
console.log('✅ 移除了直接的 typeof window 檢查');
console.log('✅ 使用 useEffect 確保客戶端狀態正確設置');
console.log('✅ 防止服務器端和客戶端渲染不匹配');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testHydrationFix();

View File

@@ -1,106 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testListApiFix() {
let connection;
try {
console.log('🔍 測試列表 API 創建者資訊修正...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 模擬列表 API 的查詢
const sql = `
SELECT
a.*,
u.name as user_creator_name,
u.email as user_creator_email,
u.department as user_creator_department,
u.role as creator_role
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
ORDER BY a.created_at DESC
LIMIT 3
`;
const [apps] = await connection.execute(sql, []);
console.log('\n📊 原始資料庫查詢結果:');
apps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` ID: ${app.id}`);
console.log(` 名稱: ${app.name}`);
console.log(` creator_id: ${app.creator_id}`);
console.log(` user_creator_name: ${app.user_creator_name}`);
console.log(` user_creator_email: ${app.user_creator_email}`);
console.log(` user_creator_department: ${app.user_creator_department}`);
console.log(` department: ${app.department}`);
});
// 模擬修正後的格式化邏輯
const formattedApps = apps.map((app) => ({
id: app.id,
name: app.name,
description: app.description,
creatorId: app.creator_id,
status: app.status,
type: app.type,
icon: app.icon,
iconColor: app.icon_color,
department: app.department,
creator: {
id: app.creator_id,
name: app.user_creator_name, // 修正:直接使用 user_creator_name
email: app.user_creator_email, // 修正:直接使用 user_creator_email
department: app.department || app.user_creator_department,
role: app.creator_role
}
}));
console.log('\n📋 修正後的格式化結果:');
formattedApps.forEach((app, index) => {
console.log(`\n應用程式 ${index + 1}:`);
console.log(` 名稱: ${app.name}`);
console.log(` 創建者 ID: ${app.creator.id}`);
console.log(` 創建者名稱: ${app.creator.name}`);
console.log(` 創建者郵箱: ${app.creator.email}`);
console.log(` 創建者部門: ${app.creator.department}`);
console.log(` 應用部門: ${app.department}`);
});
// 驗證修正是否有效
const hasValidCreatorNames = formattedApps.every(app =>
app.creator.name && app.creator.name.trim() !== ''
);
console.log('\n✅ 驗證結果:');
console.log(`所有應用程式都有有效的創建者名稱: ${hasValidCreatorNames}`);
if (hasValidCreatorNames) {
console.log('🎉 列表 API 創建者資訊修正成功!');
} else {
console.log('❌ 仍有應用程式缺少創建者名稱,需要進一步檢查。');
}
} catch (error) {
console.error('❌ 測試列表 API 修正失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行測試
testListApiFix().catch(console.error);

View File

@@ -1,137 +0,0 @@
// Test script to verify modal reset fix
console.log('Testing modal reset fix...')
// Simulate the newApp state
let newApp = {
name: "",
type: "文字處理",
department: "HQBU",
creator: "",
description: "",
appUrl: "",
icon: "Bot",
iconColor: "from-blue-500 to-purple-500",
}
// Simulate the resetNewApp function
function resetNewApp() {
newApp = {
name: "",
type: "文字處理",
department: "HQBU",
creator: "",
description: "",
appUrl: "",
icon: "Bot",
iconColor: "from-blue-500 to-purple-500",
}
console.log('✅ Form reset to initial values')
}
// Simulate the handleEditApp function
function handleEditApp(app) {
console.log('📝 Editing app:', app.name)
newApp = {
name: app.name,
type: app.type,
department: app.creator?.department || app.department || "HQBU",
creator: app.creator?.name || app.creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
}
console.log('📝 Form populated with app data:', newApp)
}
// Simulate the "Add New App" button click
function handleAddNewAppClick() {
console.log(' Add New App button clicked')
console.log('📋 Form state before reset:', newApp)
resetNewApp()
console.log('📋 Form state after reset:', newApp)
}
// Test scenario 1: Edit an app, then click "Add New App"
console.log('\n=== Test Scenario 1: Edit then Add New ===')
const testApp = {
name: "Test AI App",
type: "圖像生成",
department: "ITBU",
creator: "John Doe",
description: "A test AI application",
appUrl: "https://example.com",
icon: "Brain",
iconColor: "from-purple-500 to-pink-500",
}
console.log('1. Initial form state:')
console.log(newApp)
console.log('\n2. Edit an app:')
handleEditApp(testApp)
console.log('\n3. Click "Add New App" button:')
handleAddNewAppClick()
// Test scenario 2: Multiple edits without reset
console.log('\n=== Test Scenario 2: Multiple Edits ===')
const testApp2 = {
name: "Another Test App",
type: "語音辨識",
department: "MBU1",
creator: "Jane Smith",
description: "Another test application",
appUrl: "https://test2.com",
icon: "Mic",
iconColor: "from-green-500 to-teal-500",
}
console.log('1. Edit first app:')
handleEditApp(testApp)
console.log('2. Edit second app (without reset):')
handleEditApp(testApp2)
console.log('3. Click "Add New App" button:')
handleAddNewAppClick()
// Test scenario 3: Verify reset function works correctly
console.log('\n=== Test Scenario 3: Reset Verification ===')
console.log('1. Populate form with data:')
newApp = {
name: "Some App",
type: "其他",
department: "SBU",
creator: "Test User",
description: "Test description",
appUrl: "https://test.com",
icon: "Settings",
iconColor: "from-gray-500 to-zinc-500",
}
console.log('Form populated:', newApp)
console.log('\n2. Reset form:')
resetNewApp()
console.log('Form after reset:', newApp)
// Verify all fields are reset to initial values
const expectedInitialState = {
name: "",
type: "文字處理",
department: "HQBU",
creator: "",
description: "",
appUrl: "",
icon: "Bot",
iconColor: "from-blue-500 to-purple-500",
}
const isResetCorrect = JSON.stringify(newApp) === JSON.stringify(expectedInitialState)
console.log('\n✅ Reset verification:', isResetCorrect ? 'PASSED' : 'FAILED')
if (isResetCorrect) {
console.log('🎉 All tests passed! The modal reset fix is working correctly.')
} else {
console.log('❌ Reset verification failed. Check the resetNewApp function.')
}

View File

@@ -1,47 +0,0 @@
async function testPasswordVisibility() {
console.log('🧪 測試密碼顯示/隱藏功能...\n');
try {
// 測試各個頁面是否可以正常載入
const pages = [
{ name: '註冊頁面', url: 'http://localhost:3000/register' },
{ name: '重設密碼頁面', url: 'http://localhost:3000/reset-password?token=test' },
{ name: '評審評分頁面', url: 'http://localhost:3000/judge-scoring' },
];
for (const page of pages) {
console.log(`測試 ${page.name}...`);
try {
const response = await fetch(page.url);
if (response.ok) {
console.log(`${page.name} 載入成功 (狀態碼: ${response.status})`);
} else {
console.log(`${page.name} 載入失敗 (狀態碼: ${response.status})`);
}
} catch (error) {
console.log(`${page.name} 載入錯誤: ${error.message}`);
}
}
console.log('\n🎉 密碼顯示/隱藏功能測試完成!');
console.log('\n📋 已添加密碼顯示/隱藏功能的頁面:');
console.log('✅ 註冊頁面 (app/register/page.tsx)');
console.log('✅ 登入對話框 (components/auth/login-dialog.tsx) - 已有功能');
console.log('✅ 重設密碼頁面 (app/reset-password/page.tsx) - 已有功能');
console.log('✅ 評審評分頁面 (app/judge-scoring/page.tsx)');
console.log('✅ 註冊對話框 (components/auth/register-dialog.tsx)');
console.log('✅ 系統設定頁面 (components/admin/system-settings.tsx)');
console.log('\n🔧 功能特點:');
console.log('• 眼睛圖示切換顯示/隱藏');
console.log('• 鎖頭圖示表示密碼欄位');
console.log('• 懸停效果提升用戶體驗');
console.log('• 統一的視覺設計風格');
console.log('• 支援所有密碼相關欄位');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testPasswordVisibility();

View File

@@ -1,123 +0,0 @@
const bcrypt = require('bcryptjs');
const mysql = require('mysql2/promise');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
async function testProfileUpdate() {
console.log('🧪 測試個人資料更新功能...\n');
try {
const connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 測試查詢用戶資料(包含新字段)
console.log('1. 測試查詢用戶資料...');
const [users] = await connection.execute(`
SELECT id, name, email, department, role, phone, location, bio, created_at, updated_at
FROM users
WHERE email = 'admin@ai-platform.com'
`);
if (users.length > 0) {
const user = users[0];
console.log('✅ 找到用戶:', {
name: user.name,
email: user.email,
department: user.department,
role: user.role,
phone: user.phone || '未設定',
location: user.location || '未設定',
bio: user.bio || '未設定'
});
} else {
console.log('❌ 未找到用戶');
return;
}
// 2. 測試更新個人資料
console.log('\n2. 測試更新個人資料...');
const userId = users[0].id;
const updateData = {
phone: '0912-345-678',
location: '台北市信義區',
bio: '這是系統管理員的個人簡介,負責管理整個 AI 展示平台。'
};
const [updateResult] = await connection.execute(`
UPDATE users
SET phone = ?, location = ?, bio = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`, [updateData.phone, updateData.location, updateData.bio, userId]);
console.log('更新結果:', updateResult);
// 3. 驗證更新結果
console.log('\n3. 驗證更新結果...');
const [updatedUsers] = await connection.execute(`
SELECT id, name, email, department, role, phone, location, bio, updated_at
FROM users
WHERE id = ?
`, [userId]);
if (updatedUsers.length > 0) {
const updatedUser = updatedUsers[0];
console.log('✅ 更新後的用戶資料:');
console.log(`- 姓名: ${updatedUser.name}`);
console.log(`- 電子郵件: ${updatedUser.email}`);
console.log(`- 部門: ${updatedUser.department}`);
console.log(`- 角色: ${updatedUser.role}`);
console.log(`- 電話: ${updatedUser.phone}`);
console.log(`- 地點: ${updatedUser.location}`);
console.log(`- 個人簡介: ${updatedUser.bio}`);
console.log(`- 更新時間: ${updatedUser.updated_at}`);
}
// 4. 測試 API 端點
console.log('\n4. 測試 API 端點...');
try {
const response = await fetch('http://localhost:3000/api/auth/profile', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
userId: userId,
phone: '0987-654-321',
location: '新北市板橋區',
bio: '透過 API 更新的個人簡介'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ API 更新成功:', {
name: data.user.name,
phone: data.user.phone,
location: data.user.location,
bio: data.user.bio
});
} else {
console.log('❌ API 更新失敗:', response.status, await response.text());
}
} catch (error) {
console.log('❌ API 測試錯誤:', error.message);
}
await connection.end();
console.log('\n🎉 個人資料更新測試完成!');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testProfileUpdate();

View File

@@ -1,79 +0,0 @@
async function testRoleDisplay() {
console.log('🧪 測試密碼重設頁面的角色顯示...\n');
try {
// 1. 測試忘記密碼 API
console.log('1. 測試忘記密碼 API...');
const response = await fetch('http://localhost:3000/api/auth/forgot-password', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'admin@ai-platform.com'
})
});
if (response.ok) {
const data = await response.json();
console.log('✅ 忘記密碼 API 測試成功');
console.log('生成的重設連結:', data.resetUrl);
// 解析 URL 參數
const url = new URL(data.resetUrl);
const token = url.searchParams.get('token');
const email = url.searchParams.get('email');
const mode = url.searchParams.get('mode');
const name = url.searchParams.get('name');
const department = url.searchParams.get('department');
const role = url.searchParams.get('role');
console.log('\n📋 URL 參數解析:');
console.log('- token:', token);
console.log('- email:', email);
console.log('- mode:', mode);
console.log('- name:', name);
console.log('- department:', department);
console.log('- role:', role);
// 2. 測試註冊頁面載入
console.log('\n2. 測試註冊頁面載入...');
const registerResponse = await fetch(data.resetUrl);
if (registerResponse.ok) {
console.log('✅ 註冊頁面載入成功');
console.log('狀態碼:', registerResponse.status);
// 檢查頁面內容是否包含正確的角色資訊
const pageContent = await registerResponse.text();
if (pageContent.includes('管理員') && role === 'admin') {
console.log('✅ 角色顯示正確:管理員');
} else if (pageContent.includes('一般用戶') && role === 'user') {
console.log('✅ 角色顯示正確:一般用戶');
} else if (pageContent.includes('開發者') && role === 'developer') {
console.log('✅ 角色顯示正確:開發者');
} else {
console.log('❌ 角色顯示可能有問題');
console.log('頁面包含的角色文字:', pageContent.match(/管理員|一般用戶|開發者/g));
}
} else {
console.log('❌ 註冊頁面載入失敗:', registerResponse.status);
}
} else {
const errorData = await response.text();
console.log('❌ 忘記密碼 API 測試失敗:', response.status, errorData);
}
console.log('\n🎉 角色顯示測試完成!');
console.log('\n📋 修復內容:');
console.log('✅ 忘記密碼 API 現在包含用戶角色資訊');
console.log('✅ 註冊頁面從 URL 參數獲取正確角色');
console.log('✅ 角色顯示基於資料庫中的實際角色');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testRoleDisplay();

View File

@@ -1,165 +0,0 @@
// Test script to check type conversion and identify English types
console.log('Testing type conversion functions...')
// Simulate the type mapping functions from app-management.tsx
const mapTypeToApiType = (frontendType) => {
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
}
return typeMap[frontendType] || 'other'
}
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
// 處理舊的英文類型,確保它們都轉換為中文
'web_app': '文字處理',
'mobile_app': '文字處理',
'desktop_app': '文字處理',
'api_service': '程式開發',
'other': '其他'
}
return typeMap[apiType] || '其他'
}
// Test different scenarios
console.log('\n=== Testing Type Conversion ===')
// Test 1: Check if there are any English types that might slip through
const possibleEnglishTypes = [
'web_app', 'mobile_app', 'desktop_app', 'api_service', 'ai_model',
'data_analysis', 'automation', 'other', 'productivity', 'educational',
'healthcare', 'finance', 'iot_device', 'blockchain', 'ar_vr',
'machine_learning', 'computer_vision', 'nlp', 'robotics', 'cybersecurity',
'cloud_service'
]
console.log('\n1. Testing English API types:')
possibleEnglishTypes.forEach(englishType => {
const chineseType = mapApiTypeToDisplayType(englishType)
console.log(` ${englishType} -> ${chineseType}`)
})
// Test 2: Check if all Chinese types map back correctly
const chineseTypes = [
'文字處理', '圖像生成', '圖像處理', '語音辨識', '推薦系統', '音樂生成',
'程式開發', '影像處理', '對話系統', '數據分析', '設計工具', '語音技術',
'教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR',
'機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'
]
console.log('\n2. Testing Chinese display types:')
chineseTypes.forEach(chineseType => {
const apiType = mapTypeToApiType(chineseType)
const backToChinese = mapApiTypeToDisplayType(apiType)
const isConsistent = chineseType === backToChinese
console.log(` ${chineseType} -> ${apiType} -> ${backToChinese} ${isConsistent ? '✅' : '❌'}`)
})
// Test 3: Check for any unmapped types
console.log('\n3. Checking for unmapped types:')
const allApiTypes = new Set(possibleEnglishTypes)
const mappedApiTypes = new Set(Object.values({
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
}))
const unmappedApiTypes = [...allApiTypes].filter(type => !mappedApiTypes.has(type))
console.log(' Unmapped API types:', unmappedApiTypes)
// Test 4: Simulate what happens when editing an app
console.log('\n4. Testing edit scenario:')
const mockApiResponse = {
apps: [
{ id: '1', name: 'Test App 1', type: 'productivity' },
{ id: '2', name: 'Test App 2', type: 'ai_model' },
{ id: '3', name: 'Test App 3', type: 'web_app' }, // This should now be handled
{ id: '4', name: 'Test App 4', type: 'mobile_app' }, // This should now be handled
{ id: '5', name: 'Test App 5', type: 'other' }
]
}
console.log(' Simulating loadApps processing:')
mockApiResponse.apps.forEach(app => {
const displayType = mapApiTypeToDisplayType(app.type)
console.log(` ${app.name}: ${app.type} -> ${displayType}`)
})
// Test 5: Test the actual database types from the update
console.log('\n5. Testing database types after update:')
const databaseTypes = [
'productivity', 'ai_model', 'automation', 'data_analysis',
'educational', 'healthcare', 'finance', 'iot_device',
'blockchain', 'ar_vr', 'machine_learning', 'computer_vision',
'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
]
console.log(' Database types conversion:')
databaseTypes.forEach(dbType => {
const displayType = mapApiTypeToDisplayType(dbType)
console.log(` ${dbType} -> ${displayType}`)
})
console.log('\n✅ Type conversion test completed!')

View File

@@ -1,139 +0,0 @@
// Test script to verify type handling in app management
console.log('Testing type handling in app management...')
// Simulate the type mapping functions
const mapApiTypeToDisplayType = (apiType) => {
const typeMap = {
'productivity': '文字處理',
'ai_model': '圖像生成',
'automation': '程式開發',
'data_analysis': '數據分析',
'educational': '教育工具',
'healthcare': '健康醫療',
'finance': '金融科技',
'iot_device': '物聯網',
'blockchain': '區塊鏈',
'ar_vr': 'AR/VR',
'machine_learning': '機器學習',
'computer_vision': '電腦視覺',
'nlp': '自然語言處理',
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
'other': '其他'
}
return typeMap[apiType] || '其他'
}
const mapTypeToApiType = (frontendType) => {
const typeMap = {
'文字處理': 'productivity',
'圖像生成': 'ai_model',
'圖像處理': 'ai_model',
'語音辨識': 'ai_model',
'推薦系統': 'ai_model',
'音樂生成': 'ai_model',
'程式開發': 'automation',
'影像處理': 'ai_model',
'對話系統': 'ai_model',
'數據分析': 'data_analysis',
'設計工具': 'productivity',
'語音技術': 'ai_model',
'教育工具': 'educational',
'健康醫療': 'healthcare',
'金融科技': 'finance',
'物聯網': 'iot_device',
'區塊鏈': 'blockchain',
'AR/VR': 'ar_vr',
'機器學習': 'machine_learning',
'電腦視覺': 'computer_vision',
'自然語言處理': 'nlp',
'機器人': 'robotics',
'網路安全': 'cybersecurity',
'雲端服務': 'cloud_service',
'其他': 'other'
}
return typeMap[frontendType] || 'other'
}
// Simulate API response
const mockApiResponse = {
apps: [
{
id: '1',
name: 'Test App',
type: 'productivity', // API type (English)
description: 'Test description',
creator: {
name: 'John Doe',
department: 'HQBU'
}
},
{
id: '2',
name: 'AI App',
type: 'ai_model', // API type (English)
description: 'AI description',
creator: {
name: 'Jane Smith',
department: 'ITBU'
}
}
]
}
// Simulate loadApps processing
console.log('=== API Response ===')
console.log('Original API data:', mockApiResponse.apps)
const formattedApps = mockApiResponse.apps.map(app => ({
...app,
type: mapApiTypeToDisplayType(app.type), // Convert to Chinese display type
creator: typeof app.creator === 'object' ? app.creator.name : app.creator,
department: typeof app.creator === 'object' ? app.creator.department : app.department
}))
console.log('=== After loadApps processing ===')
console.log('Formatted apps:', formattedApps)
// Simulate handleEditApp
const simulateHandleEditApp = (app) => {
console.log('=== handleEditApp simulation ===')
console.log('Input app:', app)
const newApp = {
name: app.name,
type: app.type, // This should be the Chinese display type
department: app.department || "HQBU",
creator: app.creator || "",
description: app.description,
appUrl: app.appUrl || app.demoUrl || "",
icon: app.icon || "Bot",
iconColor: app.iconColor || "from-blue-500 to-purple-500",
}
console.log('newApp after handleEditApp:', newApp)
return newApp
}
// Test both apps
console.log('\n=== Testing handleEditApp for both apps ===')
formattedApps.forEach((app, index) => {
console.log(`\n--- App ${index + 1} ---`)
const newApp = simulateHandleEditApp(app)
console.log('Final newApp.type:', newApp.type)
console.log('Is this a valid Select value?', ['文字處理', '圖像生成', '程式開發', '數據分析', '教育工具', '健康醫療', '金融科技', '物聯網', '區塊鏈', 'AR/VR', '機器學習', '電腦視覺', '自然語言處理', '機器人', '網路安全', '雲端服務', '其他'].includes(newApp.type))
})
// Test the reverse mapping for update
console.log('\n=== Testing update mapping ===')
formattedApps.forEach((app, index) => {
console.log(`\n--- App ${index + 1} update test ---`)
const displayType = app.type
const apiType = mapTypeToApiType(displayType)
console.log('Display type:', displayType)
console.log('Mapped to API type:', apiType)
console.log('Round trip test:', mapApiTypeToDisplayType(apiType) === displayType)
})
console.log('\n=== Test completed ===')

View File

@@ -1,78 +0,0 @@
async function testUserManagementIntegration() {
console.log('🧪 測試用戶管理與資料庫整合...\n');
try {
// 1. 測試獲取用戶列表 API
console.log('1. 測試獲取用戶列表 API...');
const usersResponse = await fetch('http://localhost:3000/api/admin/users');
if (usersResponse.ok) {
const usersData = await usersResponse.json();
console.log('✅ 用戶列表 API 成功');
console.log('用戶數量:', usersData.data?.users?.length || 0);
console.log('統計數據:', {
總用戶數: usersData.data?.stats?.totalUsers || 0,
活躍用戶: usersData.data?.stats?.activeUsers || 0,
管理員: usersData.data?.stats?.adminCount || 0,
開發者: usersData.data?.stats?.developerCount || 0,
非活躍用戶: usersData.data?.stats?.inactiveUsers || 0,
本月新增: usersData.data?.stats?.newThisMonth || 0
});
} else {
console.log('❌ 用戶列表 API 失敗:', usersResponse.status);
const errorData = await usersResponse.text();
console.log('錯誤信息:', errorData);
}
// 2. 測試邀請用戶 API
console.log('\n2. 測試邀請用戶 API...');
const inviteResponse = await fetch('http://localhost:3000/api/admin/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'test@example.com',
role: 'user'
})
});
if (inviteResponse.ok) {
const inviteData = await inviteResponse.json();
console.log('✅ 邀請用戶 API 成功');
console.log('邀請連結:', inviteData.data?.invitationLink);
} else {
const errorData = await inviteResponse.text();
console.log('❌ 邀請用戶 API 失敗:', inviteResponse.status, errorData);
}
// 3. 測試管理員頁面載入
console.log('\n3. 測試管理員頁面載入...');
const adminResponse = await fetch('http://localhost:3000/admin');
if (adminResponse.ok) {
console.log('✅ 管理員頁面載入成功');
const pageContent = await adminResponse.text();
if (pageContent.includes('用戶管理')) {
console.log('✅ 用戶管理頁面正常顯示');
} else {
console.log('⚠️ 用戶管理頁面可能未正常顯示');
}
} else {
console.log('❌ 管理員頁面載入失敗:', adminResponse.status);
}
console.log('\n🎉 用戶管理整合測試完成!');
console.log('\n📋 整合內容:');
console.log('✅ 創建了用戶管理 API 端點');
console.log('✅ 更新了 UserService 以支持管理功能');
console.log('✅ 連接了前端組件與後端 API');
console.log('✅ 實現了真實的數據載入和統計');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
testUserManagementIntegration();

View File

@@ -1,41 +0,0 @@
const { UserService } = require('./lib/services/database-service');
async function testUserService() {
console.log('🧪 測試 UserService...\n');
try {
const userService = new UserService();
console.log('✅ UserService 實例創建成功');
// 測試 getUserStats
console.log('\n1. 測試 getUserStats...');
const stats = await userService.getUserStats();
console.log('✅ getUserStats 成功:', stats);
// 測試 findAll
console.log('\n2. 測試 findAll...');
const result = await userService.findAll({
page: 1,
limit: 10
});
console.log('✅ findAll 成功:', {
用戶數量: result.users.length,
總數: result.total
});
if (result.users.length > 0) {
console.log('第一個用戶:', {
id: result.users[0].id,
name: result.users[0].name,
email: result.users[0].email,
role: result.users[0].role
});
}
} catch (error) {
console.error('❌ UserService 測試失敗:', error.message);
console.error('詳細錯誤:', error);
}
}
testUserService();

View File

@@ -1,120 +0,0 @@
const mysql = require('mysql2/promise');
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00'
};
// Type mapping for converting old types to new types
const typeMapping = {
'web_app': 'productivity',
'mobile_app': 'productivity',
'desktop_app': 'productivity',
'api_service': 'automation',
'ai_model': 'ai_model',
'data_analysis': 'data_analysis',
'automation': 'automation',
'other': 'other'
};
async function updateAppTypes() {
let connection;
try {
console.log('🔄 開始更新應用程式類型...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 檢查現有的類型分佈
console.log('\n📊 檢查現有類型分佈:');
const [typeStats] = await connection.execute(`
SELECT type, COUNT(*) as count
FROM apps
WHERE type IS NOT NULL
GROUP BY type
`);
typeStats.forEach(row => {
console.log(` ${row.type}: ${row.count} 個應用程式`);
});
// 2. 更新現有數據的類型
console.log('\n🔄 更新現有應用程式的類型...');
for (const [oldType, newType] of Object.entries(typeMapping)) {
if (oldType !== newType) {
const [result] = await connection.execute(
'UPDATE apps SET type = ? WHERE type = ?',
[newType, oldType]
);
if (result.affectedRows > 0) {
console.log(` ✅ 將 ${oldType} 更新為 ${newType}: ${result.affectedRows} 個應用程式`);
}
}
}
// 3. 修改 type 欄位的 ENUM 定義
console.log('\n🔧 更新 type 欄位的 ENUM 定義...');
try {
// 先刪除舊的 ENUM 約束
await connection.execute(`
ALTER TABLE apps
MODIFY COLUMN type VARCHAR(50) DEFAULT 'other'
`);
console.log(' ✅ 移除舊的 ENUM 約束');
// 添加新的 ENUM 約束
await connection.execute(`
ALTER TABLE apps
MODIFY COLUMN type ENUM(
'productivity', 'ai_model', 'automation', 'data_analysis',
'educational', 'healthcare', 'finance', 'iot_device',
'blockchain', 'ar_vr', 'machine_learning', 'computer_vision',
'nlp', 'robotics', 'cybersecurity', 'cloud_service', 'other'
) DEFAULT 'other'
`);
console.log(' ✅ 添加新的 ENUM 約束');
} catch (error) {
console.error(' ❌ 更新 ENUM 約束失敗:', error.message);
}
// 4. 檢查更新後的類型分佈
console.log('\n📊 更新後的類型分佈:');
const [newTypeStats] = await connection.execute(`
SELECT type, COUNT(*) as count
FROM apps
WHERE type IS NOT NULL
GROUP BY type
`);
newTypeStats.forEach(row => {
console.log(` ${row.type}: ${row.count} 個應用程式`);
});
// 5. 檢查表格結構
console.log('\n📋 apps 表格結構:');
const [columns] = await connection.execute('DESCRIBE apps');
columns.forEach(col => {
if (col.Field === 'type') {
console.log(` ${col.Field}: ${col.Type} ${col.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
}
});
console.log('\n✅ 應用程式類型更新完成!');
} catch (error) {
console.error('❌ 更新應用程式類型失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
updateAppTypes().catch(console.error);