優化應用 APP 新增、編輯邏輯

This commit is contained in:
2025-08-06 16:33:11 +08:00
parent dc4594a4cd
commit af88c0f037
100 changed files with 5592 additions and 7160 deletions

View File

@@ -0,0 +1,67 @@
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

@@ -0,0 +1,104 @@
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,42 +0,0 @@
const mysql = require('mysql2/promise');
async function checkAdminPasswords() {
console.log('=== 檢查管理員密碼 ===');
try {
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 資料庫連接成功');
// 查詢管理員用戶
const [rows] = await connection.execute(`
SELECT id, name, email, role, password_hash, created_at
FROM users
WHERE role = 'admin'
ORDER BY created_at DESC
`);
console.log(`\n找到 ${rows.length} 個管理員用戶:`);
for (const user of rows) {
console.log(`\n用戶ID: ${user.id}`);
console.log(`姓名: ${user.name}`);
console.log(`郵箱: ${user.email}`);
console.log(`角色: ${user.role}`);
console.log(`密碼雜湊: ${user.password_hash.substring(0, 20)}...`);
console.log(`創建時間: ${user.created_at}`);
}
await connection.end();
} catch (error) {
console.error('❌ 資料庫連接失敗:', error.message);
}
}
checkAdminPasswords().catch(console.error);

136
scripts/check-app-types.js Normal file
View File

@@ -0,0 +1,136 @@
// 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,49 +0,0 @@
const mysql = require('mysql2/promise');
async function checkAppsCount() {
try {
// 連接資料庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('=== 檢查應用程式數量 ===');
// 檢查總數
const [totalRows] = await connection.execute('SELECT COUNT(*) as total FROM apps');
console.log('總應用程式數量:', totalRows[0].total);
// 檢查各狀態的數量
const [statusRows] = await connection.execute(`
SELECT status, COUNT(*) as count
FROM apps
GROUP BY status
`);
console.log('各狀態數量:');
statusRows.forEach(row => {
console.log(` ${row.status}: ${row.count}`);
});
// 檢查最近的應用程式
const [recentRows] = await connection.execute(`
SELECT id, name, status, created_at
FROM apps
ORDER BY created_at DESC
LIMIT 5
`);
console.log('最近的應用程式:');
recentRows.forEach(row => {
console.log(` ${row.name} (${row.status}) - ${row.created_at}`);
});
await connection.end();
} catch (error) {
console.error('檢查失敗:', error);
}
}
checkAppsCount();

View File

@@ -1,44 +0,0 @@
const mysql = require('mysql2/promise');
async function checkAppsTable() {
const connection = await mysql.createConnection({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'ai_showcase_platform'
});
try {
console.log('檢查 apps 表格結構...');
// 檢查表格結構
const [columns] = await connection.execute('DESCRIBE apps');
console.log('\napps 表格欄位:');
columns.forEach(col => {
console.log(`- ${col.Field}: ${col.Type} ${col.Null === 'NO' ? 'NOT NULL' : 'NULL'} ${col.Default ? `DEFAULT ${col.Default}` : ''}`);
});
// 檢查是否有資料
const [rows] = await connection.execute('SELECT COUNT(*) as count FROM apps');
console.log(`\napps 表格資料筆數: ${rows[0].count}`);
if (rows[0].count > 0) {
// 顯示前幾筆資料
const [sampleData] = await connection.execute('SELECT * FROM apps LIMIT 3');
console.log('\n前 3 筆資料:');
sampleData.forEach((row, index) => {
console.log(`\n${index + 1} 筆:`);
Object.keys(row).forEach(key => {
console.log(` ${key}: ${row[key]}`);
});
});
}
} catch (error) {
console.error('檢查失敗:', error);
} finally {
await connection.end();
}
}
checkAppsTable();

View File

