diff --git a/README.md b/README.md index d62cbf858ef9068250b858b603a5b47877f5419c..0891e8ec5b863b4ff4c8d75a1f3efdf2bb8c89b7 100644 --- a/README.md +++ b/README.md @@ -17,5 +17,10 @@ + rpc: rpc请求 + const.go: 常量 + http.go: 封装http相关 + + internal + + 内部用的结构体,避免和上游的冲突 + + txop: 需事务操作的行为 + + 例如 下发钻石/勋章/座驾等 + + 支持捆绑上述操作,用于替换rpc发奖品 + utils: 工具包 + script: 临时脚本 diff --git a/domain/model.go b/domain/model.go index 42a43c97e8a8924a47d4a4d9a8d1e802b967dd74..44c9cb8cb61962b5db15c15fe6079db78948fed1 100644 --- a/domain/model.go +++ b/domain/model.go @@ -1,10 +1,13 @@ package domain import ( + "fmt" "git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/redisCli" "gorm.io/gorm" + "gorm.io/gorm/clause" + "time" ) type Model struct { @@ -53,3 +56,72 @@ func (m *Model) Transaction(f func(*Model) error) error { } return txModel.Db.Commit().Error } + +func Persistent(db *gorm.DB, t mysql.EntityI) error { + if t == nil { + return nil + } + if t.IsLazyLoad() { + return nil + } + //删除 + if t.CheckDel() { + tx := db.Delete(t) + if err := tx.Error; err != nil { + return err + } + if tx.RowsAffected == 0 { + return fmt.Errorf("gorm delete.RowsAffected = 0") + } + //增加缓存行为记录(删除) + + } else if t.GetID() == 0 { + //新增 + if t.CheckOnDuplicateKeyUPDATE() { + if err := db.Set("gorm:insert_option", fmt.Sprintf("ON DUPLICATE KEY UPDATE `created_time` = '%s'", time.Now())).Create(t).Error; err != nil { + return err + } + } else if t.CheckOnDuplicateKeyIGNORE() { + if err := db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(t).Error; err != nil { + return err + } + } else { + if err := db.Create(t).Error; err != nil { + return err + } + } + //增加缓存行为记录(新增) + } else { + //fixme: 更新条件,目前是互斥的,应该改成且。 + //更新 + if t.CheckUpdateVersion() { + //版本号。乐观锁更新,注意,空值不更新 + tx := db.Model(t).Where("version = ? ", t.GetUpdateVersionBefore()).Updates(t) + if err := tx.Error; err != nil { + return err + } + if tx.RowsAffected == 0 { + return fmt.Errorf("gorm version update.RowsAffected = 0") + } + } else if t.CheckUpdateCondition() { + //条件更新 + tx := db.Model(t).Where(t.GetUpdateCondition()).Updates(t) + if err := tx.Error; err != nil { + return err + } + if tx.RowsAffected == 0 { + return fmt.Errorf("gorm condition update.RowsAffected = 0") + } + } else if len(t.GetOmit()) > 0 { + if err := db.Model(t).Omit(t.GetOmit()...).Save(t).Error; err != nil { + return err + } + } else { + if err := db.Model(t).Save(t).Error; err != nil { + return err + } + } + //增加缓存行为记录(更新) + } + return nil +} diff --git a/internal/enum/diamond_e/diamond.go b/internal/enum/diamond_e/diamond.go new file mode 100644 index 0000000000000000000000000000000000000000..1b6c482791a91d856013fd7c9aa0e17db8c1f4cb --- /dev/null +++ b/internal/enum/diamond_e/diamond.go @@ -0,0 +1,106 @@ +package diamond_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +type StatusAccount = mysql.Type + +const ( + Normal StatusAccount = 1 + //冻结,只是限制减少,不限制增加 + Frozen StatusAccount = 2 +) + +type OperateType = mysql.Type + +const ( + //注册 + /* REGISTER OperateType = 1 + //建立融云会话 + SessionPay OperateType = 2 + //购买钻石 + BuyDiamond OperateType = 3 + //发送礼物 + SendGift OperateType = 4 + //接受礼物 + ReceiveGift OperateType = 5 + //匹配条件 + MatchCondition OperateType = 6*/ + + SendGift OperateType = 1 //发送礼物 + MatchCondition OperateType = 2 //匹配条件 + SessionPay OperateType = 3 //建立融云会话 + BuyDiamond OperateType = 4 //购买钻石 + ReceiveGift OperateType = 5 //接受礼物 + REGISTER OperateType = 6 //注册 + MgrSend OperateType = 8 //平台赠送 + VideoCost OperateType = 9 //1对1视频花费 + MgrReduce OperateType = 10 //平台扣除 + ActivityBillboard OperateType = 11 //活动榜单奖励 + ExchangeBean OperateType = 12 //钻石兑换豆子 + ActivityGroupBillboard OperateType = 13 //活动榜单奖励 + DailyInAppVip OperateType = 14 //每日登陆领取钻石(VIP) + GroupIMMass OperateType = 15 //群中IM群发 + DailyInAppCommon OperateType = 16 //每日登陆领取钻石(普通用户) + GroupSupportAdmin OperateType = 17 //群组支持(利益分配者) + GroupSupportMgr OperateType = 18 //群主支持(助手) + MgrBillDiamond OperateType = 19 //管理人单据送钻石 + Headwear OperateType = 20 //送头饰扣费 + Property OperateType = 21 //送坐骑扣费 + LuckyWheelJoin OperateType = 22 //参与转盘扣费 + LuckyWheelCancel OperateType = 23 //转盘取消 + LuckyWheelWin OperateType = 24 //转盘奖励 + LuckWheelGroupOwer OperateType = 25 //转盘群主抽成 + DealerTransfer OperateType = 26 //币商转账 + GroupCustomTheme OperateType = 27 //购买群组自定义主题 + RocketAward OperateType = 28 //火箭奖励 + LuckyboxBuy OperateType = 29 //幸运盒子购买 + LuckyboxAward OperateType = 30 //幸运盒子奖励 + PrivateGift OperateType = 31 // 私聊送礼物 + PrivateGiftReturn OperateType = 32 // 私聊送礼物退款 + ActivityTriggerAward OperateType = 33 //活动触发奖励 + VideoTradeUnionGift OperateType = 34 // 视频送礼物 + VideoTradeUnionGiftReturn OperateType = 35 // 视频送礼物退款 + GlobalBroadcast OperateType = 36 //全球发布消息 + TaskAward OperateType = 37 //任务奖励 + FruitMachineAward OperateType = 38 // 水果机奖励 + FruitMachineBet OperateType = 39 // 水果机投注 + Noble OperateType = 40 //购买/赠送贵族 + FruitTycoonAward OperateType = 41 // 水果大亨奖励 + Checkout OperateType = 42 //checkout购买 + LuckyboxCycle OperateType = 43 //幸运盒子回收奖励 + ActivityRechargeFirst OperateType = 44 //首次充值奖励 + NewUserInvite OperateType = 45 // 新用户奖励活动 + GeneralActivity OperateType = 46 // 一般性活动奖励 + PowerSupportOwner OperateType = 47 // 势力支持(势力主) + PowerSupportAssistant OperateType = 48 // 势力支持(助手) + VideoMinute OperateType = 49 //1对1视频(分钟扣费) + MatchMinute OperateType = 50 //匹配视频(第一分钟扣费) + VideoMinuteBack OperateType = 51 //1对1视频(分钟扣费,返回) + VideoMinuteTotal OperateType = 52 //1对1视频(分钟扣费,返回) + GroupActivity OperateType = 53 //创建群组活动 + GroupActivityReward OperateType = 54 //群组活动奖励 + PayerMax OperateType = 55 //payerMax/茄子支付购买 + BuyPinkDiamond OperateType = 56 //购买粉钻 + VideoCostPink OperateType = 57 //1对1视频送礼(粉钻) + MatchMinutePink OperateType = 58 //匹配视频(第一分钟扣费)(粉钻) + VideoMinuteTotalPink OperateType = 59 //1对1视频(分钟扣费,返回)(粉钻) + SendPinkGift OperateType = 60 //送粉钻礼物 ---占位---暂不开放 数据库配置表中暂未配置 + MatchMinuteGiftPink OperateType = 61 //匹配视频送礼(粉钻) + MatchMinuteGiftPinkTime OperateType = 62 //匹配视频加时送礼(粉钻) + JoinGroupCost OperateType = 63 //加入群组扣费 + JoinGroupAdd OperateType = 64 //加入群组,群主得黄钻 + GameJoin OperateType = 65 //加入游戏扣费 + GameAward OperateType = 66 //游戏结算奖励 + GameRefund OperateType = 67 //游戏退费 + Paypal OperateType = 68 //paypal充值 + H5GameJoin OperateType = 69 //加入游戏扣费 + H5GameAward OperateType = 70 //游戏结算奖励 + ActFruitPutRankAward OperateType = 71 //水果机排行榜奖励 + H5GameLevelAward OperateType = 72 //游戏等级奖励 + ActSlotWeekRankAward OperateType = 73 //slot周活动排行榜奖励 +) + +const ( + DiamondYellow mysql.Type = 1 + DiamondPink mysql.Type = 2 +) diff --git a/internal/enum/headwear_e/headwear.go b/internal/enum/headwear_e/headwear.go new file mode 100644 index 0000000000000000000000000000000000000000..1b0e80d447ac523aac36e69b97dafc3c3f533174 --- /dev/null +++ b/internal/enum/headwear_e/headwear.go @@ -0,0 +1,35 @@ +package headwear_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +type UserHeadwearUsing = mysql.Type + +const ( + YesUsing UserHeadwearUsing = 1 + NoUsing UserHeadwearUsing = 0 +) + +type UserHeadwearLogOrginType = mysql.Type + +const ( + Mgr UserHeadwearLogOrginType = 1 + //购买,或者别人购买 + Send UserHeadwearLogOrginType = 2 + Activity UserHeadwearLogOrginType = 3 + Rocket UserHeadwearLogOrginType = 4 + //活动阀值自动触发奖励 + ActivityTrigger UserHeadwearLogOrginType = 5 + //首次充值奖励 + ActivityRechargeFirst UserHeadwearLogOrginType = 6 + //别人赠送 + Give UserHeadwearLogOrginType = 7 + GeneralActivity UserHeadwearLogOrginType = 8 +) + +type UserHeadwearLogType mysql.Type + +const ( + AddSecond UserHeadwearLogType = 1 + UpdateEndTime UserHeadwearLogType = 2 + Del UserHeadwearLogType = 3 +) diff --git a/internal/enum/msg_e/enum.go b/internal/enum/msg_e/enum.go new file mode 100644 index 0000000000000000000000000000000000000000..1d8f4ba89d04153707ed619f9045fac92f95210c --- /dev/null +++ b/internal/enum/msg_e/enum.go @@ -0,0 +1,131 @@ +package msg_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +//消息发送类型,消息接收者是谁 1:通知 2:官网 3:被喜欢通知 (注意:MsgReceiveType 同 MsgUserRecordType 不是树形关系s) +//MsgReceive 结构体服务 +type MsgReceiveType = mysql.Type + +const ( + //小助手的通知 + UserMsgReceiveType MsgReceiveType = 1 + //系统的通知 + SysMsgReceiveType MsgReceiveType = 2 + //喜欢消息 + LikeMeReceiveType MsgReceiveType = 3 + //工会用户通知 + TradeUnionReceiveType MsgReceiveType = 4 + //用户召回 + UserRecall MsgReceiveType = 5 + //video请求 + VideoSend MsgReceiveType = 6 + //访问 + VisitReceiveType MsgReceiveType = 7 + //拉黑 + BlockReceiveType MsgReceiveType = 8 + //短信验证码 + SmsCode MsgReceiveType = 9 +) + +//跳转类型 0:无调整 1:网页跳转 2:app跳转 3:跳转到钻石 4:跳转到背包 +type ActionType = uint16 + +const ( + NonActionType ActionType = 0 + WebActionType ActionType = 1 + AppActionType ActionType = 2 +) + +//消息记录类型(设计的不好,应该是根据消息样式类型设计,而不是业务类型,渣渣) +type MsgUserRecordType = mysql.Type + +const ( + //新用户 + //NewUserType MsgUserRecordType = 1 + //举报 + ReportType MsgUserRecordType = 2 + //喜欢我 + //LikeMeType MsgUserRecordType = 3 + //重置图片 + ResetAvatarType MsgUserRecordType = 4 + // + //喜欢我 + LikeMeType MsgUserRecordType = 5 + //访问 + VisitType MsgUserRecordType = 6 + //新匹配记录 + MatchHistoryType MsgUserRecordType = 7 + //互相喜欢 + LikeEachType MsgUserRecordType = 8 + //你获得s%钻石的礼物收益! + DiamondIncome MsgUserRecordType = 9 + //榜单结果 + ActivityBillboardResult MsgUserRecordType = 10 + //榜单钻石收益 + ActivityBillboardDiamond MsgUserRecordType = 11 + //榜单坐骑收益 + ActivityBillboardProperty MsgUserRecordType = 12 + //通过收礼物获得豆子 + ActivityBeanProperty MsgUserRecordType = 13 + //管理人送钻石 + MgrSendDiamondProperty MsgUserRecordType = 14 + //群组榜单钻石收益 + ActivityGroupBillboardDiamond MsgUserRecordType = 15 + //群组榜单坐骑收益 + ActivityGroupBillboardProperty MsgUserRecordType = 16 + //群组支持收益 + GroupSupport MsgUserRecordType = 17 + //群组支持提醒结果 + GroupSupportResult MsgUserRecordType = 18 + //管理人送座驾 + MgrSendProperty MsgUserRecordType = 19 + //送道具(座驾,头饰都属于道具) + AddProps MsgUserRecordType = 20 + //MISS活动获胜 + ActivityBillboardBeLikeResult = 21 + //CP活动获胜 + ActivityBillboardCpResult = 22 + //加入势力主 + GroupPowerUserJoin = 23 + //离开势力主 + GroupPowerUserLeave = 24 + //贵族 + AddNoble = 25 + //日充值活动通知 + ActivityTriggerDayPay = 26 + //也门活动通知 + ActivityTriggerYemen = 27 + //月充值活动通知 + ActivityTriggerMonthPay = 28 + FruitTycoonAward = 29 // 水果大亨获奖 + LuckyboxRecycle = 30 //幸运盒子回收 + HlTemp1 = 31 //产品黄蕾,2022/06/29 临时要求发给某人的小助手消息 + HLTemp2 = 32 //问卷调查 + NewUserInviteAuditPassed = 33 // 新用户奖励活动审核通过 + NewUserInviteAuditFailed = 34 // 新用户奖励活动审核不通过 + NewUserInviterAward = 35 // 新用户奖励活动邀请成功数达标 + PowerSupportSalary = 36 // 势力扶持工资领取 提醒 + CountryStarOrdinaryAward = 37 // 国家之星瓜分奖提醒 + GroupActivityRewardMsg = 38 // 群组活动钻石奖励提醒 + TemplateActAwardMsg = 39 // 通用模板活动奖励提醒 + TemplateSmsCode = 40 // 通用模板活动奖励提醒 + AddUserBag = 50 // 赠送背包礼物 +) + +type MsgSysUserType = mysql.Type + +const ( + //系统消息 + SysType MsgSysUserType = 1 + //小助手消息 + AssistantType MsgSysUserType = 2 +) + +//resMsgTransalte 中 msg_type 同 type, msg_type是属于一级类型 type属于二级类型。 msg_type 对应MsgReceiveType type:部分对应MsgUserRecordType MsgUserRecordType(应该是小助手的类型) +type MsgSysRecordType = mysql.Type + +const ( + //这个值木有意义, + SysMsgSysRecordType1 MsgSysRecordType = 1 + SysMsgSysRecordType2 MsgSysRecordType = 2 +) diff --git a/internal/enum/property_e/enum.go b/internal/enum/property_e/enum.go new file mode 100644 index 0000000000000000000000000000000000000000..6c146b22368036158bfab69dae725d27e9bc6eeb --- /dev/null +++ b/internal/enum/property_e/enum.go @@ -0,0 +1,48 @@ +package property_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +type UserPropertyUsing = mysql.Type + +const ( + YesUsing UserPropertyUsing = 1 + NoUsing UserPropertyUsing = 0 +) + +type UserPropertyLogOrginType = mysql.Type + +const ( + //活动奖励 + ActivityBillboardReward UserPropertyLogOrginType = 1 + // + Operational UserPropertyLogOrginType = 2 + //群组活动 + ActivityGroupBillboardReward UserPropertyLogOrginType = 3 + //赠送 + Send UserPropertyLogOrginType = 4 + //火箭游戏 + Rocket UserPropertyLogOrginType = 5 + //活动阀值触发奖励 + ActivityBillboardTrigger UserPropertyLogOrginType = 6 + //首次充值奖励 + ActivityRechargeFirst UserPropertyLogOrginType = 7 + Give UserPropertyLogOrginType = 8 + GeneralActivity UserPropertyLogOrginType = 9 // 一般性活动 +) + +type UserPropertyLogType mysql.Type + +const ( + AddSecond UserPropertyLogType = 1 + UpdateEndTime UserPropertyLogType = 2 + Del UserPropertyLogType = 3 +) + +type PropertyType = uint16 + +const ( + TypeNoble PropertyType = 1 + TypeMedal PropertyType = 2 + TypeHeaddress PropertyType = 3 + TypeRide PropertyType = 4 +) diff --git a/internal/model/diamond_m/diamond.go b/internal/model/diamond_m/diamond.go new file mode 100644 index 0000000000000000000000000000000000000000..131a3c72a4d45b572860e22b490eb4d8d0ffd8ff --- /dev/null +++ b/internal/model/diamond_m/diamond.go @@ -0,0 +1,156 @@ +package diamond_m + +import ( + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/diamond_e" + "git.hilo.cn/hilo-common/resource/mysql" + "strconv" + "time" +) + +type DiamondAccount struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + DiamondNum mysql.Num + PinkDiamondNum mysql.Num + Status diamond_e.StatusAccount +} + +//账号详情 +type DiamondAccountDetail struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + DiamondAccountId mysql.ID + OperateId mysql.ID + OperateType diamond_e.OperateType + OriginId mysql.ID + AddReduce mysql.AddReduce + Num mysql.Num + Remark mysql.Str + BefNum mysql.Num + AftNum mysql.Num + diamondAccount *DiamondAccount `gorm:"-"` +} + +//账号操作配置 +type DiamondOperateSet struct { + mysql.Entity + *domain.Model `gorm:"-"` + DiamondNum mysql.NumAll + FrequencyNum mysql.NumAll + FrequencyDay mysql.NumAll + DiamondMaxNum mysql.NumAll + AddReduce mysql.AddReduce + Type diamond_e.OperateType + Name mysql.Str + Status mysql.UserYesNo + DiamondType diamond_e.OperateType +} + +//通过userId获取帐号 +func GetDiamondAccountByUserId(model *domain.Model, userId mysql.ID) (*DiamondAccount, error) { + var diamondAccount DiamondAccount + if err := model.Db.WithContext(model).Where(&DiamondAccount{ + UserId: userId, + }).First(&diamondAccount).Error; err != nil { + return nil, err + } + diamondAccount.Model = model + return &diamondAccount, nil +} + +//匹配条件扣费 +func (diamondAccount *DiamondAccount) ChangeDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) { + return diamondAccount.addDiamondAccountDetail(operateType, originId, diamondNum) +} + +//钻石操作记录, +func (diamondAccount *DiamondAccount) addDiamondAccountDetail(operateType diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) { + var diamondOperateSet DiamondOperateSet + var err error + if err = diamondAccount.Db.Where(&DiamondOperateSet{ + Type: operateType, + Status: mysql.USER, + DiamondType: diamond_e.DiamondYellow, + }).First(&diamondOperateSet).Error; err != nil { + return nil, err + } + + //判断是增加,账号是否被冻结 + if diamondAccount.Status == diamond_e.Frozen && diamondOperateSet.AddReduce == mysql.REDUCE { + return nil, fmt.Errorf("bizerr.DiamondAccountFrozen") + } + + //无限,检查次数 + var count int64 + if diamondOperateSet.FrequencyDay == -1 { + if diamondOperateSet.FrequencyNum != -1 { + diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{ + UserId: diamondAccount.UserId, + OperateType: operateType, + }).Count(&count) + if count >= int64(diamondOperateSet.FrequencyNum) { + return nil, fmt.Errorf("bizerr.DiamondFrequency") + } + } + } else if diamondOperateSet.FrequencyDay == 1 { + beginTime, err := time.ParseInLocation("2006-01-02", time.Now().Format("2006-01-02"), time.Local) + if err != nil { + return nil, err + } + //一天的次数 + diamondAccount.Db.Model(&DiamondAccountDetail{}).Where(&DiamondAccountDetail{ + UserId: diamondAccount.UserId, + OperateType: operateType, + }).Where("created_time >= ? ", beginTime).Count(&count) + if count >= int64(diamondOperateSet.FrequencyNum) { + return nil, fmt.Errorf("bizerr.DiamondFrequency") + } + //终极拦截,利用 + diamondAccount.SetCheckUpdateCondition(" EXISTS (SELECT * from (SELECT COUNT(1) as n from diamond_account_detail d where d.user_id = " + strconv.FormatUint(diamondAccount.UserId, 10) + " and d.operate_type = " + strconv.FormatUint(uint64(operateType), 10) + " and d.created_time >= from_unixtime(" + strconv.FormatInt(getZeroTime(time.Now()).Unix(), 10) + ")) t where t.n < " + strconv.Itoa(diamondOperateSet.FrequencyNum) + " )") + } + + //-1,代表值无效,由参数给与 + var upateDiamondNum mysql.Num + if diamondOperateSet.DiamondNum == -1 { + upateDiamondNum = diamondNum + } else { + upateDiamondNum = mysql.Num(diamondOperateSet.DiamondNum) + } + + var afterNum mysql.Num + if diamondOperateSet.AddReduce == mysql.ADD { + afterNum = diamondAccount.DiamondNum + upateDiamondNum + } else if diamondOperateSet.AddReduce == mysql.REDUCE { + if diamondAccount.DiamondNum < upateDiamondNum { + return nil, fmt.Errorf("bizerr.DiamondNoEnough") + } + afterNum = diamondAccount.DiamondNum - upateDiamondNum + } else { + return nil, fmt.Errorf("AddReduce 值错误:" + mysql.TypeToString(diamondOperateSet.AddReduce)) + } + + diamondAccountDetail := &DiamondAccountDetail{ + Model: diamondAccount.Model, + UserId: diamondAccount.UserId, + DiamondAccountId: diamondAccount.ID, + OperateId: diamondOperateSet.ID, + OperateType: diamondOperateSet.Type, + OriginId: originId, + AddReduce: diamondOperateSet.AddReduce, + Num: upateDiamondNum, + Remark: diamondOperateSet.Name, + BefNum: diamondAccount.DiamondNum, + AftNum: afterNum, + diamondAccount: diamondAccount, + } + return diamondAccountDetail, err +} + +// 一般性活动奖励 +func (diamondAccount *DiamondAccount) AddDiamondAccountDetail(operateType diamond_e.OperateType, refId mysql.ID, diamondNum mysql.Num) (*DiamondAccountDetail, error) { + return diamondAccount.addDiamondAccountDetail(operateType, refId, diamondNum) +} diff --git a/internal/model/diamond_m/diamond_check.go b/internal/model/diamond_m/diamond_check.go new file mode 100644 index 0000000000000000000000000000000000000000..63afa77e3b6b49335dd39cfecff7199d6e6d4d06 --- /dev/null +++ b/internal/model/diamond_m/diamond_check.go @@ -0,0 +1,22 @@ +package diamond_m + +import ( + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/diamond_e" + "git.hilo.cn/hilo-common/resource/mysql" +) + +func CheckEnoughDiamondFrozen(model *domain.Model, userId mysql.ID, diamondNum mysql.Num) (*DiamondAccount, error) { + diamondAccount, err := GetDiamondAccountByUserId(model, userId) + if err != nil { + return nil, err + } + if diamondAccount.DiamondNum < diamondNum { + return nil, fmt.Errorf("bizerr.DiamondNoEnough") + } + if diamondAccount.Status == diamond_e.Frozen { + return nil, fmt.Errorf("bizerr.DiamondAccountFrozen") + } + return diamondAccount, nil +} diff --git a/internal/model/diamond_m/repo.go b/internal/model/diamond_m/repo.go new file mode 100644 index 0000000000000000000000000000000000000000..8f19586bca0a754cce1de2f840656a079be17dd9 --- /dev/null +++ b/internal/model/diamond_m/repo.go @@ -0,0 +1,52 @@ +package diamond_m + +import ( + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mylogrus" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "strconv" +) + +func (diamondAccountDetail *DiamondAccountDetail) Persistent() error { + txDiamondAccount := diamondAccountDetail.Db.Model(diamondAccountDetail.diamondAccount) + if diamondAccountDetail.diamondAccount.CheckUpdateCondition() { + txDiamondAccount = txDiamondAccount.Where(diamondAccountDetail.diamondAccount.GetUpdateCondition()) + } + if diamondAccountDetail.AddReduce == mysql.ADD { + //增加 + txDiamondAccount.UpdateColumn("diamond_num", gorm.Expr("diamond_num + ?", diamondAccountDetail.Num)) + } else if diamondAccountDetail.AddReduce == mysql.REDUCE { + //减少,保证不能扣成负数 + txDiamondAccount.Where("diamond_num >= ?", diamondAccountDetail.Num).UpdateColumn("diamond_num", gorm.Expr("diamond_num - ?", diamondAccountDetail.Num)) + } else { + mylogrus.MyLog.Errorf("addReduce 枚举错误 value:" + mysql.TypeToString(mysql.Type(diamondAccountDetail.AddReduce))) + } + if err := txDiamondAccount.Error; err != nil { + return err + } + if txDiamondAccount.RowsAffected == 0 { + mylogrus.MyLog.Errorf("gorm condition update.RowsAffected = 0,AddReduce:%v", diamondAccountDetail.AddReduce) + return fmt.Errorf("gorm condition update.RowsAffected = 0") + } + + //持久化diamondAccountDetail + if err := domain.Persistent(diamondAccountDetail.Db, diamondAccountDetail); err != nil { + return err + } + //改变diamondAccount值 + if diamondAccountDetail.diamondAccount == nil { + return fmt.Errorf("持久化错误, 模型:DiamondAccountDetail 中没有diamondAccount, DiamondAccountDetail.Id =" + strconv.Itoa(int(diamondAccountDetail.ID))) + } + + var newDiamondAccount DiamondAccount + if err := diamondAccountDetail.Db.First(&newDiamondAccount, diamondAccountDetail.diamondAccount.ID).Error; err != nil { + return err + } + + if newDiamondAccount.DiamondNum < 0 { + return fmt.Errorf("diamond_account表中,diamond_num 不能小于0, diamondAccount.id = " + strconv.Itoa(int(newDiamondAccount.ID))) + } + return nil +} diff --git a/internal/model/diamond_m/util.go b/internal/model/diamond_m/util.go new file mode 100644 index 0000000000000000000000000000000000000000..eb3898447fb23c9d91d62be0b662f91cefb24769 --- /dev/null +++ b/internal/model/diamond_m/util.go @@ -0,0 +1,7 @@ +package diamond_m + +import "time" + +func getZeroTime(t time.Time) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) +} diff --git a/internal/model/msg_m/factory.go b/internal/model/msg_m/factory.go new file mode 100644 index 0000000000000000000000000000000000000000..e49258a16a4c14012663c92824c046694a0c3fd5 --- /dev/null +++ b/internal/model/msg_m/factory.go @@ -0,0 +1,32 @@ +package msg_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" +) + +func GetMsgSysRecordInit(model *domain.Model, t uint32, msgSysId uint64) *MsgSysRecord { + return &MsgSysRecord{ + Model: model, + Type: t, + Status: mysql.EXIST, + MsgSysId: msgSysId, + } +} + +func GetMsgSysRecord(model *domain.Model, msgSysId uint64) (*MsgSysRecord, error) { + msgSysRecord := MsgSysRecord{} + if err := model.Db.Model(&MsgSysRecord{}).Where(&MsgSysRecord{ + MsgSysId: msgSysId, + }).First(&msgSysRecord).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } else { + msgSysRecord.Model = model + return &msgSysRecord, nil + } +} diff --git a/internal/model/msg_m/msg.go b/internal/model/msg_m/msg.go new file mode 100644 index 0000000000000000000000000000000000000000..e842d56dfa9207b0c79d343cf6bf3d8e211913a6 --- /dev/null +++ b/internal/model/msg_m/msg.go @@ -0,0 +1,79 @@ +package msg_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/msg_e" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/sdk/emas" + "git.hilo.cn/hilo-common/utils" +) + +type MsgUserRecord struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + Type msg_e.MsgUserRecordType + Nick mysql.Str + NickUserId mysql.ID //用户的别名 + DiamondIncome mysql.Str + DayNum mysql.Str //多少天 + PropertyUrl mysql.Str //道具地址 + BeanNum mysql.Str //多少豆子 + GroupCode mysql.Str //群组code +} + +type MsgSysRecord struct { + mysql.Entity + *domain.Model `gorm:"-"` + //Type msg_m.MsgSysRecordType + Type uint32 + Status mysql.LogicDel + MsgSysId mysql.ID +} + +//系统消息,用户最后已读的位置 +type MsgSysUser struct { + mysql.Entity + *domain.Model `gorm:"-"` + Type msg_e.MsgSysUserType + UserId mysql.ID + MsgSysLastId mysql.ID +} + +//删除 +func (msgSysRecord *MsgSysRecord) Del() *MsgSysRecord { + msgSysRecord.Status = mysql.DEL + return msgSysRecord +} + +type MsgReceive struct { + Type msg_e.MsgReceiveType `json:"type"` + //Timestamp mysql.Timestamp `json:"timestamp"` +} + +func NewUserRecord(model *domain.Model, userId mysql.ID, t msg_e.MsgUserRecordType, nick mysql.Str, nickUserId mysql.ID, diamondIncome mysql.Str, dayNum mysql.Str, propertyUrl mysql.Str, beanNum mysql.Str, groupCode mysql.Str) *MsgUserRecord { + return &MsgUserRecord{ + Model: model, + UserId: userId, + Type: t, + Nick: nick, + NickUserId: nickUserId, + DiamondIncome: diamondIncome, + DayNum: dayNum, + PropertyUrl: propertyUrl, + BeanNum: beanNum, + GroupCode: groupCode, + } +} + +// 发给小助手的消息, 不需要抛出错误 +func SendEmasMsgAssistant(model *domain.Model, externalId string, deviceType string) error { + str, _ := utils.ToString(MsgReceive{ + Type: msg_e.UserMsgReceiveType, + }) + err := emas.SendMsg(externalId, deviceType, str) + if err != nil { + model.Log.Errorf("emas.SendMsg err:%v", err) + } + return nil +} diff --git a/internal/model/msg_m/repo.go b/internal/model/msg_m/repo.go new file mode 100644 index 0000000000000000000000000000000000000000..2bfae3e98b3172a21c9cfcd8f421d7ced61830ad --- /dev/null +++ b/internal/model/msg_m/repo.go @@ -0,0 +1,23 @@ +package msg_m + +import ( + "git.hilo.cn/hilo-common/domain" +) + +func (msgUserRecord *MsgUserRecord) Persistent() error { + if err := domain.Persistent(msgUserRecord.Db, msgUserRecord); err != nil { + return err + } + return nil +} + +func (msgSysRecord *MsgSysRecord) Persistent() error { + if err := domain.Persistent(msgSysRecord.Db, msgSysRecord); err != nil { + return err + } + return nil +} + +func (msgSysUser *MsgSysUser) Persistent() error { + return domain.Persistent(msgSysUser.Db, msgSysUser) +} diff --git a/internal/model/noble_m/config.go b/internal/model/noble_m/config.go new file mode 100644 index 0000000000000000000000000000000000000000..84cc0aa6eaf7689f2df8c931c5eb7209765008bb --- /dev/null +++ b/internal/model/noble_m/config.go @@ -0,0 +1,62 @@ +package noble_m + +import ( + "gorm.io/gorm" + "time" +) + +const RENEWAL_LIMIT_DAY = 7 + +type ResNoble struct { + Level uint16 + PurchasePrice uint32 + RenewalPrice uint32 + Duration uint16 + PicUrl string + DailyGold uint + RideId uint64 // 赠送的座驾ID + HeaddressId uint64 // 赠送的头饰ID +} + +func GetAllConfig(db *gorm.DB) ([]ResNoble, error) { + rows := make([]ResNoble, 0) + err := db.Find(&rows).Error + if err != nil { + return nil, err + } + return rows, nil +} + +func GetAllConfigMap(db *gorm.DB) (map[uint16]ResNoble, error) { + rows, err := GetAllConfig(db) + if err != nil { + return nil, err + } + result := make(map[uint16]ResNoble, 0) + for _, i := range rows { + result[i.Level] = i + } + return result, nil +} + +func GetConfigByLevel(db *gorm.DB, level uint16) (ResNoble, error) { + r := ResNoble{} + if err := db.Model(&ResNoble{}).First(&r, level).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return r, nil + } else { + return r, err + } + } + return r, nil +} + +// 根据过期时间推算价格 +func CalcPrice(cfg ResNoble, endTime time.Time) uint32 { + now := time.Now() + price := cfg.RenewalPrice + if now.After(endTime.AddDate(0, 0, RENEWAL_LIMIT_DAY)) { + price = cfg.PurchasePrice + } + return price +} diff --git a/internal/model/noble_m/nobleLog.go b/internal/model/noble_m/nobleLog.go new file mode 100644 index 0000000000000000000000000000000000000000..2d574b37030278361ba8adc3f0baa1ebcc513147 --- /dev/null +++ b/internal/model/noble_m/nobleLog.go @@ -0,0 +1,30 @@ +package noble_m + +import ( + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "time" +) + +const ( + SRC_APP = 1 // APP + SRC_OPERATION = 2 // 管理后台发放 + SRC_H5 = 3 // H5页面 + SRC_ACTIVITY = 4 // 活动奖励 + RECHARGE_FIRST = 5 // 首次充值 +) + +type UserNobleLog struct { + mysql.Entity + SenderId uint64 + ReceiverId uint64 + Level uint16 + Money uint32 + SrcType uint16 + OldEndTime time.Time + NewEndTime time.Time +} + +func (ubl *UserNobleLog) Create(db *gorm.DB) error { + return db.Create(ubl).Error +} diff --git a/internal/model/noble_m/userNoble.go b/internal/model/noble_m/userNoble.go new file mode 100644 index 0000000000000000000000000000000000000000..06daa123246069f0ac82a91b87ac15941619bd1e --- /dev/null +++ b/internal/model/noble_m/userNoble.go @@ -0,0 +1,126 @@ +package noble_m + +import ( + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "time" +) + +type UserNoble struct { + mysql.Entity + UserId uint64 + Level uint16 + EndTime time.Time +} + +func (ub *UserNoble) Create(db *gorm.DB) error { + return db.Create(ub).Error +} + +func (ub *UserNoble) UpdateEndTime(db *gorm.DB, endTime time.Time) (int64, error) { + r := db.Model(&UserNoble{}).Where(ub).Update("end_time", endTime) + return r.RowsAffected, r.Error +} + +// 查询用户未过期的贵族 +func (ub *UserNoble) Find(db *gorm.DB) ([]UserNoble, error) { + rows := make([]UserNoble, 0) + if err := db.Where(ub).Where("end_time>=NOW()").Order("level DESC").Find(&rows).Error; err != nil { + return nil, err + } + return rows, nil +} + +// 查询用户所有的贵族(包括已过期) +func (ub *UserNoble) FindAll(db *gorm.DB) ([]UserNoble, error) { + rows := make([]UserNoble, 0) + if err := db.Where(ub).Order("level DESC").Find(&rows).Error; err != nil { + return nil, err + } + return rows, nil +} + +func RemoveNoble(db *gorm.DB, userId uint64, level uint16) error { + ub := UserNoble{ + UserId: userId, + Level: level, + } + return ub.Delete(db) +} + +func (ub *UserNoble) Delete(db *gorm.DB) error { + return db.Where(ub).Delete(&UserNoble{}).Error +} + +func FindActiveNoble(db *gorm.DB, userId uint64) (*UserNoble, error) { + ub := UserNoble{ + UserId: userId, + } + records, err := ub.Find(db) + if err != nil { + return nil, err + } + if len(records) <= 0 { + return nil, nil + } + return &records[0], nil +} + +func GetNobleLevel(db *gorm.DB, userId uint64) (uint16, error) { + noble, err := FindActiveNoble(db, userId) + if err != nil { + return 0, err + } + if noble == nil { + return 0, nil + } else { + return noble.Level, nil + } +} + +func BatchGetNobleLevel(db *gorm.DB, userIds []uint64) (map[uint64]uint16, error) { + m, err := BatchGetActiveNoble(db, userIds) + if err != nil { + return nil, err + } + result := make(map[uint64]uint16, 0) + for _, i := range userIds { + result[i] = m[i].Level + } + return result, nil +} + +func BatchGetActiveNoble(db *gorm.DB, userIds []uint64) (map[uint64]UserNoble, error) { + ub := UserNoble{} + + records, err := ub.batchGet(db, userIds) + if err != nil { + return nil, err + } + result := make(map[uint64]UserNoble, 0) + for _, i := range userIds { + if len(records[i]) > 0 { + result[i] = records[i][0] + } else { + result[i] = UserNoble{} + } + } + + return result, nil +} + +// 查询用户未过期的贵族 +func (ub *UserNoble) batchGet(db *gorm.DB, userIds []uint64) (map[uint64][]UserNoble, error) { + rows := make([]UserNoble, 0) + if err := db.Model(ub).Where("end_time>=NOW() AND user_id IN ?", userIds).Order("level DESC").Find(&rows).Error; err != nil { + return nil, err + } + result := make(map[uint64][]UserNoble, 0) + for _, i := range rows { + if _, ok := result[i.UserId]; !ok { + result[i.UserId] = make([]UserNoble, 0) + } + result[i.UserId] = append(result[i.UserId], i) + } + return result, nil +} diff --git a/internal/model/res_m/headwear.go b/internal/model/res_m/headwear.go new file mode 100644 index 0000000000000000000000000000000000000000..408bb949ca3a0e5cf1b6e35b14cecfd139f4c738 --- /dev/null +++ b/internal/model/res_m/headwear.go @@ -0,0 +1,124 @@ +package res_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" +) + +type ResHeadwear struct { + mysql.Entity + *domain.Model `gorm:"-"` + Name mysql.Str + PicUrl mysql.Str + EffectUrl mysql.Str +} + +//矛盾,项目负责人(产品不接受 商品 同上架分开两个数据结构的模式),又在页面上要求头饰同价格在一起展示,修改。 +//目前违背了,ResHeadwearDiamond 作为资源数据,不允许修改的特点。后果在于,对账错误。 +type ResHeadwearDiamond struct { + mysql.Entity + *domain.Model `gorm:"-"` + ResHeadwearId mysql.ID + DiamondNum mysql.Num + Second mysql.Num + Status mysql.UserYesNo +} + +func InitResHeadwearDiamond(model *domain.Model, resHeadwearId mysql.ID, diamondNum mysql.Num, second mysql.Num) *ResHeadwearDiamond { + return &ResHeadwearDiamond{ + Model: model, + ResHeadwearId: resHeadwearId, + DiamondNum: diamondNum, + Second: second, + Status: mysql.NOUSER, + } +} + +func GetResHeadwearDiamondByHeadwearIdOrNil(model *domain.Model, resHeadwearId mysql.ID) (*ResHeadwearDiamond, error) { + resHeadwearDiamond := ResHeadwearDiamond{} + if err := model.Db.Model(&ResHeadwearDiamond{}).Where(&ResHeadwearDiamond{ + ResHeadwearId: resHeadwearId, + }).First(&resHeadwearDiamond).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } + resHeadwearDiamond.Model = model + return &resHeadwearDiamond, nil +} + +func (resHeadwearDiamond *ResHeadwearDiamond) SetDiamondNum(diamondNum uint32) *ResHeadwearDiamond { + resHeadwearDiamond.DiamondNum = diamondNum + return resHeadwearDiamond +} + +func (resHeadwearDiamond *ResHeadwearDiamond) SetSecond(second uint32) *ResHeadwearDiamond { + resHeadwearDiamond.Second = second + return resHeadwearDiamond +} + +//设置成未使用 +func (resHeadwearDiamond *ResHeadwearDiamond) SetUser() *ResHeadwearDiamond { + resHeadwearDiamond.Status = mysql.USER + return resHeadwearDiamond +} + +//设置成未使用 +func (resHeadwearDiamond *ResHeadwearDiamond) SetNoUser() *ResHeadwearDiamond { + resHeadwearDiamond.Status = mysql.NOUSER + return resHeadwearDiamond +} + +//id获取头饰,不存在则抛异常 +func GetHeadwearById(model *domain.Model, id mysql.ID) (*ResHeadwear, error) { + resHeadwear := ResHeadwear{} + if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil { + return nil, err + } else { + resHeadwear.Model = model + return &resHeadwear, nil + } +} + +//初始化头饰, +func InitHeadwear(model *domain.Model, name string, picUrl string, effectUrl string) *ResHeadwear { + return &ResHeadwear{ + Model: model, + Name: name, + PicUrl: picUrl, + EffectUrl: effectUrl, + } +} + +//修改头饰 +func (resHeadwear *ResHeadwear) EditName(name string) *ResHeadwear { + resHeadwear.Name = name + return resHeadwear +} + +func (resHeadwear *ResHeadwear) EditPicUrl(picUrl string) *ResHeadwear { + resHeadwear.PicUrl = picUrl + return resHeadwear +} + +func (resHeadwear *ResHeadwear) EditEffectUrl(effectUrl string) *ResHeadwear { + resHeadwear.EffectUrl = effectUrl + return resHeadwear +} + +func CheckHeadwearValidById(model *domain.Model, id mysql.ID) (bool, error) { + resHeadwear := ResHeadwear{} + if err := model.Db.Model(&ResHeadwear{}).First(&resHeadwear, id).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return false, nil + } else { + return false, err + } + + } else { + return true, nil + } +} diff --git a/internal/model/user_m/headwear.go b/internal/model/user_m/headwear.go new file mode 100644 index 0000000000000000000000000000000000000000..495e5a36d9bedacfe1fd0294902e58b1f977a171 --- /dev/null +++ b/internal/model/user_m/headwear.go @@ -0,0 +1,143 @@ +package user_m + +import ( + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/headwear_e" + "git.hilo.cn/hilo-common/internal/model/res_m" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "strconv" + "time" +) + +//用户头饰 +type UserHeadwear struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + HeadwearId mysql.ID + EndTime time.Time + Using headwear_e.UserHeadwearUsing +} + +//获取用户头饰,不存在则新建 +func GetUserHeadwearOrInit(model *domain.Model, userId mysql.ID, headwearId mysql.ID) (*UserHeadwear, error) { + //检查headwearId是否存在/有效 + if flag, err := res_m.CheckHeadwearValidById(model, headwearId); err != nil { + return nil, err + } else { + if flag == false { + return nil, fmt.Errorf("headwearId: " + strconv.FormatUint(headwearId, 10) + " 无效") + } + } + + userHeadwear := UserHeadwear{} + if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{ + UserId: userId, + HeadwearId: headwearId, + }).First(&userHeadwear).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return &UserHeadwear{ + Model: model, + UserId: userId, + HeadwearId: headwearId, + EndTime: time.Now(), + }, nil + } else { + return nil, err + } + } + userHeadwear.Model = model + return &userHeadwear, nil +} + +//设置为使用中 +func (userHeadwear *UserHeadwear) SetUsing() (*UserHeadwear, error) { + if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil { + return nil, err + } + userHeadwear.Using = headwear_e.YesUsing + return userHeadwear, nil +} + +//增加结束时间 +func (userHeadwear *UserHeadwear) AddEndTime(t headwear_e.UserHeadwearLogOrginType, second uint32, operateUserId mysql.ID) (*UserHeadwear, mysql.ID, error) { + logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, t, headwear_e.AddSecond, &second, nil, operateUserId) + if err != nil { + return nil, 0, err + } + //if err := resetAllUserHeadwearNoUsing(userHeadwear.Model, userHeadwear.UserId); err != nil { + // return nil, logId, err + //} + nowTime := time.Now() + if userHeadwear.EndTime.After(nowTime) { + nowTime = userHeadwear.EndTime + } + userHeadwear.EndTime = nowTime.Add(time.Duration(second) * time.Second) + return userHeadwear, logId, nil +} + +//删除 +func (userHeadwear *UserHeadwear) MgrDel(mgrId mysql.ID) (*UserHeadwear, mysql.ID, error) { + logId, err := addUserHeadwearLog(userHeadwear.Model, userHeadwear.UserId, userHeadwear.HeadwearId, headwear_e.Mgr, headwear_e.Del, nil, nil, mgrId) + if err != nil { + return nil, 0, err + } + userHeadwear.SetDel() + return userHeadwear, logId, nil +} + +//重置所有的座驾均为不使用状态 +func resetAllUserHeadwearNoUsing(model *domain.Model, userId mysql.ID) error { + if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{ + UserId: userId, + }).UpdateColumn("using", headwear_e.NoUsing).Error; err != nil { + return err + } + return nil +} + +//用户装饰日志 +type UserHeadwearLog struct { + mysql.Entity + UserId mysql.ID + OperateUserId mysql.ID + HeadwearId mysql.ID + OriginType headwear_e.UserHeadwearLogOrginType + Type headwear_e.UserHeadwearLogType + AddSecond *mysql.Num + UpdateEndTime *time.Time +} + +//增加修改日志 +func addUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) { + userHeadwearLog := UserHeadwearLog{ + UserId: userId, + OperateUserId: operateUserId, + HeadwearId: headwearId, + OriginType: originType, + Type: t, + AddSecond: addSecond, + UpdateEndTime: UpdateEndTime, + } + if err := model.Db.Create(&userHeadwearLog).Error; err != nil { + return 0, err + } + return userHeadwearLog.ID, nil +} + +func GetUserHeadwearUsing(model *domain.Model, userId mysql.ID) (*UserHeadwear, error) { + userHeadwear := UserHeadwear{} + if err := model.Db.Model(&UserHeadwear{}).Where(&UserHeadwear{ + UserId: userId, + }).Where("end_time > ?", time.Now()).Order("`using` desc, updated_time desc").First(&userHeadwear).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } + userHeadwear.Model = model + return &userHeadwear, nil +} diff --git a/internal/model/user_m/medal.go b/internal/model/user_m/medal.go new file mode 100644 index 0000000000000000000000000000000000000000..5e135eac73948fef58993b04275c620a38dc9424 --- /dev/null +++ b/internal/model/user_m/medal.go @@ -0,0 +1,67 @@ +package user_m + +import ( + "context" + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mylogrus" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/resource/redisCli" + "git.hilo.cn/hilo-common/utils" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "time" +) + +//用户道具 +type UserMedal struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + MedalId uint32 + //MedalType res_m2.ResMedalType + //Scope res_m2.ResMedalScope + EndTime *time.Time +} + +func (um *UserMedal) Create(db *gorm.DB, day int) error { + err := db.Clauses(clause.OnConflict{ + DoUpdates: clause.Assignments(map[string]interface{}{ + "end_time": gorm.Expr("DATE_ADD(GREATEST(end_time,NOW()), INTERVAL ? DAY);", day)}), + }).Create(um).Error + // 删除勋章缓存, 延迟删除 + DelUserMedalMergeCacheDelay(um.UserId) + return err +} + +// 删除勋章缓存, 延迟删除 +func DelUserMedalMergeCacheDelay(userId mysql.ID) { + go func() { + defer utils.CheckGoPanic() + time.Sleep(time.Second * 5) + DelUserMedalMergeCache(userId) + }() +} +func DelUserMedalMergeCache(userId mysql.ID) error { + err := DelCache(getUserMedalMergeKey(userId)) + if err != nil { + mylogrus.MyLog.Errorf("DetUserMedalMerge err:%s, userId:%v", err, userId) + return err + } + return nil +} + +const userMedalMerge = "user:medalMerge:%d" // 勋章 + +func getUserMedalMergeKey(userId uint64) string { + return fmt.Sprintf(userMedalMerge, userId) +} + +func DelCache(key string) error { + err := redisCli.GetRedis().Del(context.Background(), key).Err() + if err != nil { + mylogrus.MyLog.Errorf("DelCache key:%s, err:%s", key, err) + return err + } + return nil +} diff --git a/internal/model/user_m/property.go b/internal/model/user_m/property.go new file mode 100644 index 0000000000000000000000000000000000000000..c8fbebe963ab04d396068493f226485c56bc7eb9 --- /dev/null +++ b/internal/model/user_m/property.go @@ -0,0 +1,110 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/property_e" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "time" +) + +//用户道具 +type UserProperty struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + PropertyId mysql.ID + EndTime time.Time + Using property_e.UserPropertyUsing +} + +func GetUserPropertyOrInit(model *domain.Model, userId mysql.ID, propertyId mysql.ID) (*UserProperty, error) { + userProperty := UserProperty{} + if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{ + UserId: userId, + PropertyId: propertyId, + }).First(&userProperty).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return &UserProperty{ + Model: model, + UserId: userId, + PropertyId: propertyId, + EndTime: time.Now(), + }, nil + } else { + return nil, err + } + } + userProperty.Model = model + return &userProperty, nil +} + +//设置为使用中 +func (userProperty *UserProperty) SetUsing() (*UserProperty, error) { + if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil { + return nil, err + } + userProperty.Using = property_e.YesUsing + return userProperty, nil +} + +//增加结束时间 +func (userProperty *UserProperty) AddEndTime(t property_e.UserPropertyLogOrginType, second uint32, operateUserId mysql.ID) (*UserProperty, mysql.ID, error) { + logId, err := addUserPropertyLog(userProperty.Model, userProperty.UserId, userProperty.PropertyId, t, property_e.AddSecond, &second, nil, operateUserId) + if err != nil { + return nil, 0, err + } + //if err := ResetAllUserPropertyNoUsing(userProperty.Model, userProperty.UserId); err != nil { + // return nil, logId, err + //} + nowTime := time.Now() + if userProperty.EndTime.After(nowTime) { + nowTime = userProperty.EndTime + } + userProperty.EndTime = nowTime.Add(time.Duration(second) * time.Second) + return userProperty, logId, nil +} + +//重置所有的座驾均为不使用状态 +func ResetAllUserPropertyNoUsing(model *domain.Model, userId mysql.ID) error { + if err := model.Db.Model(&UserProperty{}).Where(&UserProperty{ + UserId: userId, + }).UpdateColumn("using", property_e.NoUsing).Error; err != nil { + return err + } + return nil +} + +//增加修改日志 +func addUserPropertyLog(model *domain.Model, userId mysql.ID, propertyId mysql.ID, originType property_e.UserPropertyLogOrginType, t property_e.UserPropertyLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) { + userPropertyLog := UserPropertyLog{ + UserId: userId, + OperateUserId: operateUserId, + PropertyId: propertyId, + OriginType: originType, + Type: t, + AddSecond: addSecond, + UpdateEndTime: UpdateEndTime, + } + if err := model.Db.Create(&userPropertyLog).Error; err != nil { + return 0, err + } + return userPropertyLog.ID, nil +} + +func RemoveUserProperty(model *domain.Model, userId mysql.ID, propertyId mysql.ID) error { + return model.Db.Where("user_id = ? AND property_id = ?", userId, propertyId).Delete(&UserProperty{}).Error +} + +//用户道具日志 +type UserPropertyLog struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + OperateUserId mysql.ID + PropertyId mysql.ID + OriginType property_e.UserPropertyLogOrginType + Type property_e.UserPropertyLogType + AddSecond *mysql.Num + UpdateEndTime *time.Time +} \ No newline at end of file diff --git a/internal/model/user_m/repo.go b/internal/model/user_m/repo.go new file mode 100644 index 0000000000000000000000000000000000000000..1dbaf58e06e1dc924db09d22b508dd09bb98b7a4 --- /dev/null +++ b/internal/model/user_m/repo.go @@ -0,0 +1,17 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" +) + +func (userHeadwear *UserHeadwear) Persistent() error { + return domain.Persistent(userHeadwear.Db, userHeadwear) +} + +func (userProperty *UserProperty) Persistent() error { + return domain.Persistent(userProperty.Db, userProperty) +} + +func (userPropertyLog *UserPropertyLog) Persistent() error { + return domain.Persistent(userPropertyLog.Db, userPropertyLog) +} diff --git a/internal/model/user_m/user.go b/internal/model/user_m/user.go new file mode 100644 index 0000000000000000000000000000000000000000..95a979102d8982342b9265fd08d005e6ba993ce7 --- /dev/null +++ b/internal/model/user_m/user.go @@ -0,0 +1,41 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" +) + +//用户信息 +type User struct { + mysql.Entity + *domain.Model `gorm:"-"` + ExternalId mysql.Str + Avatar mysql.Str + DefaultAvatar bool + Nick mysql.Str + Sex mysql.Sex + Birthday mysql.Timestamp + Country mysql.Str + CountryIcon mysql.Str + Language mysql.Str + Description mysql.Str + Code mysql.Str + OriginCode mysql.Str + IsPush mysql.OpenClose + IsShowAge mysql.OpenClose + Status mysql.Type + DeviceType mysql.Str + LogoutTime int64 +} + +//获取用户 +func GetUser(model *domain.Model, id mysql.ID) (*User, error) { + var user User + if err := model.Db.WithContext(model.Context).Where(&User{ + Entity: mysql.Entity{ID: id}, + }).First(&user).Error; err != nil { + return nil, err + } + user.Model = model + return &user, nil +} diff --git a/script/group_power_rank.go b/script/group_power_rank.go new file mode 100644 index 0000000000000000000000000000000000000000..3b98a3c144eeeec76b4f863e53d59bc7e8e19c99 --- /dev/null +++ b/script/group_power_rank.go @@ -0,0 +1,122 @@ +package main + +import ( + "encoding/json" + "fmt" + "git.hilo.cn/hilo-common/script/model" + "git.hilo.cn/hilo-common/script/mysql" + "github.com/tealeg/xlsx" + "gorm.io/gorm" + "io/ioutil" + "net/http" +) + +type GroupPowerUser2 struct { + GroupPowerId uint64 + UserId uint64 + Role int +} + +type GroupPowerRankData struct { + Rank int // 家族排名 + Consume uint64 // 周流水 + Code string // 家族长ID + Country string // 家族长国家 + Svip int // 家族长SVIP等级 + MemNum int // 家族人数 +} + +func ats4(a interface{}) string { + return fmt.Sprintf("%d", a) +} + +func main() { + httpData := HttpGet() + var data []GroupPowerRankData + for i, r := range httpData { + admin := new(GroupPowerUser2) + if err := mysql.ProdReadOnlyDB.Table("group_power_user").Where("group_power_id = ? AND role = 2", r.GroupPowerId).First(admin).Error; err != nil { + panic(err) + } + adminUser := new(model.User) + if err := mysql.ProdReadOnlyDB.Table("user").Where("id = ?", admin.UserId).First(adminUser).Error; err != nil { + panic(err) + } + svip := 0 + userSvip := new(model.UserSvip) + if err := mysql.ProdReadOnlyDB.Table("user_svip").Where("user_id = ?", admin.UserId).First(&userSvip).Error; err != nil { + if err != gorm.ErrRecordNotFound { + panic(err) + } + } else { + svip = userSvip.Level + } + data = append(data, GroupPowerRankData{ + Rank: i + 1, + Consume: r.DiamondNum, + Code: adminUser.Code, + Country: adminUser.Country, + Svip: svip, + MemNum: r.UserN, + }) + } + excelFileName := fmt.Sprintf("./家族这周流水.xlsx") + xlFile := xlsx.NewFile() + sheet, _ := xlFile.AddSheet("charge") + row := sheet.AddRow() + c1, c2, c3, c4, c5, c6 := row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell() + c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value = + "上周家族排名", "周流水", "家族长ID", "家族长国家", "家族长SVIP", "家族人数" + for _, d := range data { + row := sheet.AddRow() + c1, c2, c3, c4, c5, c6 := row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell(), row.AddCell() + c1.Value, c2.Value, c3.Value, c4.Value, c5.Value, c6.Value = + ats4(d.Rank), ats4(d.Consume), d.Code, d.Country, ats4(d.Svip), ats4(d.MemNum) + } + _ = xlFile.Save(excelFileName) +} + +type Data struct { + GroupPowerId uint64 `json:"groupPowerId"` + DiamondNum uint64 `json:"diamondNum"` + UserN int `json:"userN"` +} + +type Response struct { + Data []Data +} + +func HttpGet() []Data { + var result []Data + url := "https://apiv1.faceline.live/v1/groupPower/billboard/week?type=2&pageIndex=1&pageSize=1000" + method := "GET" + + client := &http.Client{} + req, err := http.NewRequest(method, url, nil) + + if err != nil { + fmt.Println(err) + return result + } + req.Header.Add("token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjQ0NzA0OTEsIkV4dGVybmFsSWQiOiJjZDE5NmRjNDc1NTM0MWMzOWQwZmUyODdjMjc0NWJlMiIsImV4cCI6MTY4MTIyMjcwNSwiaXNzIjoiaGlsb0FwaSJ9.emZc2kTDMpZaqdHVWiF1cFOAfAd0nT3yCSwFw8U_fXA") + req.Header.Add("nonce", "hilo") + + res, err := client.Do(req) + if err != nil { + fmt.Println(err) + return result + } + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + fmt.Println(err) + return result + } + r := new(Response) + err = json.Unmarshal(body, r) + if err != nil { + panic(err) + } + return r.Data +} diff --git a/script/model/user.go b/script/model/user.go index ad961e1f76b9e57d197b423c8ef11892312735bb..68cd9377e6e3e5b30adb088efdc9870cc8f1206b 100644 --- a/script/model/user.go +++ b/script/model/user.go @@ -48,3 +48,8 @@ type UserNoId struct { func (UserNoId) TableName() string { return "user" } + +type UserSvip struct { + UserId uint64 + Level int +} diff --git a/txop/diamond_tx/diamond.go b/txop/diamond_tx/diamond.go new file mode 100644 index 0000000000000000000000000000000000000000..e9f40d812482466c5a2ad1f4c63df88e40807467 --- /dev/null +++ b/txop/diamond_tx/diamond.go @@ -0,0 +1,24 @@ +package diamond_tx + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/diamond_e" + "git.hilo.cn/hilo-common/internal/model/diamond_m" + "git.hilo.cn/hilo-common/resource/mysql" +) + +// 下发钻石 +func SendDiamond(model *domain.Model, userId mysql.ID, opt diamond_e.OperateType, originId mysql.ID, diamondNum mysql.Num) error { + diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, userId) + if err != nil { + return err + } + diamondSendAccountDetail, err := diamondAccount.AddDiamondAccountDetail(opt, originId, diamondNum) + if err != nil { + return err + } + if err := diamondSendAccountDetail.Persistent(); err != nil { + return err + } + return nil +} diff --git a/txop/headwear_tx/headwear.go b/txop/headwear_tx/headwear.go new file mode 100644 index 0000000000000000000000000000000000000000..951a41858f418b40a4e084fcf20f47af9daa1b1c --- /dev/null +++ b/txop/headwear_tx/headwear.go @@ -0,0 +1,53 @@ +package headwear_tx + +import ( + "errors" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/headwear_e" + "git.hilo.cn/hilo-common/internal/model/user_m" + "git.hilo.cn/hilo-common/resource/mysql" + "time" +) + +// 下发头饰 +func SendHeadwear(model *domain.Model, receiverUserId mysql.ID, headdressId mysql.ID, days int) error { + // 头饰增加 + receiveHeadwearDuration := uint32(days) * 3600 * 24 + if headdressId <= 0 { + return errors.New("headdressId is 0") + } + userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, headdressId) + if err != nil { + return err + } + nowTime := time.Now() + if userHeadwear.EndTime.After(nowTime) { + nowTime = userHeadwear.EndTime + } + userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second) + if err := userHeadwear.Persistent(); err != nil { + return err + } + //日志错误,并不事务回调 + if _, err = AddUserHeadwearLog(model, receiverUserId, headdressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil { + model.Log.Error(err) + } + return err +} + +//增加修改日志 +func AddUserHeadwearLog(model *domain.Model, userId mysql.ID, headwearId mysql.ID, originType headwear_e.UserHeadwearLogOrginType, t headwear_e.UserHeadwearLogType, addSecond *uint32, UpdateEndTime *time.Time, operateUserId mysql.ID) (mysql.ID, error) { + userHeadwearLog := user_m.UserHeadwearLog{ + UserId: userId, + OperateUserId: operateUserId, + HeadwearId: headwearId, + OriginType: originType, + Type: t, + AddSecond: addSecond, + UpdateEndTime: UpdateEndTime, + } + if err := model.Db.Create(&userHeadwearLog).Error; err != nil { + return 0, err + } + return userHeadwearLog.ID, nil +} diff --git a/txop/medal_tx/medal.go b/txop/medal_tx/medal.go new file mode 100644 index 0000000000000000000000000000000000000000..bd70c6d5fc7f38e51d113c04ed5c403080b71149 --- /dev/null +++ b/txop/medal_tx/medal.go @@ -0,0 +1,21 @@ +package medal_tx + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/model/user_m" + "git.hilo.cn/hilo-common/resource/mysql" + "time" +) + +func SendMedal(model *domain.Model, userId, medalId mysql.ID, day int) error { + endTime := time.Now().AddDate(0, 0, day) + um := user_m.UserMedal{ + UserId: userId, + MedalId: uint32(medalId), + EndTime: &endTime, + } + if err := um.Create(model.Db, day); err != nil { + return err + } + return nil +} diff --git a/txop/noble_tx/noble.go b/txop/noble_tx/noble.go new file mode 100644 index 0000000000000000000000000000000000000000..4670ba7c97b62a0180c0f33dbc88cb8cf8c29ca5 --- /dev/null +++ b/txop/noble_tx/noble.go @@ -0,0 +1,155 @@ +package noble_tx + +import ( + "fmt" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/headwear_e" + "git.hilo.cn/hilo-common/internal/enum/msg_e" + "git.hilo.cn/hilo-common/internal/enum/property_e" + "git.hilo.cn/hilo-common/internal/model/msg_m" + "git.hilo.cn/hilo-common/internal/model/noble_m" + "git.hilo.cn/hilo-common/internal/model/user_m" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/txop/headwear_tx" + "strconv" + "time" +) + +// 下发贵族 +func SendNoble(model *domain.Model, receiverUserId mysql.ID, level uint16, days int) error { + if level <= 0 { + return fmt.Errorf("level is 0") + } + + cfg, err := noble_m.GetConfigByLevel(model.Db, level) + if err != nil { + return err + } + if cfg.PurchasePrice <= 0 || cfg.RenewalPrice <= 0 { + return fmt.Errorf("level is 0") + } + n := noble_m.UserNoble{UserId: receiverUserId, Level: level} + records, err := n.FindAll(model.Db) + if err != nil { + return err + } + if len(records) > 1 { + // DB表结构决定了不可能发生 + return fmt.Errorf("bizerr.IncorrectState") + } + + if len(records) <= 0 { + // 新增贵族 + endTime := time.Now().AddDate(0, 0, int(days)) + n = noble_m.UserNoble{UserId: receiverUserId, Level: level, EndTime: endTime} + err = n.Create(model.Db) + if err != nil { + return err + } + + nbl := noble_m.UserNobleLog{ + SenderId: 0, + ReceiverId: receiverUserId, + Level: level, + Money: 0, + SrcType: noble_m.SRC_APP, + NewEndTime: endTime, + } + err = nbl.Create(model.Db) + if err != nil { + return err + } + } else { + // 延长贵族 + n = records[0] + now := time.Now() + endTime := n.EndTime.AddDate(0, 0, int(days)) + if now.After(n.EndTime) { + endTime = now.AddDate(0, 0, int(days)) + } + nn := noble_m.UserNoble{ + Entity: mysql.Entity{ID: n.ID, UpdatedTime: n.UpdatedTime}, + } + + af, err := nn.UpdateEndTime(model.Db, endTime) + if err != nil { + return err + } + if af <= 0 { + return fmt.Errorf("bizerr.TransactionFailed") + } + + nbl := noble_m.UserNobleLog{ + SenderId: 0, + ReceiverId: receiverUserId, + Level: level, + Money: 0, + SrcType: noble_m.SRC_APP, + OldEndTime: n.EndTime, + NewEndTime: endTime, + } + err = nbl.Create(model.Db) + if err != nil { + return err + } + } + // 头饰增加 + receiveHeadwearDuration := uint32(days) * 3600 * 24 + if cfg.HeaddressId != 0 { + userHeadwear, err := user_m.GetUserHeadwearOrInit(model, receiverUserId, cfg.HeaddressId) + if err != nil { + return err + } + nowTime := time.Now() + if userHeadwear.EndTime.After(nowTime) { + nowTime = userHeadwear.EndTime + } + userHeadwear.EndTime = nowTime.Add(time.Duration(receiveHeadwearDuration) * time.Second) + if err := userHeadwear.Persistent(); err != nil { + return err + } + //日志错误,并不事务回调 + if _, err := headwear_tx.AddUserHeadwearLog(model, receiverUserId, cfg.HeaddressId, headwear_e.ActivityTrigger, headwear_e.AddSecond, &receiveHeadwearDuration, nil, 0); err != nil { + model.Log.Error(err) + } + } + // 增加座驾 + receivePropertyDuration := uint32(days) * 3600 * 24 + if cfg.RideId != 0 { + userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, cfg.RideId) + if err != nil { + return err + } + nowTime := time.Now() + if userProperty.EndTime.After(nowTime) { + nowTime = userProperty.EndTime + } + userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second) + if err := userProperty.Persistent(); err != nil { + return err + } + //日志错误,并不事务回调 + if err := (&user_m.UserPropertyLog{ + Model: model, + UserId: receiverUserId, + PropertyId: cfg.RideId, + OriginType: property_e.ActivityBillboardTrigger, + Type: property_e.AddSecond, + AddSecond: &receivePropertyDuration, + UpdateEndTime: nil, + }).Persistent(); err != nil { + model.Log.Error(err) + } + } + // 推送 + user, err := user_m.GetUser(model, receiverUserId) + if err != nil { + return err + } + nobleDuration := days * 3600 * 24 + if err := msg_m.NewUserRecord(model, user.ID, msg_e.AddNoble, user.Nick, user.ID, "", strconv.Itoa(int(nobleDuration)/(24*3600)), "", "", "").Persistent(); err != nil { + return err + } + msg_m.SendEmasMsgAssistant(model, user.ExternalId, user.DeviceType) + return nil +} diff --git a/txop/ride_tx/ride.go b/txop/ride_tx/ride.go new file mode 100644 index 0000000000000000000000000000000000000000..df1ebd4e65c107b9557fa329f2846e558d1e271d --- /dev/null +++ b/txop/ride_tx/ride.go @@ -0,0 +1,40 @@ +package ride_tx + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/internal/enum/property_e" + "git.hilo.cn/hilo-common/internal/model/user_m" + "git.hilo.cn/hilo-common/resource/mysql" + "time" +) + +// 下发座驾 +func SendRide(model *domain.Model, receiverUserId mysql.ID, rideId mysql.ID, days int) error { + // 增加座驾 + receivePropertyDuration := uint32(days) * 3600 * 24 + userProperty, err := user_m.GetUserPropertyOrInit(model, receiverUserId, rideId) + if err != nil { + return err + } + nowTime := time.Now() + if userProperty.EndTime.After(nowTime) { + nowTime = userProperty.EndTime + } + userProperty.EndTime = nowTime.Add(time.Duration(receivePropertyDuration) * time.Second) + if err := userProperty.Persistent(); err != nil { + return err + } + //日志错误,并不事务回调 + if err := (&user_m.UserPropertyLog{ + Model: model, + UserId: receiverUserId, + PropertyId: rideId, + OriginType: property_e.ActivityBillboardTrigger, + Type: property_e.AddSecond, + AddSecond: &receivePropertyDuration, + UpdateEndTime: nil, + }).Persistent(); err != nil { + model.Log.Error(err) + } + return nil +}