Browse Source

修复部分bug

Pchen. 1 month ago
parent
commit
a75e998db7
1 changed files with 103 additions and 18 deletions
  1. 103 18
      lib/QK/TaskScheduler.js

+ 103 - 18
lib/QK/TaskScheduler.js

@@ -23,6 +23,8 @@ const REPORT_LOG_EVENTS = new Set([
 ])
 ])
 
 
 class TaskScheduler {
 class TaskScheduler {
+    static _schemaReady = false
+
     constructor(options = {}) {
     constructor(options = {}) {
         this.leaseMs = options.leaseMs || config.qk?.leaseMs || 90 * 1000
         this.leaseMs = options.leaseMs || config.qk?.leaseMs || 90 * 1000
         this.heartbeatTtlSeconds = options.heartbeatTtlSeconds || config.qk?.heartbeatTtlSeconds || 45
         this.heartbeatTtlSeconds = options.heartbeatTtlSeconds || config.qk?.heartbeatTtlSeconds || 45
@@ -35,6 +37,73 @@ class TaskScheduler {
         this.logger = options.logger || new Logger()
         this.logger = options.logger || new Logger()
     }
     }
 
 
+    async ensureSchema() {
+        if (TaskScheduler._schemaReady) {
+            return
+        }
+        try {
+            const rows = await db.query("SHOW COLUMNS FROM qk_task LIKE 'auto_relogin'")
+            if (!rows || rows.length === 0) {
+                await db.query(
+                    'ALTER TABLE qk_task ADD COLUMN auto_relogin TINYINT(1) NOT NULL DEFAULT 0 AFTER enable_ggxxk'
+                )
+                this.logInfo('ensureSchema', '已添加 qk_task.auto_relogin 字段')
+            }
+        } catch (err) {
+            this.logWarn('ensureSchema', '抢课任务表结构检查失败', {}, err)
+        }
+        TaskScheduler._schemaReady = true
+    }
+
+    parseAutoRelogin(payload = {}) {
+        if (payload.auto_relogin !== undefined) {
+            return payload.auto_relogin === true || Number(payload.auto_relogin) === 1
+        }
+        if (payload.AUTO_RELOGIN !== undefined) {
+            return payload.AUTO_RELOGIN === true || Number(payload.AUTO_RELOGIN) === 1
+        }
+        return false
+    }
+
+    extractReportCourseName(payload = {}) {
+        if (!payload || typeof payload !== 'object') {
+            return ''
+        }
+        if (payload.course_name) {
+            return String(payload.course_name)
+        }
+        if (payload.course) {
+            return String(payload.course)
+        }
+        if (payload.label) {
+            const label = String(payload.label)
+            const at = label.indexOf('@')
+            if (at > 0) {
+                return label.slice(0, at)
+            }
+            return label
+        }
+        if (Array.isArray(payload.courses) && payload.courses.length > 0) {
+            return payload.courses.join('、')
+        }
+        return ''
+    }
+
+    formatReportMessage(message = '', payload = {}) {
+        const courseName = this.extractReportCourseName(payload)
+        const text = String(message || '').trim()
+        if (!courseName) {
+            return text
+        }
+        if (!text) {
+            return `[${courseName}]`
+        }
+        if (text.includes(`[${courseName}]`) || text.startsWith(`${courseName}:`)) {
+            return text
+        }
+        return `[${courseName}] ${text}`
+    }
+
     calculateMaxSlots(profile = {}) {
     calculateMaxSlots(profile = {}) {
         const freeMb = Math.max(0, Number(profile.free_mem_mb) || 0)
         const freeMb = Math.max(0, Number(profile.free_mem_mb) || 0)
         const totalMb = Math.max(0, Number(profile.total_mem_mb) || 0)
         const totalMb = Math.max(0, Number(profile.total_mem_mb) || 0)
@@ -273,6 +342,7 @@ class TaskScheduler {
     serializeTask(row, includeSecret = false) {
     serializeTask(row, includeSecret = false) {
         const result = { ...row }
         const result = { ...row }
         result.enable_ggxxk = Number(result.enable_ggxxk) === 1
         result.enable_ggxxk = Number(result.enable_ggxxk) === 1
+        result.auto_relogin = Number(result.auto_relogin) === 1
         result.courses = this.normalizeArray(result.courses)
         result.courses = this.normalizeArray(result.courses)
         result.course_groups = this.normalizeArray(result.course_groups)
         result.course_groups = this.normalizeArray(result.course_groups)
         if (typeof result.result_json === 'string' && result.result_json) {
         if (typeof result.result_json === 'string' && result.result_json) {
@@ -475,23 +545,31 @@ class TaskScheduler {
                 result.payload_json = JSON.parse(result.payload_json)
                 result.payload_json = JSON.parse(result.payload_json)
             } catch (_) {}
             } catch (_) {}
         }
         }
+        const payload = result.payload_json && typeof result.payload_json === 'object'
+            ? result.payload_json
+            : {}
+        result.course_name = this.extractReportCourseName(payload)
+        result.display_message = this.formatReportMessage(result.message, payload)
         return result
         return result
     }
     }
 
 
     buildReportMessage(payload = {}) {
     buildReportMessage(payload = {}) {
-        if (payload.message) {
-            return String(payload.message)
-        }
-        if (payload.error_msg) {
-            return String(payload.error_msg)
-        }
-        if (payload.error) {
-            return String(payload.error)
-        }
-        if (payload.success === true) {
-            return payload.label ? `${payload.label} 成功` : '请求成功'
-        }
-        return payload.label ? `${payload.label} 失败` : '请求失败'
+        const base = (() => {
+            if (payload.message) {
+                return String(payload.message)
+            }
+            if (payload.error_msg) {
+                return String(payload.error_msg)
+            }
+            if (payload.error) {
+                return String(payload.error)
+            }
+            if (payload.success === true) {
+                return payload.label ? `${payload.label} 成功` : '请求成功'
+            }
+            return payload.label ? `${payload.label} 失败` : '请求失败'
+        })()
+        return this.formatReportMessage(base, payload)
     }
     }
 
 
     async assertClientTaskAccess(clientId, taskId) {
     async assertClientTaskAccess(clientId, taskId) {
@@ -553,6 +631,7 @@ class TaskScheduler {
     }
     }
 
 
     async createTask(uuid, payload) {
     async createTask(uuid, payload) {
+        await this.ensureSchema()
         const validated = this.validateTaskCoursesAndInterval(
         const validated = this.validateTaskCoursesAndInterval(
             payload.courses || payload.COURSES,
             payload.courses || payload.COURSES,
             payload.course_groups || payload.COURSE_GROUPS,
             payload.course_groups || payload.COURSE_GROUPS,
@@ -563,8 +642,8 @@ class TaskScheduler {
         await this.requireEnabledBatch(batchId)
         await this.requireEnabledBatch(batchId)
         const time = Date.now()
         const time = Date.now()
         const sql = `INSERT INTO qk_task
         const sql = `INSERT INTO qk_task
-            (create_user, name, batch_id, jx0502zbid, student_num, password_enc, courses, course_groups, enable_ggxxk, interval_ms, status, create_time, update_time)
-            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
+            (create_user, name, batch_id, jx0502zbid, student_num, password_enc, courses, course_groups, enable_ggxxk, auto_relogin, interval_ms, status, create_time, update_time)
+            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
         const result = await db.query(sql, [
         const result = await db.query(sql, [
             uuid,
             uuid,
             payload.name,
             payload.name,
@@ -575,6 +654,7 @@ class TaskScheduler {
             JSON.stringify(courses),
             JSON.stringify(courses),
             JSON.stringify(courseGroups),
             JSON.stringify(courseGroups),
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
+            this.parseAutoRelogin(payload) ? 1 : 0,
             intervalMs,
             intervalMs,
             TASK_STATUS.PAUSED,
             TASK_STATUS.PAUSED,
             time,
             time,
@@ -591,12 +671,14 @@ class TaskScheduler {
             courses_count: courses.length,
             courses_count: courses.length,
             course_groups_count: courseGroups.length,
             course_groups_count: courseGroups.length,
             interval_ms: intervalMs,
             interval_ms: intervalMs,
-            enable_ggxxk: !!(payload.enable_ggxxk || payload.ENABLE_GGXXK)
+            enable_ggxxk: !!(payload.enable_ggxxk || payload.ENABLE_GGXXK),
+            auto_relogin: this.parseAutoRelogin(payload)
         })
         })
         return result.insertId
         return result.insertId
     }
     }
 
 
     async updateTask(uuid, taskId, payload) {
     async updateTask(uuid, taskId, payload) {
+        await this.ensureSchema()
         const rows = await db.query('SELECT status FROM qk_task WHERE id = ? AND create_user = ?', [taskId, uuid])
         const rows = await db.query('SELECT status FROM qk_task WHERE id = ? AND create_user = ?', [taskId, uuid])
         if (!rows || rows.length === 0) {
         if (!rows || rows.length === 0) {
             throw new Error('任务不存在')
             throw new Error('任务不存在')
@@ -620,6 +702,7 @@ class TaskScheduler {
             JSON.stringify(courses),
             JSON.stringify(courses),
             JSON.stringify(courseGroups),
             JSON.stringify(courseGroups),
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
+            this.parseAutoRelogin(payload) ? 1 : 0,
             intervalMs,
             intervalMs,
             TASK_STATUS.PAUSED,
             TASK_STATUS.PAUSED,
             Date.now()
             Date.now()
@@ -628,7 +711,7 @@ class TaskScheduler {
             params.splice(3, 0, this.encryptPassword(payload.password || payload.pass))
             params.splice(3, 0, this.encryptPassword(payload.password || payload.pass))
         }
         }
         params.push(taskId, uuid)
         params.push(taskId, uuid)
-        const sql = `UPDATE qk_task SET name = ?, batch_id = ?, student_num = ?${passwordSql}, courses = ?, course_groups = ?, enable_ggxxk = ?, interval_ms = ?, status = ?, jx0502zbid = '', update_time = ?, assigned_client_id = NULL, lease_expire_at = NULL, result_json = NULL, error_msg = NULL, finished_time = NULL WHERE id = ? AND create_user = ?`
+        const sql = `UPDATE qk_task SET name = ?, batch_id = ?, student_num = ?${passwordSql}, courses = ?, course_groups = ?, enable_ggxxk = ?, auto_relogin = ?, interval_ms = ?, status = ?, jx0502zbid = '', update_time = ?, assigned_client_id = NULL, lease_expire_at = NULL, result_json = NULL, error_msg = NULL, finished_time = NULL WHERE id = ? AND create_user = ?`
         const result = await db.query(sql, params)
         const result = await db.query(sql, params)
         if (!result || result.affectedRows <= 0) {
         if (!result || result.affectedRows <= 0) {
             throw new Error('更新抢课任务失败')
             throw new Error('更新抢课任务失败')
@@ -784,6 +867,7 @@ class TaskScheduler {
     }
     }
 
 
     async adminUpdateTask(taskId, payload) {
     async adminUpdateTask(taskId, payload) {
+        await this.ensureSchema()
         const rows = await db.query('SELECT * FROM qk_task WHERE id = ?', [taskId])
         const rows = await db.query('SELECT * FROM qk_task WHERE id = ?', [taskId])
         if (!rows || rows.length === 0) {
         if (!rows || rows.length === 0) {
             throw new Error('任务不存在')
             throw new Error('任务不存在')
@@ -810,6 +894,7 @@ class TaskScheduler {
             JSON.stringify(courses),
             JSON.stringify(courses),
             JSON.stringify(courseGroups),
             JSON.stringify(courseGroups),
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
             payload.enable_ggxxk || payload.ENABLE_GGXXK ? 1 : 0,
+            this.parseAutoRelogin(payload) ? 1 : 0,
             intervalMs,
             intervalMs,
             TASK_STATUS.PAUSED,
             TASK_STATUS.PAUSED,
             now
             now
@@ -818,7 +903,7 @@ class TaskScheduler {
             params.splice(3, 0, this.encryptPassword(payload.password || payload.pass))
             params.splice(3, 0, this.encryptPassword(payload.password || payload.pass))
         }
         }
         params.push(taskId)
         params.push(taskId)
-        const sql = `UPDATE qk_task SET name = ?, batch_id = ?, student_num = ?${passwordSql}, courses = ?, course_groups = ?, enable_ggxxk = ?, interval_ms = ?, status = ?, jx0502zbid = '', update_time = ?, assigned_client_id = NULL, lease_expire_at = NULL, assigned_at = NULL, exclude_client_id = NULL, result_json = NULL, error_msg = NULL, finished_time = NULL WHERE id = ?`
+        const sql = `UPDATE qk_task SET name = ?, batch_id = ?, student_num = ?${passwordSql}, courses = ?, course_groups = ?, enable_ggxxk = ?, auto_relogin = ?, interval_ms = ?, status = ?, jx0502zbid = '', update_time = ?, assigned_client_id = NULL, lease_expire_at = NULL, assigned_at = NULL, exclude_client_id = NULL, result_json = NULL, error_msg = NULL, finished_time = NULL WHERE id = ?`
         const result = await db.query(sql, params)
         const result = await db.query(sql, params)
         if (!result || result.affectedRows <= 0) {
         if (!result || result.affectedRows <= 0) {
             throw new Error('更新抢课任务失败')
             throw new Error('更新抢课任务失败')