package srv_user import ( "context" "strings" "time" "videoweb/pub/common/srvdef" "videoweb/pub/models/cointransmod" "videoweb/pub/models/rechargepackagemod" "videoweb/pub/models/usermod" "videoweb/pub/payment" "videoweb/pub/pubdef" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) // GetUsers 分页查询用户列表 func GetUsers(ctx context.Context, req *UserListReq) (*UserListResp, *srvdef.SrvErr) { filter := bson.M{} if req.Id != nil && *req.Id > 0 { filter[usermod.FN.User.Id] = *req.Id } if accountNo := strings.TrimSpace(req.AccountNo); accountNo != "" { filter[usermod.FN.User.AccountNo] = accountNo } if email := strings.TrimSpace(req.Email); email != "" { filter[usermod.FN.User.Email] = email } if req.NickName != "" { filter[usermod.FN.User.NickName] = bson.M{"$regex": req.NickName} } if districtCode := strings.TrimSpace(req.DistrictCode); districtCode != "" { filter[usermod.FN.User.DistrictCode] = districtCode } if req.Status != nil { filter[usermod.FN.User.Status] = *req.Status } if req.Type != nil { filter[usermod.FN.User.Type] = *req.Type } opts := options.Find(). SetSort(bson.M{usermod.FN.User.Id: -1}). SetSkip((req.PageNum - 1) * req.PageSize). SetLimit(req.PageSize) resp := &UserListResp{} total, serr := usermod.CountUsers(ctx, filter) if serr != nil { return resp, serr } resp.Total = total if total == 0 { return resp, nil } list, serr := usermod.FindManyUser(ctx, filter, opts) if serr != nil { return resp, serr } resp.List = list return resp, nil } // UpdateUser 更新指定用户信息 func UpdateUser(ctx context.Context, id int64, param usermod.UserUpdate) *srvdef.SrvErr { now := time.Now() param.UpdatedAt = &now return usermod.UpdateOneUser(ctx, bson.M{usermod.FN.User.Id: id}, bson.M{"$set": param}, ) } // GiftCoin 给用户赠送/扣除金币,并写入流水记录 // coin 为正数时增加余额,为负数时扣减(不校验余额是否充足,由调用方确保) func GiftCoin(ctx context.Context, req *GiftCoinReq) *srvdef.SrvErr { if req.Coin == 0 { return srvdef.New(srvdef.ErrParamError, "金币数量不能为 0", "") } // 原子更新余额 if serr := usermod.UpdateOneUser(ctx, bson.M{usermod.FN.User.Id: req.UserId}, bson.M{ "$inc": bson.M{usermod.FN.User.Recharge: req.Coin}, "$set": bson.M{usermod.FN.User.UpdatedAt: time.Now()}, }, ); serr != nil { return serr } // 写流水(更新后再查余额,作为 balanceAfter) flowDir := cointransmod.FlowIn amount := req.Coin if req.Coin < 0 { flowDir = cointransmod.FlowOut amount = -req.Coin } remark := req.Remark if remark == "" { remark = payment.CoinTransRemark(cointransmod.TranTypeAdminAdjust, "") } _ = payment.WriteCoinTransByUser(ctx, payment.WriteCoinTransOpt{ UserId: req.UserId, FlowDir: flowDir, TranType: cointransmod.TranTypeAdminAdjust, Amount: amount, Remark: remark, }) return nil } // UpdateVip 根据会员畅享套餐修改用户会员信息。 func UpdateVip(ctx context.Context, req *UpdateVipReq) *srvdef.SrvErr { if req == nil || req.UserId <= 0 || req.PackageId <= 0 { return srvdef.New(srvdef.ErrParamError, "用户ID和套餐ID不能为空", "") } user, serr := usermod.FindOneUser(ctx, bson.M{usermod.FN.User.Id: req.UserId}) if serr != nil || user == nil { return srvdef.New(srvdef.ErrUserNotExsit, "", "") } pkg, serr := rechargepackagemod.FindOneRechargePackage(ctx, bson.M{ rechargepackagemod.FN.RechargePackage.Id: req.PackageId, rechargepackagemod.FN.RechargePackage.PackageType: rechargepackagemod.PackageTypeVip, rechargepackagemod.FN.RechargePackage.Status: rechargepackagemod.StatusEnabled, }) if serr != nil || pkg == nil { return srvdef.New(srvdef.ErrNoData, "会员套餐不存在或未启用", "") } if pkg.DurationDays <= 0 { return srvdef.New(srvdef.ErrParamError, "会员套餐有效天数无效", "") } now := time.Now() baseTime := now if user.CurrentVipExpire.After(now) { baseTime = user.CurrentVipExpire } newExpire := baseTime.Add(time.Duration(pkg.DurationDays) * 24 * time.Hour) updateDoc := bson.M{ "$set": bson.M{ usermod.FN.User.VipType: vipTypeFromDurationDays(pkg.DurationDays), usermod.FN.User.ShowCardId: pkg.Id, usermod.FN.User.ShowCardName: pkg.Name, usermod.FN.User.CurrentVipExpire: newExpire, usermod.FN.User.UpdatedAt: now, }, } if serr = usermod.UpdateOneUser(ctx, bson.M{usermod.FN.User.Id: req.UserId}, updateDoc); serr != nil { return serr } return nil } func vipTypeFromDurationDays(days int64) pubdef.VipType { if days >= 365 { return pubdef.VipTypeYear } if days > 0 { return pubdef.VipTypeMonth } return pubdef.VipTypeNone }