@@ -1,53 +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 checkDatabase() {
let connection;
try {
console.log('🔍 檢查資料庫表結構...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查 apps 表結構
console.log('\n📋 Apps 表結構:');
const [appsStructure] = await connection.execute('DESCRIBE apps');
console.table(appsStructure);
// 檢查 apps 表資料
console.log('\n📊 Apps 表資料:');
const [appsData] = await connection.execute('SELECT id, name, type, status, creator_id FROM apps LIMIT 5');
console.table(appsData);
// 檢查 users 表結構
console.log('\n👥 Users 表結構:');
const [usersStructure] = await connection.execute('DESCRIBE users');
console.table(usersStructure);
// 檢查是否有開發者或管理員用戶
console.log('\n🔑 檢查開發者/管理員用戶:');
const [adminUsers] = await connection.execute('SELECT id, name, email, role FROM users WHERE role IN ("developer", "admin")');
console.table(adminUsers);
console.log('\n✅ 資料庫檢查完成');
} catch (error) {
console.error('❌ 檢查失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
checkDatabase();

View File

@@ -0,0 +1,99 @@
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,61 +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 checkTeamsTable() {
let connection;
try {
console.log('🔍 檢查 teams 表...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查所有表
console.log('\n📋 所有表:');
const [tables] = await connection.execute('SHOW TABLES');
console.table(tables);
// 檢查 teams 表是否存在
console.log('\n🔍 檢查 teams 表是否存在...');
const [teamsTable] = await connection.execute("SHOW TABLES LIKE 'teams'");
if (teamsTable.length > 0) {
console.log('✅ teams 表存在');
// 檢查 teams 表結構
console.log('\n📋 Teams 表結構:');
const [teamsStructure] = await connection.execute('DESCRIBE teams');
console.table(teamsStructure);
// 檢查 teams 表資料
console.log('\n📊 Teams 表資料:');
const [teamsData] = await connection.execute('SELECT * FROM teams LIMIT 5');
console.table(teamsData);
} else {
console.log('❌ teams 表不存在');
}
// 測試簡單的 apps 查詢
console.log('\n🧪 測試簡單的 apps 查詢...');
const [appsData] = await connection.execute('SELECT id, name, type, status, creator_id FROM apps LIMIT 5');
console.table(appsData);
} catch (error) {
console.error('❌ 檢查失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
checkTeamsTable();

View File

@@ -1,52 +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 checkUserPasswords() {
let connection;
try {
console.log('🔍 檢查用戶密碼...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查用戶密碼哈希
console.log('\n📊 用戶密碼哈希:');
const [users] = await connection.execute('SELECT id, name, email, password_hash FROM users');
for (const user of users) {
console.log(`\n用戶: ${user.name} (${user.email})`);
console.log(`密碼哈希: ${user.password_hash}`);
// 測試一些常見密碼
const testPasswords = ['Admin123', 'admin123', 'password', '123456', 'admin'];
for (const password of testPasswords) {
const isValid = await bcrypt.compare(password, user.password_hash);
if (isValid) {
console.log(`✅ 找到正確密碼: ${password}`);
break;
}
}
}
} catch (error) {
console.error('❌ 檢查失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
checkUserPasswords();

View File

@@ -1,65 +0,0 @@
const mysql = require('mysql2/promise');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function checkUsers() {
try {
// 連接資料庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('=== 檢查用戶 ===');
// 檢查用戶
const [userRows] = await connection.execute('SELECT id, email, name, role FROM users LIMIT 5');
console.log('用戶列表:');
userRows.forEach(user => {
console.log(` ID: ${user.id}, Email: ${user.email}, Name: ${user.name}, Role: ${user.role}`);
});
// 為第一個用戶生成 token
if (userRows.length > 0) {
const user = userRows[0];
const token = jwt.sign({
userId: user.id,
email: user.email,
role: user.role
}, JWT_SECRET, { expiresIn: '1h' });
console.log('\n生成的 Token:');
console.log(token);
// 測試 API
console.log('\n=== 測試 API ===');
const response = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const data = await response.json();
console.log('✅ API 回應成功');
console.log('分頁資訊:', data.pagination);
console.log('統計資訊:', data.stats);
console.log(`應用程式數量: ${data.apps?.length || 0}`);
} else {
console.log('❌ API 回應失敗:', response.status, response.statusText);
const errorText = await response.text();
console.log('錯誤詳情:', errorText);
}
}
await connection.end();
} catch (error) {
console.error('檢查失敗:', error);
}
}
checkUsers();

View File

@@ -1,134 +0,0 @@
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
// 資料庫配置
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'
};
// 生成 UUID
function generateId() {
return crypto.randomUUID();
}
// 加密密碼
async function hashPassword(password) {
const saltRounds = 12;
return await bcrypt.hash(password, saltRounds);
}
async function createAdmin() {
let connection;
try {
console.log('🔌 連接資料庫...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 管理員資料
const adminData = {
id: generateId(),
name: 'AI平台管理員',
email: 'admin@theaken.com',
password: 'Admin@2024',
department: '資訊技術部',
role: 'admin'
};
console.log('\n📋 準備建立管理員帳號:');
console.log(` 姓名: ${adminData.name}`);
console.log(` 電子郵件: ${adminData.email}`);
console.log(` 部門: ${adminData.department}`);
console.log(` 角色: ${adminData.role}`);
// 檢查是否已存在
const [existingUser] = await connection.execute(
'SELECT id FROM users WHERE email = ?',
[adminData.email]
);
if (existingUser.length > 0) {
console.log('\n⚠ 管理員帳號已存在,更新密碼...');
// 加密新密碼
const passwordHash = await hashPassword(adminData.password);
// 更新密碼
await connection.execute(
'UPDATE users SET password_hash = ?, updated_at = NOW() WHERE email = ?',
[passwordHash, adminData.email]
);
console.log('✅ 管理員密碼已更新');
} else {
console.log('\n📝 建立新的管理員帳號...');
// 加密密碼
const passwordHash = await hashPassword(adminData.password);
// 插入管理員資料
await connection.execute(`
INSERT INTO users (
id, name, email, password_hash, department, role,
join_date, total_likes, total_views, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, CURDATE(), 0, 0, NOW(), NOW())
`, [
adminData.id,
adminData.name,
adminData.email,
passwordHash,
adminData.department,
adminData.role
]);
console.log('✅ 管理員帳號建立成功');
}
// 驗證建立結果
console.log('\n🔍 驗證管理員帳號...');
const [adminUser] = await connection.execute(
'SELECT id, name, email, department, role, created_at FROM users WHERE email = ?',
[adminData.email]
);
if (adminUser.length > 0) {
const user = adminUser[0];
console.log('✅ 管理員帳號驗證成功:');
console.log(` ID: ${user.id}`);
console.log(` 姓名: ${user.name}`);
console.log(` 電子郵件: ${user.email}`);
console.log(` 部門: ${user.department}`);
console.log(` 角色: ${user.role}`);
console.log(` 建立時間: ${user.created_at}`);
}
console.log('\n🎉 管理員帳號設定完成!');
console.log('\n📋 登入資訊:');
console.log(` 電子郵件: ${adminData.email}`);
console.log(` 密碼: ${adminData.password}`);
console.log('\n⚠ 請妥善保管登入資訊,建議在首次登入後更改密碼');
} catch (error) {
console.error('❌ 建立管理員帳號失敗:', error.message);
process.exit(1);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 如果直接執行此腳本
if (require.main === module) {
createAdmin();
}
module.exports = { createAdmin };

View File

@@ -51,6 +51,12 @@ async function fixAppsTable() {
// 添加版本欄位
`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`
];

View File

@@ -1,80 +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 fixUserLikes() {
let connection;
try {
console.log('🔧 修復 user_likes 表...');
// 連接資料庫
connection = await mysql.createConnection(dbConfig);
// 先刪除可能存在的表
try {
await connection.query('DROP TABLE IF EXISTS user_likes');
console.log('✅ 刪除舊的 user_likes 表');
} catch (error) {
console.log('沒有舊表需要刪除');
}
// 建立簡化版的 user_likes 表
const userLikesTable = `
CREATE TABLE 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,
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 表建立成功');
// 驗證結果
const [tables] = await connection.query(`
SELECT TABLE_NAME, TABLE_ROWS
FROM information_schema.tables
WHERE table_schema = '${dbConfig.database}' AND TABLE_NAME = 'user_likes'
`);
if (tables.length > 0) {
console.log('✅ user_likes 表驗證成功');
} else {
console.log('❌ user_likes 表建立失敗');
}
} catch (error) {
console.error('❌ 修復 user_likes 表失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 資料庫連接已關閉');
}
}
}
// 執行修復腳本
if (require.main === module) {
fixUserLikes();
}
module.exports = { fixUserLikes };

View File

@@ -1,64 +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 resetUserPassword() {
let connection;
try {
console.log('🔧 重置用戶密碼...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 新密碼
const newPassword = 'Admin123';
const hashedPassword = await bcrypt.hash(newPassword, 12);
console.log(`\n新密碼: ${newPassword}`);
console.log(`密碼哈希: ${hashedPassword}`);
// 重置所有管理員用戶的密碼
const adminEmails = [
'admin@theaken.com',
'admin@example.com',
'petty091901@gmail.com'
];
for (const email of adminEmails) {
try {
await connection.execute(
'UPDATE users SET password_hash = ? WHERE email = ?',
[hashedPassword, email]
);
console.log(`✅ 已重置 ${email} 的密碼`);
} catch (error) {
console.error(`❌ 重置 ${email} 密碼失敗:`, error.message);
}
}
console.log('\n🎉 密碼重置完成!');
console.log('現在可以使用以下憑證登入:');
console.log('電子郵件: admin@theaken.com');
console.log('密碼: Admin123');
} catch (error) {
console.error('❌ 重置失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
resetUserPassword();

View File

@@ -1,491 +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 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 sqlStatements = [
// 1. 用戶表
`CREATE TABLE IF NOT EXISTS users (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
avatar VARCHAR(500),
department VARCHAR(100) NOT NULL,
role ENUM('user', 'developer', 'admin') DEFAULT 'user',
join_date DATE NOT NULL,
total_likes INT DEFAULT 0,
total_views INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_email (email),
INDEX idx_department (department),
INDEX idx_role (role)
)`,
// 2. 競賽表
`CREATE TABLE IF NOT EXISTS competitions (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(200) NOT NULL,
year INT NOT NULL,
month INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
status ENUM('upcoming', 'active', 'judging', 'completed') DEFAULT 'upcoming',
description TEXT,
type ENUM('individual', 'team', 'mixed', 'proposal') NOT NULL,
evaluation_focus TEXT,
max_team_size INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_status (status),
INDEX idx_type (type),
INDEX idx_year_month (year, month),
INDEX idx_dates (start_date, end_date)
)`,
// 3. 評審表
`CREATE TABLE IF NOT EXISTS judges (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
title VARCHAR(100) NOT NULL,
department VARCHAR(100) NOT NULL,
expertise JSON,
avatar VARCHAR(500),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_department (department)
)`,
// 4. 團隊表
`CREATE TABLE IF NOT EXISTS teams (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(200) NOT NULL,
leader_id VARCHAR(36) NOT NULL,
department VARCHAR(100) NOT NULL,
contact_email VARCHAR(255) NOT NULL,
total_likes INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (leader_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_department (department),
INDEX idx_leader (leader_id)
)`,
// 5. 團隊成員表
`CREATE TABLE IF NOT EXISTS team_members (
id VARCHAR(36) PRIMARY KEY,
team_id VARCHAR(36) NOT NULL,
user_id VARCHAR(36) NOT NULL,
role VARCHAR(50) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE KEY unique_team_user (team_id, user_id),
INDEX idx_team (team_id),
INDEX idx_user (user_id)
)`,
// 6. 應用表
`CREATE TABLE IF NOT EXISTS apps (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(200) NOT NULL,
description TEXT,
creator_id VARCHAR(36) NOT NULL,
team_id VARCHAR(36),
likes_count INT DEFAULT 0,
views_count INT DEFAULT 0,
rating DECIMAL(3,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL,
INDEX idx_creator (creator_id),
INDEX idx_team (team_id),
INDEX idx_rating (rating),
INDEX idx_likes (likes_count)
)`,
// 7. 提案表
`CREATE TABLE IF NOT EXISTS proposals (
id VARCHAR(36) PRIMARY KEY,
title VARCHAR(200) NOT NULL,
description TEXT,
creator_id VARCHAR(36) NOT NULL,
team_id VARCHAR(36),
status ENUM('draft', 'submitted', 'under_review', 'approved', 'rejected') DEFAULT 'draft',
likes_count INT DEFAULT 0,
views_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL,
INDEX idx_creator (creator_id),
INDEX idx_status (status)
)`,
// 8. 評分表
`CREATE TABLE IF NOT EXISTS judge_scores (
id VARCHAR(36) PRIMARY KEY,
judge_id VARCHAR(36) NOT NULL,
app_id VARCHAR(36),
proposal_id VARCHAR(36),
scores JSON NOT NULL,
comments TEXT,
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (judge_id) REFERENCES judges(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_judge_app (judge_id, app_id),
UNIQUE KEY unique_judge_proposal (judge_id, proposal_id),
INDEX idx_judge (judge_id),
INDEX idx_app (app_id),
INDEX idx_proposal (proposal_id)
)`,
// 9. 獎項表
`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,
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)
)`,
// 10. 聊天會話表
`CREATE TABLE IF NOT EXISTS chat_sessions (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user (user_id),
INDEX idx_created (created_at)
)`,
// 11. 聊天訊息表
`CREATE TABLE IF NOT EXISTS chat_messages (
id VARCHAR(36) PRIMARY KEY,
session_id VARCHAR(36) NOT NULL,
text TEXT NOT NULL,
sender ENUM('user', 'bot') NOT NULL,
quick_questions JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES chat_sessions(id) ON DELETE CASCADE,
INDEX idx_session (session_id),
INDEX idx_created (created_at)
)`,
// 12. AI助手配置表
`CREATE TABLE IF NOT EXISTS ai_assistant_configs (
id VARCHAR(36) PRIMARY KEY,
api_key VARCHAR(255) NOT NULL,
api_url VARCHAR(500) NOT NULL,
model VARCHAR(100) NOT NULL,
max_tokens INT DEFAULT 200,
temperature DECIMAL(3,2) DEFAULT 0.7,
system_prompt TEXT NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_active (is_active)
)`,
// 13. 用戶收藏表
`CREATE TABLE IF NOT EXISTS user_favorites (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
app_id VARCHAR(36),
proposal_id VARCHAR(36),
created_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 (user_id, app_id),
UNIQUE KEY unique_user_proposal (user_id, proposal_id),
INDEX idx_user (user_id)
)`,
// 14. 用戶按讚表
`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)
)`,
// 15. 競賽參與表
`CREATE TABLE IF NOT EXISTS competition_participants (
id VARCHAR(36) PRIMARY KEY,
competition_id VARCHAR(36) NOT NULL,
user_id VARCHAR(36),
team_id VARCHAR(36),
app_id VARCHAR(36),
proposal_id VARCHAR(36),
status ENUM('registered', 'submitted', 'approved', 'rejected') DEFAULT 'registered',
registered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (competition_id) REFERENCES competitions(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE,
FOREIGN KEY (app_id) REFERENCES apps(id) ON DELETE CASCADE,
FOREIGN KEY (proposal_id) REFERENCES proposals(id) ON DELETE CASCADE,
INDEX idx_competition (competition_id),
INDEX idx_user (user_id),
INDEX idx_team (team_id),
INDEX idx_status (status)
)`,
// 16. 競賽評審分配表
`CREATE TABLE IF NOT EXISTS competition_judges (
id VARCHAR(36) PRIMARY KEY,
competition_id VARCHAR(36) NOT NULL,
judge_id VARCHAR(36) NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (competition_id) REFERENCES competitions(id) ON DELETE CASCADE,
FOREIGN KEY (judge_id) REFERENCES judges(id) ON DELETE CASCADE,
UNIQUE KEY unique_competition_judge (competition_id, judge_id),
INDEX idx_competition (competition_id),
INDEX idx_judge (judge_id)
)`,
// 17. 系統設定表
`CREATE TABLE IF NOT EXISTS system_settings (
id VARCHAR(36) PRIMARY KEY,
setting_key VARCHAR(100) UNIQUE NOT NULL,
setting_value TEXT,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_key (setting_key)
)`,
// 18. 活動日誌表
`CREATE TABLE IF NOT EXISTS activity_logs (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36),
action VARCHAR(100) NOT NULL,
target_type ENUM('user', 'competition', 'app', 'proposal', 'team', 'award') NOT NULL,
target_id VARCHAR(36),
details JSON,
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
INDEX idx_user (user_id),
INDEX idx_action (action),
INDEX idx_target (target_type, target_id),
INDEX idx_created (created_at)
)`
];
console.log(`📋 準備執行 ${sqlStatements.length} 個SQL語句`);
for (let i = 0; i < sqlStatements.length; i++) {
const statement = sqlStatements[i];
try {
console.log(`執行語句 ${i + 1}/${sqlStatements.length}: ${statement.substring(0, 50)}...`);
await connection.query(statement);
} catch (error) {
console.error(`SQL執行錯誤 (語句 ${i + 1}):`, error.message);
}
}
// 5. 插入初始數據
console.log('\n📝 插入初始數據...');
const insertStatements = [
// 插入預設管理員用戶
`INSERT IGNORE INTO users (id, name, email, password_hash, department, role, join_date) VALUES
('admin-001', '系統管理員', 'admin@theaken.com', '$2b$10$rQZ8K9mN2pL1vX3yU7wE4tA6sB8cD1eF2gH3iJ4kL5mN6oP7qR8sT9uV0wX1yZ2a', '資訊部', 'admin', '2025-01-01')`,
// 插入預設評審
`INSERT IGNORE INTO judges (id, name, title, department, expertise) VALUES
('judge-001', '張教授', '資深技術顧問', '研發部', '["AI", "機器學習", "深度學習"]'),
('judge-002', '李經理', '產品經理', '產品部', '["產品設計", "用戶體驗", "市場分析"]'),
('judge-003', '王工程師', '資深工程師', '技術部', '["軟體開發", "系統架構", "雲端技術"]')`,
// 插入預設競賽
`INSERT IGNORE INTO competitions (id, name, year, month, start_date, end_date, status, description, type, evaluation_focus, max_team_size) VALUES
('comp-2025-01', '2025年AI創新競賽', 2025, 1, '2025-01-15', '2025-03-15', 'upcoming', '年度AI技術創新競賽鼓勵員工開發創新AI應用', 'mixed', '創新性、技術實現、實用價值', 5),
('comp-2025-02', '2025年提案競賽', 2025, 2, '2025-02-01', '2025-04-01', 'upcoming', 'AI解決方案提案競賽', 'proposal', '解決方案可行性、創新程度、商業價值', NULL)`,
// 插入AI助手配置
`INSERT IGNORE INTO ai_assistant_configs (id, api_key, api_url, model, max_tokens, temperature, system_prompt, is_active) VALUES
('ai-config-001', 'your_deepseek_api_key_here', 'https://api.deepseek.com/v1/chat/completions', 'deepseek-chat', 200, 0.7, '你是一個AI展示平台的智能助手專門協助用戶使用平台功能。請用友善、專業的態度回答問題。', TRUE)`,
// 插入系統設定
`INSERT IGNORE INTO system_settings (setting_key, setting_value, description) VALUES
('daily_like_limit', '5', '用戶每日按讚限制'),
('max_team_size', '5', '最大團隊人數'),
('competition_registration_deadline', '7', '競賽報名截止天數'),
('judge_score_weight_innovation', '25', '創新性評分權重'),
('judge_score_weight_technical', '25', '技術性評分權重'),
('judge_score_weight_usability', '20', '實用性評分權重'),
('judge_score_weight_presentation', '15', '展示效果評分權重'),
('judge_score_weight_impact', '15', '影響力評分權重')`
];
for (let i = 0; i < insertStatements.length; i++) {
const statement = insertStatements[i];
try {
console.log(`插入數據 ${i + 1}/${insertStatements.length}...`);
await connection.query(statement);
} catch (error) {
console.error(`插入數據錯誤 (語句 ${i + 1}):`, error.message);
}
}
console.log('✅ 資料庫建立完成!');
// 6. 驗證建立結果
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

@@ -43,7 +43,7 @@ async function setupDatabase() {
// 4. 讀取並執行SQL腳本
console.log('📝 執行資料庫建立腳本...');
const sqlScript = fs.readFileSync(path.join(__dirname, '../database_setup_simple.sql'), 'utf8');
const sqlScript = fs.readFileSync(path.join(__dirname, '../database_setup.sql'), 'utf8');
// 分割SQL語句並執行
const statements = sqlScript

View File

@@ -1,80 +0,0 @@
const http = require('http');
// 簡單的 HTTP 請求函數
function makeSimpleRequest(url, method = 'GET', body = null) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json'
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
async function testSimple() {
console.log('🧪 簡單 API 測試...\n');
try {
// 測試健康檢查
console.log('1⃣ 測試健康檢查...');
const health = await makeSimpleRequest('http://localhost:3000/api');
console.log(` 狀態碼: ${health.status}`);
console.log(` 回應: ${JSON.stringify(health.data, null, 2)}`);
console.log('');
// 測試註冊 API
console.log('2⃣ 測試註冊 API...');
const register = await makeSimpleRequest('http://localhost:3000/api/auth/register', 'POST', {
name: '測試用戶',
email: 'test@example.com',
password: 'Test@2024',
department: '測試部門'
});
console.log(` 狀態碼: ${register.status}`);
console.log(` 回應: ${JSON.stringify(register.data, null, 2)}`);
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testSimple();

View File

@@ -1,107 +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 testAdminAppCreation() {
let connection;
try {
console.log('🧪 測試管理後台應用程式創建流程...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 創建測試用戶(管理員)
const userData = {
id: 'admin-test-' + Date.now(),
name: '管理員測試用戶',
email: 'admin-test@example.com',
password_hash: 'test_hash',
department: 'ITBU',
role: 'admin',
join_date: new Date(),
created_at: new Date(),
updated_at: new Date()
};
await connection.execute(
'INSERT INTO users (id, name, email, password_hash, department, role, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[userData.id, userData.name, userData.email, userData.password_hash, userData.department, userData.role, userData.join_date, userData.created_at, userData.updated_at]
);
console.log('✅ 測試管理員用戶創建成功');
// 模擬管理後台提交的資料
const adminAppData = {
name: '管理後台測試應用',
description: '這是一個通過管理後台創建的測試應用程式',
type: 'ai_model', // 映射後的類型
demoUrl: 'https://admin-test.example.com/demo',
version: '1.0.0'
};
console.log('📋 管理後台提交的資料:', adminAppData);
// 創建應用程式
const appId = Date.now().toString(36) + Math.random().toString(36).substr(2);
const appInsertData = {
id: appId,
name: adminAppData.name,
description: adminAppData.description,
creator_id: userData.id,
type: adminAppData.type,
demo_url: adminAppData.demoUrl,
version: adminAppData.version,
status: 'draft'
};
await connection.execute(
'INSERT INTO apps (id, name, description, creator_id, type, demo_url, version, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())',
[appInsertData.id, appInsertData.name, appInsertData.description, appInsertData.creator_id, appInsertData.type, appInsertData.demo_url, appInsertData.version, appInsertData.status]
);
console.log('✅ 應用程式創建成功');
// 查詢並顯示創建的應用程式
const [appResult] = await connection.execute(
'SELECT a.*, u.name as creator_name FROM apps a LEFT JOIN users u ON a.creator_id = u.id WHERE a.id = ?',
[appId]
);
if (appResult.length > 0) {
const app = appResult[0];
console.log('\n📋 資料庫中的應用程式資料:');
console.log(` ID: ${app.id}`);
console.log(` 名稱: ${app.name}`);
console.log(` 描述: ${app.description}`);
console.log(` 類型: ${app.type}`);
console.log(` 狀態: ${app.status}`);
console.log(` 創建者: ${app.creator_name}`);
console.log(` 演示連結: ${app.demo_url}`);
console.log(` 版本: ${app.version}`);
console.log(` 創建時間: ${app.created_at}`);
}
console.log('\n✅ 管理後台應用程式創建測試成功!');
console.log('🎯 問題已解決:管理後台現在可以正確創建應用程式並保存到資料庫');
// 清理測試資料
await connection.execute('DELETE FROM apps WHERE id = ?', [appId]);
await connection.execute('DELETE FROM users WHERE id = ?', [userData.id]);
console.log('✅ 測試資料清理完成');
} catch (error) {
console.error('❌ 測試失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testAdminAppCreation().catch(console.error);

View File

@@ -1,80 +0,0 @@
const jwt = require('jsonwebtoken');
// 使用環境變數的 JWT_SECRET
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testAdminLogin() {
console.log('=== 測試管理員登入 ===');
console.log('使用的 JWT_SECRET:', JWT_SECRET);
const adminCredentials = [
{
email: 'admin@theaken.com',
password: 'Admin123!'
},
{
email: 'admin@example.com',
password: 'Admin123!'
},
{
email: 'petty091901@gmail.com',
password: 'Admin123!'
}
];
const ports = [3000, 3002];
for (const port of ports) {
console.log(`\n=== 測試端口 ${port} ===`);
for (const cred of adminCredentials) {
console.log(`\n測試管理員: ${cred.email}`);
console.log(`使用密碼: ${cred.password}`);
try {
const response = await fetch(`http://localhost:${port}/api/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: cred.email,
password: cred.password
})
});
const data = await response.json();
if (response.ok) {
console.log('✅ 登入成功');
console.log('用戶角色:', data.user.role);
console.log('Token 長度:', data.token.length);
// 驗證 Token
try {
const decoded = jwt.verify(data.token, JWT_SECRET);
console.log('✅ Token 驗證成功');
console.log('Token 內容:', {
userId: decoded.userId,
email: decoded.email,
role: decoded.role,
exp: new Date(decoded.exp * 1000).toLocaleString()
});
} catch (tokenError) {
console.log('❌ Token 驗證失敗:', tokenError.message);
}
} else {
console.log('❌ 登入失敗');
console.log('錯誤:', data.error);
if (data.details) {
console.log('詳細錯誤:', data.details);
}
}
} catch (error) {
console.log('❌ 請求失敗:', error.message);
}
}
}
}
testAdminLogin().catch(console.error);

View File

@@ -1,104 +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 testApiError() {
let connection;
try {
console.log('🧪 測試 API 錯誤...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查 apps 表結構
const [describeResult] = await connection.execute('DESCRIBE apps');
console.log('\n📋 apps 表結構:');
describeResult.forEach(row => {
console.log(` ${row.Field}: ${row.Type} ${row.Null === 'YES' ? 'NULL' : 'NOT NULL'} ${row.Default ? `DEFAULT ${row.Default}` : ''}`);
});
// 檢查是否有管理員用戶
const [users] = await connection.execute('SELECT id, name, email, role FROM users WHERE role = "admin" LIMIT 1');
if (users.length === 0) {
console.log('\n⚠ 沒有找到管理員用戶,創建一個...');
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);
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('✅ 管理員用戶創建成功');
} else {
console.log('\n✅ 找到管理員用戶:', users[0].email);
}
// 測試直接插入應用程式
console.log('\n🧪 測試直接插入應用程式...');
const testAppData = {
id: 'test-app-' + Date.now(),
name: '測試應用',
description: '這是一個測試應用程式,用於檢查資料庫插入是否正常工作',
creator_id: users.length > 0 ? users[0].id : 'admin-' + Date.now(),
type: 'ai_model',
demo_url: 'https://test.example.com',
version: '1.0.0',
status: 'draft'
};
try {
await connection.execute(
'INSERT INTO apps (id, name, description, creator_id, type, demo_url, version, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())',
[testAppData.id, testAppData.name, testAppData.description, testAppData.creator_id, testAppData.type, testAppData.demo_url, testAppData.version, testAppData.status]
);
console.log('✅ 直接插入應用程式成功');
// 清理測試資料
await connection.execute('DELETE FROM apps WHERE id = ?', [testAppData.id]);
console.log('✅ 測試資料清理完成');
} catch (insertError) {
console.error('❌ 直接插入失敗:', insertError.message);
console.error('詳細錯誤:', insertError);
}
// 檢查資料庫連接狀態
console.log('\n🧪 檢查資料庫連接狀態...');
const [result] = await connection.execute('SELECT 1 as test');
console.log('✅ 資料庫連接正常:', result[0]);
} catch (error) {
console.error('❌ 測試失敗:', error.message);
console.error('詳細錯誤:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testApiError().catch(console.error);

View File

@@ -1,69 +0,0 @@
const http = require('http');
function makeRequest(url, method = 'GET') {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json'
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}
async function testAPI() {
try {
console.log('🧪 測試 API 可訪問性...');
// 測試根 API
console.log('\n1. 測試根 API...');
const response = await makeRequest('http://localhost:3000/api');
console.log('狀態碼:', response.status);
console.log('回應:', JSON.stringify(response.data, null, 2));
// 測試 apps API
console.log('\n2. 測試 apps API...');
const appsResponse = await makeRequest('http://localhost:3000/api/apps');
console.log('狀態碼:', appsResponse.status);
console.log('回應:', JSON.stringify(appsResponse.data, null, 2));
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testAPI();

View File

@@ -1,41 +0,0 @@
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testApiStats() {
try {
// Generate a token for admin user
const adminPayload = {
id: 1,
email: 'admin@example.com',
role: 'admin'
};
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
console.log('=== 測試 API 統計 ===');
// Test the apps API
const response = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const data = await response.json();
console.log('✅ API 回應成功');
console.log('分頁資訊:', data.pagination);
console.log('統計資訊:', data.stats);
console.log(`應用程式數量: ${data.apps?.length || 0}`);
} else {
console.log('❌ API 回應失敗:', response.status, response.statusText);
const errorText = await response.text();
console.log('錯誤詳情:', errorText);
}
} catch (error) {
console.error('測試過程中發生錯誤:', error);
}
}
testApiStats();

View File

@@ -1,154 +0,0 @@
const https = require('https');
const http = require('http');
// 測試配置
const BASE_URL = 'http://localhost:3000';
const ADMIN_EMAIL = 'admin@theaken.com';
const ADMIN_PASSWORD = 'Admin@2024';
// 測試用戶資料
const TEST_USER = {
name: '測試用戶',
email: 'test@theaken.com',
password: 'Test@2024',
department: '測試部門',
role: 'user'
};
// 發送 HTTP 請求
async function makeRequest(url, options = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const isHttps = urlObj.protocol === 'https:';
const client = isHttps ? https : http;
const requestOptions = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname + urlObj.search,
method: options.method || 'GET',
headers: {
'Content-Type': 'application/json',
...options.headers
}
};
const req = client.request(requestOptions, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
headers: res.headers,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
headers: res.headers,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
if (options.body) {
req.write(JSON.stringify(options.body));
}
req.end();
});
}
// 測試函數
async function testAPI() {
console.log('🧪 開始測試 API...\n');
try {
// 1. 測試健康檢查
console.log('1⃣ 測試健康檢查 API...');
const healthResponse = await makeRequest(`${BASE_URL}/api`);
console.log(` 狀態碼: ${healthResponse.status}`);
console.log(` 回應: ${JSON.stringify(healthResponse.data, null, 2)}`);
console.log('');
// 2. 測試註冊 API
console.log('2⃣ 測試註冊 API...');
const registerResponse = await makeRequest(`${BASE_URL}/api/auth/register`, {
method: 'POST',
body: TEST_USER
});
console.log(` 狀態碼: ${registerResponse.status}`);
console.log(` 回應: ${JSON.stringify(registerResponse.data, null, 2)}`);
console.log('');
// 3. 測試登入 API
console.log('3⃣ 測試登入 API...');
const loginResponse = await makeRequest(`${BASE_URL}/api/auth/login`, {
method: 'POST',
body: {
email: ADMIN_EMAIL,
password: ADMIN_PASSWORD
}
});
console.log(` 狀態碼: ${loginResponse.status}`);
let authToken = null;
if (loginResponse.status === 200) {
authToken = loginResponse.data.token;
console.log(` 登入成功,獲得 Token`);
} else {
console.log(` 登入失敗: ${JSON.stringify(loginResponse.data, null, 2)}`);
}
console.log('');
// 4. 測試獲取當前用戶 API
if (authToken) {
console.log('4⃣ 測試獲取當前用戶 API...');
const meResponse = await makeRequest(`${BASE_URL}/api/auth/me`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
console.log(` 狀態碼: ${meResponse.status}`);
console.log(` 回應: ${JSON.stringify(meResponse.data, null, 2)}`);
console.log('');
}
// 5. 測試用戶列表 API (需要管理員權限)
if (authToken) {
console.log('5⃣ 測試用戶列表 API...');
const usersResponse = await makeRequest(`${BASE_URL}/api/users`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
console.log(` 狀態碼: ${usersResponse.status}`);
console.log(` 回應: ${JSON.stringify(usersResponse.data, null, 2)}`);
console.log('');
}
console.log('✅ API 測試完成!');
} catch (error) {
console.error('❌ API 測試失敗:', error.message);
console.error('錯誤詳情:', error);
}
}
// 執行測試
if (require.main === module) {
testAPI();
}
module.exports = { testAPI };

View File

@@ -0,0 +1,124 @@
// 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

@@ -0,0 +1,166 @@
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,105 +0,0 @@
const http = require('http');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
// 生成測試 Token
function generateTestToken() {
return jwt.sign({
userId: 'mdxxt1xt7slle4g8wz8', // 使用現有的管理員用戶 ID
email: 'petty091901@gmail.com',
role: 'admin'
}, JWT_SECRET, { expiresIn: '1h' });
}
// 發送 HTTP 請求
function makeRequest(url, method = 'GET', body = null, headers = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json',
...headers
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
async function testAppCreation() {
try {
console.log('🧪 測試應用程式創建...');
// 生成測試 Token
const token = generateTestToken();
console.log('✅ Token 生成成功');
// 準備測試資料(模擬前端發送的資料)
const appData = {
name: 'ITBU_佩庭_天氣查詢機器人',
description: '你是一位天氣小幫手,能夠查詢世界上任何城市的目前天氣資料。',
type: 'productivity',
demoUrl: 'https://dify.theaken.com/chat/xLqNfXDQIeoKGROm',
version: '1.0.0'
};
console.log('📤 發送資料:', JSON.stringify(appData, null, 2));
// 發送請求
console.log('🔑 使用 Token:', token.substring(0, 50) + '...');
const response = await makeRequest('http://localhost:3000/api/apps', 'POST', appData, {
'Authorization': `Bearer ${token}`
});
console.log('📥 回應狀態:', response.status);
console.log('📥 回應資料:', JSON.stringify(response.data, null, 2));
if (response.status === 201) {
console.log('✅ 應用程式創建成功!');
} else {
console.log('❌ 應用程式創建失敗');
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testAppCreation();

View File

@@ -0,0 +1,101 @@
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);

98
scripts/test-app-edit.js Normal file
View File

@@ -0,0 +1,98 @@
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,156 +0,0 @@
// Simple test script for app operations
async function testAppOperations() {
console.log('🧪 開始測試應用程式操作功能...');
try {
// Test 1: Check if server is running
console.log('\n📡 測試 1: 檢查伺服器狀態');
try {
const response = await fetch('http://localhost:3000/api/apps');
if (response.ok) {
console.log('✅ 伺服器正在運行');
} else {
console.log(`❌ 伺服器回應異常: ${response.status}`);
}
} catch (error) {
console.log(`❌ 無法連接到伺服器: ${error.message}`);
console.log('💡 請確保 Next.js 開發伺服器正在運行 (npm run dev)');
return;
}
// Test 2: Test GET /api/apps (List Apps)
console.log('\n📋 測試 2: 獲取應用程式列表');
try {
const response = await fetch('http://localhost:3000/api/apps?page=1&limit=5');
if (response.ok) {
const data = await response.json();
console.log('✅ 應用程式列表獲取成功');
console.log(` - 應用程式數量: ${data.apps?.length || 0}`);
console.log(` - 總頁數: ${data.pagination?.totalPages || 0}`);
console.log(` - 總數量: ${data.pagination?.total || 0}`);
if (data.apps && data.apps.length > 0) {
const firstApp = data.apps[0];
console.log(` - 第一個應用: ${firstApp.name} (ID: ${firstApp.id})`);
// Test 3: Test GET /api/apps/[id] (View Details)
console.log('\n📖 測試 3: 查看應用程式詳情');
const detailResponse = await fetch(`http://localhost:3000/api/apps/${firstApp.id}`);
if (detailResponse.ok) {
const appDetails = await detailResponse.json();
console.log('✅ 應用程式詳情獲取成功:');
console.log(` - 名稱: ${appDetails.name}`);
console.log(` - 描述: ${appDetails.description}`);
console.log(` - 狀態: ${appDetails.status}`);
console.log(` - 類型: ${appDetails.type}`);
console.log(` - 創建者: ${appDetails.creator?.name || '未知'}`);
// Test 4: Test PUT /api/apps/[id] (Edit Application)
console.log('\n✏ 測試 4: 編輯應用程式');
const updateData = {
name: `${appDetails.name}_updated_${Date.now()}`,
description: '這是更新後的應用程式描述',
type: 'productivity'
};
const updateResponse = await fetch(`http://localhost:3000/api/apps/${firstApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(updateData)
});
if (updateResponse.ok) {
const result = await updateResponse.json();
console.log('✅ 應用程式更新成功:', result.message);
} else {
const errorData = await updateResponse.json();
console.log(`❌ 更新應用程式失敗: ${errorData.error || updateResponse.statusText}`);
}
// Test 5: Test status change (Publish/Unpublish)
console.log('\n📢 測試 5: 發布/下架應用程式');
const currentStatus = appDetails.status;
const newStatus = currentStatus === 'published' ? 'draft' : 'published';
const statusResponse = await fetch(`http://localhost:3000/api/apps/${firstApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ status: newStatus })
});
if (statusResponse.ok) {
console.log(`✅ 應用程式狀態更新成功: ${currentStatus}${newStatus}`);
} else {
const errorData = await statusResponse.json();
console.log(`❌ 狀態更新失敗: ${errorData.error || statusResponse.statusText}`);
}
// Test 6: Test DELETE /api/apps/[id] (Delete Application)
console.log('\n🗑 測試 6: 刪除應用程式');
// Create a test app to delete
const createResponse = await fetch('http://localhost:3000/api/apps', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: `Test App for Delete ${Date.now()}`,
description: 'This is a test app for deletion',
type: 'productivity',
demoUrl: 'https://example.com',
version: '1.0.0'
})
});
if (createResponse.ok) {
const newApp = await createResponse.json();
console.log(`✅ 創建測試應用程式成功 (ID: ${newApp.appId})`);
const deleteResponse = await fetch(`http://localhost:3000/api/apps/${newApp.appId}`, {
method: 'DELETE'
});
if (deleteResponse.ok) {
const result = await deleteResponse.json();
console.log('✅ 應用程式刪除成功:', result.message);
} else {
const errorData = await deleteResponse.json();
console.log(`❌ 刪除應用程式失敗: ${errorData.error || deleteResponse.statusText}`);
}
} else {
console.log('❌ 無法創建測試應用程式進行刪除測試');
}
} else {
console.log(`❌ 獲取應用程式詳情失敗: ${detailResponse.status} ${detailResponse.statusText}`);
}
} else {
console.log('⚠️ 沒有找到應用程式,跳過詳細測試');
}
} else {
const errorData = await response.json();
console.log(`❌ 獲取應用程式列表失敗: ${errorData.error || response.statusText}`);
}
} catch (error) {
console.log(`❌ 測試應用程式列表時發生錯誤: ${error.message}`);
}
console.log('\n🎉 所有測試完成!');
console.log('\n📝 測試總結:');
console.log('✅ 查看詳情功能: 已實現並測試');
console.log('✅ 編輯應用功能: 已實現並測試');
console.log('✅ 發布應用功能: 已實現並測試');
console.log('✅ 刪除應用功能: 已實現並測試');
console.log('\n💡 所有功能都已與資料庫串聯並正常工作!');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
}
}
// Run the test
testAppOperations().catch(console.error);

View File

@@ -1,222 +0,0 @@
const mysql = require('mysql2/promise');
// Database connection configuration - using environment variables directly
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'ai_showcase_platform',
port: process.env.DB_PORT || 3306
};
async function testAppOperations() {
let connection;
try {
console.log('🔗 連接到資料庫...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// Test 1: Check existing apps
console.log('\n📋 測試 1: 檢查現有應用程式');
const [apps] = await connection.execute('SELECT id, name, status, type FROM apps LIMIT 5');
console.log(`找到 ${apps.length} 個應用程式:`);
apps.forEach(app => {
console.log(` - ID: ${app.id}, 名稱: ${app.name}, 狀態: ${app.status}, 類型: ${app.type}`);
});
if (apps.length === 0) {
console.log('❌ 沒有找到應用程式,無法進行操作測試');
return;
}
const testApp = apps[0];
console.log(`\n🎯 使用應用程式進行測試: ${testApp.name} (ID: ${testApp.id})`);
// Test 2: Test GET /api/apps/[id] (View Details)
console.log('\n📖 測試 2: 查看應用程式詳情');
try {
const token = 'test-token'; // In real scenario, this would be a valid JWT
const response = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const appDetails = await response.json();
console.log('✅ 應用程式詳情獲取成功:');
console.log(` - 名稱: ${appDetails.name}`);
console.log(` - 描述: ${appDetails.description}`);
console.log(` - 狀態: ${appDetails.status}`);
console.log(` - 類型: ${appDetails.type}`);
console.log(` - 創建者: ${appDetails.creator?.name || '未知'}`);
} else {
console.log(`❌ 獲取應用程式詳情失敗: ${response.status} ${response.statusText}`);
}
} catch (error) {
console.log(`❌ 測試應用程式詳情時發生錯誤: ${error.message}`);
}
// Test 3: Test PUT /api/apps/[id] (Edit Application)
console.log('\n✏ 測試 3: 編輯應用程式');
try {
const updateData = {
name: `${testApp.name}_updated_${Date.now()}`,
description: '這是更新後的應用程式描述',
type: 'productivity'
};
const response = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(updateData)
});
if (response.ok) {
const result = await response.json();
console.log('✅ 應用程式更新成功:', result.message);
// Verify the update in database
const [updatedApp] = await connection.execute(
'SELECT name, description, type FROM apps WHERE id = ?',
[testApp.id]
);
if (updatedApp.length > 0) {
console.log('✅ 資料庫更新驗證成功:');
console.log(` - 新名稱: ${updatedApp[0].name}`);
console.log(` - 新描述: ${updatedApp[0].description}`);
console.log(` - 新類型: ${updatedApp[0].type}`);
}
} else {
const errorData = await response.json();
console.log(`❌ 更新應用程式失敗: ${errorData.error || response.statusText}`);
}
} catch (error) {
console.log(`❌ 測試應用程式更新時發生錯誤: ${error.message}`);
}
// Test 4: Test status change (Publish/Unpublish)
console.log('\n📢 測試 4: 發布/下架應用程式');
try {
const currentStatus = testApp.status;
const newStatus = currentStatus === 'published' ? 'draft' : 'published';
const response = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ status: newStatus })
});
if (response.ok) {
console.log(`✅ 應用程式狀態更新成功: ${currentStatus}${newStatus}`);
// Verify the status change in database
const [statusCheck] = await connection.execute(
'SELECT status FROM apps WHERE id = ?',
[testApp.id]
);
if (statusCheck.length > 0) {
console.log(`✅ 資料庫狀態驗證成功: ${statusCheck[0].status}`);
}
} else {
const errorData = await response.json();
console.log(`❌ 狀態更新失敗: ${errorData.error || response.statusText}`);
}
} catch (error) {
console.log(`❌ 測試狀態更新時發生錯誤: ${error.message}`);
}
// Test 5: Check app statistics
console.log('\n📊 測試 5: 檢查應用程式統計');
try {
const [stats] = await connection.execute(`
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'published' THEN 1 ELSE 0 END) as published,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
SUM(CASE WHEN status = 'draft' THEN 1 ELSE 0 END) as draft,
SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected
FROM apps
`);
console.log('✅ 應用程式統計:');
console.log(` - 總數: ${stats[0].total}`);
console.log(` - 已發布: ${stats[0].published}`);
console.log(` - 待審核: ${stats[0].pending}`);
console.log(` - 草稿: ${stats[0].draft}`);
console.log(` - 已拒絕: ${stats[0].rejected}`);
} catch (error) {
console.log(`❌ 檢查統計時發生錯誤: ${error.message}`);
}
// Test 6: Test DELETE /api/apps/[id] (Delete Application)
console.log('\n🗑 測試 6: 刪除應用程式');
// First, create a test app to delete
const [newApp] = await connection.execute(`
INSERT INTO apps (name, description, type, status, creator_id, version, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())
`, [
`Test App for Delete ${Date.now()}`,
'This is a test app for deletion',
'productivity',
'draft',
1, // Assuming user ID 1 exists
'1.0.0'
]);
const testDeleteAppId = newApp.insertId;
console.log(`✅ 創建測試應用程式成功 (ID: ${testDeleteAppId})`);
try {
const response = await fetch(`http://localhost:3000/api/apps/${testDeleteAppId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const result = await response.json();
console.log('✅ 應用程式刪除成功:', result.message);
// Verify deletion in database
const [deletedApp] = await connection.execute(
'SELECT id FROM apps WHERE id = ?',
[testDeleteAppId]
);
if (deletedApp.length === 0) {
console.log('✅ 資料庫刪除驗證成功: 應用程式已從資料庫中移除');
} else {
console.log('❌ 資料庫刪除驗證失敗: 應用程式仍然存在');
}
} else {
const errorData = await response.json();
console.log(`❌ 刪除應用程式失敗: ${errorData.error || response.statusText}`);
}
} catch (error) {
console.log(`❌ 測試應用程式刪除時發生錯誤: ${error.message}`);
}
console.log('\n🎉 所有測試完成!');
} catch (error) {
console.error('❌ 測試過程中發生錯誤:', error);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 資料庫連接已關閉');
}
}
}
// Run the test
testAppOperations().catch(console.error);

View File

@@ -0,0 +1,161 @@
// 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,88 +0,0 @@
const jwt = require('jsonwebtoken');
async function testApproval() {
console.log('🧪 測試批准功能...');
// 生成測試 token
const token = jwt.sign(
{ userId: 'admin-001', role: 'admin' },
process.env.JWT_SECRET || 'good777',
{ expiresIn: '1h' }
);
console.log('✅ Token 生成成功\n');
try {
// 首先獲取應用程式列表
const response = await fetch('http://localhost:3000/api/apps', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
console.log(`❌ 獲取應用程式失敗: ${response.status}`);
return;
}
const data = await response.json();
console.log(`✅ 獲取到 ${data.apps.length} 個應用程式`);
// 找到一個可以測試的應用程式
const testApp = data.apps[0];
if (!testApp) {
console.log('❌ 沒有找到可測試的應用程式');
return;
}
console.log(`\n測試應用程式: ${testApp.name} (ID: ${testApp.id})`);
console.log(`當前狀態: ${testApp.status}`);
// 測試批准功能
console.log('\n測試批准功能...');
const approveResponse = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
status: 'published'
})
});
if (approveResponse.ok) {
console.log('✅ 批准成功');
} else {
const errorData = await approveResponse.json();
console.log(`❌ 批准失敗: ${errorData.error}`);
}
// 測試拒絕功能
console.log('\n測試拒絕功能...');
const rejectResponse = await fetch(`http://localhost:3000/api/apps/${testApp.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
status: 'rejected'
})
});
if (rejectResponse.ok) {
console.log('✅ 拒絕成功');
} else {
const errorData = await rejectResponse.json();
console.log(`❌ 拒絕失敗: ${errorData.error}`);
}
} catch (error) {
console.log(`❌ 測試失敗: ${error.message}`);
}
console.log('\n✅ 批准測試完成');
}
testApproval();

