diff --git a/app/mix/controller/init.go b/app/mix/controller/init.go index 5e031c5b..973e115c 100644 --- a/app/mix/controller/init.go +++ b/app/mix/controller/init.go @@ -224,6 +224,7 @@ func Init(r *gin.Engine) { apiZoneGroup.POST("refund", middleware.JSONParamValidator(vasproto.ZoneRefundReq{}), ZoneRefund) apiZoneGroup.POST("member_list", middleware.JSONParamValidator(vasproto.GetZoneMemberListReq{}), ZoneMemberList) apiZoneGroup.POST("free_join", middleware.JSONParamValidator(vasproto.ZoneFreeJoinReq{}), ZoneFreeJoin) + apiZoneGroup.POST("exit", middleware.JSONParamValidator(vasproto.ZoneExitReq{}), ZoneExit) // 私密圈动态 apiZoneMomentGroup := r.Group("/api/zone_moment", PrepareToC()) diff --git a/app/mix/controller/zone_vas_api.go b/app/mix/controller/zone_vas_api.go index e7f57186..e0ad9ad2 100644 --- a/app/mix/controller/zone_vas_api.go +++ b/app/mix/controller/zone_vas_api.go @@ -31,8 +31,8 @@ func ZoneCreateOrder(ctx *gin.Context) { func ZoneGetCashier(ctx *gin.Context) { req := ctx.MustGet("client_req").(*vasproto.ZoneGetCashierReq) - if len(req.ProductId) <= 0 { - logger.Error("CreateOrder, invalid param, req: %v", util.ToJson(req)) + if req.Mid <= 0 || req.Zid <= 0 || len(req.ProductId) <= 0 { + logger.Error("ZoneGetCashier, invalid param, req: %v", util.ToJson(req)) ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) return } @@ -51,6 +51,11 @@ func ZoneGetCashier(ctx *gin.Context) { func ZoneRefundPage(ctx *gin.Context) { req := ctx.MustGet("client_req").(*vasproto.ZoneRefundPageReq) + if req.Mid <= 0 || req.Zid <= 0 { + logger.Error("ZoneRefund, invalid param, req: %v", util.ToJson(req)) + ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) + return + } name, price, ec, err := service.DefaultService.ZoneGetRefundPage(ctx, req) if ec != errcode.ErrCodeVasSrvOk { logger.Error("ZoneGetRefundPage fail, req: %v, ec: %v", util.ToJson(req), ec) @@ -70,8 +75,8 @@ func ZoneRefundPage(ctx *gin.Context) { func ZoneRefund(ctx *gin.Context) { req := ctx.MustGet("client_req").(*vasproto.ZoneRefundReq) - if req.Mid <= 0 { - logger.Error("CreateOrder, invalid param, req: %v", util.ToJson(req)) + if req.Mid <= 0 || req.Zid <= 0 { + logger.Error("ZoneRefund, invalid param, req: %v", util.ToJson(req)) ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) return } @@ -90,7 +95,7 @@ func ZoneRefund(ctx *gin.Context) { func ZoneMemberList(ctx *gin.Context) { req := ctx.MustGet("client_req").(*vasproto.GetZoneMemberListReq) - if req.Mid <= 0 { + if req.Mid <= 0 || req.Zid <= 0 { logger.Error("ZoneMemberList, invalid param, req: %v", util.ToJson(req)) ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) return @@ -113,6 +118,11 @@ func ZoneMemberList(ctx *gin.Context) { func ZoneFreeJoin(ctx *gin.Context) { req := ctx.MustGet("client_req").(*vasproto.ZoneFreeJoinReq) + if req.Mid <= 0 || req.Zid <= 0 { + logger.Error("ZoneFreeJoin, invalid param, req: %v", util.ToJson(req)) + ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) + return + } ec, err := service.DefaultService.ZoneFreeJoin(ctx, req) if ec != errcode.ErrCodeVasSrvOk { logger.Error("ZoneFreeJoin fail, req: %v, ec: %v", util.ToJson(req), ec) @@ -125,3 +135,23 @@ func ZoneFreeJoin(ctx *gin.Context) { } ReplyOk(ctx, nil) } + +func ZoneExit(ctx *gin.Context) { + req := ctx.MustGet("client_req").(*vasproto.ZoneExitReq) + if req.Mid <= 0 || req.Zid <= 0 { + logger.Error("ZoneExit, invalid param, req: %v", util.ToJson(req)) + ReplyErrCodeMsg(ctx, errcode.ErrCodeBadParam) + return + } + ec, err := service.DefaultService.ZoneExit(ctx, req) + if ec != errcode.ErrCodeVasSrvOk { + logger.Error("ZoneExit fail, req: %v, ec: %v", util.ToJson(req), ec) + if ec == errcode.ErrCodeVasSrvFail && err != nil { + ReplyErrorMsg(ctx, err.Error()) + return + } + ReplyErrCodeMsg(ctx, ec) + return + } + ReplyOk(ctx, nil) +} diff --git a/app/mix/dao/mysql_zone.go b/app/mix/dao/mysql_zone.go index 1767331d..50f689bf 100644 --- a/app/mix/dao/mysql_zone.go +++ b/app/mix/dao/mysql_zone.go @@ -161,11 +161,28 @@ func (m *Mysql) UnlockZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid, unt return err } -// 删除空间普通会员 -func (m *Mysql) DeleteZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid int64) error { +// 退款空间普通会员 +func (m *Mysql) RefundZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid int64) error { var err error - sqlStr := "update " + TableVasZoneUnlock + " set admission_ct=?, admission_until=? where mid=? and zid=?" - args := []any{0, 0, mid, zid} + sqlStr := "update " + TableVasZoneUnlock + " set admission_ct=?, admission_until=?, admission_unlock_type=? where mid=? and zid=?" + args := []any{0, 0, dbstruct.ZoneUnlockTypeRefund, mid, zid} + if tx != nil { + _, err = tx.ExecContext(ctx, sqlStr, args...) + } else { + db := m.getDBVas() + _, err = db.ExecContext(ctx, sqlStr, args...) + } + if err != nil { + return err + } + return err +} + +// 退出空间 +func (m *Mysql) ExitZoneAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid int64) error { + var err error + sqlStr := "update " + TableVasZoneUnlock + " set admission_ct=?, admission_until=?, admission_unlock_type=? where mid=? and zid=?" + args := []any{0, 0, dbstruct.ZoneUnlockTypeExit, mid, zid} if tx != nil { _, err = tx.ExecContext(ctx, sqlStr, args...) } else { diff --git a/app/mix/service/apiservice.go b/app/mix/service/apiservice.go index a4fa3af8..3ccbb5d5 100644 --- a/app/mix/service/apiservice.go +++ b/app/mix/service/apiservice.go @@ -2933,6 +2933,13 @@ func (s *Service) ApiCreateZoneThirdPartner(ctx *gin.Context, req *zone_third_pa ec = errcode.ErrCodeZoneThirdPartnerSrvFail return } + + // 3.直接加入空间 + _err := _DefaultVas.ZoneFreeJoinThirdPartner(ctx, req.ZoneThirdPartner.GetThirdPartnerMid(), req.ZoneThirdPartner.GetZid()) + if _err != nil { + logger.Error("ZoneFreeJoinThirdPartner fail, mid: %v, zid: %v, err: %v", req.ZoneThirdPartner.GetThirdPartnerMid(), req.ZoneThirdPartner.GetZid(), _err) + } + return } @@ -3016,6 +3023,12 @@ func (s *Service) ApiCreateZoneCollaborator(ctx *gin.Context, req *zone_collabor ec = errcode.ErrCodeZoneCollaboratorSrvFail return } + + // 协作者直接加入空间 + _err := _DefaultVas.ZoneFreeJoinCollaborator(ctx, req.ZoneCollaborator.GetCollaboratorMid(), req.ZoneCollaborator.GetZid()) + if _err != nil { + logger.Error("ZoneFreeJoinCollaborator fail, mid: %v, zid: %v, err: %v", req.ZoneCollaborator.GetCollaboratorMid(), req.ZoneCollaborator.GetZid(), _err) + } return } diff --git a/app/mix/service/logic/vas.go b/app/mix/service/logic/vas.go index 6cf10a78..b44fd315 100644 --- a/app/mix/service/logic/vas.go +++ b/app/mix/service/logic/vas.go @@ -2563,9 +2563,9 @@ func (v *Vas) refundZoneAdmission(ctx *gin.Context, order *dbstruct.Order, req * } // 删除空间普通会员 - err = v.store.DeleteZoneAdmission(ctx, tx, mid, zid) + err = v.store.RefundZoneAdmission(ctx, tx, mid, zid) if err != nil { - logger.Error("DeleteZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) + logger.Error("RefundZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) return err } diff --git a/app/mix/service/logic/vas_zone.go b/app/mix/service/logic/vas_zone.go index 8f2e2094..7259eafc 100644 --- a/app/mix/service/logic/vas_zone.go +++ b/app/mix/service/logic/vas_zone.go @@ -829,49 +829,6 @@ func (v *Vas) GetZoneMemberList(ctx *gin.Context, zid int64, memType int32) (lis return } -// 免费加入空间 -func (v *Vas) ZoneFreeJoin(ctx *gin.Context, mid, zid int64) error { - // 查询空间价格 - zv, _ := v.store.GetZoneVasById(ctx, zid) - if zv == nil { - logger.Error("GetZoneVasById fail, no such zid: %v", zid) - return fmt.Errorf("该主播没有开通空间") - } - if zv.AdmissionPrice != 0 { - return fmt.Errorf("不是免费空间") - } - - // 开启事务 - tx, err := v.store.VasBegin(ctx) - if err != nil { - logger.Error("vas begin fail, err: %v", err) - return err - } - defer func() { - errTx := v.store.DealTxCR(tx, err) - if errTx != nil { - logger.Error("DealTxCR fail, err: %v", errTx) - return - } - }() - - // 解锁空间会员 - err = v.MustUnlockAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeFree) - if err != nil { - logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) - return err - } - - // 添加到空间成员 - err = v.store.AddZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeNormal) - if err != nil { - logger.Error("AddZoneMember normal fail, mid: %v, zid: %v, err: %v", mid, zid, err) - return err - } - - return nil -} - func (v *Vas) MustUnlockAdmission(ctx *gin.Context, tx *sqlx.Tx, mid, zid, until int64, orderId string, unlockType int32) error { // 检查解锁 _, exist := v.CheckZoneUnlockExist(ctx, tx, mid, zid) @@ -907,3 +864,189 @@ func (v *Vas) MustUnlockSuperfanship(ctx *gin.Context, tx *sqlx.Tx, mid, zid, un // 解锁超粉 return v.store.UnlockZoneSuperfanship(ctx, tx, mid, zid, until, orderId, unlockType) } + +// 免费加入空间 +func (v *Vas) ZoneFreeJoin(ctx *gin.Context, mid, zid int64) error { + // 查询空间价格 + zv, _ := v.store.GetZoneVasById(ctx, zid) + if zv == nil { + logger.Error("GetZoneVasById fail, no such zid: %v", zid) + return fmt.Errorf("该主播没有开通空间") + } + if zv.AdmissionPrice != 0 { + return fmt.Errorf("不是免费空间") + } + + // 是否已加入 + zu, _ := v.CheckZoneUnlockExist(ctx, nil, mid, zid) + if zu.IsUnlockAdmission() { + return fmt.Errorf("不能重复加入空间") + } + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 解锁空间会员 + err = v.MustUnlockAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeFree) + if err != nil { + logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + // 添加到空间成员 + err = v.store.AddZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeNormal) + if err != nil { + logger.Error("AddZoneMember normal fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + return nil +} + +// 代运营加入空间 +func (v *Vas) ZoneFreeJoinThirdPartner(ctx *gin.Context, mid, zid int64) error { + // 查询空间价格 + zv, _ := v.store.GetZoneVasById(ctx, zid) + if zv == nil { + logger.Error("GetZoneVasById fail, no such zid: %v", zid) + return fmt.Errorf("该主播没有开通空间") + } + + // 是否已加入 + zu, _ := v.CheckZoneUnlockExist(ctx, nil, mid, zid) + if zu.IsUnlockAdmission() { + return fmt.Errorf("不能重复加入空间") + } + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 解锁空间会员 + err = v.MustUnlockAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeThirdPartner) + if err != nil { + logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + // 删除空间成员 + err = v.store.AddZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeNormal) + if err != nil { + logger.Error("AddZoneMember normal fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + return nil +} + +// 协作者加入空间 +func (v *Vas) ZoneFreeJoinCollaborator(ctx *gin.Context, mid, zid int64) error { + // 查询空间价格 + zv, _ := v.store.GetZoneVasById(ctx, zid) + if zv == nil { + logger.Error("GetZoneVasById fail, no such zid: %v", zid) + return fmt.Errorf("该主播没有开通空间") + } + + // 是否已加入 + zu, _ := v.CheckZoneUnlockExist(ctx, nil, mid, zid) + if zu.IsUnlockAdmission() { + return fmt.Errorf("不能重复加入空间") + } + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 解锁空间会员 + err = v.MustUnlockAdmission(ctx, tx, mid, zid, -1, "", dbstruct.ZoneUnlockTypeCollaborator) + if err != nil { + logger.Error("UnlockZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + // 添加到空间成员 + err = v.store.AddZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeNormal) + if err != nil { + logger.Error("AddZoneMember normal fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + return nil +} + +// 退出空间 +func (v *Vas) ZoneExit(ctx *gin.Context, mid, zid int64) error { + // 是否已加入 + zu, _ := v.CheckZoneUnlockExist(ctx, nil, mid, zid) + if !zu.IsUnlockAdmission() { + return fmt.Errorf("不能退出未加入的空间") + } + + // 开启事务 + tx, err := v.store.VasBegin(ctx) + if err != nil { + logger.Error("vas begin fail, err: %v", err) + return err + } + defer func() { + errTx := v.store.DealTxCR(tx, err) + if errTx != nil { + logger.Error("DealTxCR fail, err: %v", errTx) + return + } + }() + + // 退出空间 + err = v.store.ExitZoneAdmission(ctx, tx, mid, zid) + if err != nil { + logger.Error("ExitZoneAdmission fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + + // 删除空间成员 + err = v.store.DeleteZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeNormal) + if err != nil { + logger.Error("AddZoneMember normal fail, mid: %v, zid: %v, err: %v", mid, zid, err) + return err + } + if zu.IsUnlockIronfanship() { + _ = v.store.DeleteZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeIronfan) + } + if zu.IsUnlockSuperfanship() { + _ = v.store.DeleteZoneMember(ctx, tx, mid, zid, dbstruct.ZoneMemberTypeSuperfan) + } + + return nil +} diff --git a/app/mix/service/vasservice.go b/app/mix/service/vasservice.go index ef5657f7..b5eb0ee4 100644 --- a/app/mix/service/vasservice.go +++ b/app/mix/service/vasservice.go @@ -801,7 +801,17 @@ func (s *Service) ZoneFreeJoin(ctx *gin.Context, req *vasproto.ZoneFreeJoinReq) err = _DefaultVas.ZoneFreeJoin(ctx, req.Mid, req.Zid) ec, err = errs.DealVasErr(err) if err != nil { - logger.Error("ZoneRefund fail, err: %v", err) + logger.Error("ZoneFreeJoin fail, err: %v", err) + return + } + return +} + +func (s *Service) ZoneExit(ctx *gin.Context, req *vasproto.ZoneExitReq) (ec errcode.ErrCode, err error) { + err = _DefaultVas.ZoneExit(ctx, req.Mid, req.Zid) + ec, err = errs.DealVasErr(err) + if err != nil { + logger.Error("ZoneExit fail, err: %v", err) return } return diff --git a/dbstruct/vas_mysql.go b/dbstruct/vas_mysql.go index a974a6d8..655fd6fe 100644 --- a/dbstruct/vas_mysql.go +++ b/dbstruct/vas_mysql.go @@ -932,9 +932,13 @@ func (p *UserVasMembershipUnlock) GetOrderId() string { // 用户解锁空间详情 const ( - ZoneUnlockTypeFree = 1 // 免费解锁 - ZoneUnlockTypePay = 2 // 付费解锁 - ZoneUnlockTypeReachConsume = 3 // 满足消费额解锁 + ZoneUnlockTypeRefund = -2 // 空间退款 + ZoneUnlockTypeExit = -1 // 主动退出空间 + ZoneUnlockTypeFree = 1 // 免费解锁 + ZoneUnlockTypePay = 2 // 付费解锁 + ZoneUnlockTypeReachConsume = 3 // 满足消费额解锁 + ZoneUnlockTypeThirdPartner = 4 // 代运营直接解锁 + ZoneUnlockTypeCollaborator = 5 // 协作者直接解锁 ) type ZoneUnlock struct { diff --git a/dbstruct/zone_collaborator.go b/dbstruct/zone_collaborator.go index 06faf588..2c769183 100644 --- a/dbstruct/zone_collaborator.go +++ b/dbstruct/zone_collaborator.go @@ -10,6 +10,13 @@ type ZoneCollaborator struct { DelFlag *int64 `json:"del_flag" bson:"del_flag"` // 删除标记 } +func (p *ZoneCollaborator) GetZid() int64 { + if p != nil && p.Zid != nil { + return *p.Zid + } + return 0 +} + func (p *ZoneCollaborator) GetCollaboratorMid() int64 { if p != nil && p.CollaboratorMid != nil { return *p.CollaboratorMid diff --git a/dbstruct/zone_third_partner.go b/dbstruct/zone_third_partner.go index b3e289bb..3e5cebcb 100644 --- a/dbstruct/zone_third_partner.go +++ b/dbstruct/zone_third_partner.go @@ -11,6 +11,13 @@ type ZoneThirdPartner struct { } +func (p *ZoneThirdPartner) GetZid() int64 { + if p != nil && p.Zid != nil { + return *p.Zid + } + return 0 +} + func (p *ZoneThirdPartner) GetThirdPartnerMid() int64 { if p != nil && p.ThirdPartnerMid != nil { return *p.ThirdPartnerMid