删除不再使用的文件,包括开放 API 鉴权规范文档、数据库迁移脚本和旧版图标组件,优化项目结构和资源管理。更新小程序代码以支持代付功能,增加代付分享弹窗和支付逻辑,提升用户体验。
This commit is contained in:
@@ -203,3 +203,86 @@ func CronSyncOrders(c *gin.Context) {
|
||||
func CronUnbindExpired(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||
}
|
||||
|
||||
// RunSyncVipCkbPlans 扫描已到期 VIP 用户,自动停用其绑定 Person 的存客宝计划
|
||||
// - 最佳努力:停用失败只记日志,不中断整体任务
|
||||
// - 幂等:重复执行不会产生额外副作用(计划已停用则仍然 update)
|
||||
func RunSyncVipCkbPlans(ctx context.Context, limit int) (scanned, disabled int, err error) {
|
||||
if limit < 1 {
|
||||
limit = 200
|
||||
}
|
||||
if limit > 2000 {
|
||||
limit = 2000
|
||||
}
|
||||
db := database.DB()
|
||||
|
||||
// 只处理“有过期日且已过期,并且绑定了 Person(user_id) 且有 planId”的用户
|
||||
// 说明:persons.user_id 为新增字段;历史未绑定的不在本任务处理范围内
|
||||
type row struct {
|
||||
UserID string `gorm:"column:user_id"`
|
||||
PlanID int64 `gorm:"column:ckb_plan_id"`
|
||||
Nickname string `gorm:"column:nickname"`
|
||||
}
|
||||
rows := make([]row, 0)
|
||||
q := `
|
||||
SELECT u.id as user_id, p.ckb_plan_id, COALESCE(u.nickname,'') as nickname
|
||||
FROM users u
|
||||
INNER JOIN persons p ON p.user_id = u.id
|
||||
WHERE u.is_vip = 1
|
||||
AND u.vip_expire_date IS NOT NULL
|
||||
AND u.vip_expire_date <= NOW()
|
||||
AND p.ckb_plan_id > 0
|
||||
ORDER BY u.vip_expire_date ASC
|
||||
LIMIT ?`
|
||||
if err := db.Raw(q, limit).Scan(&rows).Error; err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
scanned = len(rows)
|
||||
if scanned == 0 {
|
||||
return scanned, 0, nil
|
||||
}
|
||||
|
||||
openToken, tokErr := ckbOpenGetToken()
|
||||
if tokErr != nil {
|
||||
// 没 token 直接失败,让 cron 重试(避免把用户标记成非 VIP 但计划未停用)
|
||||
return scanned, 0, tokErr
|
||||
}
|
||||
|
||||
for _, r := range rows {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return scanned, disabled, ctx.Err()
|
||||
default:
|
||||
}
|
||||
if r.PlanID <= 0 || r.UserID == "" {
|
||||
continue
|
||||
}
|
||||
if err := setCkbPlanEnabled(openToken, r.PlanID, false); err != nil {
|
||||
syncOrdersLogf("停用存客宝计划失败: userId=%s, planId=%d, nickname=%s, err=%v", r.UserID, r.PlanID, r.Nickname, err)
|
||||
continue
|
||||
}
|
||||
disabled++
|
||||
syncOrdersLogf("已停用存客宝计划: userId=%s, planId=%d, nickname=%s", r.UserID, r.PlanID, r.Nickname)
|
||||
|
||||
// 兜底清理脏标记:到期用户将 is_vip 置为 0(vip_expire_date 保留)
|
||||
_ = db.Model(&model.User{}).Where("id = ?", r.UserID).Update("is_vip", false).Error
|
||||
}
|
||||
return scanned, disabled, nil
|
||||
}
|
||||
|
||||
// CronSyncVipCkbPlans GET/POST /api/cron/sync-vip-ckb-plans
|
||||
// ?limit=200 每次最多处理 N 个到期用户
|
||||
func CronSyncVipCkbPlans(c *gin.Context) {
|
||||
limit := 200
|
||||
if s := strings.TrimSpace(c.Query("limit")); s != "" {
|
||||
if n, err := strconv.Atoi(s); err == nil && n > 0 && n <= 2000 {
|
||||
limit = n
|
||||
}
|
||||
}
|
||||
scanned, disabled, err := RunSyncVipCkbPlans(c.Request.Context(), limit)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error(), "scanned": scanned, "disabled": disabled})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "scanned": scanned, "disabled": disabled, "limit": limit})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user