Browse Source

✨ feat: 完善二师乐跑

Pchen. 1 month ago
parent
commit
ce912ed670

+ 57 - 0
apis/Corn/ResetMonthTermNum.js

@@ -0,0 +1,57 @@
+const API = require("../../lib/API.js")
+const db = require('../../plugin/DataBase/db')
+const Redis = require('../../plugin/DataBase/Redis')
+const { BaseStdResponse } = require("../../BaseStdResponse")
+
+class ResetMonthTermNum extends API {
+    constructor() {
+        super()
+        this.noEncrypt()
+        this.setPath('/Corn/ResetMonthTermNum')
+        this.setMethod('GET')
+    }
+
+    async onRequest(req, res) {
+        try {
+            res.json({
+                ...BaseStdResponse.OK
+            })
+
+            // 1) 清空所有账号本月累计里程(term_num)
+            const r = await db.query('UPDATE lepao_account SET term_num = 0')
+            if (!r) {
+                this.logger.error('月初重置 term_num 失败:数据库更新失败')
+                return
+            }
+
+            // 2) 清理 Redis 当月缓存(jkes_month:{student}:{YYYY-MM})
+            const now = new Date()
+            const y = now.getFullYear()
+            const m = String(now.getMonth() + 1).padStart(2, '0')
+            const pattern = `jkes_month:*:${y}-${m}`
+
+            try {
+                const toDel = []
+                for await (const key of Redis.scanIterator({ MATCH: pattern, COUNT: 500 })) {
+                    toDel.push(key)
+                    if (toDel.length >= 500) {
+                        await Redis.del(toDel)
+                        toDel.length = 0
+                    }
+                }
+                if (toDel.length) {
+                    await Redis.del(toDel)
+                }
+            } catch (e) {
+                this.logger.warn(`月初清理 Redis 月缓存失败:${e.message || e}`)
+            }
+
+            this.logger.info(`月初重置完成:term_num=0,pattern=${pattern}`)
+        } catch (error) {
+            this.logger.error(error)
+        }
+    }
+}
+
+module.exports.ResetMonthTermNum = ResetMonthTermNum
+

+ 3 - 3
apis/Lepao/Account/AddAccount.js

@@ -78,7 +78,7 @@ class AddAccount extends API {
                 ...BaseStdResponse.ACCESS_DENIED
                 ...BaseStdResponse.ACCESS_DENIED
             })
             })
 
 
-        let countSql = 'SELECT id, create_user, total_num FROM lepao_account WHERE student_num = ?'
+        let countSql = 'SELECT id, create_user, total_num, term_num FROM lepao_account WHERE student_num = ?'
         let countRows = await db.query(countSql, [student_num])
         let countRows = await db.query(countSql, [student_num])
 
 
         if (!countRows)
         if (!countRows)
@@ -94,10 +94,10 @@ class AddAccount extends API {
         }
         }
 
 
         if (countRows.length !== 0) {
         if (countRows.length !== 0) {
-            if (auto_run === 1 && countRows[0].total_num >= targetKm && targetKm !== 0)
+            if (auto_run === 1 && countRows[0].term_num >= targetKm && targetKm !== 0)
                 return res.json({
                 return res.json({
                     ...BaseStdResponse.ERR,
                     ...BaseStdResponse.ERR,
-                    msg: '该账号累计跑步里程已达到或超过预设目标里程,请增大目标后再试'
+                    msg: '该账号本月跑步里程已达到或超过预设目标里程,请增大目标后再试'
                 })
                 })
         }
         }
 
 

+ 3 - 3
apis/Lepao/ChangeAutoRun.js

@@ -24,7 +24,7 @@ class ChangeAutoRun extends API {
                 ...BaseStdResponse.ACCESS_DENIED
                 ...BaseStdResponse.ACCESS_DENIED
             })
             })
 
 
