完成 APP 建立流程和使用分析、增加主機備機的備援機制、管理者後臺增加資料庫監控
This commit is contained in:
@@ -202,69 +202,6 @@ export class UserService {
|
||||
};
|
||||
}
|
||||
|
||||
// 獲取用戶的應用和評價統計
|
||||
async getUserAppAndReviewStats(userId: string): Promise<{
|
||||
appCount: number;
|
||||
reviewCount: number;
|
||||
}> {
|
||||
try {
|
||||
console.log('獲取用戶統計數據,userId:', userId);
|
||||
|
||||
// 先檢查資料庫中是否有數據
|
||||
const checkAppsSql = 'SELECT COUNT(*) as total FROM apps';
|
||||
const checkRatingsSql = 'SELECT COUNT(*) as total FROM user_ratings';
|
||||
const checkUsersSql = 'SELECT COUNT(*) as total FROM users';
|
||||
|
||||
const [totalApps, totalRatings, totalUsers] = await Promise.all([
|
||||
this.queryOne(checkAppsSql),
|
||||
this.queryOne(checkRatingsSql),
|
||||
this.queryOne(checkUsersSql)
|
||||
]);
|
||||
|
||||
console.log('資料庫總數據:', {
|
||||
totalApps: totalApps?.total || 0,
|
||||
totalRatings: totalRatings?.total || 0,
|
||||
totalUsers: totalUsers?.total || 0
|
||||
});
|
||||
|
||||
// 獲取用戶創建的應用數量
|
||||
const appCountSql = `
|
||||
SELECT COUNT(*) as app_count
|
||||
FROM apps
|
||||
WHERE creator_id = ?
|
||||
`;
|
||||
|
||||
// 獲取用戶撰寫的評價數量
|
||||
const reviewCountSql = `
|
||||
SELECT COUNT(*) as review_count
|
||||
FROM user_ratings
|
||||
WHERE user_id = ?
|
||||
`;
|
||||
|
||||
const [appResult, reviewResult] = await Promise.all([
|
||||
this.queryOne(appCountSql, [userId]),
|
||||
this.queryOne(reviewCountSql, [userId])
|
||||
]);
|
||||
|
||||
console.log('應用查詢結果:', appResult);
|
||||
console.log('評價查詢結果:', reviewResult);
|
||||
|
||||
const result = {
|
||||
appCount: appResult?.app_count || 0,
|
||||
reviewCount: reviewResult?.review_count || 0
|
||||
};
|
||||
|
||||
console.log('最終統計結果:', result);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('獲取用戶應用和評價統計錯誤:', error);
|
||||
return {
|
||||
appCount: 0,
|
||||
reviewCount: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 獲取用戶活動記錄
|
||||
async getUserActivities(
|
||||
userId: string,
|
||||
@@ -804,7 +741,7 @@ export class UserService {
|
||||
|
||||
// 獲取所有用戶
|
||||
async getAllUsers(limit = 50, offset = 0): Promise<User[]> {
|
||||
const sql = 'SELECT * FROM users WHERE is_active = TRUE ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
||||
const sql = 'SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?';
|
||||
return await db.query<User>(sql, [limit, offset]);
|
||||
}
|
||||
|
||||
@@ -839,6 +776,46 @@ export class UserService {
|
||||
const service = new UserService();
|
||||
return await service.getAllUsers(limit, offset);
|
||||
}
|
||||
|
||||
// 獲取用戶的應用和評價統計
|
||||
async getUserAppAndReviewStats(userId: string): Promise<{
|
||||
appCount: number;
|
||||
reviewCount: number;
|
||||
}> {
|
||||
try {
|
||||
// 獲取用戶創建的應用數量
|
||||
const appCountSql = `
|
||||
SELECT COUNT(*) as app_count
|
||||
FROM apps
|
||||
WHERE creator_id = ?
|
||||
`;
|
||||
|
||||
// 獲取用戶撰寫的評價數量
|
||||
const reviewCountSql = `
|
||||
SELECT COUNT(*) as review_count
|
||||
FROM user_ratings
|
||||
WHERE user_id = ?
|
||||
`;
|
||||
|
||||
const [appResult, reviewResult] = await Promise.all([
|
||||
this.queryOne(appCountSql, [userId]),
|
||||
this.queryOne(reviewCountSql, [userId])
|
||||
]);
|
||||
|
||||
const result = {
|
||||
appCount: appResult?.app_count || 0,
|
||||
reviewCount: reviewResult?.review_count || 0
|
||||
};
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('獲取用戶應用和評價統計錯誤:', error);
|
||||
return {
|
||||
appCount: 0,
|
||||
reviewCount: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
@@ -1358,7 +1335,7 @@ export class AppService {
|
||||
}
|
||||
|
||||
// 獲取應用使用統計
|
||||
async getAppUsageStats(appId: string, startDate?: string, endDate?: string): Promise<{
|
||||
async getAppUsageStats(appId: string, startDate?: string, endDate?: string, department?: string): Promise<{
|
||||
dailyUsers: number;
|
||||
weeklyUsers: number;
|
||||
monthlyUsers: number;
|
||||
@@ -1369,7 +1346,7 @@ export class AppService {
|
||||
try {
|
||||
// 今日使用者
|
||||
const dailySql = `
|
||||
SELECT COUNT(DISTINCT user_id) as daily_users
|
||||
SELECT COUNT(*) as daily_users
|
||||
FROM user_views
|
||||
WHERE app_id = ? AND DATE(viewed_at) = CURDATE()
|
||||
`;
|
||||
@@ -1377,7 +1354,7 @@ export class AppService {
|
||||
|
||||
// 本週使用者
|
||||
const weeklySql = `
|
||||
SELECT COUNT(DISTINCT user_id) as weekly_users
|
||||
SELECT COUNT(*) as weekly_users
|
||||
FROM user_views
|
||||
WHERE app_id = ? AND viewed_at >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
|
||||
`;
|
||||
@@ -1385,7 +1362,7 @@ export class AppService {
|
||||
|
||||
// 本月使用者
|
||||
const monthlySql = `
|
||||
SELECT COUNT(DISTINCT user_id) as monthly_users
|
||||
SELECT COUNT(*) as monthly_users
|
||||
FROM user_views
|
||||
WHERE app_id = ? AND viewed_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
|
||||
`;
|
||||
@@ -1399,48 +1376,73 @@ export class AppService {
|
||||
`;
|
||||
const totalResult = await this.queryOne(totalSql, [appId]);
|
||||
|
||||
// 部門使用統計
|
||||
const deptSql = `
|
||||
SELECT
|
||||
u.department,
|
||||
COUNT(*) as count
|
||||
FROM user_views uv
|
||||
JOIN users u ON uv.user_id = u.id
|
||||
WHERE uv.app_id = ?
|
||||
GROUP BY u.department
|
||||
ORDER BY count DESC
|
||||
LIMIT 5
|
||||
`;
|
||||
const deptResult = await this.query(deptSql, [appId]);
|
||||
// 部門使用統計 - 支援日期範圍過濾
|
||||
let deptSql: string;
|
||||
let deptParams: any[];
|
||||
|
||||
// 使用趨勢 - 支援自定義日期範圍
|
||||
if (startDate && endDate) {
|
||||
deptSql = `
|
||||
SELECT
|
||||
u.department,
|
||||
COUNT(*) as count
|
||||
FROM user_views uv
|
||||
JOIN users u ON uv.user_id = u.id
|
||||
WHERE uv.app_id = ? AND DATE(uv.viewed_at) BETWEEN ? AND ?
|
||||
GROUP BY u.department
|
||||
ORDER BY count DESC
|
||||
LIMIT 5
|
||||
`;
|
||||
deptParams = [appId, startDate, endDate];
|
||||
} else {
|
||||
deptSql = `
|
||||
SELECT
|
||||
u.department,
|
||||
COUNT(*) as count
|
||||
FROM user_views uv
|
||||
JOIN users u ON uv.user_id = u.id
|
||||
WHERE uv.app_id = ?
|
||||
GROUP BY u.department
|
||||
ORDER BY count DESC
|
||||
LIMIT 5
|
||||
`;
|
||||
deptParams = [appId];
|
||||
}
|
||||
const deptResult = await this.query(deptSql, deptParams);
|
||||
|
||||
// 使用趨勢 - 支援自定義日期範圍和部門過濾
|
||||
let trendSql: string;
|
||||
let trendParams: any[];
|
||||
|
||||
// 構建部門過濾條件
|
||||
const departmentFilter = department ? 'AND u.department = ?' : '';
|
||||
const baseWhere = `uv.app_id = ? ${departmentFilter}`;
|
||||
|
||||
if (startDate && endDate) {
|
||||
// 使用自定義日期範圍
|
||||
trendSql = `
|
||||
SELECT
|
||||
DATE(viewed_at) as date,
|
||||
COUNT(DISTINCT user_id) as users
|
||||
FROM user_views
|
||||
WHERE app_id = ? AND DATE(viewed_at) BETWEEN ? AND ?
|
||||
GROUP BY DATE(viewed_at)
|
||||
DATE(uv.viewed_at) as date,
|
||||
COUNT(*) as users
|
||||
FROM user_views uv
|
||||
JOIN users u ON uv.user_id = u.id
|
||||
WHERE ${baseWhere} AND DATE(uv.viewed_at) BETWEEN ? AND ?
|
||||
GROUP BY DATE(uv.viewed_at)
|
||||
ORDER BY date ASC
|
||||
`;
|
||||
trendParams = [appId, startDate, endDate];
|
||||
trendParams = department ? [appId, department, startDate, endDate] : [appId, startDate, endDate];
|
||||
} else {
|
||||
// 預設過去7天
|
||||
trendSql = `
|
||||
SELECT
|
||||
DATE(viewed_at) as date,
|
||||
COUNT(DISTINCT user_id) as users
|
||||
FROM user_views
|
||||
WHERE app_id = ? AND viewed_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
|
||||
GROUP BY DATE(viewed_at)
|
||||
DATE(uv.viewed_at) as date,
|
||||
COUNT(*) as users
|
||||
FROM user_views uv
|
||||
JOIN users u ON uv.user_id = u.id
|
||||
WHERE ${baseWhere} AND uv.viewed_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
|
||||
GROUP BY DATE(uv.viewed_at)
|
||||
ORDER BY date ASC
|
||||
`;
|
||||
trendParams = [appId];
|
||||
trendParams = department ? [appId, department] : [appId];
|
||||
}
|
||||
|
||||
const trendResult = await this.query(trendSql, trendParams);
|
||||
|
Reference in New Issue
Block a user