169 lines
5.0 KiB
JavaScript
169 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* 自动解绑定时任务 - 简化版(直接连接MySQL)
|
||
*
|
||
* 功能:定时检查并解绑过期的推荐关系
|
||
*
|
||
* 解绑条件:
|
||
* 1. 绑定状态为 active
|
||
* 2. 过期时间已到(expiry_date < NOW)
|
||
* 3. 期间没有任何购买(purchase_count = 0)
|
||
*
|
||
* 使用方式:
|
||
* 1. 确保已安装 mysql2: npm install mysql2
|
||
* 2. 配置环境变量或修改下方 DB_CONFIG
|
||
* 3. 手动执行:node scripts/auto-unbind-expired-simple.js
|
||
* 4. 宝塔定时任务:每天 02:00 执行
|
||
*/
|
||
|
||
const mysql = require('mysql2/promise')
|
||
require('dotenv').config()
|
||
|
||
// 数据库配置(从环境变量读取)
|
||
const DB_CONFIG = {
|
||
host: process.env.DB_HOST || 'localhost',
|
||
port: parseInt(process.env.DB_PORT) || 3306,
|
||
user: process.env.DB_USER || 'root',
|
||
password: process.env.DB_PASSWORD || '',
|
||
database: process.env.DB_NAME || 'mycontent_db',
|
||
charset: 'utf8mb4'
|
||
}
|
||
|
||
async function autoUnbind() {
|
||
console.log('=' .repeat(60))
|
||
console.log('自动解绑定时任务')
|
||
console.log('执行时间:', new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }))
|
||
console.log('=' .repeat(60))
|
||
console.log()
|
||
|
||
let connection
|
||
|
||
try {
|
||
// 连接数据库
|
||
connection = await mysql.createConnection(DB_CONFIG)
|
||
console.log(`✅ 已连接到数据库: ${DB_CONFIG.database}`)
|
||
console.log()
|
||
|
||
// 1. 查询需要解绑的记录
|
||
console.log('步骤 1: 查询需要解绑的记录...')
|
||
console.log('-' .repeat(60))
|
||
|
||
const [expiredBindings] = await connection.execute(`
|
||
SELECT
|
||
id,
|
||
referee_id,
|
||
referrer_id,
|
||
binding_date,
|
||
expiry_date,
|
||
purchase_count,
|
||
total_commission
|
||
FROM referral_bindings
|
||
WHERE status = 'active'
|
||
AND expiry_date < NOW()
|
||
AND purchase_count = 0
|
||
ORDER BY expiry_date ASC
|
||
`)
|
||
|
||
if (expiredBindings.length === 0) {
|
||
console.log('✅ 无需解绑的记录')
|
||
console.log()
|
||
console.log('=' .repeat(60))
|
||
console.log('任务完成')
|
||
console.log('=' .repeat(60))
|
||
return
|
||
}
|
||
|
||
console.log(`找到 ${expiredBindings.length} 条需要解绑的记录`)
|
||
console.log()
|
||
|
||
// 2. 输出明细
|
||
console.log('步骤 2: 解绑明细')
|
||
console.log('-' .repeat(60))
|
||
|
||
expiredBindings.forEach((binding, index) => {
|
||
const bindingDate = new Date(binding.binding_date).toLocaleDateString('zh-CN')
|
||
const expiryDate = new Date(binding.expiry_date).toLocaleDateString('zh-CN')
|
||
const daysExpired = Math.floor((Date.now() - new Date(binding.expiry_date).getTime()) / (1000 * 60 * 60 * 24))
|
||
|
||
console.log(`${index + 1}. 用户 ${binding.referee_id}`)
|
||
console.log(` 推荐人: ${binding.referrer_id}`)
|
||
console.log(` 绑定时间: ${bindingDate}`)
|
||
console.log(` 过期时间: ${expiryDate} (已过期 ${daysExpired} 天)`)
|
||
console.log(` 购买次数: ${binding.purchase_count}`)
|
||
console.log(` 累计佣金: ¥${(binding.total_commission || 0).toFixed(2)}`)
|
||
console.log()
|
||
})
|
||
|
||
// 3. 批量更新为 expired
|
||
console.log('步骤 3: 执行解绑操作...')
|
||
console.log('-' .repeat(60))
|
||
|
||
const ids = expiredBindings.map(b => b.id)
|
||
const placeholders = ids.map(() => '?').join(',')
|
||
|
||
const [result] = await connection.execute(
|
||
`UPDATE referral_bindings SET status = 'expired' WHERE id IN (${placeholders})`,
|
||
ids
|
||
)
|
||
|
||
console.log(`✅ 已成功解绑 ${result.affectedRows} 条记录`)
|
||
console.log()
|
||
|
||
// 4. 更新推荐人的推广数量
|
||
console.log('步骤 4: 更新推荐人统计...')
|
||
console.log('-' .repeat(60))
|
||
|
||
const referrerCounts = {}
|
||
expiredBindings.forEach(binding => {
|
||
referrerCounts[binding.referrer_id] = (referrerCounts[binding.referrer_id] || 0) + 1
|
||
})
|
||
|
||
for (const [referrerId, count] of Object.entries(referrerCounts)) {
|
||
await connection.execute(
|
||
`UPDATE users SET referral_count = GREATEST(referral_count - ?, 0) WHERE id = ?`,
|
||
[count, referrerId]
|
||
)
|
||
console.log(` - ${referrerId}: -${count} 个绑定`)
|
||
}
|
||
|
||
console.log(`✅ 已更新 ${Object.keys(referrerCounts).length} 个推荐人的统计数据`)
|
||
console.log()
|
||
|
||
// 5. 总结
|
||
console.log('=' .repeat(60))
|
||
console.log('✅ 任务完成')
|
||
console.log(` - 解绑记录数: ${expiredBindings.length}`)
|
||
console.log(` - 受影响推荐人: ${Object.keys(referrerCounts).length}`)
|
||
console.log('=' .repeat(60))
|
||
|
||
} catch (error) {
|
||
console.error('❌ 任务执行失败:', error.message)
|
||
console.error(error.stack)
|
||
throw error
|
||
} finally {
|
||
// 关闭数据库连接
|
||
if (connection) {
|
||
await connection.end()
|
||
console.log('\n数据库连接已关闭')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 主函数
|
||
async function main() {
|
||
try {
|
||
await autoUnbind()
|
||
process.exit(0)
|
||
} catch (error) {
|
||
console.error('\n❌ 脚本执行失败')
|
||
process.exit(1)
|
||
}
|
||
}
|
||
|
||
// 运行
|
||
if (require.main === module) {
|
||
main()
|
||
}
|
||
|
||
module.exports = { autoUnbind }
|