-        let selectSql = 'SELECT create_user, target_count, total_num, auto_run FROM lepao_account WHERE id = ?'
+        let selectSql = 'SELECT create_user, target_count, term_num, auto_run FROM lepao_account WHERE id = ?'
         let selectRows = await db.query(selectSql, [id])
         let selectRows = await db.query(selectSql, [id])
         if (!selectRows || selectRows.length === 0)
         if (!selectRows || selectRows.length === 0)
             return res.json({
             return res.json({
@@ -41,10 +41,10 @@ class ChangeAutoRun extends API {
                 })
                 })
         }
         }
 
 
-        if (selectRows[0].auto_run === 0 && (selectRows[0].target_count <= selectRows[0].total_num) && selectRows[0].target_count !== 0) {
+        if (selectRows[0].auto_run === 0 && (selectRows[0].target_count <= selectRows[0].term_num) && selectRows[0].target_count !== 0) {
             return res.json({
             return res.json({
                 ...BaseStdResponse.ERR,
                 ...BaseStdResponse.ERR,
-                msg: '该账号累计跑步次数已达到预设目标次数,请尝试增大目标次数后再试'
+                msg: '该账号本月跑步里程已达到预设目标里程,请尝试增大目标后再试'
             })
             })
         }
         }
 
 

+ 7 - 0
apis/Lepao/Record/Admin/GetLepaoRecords.js

