整合資料庫、完成登入註冊忘記密碼功能
This commit is contained in:
253
scripts/migrate-views.js
Normal file
253
scripts/migrate-views.js
Normal file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// =====================================================
|
||||
// 視圖遷移腳本
|
||||
// =====================================================
|
||||
|
||||
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',
|
||||
acquireTimeout: 60000,
|
||||
timeout: 60000,
|
||||
reconnect: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
};
|
||||
|
||||
async function migrateViews() {
|
||||
let connection;
|
||||
|
||||
try {
|
||||
console.log('🚀 開始視圖遷移...');
|
||||
|
||||
// 創建連接
|
||||
connection = await mysql.createConnection({
|
||||
...dbConfig,
|
||||
multipleStatements: true
|
||||
});
|
||||
|
||||
console.log('✅ 資料庫連接成功');
|
||||
|
||||
// 視圖 SQL
|
||||
const viewSQL = `
|
||||
-- 用戶統計視圖
|
||||
CREATE VIEW user_statistics AS
|
||||
SELECT
|
||||
u.id,
|
||||
u.name,
|
||||
u.email,
|
||||
u.department,
|
||||
u.role,
|
||||
u.join_date,
|
||||
u.total_likes,
|
||||
u.total_views,
|
||||
COUNT(DISTINCT f.app_id) as favorite_count,
|
||||
COUNT(DISTINCT l.app_id) as liked_apps_count,
|
||||
COUNT(DISTINCT v.app_id) as viewed_apps_count,
|
||||
AVG(r.rating) as average_rating_given,
|
||||
COUNT(DISTINCT t.id) as teams_joined,
|
||||
COUNT(DISTINCT CASE WHEN t.leader_id = u.id THEN t.id END) as teams_led
|
||||
FROM users u
|
||||
LEFT JOIN user_favorites f ON u.id = f.user_id
|
||||
LEFT JOIN user_likes l ON u.id = l.user_id
|
||||
LEFT JOIN user_views v ON u.id = v.user_id
|
||||
LEFT JOIN user_ratings r ON u.id = r.user_id
|
||||
LEFT JOIN team_members tm ON u.id = tm.user_id
|
||||
LEFT JOIN teams t ON tm.team_id = t.id
|
||||
WHERE u.is_active = TRUE
|
||||
GROUP BY u.id;
|
||||
|
||||
-- 應用統計視圖
|
||||
CREATE VIEW app_statistics AS
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.description,
|
||||
a.category,
|
||||
a.type,
|
||||
a.likes_count,
|
||||
a.views_count,
|
||||
a.rating,
|
||||
u.name as creator_name,
|
||||
u.department as creator_department,
|
||||
t.name as team_name,
|
||||
COUNT(DISTINCT f.user_id) as favorite_users_count,
|
||||
COUNT(DISTINCT l.user_id) as liked_users_count,
|
||||
COUNT(DISTINCT v.user_id) as viewed_users_count,
|
||||
AVG(ajs.total_score) as average_judge_score,
|
||||
COUNT(DISTINCT ajs.judge_id) as judge_count
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
LEFT JOIN teams t ON a.team_id = t.id
|
||||
LEFT JOIN user_favorites f ON a.id = f.app_id
|
||||
LEFT JOIN user_likes l ON a.id = l.app_id
|
||||
LEFT JOIN user_views v ON a.id = v.app_id
|
||||
LEFT JOIN app_judge_scores ajs ON a.id = ajs.app_id
|
||||
WHERE a.is_active = TRUE
|
||||
GROUP BY a.id;
|
||||
|
||||
-- 競賽統計視圖
|
||||
CREATE VIEW competition_statistics AS
|
||||
SELECT
|
||||
c.id,
|
||||
c.name,
|
||||
c.year,
|
||||
c.month,
|
||||
c.type,
|
||||
c.status,
|
||||
COUNT(DISTINCT cj.judge_id) as judge_count,
|
||||
COUNT(DISTINCT ca.app_id) as app_count,
|
||||
COUNT(DISTINCT ct.team_id) as team_count,
|
||||
COUNT(DISTINCT cp.proposal_id) as proposal_count,
|
||||
COUNT(DISTINCT aw.id) as award_count
|
||||
FROM competitions c
|
||||
LEFT JOIN competition_judges cj ON c.id = cj.competition_id
|
||||
LEFT JOIN competition_apps ca ON c.id = ca.competition_id
|
||||
LEFT JOIN competition_teams ct ON c.id = ct.competition_id
|
||||
LEFT JOIN competition_proposals cp ON c.id = cp.competition_id
|
||||
LEFT JOIN awards aw ON c.id = aw.competition_id
|
||||
WHERE c.is_active = TRUE
|
||||
GROUP BY c.id;
|
||||
`;
|
||||
|
||||
console.log('⚡ 執行視圖 SQL...');
|
||||
|
||||
// 分別執行每個視圖
|
||||
const views = [
|
||||
{
|
||||
name: 'user_statistics',
|
||||
sql: `CREATE VIEW user_statistics AS
|
||||
SELECT
|
||||
u.id,
|
||||
u.name,
|
||||
u.email,
|
||||
u.department,
|
||||
u.role,
|
||||
u.join_date,
|
||||
u.total_likes,
|
||||
u.total_views,
|
||||
COUNT(DISTINCT f.app_id) as favorite_count,
|
||||
COUNT(DISTINCT l.app_id) as liked_apps_count,
|
||||
COUNT(DISTINCT v.app_id) as viewed_apps_count,
|
||||
AVG(r.rating) as average_rating_given,
|
||||
COUNT(DISTINCT t.id) as teams_joined,
|
||||
COUNT(DISTINCT CASE WHEN t.leader_id = u.id THEN t.id END) as teams_led
|
||||
FROM users u
|
||||
LEFT JOIN user_favorites f ON u.id = f.user_id
|
||||
LEFT JOIN user_likes l ON u.id = l.user_id
|
||||
LEFT JOIN user_views v ON u.id = v.user_id
|
||||
LEFT JOIN user_ratings r ON u.id = r.user_id
|
||||
LEFT JOIN team_members tm ON u.id = tm.user_id
|
||||
LEFT JOIN teams t ON tm.team_id = t.id
|
||||
WHERE u.is_active = TRUE
|
||||
GROUP BY u.id`
|
||||
},
|
||||
{
|
||||
name: 'app_statistics',
|
||||
sql: `CREATE VIEW app_statistics AS
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.description,
|
||||
a.category,
|
||||
a.type,
|
||||
a.likes_count,
|
||||
a.views_count,
|
||||
a.rating,
|
||||
u.name as creator_name,
|
||||
u.department as creator_department,
|
||||
t.name as team_name,
|
||||
COUNT(DISTINCT f.user_id) as favorite_users_count,
|
||||
COUNT(DISTINCT l.user_id) as liked_users_count,
|
||||
COUNT(DISTINCT v.user_id) as viewed_users_count,
|
||||
AVG(ajs.total_score) as average_judge_score,
|
||||
COUNT(DISTINCT ajs.judge_id) as judge_count
|
||||
FROM apps a
|
||||
LEFT JOIN users u ON a.creator_id = u.id
|
||||
LEFT JOIN teams t ON a.team_id = t.id
|
||||
LEFT JOIN user_favorites f ON a.id = f.app_id
|
||||
LEFT JOIN user_likes l ON a.id = l.app_id
|
||||
LEFT JOIN user_views v ON a.id = v.app_id
|
||||
LEFT JOIN app_judge_scores ajs ON a.id = ajs.app_id
|
||||
WHERE a.is_active = TRUE
|
||||
GROUP BY a.id`
|
||||
},
|
||||
{
|
||||
name: 'competition_statistics',
|
||||
sql: `CREATE VIEW competition_statistics AS
|
||||
SELECT
|
||||
c.id,
|
||||
c.name,
|
||||
c.year,
|
||||
c.month,
|
||||
c.type,
|
||||
c.status,
|
||||
COUNT(DISTINCT cj.judge_id) as judge_count,
|
||||
COUNT(DISTINCT ca.app_id) as app_count,
|
||||
COUNT(DISTINCT ct.team_id) as team_count,
|
||||
COUNT(DISTINCT cp.proposal_id) as proposal_count,
|
||||
COUNT(DISTINCT aw.id) as award_count
|
||||
FROM competitions c
|
||||
LEFT JOIN competition_judges cj ON c.id = cj.competition_id
|
||||
LEFT JOIN competition_apps ca ON c.id = ca.competition_id
|
||||
LEFT JOIN competition_teams ct ON c.id = ct.competition_id
|
||||
LEFT JOIN competition_proposals cp ON c.id = cp.competition_id
|
||||
LEFT JOIN awards aw ON c.id = aw.competition_id
|
||||
WHERE c.is_active = TRUE
|
||||
GROUP BY c.id`
|
||||
}
|
||||
];
|
||||
|
||||
for (const view of views) {
|
||||
try {
|
||||
await connection.execute(view.sql);
|
||||
console.log(`✅ 創建視圖: ${view.name}`);
|
||||
} catch (error) {
|
||||
if (error.code === 'ER_TABLE_EXISTS') {
|
||||
console.log(`⚠️ 視圖已存在: ${view.name}`);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('✅ 視圖創建成功!');
|
||||
|
||||
// 檢查視圖
|
||||
console.log('🔍 檢查視圖...');
|
||||
const [viewList] = await connection.execute('SHOW FULL TABLES WHERE Table_type = "VIEW"');
|
||||
console.log(`📈 共創建了 ${viewList.length} 個視圖:`);
|
||||
|
||||
viewList.forEach((view, index) => {
|
||||
const viewName = Object.values(view)[0];
|
||||
console.log(` ${index + 1}. ${viewName}`);
|
||||
});
|
||||
|
||||
console.log('🎉 視圖遷移完成!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 視圖遷移失敗:', error.message);
|
||||
console.error('詳細錯誤:', error);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (connection) {
|
||||
await connection.end();
|
||||
console.log('🔌 資料庫連接已關閉');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 執行遷移
|
||||
if (require.main === module) {
|
||||
migrateViews().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { migrateViews };
|
Reference in New Issue
Block a user