View File

@@ -1,199 +0,0 @@
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
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 JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testAppsAPI() {
let connection;
try {
console.log('🧪 開始測試應用程式 API...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 創建測試用戶
console.log('\n1. 創建測試用戶...');
const testUserId = 'test-user-' + Date.now();
const hashedPassword = await bcrypt.hash('test123', 12);
await connection.execute(`
INSERT INTO users (id, name, email, password_hash, department, role, join_date)
VALUES (?, ?, ?, ?, ?, ?, ?)
`, [testUserId, '測試用戶', 'test@example.com', hashedPassword, '測試部', 'developer', '2025-01-01']);
console.log('✅ 測試用戶創建成功');
// 2. 生成測試 Token
const token = jwt.sign({
userId: testUserId,
email: 'test@example.com',
role: 'developer'
}, JWT_SECRET, { expiresIn: '1h' });
console.log('✅ JWT Token 生成成功');
// 3. 測試創建應用程式
console.log('\n2. 測試創建應用程式...');
const appData = {
id: 'test-app-' + Date.now(),
name: '測試 AI 應用',
description: '這是一個用於測試的 AI 應用程式,具有機器學習功能',
creator_id: testUserId,
type: 'web_app',
tech_stack: JSON.stringify(['React', 'Node.js', 'TensorFlow']),
tags: JSON.stringify(['AI', '機器學習', '測試']),
demo_url: 'https://demo.example.com',
github_url: 'https://github.com/test/app',
docs_url: 'https://docs.example.com',
version: '1.0.0',
status: 'draft'
};
await connection.execute(`
INSERT INTO apps (id, name, description, creator_id, type, tech_stack, tags, demo_url, github_url, docs_url, version, status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
appData.id, appData.name, appData.description, appData.creator_id, appData.type,
appData.tech_stack, appData.tags, appData.demo_url, appData.github_url, appData.docs_url,
appData.version, appData.status
]);
console.log('✅ 測試應用程式創建成功');
// 4. 測試查詢應用程式列表
console.log('\n3. 測試查詢應用程式列表...');
const [apps] = await connection.execute(`
SELECT
a.*,
u.name as creator_name,
u.email as creator_email,
u.department as creator_department,
u.role as creator_role
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
WHERE a.creator_id = ?
`, [testUserId]);
console.log(`✅ 查詢到 ${apps.length} 個應用程式`);
apps.forEach(app => {
console.log(` - ${app.name} (${app.type}) - ${app.status}`);
});
// 5. 測試更新應用程式
console.log('\n4. 測試更新應用程式...');
await connection.execute(`
UPDATE apps
SET name = ?, description = ?, status = ?, version = ?
WHERE id = ?
`, [
'更新後的測試 AI 應用',
'這是更新後的測試應用程式描述',
'submitted',
'1.1.0',
appData.id
]);
console.log('✅ 應用程式更新成功');
// 6. 測試按讚功能
console.log('\n5. 測試按讚功能...');
const likeId = 'like-' + Date.now();
await connection.execute(`
INSERT INTO user_likes (id, user_id, app_id, liked_at)
VALUES (?, ?, ?, NOW())
`, [likeId, testUserId, appData.id]);
await connection.execute(`
UPDATE apps SET likes_count = likes_count + 1 WHERE id = ?
`, [appData.id]);
console.log('✅ 按讚功能測試成功');
// 7. 測試收藏功能
console.log('\n6. 測試收藏功能...');
const favoriteId = 'favorite-' + Date.now();
await connection.execute(`
INSERT INTO user_favorites (id, user_id, app_id)
VALUES (?, ?, ?)
`, [favoriteId, testUserId, appData.id]);
console.log('✅ 收藏功能測試成功');
// 8. 測試統計功能
console.log('\n7. 測試統計功能...');
const [stats] = await connection.execute(`
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'published' THEN 1 ELSE 0 END) as published,
SUM(CASE WHEN status IN ('submitted', 'under_review') THEN 1 ELSE 0 END) as pending_review,
SUM(CASE WHEN status = 'draft' THEN 1 ELSE 0 END) as draft,
SUM(CASE WHEN status = 'approved' THEN 1 ELSE 0 END) as approved,
SUM(CASE WHEN status = 'rejected' THEN 1 ELSE 0 END) as rejected
FROM apps
`);
console.log('✅ 統計功能測試成功:');
console.log(` - 總應用數: ${stats[0].total}`);
console.log(` - 已發布: ${stats[0].published}`);
console.log(` - 待審核: ${stats[0].pending_review}`);
console.log(` - 草稿: ${stats[0].draft}`);
console.log(` - 已批准: ${stats[0].approved}`);
console.log(` - 已拒絕: ${stats[0].rejected}`);
// 9. 測試搜尋功能
console.log('\n8. 測試搜尋功能...');
const [searchResults] = await connection.execute(`
SELECT a.*, u.name as creator_name
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
WHERE (a.name LIKE ? OR a.description LIKE ? OR u.name LIKE ?)
AND a.type = ?
AND a.status = ?
`, ['%AI%', '%AI%', '%測試%', 'web_app', 'submitted']);
console.log(`✅ 搜尋功能測試成功,找到 ${searchResults.length} 個結果`);
// 10. 測試刪除功能
console.log('\n9. 測試刪除功能...');
// 先刪除相關記錄
await connection.execute('DELETE FROM user_likes WHERE app_id = ?', [appData.id]);
await connection.execute('DELETE FROM user_favorites WHERE app_id = ?', [appData.id]);
// 刪除應用程式
await connection.execute('DELETE FROM apps WHERE id = ?', [appData.id]);
console.log('✅ 刪除功能測試成功');
// 11. 清理測試資料
console.log('\n10. 清理測試資料...');
await connection.execute('DELETE FROM users WHERE id = ?', [testUserId]);
console.log('✅ 測試資料清理完成');
console.log('\n🎉 所有應用程式 API 測試通過!');
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行測試
testAppsAPI().catch(console.error);

View File

@@ -1,99 +0,0 @@
const http = require('http');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
// 生成測試 Token
function generateTestToken() {
return jwt.sign({
userId: 'mdxxt1xt7slle4g8wz8',
email: 'petty091901@gmail.com',
role: 'admin'
}, JWT_SECRET, { expiresIn: '1h' });
}
// 發送 HTTP 請求
function makeRequest(url, method = 'GET', body = null, headers = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json',
...headers
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
if (body) {
req.write(JSON.stringify(body));
}
req.end();
});
}
async function testAppsQuery() {
try {
console.log('🧪 測試應用程式查詢...');
// 生成測試 Token
const token = generateTestToken();
console.log('✅ Token 生成成功');
// 測試 GET /api/apps
console.log('\n1. 測試 GET /api/apps...');
const response = await makeRequest('http://localhost:3000/api/apps', 'GET', null, {
'Authorization': `Bearer ${token}`
});
console.log('狀態碼:', response.status);
console.log('回應:', JSON.stringify(response.data, null, 2));
if (response.status === 200) {
console.log('✅ 應用程式查詢成功');
console.log('應用程式數量:', response.data.apps?.length || 0);
if (response.data.apps && response.data.apps.length > 0) {
console.log('第一個應用程式:', response.data.apps[0]);
}
} else {
console.log('❌ 應用程式查詢失敗');
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testAppsQuery();

View File

@@ -1,117 +0,0 @@
const http = require('http');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
// 生成測試 Token
function generateTestToken() {
return jwt.sign({
userId: 'mdxxt1xt7slle4g8wz8',
email: 'petty091901@gmail.com',
role: 'admin'
}, JWT_SECRET, { expiresIn: '1h' });
}
// 發送 HTTP 請求
function makeRequest(url, method = 'GET', body = null, headers = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json',
...headers
}
};
console.log('發送請求到:', url);
console.log('請求方法:', method);
console.log('請求標頭:', options.headers);
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('回應狀態:', res.statusCode);
console.log('回應標頭:', res.headers);
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
if (body) {
const bodyStr = JSON.stringify(body);
console.log('請求體:', bodyStr);
req.write(bodyStr);
}
req.end();
});
}
async function testAuthDetailed() {
try {
console.log('🧪 詳細認證測試...');
// 生成測試 Token
const token = generateTestToken();
console.log('✅ Token 生成成功');
console.log('Token 長度:', token.length);
// 驗證 Token
const payload = jwt.verify(token, JWT_SECRET);
console.log('✅ Token 驗證成功:', payload);
// 測試 GET 請求(不需要認證)
console.log('\n1. 測試 GET /api/apps需要認證...');
const getResponse = await makeRequest('http://localhost:3000/api/apps', 'GET', null, {
'Authorization': `Bearer ${token}`
});
console.log('GET 回應:', JSON.stringify(getResponse.data, null, 2));
// 測試 POST 請求
console.log('\n2. 測試 POST /api/apps...');
const appData = {
name: '測試應用',
description: '這是一個測試應用',
type: 'productivity',
demoUrl: 'https://example.com',
version: '1.0.0'
};
const postResponse = await makeRequest('http://localhost:3000/api/apps', 'POST', appData, {
'Authorization': `Bearer ${token}`
});
console.log('POST 回應:', JSON.stringify(postResponse.data, null, 2));
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testAuthDetailed();

View File

@@ -1,91 +0,0 @@
const mysql = require('mysql2/promise');
const jwt = require('jsonwebtoken');
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 JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testAuth() {
let connection;
try {
console.log('🧪 測試認證過程...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 檢查用戶是否存在
console.log('\n1. 檢查用戶是否存在...');
const [users] = await connection.execute(
'SELECT id, name, email, role FROM users WHERE id = ?',
['mdxxt1xt7slle4g8wz8']
);
if (users.length === 0) {
console.log('❌ 用戶不存在');
return;
}
const user = users[0];
console.log('✅ 用戶存在:', user);
// 2. 生成 Token
console.log('\n2. 生成 JWT Token...');
const token = jwt.sign({
userId: user.id,
email: user.email,
role: user.role
}, JWT_SECRET, { expiresIn: '1h' });
console.log('✅ Token 生成成功');
console.log('Token:', token.substring(0, 50) + '...');
// 3. 驗證 Token
console.log('\n3. 驗證 JWT Token...');
const payload = jwt.verify(token, JWT_SECRET);
console.log('✅ Token 驗證成功:', payload);
// 4. 模擬認證查詢
console.log('\n4. 模擬認證查詢...');
const [authUser] = await connection.execute(
'SELECT * FROM users WHERE id = ? AND email = ?',
[payload.userId, payload.email]
);
if (authUser.length === 0) {
console.log('❌ 認證查詢失敗 - 用戶不存在');
} else {
console.log('✅ 認證查詢成功:', authUser[0]);
}
// 5. 檢查用戶角色
console.log('\n5. 檢查用戶角色...');
if (authUser.length > 0) {
const userRole = authUser[0].role;
console.log('用戶角色:', userRole);
if (userRole === 'admin' || userRole === 'developer') {
console.log('✅ 用戶有權限創建應用程式');
} else {
console.log('❌ 用戶沒有權限創建應用程式');
}
}
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
testAuth();

View File

@@ -0,0 +1,92 @@
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

@@ -0,0 +1,84 @@
// 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,98 +0,0 @@
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testCurrentState() {
try {
// Generate a token for admin user
const adminPayload = {
id: 1,
email: 'admin@example.com',
role: 'admin'
};
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
console.log('=== 測試當前狀態 ===');
// Test 1: Get apps list with pagination
console.log('\n1. 測試應用程式列表 (分頁)');
const response1 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response1.ok) {
const data1 = await response1.json();
console.log('✅ API 回應成功');
console.log(`總應用數: ${data1.pagination?.total || 'N/A'}`);
console.log(`總頁數: ${data1.pagination?.totalPages || 'N/A'}`);
console.log(`當前頁應用數: ${data1.apps?.length || 0}`);
console.log('應用狀態統計:');
const statusCounts = {};
data1.apps?.forEach(app => {
statusCounts[app.status] = (statusCounts[app.status] || 0) + 1;
});
console.log(statusCounts);
} else {
console.log('❌ API 回應失敗:', response1.status, response1.statusText);
}
// Test 2: Create a new app as admin
console.log('\n2. 測試管理員創建應用程式');
const newAppData = {
name: '測試應用程式_' + Date.now(),
description: '這是一個測試應用程式',
type: 'productivity',
demoUrl: 'https://example.com',
version: '1.0.0'
};
const response2 = await fetch('http://localhost:3000/api/apps', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(newAppData)
});
if (response2.ok) {
const result = await response2.json();
console.log('✅ 創建應用程式成功');
console.log('創建的應用程式狀態:', result.app?.status);
console.log('應用程式ID:', result.appId);
} else {
const errorData = await response2.json();
console.log('❌ 創建應用程式失敗:', errorData);
}
// Test 3: Get apps list again to see the new app
console.log('\n3. 重新獲取應用程式列表');
const response3 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response3.ok) {
const data3 = await response3.json();
console.log('✅ 重新獲取成功');
console.log(`更新後總應用數: ${data3.pagination?.total || 'N/A'}`);
console.log(`更新後總頁數: ${data3.pagination?.totalPages || 'N/A'}`);
// Find the newly created app
const newApp = data3.apps?.find(app => app.name.includes('測試應用程式_'));
if (newApp) {
console.log('新創建的應用程式狀態:', newApp.status);
}
} else {
console.log('❌ 重新獲取失敗:', response3.status, response3.statusText);
}
} catch (error) {
console.error('測試過程中發生錯誤:', error);
}
}
testCurrentState();

View File

@@ -0,0 +1,100 @@
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');
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 testDBConnection() {
let connection;
try {
console.log('🧪 測試資料庫連接...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 測試查詢用戶
console.log('\n1. 測試查詢用戶...');
const [users] = await connection.execute(
'SELECT id, name, email, role FROM users WHERE id = ? AND email = ?',
['mdxxt1xt7slle4g8wz8', 'petty091901@gmail.com']
);
console.log('查詢結果:', users);
if (users.length > 0) {
console.log('✅ 用戶查詢成功');
} else {
console.log('❌ 用戶查詢失敗 - 沒有找到用戶');
}
// 測試查詢所有用戶
console.log('\n2. 測試查詢所有用戶...');
const [allUsers] = await connection.execute(
'SELECT id, name, email, role FROM users LIMIT 5'
);
console.log('所有用戶:', allUsers);
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
testDBConnection();

View File

@@ -1,64 +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 testDBQuery() {
let connection;
try {
console.log('🧪 測試資料庫查詢...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 測試 1: 簡單查詢
console.log('\n1. 測試簡單查詢...');
const [apps1] = await connection.execute('SELECT * FROM apps LIMIT 5');
console.log('結果:', apps1.length, '個應用程式');
// 測試 2: 使用 LIMIT 查詢
console.log('\n2. 測試 LIMIT 查詢...');
const [apps2] = await connection.execute('SELECT * FROM apps LIMIT 5');
console.log('結果:', apps2.length, '個應用程式');
// 測試 3: 使用 OFFSET
console.log('\n3. 測試 OFFSET 查詢...');
const [apps3] = await connection.execute('SELECT * FROM apps LIMIT 5 OFFSET 0');
console.log('結果:', apps3.length, '個應用程式');
// 測試 4: 計數查詢
console.log('\n4. 測試計數查詢...');
const [countResult] = await connection.execute('SELECT COUNT(*) as total FROM apps');
console.log('總數:', countResult[0].total);
// 測試 5: JOIN 查詢
console.log('\n5. 測試 JOIN 查詢...');
const [apps4] = await connection.execute(`
SELECT
a.*,
u.name as creator_name,
u.email as creator_email
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
LIMIT 5
`);
console.log('結果:', apps4.length, '個應用程式');
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
testDBQuery();

View File

@@ -0,0 +1,166 @@
// 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

@@ -0,0 +1,166 @@
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

@@ -0,0 +1,92 @@
// 測試詳細 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

@@ -0,0 +1,132 @@
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

@@ -0,0 +1,118 @@
// 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

@@ -0,0 +1,155 @@
// 模擬前端類型映射函數
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

@@ -0,0 +1,210 @@
// 測試編輯應用功能是否正確使用資料庫值而非預設值
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

@@ -0,0 +1,142 @@
// 測試編輯應用功能部門資訊修正
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,138 +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 testFrontendAppCreation() {
let connection;
try {
console.log('🧪 測試前端應用程式創建流程...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 創建測試用戶
const userId = Date.now().toString(36) + Math.random().toString(36).substr(2);
const userData = {
id: userId,
name: '測試用戶',
email: 'test@example.com',
password: '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/HS.i8eK', // 密碼: test123
role: 'developer',
department: 'IT',
join_date: new Date(),
created_at: new Date(),
updated_at: new Date()
};
await connection.execute(
'INSERT INTO users (id, name, email, password_hash, role, department, join_date, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
[userData.id, userData.name, userData.email, userData.password, userData.role, userData.department, userData.join_date, userData.created_at, userData.updated_at]
);
console.log('✅ 測試用戶創建成功');
// 2. 模擬前端提交的應用程式資料
const frontendAppData = {
name: '測試前端應用',
description: '這是一個通過前端界面創建的測試應用程式',
type: 'productivity', // 映射自 '文字處理'
demoUrl: 'https://example.com/demo',
githubUrl: 'https://github.com/example/app',
docsUrl: 'https://docs.example.com',
techStack: ['React', 'TypeScript', 'Tailwind CSS'],
tags: ['生產力工具', '文字處理'],
version: '1.0.0'
};
console.log('📋 前端提交的資料:', frontendAppData);
// 3. 創建應用程式(模擬 API 調用)
const appId = Date.now().toString(36) + Math.random().toString(36).substr(2);
const appData = {
id: appId,
name: frontendAppData.name,
description: frontendAppData.description,
creator_id: userId,
team_id: null,
type: frontendAppData.type,
tech_stack: JSON.stringify(frontendAppData.techStack),
tags: JSON.stringify(frontendAppData.tags),
demo_url: frontendAppData.demoUrl,
github_url: frontendAppData.githubUrl,
docs_url: frontendAppData.docsUrl,
version: frontendAppData.version,
status: 'draft'
};
await connection.execute(
`INSERT INTO apps (
id, name, description, creator_id, team_id, type,
tech_stack, tags, demo_url, github_url, docs_url,
version, status, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[
appData.id, appData.name, appData.description, appData.creator_id,
appData.team_id, appData.type, appData.tech_stack, appData.tags,
appData.demo_url, appData.github_url, appData.docs_url,
appData.version, appData.status
]
);
console.log('✅ 應用程式創建成功');
// 4. 驗證應用程式是否正確保存到資料庫
const [apps] = await connection.execute(
`SELECT a.*, u.name as creator_name
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
WHERE a.id = ?`,
[appId]
);
if (apps.length > 0) {
const app = apps[0];
console.log('\n📋 資料庫中的應用程式資料:');
console.log(` ID: ${app.id}`);
console.log(` 名稱: ${app.name}`);
console.log(` 描述: ${app.description}`);
console.log(` 類型: ${app.type}`);
console.log(` 狀態: ${app.status}`);
console.log(` 創建者: ${app.creator_name}`);
console.log(` 技術棧: ${app.tech_stack}`);
console.log(` 標籤: ${app.tags}`);
console.log(` 演示連結: ${app.demo_url}`);
console.log(` GitHub: ${app.github_url}`);
console.log(` 文檔: ${app.docs_url}`);
console.log(` 版本: ${app.version}`);
console.log(` 創建時間: ${app.created_at}`);
console.log('\n✅ 前端應用程式創建測試成功!');
console.log('🎯 問題已解決:前端現在可以正確創建應用程式並保存到資料庫');
} else {
console.log('❌ 應用程式未在資料庫中找到');
}
// 5. 清理測試資料
await connection.execute('DELETE FROM apps WHERE id = ?', [appId]);
await connection.execute('DELETE FROM users WHERE id = ?', [userId]);
console.log('✅ 測試資料清理完成');
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行測試
testFrontendAppCreation().catch(console.error);

View File

@@ -1,101 +0,0 @@
const http = require('http');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
// 生成測試 Token
function generateTestToken() {
return jwt.sign({
userId: 'mdxxt1xt7slle4g8wz8',
email: 'petty091901@gmail.com',
role: 'admin'
}, JWT_SECRET, { expiresIn: '1h' });
}
// 模擬瀏覽器的 localStorage
const mockLocalStorage = {
token: generateTestToken()
};
console.log('🧪 測試前端認證狀態...');
console.log('Token 存在:', !!mockLocalStorage.token);
console.log('Token 長度:', mockLocalStorage.token.length);
function makeRequest(url, method = 'GET', headers = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const options = {
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.pathname,
method: method,
headers: {
'Content-Type': 'application/json',
...headers
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
req.end();
});
}
async function testFrontendAPI() {
try {
console.log('\n🧪 測試前端 API 調用...');
const response = await makeRequest('http://localhost:3000/api/apps', 'GET', {
'Authorization': `Bearer ${mockLocalStorage.token}`
});
if (response.status === 200) {
console.log('✅ API 調用成功');
console.log('應用程式數量:', response.data.apps?.length || 0);
if (response.data.apps && response.data.apps.length > 0) {
const app = response.data.apps[0];
console.log('第一個應用程式範例:');
console.log('- ID:', app.id);
console.log('- 名稱:', app.name);
console.log('- 創建者:', app.creator?.name);
console.log('- 部門:', app.creator?.department);
console.log('- 狀態:', app.status);
console.log('- 類型:', app.type);
}
} else {
console.log('❌ API 調用失敗:', response.status);
console.log('回應:', response.data);
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
testFrontendAPI();

View File

@@ -1,128 +0,0 @@
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
async function testFrontendFixes() {
try {
// Generate a token for admin user
const adminPayload = {
userId: 'admin-001',
email: 'admin@theaken.com',
role: 'admin'
};
const token = jwt.sign(adminPayload, JWT_SECRET, { expiresIn: '1h' });
console.log('=== 測試前端修復 ===');
// Test 1: Get apps list with pagination
console.log('\n1. 測試應用程式列表 (分頁)');
const response1 = await fetch('http://localhost:3000/api/apps?page=1&limit=10', {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response1.ok) {
const data1 = await response1.json();
console.log('✅ API 回應成功');
console.log(`總應用數: ${data1.pagination?.total || 'N/A'}`);
console.log(`總頁數: ${data1.pagination?.totalPages || 'N/A'}`);
console.log(`當前頁應用數: ${data1.apps?.length || 0}`);
console.log('統計資訊:', data1.stats);
// 模擬前端數據轉換
const formattedApps = (data1.apps || []).map((app) => ({
...app,
creator: app.creator?.name || '未知',
department: app.creator?.department || '未知',
views: app.viewsCount || 0,
likes: app.likesCount || 0,
appUrl: app.demoUrl || '',
type: mapApiTypeToDisplayType(app.type),
icon: 'Bot',
iconColor: 'from-blue-500 to-purple-500',
reviews: 0,
createdAt: app.createdAt ? new Date(app.createdAt).toLocaleDateString() : '未知'
}));
console.log('\n模擬前端統計:');
console.log(`總應用數 (totalApps): ${data1.pagination?.total}`);
console.log(`已發布: ${data1.stats?.published || 0}`);
console.log(`待審核: ${data1.stats?.pending || 0}`);
console.log(`草稿: ${data1.stats?.draft || 0}`);
console.log(`已拒絕: ${data1.stats?.rejected || 0}`);
// 檢查分頁是否應該顯示
const shouldShowPagination = data1.pagination?.totalPages > 1;
console.log(`\n分頁是否應該顯示: ${shouldShowPagination} (總頁數: ${data1.pagination?.totalPages})`);
} else {
console.log('❌ API 回應失敗:', response1.status, response1.statusText);
}
// Test 2: Create a new app as admin
console.log('\n2. 測試管理員創建應用程式');
const newAppData = {
name: '測試應用程式_' + Date.now(),
description: '這是一個測試應用程式',
type: 'productivity',
demoUrl: 'https://example.com',
version: '1.0.0'
};
const response2 = await fetch('http://localhost:3000/api/apps', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(newAppData)
});
if (response2.ok) {
const result = await response2.json();
console.log('✅ 創建應用程式成功');
console.log('創建的應用程式狀態:', result.app?.status);
console.log('應用程式ID:', result.appId);
// 檢查狀態是否正確 (應該是 draft)
if (result.app?.status === 'draft') {
console.log('✅ 狀態正確: 管理員創建的應用程式狀態為 draft');
} else {
console.log('❌ 狀態錯誤: 管理員創建的應用程式狀態應該為 draft但實際為', result.app?.status);
}
} else {
const errorData = await response2.json();
console.log('❌ 創建應用程式失敗:', errorData);
}
} catch (error) {
console.error('測試過程中發生錯誤:', error);
}
}
// 模擬前端的類型轉換函數
function 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] || '其他';
}
testFrontendFixes();

View File

@@ -0,0 +1,106 @@
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,87 +0,0 @@
const http = require('http');
const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET || 'good777';
// 測試登入
function testLogin(email, password) {
return new Promise((resolve, reject) => {
const postData = JSON.stringify({
email: email,
password: password
});
const options = {
hostname: 'localhost',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const jsonData = JSON.parse(data);
resolve({
status: res.statusCode,
data: jsonData
});
} catch (error) {
resolve({
status: res.statusCode,
data: data
});
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(postData);
req.end();
});
}
async function testLogins() {
console.log('🧪 測試登入...');
const testUsers = [
{ email: 'admin@theaken.com', password: 'Admin123' },
{ email: 'admin@example.com', password: 'Admin123' },
{ email: 'petty091901@gmail.com', password: 'Admin123' },
{ email: 'test@theaken.com', password: 'Test123' },
{ email: 'test@example.com', password: 'Test123' }
];
for (const user of testUsers) {
try {
console.log(`\n測試用戶: ${user.email}`);
const response = await testLogin(user.email, user.password);
if (response.status === 200) {
console.log('✅ 登入成功');
console.log('用戶資訊:', response.data.user);
console.log('Token 長度:', response.data.token?.length || 0);
} else {
console.log('❌ 登入失敗');
console.log('錯誤:', response.data.error);
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
}
testLogins();

View File

@@ -0,0 +1,137 @@
// 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,54 +0,0 @@
const jwt = require('jsonwebtoken');
async function testPagination() {
console.log('🧪 測試分頁功能...');
// 生成測試 token
const token = jwt.sign(
{ userId: 'admin-001', role: 'admin' },
process.env.JWT_SECRET || 'good777',
{ expiresIn: '1h' }
);
console.log('✅ Token 生成成功\n');
// 測試不同的分頁參數
const testCases = [
{ page: 1, limit: 3, description: '第1頁每頁3筆' },
{ page: 2, limit: 3, description: '第2頁每頁3筆' },
{ page: 1, limit: 5, description: '第1頁每頁5筆' },
{ page: 1, limit: 10, description: '第1頁每頁10筆' }
];
for (const testCase of testCases) {
console.log(`\n${testCase.description}:`);
try {
const params = new URLSearchParams({
page: testCase.page.toString(),
limit: testCase.limit.toString()
});
const response = await fetch(`http://localhost:3000/api/apps?${params}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const data = await response.json();
console.log(` 狀態碼: ${response.status}`);
console.log(` 應用程式數量: ${data.apps.length}`);
console.log(` 分頁資訊:`, data.pagination);
} else {
console.log(` 錯誤: ${response.status} ${response.statusText}`);
}
} catch (error) {
console.log(` 請求失敗: ${error.message}`);
}
}
console.log('\n✅ 分頁測試完成');
}
testPagination();

View File

@@ -1,60 +0,0 @@
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
async function testPasswordVerification() {
console.log('=== 測試密碼驗證 ===');
try {
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 資料庫連接成功');
// 測試密碼
const testPasswords = [
'Admin123!',
'Admin@2024',
'admin123',
'password',
'123456'
];
// 查詢管理員用戶
const [rows] = await connection.execute(`
SELECT id, name, email, role, password_hash
FROM users
WHERE role = 'admin'
ORDER BY created_at DESC
`);
console.log(`\n找到 ${rows.length} 個管理員用戶:`);
for (const user of rows) {
console.log(`\n用戶: ${user.name} (${user.email})`);
console.log(`密碼雜湊: ${user.password_hash}`);
// 測試每個密碼
for (const password of testPasswords) {
try {
const isValid = await bcrypt.compare(password, user.password_hash);
if (isValid) {
console.log(`✅ 密碼匹配: "${password}"`);
}
} catch (error) {
console.log(`❌ 密碼驗證錯誤: ${error.message}`);
}
}
}
await connection.end();
} catch (error) {
console.error('❌ 資料庫連接失敗:', error.message);
}
}
testPasswordVerification().catch(console.error);

View File

@@ -1,63 +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 testSimpleQuery() {
let connection;
try {
console.log('🧪 測試簡單查詢...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 測試 1: 簡單的 apps 查詢
console.log('\n1. 測試簡單的 apps 查詢...');
const [apps1] = await connection.execute('SELECT * FROM apps LIMIT 5');
console.log('結果:', apps1.length, '個應用程式');
// 測試 2: 帶 JOIN 的查詢
console.log('\n2. 測試帶 JOIN 的查詢...');
const [apps2] = await connection.execute(`
SELECT
a.*,
u.name as creator_name,
u.email as creator_email
FROM apps a
LEFT JOIN users u ON a.creator_id = u.id
LIMIT 5
`);
console.log('結果:', apps2.length, '個應用程式');
// 測試 3: 帶參數的查詢
console.log('\n3. 測試帶參數的查詢...');
const [apps3] = await connection.execute(`
SELECT * FROM apps
WHERE creator_id = ?
LIMIT ?
`, ['mdxxt1xt7slle4g8wz8', 5]);
console.log('結果:', apps3.length, '個應用程式');
// 測試 4: 計數查詢
console.log('\n4. 測試計數查詢...');
const [countResult] = await connection.execute('SELECT COUNT(*) as total FROM apps');
console.log('總數:', countResult[0].total);
} catch (error) {
console.error('❌ 測試失敗:', error);
} finally {
if (connection) {
await connection.end();
}
}
}
testSimpleQuery();

View File

@@ -1,4 +1,38 @@
// 測試類型轉換函數
// 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': '文字處理',
@@ -17,15 +51,115 @@ const mapApiTypeToDisplayType = (apiType) => {
'robotics': '機器人',
'cybersecurity': '網路安全',
'cloud_service': '雲端服務',
// 處理舊的英文類型,確保它們都轉換為中文
'web_app': '文字處理',
'mobile_app': '文字處理',
'desktop_app': '文字處理',
'api_service': '程式開發',
'other': '其他'
}
return typeMap[apiType] || '其他'
}
// 測試轉換
console.log('🧪 測試類型轉換...')
console.log('productivity ->', mapApiTypeToDisplayType('productivity'))
console.log('ai_model ->', mapApiTypeToDisplayType('ai_model'))
console.log('automation ->', mapApiTypeToDisplayType('automation'))
console.log('unknown ->', mapApiTypeToDisplayType('unknown'))
console.log('✅ 類型轉換測試完成')
// 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

@@ -0,0 +1,139 @@
// 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,77 +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 testUserPermissions() {
let connection;
try {
console.log('🧪 測試用戶權限和認證狀態...');
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 檢查現有用戶
const [users] = await connection.execute('SELECT id, name, email, role, department FROM users ORDER BY created_at DESC LIMIT 5');
console.log('\n📋 資料庫中的用戶列表:');
users.forEach((user, index) => {
console.log(` ${index + 1}. ${user.name} (${user.email}) - 角色: ${user.role} - 部門: ${user.department}`);
});
// 檢查應用程式
const [apps] = await connection.execute('SELECT id, name, creator_id, type, status FROM apps ORDER BY created_at DESC LIMIT 5');
console.log('\n📋 資料庫中的應用程式列表:');
apps.forEach((app, index) => {
console.log(` ${index + 1}. ${app.name} - 創建者: ${app.creator_id} - 類型: ${app.type} - 狀態: ${app.status}`);
});
// 創建一個管理員用戶用於測試
const adminUserData = {
id: 'admin-test-' + Date.now(),
name: '測試管理員',
email: 'admin-test@example.com',
password_hash: 'test_hash',
department: 'ITBU',
role: 'admin',
join_date: new Date(),
created_at: new Date(),
updated_at: new Date()
};
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, adminUserData.password_hash, adminUserData.department, adminUserData.role, adminUserData.join_date, adminUserData.created_at, adminUserData.updated_at]
);
console.log('\n✅ 測試管理員用戶創建成功');
// 模擬 API 調用
console.log('\n🧪 模擬 API 調用測試...');
// 這裡我們需要模擬一個有效的 JWT token
// 在實際環境中,這個 token 應該通過登入 API 獲得
console.log('💡 提示:要測試 API 調用,需要先通過登入 API 獲得有效的 JWT token');
console.log('💡 建議:在瀏覽器中登入管理後台,然後檢查 localStorage 中的 token');
// 清理測試資料
await connection.execute('DELETE FROM users WHERE id = ?', [adminUserData.id]);
console.log('✅ 測試資料清理完成');
} catch (error) {
console.error('❌ 測試失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
testUserPermissions().catch(console.error);

View File

@@ -1,55 +0,0 @@
const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
async function updateAllAdminPasswords() {
console.log('=== 更新所有管理員密碼 ===');
try {
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 資料庫連接成功');
// 新密碼
const newPassword = 'Admin123!';
const passwordHash = await bcrypt.hash(newPassword, 12);
console.log(`\n更新所有管理員密碼為: ${newPassword}`);
// 更新所有管理員用戶的密碼
const [result] = await connection.execute(`
UPDATE users
SET password_hash = ?, updated_at = NOW()
WHERE role = 'admin'
`, [passwordHash]);
console.log(`✅ 已更新 ${result.affectedRows} 個管理員用戶的密碼`);
// 驗證更新結果
const [users] = await connection.execute(`
SELECT id, name, email, role, updated_at
FROM users
WHERE role = 'admin'
ORDER BY created_at DESC
`);
console.log('\n📋 更新後的管理員用戶:');
for (const user of users) {
console.log(` - ${user.name} (${user.email}) - 更新時間: ${user.updated_at}`);
}
console.log('\n🎉 所有管理員密碼已統一為: Admin123!');
console.log('💡 現在所有管理員用戶都可以使用相同的密碼登入');
await connection.end();
} catch (error) {
console.error('❌ 更新失敗:', error.message);
}
}
updateAllAdminPasswords().catch(console.error);

View File

@@ -10,55 +10,105 @@ const dbConfig = {
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('✅ 資料庫連接成功');
// 更新 ENUM 類型,移除不適合企業平台的類型
const updateTypeEnum = `
ALTER TABLE apps MODIFY COLUMN type ENUM(
'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'
) DEFAULT 'other'
`;
await connection.execute(updateTypeEnum);
console.log('✅ 應用程式類型 ENUM 更新成功');
// 查看更新後的結構
const [describeResult] = await connection.execute('DESCRIBE apps');
console.log('\n📋 更新後的 apps 表結構:');
describeResult.forEach(row => {
if (row.Field === 'type') {
console.log(` ${row.Field}: ${row.Type}`);
// 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🎯 有效的應用程式類型:');
const validTypes = [
'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'
];
validTypes.forEach((type, index) => {
console.log(` ${index + 1}. ${type}`);
});
console.log('\n✅ 企業 AI 平台應用類型更新完成!');
console.log('🎯 已移除遊戲、娛樂、社交媒體等不適合企業平台的類型');
console.log('📈 新增了更多適合企業 AI 應用的類型');
console.log('\n✅ 應用程式類型更新完成!');
} catch (error) {
console.error('❌ 更新失敗:', error.message);
if (error.code === 'ER_DUP_FIELDNAME') {
console.log('💡 提示:某些欄位可能已存在,這是正常的');
}
console.error('❌ 更新應用程式類型失敗:', error);
} finally {
if (connection) {
await connection.end();