capsule.go 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  1. package dao
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/pkg/errors"
  10. v12 "go-common/app/service/live/rc/api/liverpc/v1"
  11. "go-common/library/cache/redis"
  12. "go-common/app/job/live/xlottery/internal/model"
  13. "go-common/library/database/sql"
  14. "go-common/library/log"
  15. "go-common/library/queue/databus/report"
  16. )
  17. // NormalCoinId 普通扭蛋id
  18. const NormalCoinId = 1
  19. // ColorfulCoinId 梦幻扭蛋id
  20. const ColorfulCoinId = 2
  21. // WeekCoinId 周星扭蛋id
  22. const WeekCoinId = 3
  23. // LplCoinId 周星扭蛋id
  24. const LplCoinId = 4
  25. // BlessCoinId 祈福抽奖券
  26. const BlessCoinId = 5
  27. // IsBottomPool 是否为保底奖池
  28. const IsBottomPool = 1
  29. // CapsuleActionTrans 转换扭蛋币
  30. const CapsuleActionTrans = "trans"
  31. const (
  32. // NormalCoinString 普通扭蛋字符串标识,数据库和redis
  33. NormalCoinString = "normal"
  34. // ColorfulCoinString 梦幻扭蛋字符串标识,数据库和redis
  35. ColorfulCoinString = "colorful"
  36. // WeekCoinString 周星扭蛋字符串标识,数据库和redis
  37. WeekCoinString = "week"
  38. // LplCoinString 周星扭蛋字符串标识,数据库和redis
  39. LplCoinString = "lpl"
  40. // BlessCoinString 祈福扭蛋字符串标识,数据库和redis
  41. BlessCoinString = "bless"
  42. )
  43. const (
  44. _capsuleNotice = "capsule:notice:%s:%d"
  45. _userCapsuleCoinRedis = "hash:capsule:user:%d"
  46. _userInfoRedis = "capsule:user:info:%d:%d"
  47. _capsuleConfRand = "capsule:rand"
  48. _lplSendGiftRedis = "capsule:lpl:send:gift:%s:%d"
  49. )
  50. const (
  51. _ = iota
  52. // CapsulePrizeGift1Type 辣条
  53. CapsulePrizeGift1Type // 辣条
  54. // CapsulePrizeTitleType 头衔
  55. CapsulePrizeTitleType
  56. // CapsulePrizeStuff1Type 经验原石
  57. CapsulePrizeStuff1Type
  58. // CapsulePrizeStuff2Type 经验曜石
  59. CapsulePrizeStuff2Type
  60. // CapsulePrizeStuff3Type 贤者之石
  61. CapsulePrizeStuff3Type
  62. // CapsulePrizeSmallTvType 小电视
  63. CapsulePrizeSmallTvType
  64. // CapsulePrizeGuard3Type 舰长体验
  65. CapsulePrizeGuard3Type
  66. // CapsulePrizeGuard2Type 提督体验
  67. CapsulePrizeGuard2Type
  68. // CapsulePrizeGuard1Type 总督体验
  69. CapsulePrizeGuard1Type
  70. )
  71. const (
  72. _ = iota
  73. // CapsuleGiftTypeAll gift_type 为全部道具
  74. CapsuleGiftTypeAll
  75. // CapsuleGiftTypeGold gift_type 为金瓜子道具
  76. CapsuleGiftTypeGold
  77. // CapsuleGiftTypeSelected gift_type 为指定道具
  78. CapsuleGiftTypeSelected
  79. )
  80. const (
  81. _getActiveColorPool = "SELECT id, coin_id, title, rule, start_time, end_time, status FROM capsule_pool WHERE status = 1 AND coin_id = ?"
  82. _getCapsuleMaxId = "SELECT id FROM capsule_%s order by id desc limit 1"
  83. _transCapsule = "UPDATE capsule_%s SET normal_score = normal_score + ?,colorful_score = 0 WHERE uid = ?"
  84. _getChangeNum = "SELECT change_num FROM capsule_coin WHERE id = ?"
  85. _getUserInfoById = "SELECT uid,normal_score,colorful_score FROM capsule_%s WHERE id >= ? AND id < ? and colorful_score > 0"
  86. _getUserInfoByUids = "SELECT uid,normal_score,colorful_score FROM capsule_%s WHERE uid in(%s)"
  87. _getOnCoin = "SELECT id, title, gift_type, change_num, start_time, end_time, status FROM capsule_coin WHERE status = 1"
  88. _getCoinConfigMap = "SELECT coin_id, type, area_v2_parent_id, area_v2_id, gift_id FROM capsule_coin_config WHERE coin_id in (%v) AND status = 1"
  89. _getPoolMap = "SELECT id, coin_id, title, rule, start_time, end_time, status, is_bottom FROM capsule_pool WHERE status = 1 and coin_id in (%v)"
  90. _getPoolPrizeMap = "SELECT id, pool_id, type, num, object_id,expire, web_url, mobile_url, description, jump_url, pro_type, chance, loop_num, limit_num, weight FROM capsule_pool_prize WHERE pool_id in (%s) and status = 1 order by ctime"
  91. _reportCapsuleChangeMysql = "insert into capsule_log_%s(uid, type, score, action, platform, pre_normal_score, pre_colorful_score, cur_normal_score, cur_colorful_score) values(?,?,?,?,?,?,?,?,?)"
  92. _userCapsuleCoinMysql = "select normal_score, colorful_score from capsule_%d where uid = ?"
  93. _addCapsuleCoinMysql = "insert into capsule_%d(uid, normal_score, colorful_score) values(?, ?, ?)"
  94. _userInfoMysql = "select score from capsule_info_%d where uid = ? and type = ?"
  95. _addInfoMysql = "insert into capsule_info_%d(uid,type,score) values(?, ?, ?)"
  96. _transUserCapsuleMysql = "update capsule_%d set colorful_score = 0, normal_score = normal_score + ? where uid = ?"
  97. _updateUserCapsuleMysql = "update capsule_%d set %s_score = %s_score + ? where uid = ?"
  98. _updateUserInfoMysql = "update capsule_info_%d set score = score + ? where uid = ? and type = ?"
  99. _getExtraDataMysql = "select item_value, item_extra from capsule_extra_data where uid = ? and type = ?"
  100. _addExtraDataMysql = "insert into capsule_extra_data(uid,type,item_value,item_extra) values(?,?,?,?)"
  101. _getExtraDataByTimeMysql = "select id, uid, type, item_value, item_extra from capsule_extra_data where mtime >= ? and mtime < ?"
  102. _updateExtraValueMysql = "update capsule_extra_data set item_value = ? where id = ?"
  103. _updateExtraMtimeMysql = "update capsule_extra_data set mtime = ? where id = ?"
  104. _updateExtraMysql = "update capsule_extra_data set item_value = ?, item_extra = ? where id = ?"
  105. _getExtraDataMaxIdMysql = "select id from capsule_extra_data order by id desc limit 1"
  106. _getExtraDataByIdMysql = "select id, uid, type, item_value, item_extra from capsule_extra_data where id >= ? and id < ?"
  107. )
  108. var (
  109. capsuleConf CapsuleConf
  110. // ReprotConfig map
  111. ReprotConfig map[int64]string
  112. // CoinIdIntMap map
  113. CoinIdIntMap map[int64]string
  114. // PrizeNameMap map
  115. PrizeNameMap map[int64]string
  116. )
  117. var (
  118. // UnLockGetWrong flag
  119. UnLockGetWrong = "UnLockGetWrong"
  120. // ErrUnLockGet error
  121. ErrUnLockGet = errors.New(UnLockGetWrong)
  122. )
  123. // CapsuleConf 扭蛋全局配置
  124. type CapsuleConf struct {
  125. CoinConfMap map[int64]*CapsuleCoinConf
  126. CacheTime int64
  127. ChangeFlag int64
  128. RwLock sync.RWMutex
  129. }
  130. // CapsuleCoinConf 扭蛋币配置
  131. type CapsuleCoinConf struct {
  132. Id int64
  133. Title string
  134. GiftType int64
  135. ChangeNum int64
  136. StartTime int64
  137. EndTime int64
  138. Status int64
  139. GiftMap map[int64]struct{}
  140. AreaMap map[int64]struct{}
  141. PoolConf *CapsulePoolConf
  142. AllPoolConf []*CapsulePoolConf
  143. }
  144. // CapsulePoolConf 奖池配置
  145. type CapsulePoolConf struct {
  146. Id int64
  147. CoinId int64
  148. Title string
  149. Rule string
  150. StartTime, EndTime int64
  151. Status int64
  152. IsBottom int64
  153. PoolPrize []*CapsulePoolPrize
  154. }
  155. // CapsulePoolPrize 奖池奖品
  156. type CapsulePoolPrize struct {
  157. Id, PoolId, Type, Num, ObjectId, Expire int64
  158. Name, WebImage, MobileImage, Description, JumpUrl string
  159. ProType int64
  160. Chance int64
  161. LoopNum, LimitNum, Weight int64
  162. }
  163. func init() {
  164. CoinIdIntMap = make(map[int64]string)
  165. CoinIdIntMap[NormalCoinId] = NormalCoinString
  166. CoinIdIntMap[ColorfulCoinId] = ColorfulCoinString
  167. CoinIdIntMap[WeekCoinId] = WeekCoinString
  168. CoinIdIntMap[LplCoinId] = LplCoinString
  169. CoinIdIntMap[BlessCoinId] = BlessCoinString
  170. PrizeNameMap = make(map[int64]string)
  171. PrizeNameMap[CapsulePrizeGift1Type] = "辣条"
  172. PrizeNameMap[CapsulePrizeTitleType] = "头衔"
  173. PrizeNameMap[CapsulePrizeStuff1Type] = "经验原石"
  174. PrizeNameMap[CapsulePrizeStuff2Type] = "经验曜石"
  175. PrizeNameMap[CapsulePrizeStuff3Type] = "贤者之石"
  176. PrizeNameMap[CapsulePrizeSmallTvType] = "小电视抱枕"
  177. PrizeNameMap[CapsulePrizeGuard3Type] = "舰长体验"
  178. PrizeNameMap[CapsulePrizeGuard2Type] = "提督体验"
  179. ReprotConfig = make(map[int64]string)
  180. ReprotConfig[0] = "未知"
  181. ReprotConfig[1] = "增加普通扭蛋"
  182. ReprotConfig[2] = "增加梦幻扭蛋"
  183. ReprotConfig[3] = "减少普通扭蛋"
  184. ReprotConfig[4] = "减少梦幻扭蛋"
  185. ReprotConfig[5] = "梦幻转化普通"
  186. }
  187. // GetActiveColorPool 获取奖池
  188. func (d *Dao) GetActiveColorPool(ctx context.Context) (pool []*model.Pool, err error) {
  189. var rows *sql.Rows
  190. if rows, err = d.db.Query(ctx, _getActiveColorPool, ColorfulCoinId); err != nil {
  191. log.Error("[dao.capsule | GetActiveColorPool]query(%s) error(%v)", _getActiveColorPool, err)
  192. return
  193. }
  194. defer rows.Close()
  195. for rows.Next() {
  196. p := &model.Pool{}
  197. if err = rows.Scan(&p.Id, &p.CoinId, &p.Title, &p.Description, &p.StartTime, &p.EndTime, &p.Status); err != nil {
  198. log.Error("[dao.capsule | GetActiveColorPool] scan error, err %v", err)
  199. return
  200. }
  201. pool = append(pool, p)
  202. }
  203. return
  204. }
  205. // GetUserInfoById 获取扭蛋币信息
  206. func (d *Dao) GetUserInfoById(ctx context.Context, table string, start int64, end int64) (infos [][4]int64, err error) {
  207. var rows *sql.Rows
  208. sqlStr := fmt.Sprintf(_getUserInfoById, table)
  209. if rows, err = d.db.Query(ctx, sqlStr, start, end); err != nil {
  210. log.Error("[dao.capsule | GetUserInfos]query(%s) error(%v)", _getUserInfoById, err)
  211. return
  212. }
  213. defer rows.Close()
  214. infos = make([][4]int64, 0)
  215. for rows.Next() {
  216. p := &model.UserInfo{}
  217. if err = rows.Scan(&p.Uid, &p.NormalScore, &p.ColorfulScore); err != nil {
  218. log.Error("[dao.capsule | GetUserInfos] scan error, err %v", err)
  219. return
  220. }
  221. infos = append(infos, [4]int64{p.Uid, p.NormalScore, p.ColorfulScore, 0})
  222. }
  223. return
  224. }
  225. // GetUserInfoByUids 获取扭蛋币信息
  226. func (d *Dao) GetUserInfoByUids(ctx context.Context, table string, uids []int64) (infos map[int64][2]int64, err error) {
  227. var rows *sql.Rows
  228. uidStrArray := make([]string, len(uids))
  229. for ix, uid := range uids {
  230. uidStrArray[ix] = strconv.FormatInt(uid, 10)
  231. }
  232. uidStr := strings.Join(uidStrArray, ",")
  233. sqlStr := fmt.Sprintf(_getUserInfoByUids, table, uidStr)
  234. if rows, err = d.db.Query(ctx, sqlStr); err != nil {
  235. log.Error("[dao.capsule | GetUserInfoByUids]query(%s) error(%v)", _getUserInfoByUids, err)
  236. return
  237. }
  238. defer rows.Close()
  239. infos = make(map[int64][2]int64)
  240. for rows.Next() {
  241. p := &model.UserInfo{}
  242. if err = rows.Scan(&p.Uid, &p.NormalScore, &p.ColorfulScore); err != nil {
  243. log.Error("[dao.capsule | GetUserInfoByUids] scan error, err %v", err)
  244. return
  245. }
  246. infos[p.Uid] = [2]int64{p.NormalScore, p.ColorfulScore}
  247. }
  248. return
  249. }
  250. // GetTransNum 获取扭蛋币数量
  251. func (d *Dao) GetTransNum(ctx context.Context, coinId int64) (changeNum int64, err error) {
  252. var rows *sql.Rows
  253. if rows, err = d.db.Query(ctx, _getChangeNum, coinId); err != nil {
  254. log.Error("[dao.capsule | GetTransNum]query(%s) error(%v)", _getChangeNum, err)
  255. return
  256. }
  257. defer rows.Close()
  258. for rows.Next() {
  259. p := &model.Coin{}
  260. if err = rows.Scan(&p.ChangeNum); err != nil {
  261. log.Error("[dao.capsule | GetTransNum]scan error, err %v", err)
  262. return
  263. }
  264. changeNum = p.ChangeNum
  265. }
  266. return
  267. }
  268. // TransCapsule 转换扭蛋币
  269. func (d *Dao) TransCapsule(ctx context.Context, table string, colorChangeNum int64, normalChangeNum int64) (err error) {
  270. var maxId int64
  271. row := d.db.QueryRow(ctx, fmt.Sprintf(_getCapsuleMaxId, table))
  272. if err = row.Scan(&maxId); err != nil {
  273. log.Error("[dao.capsule | TransCapsule] query(%s),err(%v)", _getCapsuleMaxId, err)
  274. return
  275. }
  276. log.Info("[dao.capsule | TransCapsule] table: %s, max: %d", table, maxId)
  277. conn := d.redis.Get(ctx)
  278. defer conn.Close()
  279. var i int64
  280. for i = 0; i <= maxId; i = i + 1000 {
  281. var userInfos [][4]int64
  282. userInfos, err = d.GetUserInfoById(ctx, table, i, i+1000)
  283. if err != nil {
  284. log.Error("[dao.capsule | TransCapsule] GetUserInfos error %v", err)
  285. return err
  286. }
  287. ulen := len(userInfos)
  288. if ulen < 1 {
  289. continue
  290. }
  291. uids := make([]int64, ulen)
  292. for ix, userInfo := range userInfos {
  293. uid := userInfo[0]
  294. changeScore := userInfo[2] - userInfo[2]%normalChangeNum
  295. _, err = d.db.Exec(ctx, fmt.Sprintf(_transCapsule, table), changeScore, uid)
  296. if err != nil {
  297. log.Error("[dao.capsule | TransCapsule]query(%s) error(%v)", _transCapsule, err)
  298. return
  299. }
  300. userInfos[ix][3] = changeScore
  301. uids[ix] = uid
  302. uKey := userKey(uid)
  303. _, e := conn.Do("DEL", uKey)
  304. if e != nil {
  305. log.Error("redis_lottery|delete score error,%v, uid %v", e, uid)
  306. }
  307. }
  308. var userMap map[int64][2]int64
  309. userMap, err = d.GetUserInfoByUids(ctx, table, uids)
  310. if err != nil {
  311. log.Error("[dao.capsule | TransCapsule] GetUserInfoByUids error %v", err)
  312. return err
  313. }
  314. if userMap == nil {
  315. continue
  316. }
  317. for _, userInfo := range userInfos {
  318. changeScore := userInfo[3]
  319. uid := userInfo[0]
  320. if _, ok := userMap[uid]; !ok {
  321. continue
  322. }
  323. report.User(&report.UserInfo{
  324. Business: 101,
  325. Type: int(1),
  326. Oid: uid,
  327. Action: "capsule_change",
  328. Ctime: time.Now(),
  329. Index: []interface{}{
  330. "梦幻转化普通",
  331. changeScore,
  332. userMap[uid][0],
  333. userMap[uid][1],
  334. "trans",
  335. },
  336. })
  337. date := time.Now().Format("200601")
  338. sqlStr := fmt.Sprintf(_reportCapsuleChangeMysql, date)
  339. _, err := d.execSqlWithBindParams(ctx, &sqlStr, uid, 1, changeScore, "trans", "", userInfo[1], userInfo[2], userMap[uid][0], userMap[uid][1])
  340. if err != nil {
  341. log.Error("[dao.capsule | TransCapsule] AddCapsuleLog error %v", err)
  342. continue
  343. }
  344. }
  345. }
  346. return
  347. }
  348. func userKey(uid int64) string {
  349. return fmt.Sprintf(_userCapsuleCoinRedis, uid)
  350. }
  351. func userInfoKey(uid int64, coinId int64) string {
  352. return fmt.Sprintf(_userInfoRedis, uid, coinId)
  353. }
  354. // GetCapsuleChangeFlag 获取扭蛋配置变化标记
  355. func (d *Dao) GetCapsuleChangeFlag(ctx context.Context) (randNum int64, err error) {
  356. conn := d.redis.Get(ctx)
  357. defer conn.Close()
  358. randNum, err = redis.Int64(conn.Do("GET", _capsuleConfRand))
  359. if err != nil {
  360. log.Error("[dao.redis_lottery|GetCapsuleChangeFlag] conn.GET(%s) error(%v)", _capsuleConfRand, err)
  361. return
  362. }
  363. return
  364. }
  365. // GetCapsuleConf 获取扭蛋币配置
  366. func (d *Dao) GetCapsuleConf(ctx context.Context) (conf map[int64]*CapsuleCoinConf, err error) {
  367. capsuleConf.RwLock.RLock()
  368. tmpConf := capsuleConf.CoinConfMap
  369. capsuleConf.RwLock.RUnlock()
  370. if len(tmpConf) == 0 {
  371. redisChangeFlag, _ := d.GetCapsuleChangeFlag(ctx)
  372. tmpConf, err = d.RelaodCapsuleConfig(ctx, redisChangeFlag)
  373. if err != nil || tmpConf == nil || len(tmpConf) == 0 {
  374. log.Error("[dao.capsule | GetCapsuleConf] CapsuleCoinConf is empty")
  375. return nil, err
  376. }
  377. }
  378. now := time.Now().Unix()
  379. conf = make(map[int64]*CapsuleCoinConf)
  380. for coinId := range CoinIdIntMap {
  381. if _, ok := tmpConf[coinId]; ok {
  382. coinConf := tmpConf[coinId]
  383. if coinConf.AllPoolConf != nil && len(coinConf.AllPoolConf) > 0 {
  384. for _, poolConf := range coinConf.AllPoolConf {
  385. if poolConf.StartTime < now && poolConf.EndTime > now {
  386. if _, ok := conf[coinId]; !ok {
  387. conf[coinId] = &CapsuleCoinConf{
  388. Id: coinConf.Id,
  389. Title: coinConf.Title,
  390. GiftType: coinConf.GiftType,
  391. ChangeNum: coinConf.ChangeNum,
  392. StartTime: coinConf.StartTime,
  393. EndTime: coinConf.EndTime,
  394. Status: coinConf.Status,
  395. GiftMap: coinConf.GiftMap,
  396. AreaMap: coinConf.AreaMap,
  397. PoolConf: poolConf,
  398. AllPoolConf: coinConf.AllPoolConf,
  399. }
  400. } else {
  401. if poolConf.IsBottom != IsBottomPool {
  402. conf[coinId] = &CapsuleCoinConf{
  403. Id: coinConf.Id,
  404. Title: coinConf.Title,
  405. GiftType: coinConf.GiftType,
  406. ChangeNum: coinConf.ChangeNum,
  407. StartTime: coinConf.StartTime,
  408. EndTime: coinConf.EndTime,
  409. Status: coinConf.Status,
  410. GiftMap: coinConf.GiftMap,
  411. AreaMap: coinConf.AreaMap,
  412. PoolConf: poolConf,
  413. AllPoolConf: coinConf.AllPoolConf,
  414. }
  415. }
  416. }
  417. }
  418. }
  419. }
  420. }
  421. }
  422. return conf, nil
  423. }
  424. //GetCoinMap 批量获取扭蛋币
  425. func (d *Dao) GetCoinMap(ctx context.Context) (coinMap map[int64]*model.Coin, err error) {
  426. var rows *sql.Rows
  427. if rows, err = d.db.Query(ctx, _getOnCoin); err != nil {
  428. log.Error("[dao.coin | GetCoinMap] query(%s) error(%v)", _getOnCoin, err)
  429. return
  430. }
  431. defer rows.Close()
  432. coinMap = make(map[int64]*model.Coin)
  433. for rows.Next() {
  434. p := &model.Coin{}
  435. if err = rows.Scan(&p.Id, &p.Title, &p.GiftType, &p.ChangeNum, &p.StartTime, &p.EndTime, &p.Status); err != nil {
  436. log.Error("[dao.coin | GetCoinMap] scan error, err %v", err)
  437. return
  438. }
  439. coinMap[p.Id] = p
  440. }
  441. return
  442. }
  443. //GetCoinConfigMap 批量获取扭蛋币
  444. func (d *Dao) GetCoinConfigMap(ctx context.Context, coinIds []int64) (configMap map[int64][]*model.CoinConfig, err error) {
  445. var rows *sql.Rows
  446. stringCoinIds := make([]string, 0)
  447. for _, coinId := range coinIds {
  448. stringCoinIds = append(stringCoinIds, strconv.FormatInt(coinId, 10))
  449. }
  450. coinString := strings.Join(stringCoinIds, ",")
  451. if rows, err = d.db.Query(ctx, fmt.Sprintf(_getCoinConfigMap, coinString)); err != nil {
  452. log.Error("[dao.coin_config | GetCoinConfigMap]query(%s) error(%v)", _getCoinConfigMap, err)
  453. return
  454. }
  455. defer rows.Close()
  456. configMap = make(map[int64][]*model.CoinConfig)
  457. for rows.Next() {
  458. d := &model.CoinConfig{}
  459. if err = rows.Scan(&d.CoinId, &d.Type, &d.AreaV2ParentId, &d.AreaV2Id, &d.GiftId); err != nil {
  460. log.Error("[dao.coin_config | GetCoinConfigMap] scan error, err %v", err)
  461. return
  462. }
  463. configMap[d.CoinId] = append(configMap[d.CoinId], d)
  464. }
  465. return
  466. }
  467. //GetPoolMap 批量奖池信息
  468. func (d *Dao) GetPoolMap(ctx context.Context, coinIds []int64) (poolMap map[int64][]*model.Pool, err error) {
  469. var rows *sql.Rows
  470. stringCoinIds := make([]string, 0)
  471. for _, coinId := range coinIds {
  472. stringCoinIds = append(stringCoinIds, strconv.FormatInt(coinId, 10))
  473. }
  474. coinString := strings.Join(stringCoinIds, ",")
  475. if rows, err = d.db.Query(ctx, fmt.Sprintf(_getPoolMap, coinString)); err != nil {
  476. log.Error("[dao.pool | GetPoolMap]query(%s) error(%v)", _getPoolMap, err)
  477. return
  478. }
  479. defer rows.Close()
  480. poolMap = make(map[int64][]*model.Pool)
  481. for rows.Next() {
  482. d := &model.Pool{}
  483. if err = rows.Scan(&d.Id, &d.CoinId, &d.Title, &d.Description, &d.StartTime, &d.EndTime, &d.Status, &d.IsBottom); err != nil {
  484. log.Error("[dao.pool |GetPoolMap] scan error, err %v", err)
  485. return
  486. }
  487. if _, ok := poolMap[d.CoinId]; !ok {
  488. poolMap[d.CoinId] = make([]*model.Pool, 0)
  489. }
  490. poolMap[d.CoinId] = append(poolMap[d.CoinId], d)
  491. }
  492. return
  493. }
  494. // GetPoolPrizeMap 批量奖池奖品
  495. func (d *Dao) GetPoolPrizeMap(ctx context.Context, poolIds []int64) (poolPrizeMap map[int64][]*model.PoolPrize, err error) {
  496. var rows *sql.Rows
  497. stringPoolIds := make([]string, 0)
  498. for _, poolId := range poolIds {
  499. stringPoolIds = append(stringPoolIds, strconv.FormatInt(poolId, 10))
  500. }
  501. poolString := strings.Join(stringPoolIds, ",")
  502. if rows, err = d.db.Query(ctx, fmt.Sprintf(_getPoolPrizeMap, poolString)); err != nil {
  503. log.Error("[dao.pool_prize | GetPoolPrizeMap] query(%s) error(%v)", _getPoolPrizeMap, err)
  504. return
  505. }
  506. defer rows.Close()
  507. poolPrizeMap = make(map[int64][]*model.PoolPrize)
  508. for rows.Next() {
  509. d := &model.PoolPrize{}
  510. if err = rows.Scan(&d.Id, &d.PoolId, &d.Type, &d.Num, &d.ObjectId, &d.Expire, &d.WebUrl, &d.MobileUrl, &d.Description, &d.JumpUrl, &d.ProType, &d.Chance, &d.LoopNum, &d.LimitNum, &d.Weight); err != nil {
  511. log.Error("[dao.pool_prize | GetPoolPrizeMap] scan error, err %v", err)
  512. return
  513. }
  514. if _, ok := PrizeNameMap[d.Type]; !ok {
  515. continue
  516. }
  517. poolPrizeMap[d.PoolId] = append(poolPrizeMap[d.PoolId], d)
  518. }
  519. return
  520. }
  521. // RelaodCapsuleConfig 重新加载扭蛋配置
  522. func (d *Dao) RelaodCapsuleConfig(ctx context.Context, changeFlag int64) (conf map[int64]*CapsuleCoinConf, err error) {
  523. coinMap, err := d.GetCoinMap(ctx)
  524. if err != nil || len(coinMap) == 0 {
  525. log.Error("[dao.capsule | RelaodCapsuleConfig] coinMap is empty")
  526. return
  527. }
  528. coinIds := make([]int64, len(coinMap))
  529. ix := 0
  530. for _, coinInfo := range coinMap {
  531. coinIds[ix] = coinInfo.Id
  532. ix++
  533. }
  534. coinConfigMap, err := d.GetCoinConfigMap(ctx, coinIds)
  535. if err != nil || len(coinConfigMap) == 0 {
  536. log.Error("[dao.capsule | RelaodCapsuleConfig] CoinConfigMap is empty")
  537. return
  538. }
  539. poolMap, err := d.GetPoolMap(ctx, coinIds)
  540. if err != nil || len(poolMap) == 0 {
  541. log.Error("[dao.capsule | RelaodCapsuleConfig] PoolMap is empty")
  542. return
  543. }
  544. poolIds := make([]int64, 0)
  545. for _, pools := range poolMap {
  546. for _, pool := range pools {
  547. poolIds = append(poolIds, pool.Id)
  548. }
  549. }
  550. poolPrizeMap, err := d.GetPoolPrizeMap(ctx, poolIds)
  551. if err != nil || len(poolPrizeMap) == 0 {
  552. log.Error("[dao.capsule | RelaodCapsuleConfig] PoolPrizeMap is empty")
  553. return
  554. }
  555. coinConfMap := make(map[int64]*CapsuleCoinConf)
  556. ids := make([]int64, 0)
  557. idMap := make(map[int64]struct{})
  558. for _, prizeList := range poolPrizeMap {
  559. for _, prize := range prizeList {
  560. if prize.ObjectId != 0 && prize.Type == CapsulePrizeTitleType {
  561. if _, ok := idMap[prize.ObjectId]; !ok {
  562. ids = append(ids, prize.ObjectId)
  563. idMap[prize.ObjectId] = struct{}{}
  564. }
  565. }
  566. }
  567. }
  568. titleMap := make(map[int64]string)
  569. if len(ids) != 0 {
  570. TitleData, err1 := RcApi.V1UserTitle.GetTitleByIds(ctx, &v12.UserTitleGetTitleByIdsReq{Ids: ids})
  571. if err1 != nil {
  572. log.Error("[dao.capsule | RelaodCapsuleConfig] GetTitleByIds error")
  573. }
  574. if TitleData != nil && TitleData.Data != nil {
  575. titleMap = TitleData.Data
  576. }
  577. }
  578. for coinId, coinConf := range coinMap {
  579. conf := &CapsuleCoinConf{}
  580. conf.Status = coinConf.Status
  581. conf.GiftType = coinConf.GiftType
  582. conf.Title = coinConf.Title
  583. conf.EndTime = coinConf.EndTime
  584. conf.StartTime = coinConf.StartTime
  585. conf.Id = coinConf.Id
  586. conf.ChangeNum = coinConf.ChangeNum
  587. if _, ok := coinConfigMap[coinId]; ok {
  588. coinConfig := coinConfigMap[coinId]
  589. gifts := make(map[int64]struct{})
  590. areas := make(map[int64]struct{})
  591. for _, config := range coinConfig {
  592. if config.GiftId > 0 {
  593. gifts[config.GiftId] = struct{}{}
  594. }
  595. if config.AreaV2ParentId > 0 {
  596. areas[config.AreaV2Id] = struct{}{}
  597. }
  598. }
  599. conf.AreaMap = areas
  600. conf.GiftMap = gifts
  601. }
  602. if _, ok := poolMap[coinId]; ok {
  603. for _, poolConf := range poolMap[coinId] {
  604. pool := &CapsulePoolConf{}
  605. pool.Id = poolConf.Id
  606. pool.StartTime = poolConf.StartTime
  607. pool.EndTime = poolConf.EndTime
  608. pool.Title = poolConf.Title
  609. pool.Status = poolConf.Status
  610. pool.Rule = poolConf.Description
  611. pool.CoinId = poolConf.CoinId
  612. pool.IsBottom = poolConf.IsBottom
  613. if _, ok := poolPrizeMap[pool.Id]; ok {
  614. prizeConfigs := poolPrizeMap[pool.Id]
  615. pool.PoolPrize = make([]*CapsulePoolPrize, len(poolPrizeMap[pool.Id]))
  616. for ix, prizeConfig := range prizeConfigs {
  617. name := PrizeNameMap[prizeConfig.Type]
  618. if prizeConfig.Type == CapsulePrizeTitleType && titleMap != nil {
  619. if _, ok := titleMap[prizeConfig.ObjectId]; ok {
  620. name = titleMap[prizeConfig.ObjectId]
  621. }
  622. }
  623. prize := &CapsulePoolPrize{
  624. Id: prizeConfig.Id,
  625. PoolId: prizeConfig.PoolId,
  626. Type: prizeConfig.Type,
  627. Num: prizeConfig.Num,
  628. ObjectId: prizeConfig.ObjectId,
  629. Expire: prizeConfig.Expire,
  630. Name: name,
  631. WebImage: prizeConfig.WebUrl,
  632. MobileImage: prizeConfig.MobileUrl,
  633. Description: prizeConfig.Description,
  634. JumpUrl: prizeConfig.JumpUrl,
  635. ProType: prizeConfig.ProType,
  636. Chance: prizeConfig.Chance,
  637. LoopNum: prizeConfig.LoopNum,
  638. LimitNum: prizeConfig.LimitNum,
  639. Weight: prizeConfig.Weight,
  640. }
  641. pool.PoolPrize[ix] = prize
  642. }
  643. }
  644. if conf.AllPoolConf == nil {
  645. conf.AllPoolConf = make([]*CapsulePoolConf, 0)
  646. }
  647. conf.AllPoolConf = append(conf.AllPoolConf, pool)
  648. }
  649. }
  650. coinConfMap[coinId] = conf
  651. }
  652. cacheTime := time.Now().Unix()
  653. capsuleConf.RwLock.Lock()
  654. capsuleConf.CacheTime = cacheTime
  655. capsuleConf.ChangeFlag = changeFlag
  656. capsuleConf.CoinConfMap = coinConfMap
  657. capsuleConf.RwLock.Unlock()
  658. log.Info("[dao.capsule | RelaodCapsuleConfig] reload conf")
  659. return coinConfMap, nil
  660. }
  661. func getCapsuleTable(Uid int64) int64 {
  662. return Uid % 10
  663. }
  664. // UpdateScore 更新扭蛋币积分
  665. func (d *Dao) UpdateScore(ctx context.Context, uid, coinId, score int64, action, platform string, userInfo map[int64]int64, coinConf *CapsuleCoinConf) (affect int64, err error) {
  666. var (
  667. sqlStr, uKey, iKey string
  668. )
  669. if _, ok := userInfo[coinId]; !ok {
  670. userInfo, _ = d.GetUserCapsuleInfo(ctx, uid)
  671. }
  672. if action == CapsuleActionTrans {
  673. sqlStr = fmt.Sprintf(_transUserCapsuleMysql, getCapsuleTable(uid))
  674. } else {
  675. sqlStr = fmt.Sprintf(_updateUserCapsuleMysql, getCapsuleTable(uid), CoinIdIntMap[coinId], CoinIdIntMap[coinId])
  676. }
  677. conn := d.redis.Get(ctx)
  678. defer conn.Close()
  679. uKey = userKey(uid)
  680. iKey = userInfoKey(uid, coinId)
  681. affect, err = d.execSqlWithBindParams(ctx, &sqlStr, score, uid)
  682. if err != nil {
  683. log.Error("[dao.mysql_lottery|updateScore] uid(%d) type(%d) score(%d) error(%v)", uid, coinId, score, err)
  684. _, e := conn.Do("DEL", uKey, iKey)
  685. if e != nil {
  686. log.Error("[dao.redis_lottery|updateScore] conn.DEL(%s, %s) error(%v)", uKey, iKey, e)
  687. }
  688. return
  689. }
  690. _, e := conn.Do("DEL", uKey, iKey)
  691. if e != nil {
  692. log.Error("[dao.redis_lottery|updateScore] conn.DEL(%s, %s) error(%v)", uKey, iKey, e)
  693. }
  694. d.ReportCapsuleChange(ctx, coinId, uid, score, action, platform, userInfo, coinConf)
  695. return
  696. }
  697. // UpdateCapsule 更新扭蛋币积分
  698. func (d *Dao) UpdateCapsule(ctx context.Context, uid, coinId, score int64, action, platform string, coinConf *CapsuleCoinConf) (affect int64, err error) {
  699. var (
  700. sqlStr, uKey, iKey string
  701. )
  702. userInfo, _ := d.GetUserInfo(ctx, uid, coinId)
  703. sqlStr = fmt.Sprintf(_updateUserInfoMysql, getCapsuleTable(uid))
  704. conn := d.redis.Get(ctx)
  705. defer conn.Close()
  706. uKey = userKey(uid)
  707. iKey = userInfoKey(uid, coinId)
  708. affect, err = d.execSqlWithBindParams(ctx, &sqlStr, score, uid, CoinIdIntMap[coinId])
  709. if err != nil {
  710. log.Error("[dao.mysql_lottery|UpdateCapsule] uid(%d) type(%d) score(%d) error(%v)", uid, coinId, score, err)
  711. _, e := conn.Do("DEL", uKey, iKey)
  712. if e != nil {
  713. log.Error("[dao.redis_lottery|UpdateCapsule] conn.DEL(%s, %s) error(%v)", uKey, iKey, e)
  714. }
  715. return
  716. }
  717. _, e := conn.Do("DEL", uKey, iKey)
  718. if e != nil {
  719. log.Error("[dao.redis_lottery|UpdateCapsule] conn.DEL(%s, %s) error(%v)", uKey, iKey, e)
  720. }
  721. d.ReportCapsuleChange(ctx, coinId, uid, score, action, platform, userInfo, coinConf)
  722. return
  723. }
  724. // GetUserCapsuleInfo 获取扭蛋币积分
  725. func (d *Dao) GetUserCapsuleInfo(c context.Context, uid int64) (coinMap map[int64]int64, err error) {
  726. var (
  727. isEmpty bool
  728. uKey string
  729. normalScore int64
  730. colorfulScore int64
  731. )
  732. uKey = userKey(uid)
  733. conn := d.redis.Get(c)
  734. defer conn.Close()
  735. uInfo, err := redis.Int64Map(conn.Do("HGETALL", uKey))
  736. if err != nil {
  737. if err == redis.ErrNil {
  738. isEmpty = true
  739. err = nil
  740. } else {
  741. log.Error("[dao.redis_lottery|setUserCapsuleInfoCache] getUserCapsuleInfoCache conn.HMGET(%s) error(%v)", uKey, err)
  742. return
  743. }
  744. } else if len(uInfo) == 0 {
  745. isEmpty = true
  746. }
  747. coinMap = make(map[int64]int64)
  748. if isEmpty {
  749. sqlStr := fmt.Sprintf(_userCapsuleCoinMysql, getCapsuleTable(uid))
  750. row := d.db.QueryRow(c, sqlStr, uid)
  751. err = row.Scan(&normalScore, &colorfulScore)
  752. if err != nil && err != sql.ErrNoRows {
  753. return
  754. }
  755. if err == sql.ErrNoRows {
  756. sqlStr := fmt.Sprintf(_addCapsuleCoinMysql, getCapsuleTable(uid))
  757. _, err = d.db.Exec(c, sqlStr, uid, 0, 0)
  758. if err != nil {
  759. log.Error("[dao.redis_lottery|GetUserCapsuleInfo] init sql(%s) uid(%d) error(%v)", sqlStr, uid, err)
  760. return
  761. }
  762. normalScore, colorfulScore = 0, 0
  763. }
  764. _, err = conn.Do("HMSET", uKey, CoinIdIntMap[NormalCoinId], normalScore, CoinIdIntMap[ColorfulCoinId], colorfulScore)
  765. if err != nil {
  766. log.Error("[dao.redis_lottery|GetUserCapsuleInfo] setUserCapsuleInfoCache conn.HMSET(%s) error(%v)", uKey, err)
  767. }
  768. coinMap[NormalCoinId] = normalScore
  769. coinMap[ColorfulCoinId] = colorfulScore
  770. err = nil
  771. } else {
  772. if _, ok := uInfo[CoinIdIntMap[NormalCoinId]]; ok {
  773. coinMap[NormalCoinId] = uInfo[CoinIdIntMap[NormalCoinId]]
  774. }
  775. if _, ok := uInfo[CoinIdIntMap[ColorfulCoinId]]; ok {
  776. coinMap[ColorfulCoinId] = uInfo[CoinIdIntMap[ColorfulCoinId]]
  777. }
  778. }
  779. return
  780. }
  781. // GetUserInfo 获取扭蛋币详情
  782. func (d *Dao) GetUserInfo(c context.Context, uid, coinId int64) (coinMap map[int64]int64, err error) {
  783. if coinId <= ColorfulCoinId {
  784. return d.GetUserCapsuleInfo(c, uid)
  785. }
  786. var (
  787. isEmpty bool
  788. uKey string
  789. )
  790. uKey = userInfoKey(uid, coinId)
  791. conn := d.redis.Get(c)
  792. defer conn.Close()
  793. score, err := redis.Int64(conn.Do("GET", uKey))
  794. if err != nil {
  795. if err == redis.ErrNil {
  796. isEmpty = true
  797. err = nil
  798. } else {
  799. log.Error("[dao.redis_lottery|setUserCapsuleInfoCache] getUserInfoCache conn.HMGET(%s) error(%v)", uKey, err)
  800. return
  801. }
  802. }
  803. coinMap = make(map[int64]int64)
  804. if isEmpty {
  805. sqlStr := fmt.Sprintf(_userInfoMysql, getCapsuleTable(uid))
  806. row := d.db.QueryRow(c, sqlStr, uid, CoinIdIntMap[coinId])
  807. err = row.Scan(&score)
  808. if err != nil && err != sql.ErrNoRows {
  809. return
  810. }
  811. if err == sql.ErrNoRows {
  812. sqlStr := fmt.Sprintf(_addInfoMysql, getCapsuleTable(uid))
  813. _, err = d.db.Exec(c, sqlStr, uid, CoinIdIntMap[coinId], 0)
  814. if err != nil {
  815. return
  816. }
  817. score = 0
  818. }
  819. _, err = conn.Do("SET", uKey, score)
  820. if err != nil {
  821. log.Error("[dao.redis_lottery|GetUserInfo] setUserCapsuleInfoCache conn.HMSET(%s) error(%v)", uKey, err)
  822. }
  823. coinMap[coinId] = score
  824. err = nil
  825. } else {
  826. coinMap[coinId] = score
  827. }
  828. return
  829. }
  830. // ReportCapsuleChange 通知扭蛋积分变换
  831. func (d *Dao) ReportCapsuleChange(ctx context.Context, coinId, uid, score int64, action, platform string, pInfo map[int64]int64, coinConf *CapsuleCoinConf) bool {
  832. if _, ok := pInfo[coinId]; !ok {
  833. return false
  834. }
  835. chnageType := coinId
  836. cInfo, err := d.GetUserInfo(ctx, uid, coinId)
  837. if err != nil {
  838. return false
  839. }
  840. if _, ok := cInfo[coinId]; !ok {
  841. return false
  842. }
  843. change := d.GetCoin(cInfo[coinId], coinConf) - d.GetCoin(pInfo[coinId], coinConf)
  844. if change > 0 {
  845. d.AddNotice(ctx, uid, coinId, change)
  846. }
  847. var normalPreScore, colorPreScore, normalNowScore, colorNowScore int64
  848. if coinId <= ColorfulCoinId {
  849. if action == CapsuleActionTrans {
  850. chnageType = 5
  851. } else {
  852. if score < 0 {
  853. chnageType += 2
  854. score = -score
  855. }
  856. }
  857. normalPreScore, colorPreScore, normalNowScore, colorNowScore = pInfo[NormalCoinId], pInfo[ColorfulCoinId], cInfo[NormalCoinId], cInfo[ColorfulCoinId]
  858. } else {
  859. chnageType = coinId * 10
  860. if score < 0 {
  861. chnageType += 1
  862. }
  863. normalPreScore, colorPreScore, normalNowScore, colorNowScore = 0, pInfo[coinId], 0, cInfo[coinId]
  864. }
  865. date := time.Now().Format("200601")
  866. sqlStr := fmt.Sprintf(_reportCapsuleChangeMysql, date)
  867. affect, _ := d.execSqlWithBindParams(ctx, &sqlStr, uid, chnageType, score, action, platform, normalPreScore, colorPreScore, normalNowScore, colorNowScore)
  868. var rcontent string
  869. if _, ok := ReprotConfig[chnageType]; ok {
  870. rcontent = ReprotConfig[chnageType]
  871. }
  872. if rcontent == "" {
  873. if chnageType%10 == 0 {
  874. rcontent = "减少" + coinConf.Title
  875. } else if chnageType%10 == 1 {
  876. rcontent = "增加" + coinConf.Title
  877. } else if chnageType%10 == 2 {
  878. rcontent = "转化" + coinConf.Title
  879. }
  880. }
  881. report.User(&report.UserInfo{
  882. Platform: platform,
  883. Business: 101, // 101 102 103 104 105 106
  884. Type: int(chnageType),
  885. Oid: uid,
  886. Action: "capsule_change",
  887. Ctime: time.Now(),
  888. Index: []interface{}{
  889. rcontent,
  890. score,
  891. normalNowScore,
  892. colorNowScore,
  893. action,
  894. },
  895. })
  896. return affect > 0
  897. }
  898. // GetCoin 获取扭蛋数量
  899. func (d *Dao) GetCoin(score int64, coinConf *CapsuleCoinConf) (coinNum int64) {
  900. if coinConf == nil || coinConf.ChangeNum == 0 {
  901. return 0
  902. }
  903. coinNum = score / coinConf.ChangeNum
  904. return
  905. }
  906. // AddNotice 增加标记
  907. func (d *Dao) AddNotice(ctx context.Context, uid, coinId, coinNum int64) {
  908. nKey := fmt.Sprintf(_capsuleNotice, CoinIdIntMap[coinId], uid)
  909. conn := d.redis.Get(ctx)
  910. defer conn.Close()
  911. _, err := conn.Do("SET", nKey, coinNum, "EX", 30*86400)
  912. if err != nil {
  913. log.Error("[dao.redis_lottery|AddNotice] conn.SET(%s) error(%v)", nKey, err)
  914. }
  915. }
  916. // GetCapsuleChangeInfo 获取扭蛋配置信息
  917. func (d *Dao) GetCapsuleChangeInfo(ctx context.Context) (int64, int64) {
  918. capsuleConf.RwLock.RLock()
  919. CacheTime := capsuleConf.CacheTime
  920. ChangeFlag := capsuleConf.ChangeFlag
  921. capsuleConf.RwLock.RUnlock()
  922. return CacheTime, ChangeFlag
  923. }
  924. // CheckLplFirstGift 检测是否首次送礼
  925. func (d *Dao) CheckLplFirstGift(ctx context.Context, uid, giftId int64) bool {
  926. var (
  927. value int64
  928. extra string
  929. day string
  930. cType string
  931. )
  932. day = time.Now().Format("2006-01-02")
  933. cType = "lpl" + day
  934. nKey := fmt.Sprintf(_lplSendGiftRedis, day, uid)
  935. conn := d.redis.Get(ctx)
  936. defer conn.Close()
  937. _, err := redis.Int64(conn.Do("GET", nKey))
  938. log.Info("[dao.redis_lottery|CheckLplFirstGift] conn.GET(%s) error(%v)", nKey, err)
  939. if err == redis.ErrNil {
  940. row := d.db.QueryRow(ctx, _getExtraDataMysql, uid, cType)
  941. err = row.Scan(&value, &extra)
  942. if err == sql.ErrNoRows {
  943. _, err = d.db.Exec(ctx, _addExtraDataMysql, uid, cType, time.Now().Unix(), strconv.FormatInt(giftId, 10))
  944. if err != nil {
  945. log.Error("[dao.redis_lottery|CheckLplFirstGift] conn.addExtraData(%s) error(%v)", nKey, err)
  946. return false
  947. }
  948. return true
  949. }
  950. if err != nil {
  951. log.Error("[dao.redis_lottery|CheckLplFirstGift] conn.getExtraData(%s) error(%v)", nKey, err)
  952. return false
  953. }
  954. _, err = conn.Do("SET", nKey, 1, "EX", 86400)
  955. if err != nil {
  956. log.Error("[dao.redis_lottery|CheckLplFirstGift] conn.SET(%s) error(%v)", nKey, err)
  957. }
  958. return false
  959. }
  960. if err != nil {
  961. log.Error("[dao.redis_lottery|CheckLplFirstGift] conn.GET(%s) error(%v)", nKey, err)
  962. }
  963. return false
  964. }
  965. // GetExtraDataByTime 获取数据
  966. func (d *Dao) GetExtraDataByTime(ctx context.Context, startTime, endTime string) (extraData []*model.ExtraData, err error) {
  967. var rows *sql.Rows
  968. if rows, err = d.db.Query(ctx, _getExtraDataByTimeMysql, startTime, endTime); err != nil {
  969. log.Error("[dao.extra | GetExtraDataByType] query(%s) error (%v)", _getExtraDataByTimeMysql, err)
  970. return
  971. }
  972. log.Info("[dao.extra | GetExtraDataByType] start(%d) end(%s)", startTime, endTime)
  973. defer rows.Close()
  974. extraData = make([]*model.ExtraData, 0)
  975. for rows.Next() {
  976. p := &model.ExtraData{}
  977. if err = rows.Scan(&p.Id, &p.Uid, &p.Type, &p.ItemValue, &p.ItemExtra); err != nil {
  978. log.Error("[dao.extra | GetExtraDataByType] scan error, err %v", err)
  979. return
  980. }
  981. extraData = append(extraData, p)
  982. }
  983. return
  984. }
  985. // UpdateExtraValueById 更新数据
  986. func (d *Dao) UpdateExtraValueById(ctx context.Context, id int64, itemValue int64) (status bool, err error) {
  987. res, err := d.db.Exec(ctx, _updateExtraValueMysql, itemValue, id)
  988. if err != nil {
  989. log.Error("[dao.extra | UpdateExtraValue] update(%s) error(%v)", _updateExtraValueMysql, err)
  990. return false, err
  991. }
  992. var rows int64
  993. rows, err = res.RowsAffected()
  994. if err != nil {
  995. log.Error("[dao.extra | UpdateExtraValue] err %v", err)
  996. return false, err
  997. }
  998. return rows > 0, nil
  999. }
  1000. // UpdateExtraMtimeById 更新时间数据
  1001. func (d *Dao) UpdateExtraMtimeById(ctx context.Context, id int64, mtime string) (status bool, err error) {
  1002. res, err := d.db.Exec(ctx, _updateExtraMtimeMysql, mtime, id)
  1003. if err != nil {
  1004. log.Error("[dao.extra | UpdateExtraMtimeById] update(%s) error(%v)", _updateExtraMtimeMysql, err)
  1005. return false, err
  1006. }
  1007. var rows int64
  1008. rows, err = res.RowsAffected()
  1009. if err != nil {
  1010. log.Error("[dao.extra | UpdateExtraMtimeById] err %v", err)
  1011. return false, err
  1012. }
  1013. return rows > 0, nil
  1014. }
  1015. // UpdateExtraById 更新数据
  1016. func (d *Dao) UpdateExtraById(ctx context.Context, id int64, itemValue int64, itemExtra string) (status bool, err error) {
  1017. res, err := d.db.Exec(ctx, _updateExtraMysql, itemValue, itemExtra, id)
  1018. if err != nil {
  1019. log.Error("[dao.extra | UpdateExtraById] update(%s) error(%v)", _updateExtraMysql, err)
  1020. return false, err
  1021. }
  1022. var rows int64
  1023. rows, err = res.RowsAffected()
  1024. if err != nil {
  1025. log.Error("[dao.extra | UpdateExtraById] err %v", err)
  1026. return false, err
  1027. }
  1028. return rows > 0, nil
  1029. }
  1030. // GetExtraDataByIds 获取数据
  1031. func (d *Dao) GetExtraDataByIds(ctx context.Context, start, end int64) (extraData []*model.ExtraData, err error) {
  1032. var rows *sql.Rows
  1033. if rows, err = d.db.Query(ctx, _getExtraDataByIdMysql, start, end); err != nil {
  1034. log.Error("[dao.capsule | GetExtraDataByIds]query(%s) error(%v)", _getUserInfoById, err)
  1035. return
  1036. }
  1037. defer rows.Close()
  1038. extraData = make([]*model.ExtraData, 0)
  1039. for rows.Next() {
  1040. p := &model.ExtraData{}
  1041. if err = rows.Scan(&p.Id, &p.Uid, &p.Type, &p.ItemValue, &p.ItemExtra); err != nil {
  1042. log.Error("[dao.capsule | GetExtraDataByIds] scan error, err %v", err)
  1043. return
  1044. }
  1045. extraData = append(extraData, p)
  1046. }
  1047. return
  1048. }
  1049. // GetCouponData 添加数据
  1050. func (d *Dao) GetCouponData(ctx context.Context) (extraData []*model.ExtraData, err error) {
  1051. var i, maxId int64
  1052. row := d.db.QueryRow(ctx, _getExtraDataMaxIdMysql)
  1053. if err = row.Scan(&maxId); err != nil {
  1054. log.Error("[dao.capsule | GetCouponData] query(%s),err(%v)", _getExtraDataMaxIdMysql, err)
  1055. return
  1056. }
  1057. extraData = make([]*model.ExtraData, 0)
  1058. for i = 0; i < maxId; i = i + 10000 {
  1059. var curExtraData []*model.ExtraData
  1060. curExtraData, err = d.GetExtraDataByIds(ctx, i, i+10000)
  1061. if err != nil {
  1062. return
  1063. }
  1064. for _, extra := range curExtraData {
  1065. if extra.ItemValue != 0 {
  1066. continue
  1067. }
  1068. if !strings.HasPrefix(extra.Type, "CouponRetry") {
  1069. continue
  1070. }
  1071. extraData = append(extraData, extra)
  1072. }
  1073. }
  1074. return
  1075. }