@@ -61,6 +61,9 @@ class AdminGetLepaoRecords extends API {
                     r.path_id,
                     r.path_id,
                     a.name,
                     a.name,
                     a.user_avatar,
                     a.user_avatar,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance,
                     u.username,
                     u.username,
                     u.avatar
                     u.avatar
                 FROM 
                 FROM 
@@ -69,6 +72,10 @@ class AdminGetLepaoRecords extends API {
                     lepao_account a
                     lepao_account a
                 ON 
                 ON 
                     r.lepao_account = a.student_num
                     r.lepao_account = a.student_num
+                LEFT JOIN
+                    path_data p
+                ON
+                    r.path_id = p.id
                 LEFT JOIN 
                 LEFT JOIN 
                     users u
                     users u
                 ON 
                 ON 

+ 8 - 2
apis/Lepao/Record/Admin/GetRecordDetail.js

@@ -63,7 +63,10 @@ class AdminGetRecordDetail extends API {
                     r.path_id,
                     r.path_id,
                     r.path_data AS run_path_data,
                     r.path_data AS run_path_data,
                     a.name,
                     a.name,
-                    p.data
+                    p.data,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance
                 ${baseWhere}
                 ${baseWhere}
             `
             `
             rows = await db.query(sql, [id])
             rows = await db.query(sql, [id])
@@ -78,7 +81,10 @@ class AdminGetRecordDetail extends API {
                     r.path_id,
                     r.path_id,
                     r.point_data AS run_path_data,
                     r.point_data AS run_path_data,
                     a.name,
                     a.name,
-                    p.data
+                    p.data,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance
                 ${baseWhere}
                 ${baseWhere}
             `
             `
             rows = await db.query(sql, [id])
             rows = await db.query(sql, [id])

+ 8 - 1
apis/Lepao/Record/GetLepaoRecords.js

@@ -53,13 +53,20 @@ class GetLepaoRecords extends API {
                     r.lepao_account,
                     r.lepao_account,
                     r.path_id,
                     r.path_id,
                     a.name,
                     a.name,
-                    a.user_avatar
+                    a.user_avatar,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance
                 FROM 
                 FROM 
                     lepao_record r
                     lepao_record r
                 LEFT JOIN 
                 LEFT JOIN 
                     lepao_account a
                     lepao_account a
                 ON 
                 ON 
                     r.lepao_account = a.student_num
                     r.lepao_account = a.student_num
+                LEFT JOIN
+                    path_data p
+                ON
+                    r.path_id = p.id
                 WHERE 
                 WHERE 
                     (r.uuid = ? OR a.create_user = ?)
                     (r.uuid = ? OR a.create_user = ?)
             `
             `

+ 8 - 2
apis/Lepao/Record/GetRecordDetail.js

@@ -55,7 +55,10 @@ class GetRecordDetail extends API {
                     r.path_id,
                     r.path_id,
                     r.path_data AS run_path_data,
                     r.path_data AS run_path_data,
                     a.name,
                     a.name,
-                    p.data
+                    p.data,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance
                 ${baseWhere}
                 ${baseWhere}
             `
             `
             rows = await db.query(sql, [uuid, uuid, id])
             rows = await db.query(sql, [uuid, uuid, id])
@@ -70,7 +73,10 @@ class GetRecordDetail extends API {
                     r.path_id,
                     r.path_id,
                     r.point_data AS run_path_data,
                     r.point_data AS run_path_data,
                     a.name,
                     a.name,
-                    p.data
+                    p.data,
+                    p.run_zone_name,
+                    p.run_zone_name AS path_run_zone_name,
+                    NULL AS path_distance
                 ${baseWhere}
                 ${baseWhere}
             `
             `
             rows = await db.query(sql, [uuid, uuid, id])
             rows = await db.query(sql, [uuid, uuid, id])

+ 6 - 13
apis/Lepao/SingleRun.js

@@ -34,21 +34,14 @@ class SingleRun extends API {
                 ...BaseStdResponse.ACCESS_DENIED
                 ...BaseStdResponse.ACCESS_DENIED
             })
             })
 
 
-        let hour = new Date().getHours()
-        if (hour < 7)
-            return res.json({
-                ...BaseStdResponse.ERR,
-                msg: '当前不在有效乐跑时间范围内。请在7:00~24:00发起乐跑'
-            })
+        // let hour = new Date().getHours()
+        // if (hour < 7)
+        //     return res.json({
+        //         ...BaseStdResponse.ERR,
+        //         msg: '当前不在有效乐跑时间范围内。请在7:00~24:00发起乐跑'
+        //     })
 
 
         try {
         try {
-            const isSuccess = await Redis.get(jkesRedisKeys.lepaoSuccess(student_num))
-            if (isSuccess)
-                return res.json({
-                    ...BaseStdResponse.ERR,
-                    msg: '该账号当天已乐跑成功!请勿重复乐跑'
-                })
-
             const isProgress = await Redis.get(jkesRedisKeys.lepaoProgress(student_num))
             const isProgress = await Redis.get(jkesRedisKeys.lepaoProgress(student_num))
             if (isProgress)
             if (isProgress)
                 return res.json({
                 return res.json({

+ 73 - 9
lib/Lepao/Worker.js

@@ -289,8 +289,8 @@ class Worker {
             let deductedKm = 0
             let deductedKm = 0
 
 
             try {
             try {
-                const isSuccess = await Redis.get(jkesRedisKeys.lepaoSuccess(req.account))
-                if (isSuccess) throw new Error('该账号当天已乐跑成功!请勿重复乐跑')
+                // const isSuccess = await Redis.get(jkesRedisKeys.lepaoSuccess(req.account))
+                // if (isSuccess) throw new Error('该账号当天已乐跑成功!请勿重复乐跑')
 
 
                 userData = await this.handlers['lepao.getUserData'](req, ctx)
                 userData = await this.handlers['lepao.getUserData'](req, ctx)
 
 
@@ -308,9 +308,9 @@ class Worker {
                 await Redis.set(progressKey, req.account, { EX: 1800 })
                 await Redis.set(progressKey, req.account, { EX: 1800 })
 
 
                 const hour = new Date().getHours()
                 const hour = new Date().getHours()
-                if (hour < 7) {
-                    throw new Error('当前不在有效乐跑时间范围内。RunForge支持乐跑时间段为7:00~24:00')
-                }
+                // if (hour < 7) {
+                //     throw new Error('当前不在有效乐跑时间范围内。RunForge支持乐跑时间段为7:00~24:00')
+                // }
 
 
                 const { runJkesRecord } = require('../../plugin/jkes/runRecord')
                 const { runJkesRecord } = require('../../plugin/jkes/runRecord')
                 const { getJkesSettings } = require('../../plugin/jkes/jkesSettings')
                 const { getJkesSettings } = require('../../plugin/jkes/jkesSettings')
@@ -407,18 +407,26 @@ class Worker {
                 }
                 }
 
 
                 const info = jkesEnd.endJson?.data?.info
                 const info = jkesEnd.endJson?.data?.info
+                const infoWithMeta = info
+                    ? {
+                          ...info,
+                          planned_km: targetKm,
+                          deducted_km: deductedKm,
+                          pace_sec_per_km: pace
+                      }
+                    : null
                 if (!recordDbId) {
                 if (!recordDbId) {
                     recordDbId = await this.createLepaoRecord({
                     recordDbId = await this.createLepaoRecord({
                         uuid: userData?.create_user,
                         uuid: userData?.create_user,
                         account: req.account,
                         account: req.account,
                         pathId: jkesPathId,
                         pathId: jkesPathId,
                         pathData: jkesEnd.uploadedPayloadPoints || [],
                         pathData: jkesEnd.uploadedPayloadPoints || [],
-                        result: info || jkesEnd.endJson?.data || {},
+                        result: infoWithMeta || jkesEnd.endJson?.data || {},
                         state: 1
                         state: 1
                     })
                     })
                 } else {
                 } else {
                     await this.updateLepaoRecord(recordDbId, {
                     await this.updateLepaoRecord(recordDbId, {
-                        result: info || jkesEnd.endJson?.data || {},
+                        result: infoWithMeta || jkesEnd.endJson?.data || {},
                         pathData: jkesEnd.uploadedPayloadPoints || [],
                         pathData: jkesEnd.uploadedPayloadPoints || [],
                         state: 1
                         state: 1
                     })
                     })
@@ -592,12 +600,43 @@ class Worker {
             }
             }
 
 
             await this.updateLepaoRecord(recordDbId, {
             await this.updateLepaoRecord(recordDbId, {
-                result: latest,
+                result: {
+                    ...(latest || {}),
+                    planned_km: this.roundKm(targetKm || 0),
+                    deducted_km: preDeduct,
+                    official_km: officialKm,
+                    refunded_km: refundKm
+                },
                 state: 2
                 state: 2
             })
             })
             await recordSuccess(account, officialKm, { autoDoubleSlot: officialKm >= 2 && !!autoDoubleSlot })
             await recordSuccess(account, officialKm, { autoDoubleSlot: officialKm >= 2 && !!autoDoubleSlot })
             await this.syncRunCount({ account, student_id: account, token })
             await this.syncRunCount({ account, student_id: account, token })
 
 
+            // 达成本月预设目标后:关闭自动乐跑并发送目标完成邮件(target_count=0 表示不限制)
+            try {
+                const accRows = await db.query(
+                    'SELECT name, email, notice_type, auto_run, target_count, term_num, total_num FROM lepao_account WHERE student_num = ?',
+                    [account]
+                )
+                if (accRows && accRows.length) {
+                    const acc = accRows[0]
+                    const targetKm = Number(acc.target_count) || 0
+                    const monthKm = Number(acc.term_num) || 0
+                    if (acc.auto_run === 1 && targetKm !== 0 && monthKm >= targetKm) {
+                        await db.query('UPDATE lepao_account SET auto_run = 0 WHERE student_num = ?', [account])
+
+                        if (acc.notice_type === 'email' && acc.email) {
+                            await EmailTemplate.lepaoOver(acc.email, {
+                                name: acc.name || account,
+                                month_km: monthKm
+                            })
+                        }
+                    }
+                }
+            } catch (e) {
+                this.logger.warn(`[${traceId}] 目标达成处理失败:${e.message || e}`)
+            }
+
             if (ctx.channel) {
             if (ctx.channel) {
                 await this.enqueueTask(ctx.channel, 'lepao.sendNotice', {
                 await this.enqueueTask(ctx.channel, 'lepao.sendNotice', {
                     account,
                     account,
@@ -626,6 +665,8 @@ class Worker {
                     a.name, 
                     a.name, 
                     a.email, 
                     a.email, 
                     a.target_count,
                     a.target_count,
+                    a.term_num,
+                    a.total_num,
                     a.notice_type,
                     a.notice_type,
                     e.bot_umo
                     e.bot_umo
                 FROM 
                 FROM 
@@ -645,12 +686,35 @@ class Worker {
             const user = rows[0]
             const user = rows[0]
             const noticeType = user.notice_type || 'none'
             const noticeType = user.notice_type || 'none'
 
 
+            let runZoneName = data?.run_zone_name
+            if (!runZoneName && success) {
+                try {
+                    const z = await db.query(
+                        `
+                        SELECT p.run_zone_name
+                        FROM lepao_record r
+                        LEFT JOIN path_data p ON r.path_id = p.id
+                        WHERE r.lepao_account = ?
+                        ORDER BY r.id DESC
+                        LIMIT 1
+                        `,
+                        [account]
+                    )
+                    runZoneName = z?.length ? z[0].run_zone_name : null
+                } catch (e) {
+                    this.logger.warn(`[${traceId}] 查询跑区失败:${e.message || e}`)
+                }
+            }
+
             const payload = success
             const payload = success
                 ? {
                 ? {
                       ...(data && typeof data === 'object' ? data : {}),
                       ...(data && typeof data === 'object' ? data : {}),
                       type: 'lepao_success',
                       type: 'lepao_success',
                       umo: user.bot_umo,
                       umo: user.bot_umo,
-                      term_num: user.target_count ?? 0,
+                      run_zone_name: runZoneName,
+                      month_km: Number(user.term_num) || 0,
+                      total_km: Number(user.total_num) || 0,
+                      target_km: Number(user.target_count) || 0,
                       name: user.name,
                       name: user.name,
                       account,
                       account,
                       traceId
                       traceId

+ 8 - 7
plugin/Email/emailTemplate.js

@@ -359,6 +359,10 @@ class emailTemplate {
                     📬 如果有任何问题,随时给我们戳小窗~我们在线等你哟 (´▽`)ノ♪
                     📬 如果有任何问题,随时给我们戳小窗~我们在线等你哟 (´▽`)ノ♪
                     </p>
                     </p>
 
 
+                    <div class="info">
+                      <p><strong>本月累计里程:</strong> ${(Number(data.month_km) || 0).toFixed(2)} Km 🎉</p>
+                    </div>
+
                     <p>
                     <p>
                     🥳 祝你假期躺赢、学习加buff、每天都开心到冒泡泡!✧*。٩(ˊᗜˋ*)و✧*。<br>
                     🥳 祝你假期躺赢、学习加buff、每天都开心到冒泡泡!✧*。٩(ˊᗜˋ*)و✧*。<br>
                     📚 新学期我们一起继续加速奔跑吧~Let's gooo!🔥🔥
                     📚 新学期我们一起继续加速奔跑吧~Let's gooo!🔥🔥
@@ -451,16 +455,13 @@ class emailTemplate {
 
 
                 <div class="info">
                 <div class="info">
                 <p><strong>学号:</strong> ${data.account}</p>
                 <p><strong>学号:</strong> ${data.account}</p>
-                <p><strong>跑区:</strong> ${data.pass_tit} 🌈</p>
+                <p><strong>跑区:</strong> ${data.run_zone_name ?? data.pass_tit ?? '—'} 🌈</p>
                 <p><strong>跑步时间:</strong> ${this.formatSecondsToMinSec(data.time)} ⏱️</p>
                 <p><strong>跑步时间:</strong> ${this.formatSecondsToMinSec(data.time)} ⏱️</p>
                 <p><strong>平均配速:</strong> ${this.calculatePace(data.time, data.distance)} 🐇</p>
                 <p><strong>平均配速:</strong> ${this.calculatePace(data.time, data.distance)} 🐇</p>
                 <p><strong>跑步距离:</strong> ${data.distance} Km 💕</p>
                 <p><strong>跑步距离:</strong> ${data.distance} Km 💕</p>
-                <p><strong>累计次数:</strong> ${data.total_num} 次 ✨</p>
-                <p><strong>剩余次数:</strong>  ${data.term_num === 0 
-                                                ? '∞' 
-                                                : (data.term_num - data.total_num >= 0 
-                                                    ? (data.term_num - data.total_num) 
-                                                    : '已完成')} 次 🎯</p>
+                <p><strong>本月累计:</strong> ${(Number(data.month_km) || 0).toFixed(2)} Km ✨</p>
+                <p><strong>累计总里程:</strong> ${(Number(data.total_km) || 0).toFixed(2)} Km 🧾</p>
+                <p><strong>本月目标:</strong> ${Number(data.target_km) === 0 ? '不限' : `${(Number(data.target_km) || 0).toFixed(2)} Km`} 🎯</p>
                 </div>
                 </div>
 
 
                 <p class="important">如果宝宝开启了自动乐跑,要记得不要在其他设备上登录“智慧体育”小程序哦 🚫📱,不然登录就会失效,要重新来一次啦~</p>
                 <p class="important">如果宝宝开启了自动乐跑,要记得不要在其他设备上登录“智慧体育”小程序哦 🚫📱,不然登录就会失效,要重新来一次啦~</p>

+ 9 - 3
plugin/jkes/monthPolicy.js

@@ -97,8 +97,15 @@ async function refreshMonthKmFromApi(account, token, d = new Date()) {
     const m = d.getMonth() + 1
     const m = d.getMonth() + 1
     const apiKm = await fetchJkesMonthKm(token, y, m)
     const apiKm = await fetchJkesMonthKm(token, y, m)
     const prev = await readState(account, d)
     const prev = await readState(account, d)
-    /** 官方 mylist 里程、配速往往延迟数分钟~数十分钟才更新,取较大值避免覆盖 recordSuccess/本地进度 */
-    const km = Math.max(apiKm, Number(prev.km) || 0)
+    /**
+     * 官方 mylist 里程、配速往往延迟数分钟~数十分钟才更新。
+     * 但本地 Redis 可能因历史累计/异常写入变得非常大,不能无条件取 max,
+     * 否则会导致“未达标却被判定已达标”。
+     * 仅在差距较小(<=5km)时才允许用本地值兜底。
+     */
+    const prevKm = Number(prev.km) || 0
+    const drift = prevKm - apiKm
+    const km = drift > 0 && drift <= 5 ? prevKm : apiKm
     await writeState(account, { km, doubles: prev.doubles }, d)
     await writeState(account, { km, doubles: prev.doubles }, d)
     return km
     return km
 }
 }
@@ -173,7 +180,6 @@ async function planJkesAutoRun(account, autoDayRaw, token, options = {}, d = new
         targetKm = Math.max(targetKm, 2)
         targetKm = Math.max(targetKm, 2)
     }
     }
     targetKm = Math.min(maxAutoSingleKm, Math.max(1, Math.round(targetKm * 100) / 100))
     targetKm = Math.min(maxAutoSingleKm, Math.max(1, Math.round(targetKm * 100) / 100))
-
     return { run: true, targetKm, monthTargetKm }
     return { run: true, targetKm, monthTargetKm }
 }
 }
 
 

+ 4 - 10
plugin/jkes/runRecord.js

@@ -270,7 +270,7 @@ async function runJkesRecord(opts) {
         firstBatchSize = 1,
         firstBatchSize = 1,
         altitude = s.gpsAltitude,
         altitude = s.gpsAltitude,
         defaultAccuracy = s.gpsDefaultAccuracy,
         defaultAccuracy = s.gpsDefaultAccuracy,
-        log = () => {}
+        log = () => { }
     } = opts
     } = opts
 
 
     if (!token || String(token).trim() === '') {
     if (!token || String(token).trim() === '') {
@@ -334,7 +334,8 @@ async function runJkesRecord(opts) {
         speed: points[0].speed >= 0 ? points[0].speed : -1
         speed: points[0].speed >= 0 ? points[0].speed : -1
     })
     })
     const recordId = startJson.data.info.id
     const recordId = startJson.data.info.id
-    log(`已开始跑步 recordId=${recordId}`)
+    const chunks = chunkPoints(points, firstBatchSize, batchSize)
+    log(`已开始跑步 recordId=${recordId} 预计耗时${(CALC_INTERVAL_MS * chunks.length / 1000).toFixed(2)}秒`)
 
 
     const calcState = {
     const calcState = {
         runStartMs,
         runStartMs,
@@ -347,8 +348,6 @@ async function runJkesRecord(opts) {
             calcState.nextCalcDueDeviceTime += CALC_INTERVAL_MS
             calcState.nextCalcDueDeviceTime += CALC_INTERVAL_MS
         }
         }
     }
     }
-
-    const chunks = chunkPoints(points, firstBatchSize, batchSize)
     const uploadedPayloadPoints = []
     const uploadedPayloadPoints = []
     let prevSegmentEndDeviceTime = null
     let prevSegmentEndDeviceTime = null
 
 
@@ -358,7 +357,6 @@ async function runJkesRecord(opts) {
             const gap = chunk[0].deviceTime - prevSegmentEndDeviceTime
             const gap = chunk[0].deviceTime - prevSegmentEndDeviceTime
             const waitMs = Math.max(0, gap)
             const waitMs = Math.max(0, gap)
             if (waitMs > 0) {
             if (waitMs > 0) {
-                log(`等待 ${waitMs}ms(批次间隔)`)
                 await sleep(waitMs)
                 await sleep(waitMs)
             }
             }
         }
         }
@@ -371,13 +369,11 @@ async function runJkesRecord(opts) {
         const batch = chunk.map((p) => toGpsPayloadPoint(p, { altitude, defaultAccuracy }))
         const batch = chunk.map((p) => toGpsPayloadPoint(p, { altitude, defaultAccuracy }))
         await postJson(`/health/runRecord/gps/${recordId}`, batch)
         await postJson(`/health/runRecord/gps/${recordId}`, batch)
         uploadedPayloadPoints.push(...batch)
         uploadedPayloadPoints.push(...batch)
-        log(`已上传 GPS 批次 ${c + 1}/${chunks.length}`)
 
 
         await flushCalcThroughDeviceTime(tEnd)
         await flushCalcThroughDeviceTime(tEnd)
 
 
         const intraMs = Math.max(0, tEnd - tStart)
         const intraMs = Math.max(0, tEnd - tStart)
         if (intraMs > 0) {
         if (intraMs > 0) {
-            log(`等待 ${intraMs}ms(批内时长)`)
             await sleep(intraMs)
             await sleep(intraMs)
         }
         }
 
 
@@ -385,10 +381,8 @@ async function runJkesRecord(opts) {
     }
     }
 
 
     await postJson(`/health/runRecord/pause/${recordId}`, {})
     await postJson(`/health/runRecord/pause/${recordId}`, {})
-    log('已暂停(结束跑步前必须暂停)')
-
     const endJson = await postJson(`/health/runRecord/end/${recordId}`, {})
     const endJson = await postJson(`/health/runRecord/end/${recordId}`, {})
-    log('跑步已结束')
+    log(`ID:{recordId} 跑步已结束`)
     return { recordId, endJson, runStartMs, uploadedPayloadPoints }
     return { recordId, endJson, runStartMs, uploadedPayloadPoints }
 }
 }