Files
soul-yongping/scripts/auto-unbind-expired-simple.js

169 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 }