@@ -17,9 +17,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||||
var data = &model.DayLuckDrawOrderJackpot{ | var data = &model.DayLuckDrawOrderJackpot{ | ||||
Oid: req.Oid, | Oid: req.Oid, | ||||
Pvd: req.Pvd, | Pvd: req.Pvd, | ||||
Amount: req.Amount, | |||||
Commission: req.Commission, | |||||
Reward: req.Reward, | |||||
Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), | Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), | ||||
CreateTime: time.Now(), | CreateTime: time.Now(), | ||||
} | } | ||||
@@ -33,18 +30,6 @@ func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||||
return nil | return nil | ||||
} | } | ||||
/*** | |||||
1.创建期数 | |||||
2.获取还没分配的金额 就是 期数为0的 | |||||
3.把期数设置到订单 | |||||
4.查出所有订单号 | |||||
5.随机出订单号(每个名额随机一次 如果重复再次循环) 先按一等奖分 | |||||
*/ | |||||
func GetAllOrderSum(sess *xorm.Session) float64 { | |||||
sum, _ := sess.Where("period=0").Sum(&model.DayLuckDrawOrderJackpot{}, "reward") | |||||
return sum | |||||
} | |||||
func GetAllOrderOid(sess *xorm.Session) []string { | func GetAllOrderOid(sess *xorm.Session) []string { | ||||
sql := `SELECT oid,uid FROM day_luck_draw_order_jackpot where period=0;` | sql := `SELECT oid,uid FROM day_luck_draw_order_jackpot where period=0;` | ||||
data, _ := QueryNativeStringSess(sess, sql) | data, _ := QueryNativeStringSess(sess, sql) | ||||
@@ -8,11 +8,12 @@ import ( | |||||
"xorm.io/xorm" | "xorm.io/xorm" | ||||
) | ) | ||||
func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq) bool { | |||||
func AddPeriod(sess *xorm.Session, req md.DayLuckDrawPeriodReq, base string) bool { | |||||
var data = &model.DayLuckDrawPeriod{ | var data = &model.DayLuckDrawPeriod{ | ||||
Reward: req.Reward, | Reward: req.Reward, | ||||
CreateTime: time.Now(), | CreateTime: time.Now(), | ||||
Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | ||||
Base: base, | |||||
} | } | ||||
insert, err := sess.Insert(data) | insert, err := sess.Insert(data) | ||||
if insert == 0 || err != nil { | if insert == 0 || err != nil { | ||||
@@ -9,8 +9,8 @@ import ( | |||||
"xorm.io/xorm" | "xorm.io/xorm" | ||||
) | ) | ||||
func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { | |||||
count, _ := eg.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) | |||||
func AddPeriodReward(sess *xorm.Session, req md.DayLuckDrawRewardReq) error { | |||||
count, _ := sess.Where("uid=? and period=?", req.Uid, req.Period).Count(&model.DayLuckDrawPeriodReward{}) | |||||
if count > 0 { | if count > 0 { | ||||
return nil | return nil | ||||
} | } | ||||
@@ -21,7 +21,7 @@ func AddPeriodReward(eg *xorm.Engine, req md.DayLuckDrawRewardReq) error { | |||||
Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | Period: zhios_day_luck_draw_utils.StrToInt(req.Period), | ||||
Lv: zhios_day_luck_draw_utils.StrToInt(req.Lv), | Lv: zhios_day_luck_draw_utils.StrToInt(req.Lv), | ||||
} | } | ||||
one, err := eg.InsertOne(data) | |||||
one, err := sess.Insert(data) | |||||
if one == 0 { | if one == 0 { | ||||
return errors.New("失败") | return errors.New("失败") | ||||
} | } | ||||
@@ -2,6 +2,8 @@ package db | |||||
import ( | import ( | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | ||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||||
"time" | |||||
"xorm.io/xorm" | "xorm.io/xorm" | ||||
) | ) | ||||
@@ -19,6 +21,23 @@ func GetDayLuckDrawSetting(eg *xorm.Engine) *model.DayLuckDrawSetting { | |||||
} | } | ||||
return &data | return &data | ||||
} | } | ||||
func CheckSetting(eg *xorm.Engine, pvd string) bool { | |||||
setting := GetDayLuckDrawSetting(eg) | |||||
if setting == nil { | |||||
return false | |||||
} | |||||
now := time.Now().Unix() | |||||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||||
return false | |||||
} | |||||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||||
return false | |||||
} | |||||
if setting.OrderSoruce == "mall" && pvd != "" && zhios_day_luck_draw_utils.InArr(pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { | |||||
return false | |||||
} | |||||
return true | |||||
} | |||||
func GetDayLuckDrawSettingSess(sess *xorm.Session) *model.DayLuckDrawSetting { | func GetDayLuckDrawSettingSess(sess *xorm.Session) *model.DayLuckDrawSetting { | ||||
var data model.DayLuckDrawSetting | var data model.DayLuckDrawSetting | ||||
get, err := sess.Get(&data) | get, err := sess.Get(&data) | ||||
@@ -0,0 +1,38 @@ | |||||
package db | |||||
import ( | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||||
"errors" | |||||
"time" | |||||
"xorm.io/xorm" | |||||
) | |||||
func GetSettleAllOrderSum(sess *xorm.Session) float64 { | |||||
sum, _ := sess.Where("is_send=0").Sum(&model.DayLuckDrawSettleOrder{}, "commission") | |||||
return sum | |||||
} | |||||
func AddSettle(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||||
count, _ := eg.Where("oid=? and uid=? and pvd=?", req.Oid, req.Uid, req.Pvd).Count(&model.DayLuckDrawSettleOrder{}) | |||||
if count > 0 { | |||||
return nil | |||||
} | |||||
var data = &model.DayLuckDrawSettleOrder{ | |||||
Oid: req.Oid, | |||||
Pvd: req.Pvd, | |||||
Amount: req.Amount, | |||||
Commission: req.Commission, | |||||
Uid: zhios_day_luck_draw_utils.StrToInt(req.Uid), | |||||
CreateTime: time.Now(), | |||||
} | |||||
one, err := eg.InsertOne(data) | |||||
if one == 0 { | |||||
return errors.New("失败") | |||||
} | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return nil | |||||
} |
@@ -14,3 +14,12 @@ func UserFindByMobile(Db *xorm.Engine, mobile string) (*model.User, error) { | |||||
} | } | ||||
return &m, nil | return &m, nil | ||||
} | } | ||||
func UserProfileFindByIDWithSession(sess *xorm.Session, id interface{}) (*model.UserProfile, error) { | |||||
var m model.UserProfile | |||||
if has, err := sess.Where("uid = ?", id). | |||||
Get(&m); err != nil || has == false { | |||||
return nil, err | |||||
} | |||||
return &m, nil | |||||
} |
@@ -8,9 +8,6 @@ type DayLuckDrawOrderJackpot struct { | |||||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | ||||
Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` | Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` | ||||
Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` | Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` | ||||
Amount string `json:"amount" xorm:"DECIMAL(11,6)"` | |||||
Commission string `json:"commission" xorm:"DECIMAL(11,6)"` | |||||
Reward string `json:"reward" xorm:"DECIMAL(11,6)"` | |||||
Uid int `json:"uid" xorm:"index INT(11)"` | Uid int `json:"uid" xorm:"index INT(11)"` | ||||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | ||||
Period int `json:"period" xorm:"default 0 INT(11)"` | Period int `json:"period" xorm:"default 0 INT(11)"` | ||||
@@ -7,6 +7,7 @@ import ( | |||||
type DayLuckDrawPeriod struct { | type DayLuckDrawPeriod struct { | ||||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | ||||
Reward string `json:"reward" xorm:"VARCHAR(255)"` | Reward string `json:"reward" xorm:"VARCHAR(255)"` | ||||
Base string `json:"base" xorm:"TEXT"` | |||||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | ||||
Period int `json:"period" xorm:"default 0 INT(11)"` | Period int `json:"period" xorm:"default 0 INT(11)"` | ||||
} | } |
@@ -0,0 +1,16 @@ | |||||
package model | |||||
import ( | |||||
"time" | |||||
) | |||||
type DayLuckDrawSettleOrder struct { | |||||
Id int `json:"id" xorm:"not null pk autoincr INT(11)"` | |||||
Oid string `json:"oid" xorm:"index unique(oid_pvd) VARCHAR(255)"` | |||||
Pvd string `json:"pvd" xorm:"unique(oid_pvd) index VARCHAR(255)"` | |||||
Amount string `json:"amount" xorm:"DECIMAL(11,6)"` | |||||
Commission string `json:"commission" xorm:"DECIMAL(11,6)"` | |||||
Uid int `json:"uid" xorm:"index INT(11)"` | |||||
CreateTime time.Time `json:"create_time" xorm:"DATETIME"` | |||||
IsSend int `json:"is_send" xorm:"default 0 INT(11)"` | |||||
} |
@@ -0,0 +1,29 @@ | |||||
package model | |||||
import ( | |||||
"time" | |||||
) | |||||
type FinUserFlow struct { | |||||
Id int64 `json:"id" xorm:"pk autoincr comment('流水编号') BIGINT(20)"` | |||||
Uid int `json:"uid" xorm:"not null default 0 comment('用户id') INT(11)"` | |||||
Type int `json:"type" xorm:"not null default 0 comment('0收入,1支出') TINYINT(1)"` | |||||
Amount string `json:"amount" xorm:"not null default 0.0000 comment('变动金额') DECIMAL(11,4)"` | |||||
BeforeAmount string `json:"before_amount" xorm:"not null default 0.0000 comment('变动前金额') DECIMAL(11,4)"` | |||||
AfterAmount string `json:"after_amount" xorm:"not null default 0.0000 comment('变动后金额') DECIMAL(11,4)"` | |||||
SysFee string `json:"sys_fee" xorm:"not null default 0.0000 comment('手续费') DECIMAL(11,4)"` | |||||
PaymentType int `json:"payment_type" xorm:"not null default 1 comment('1支付宝,2微信.3手动转账') TINYINT(1)"` | |||||
OrdType string `json:"ord_type" xorm:"not null default '' comment('订单类型taobao,jd,pdd,vip,suning,kaola,own自营,withdraw提现') VARCHAR(20)"` | |||||
OrdId string `json:"ord_id" xorm:"not null default '' comment('对应订单编号') VARCHAR(50)"` | |||||
OrdTitle string `json:"ord_title" xorm:"not null default '' comment('订单标题') VARCHAR(50)"` | |||||
OrdAction int `json:"ord_action" xorm:"not null default 0 comment('10自购,11推广,12团队,20提现,21消费') TINYINT(2)"` | |||||
OrdTime int `json:"ord_time" xorm:"not null default 0 comment('下单时间or提现时间') INT(11)"` | |||||
OrdDetail string `json:"ord_detail" xorm:"not null default '' comment('记录商品ID或提现账号') VARCHAR(50)"` | |||||
ExpectedTime string `json:"expected_time" xorm:"not null default '0' comment('预期到账时间,字符串用于直接显示,结算后清除内容') VARCHAR(30)"` | |||||
State int `json:"state" xorm:"not null default 1 comment('1未到账,2已到账') TINYINT(1)"` | |||||
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(2000)"` | |||||
OtherId int64 `json:"other_id" xorm:"not null default 0 comment('其他关联订单,具体根据订单类型判断') BIGINT(20)"` | |||||
AliOrdId string `json:"ali_ord_id" xorm:"default '' comment('支付宝订单号') VARCHAR(128)"` | |||||
CreateAt time.Time `json:"create_at" xorm:"created not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"` | |||||
UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` | |||||
} |
@@ -0,0 +1,91 @@ | |||||
package model | |||||
import ( | |||||
"time" | |||||
) | |||||
type UserProfile struct { | |||||
Uid int `json:"uid" xorm:"not null pk comment('关联userID') INT(20)"` | |||||
ArkidUid int `json:"arkid_uid" xorm:"not null default 0 comment('Arkid 用户ID') INT(20)"` | |||||
ParentUid int `json:"parent_uid" xorm:"not null default 0 comment('上级ID') INT(20)"` | |||||
ArkidToken string `json:"arkid_token" xorm:"not null default '' comment('token') VARCHAR(2000)"` | |||||
AvatarUrl string `json:"avatar_url" xorm:"not null default '' comment('头像URL') VARCHAR(2000)"` | |||||
CustomInviteCode string `json:"custom_invite_code" xorm:"not null default '' comment('邀请码(自定义)') VARCHAR(16)"` | |||||
InviteCode string `json:"invite_code" xorm:"not null default '' comment('邀请码(系统)') VARCHAR(16)"` | |||||
Gender int `json:"gender" xorm:"not null default 2 comment('性别0女,1男,2未知') TINYINT(1)"` | |||||
Birthday int `json:"birthday" xorm:"not null default 0 comment('出生日期') INT(10)"` | |||||
AccWxId string `json:"acc_wx_id" xorm:"not null default '' comment('账户_微信id') VARCHAR(50)"` | |||||
AccWxOpenid string `json:"acc_wx_openid" xorm:"not null default '' comment('账户_微信openid') VARCHAR(80)"` | |||||
AccTaobaoNickname string `json:"acc_taobao_nickname" xorm:"not null default '' comment('淘宝昵称') VARCHAR(50)"` | |||||
AccTaobaoAuthTime int64 `json:"acc_taobao_auth_time" xorm:"not null default 0 comment('淘宝授权备案时间') BIGINT(11)"` | |||||
AccTaobaoShareId int64 `json:"acc_taobao_share_id" xorm:"not null default 0 comment('淘宝分享relationId,') index BIGINT(12)"` | |||||
AccTaobaoSelfId int64 `json:"acc_taobao_self_id" xorm:"not null default 0 comment('淘宝自购specialId') index BIGINT(12)"` | |||||
AccJdSelfId string `json:"acc_jd_self_id" xorm:"not null default '' comment('京东自购ID') index VARCHAR(50)"` | |||||
AccJdShareId string `json:"acc_jd_share_id" xorm:"not null default '' comment('京东分享ID') index VARCHAR(50)"` | |||||
AccJdFreeId string `json:"acc_jd_free_id" xorm:"not null default '' comment('京东新人免单ID') VARCHAR(50)"` | |||||
AccSuningSelfId string `json:"acc_suning_self_id" xorm:"not null default '' comment('苏宁自购ID') index VARCHAR(50)"` | |||||
AccSuningShareId string `json:"acc_suning_share_id" xorm:"not null default '' comment('苏宁分享ID') index VARCHAR(50)"` | |||||
AccSuningFreeId string `json:"acc_suning_free_id" xorm:"not null default '' comment('苏宁新人免单ID') VARCHAR(50)"` | |||||
AccPddSelfId string `json:"acc_pdd_self_id" xorm:"not null default '' comment('拼多多自购ID') index VARCHAR(50)"` | |||||
AccPddShareId string `json:"acc_pdd_share_id" xorm:"not null default '' comment('拼多多分享ID') index VARCHAR(50)"` | |||||
AccPddFreeId string `json:"acc_pdd_free_id" xorm:"not null default '' comment('拼多多新人免单ID') VARCHAR(50)"` | |||||
AccPddBind int `json:"acc_pdd_bind" xorm:"not null default 0 comment('拼多多是否授权绑定') TINYINT(1)"` | |||||
AccVipSelfId string `json:"acc_vip_self_id" xorm:"not null default '' comment('唯品会自购ID') index VARCHAR(50)"` | |||||
AccVipShareId string `json:"acc_vip_share_id" xorm:"not null default '' comment('唯品会分享ID') index VARCHAR(50)"` | |||||
AccVipFreeId string `json:"acc_vip_free_id" xorm:"not null default '' comment('唯品会新人免单ID') VARCHAR(50)"` | |||||
AccKaolaSelfId string `json:"acc_kaola_self_id" xorm:"not null default '' comment('考拉自购ID') index VARCHAR(50)"` | |||||
AccKaolaShareId string `json:"acc_kaola_share_id" xorm:"not null default '' comment('考拉分享ID') index VARCHAR(50)"` | |||||
AccKaolaFreeId string `json:"acc_kaola_free_id" xorm:"not null default '' comment('考拉新人免单ID') VARCHAR(50)"` | |||||
AccDuomaiShareId int64 `json:"acc_duomai_share_id" xorm:"not null pk default 0 comment('多麦联盟分享ID') BIGINT(12)"` | |||||
AccAlipay string `json:"acc_alipay" xorm:"not null default '' comment('支付宝账号') VARCHAR(50)"` | |||||
AccAlipayRealName string `json:"acc_alipay_real_name" xorm:"not null default '' comment('支付宝账号真实姓名') VARCHAR(50)"` | |||||
CertTime int `json:"cert_time" xorm:"not null default 0 comment('认证时间') INT(10)"` | |||||
CertName string `json:"cert_name" xorm:"not null default '' comment('证件上名字,也是真实姓名') VARCHAR(50)"` | |||||
CertNum string `json:"cert_num" xorm:"not null default '' comment('证件号码') VARCHAR(50)"` | |||||
CertState int `json:"cert_state" xorm:"not null default 0 comment('认证状态(0为未认证,1为认证中,2为已认证,3为认证失败)') TINYINT(1)"` | |||||
FinCommission string `json:"fin_commission" xorm:"not null default 0.0000 comment('累计佣金') DECIMAL(10,4)"` | |||||
FinValid string `json:"fin_valid" xorm:"not null default 0.0000 comment('可用余额,fin=>finance财务') DECIMAL(10,4)"` | |||||
FinInvalid string `json:"fin_invalid" xorm:"not null default 0.0000 comment('不可用余额,冻结余额') DECIMAL(10,4)"` | |||||
FinSelfOrderCount int `json:"fin_self_order_count" xorm:"not null default 0 comment('自购订单数,包括未完成') INT(11)"` | |||||
FinSelfOrderCountDone int `json:"fin_self_order_count_done" xorm:"not null default 0 comment('自购已完成订单') INT(11)"` | |||||
FinSelfRebate float32 `json:"fin_self_rebate" xorm:"not null default 0.000000 comment('累积自购获得返利金额') FLOAT(14,6)"` | |||||
FinTotal float32 `json:"fin_total" xorm:"not null default 0.000000 comment('累计总收益') FLOAT(14,6)"` | |||||
Lat float32 `json:"lat" xorm:"not null default 0.000000 comment('纬度') FLOAT(15,6)"` | |||||
Lng float32 `json:"lng" xorm:"not null default 0.000000 comment('经度') FLOAT(15,6)"` | |||||
Memo string `json:"memo" xorm:"not null default '' comment('用户简述备注') VARCHAR(2048)"` | |||||
IsNew int `json:"is_new" xorm:"not null default 1 comment('是否是新用户') TINYINT(1)"` | |||||
IsVerify int `json:"is_verify" xorm:"not null default 0 comment('是否有效会员') TINYINT(1)"` | |||||
IsOrdered int `json:"is_ordered" xorm:"not null default 0 comment('是否已完成首单(0否,1是)') TINYINT(1)"` | |||||
FromWay string `json:"from_way" xorm:"not null default '' comment('注册来源: | |||||
no_captcha_phone:免验证码手机号注册; | |||||
manual_phone:手动手机验证码注册; | |||||
wx:微信授权; | |||||
wx_mp:小程序授权; | |||||
wx_pub:公众号授权; | |||||
wx_bind_phone:微信注册绑定手机号; | |||||
admin:管理员添加;taobao_bind_phone:淘宝注册绑定手机号,apple_bind_phone:苹果注册绑定手机号') VARCHAR(16)"` | |||||
HidOrder int `json:"hid_order" xorm:"not null default 0 comment('隐藏订单') TINYINT(3)"` | |||||
HidContact int `json:"hid_contact" xorm:"not null default 0 comment('隐藏联系方式') TINYINT(4)"` | |||||
NewMsgNotice int `json:"new_msg_notice" xorm:"not null default 1 comment('新消息通知') TINYINT(1)"` | |||||
WxAccount string `json:"wx_account" xorm:"not null default '' comment('微信号') VARCHAR(100)"` | |||||
WxQrcode string `json:"wx_qrcode" xorm:"not null default '' comment('微信二维码') VARCHAR(100)"` | |||||
ThirdPartyTaobaoOid string `json:"third_party_taobao_oid" xorm:"not null default '' comment('淘宝第三方登录openID') VARCHAR(100)"` | |||||
ThirdPartyTaobaoSid string `json:"third_party_taobao_sid" xorm:"not null default '' comment('淘宝第三方登录sID') VARCHAR(255)"` | |||||
ThirdPartyTaobaoAcctoken string `json:"third_party_taobao_acctoken" xorm:"not null default '' comment('淘宝第三方登录topaccesstoken') VARCHAR(100)"` | |||||
ThirdPartyTaobaoAuthcode string `json:"third_party_taobao_authcode" xorm:"not null default '' comment('淘宝第三方登录topAuthCode') VARCHAR(100)"` | |||||
ThirdPartyAppleToken string `json:"third_party_apple_token" xorm:"not null default '' comment('苹果第三方登录token') VARCHAR(1024)"` | |||||
ThirdPartyQqAccessToken string `json:"third_party_qq_access_token" xorm:"not null default '' comment('QQ第三方登录access_token') VARCHAR(255)"` | |||||
ThirdPartyQqExpiresIn string `json:"third_party_qq_expires_in" xorm:"not null default '' comment('QQ第三方登录expires_in(剩余时长)') VARCHAR(255)"` | |||||
ThirdPartyQqOpenid string `json:"third_party_qq_openid" xorm:"not null default '' comment('QQ第三方登陆openid(不变,用于认证)') VARCHAR(255)"` | |||||
ThirdPartyQqUnionid string `json:"third_party_qq_unionid" xorm:"not null default '' comment('QQ第三方登陆unionid') VARCHAR(255)"` | |||||
ThirdPartyWechatExpiresIn string `json:"third_party_wechat_expires_in" xorm:"not null default '' comment('微信第三方登录expires_in(剩余时长)') VARCHAR(255)"` | |||||
ThirdPartyWechatOpenid string `json:"third_party_wechat_openid" xorm:"not null default '' comment('微信第三方登陆openid(不变,用于认证)') VARCHAR(255)"` | |||||
ThirdPartyWechatUnionid string `json:"third_party_wechat_unionid" xorm:"not null default '' comment('微信第三方登陆unionid') VARCHAR(255)"` | |||||
ThirdPartyWechatMiniOpenid string `json:"third_party_wechat_mini_openid" xorm:"not null default '' comment('微信小程序登录open_id') VARCHAR(255)"` | |||||
ThirdPartyWechatH5Openid string `json:"third_party_wechat_h5_openid" xorm:"not null default '' comment('微信H5登录open_id') VARCHAR(255)"` | |||||
FreeRemainTime int `json:"free_remain_time" xorm:"not null default 0 comment('免单剩余次数') INT(11)"` | |||||
FreeCumulativeTime int `json:"free_cumulative_time" xorm:"not null default 0 comment('免单累计次数') INT(11)"` | |||||
IsDelete int `json:"is_delete" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"` | |||||
UpdateAt time.Time `json:"update_at" xorm:"updated not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"` | |||||
SignDay int `json:"sign_day" xorm:"not null default 0 comment('签到天数') INT(11)"` | |||||
} |
@@ -9,4 +9,5 @@ require ( | |||||
go.uber.org/zap v1.13.0 | go.uber.org/zap v1.13.0 | ||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 | ||||
xorm.io/xorm v1.3.1 | xorm.io/xorm v1.3.1 | ||||
github.com/shopspring/decimal v1.3.1 | |||||
) | ) |
@@ -0,0 +1,20 @@ | |||||
package md | |||||
// 缓存key统一管理, %s格式化为masterId | |||||
const ( | |||||
AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母 | |||||
VirtualCoinCfgCacheKey = "%s:virtual_coin_cfg" | |||||
PlanRewardCfgCacheKey = "%s:plan_reward_cfg" | |||||
UnionSetCacheCfg = "%s:union_set_cfg:%s" // 联盟设置缓存key | |||||
UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额) | |||||
UserVirtualAmountUpdateLock = "%s:user_virtual_amount_update_lock:%s" // 用户虚拟币更新锁(能拿到锁才能更新余额) | |||||
WithdrawApplyQueueListKey = "withdraw_apply_queue" // 提现队列 | |||||
TplBottomNavRedisKey = "%s:tpl_nav_bottom_key:%s" // master_id platform | |||||
SysModByIdRedisKey = "%s:sys_mod_tpl_by_id:%s" | |||||
CfgCacheTime = 86400 | |||||
) |
@@ -4,4 +4,5 @@ type RewardData struct { | |||||
Key string `json:"key"` | Key string `json:"key"` | ||||
Bili string `json:"bili"` | Bili string `json:"bili"` | ||||
Num string `json:"num"` | Num string `json:"num"` | ||||
Probability string `json:"probability"` | |||||
} | } |
@@ -0,0 +1,45 @@ | |||||
package md | |||||
const ( | |||||
FinUserFlowDirectionIncome = 1 //流水 - 收入 | |||||
FinUserFlowDirectionExpenditure = 2 //流水 - 支出 | |||||
) | |||||
const ( | |||||
FinUserFlowRedisDataBase = 0 | |||||
FinUserFlowRedisKey = "%s:fin_user_flow:%d:user:%d" | |||||
) | |||||
const ( | |||||
IntegralReleaseServiceRevenueTitleForFinUserFlow = "积分释放-服务收益" | |||||
IntegralReleaseServiceRevenueRefundTitleForFinUserFlow = "订单退款-服务收益扣除" | |||||
) | |||||
const ( | |||||
IntegralReleaseServiceRevenueOrderTypeForFinUserFlow = 50 // 积分释放-服务收益 | |||||
IntegralReleaseServiceRevenueOrderRefundTypeForFinUserFlow = 51 // 积分释放-服务收益退款 | |||||
) | |||||
const DealUserAmountRequestIdPrefix = "%s:deal_user_amount:%d" | |||||
const UserAmountRedisKey = "%s:user_amount:%d" | |||||
type DealIntegralReleaseInterpositionUserAmountReq struct { | |||||
Kind string `json:"kind"` | |||||
Mid string `json:"mid"` | |||||
OrdId string `json:"ord_id"` | |||||
CoinId int `json:"coin_id"` | |||||
Uid int `json:"uid"` | |||||
OriginalUid int `json:"original_uid"` | |||||
Amount float64 `json:"amount"` | |||||
} | |||||
type DealUserAmount struct { | |||||
Kind string `json:"kind"` | |||||
Mid string `json:"mid"` | |||||
Title string `json:"title"` | |||||
OrderType string `json:"order_type"` | |||||
OrdAction int `json:"ord_action"` | |||||
OrdId string `json:"ord_id"` | |||||
Uid int `json:"uid"` | |||||
Amount float64 `json:"amount"` | |||||
} |
@@ -3,21 +3,12 @@ package svc | |||||
import ( | import ( | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | ||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||||
"time" | |||||
"xorm.io/xorm" | "xorm.io/xorm" | ||||
) | ) | ||||
func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | func AddOrderJackpot(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | ||||
setting := db.GetDayLuckDrawSetting(eg) | |||||
if setting == nil { | |||||
return nil | |||||
} | |||||
now := time.Now().Unix() | |||||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { | |||||
return nil | |||||
} | |||||
if setting.OrderSoruce == "mall" && zhios_day_luck_draw_utils.InArr(req.Pvd, []string{"mall_goods", "mall_group_buy", "mall_goods_user_lv", "super_group_buy", "mall_supply", "mall_group_own_buy"}) == false { | |||||
setting := db.CheckSetting(eg, req.Pvd) | |||||
if setting == false { | |||||
return nil | return nil | ||||
} | } | ||||
err := db.AddOrderJackpot(eg, req) | err := db.AddOrderJackpot(eg, req) | ||||
@@ -2,14 +2,27 @@ package svc | |||||
import ( | import ( | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | ||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | ||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||||
"encoding/json" | "encoding/json" | ||||
"errors" | |||||
"fmt" | |||||
"github.com/shopspring/decimal" | |||||
"math/rand" | "math/rand" | ||||
"time" | "time" | ||||
"xorm.io/xorm" | "xorm.io/xorm" | ||||
) | ) | ||||
func InitForDayLuckDraw(redisAddr string) (err error) { | |||||
if redisAddr != "" { | |||||
cache.NewRedis(redisAddr) | |||||
} | |||||
_, err = cache.SelectDb(0) | |||||
return | |||||
} | |||||
//随机几个用户 | //随机几个用户 | ||||
func RandUser(sess *xorm.Session) []string { | func RandUser(sess *xorm.Session) []string { | ||||
var newOid = make([]string, 0) | var newOid = make([]string, 0) | ||||
@@ -19,7 +32,10 @@ func RandUser(sess *xorm.Session) []string { | |||||
return newOid | return newOid | ||||
} | } | ||||
now := time.Now().Unix() | now := time.Now().Unix() | ||||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() || (now > setting.StartTime.Unix() && now < setting.EndTime.Unix()) { | |||||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||||
return newOid | |||||
} | |||||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||||
return newOid | return newOid | ||||
} | } | ||||
count := 0 | count := 0 | ||||
@@ -38,6 +54,224 @@ func RandUser(sess *xorm.Session) []string { | |||||
return newOid | return newOid | ||||
} | } | ||||
/*** | |||||
1.创建期数 | |||||
2.获取还没分配的金额 就是 期数为0的 | |||||
3.把期数设置到订单 | |||||
4.查出所有订单号 | |||||
5.随机出订单号(每个名额随机一次 如果重复再次循环) 按概率分几等奖 | |||||
*/ | |||||
func GetUserReward(eg *xorm.Engine, mid string, isTask bool) error { | |||||
// 加锁 防止频繁操作 | |||||
mutexKey := fmt.Sprintf("%s:day_lucky_raw_settle", mid) | |||||
operationSumAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 3600, "NX") | |||||
if err != nil { | |||||
return err | |||||
} | |||||
defer cache.Del(mutexKey) | |||||
if operationSumAvailable != "OK" { | |||||
return errors.New("上一次未运行完成") | |||||
} | |||||
sess := eg.NewSession() | |||||
defer func() { | |||||
sess.Close() | |||||
if err := recover(); err != nil { | |||||
fmt.Println(err) | |||||
} | |||||
}() | |||||
sess.Begin() | |||||
key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||||
isDone, _ := cache.GetString(key) | |||||
if isDone == "" || isDone == "0" { | |||||
SetAllAwardsProbability(sess, mid) | |||||
} | |||||
probabilityMap := make([]map[int]int64, 0) | |||||
key = fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) | |||||
err = cache.GetJson(key, &probabilityMap) | |||||
if err != nil { | |||||
sess.Rollback() | |||||
return err | |||||
} | |||||
setting := db.GetDayLuckDrawSettingSess(sess) | |||||
var rewardData = make([]md.RewardData, 0) | |||||
err = json.Unmarshal([]byte(setting.RewardData), &rewardData) | |||||
if err != nil { | |||||
sess.Rollback() | |||||
return err | |||||
} | |||||
now := time.Now().Unix() | |||||
if isTask { | |||||
if setting.IsUse == 0 || setting.StartTime.IsZero() || setting.EndTime.IsZero() { | |||||
return errors.New("未开始") | |||||
} | |||||
if now < setting.StartTime.Unix() || now > setting.EndTime.Unix() { | |||||
return errors.New("未开始") | |||||
} | |||||
if setting.OpenTime.IsZero() { | |||||
return errors.New("没抽奖时间") | |||||
} | |||||
if now < setting.OpenTime.Unix() { | |||||
return errors.New("没到时间") | |||||
} | |||||
} | |||||
if setting.Source == "" { | |||||
return errors.New("未选择奖励池数据类型") | |||||
} | |||||
//设置期数 | |||||
max := db.GetPeriodMax(sess) | |||||
sum := db.GetSettleAllOrderSum(sess) | |||||
if setting.Source == "amount" { | |||||
sum = zhios_day_luck_draw_utils.StrToFloat64(setting.Amount) | |||||
} else { | |||||
sum = sum * zhios_day_luck_draw_utils.StrToFloat64(setting.CommissionBili) / 100 | |||||
} | |||||
if sum == 0 { //没金额中断了 | |||||
setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) | |||||
update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) | |||||
if err != nil || update == 0 { | |||||
sess.Rollback() | |||||
return errors.New("失败") | |||||
} | |||||
sess.Commit() | |||||
return errors.New("没金额") | |||||
} | |||||
period := 1 | |||||
if max != nil { | |||||
period = max.Period + 1 | |||||
} | |||||
req := md.DayLuckDrawPeriodReq{ | |||||
Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(sum, 7), | |||||
Period: zhios_day_luck_draw_utils.IntToStr(period), | |||||
} | |||||
settingStr, _ := json.Marshal(setting) | |||||
bools := db.AddPeriod(sess, req, string(settingStr)) | |||||
if bools == false { | |||||
return errors.New("期数写入错误") | |||||
} | |||||
rewardDataMap := make(map[int64]int, 0) | |||||
for _, v := range rewardData { | |||||
rewardDataMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] = zhios_day_luck_draw_utils.StrToInt(v.Num) | |||||
} | |||||
uids := RandUser(sess) | |||||
var award = make(map[string]int64) | |||||
var awardIdMap = make(map[int64]int) | |||||
for _, v := range uids { | |||||
for i := 0; i < 10; i++ { | |||||
key := AwardRandomNumberFor100000() | |||||
awardId := int64(0) | |||||
for _, awardProbabilityMap := range probabilityMap { | |||||
id, ok := awardProbabilityMap[key] | |||||
if ok { | |||||
awardId = id | |||||
} else { | |||||
continue | |||||
} | |||||
} | |||||
if awardId == 0 || award[v] > 0 { | |||||
continue | |||||
} | |||||
//查下已产生用户数量 | |||||
awardCount, ok := awardIdMap[awardId] | |||||
//查下总数量 | |||||
rewardDataCount, ok := rewardDataMap[awardId] | |||||
if ok == false { | |||||
continue | |||||
} | |||||
if ok { | |||||
if awardCount+1 > rewardDataCount { | |||||
continue | |||||
} | |||||
} | |||||
if rewardDataCount == 0 { | |||||
continue | |||||
} | |||||
awardIdMap[awardId] = awardCount + 1 | |||||
award[v] = awardId | |||||
} | |||||
} | |||||
//处理奖励 | |||||
var awardMap = make(map[int64][]string) | |||||
for k, v := range award { | |||||
awardMap[v] = append(awardMap[v], k) | |||||
} | |||||
for _, v := range rewardData { | |||||
uid, ok := awardMap[zhios_day_luck_draw_utils.StrToInt64(v.Key)] | |||||
if ok { | |||||
err := SendReward(sess, uid, mid, period, sum, v) | |||||
if err != nil { | |||||
sess.Rollback() | |||||
return err | |||||
} | |||||
} | |||||
} | |||||
setting.OpenTime = time.Unix(now+int64(setting.CycleDay)*86400, 0) | |||||
update, err := sess.Where("id=?", setting.Id).Cols("open_time").Update(setting) | |||||
if err != nil || update == 0 { | |||||
sess.Rollback() | |||||
return errors.New("失败") | |||||
} | |||||
update1, err1 := sess.Where("is_send=0").Cols("is_send").Update(&model.DayLuckDrawSettleOrder{IsSend: 1}) | |||||
if err1 != nil || update1 == 0 { | |||||
sess.Rollback() | |||||
return errors.New("失败") | |||||
} | |||||
update2, err2 := sess.Where("period=0").Cols("period").Update(&model.DayLuckDrawOrderJackpot{Period: period}) | |||||
if err2 != nil || update2 == 0 { | |||||
sess.Rollback() | |||||
return errors.New("失败") | |||||
} | |||||
sess.Commit() | |||||
return nil | |||||
} | |||||
func SendReward(sess *xorm.Session, uid []string, mid string, period int, sum float64, rewardData md.RewardData) error { | |||||
count := len(uid) | |||||
if count == 0 { | |||||
return nil | |||||
} | |||||
bili := zhios_day_luck_draw_utils.StrToFloat64(rewardData.Bili) | |||||
if bili == 0 { | |||||
return nil | |||||
} | |||||
amount := sum * bili / float64(count) | |||||
for _, v := range uid { | |||||
var req = md.DayLuckDrawRewardReq{ | |||||
Uid: v, | |||||
Period: zhios_day_luck_draw_utils.IntToStr(period), | |||||
Reward: zhios_day_luck_draw_utils.Float64ToStrByPrec(amount, 7), | |||||
Lv: rewardData.Key, | |||||
} | |||||
err := db.AddPeriodReward(sess, req) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
var dealUserAmount = md.DealUserAmount{ | |||||
Kind: "add", | |||||
Mid: mid, | |||||
Title: "每日抽奖奖励", | |||||
OrderType: "", | |||||
OrdAction: 85, | |||||
OrdId: "", | |||||
Uid: zhios_day_luck_draw_utils.StrToInt(v), | |||||
Amount: amount, | |||||
} | |||||
err = DealUserAmount(sess, dealUserAmount) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
} | |||||
return nil | |||||
} | |||||
func AwardRandomNumberFor100000() int { | |||||
rand.Seed(time.Now().UnixNano()) | |||||
num := rand.Intn(100000) | |||||
return num | |||||
} | |||||
func MicsSlice(origin []string, count int) []string { | func MicsSlice(origin []string, count int) []string { | ||||
tmpOrigin := make([]string, len(origin)) | tmpOrigin := make([]string, len(origin)) | ||||
copy(tmpOrigin, origin) | copy(tmpOrigin, origin) | ||||
@@ -47,12 +281,99 @@ func MicsSlice(origin []string, count int) []string { | |||||
tmpOrigin[i], tmpOrigin[j] = tmpOrigin[j], tmpOrigin[i] | tmpOrigin[i], tmpOrigin[j] = tmpOrigin[j], tmpOrigin[i] | ||||
}) | }) | ||||
result := make([]string, 0, count) | |||||
for index, value := range tmpOrigin { | |||||
if index == count { | |||||
result := make([]string, 0) | |||||
for _, value := range tmpOrigin { | |||||
if len(result) == count { | |||||
break | break | ||||
} | } | ||||
if zhios_day_luck_draw_utils.InArr(value, result) { | |||||
continue | |||||
} | |||||
result = append(result, value) | result = append(result, value) | ||||
} | } | ||||
return result | return result | ||||
} | } | ||||
func SetAllAwardsProbability(sess *xorm.Session, mid string) error { | |||||
defer func() { | |||||
//处理异常错误 | |||||
if r := recover(); r != nil { | |||||
fmt.Println(r) | |||||
} | |||||
}() | |||||
setting := db.GetDayLuckDrawSettingSess(sess) | |||||
var rewardData = make([]md.RewardData, 0) | |||||
err := json.Unmarshal([]byte(setting.RewardData), &rewardData) | |||||
if err != nil { | |||||
key := fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||||
_, err = cache.SetEx(key, "0", 39528000) // 半年 | |||||
if err != nil { | |||||
return err | |||||
} | |||||
} | |||||
//建立协程池 | |||||
workerCount := 0 | |||||
ProbabilityKeyChan := make(chan int, 100000) | |||||
awardsMapChan := make(chan map[int]int64, len(rewardData)) | |||||
doneChan := make(chan bool, len(rewardData)) | |||||
for i := 0; i < 10; i++ { | |||||
go func(endNum int) { | |||||
for startNum := (endNum * 10000) + 1; startNum <= (endNum+1)*10000; startNum++ { | |||||
ProbabilityKeyChan <- startNum | |||||
} | |||||
if i == 9 { | |||||
close(ProbabilityKeyChan) | |||||
} | |||||
}(i) | |||||
} | |||||
for _, award := range rewardData { | |||||
probabilityD, err := decimal.NewFromString(award.Num) | |||||
if err != nil { | |||||
probabilityD = decimal.NewFromInt(0) | |||||
} | |||||
probabilityD = probabilityD.Div(decimal.NewFromInt(100)) | |||||
probability, _ := probabilityD.Float64() | |||||
go CalculateAwardsProbability(zhios_day_luck_draw_utils.StrToInt64(award.Key), probability, ProbabilityKeyChan, awardsMapChan, doneChan) | |||||
workerCount++ | |||||
} | |||||
probabilityMap := make([]map[int]int64, 0) | |||||
WaitChain(workerCount, awardsMapChan, doneChan) | |||||
for awards := range awardsMapChan { | |||||
probabilityMap = append(probabilityMap, awards) | |||||
} | |||||
key := fmt.Sprintf("%s:day_lucky_draw_rotary_bingo_rate", mid) | |||||
_, err = cache.SetEx(key, zhios_day_luck_draw_utils.SerializeStr(probabilityMap), 39528000) // 半年 | |||||
if err != nil { | |||||
return err | |||||
} | |||||
key = fmt.Sprintf("%s:day_lucky_draw_bingo_rate_calculate", mid) | |||||
_, err = cache.SetEx(key, "1", 39528000) // 半年 | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return nil | |||||
} | |||||
func CalculateAwardsProbability(awardsId int64, probability float64, ProbabilityKeyChan chan int, awardsMapChan chan map[int]int64, doneChan chan bool) { | |||||
//计算要循环多少次 | |||||
var awardsMap = make(map[int]int64) | |||||
for i := 0; i < int(100000*probability); i++ { | |||||
key := <-ProbabilityKeyChan | |||||
awardsMap[key] = awardsId | |||||
} | |||||
awardsMapChan <- awardsMap | |||||
doneChan <- true | |||||
} | |||||
func WaitChain(workerCount int, awardsMapChan chan map[int]int64, doneChan chan bool) { | |||||
for { | |||||
select { | |||||
case <-doneChan: | |||||
workerCount-- | |||||
if workerCount == 0 { | |||||
close(awardsMapChan) | |||||
return | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
package svc | |||||
import ( | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||||
"xorm.io/xorm" | |||||
) | |||||
func AddSettleOrder(eg *xorm.Engine, req md.DayLuckDrawOrderJackpotReq) error { | |||||
setting := db.CheckSetting(eg, req.Pvd) | |||||
if setting == false { | |||||
return nil | |||||
} | |||||
err := db.AddSettle(eg, req) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return nil | |||||
} |
@@ -0,0 +1,126 @@ | |||||
package svc | |||||
import ( | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/db/model" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||||
"errors" | |||||
"fmt" | |||||
"github.com/shopspring/decimal" | |||||
"strconv" | |||||
"time" | |||||
"xorm.io/xorm" | |||||
) | |||||
// DealUserAmount 处理给用户余额 | |||||
func DealUserAmount(session *xorm.Session, req md.DealUserAmount) (err error) { | |||||
if req.Amount < 0 { | |||||
req.Amount = 0 | |||||
} | |||||
//1、分布式锁阻拦 | |||||
requestIdPrefix := fmt.Sprintf(md.DealUserAmountRequestIdPrefix, req.Mid, req.Uid) | |||||
cb, err := HandleBalanceDistributedLockForAmount(req.Mid, strconv.Itoa(req.Uid), requestIdPrefix) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
if cb != nil { | |||||
defer cb() // 释放锁 | |||||
} | |||||
//2、计算&&组装数据 | |||||
now := time.Now() | |||||
userAmount, err := GetUserAmount(session, req.Mid, req.Uid) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
userAmountValue := decimal.NewFromFloat(zhios_day_luck_draw_utils.StrToFloat64(userAmount)) | |||||
amountValue := decimal.NewFromFloat(req.Amount).RoundFloor(8) | |||||
var finUserFlow = model.FinUserFlow{ | |||||
Uid: req.Uid, | |||||
Amount: amountValue.String(), | |||||
BeforeAmount: userAmount, | |||||
OrdType: req.OrderType, | |||||
OrdId: req.OrdId, | |||||
OrdTitle: req.Title, | |||||
OrdAction: req.OrdAction, | |||||
OrdTime: int(now.Unix()), | |||||
State: 1, | |||||
CreateAt: now, | |||||
UpdateAt: now, | |||||
} | |||||
if req.Kind == "add" { | |||||
finUserFlow.Type = 0 | |||||
finUserFlow.AfterAmount = userAmountValue.Add(amountValue).RoundFloor(8).String() | |||||
} else if req.Kind == "sub" { | |||||
finUserFlow.Type = 1 | |||||
finUserFlow.AfterAmount = userAmountValue.Sub(amountValue).RoundFloor(8).String() | |||||
} else { | |||||
err = errors.New("错误的kind类型") | |||||
return err | |||||
} | |||||
if zhios_day_luck_draw_utils.StrToFloat64(finUserFlow.AfterAmount) < 0 { | |||||
return errors.New("用户余额不足") | |||||
} | |||||
//3、插入 `user_virtual_coin_flow` 记录 | |||||
affected, err := session.Insert(&finUserFlow) | |||||
if affected == 0 || err != nil { | |||||
return err | |||||
} | |||||
//4、修改 `user_profile`的fin_valid值 && 及缓存 | |||||
err = SetCacheUserAmount(session, req.Mid, finUserFlow.AfterAmount, req.Uid, true) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return nil | |||||
} | |||||
// GetUserAmount 获取用户余额 | |||||
func GetUserAmount(session *xorm.Session, masterId string, uid int) (amount string, err error) { | |||||
redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) | |||||
amount, err = cache.GetString(redisKey) | |||||
if err != nil { | |||||
if err.Error() == "redigo: nil returned" { | |||||
userAmount, err := db.UserProfileFindByIDWithSession(session, uid) | |||||
if err != nil { | |||||
return amount, err | |||||
} | |||||
if userAmount == nil { | |||||
amount = "0" | |||||
} else { | |||||
amount = userAmount.FinValid | |||||
} | |||||
//将获取到的余额值缓存至redis | |||||
_ = SetCacheUserAmount(session, masterId, amount, uid, false) | |||||
return amount, nil | |||||
} | |||||
return amount, err | |||||
} | |||||
return amount, nil | |||||
} | |||||
// SetCacheUserAmount 设置缓存的用户余额 | |||||
func SetCacheUserAmount(session *xorm.Session, masterId, amount string, uid int, isUpdateDb bool) error { | |||||
redisKey := fmt.Sprintf(md.UserAmountRedisKey, masterId, uid) | |||||
if isUpdateDb { | |||||
_, err := session.Where("uid=?", uid).Update(model.UserProfile{ | |||||
Uid: uid, | |||||
FinValid: amount, | |||||
}) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
} | |||||
//_, err := cache.Set(redisKey, int64(utils.StrToFloat64(amount))) | |||||
//TODO::默认缓存1小时 (先调整为 2 min) | |||||
_, err := cache.SetEx(redisKey, zhios_day_luck_draw_utils.StrToFloat64(amount), 60*2) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
return nil | |||||
} |
@@ -0,0 +1,84 @@ | |||||
package svc | |||||
import ( | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||||
zhios_day_luck_draw_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils" | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/utils/cache" | |||||
"errors" | |||||
"fmt" | |||||
"math/rand" | |||||
"reflect" | |||||
"time" | |||||
) | |||||
const redisMutexLockExpTime = 15 | |||||
// TryGetDistributedLock 分布式锁获取 | |||||
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一 | |||||
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool { | |||||
if isNegative { // 多次尝试获取 | |||||
retry := 1 | |||||
for { | |||||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||||
// 获取锁成功 | |||||
if err == nil && ok == "OK" { | |||||
return true | |||||
} | |||||
// 尝试多次没获取成功 | |||||
if retry > 10 { | |||||
return false | |||||
} | |||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) | |||||
retry += 1 | |||||
} | |||||
} else { // 只尝试一次 | |||||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||||
// 获取锁成功 | |||||
if err == nil && ok == "OK" { | |||||
return true | |||||
} | |||||
return false | |||||
} | |||||
} | |||||
// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型 | |||||
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) { | |||||
luaScript := ` | |||||
if redis.call("get",KEYS[1]) == ARGV[1] | |||||
then | |||||
return redis.call("del",KEYS[1]) | |||||
else | |||||
return 0 | |||||
end` | |||||
do, err := cache.Do("eval", luaScript, 1, lockKey, requestId) | |||||
fmt.Println(reflect.TypeOf(do)) | |||||
fmt.Println(do) | |||||
if zhios_day_luck_draw_utils.AnyToInt64(do) == 1 { | |||||
return true, err | |||||
} else { | |||||
return false, err | |||||
} | |||||
} | |||||
func GetDistributedLockRequestId(prefix string) string { | |||||
return prefix + zhios_day_luck_draw_utils.IntToStr(rand.Intn(100000000)) | |||||
} | |||||
// HandleDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 | |||||
func HandleDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) { | |||||
// 获取余额更新锁 | |||||
balanceLockKey := fmt.Sprintf(md.UserVirtualAmountUpdateLock, masterId, uid) | |||||
requestId := GetDistributedLockRequestId(requestIdPrefix) | |||||
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) | |||||
if !balanceLockOk { | |||||
return nil, errors.New("系统繁忙,请稍后再试") | |||||
} | |||||
cb = func() { | |||||
_, _ = ReleaseDistributedLock(balanceLockKey, requestId) | |||||
} | |||||
return cb, nil | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package svc | |||||
import ( | |||||
"code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git/md" | |||||
"errors" | |||||
"fmt" | |||||
) | |||||
// HandleBalanceDistributedLockForAmount 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 | |||||
func HandleBalanceDistributedLockForAmount(masterId, uid, requestIdPrefix string) (cb func(), err error) { | |||||
// 获取余额更新锁 | |||||
balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid) | |||||
requestId := GetDistributedLockRequestId(requestIdPrefix) | |||||
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) | |||||
if !balanceLockOk { | |||||
return nil, errors.New("系统繁忙,请稍后再试") | |||||
} | |||||
cb = func() { | |||||
_, _ = ReleaseDistributedLock(balanceLockKey, requestId) | |||||
} | |||||
return cb, nil | |||||
} |