Browse Source

✨ feat: 新增bot通知提醒

Pchen. 1 month ago
parent
commit
d3b16340cc

+ 43 - 5
apis/Lepao/Account/UpdateAccount/UpdateAccount.js

@@ -4,6 +4,7 @@ const axios = require('axios')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const config = require('../../../../config.json')
 const config = require('../../../../config.json')
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
+const mq = require('../../../../plugin/mq')
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 
 
 // 客户端上传数据接口
 // 客户端上传数据接口
@@ -11,6 +12,8 @@ class UpdateAccount extends API {
     constructor() {
     constructor() {
         super()
         super()
 
 
+        this.messageQueue = 'runforge_message_queue'
+
         this.runpy = config.runpy
         this.runpy = config.runpy
         this.noEncrypt()
         this.noEncrypt()
         this.setPath('/Lepao/UpdateAccount')
         this.setPath('/Lepao/UpdateAccount')
@@ -55,7 +58,19 @@ class UpdateAccount extends API {
                     msg: '未提取出用户登录信息,请重试'
                     msg: '未提取出用户登录信息,请重试'
                 })
                 })
 
 
-            let findSql = 'SELECT email, create_user, auto_run, auto_day FROM lepao_account WHERE student_num = ? AND create_user IS NOT NULL'
+            let findSql = `
+                SELECT 
+                    a.email, a.create_user, a.auto_run, a.auto_day, a.notice_type, e.umo
+                FROM
+                    lepao_account a
+                LEFT JOIN
+                    lepao_extra e
+                ON
+                    a.student_num = e.student_num
+                WHERE
+                    a.student_num = ? AND a.create_user IS NOT NULL
+                `
+
             let findRows = await db.query(findSql, [student_num])
             let findRows = await db.query(findSql, [student_num])
             if (!findRows)
             if (!findRows)
                 return res.json({
                 return res.json({
@@ -73,11 +88,11 @@ class UpdateAccount extends API {
 
 
             if (updateRows && updateRows.affectedRows > 0) {
             if (updateRows && updateRows.affectedRows > 0) {
                 let msg
                 let msg
-                if(findRows[0].auto_run === 1) {
-                    msg = `当前已开启自动乐跑,系统随后将自动进行乐跑。后续通知将发送到您的邮箱:${findRows[0].email}。请留意邮箱提醒。`
+                if (findRows[0].auto_run === 1) {
+                    msg = `当前已开启自动乐跑,系统随后将自动进行乐跑。后续通知将发送到您预留的联系方式,请留意。`
                 }
                 }
                 else {
                 else {
-                    msg = `当前未开启自动乐跑,如需进行乐跑,请前往 RunForge 手动执行乐跑操作。后续通知将发送到您的邮箱:${findRows[0].email},请留意邮箱提醒。`
+                    msg = `当前未开启自动乐跑,如需进行乐跑,请前往 RunForge 手动执行乐跑操作。后续通知将发送到您预留的联系方式,请留意。`
                 }
                 }
                 res.json({
                 res.json({
                     ...BaseStdResponse.OK,
                     ...BaseStdResponse.OK,
@@ -92,13 +107,36 @@ class UpdateAccount extends API {
                 })
                 })
                 let emailData = {
                 let emailData = {
                     name,
                     name,
+                    type: 'lepao_update',
+                    umo: findRows[0].umo,
                     account: student_num,
                     account: student_num,
                     academy_name,
                     academy_name,
                     grade_id,
                     grade_id,
                     auto_run: findRows[0].auto_run
                     auto_run: findRows[0].auto_run
                 }
                 }
 
 
-                await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                if (findRows[0].notice_type === 'bot' && findRows[0].bot_umo) {
+                    this.logger.info(`${account}发送乐跑更新Bot通知,UMO=${rows[0].bot_umo}`)
+                    const ch = await mq.getChannel(this.messageQueue)
+
+                    await ch.assertQueue(this.messageQueue, {
+                        durable: true
+                    })
+
+                    ch.sendToQueue(
+                        this.messageQueue,
+                        Buffer.from(JSON.stringify(emailData)),
+                        {
+                            persistent: true,
+                            contentType: 'application/json'
+                        }
+                    )
+
+                    this.logger.info(`${account}乐跑更新Bot通知发送完成`)
+                } else if (findRows[0].notice_type === 'email' && findRows[0].email) {
+                    await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                    this.logger.info(`${account}乐跑更新邮件发送完成`)
+                }
 
 
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)

+ 40 - 4
apis/Lepao/Account/UpdateAccount/UpdateAccountAndroidApp.js

@@ -4,6 +4,7 @@ const axios = require('axios')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const config = require('../../../../config.json')
 const config = require('../../../../config.json')
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
+const mq = require('../../../../plugin/mq')
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 
 
 // 客户端上传数据接口
 // 客户端上传数据接口
@@ -11,6 +12,7 @@ class UpdateAccountAndroidApp extends API {
     constructor() {
     constructor() {
         super()
         super()
 
 
+        this.messageQueue = 'runforge_message_queue'
         this.runpy = config.runpy
         this.runpy = config.runpy
 
 
         this.setPath('/Lepao/UpdateAccountAndroidApp')
         this.setPath('/Lepao/UpdateAccountAndroidApp')
@@ -56,7 +58,18 @@ class UpdateAccountAndroidApp extends API {
                     msg: '未提取出用户登录信息,请重试'
                     msg: '未提取出用户登录信息,请重试'
                 })
                 })
 
 
-            let findSql = 'SELECT email, create_user, auto_run, auto_day FROM lepao_account WHERE student_num = ? AND create_user IS NOT NULL'
+            let findSql = `
+                SELECT 
+                    a.email, a.create_user, a.auto_run, a.auto_day, a.notice_type, e.umo
+                FROM
+                    lepao_account a
+                LEFT JOIN
+                    lepao_extra e
+                ON
+                    a.student_num = e.student_num
+                WHERE
+                    a.student_num = ? AND a.create_user IS NOT NULL
+                `
             let findRows = await db.query(findSql, [student_num])
             let findRows = await db.query(findSql, [student_num])
             if (!findRows)
             if (!findRows)
                 return res.json({
                 return res.json({
@@ -75,10 +88,10 @@ class UpdateAccountAndroidApp extends API {
             if (updateRows && updateRows.affectedRows > 0) {
             if (updateRows && updateRows.affectedRows > 0) {
                 let msg
                 let msg
                 if (findRows[0].auto_run === 1) {
                 if (findRows[0].auto_run === 1) {
-                    msg = `当前已开启自动乐跑,系统将自动进行乐跑。后续通知将发送到您的邮箱:${findRows[0].email}。请留意邮箱提醒。`
+                    msg = `当前已开启自动乐跑,系统将自动进行乐跑。后续通知将发送到您预留的联系方式,请留意。`
                 }
                 }
                 else {
                 else {
-                    msg = `当前未开启自动乐跑,如需进行乐跑,请前往 RunForge 手动执行乐跑操作。后续通知将发送到您的邮箱:${findRows[0].email},请留意邮箱提醒。`
+                    msg = `当前未开启自动乐跑,如需进行乐跑,请前往 RunForge 手动执行乐跑操作。后续通知将发送到您预留的联系方式,请留意。`
                 }
                 }
                 res.json({
                 res.json({
                     ...BaseStdResponse.OK,
                     ...BaseStdResponse.OK,
@@ -96,13 +109,36 @@ class UpdateAccountAndroidApp extends API {
 
 
                 let emailData = {
                 let emailData = {
                     name,
                     name,
+                    type: 'lepao_update',
+                    umo: findRows[0].umo,
                     account: student_num,
                     account: student_num,
                     academy_name,
                     academy_name,
                     grade_id,
                     grade_id,
                     auto_run: findRows[0].auto_run
                     auto_run: findRows[0].auto_run
                 }
                 }
 
 
-                await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                if (findRows[0].notice_type === 'bot' && findRows[0].bot_umo) {
+                    this.logger.info(`${account}发送乐跑更新Bot通知,UMO=${rows[0].bot_umo}`)
+                    const ch = await mq.getChannel(this.messageQueue)
+
+                    await ch.assertQueue(this.messageQueue, {
+                        durable: true
+                    })
+
+                    ch.sendToQueue(
+                        this.messageQueue,
+                        Buffer.from(JSON.stringify(emailData)),
+                        {
+                            persistent: true,
+                            contentType: 'application/json'
+                        }
+                    )
+
+                    this.logger.info(`${account}乐跑更新Bot通知发送完成`)
+                } else if (findRows[0].notice_type === 'email' && findRows[0].email) {
+                    await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                    this.logger.info(`${account}乐跑更新邮件发送完成`)
+                }
 
 
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)

+ 38 - 2
apis/Lepao/Account/UpdateAccount/UpdateAccountiPhone.js

@@ -4,6 +4,7 @@ const axios = require('axios')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const EmailTemplate = require('../../../../plugin/Email/emailTemplate.js')
 const config = require('../../../../config.json')
 const config = require('../../../../config.json')
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
 const lepao = require("../../../../lib/Lepao/Lepao.js").lepao
+const mq = require('../../../../plugin/mq')
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 const { BaseStdResponse } = require("../../../../BaseStdResponse.js")
 
 
 // 客户端上传数据接口
 // 客户端上传数据接口
@@ -11,6 +12,7 @@ class UpdateAccountiPhone extends API {
     constructor() {
     constructor() {
         super()
         super()
 
 
+        this.messageQueue = 'runforge_message_queue'
         this.runpy = config.runpy
         this.runpy = config.runpy
         this.noEncrypt()
         this.noEncrypt()
         this.setPath('/Lepao/UpdateAccountiPhone')
         this.setPath('/Lepao/UpdateAccountiPhone')
@@ -57,7 +59,18 @@ class UpdateAccountiPhone extends API {
                     msg: '未提取出用户登录信息,请重试'
                     msg: '未提取出用户登录信息,请重试'
                 })
                 })
 
 
-            let findSql = 'SELECT email, create_user, auto_run, auto_day FROM lepao_account WHERE student_num = ? AND create_user IS NOT NULL'
+            let findSql = `
+                SELECT 
+                    a.email, a.create_user, a.auto_run, a.auto_day, a.notice_type, e.umo
+                FROM
+                    lepao_account a
+                LEFT JOIN
+                    lepao_extra e
+                ON
+                    a.student_num = e.student_num
+                WHERE
+                    a.student_num = ? AND a.create_user IS NOT NULL
+                `
             let findRows = await db.query(findSql, [student_num])
             let findRows = await db.query(findSql, [student_num])
             if (!findRows)
             if (!findRows)
                 return res.json({
                 return res.json({
@@ -98,13 +111,36 @@ class UpdateAccountiPhone extends API {
 
 
                 let emailData = {
                 let emailData = {
                     name,
                     name,
+                    type: 'lepao_update',
+                    umo: findRows[0].umo,
                     account: student_num,
                     account: student_num,
                     academy_name,
                     academy_name,
                     grade_id,
                     grade_id,
                     auto_run: findRows[0].auto_run
                     auto_run: findRows[0].auto_run
                 }
                 }
 
 
-                await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                if (findRows[0].notice_type === 'bot' && findRows[0].bot_umo) {
+                    this.logger.info(`${account}发送乐跑更新Bot通知,UMO=${rows[0].bot_umo}`)
+                    const ch = await mq.getChannel(this.messageQueue)
+
+                    await ch.assertQueue(this.messageQueue, {
+                        durable: true
+                    })
+
+                    ch.sendToQueue(
+                        this.messageQueue,
+                        Buffer.from(JSON.stringify(emailData)),
+                        {
+                            persistent: true,
+                            contentType: 'application/json'
+                        }
+                    )
+
+                    this.logger.info(`${account}乐跑更新Bot通知发送完成`)
+                } else if (findRows[0].notice_type === 'email' && findRows[0].email) {
+                    await EmailTemplate.updateSuccess(findRows[0].email, emailData)
+                    this.logger.info(`${account}乐跑更新邮件发送完成`)
+                }
 
 
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                 if (findRows[0].auto_run === 1 && Array.isArray(findRows[0].auto_day) && findRows[0].auto_day.includes(new Date().getDay())) {
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)
                     lepao.beginLepao(findRows[0].create_user, student_num, token, uid, school_id, 1)

+ 117 - 15
lib/Lepao/Lepao.js

@@ -5,11 +5,14 @@ const Logger = require('../Logger')
 const path = require('path')
 const path = require('path')
 const EmailTemplate = require('../../plugin/Email/emailTemplate')
 const EmailTemplate = require('../../plugin/Email/emailTemplate')
 const config = require('../../config.json')
 const config = require('../../config.json')
+const mq = require('../../plugin/mq')
 
 
 class Lepao {
 class Lepao {
     constructor() {
     constructor() {
         this.logger = new Logger(path.join(__dirname, '../logs/Lepao.log'), 'INFO')
         this.logger = new Logger(path.join(__dirname, '../logs/Lepao.log'), 'INFO')
         this.runpy = config.runpy
         this.runpy = config.runpy
+
+        this.messageQueue = 'runforge_message_queue'
     }
     }
 
 
     async getPath(account, vip) {
     async getPath(account, vip) {
@@ -167,7 +170,7 @@ class Lepao {
                 throw error
                 throw error
             }
             }
 
 
-             // 临时修复3.12~3.18期间未入库记录,后续可删除
+            // 临时修复3.12~3.18期间未入库记录,后续可删除
             await this.fixRecords(uuid, ossData)
             await this.fixRecords(uuid, ossData)
 
 
             // 上传 OSS
             // 上传 OSS
@@ -199,7 +202,6 @@ class Lepao {
                 throw new Error('系统繁忙,请联系客服或稍后再试')
                 throw new Error('系统繁忙,请联系客服或稍后再试')
             }
             }
 
 
-           
             // 扣除乐跑次数
             // 扣除乐跑次数
             this.logger.info(`${account}开始扣减乐跑次数`)
             this.logger.info(`${account}开始扣减乐跑次数`)
             const useLepaoCountSql = 'UPDATE users SET lepao_count = lepao_count - 1 WHERE uuid  = ?'
             const useLepaoCountSql = 'UPDATE users SET lepao_count = lepao_count - 1 WHERE uuid  = ?'
@@ -296,27 +298,90 @@ class Lepao {
     async sendSuccessEmail(account, lepaoData, term_num, total_num) {
     async sendSuccessEmail(account, lepaoData, term_num, total_num) {
         try {
         try {
             this.logger.info(`${account}发送乐跑成功邮件`)
             this.logger.info(`${account}发送乐跑成功邮件`)
-            const emailSql = 'SELECT name, email, target_count FROM lepao_account WHERE student_num = ?'
+            const emailSql = `
+                SELECT 
+                    a.name, 
+                    a.email, 
+                    a.target_count,
+                    a.notice_type,
+                    e.bot_umo 
+                FROM 
+                    lepao_account a
+                LEFT JOIN
+                    lepao_extra e
+                ON 
+                    a.student_num = e.student_num
+                WHERE
+                    a.student_num = ?
+            `
+
             const rows = await db.query(emailSql, [account])
             const rows = await db.query(emailSql, [account])
             if (!rows || rows.length === 0) {
             if (!rows || rows.length === 0) {
-                this.logger.error(`${account}查找用户邮箱失败`)
-                throw new Error('查找用户邮箱失败')
+                this.logger.error(`${account}查找用户信息失败`)
+                throw new Error('查找用户信息失败')
             }
             }
 
 
-            const data = {
+            let data = {
                 ...lepaoData,
                 ...lepaoData,
+                type: 'lepao_success',
+                umo: rows[0].bot_umo,
                 term_num: rows[0].target_count,
                 term_num: rows[0].target_count,
                 total_num,
                 total_num,
                 name: rows[0].name,
                 name: rows[0].name,
                 account
                 account
             }
             }
 
 
-            await EmailTemplate.lepaoSuccess(rows[0].email, data)
-            this.logger.info(`${account}乐跑成功邮件发送完成`)
+            if (rows[0].notice_type === 'bot' && rows[0].bot_umo) {
+                this.logger.info(`${account}发送乐跑成功Bot通知,UMO=${rows[0].bot_umo}`)
+                const ch = await mq.getChannel(this.messageQueue)
+
+                await ch.assertQueue(this.messageQueue, {
+                    durable: true
+                })
+
+                ch.sendToQueue(
+                    this.messageQueue,
+                    Buffer.from(JSON.stringify(data)),
+                    {
+                        persistent: true,
+                        contentType: 'application/json'
+                    }
+                )
+
+                this.logger.info(`${account}乐跑成功Bot通知发送完成`)
+            } else if (rows[0].notice_type === 'email' && rows[0].email) {
+                await EmailTemplate.lepaoSuccess(rows[0].email, data)
+                this.logger.info(`${account}乐跑成功邮件发送完成`)
+            }
 
 
             if (rows[0].target_count !== 0 && total_num >= rows[0].target_count) {
             if (rows[0].target_count !== 0 && total_num >= rows[0].target_count) {
-                this.logger.info(`${account}乐跑目标完成,发送乐跑结束邮件并关闭自动乐跑`)
-                await EmailTemplate.lepaoOver(rows[0].email, data)
+                this.logger.info(`${account}乐跑目标完成,发送乐跑结束通知并关闭自动乐跑`)
+
+                if (rows[0].notice_type === 'bot' && rows[0].bot_umo) {
+                    this.logger.info(`${account}发送乐跑完成Bot通知,UMO=${rows[0].bot_umo}`)
+                    const ch = await mq.getChannel(this.messageQueue)
+
+                    await ch.assertQueue(this.messageQueue, {
+                        durable: true
+                    })
+
+                    data.type = 'lepao_over'
+
+                    ch.sendToQueue(
+                        this.messageQueue,
+                        Buffer.from(JSON.stringify(data)),
+                        {
+                            persistent: true,
+                            contentType: 'application/json'
+                        }
+                    )
+
+                    this.logger.info(`${account}乐跑完成Bot通知发送完成`)
+                } else if (rows[0].notice_type === 'email' && rows[0].email) {
+                    await EmailTemplate.lepaoOver(rows[0].email, data)
+                    this.logger.info(`${account}乐跑完成邮件发送完成`)
+                }
+
                 let overSql = 'UPDATE lepao_account SET auto_run = 0 WHERE student_num = ?'
                 let overSql = 'UPDATE lepao_account SET auto_run = 0 WHERE student_num = ?'
                 let overRows = await db.query(overSql, [account])
                 let overRows = await db.query(overSql, [account])
                 if (!overRows || overRows.affectedRows !== 1)
                 if (!overRows || overRows.affectedRows !== 1)
@@ -331,8 +396,23 @@ class Lepao {
 
 
     async sendFailEmail(account, reason) {
     async sendFailEmail(account, reason) {
         try {
         try {
-            this.logger.info(`${account}发送乐跑失败邮件,原因: ${reason}`)
-            const emailSql = 'SELECT name, email FROM lepao_account WHERE student_num = ?'
+            this.logger.info(`${account}发送乐跑失败通知,原因: ${reason}`)
+            const emailSql = `
+                SELECT 
+                    a.name, 
+                    a.email, 
+                    a.target_count,
+                    a.notice_type,
+                    e.bot_umo 
+                FROM 
+                    lepao_account a
+                LEFT JOIN
+                    lepao_extra e
+                ON 
+                    a.student_num = e.student_num
+                WHERE
+                    a.student_num = ?
+            `
             const rows = await db.query(emailSql, [account])
             const rows = await db.query(emailSql, [account])
             if (!rows || rows.length == 0) {
             if (!rows || rows.length == 0) {
                 this.logger.error(`${account}查找用户邮箱失败`)
                 this.logger.error(`${account}查找用户邮箱失败`)
@@ -340,13 +420,35 @@ class Lepao {
             }
             }
 
 
             const data = {
             const data = {
+                type: 'lepao_fail',
+                umo: rows[0].bot_umo,
                 name: rows[0].name,
                 name: rows[0].name,
                 account,
                 account,
                 reason: reason === 'Request failed with status code 503' ? 'RunForge系统维护中,请稍后再试' : reason
                 reason: reason === 'Request failed with status code 503' ? 'RunForge系统维护中,请稍后再试' : reason
             }
             }
 
 
-            await EmailTemplate.lepaoFail(rows[0].email, data)
-            this.logger.info(`${account}乐跑失败邮件发送完成`)
+            if (rows[0].notice_type === 'bot' && rows[0].bot_umo) {
+                this.logger.info(`${account}发送乐跑失败Bot通知,UMO=${rows[0].bot_umo}`)
+                const ch = await mq.getChannel(this.messageQueue)
+
+                await ch.assertQueue(this.messageQueue, {
+                    durable: true
+                })
+
+                ch.sendToQueue(
+                    this.messageQueue,
+                    Buffer.from(JSON.stringify(data)),
+                    {
+                        persistent: true,
+                        contentType: 'application/json'
+                    }
+                )
+
+                this.logger.info(`${account}Bot通知发送完成`)
+            } else if (rows[0].notice_type === 'email' && rows[0].email) {
+                await EmailTemplate.lepaoFail(rows[0].email, data)
+                this.logger.info(`${account}乐跑失败邮件发送完成`)
+            }
         } catch (error) {
         } catch (error) {
             this.logger.error(`发送失败邮件失败: ${error.stack || error.message}`)
             this.logger.error(`发送失败邮件失败: ${error.stack || error.message}`)
         }
         }
@@ -390,7 +492,7 @@ class Lepao {
 
 
             const recordRes = await axios.post(countUrl, reqData)
             const recordRes = await axios.post(countUrl, reqData)
             const { data } = recordRes
             const { data } = recordRes
-            if(!data || !data.counts) {
+            if (!data || !data.counts) {
                 this.logger.warn(`修复乐跑记录失败,接口返回异常`)
                 this.logger.warn(`修复乐跑记录失败,接口返回异常`)
                 return
                 return
             }
             }

+ 5 - 1
plugin/Email/emailTemplate.js

@@ -456,7 +456,11 @@ class emailTemplate {
                 <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.total_num} 次 ✨</p>
-                <p><strong>剩余次数:</strong> ${data.term_num - data.total_num >= 0 ? (data.term_num - 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>
                 </div>
                 </div>
 
 
                 <p class="important">如果宝宝开启了自动乐跑,要记得不要在其他设备上登录“智慧体育”小程序哦 🚫📱,不然登录就会失效,要重新来一次啦~</p>
                 <p class="important">如果宝宝开启了自动乐跑,要记得不要在其他设备上登录“智慧体育”小程序哦 🚫📱,不然登录就会失效,要重新来一次啦~</p>