Commit 3aa88c95 authored by hujiebin's avatar hujiebin

feat:增加tx操作

parent ddc1a92e
...@@ -17,5 +17,10 @@ ...@@ -17,5 +17,10 @@
+ rpc: rpc请求 + rpc: rpc请求
+ const.go: 常量 + const.go: 常量
+ http.go: 封装http相关 + http.go: 封装http相关
+ internal
+ 内部用的结构体,避免和上游的冲突
+ txop: 需事务操作的行为
+ 例如 下发钻石/勋章/座驾等
+ 支持捆绑上述操作,用于替换rpc发奖品
+ utils: 工具包 + utils: 工具包
+ script: 临时脚本 + script: 临时脚本
package domain package domain
import ( import (
"fmt"
"git.hilo.cn/hilo-common/mycontext" "git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/resource/mysql"
"git.hilo.cn/hilo-common/resource/redisCli" "git.hilo.cn/hilo-common/resource/redisCli"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
) )
type Model struct { type Model struct {
...@@ -53,3 +56,72 @@ func (m *Model) Transaction(f func(*Model) error) error { ...@@ -53,3 +56,72 @@ func (m *Model) Transaction(f func(*Model) error) error {
} }
return txModel.Db.Commit().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
}
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
)
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
)
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
)
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
)
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)
}
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
}
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
}
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())
}
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
}
}
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
}
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)
}
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
}
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
}
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
}
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
}
}
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
}
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
}
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
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)
}
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
}
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
}
...@@ -48,3 +48,8 @@ type UserNoId struct { ...@@ -48,3 +48,8 @@ type UserNoId struct {
func (UserNoId) TableName() string { func (UserNoId) TableName() string {
return "user" return "user"
} }
type UserSvip struct {
UserId uint64
Level int
}
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
}
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
}
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
}
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
}
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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment