實作前台 APP 呈現、APP 詳細頁面

This commit is contained in:
2025-09-10 00:27:26 +08:00
parent 900e33aefa
commit bc2104d374
17 changed files with 318 additions and 1565 deletions

View File

@@ -18,6 +18,14 @@ const dbConfig = {
reconnect: true,
connectionLimit: 10,
queueLimit: 0,
// 添加連接重試和錯誤處理配置
retryDelay: 2000,
maxRetries: 3,
// 添加連接池配置
idleTimeout: 300000,
maxIdle: 10,
// 添加 SSL 配置(如果需要)
ssl: false,
};
// 創建連接池
@@ -46,19 +54,51 @@ export class Database {
// 執行查詢
public async query<T = any>(sql: string, params?: any[]): Promise<T[]> {
const connection = await this.getConnection();
try {
const [rows] = await connection.execute(sql, params);
return rows as T[];
} finally {
connection.release();
let connection;
let retries = 0;
const maxRetries = 3;
while (retries < maxRetries) {
try {
connection = await this.getConnection();
const [rows] = await connection.execute(sql, params);
return rows as T[];
} catch (error: any) {
console.error(`資料庫查詢錯誤 (嘗試 ${retries + 1}/${maxRetries}):`, error.message);
if (connection) {
connection.release();
}
if (error.code === 'ECONNRESET' || error.code === 'PROTOCOL_CONNECTION_LOST') {
retries++;
if (retries < maxRetries) {
console.log(`等待 ${2000 * retries}ms 後重試...`);
await new Promise(resolve => setTimeout(resolve, 2000 * retries));
continue;
}
}
throw error;
} finally {
if (connection) {
connection.release();
}
}
}
throw new Error('資料庫連接失敗,已達到最大重試次數');
}
// 執行單一查詢
public async queryOne<T = any>(sql: string, params?: any[]): Promise<T | null> {
const results = await this.query<T>(sql, params);
return results.length > 0 ? results[0] : null;
try {
const results = await this.query<T>(sql, params);
return results.length > 0 ? results[0] : null;
} catch (error) {
console.error('資料庫單一查詢錯誤:', error);
throw error;
}
}
// 執行插入

View File

@@ -239,6 +239,7 @@ export interface UserRating {
user_id: string;
app_id: string;
rating: number;
comment?: string;
rated_at: string;
}

View File

@@ -1396,6 +1396,7 @@ export class AppService {
SELECT
ur.id,
ur.rating,
ur.comment,
ur.rated_at,
u.name as user_name,
u.department as user_department,
@@ -1411,7 +1412,7 @@ export class AppService {
return reviews.map((review: any) => ({
id: review.id,
rating: review.rating,
review: '用戶評價', // 暫時使用固定文字,因為資料庫中沒有 review 欄位
review: review.comment || '用戶評價', // 使用 comment 欄位,如果為空則顯示預設文字
ratedAt: review.rated_at,
userName: review.user_name,
userDepartment: review.user_department,
@@ -1464,6 +1465,79 @@ export class AppService {
return { success: false, error: '刪除評價時發生錯誤' };
}
}
// 獲取應用部門列表
async getAppDepartments(): Promise<{ department: string; count: number }[]> {
try {
const sql = `
SELECT
u.department,
COUNT(DISTINCT a.id) as count
FROM apps a
JOIN users u ON a.creator_id = u.id
WHERE a.is_active = TRUE
GROUP BY u.department
ORDER BY count DESC, u.department ASC
`;
const departments = await this.query(sql);
return departments.map((dept: any) => ({
department: dept.department,
count: parseInt(dept.count)
}));
} catch (error) {
console.error('獲取應用部門列表錯誤:', error);
return [];
}
}
// 獲取應用類型列表
async getAppTypes(): Promise<{ type: string; count: number }[]> {
try {
const sql = `
SELECT
type,
COUNT(*) as count
FROM apps
WHERE is_active = TRUE
GROUP BY type
ORDER BY count DESC, type ASC
`;
const types = await this.query(sql);
return types.map((type: any) => ({
type: type.type,
count: parseInt(type.count)
}));
} catch (error) {
console.error('獲取應用類型列表錯誤:', error);
return [];
}
}
// 獲取應用分類列表
async getAppCategories(): Promise<{ category: string; count: number }[]> {
try {
const sql = `
SELECT
category,
COUNT(*) as count
FROM apps
WHERE is_active = TRUE
GROUP BY category
ORDER BY count DESC, category ASC
`;
const categories = await this.query(sql);
return categories.map((cat: any) => ({
category: cat.category,
count: parseInt(cat.count)
}));
} catch (error) {
console.error('獲取應用分類列表錯誤:', error);
return [];
}
}
}
// =====================================================