admin_email.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "entrance-grpc/iam"
  6. "fmt"
  7. "gadmin/config"
  8. "gadmin/internal/admin/consts"
  9. "gadmin/internal/admin/forms"
  10. "gadmin/internal/admin/gm_rpc/rpc_share"
  11. "gadmin/internal/gorm/model"
  12. "gadmin/internal/gorm/query"
  13. "gadmin/package/gmdata"
  14. "gadmin/utility"
  15. "gadmin/utility/character"
  16. "gadmin/utility/player"
  17. "gadmin/utility/serializer"
  18. "gadmin/utility/token"
  19. "github.com/gin-gonic/gin"
  20. "github.com/sirupsen/logrus"
  21. "github.com/spf13/cast"
  22. "github.com/xuri/excelize/v2"
  23. model2 "leafstalk/covenant/model"
  24. msg2 "leafstalk/covenant/msg"
  25. "strconv"
  26. "strings"
  27. "time"
  28. )
  29. // AdminEmail 邮件
  30. var AdminEmail = new(sAdminEmail)
  31. type sAdminEmail struct{}
  32. type Ret struct {
  33. model.AdminEmail
  34. Sender string `json:"sender"`
  35. }
  36. type Ext struct {
  37. Id string `json:"id"`
  38. Count string `json:"count"`
  39. }
  40. func (s *sAdminEmail) List(ctx *gin.Context, req forms.AdminEmailListReq) serializer.Response {
  41. var (
  42. q = query.Use(config.DB).AdminEmail
  43. m = q.WithContext(ctx)
  44. //u = query.Use(config.DB).AdminUser
  45. offset int64 = 0
  46. models forms.UserAccountListRes
  47. lists []*Ret
  48. )
  49. req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
  50. models.Page = req.Page
  51. models.PerPage = req.PerPage
  52. if req.Sender != "" {
  53. first, err := config.GetIamClient().GetAdminUserByNickName(ctx, &iam.GetAdminUserByNickNameReq{
  54. NickName: req.Sender,
  55. })
  56. if err == nil && first.Code == 0 {
  57. m = m.Where(q.OperatorID.Eq(first.Data.ID))
  58. }
  59. }
  60. if req.OperatorId > 0 {
  61. m = m.Where(q.OperatorID.Eq(req.OperatorId))
  62. }
  63. if len(req.CreatedAt) == 2 {
  64. m = m.Where(q.CreatedAt.Between(req.CreatedAt[0], req.CreatedAt[1]))
  65. }
  66. m = m.Order(q.ID.Desc())
  67. count, err := m.Count()
  68. if err != nil {
  69. return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
  70. }
  71. if count == 0 {
  72. return serializer.Suc(models)
  73. }
  74. if req.IsExport == 1 {
  75. if err = m.Scan(&lists); err != nil {
  76. return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
  77. }
  78. err = s.Export(ctx, lists)
  79. if err != nil {
  80. return serializer.Err(consts.CodeParamErr, "导出错误", err)
  81. }
  82. return serializer.Response{}
  83. }
  84. if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
  85. return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
  86. }
  87. uIdMap := make(map[int64]struct{})
  88. for i, v := range lists {
  89. if v.OperatorID > 0 {
  90. uIdMap[v.OperatorID] = struct{}{}
  91. }
  92. lists[i].PlayerIds = strings.Replace(v.PlayerIds, "[", "", -1)
  93. lists[i].PlayerIds = strings.Replace(v.PlayerIds, "]", "", -1)
  94. lists[i].PlayerIds = strings.Replace(v.PlayerIds, "\"", "", -1)
  95. }
  96. uIds := make([]int64, 0, len(lists))
  97. for uid := range uIdMap {
  98. uIds = append(uIds, uid)
  99. }
  100. res, err := config.GetIamClient().BatchGetAdminUser(context.Background(), &iam.BatchGetAdminUserReq{UIds: uIds})
  101. if err != nil || res.Code != 0 {
  102. return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
  103. }
  104. uMap := make(map[int64]*iam.AdminUserInfo)
  105. for _, usr := range res.Data {
  106. uMap[usr.ID] = usr
  107. }
  108. for _, item := range lists {
  109. item.Sender = uMap[item.OperatorID].NickName
  110. }
  111. models.List = lists
  112. models.PageCount = (count + req.PerPage - 1) / req.PerPage
  113. return serializer.Suc(models)
  114. }
  115. func (s *sAdminEmail) Verify(ctx *gin.Context, req forms.AdminEmailVerifyReq) serializer.Response {
  116. var q = query.Use(config.DB).AdminEmail
  117. first, err := q.WithContext(ctx).Where(q.ID.Eq(req.Id)).First()
  118. if err != nil {
  119. return serializer.ParamErr(err.Error(), err)
  120. }
  121. if first == nil {
  122. return serializer.ParamErr("邮件不存在", nil)
  123. }
  124. if first.Status != consts.EmailStatusVerify {
  125. return serializer.ParamErr("当前邮件状态非审核状态,操作失败!", nil)
  126. }
  127. // 拒绝发送
  128. if req.VerifyStatus == 2 {
  129. _, err2 := q.WithContext(ctx).Where(q.ID.Eq(first.ID)).Updates(model.AdminEmail{
  130. Status: consts.EmailStatusCanceled,
  131. })
  132. if err2 != nil {
  133. return serializer.ParamErr(err.Error(), err)
  134. }
  135. return serializer.Suc(nil)
  136. }
  137. // 同意发送,进入发送环节
  138. var status int32
  139. // 立即发送,进入发送中状态
  140. if first.SendType == 1 {
  141. status = consts.EmailStatusIn
  142. }
  143. // 延迟发送
  144. if first.SendType == 2 {
  145. status = consts.EmailStatusWait
  146. }
  147. // 先更新数据
  148. if _, err = q.WithContext(ctx).Where(q.ID.Eq(first.ID)).Updates(model.AdminEmail{Status: status}); err != nil {
  149. return serializer.ParamErr(err.Error(), err)
  150. }
  151. // 立即发送
  152. if status == consts.EmailStatusIn {
  153. q := query.Use(config.DB).AdminEmail
  154. if err = s.SendEmailToWorld(first); err != nil {
  155. logrus.Warnf("邮件发送失败-3:%+v", err)
  156. _, err2 := q.WithContext(ctx).Where(q.ID.Eq(first.ID)).Updates(model.AdminEmail{Status: consts.EmailStatusErr})
  157. if err2 != nil {
  158. logrus.Warnf("邮件更新失败:%+v", err2)
  159. }
  160. return serializer.ParamErr(err.Error(), err)
  161. }
  162. // 发送成功
  163. _, err2 := q.WithContext(ctx).Where(q.ID.Eq(first.ID)).Updates(model.AdminEmail{
  164. Status: consts.EmailStatusSent,
  165. SendAt: time.Now().Unix(),
  166. })
  167. if err2 != nil {
  168. logrus.Warnf("邮件更新失败-2:%+v", err2)
  169. }
  170. }
  171. return serializer.Suc(nil)
  172. }
  173. func (s *sAdminEmail) Add(ctx *gin.Context, req forms.AdminEmailAddReq) serializer.Response {
  174. ext, err := json.Marshal(req.Ext)
  175. if err != nil {
  176. return serializer.ParamErr(err.Error(), err)
  177. }
  178. serverIds, err := json.Marshal(req.ServerIds)
  179. if err != nil {
  180. return serializer.ParamErr(err.Error(), err)
  181. }
  182. playerIds, err := json.Marshal(req.PlayerIds)
  183. if err != nil {
  184. return serializer.ParamErr(err.Error(), err)
  185. }
  186. var status int32
  187. // 立即发送,进入发送中状态
  188. if req.SendType == 1 {
  189. status = consts.EmailStatusIn
  190. }
  191. // 延迟发送
  192. if req.SendType == 2 {
  193. status = consts.EmailStatusWait
  194. }
  195. // 非超管发送全服或指定服邮件直接进入待审核状态
  196. if ctx.GetInt64("admin_role_id") != 1 {
  197. status = consts.EmailStatusVerify
  198. }
  199. logrus.Warnf("AdminEmailAdd req:%+v", utility.DumpToJSON(req))
  200. data := &model.AdminEmail{
  201. ID: 0,
  202. Title: req.Title,
  203. Content: req.Content,
  204. Ext: string(ext),
  205. SendType: req.SendType,
  206. SendAt: req.SendAt,
  207. Expired: req.Expired,
  208. ReceiptType: req.ReceiptType,
  209. ServerIds: string(serverIds),
  210. PlayerIds: string(playerIds),
  211. OperatorID: token.GetUID(ctx),
  212. Status: status,
  213. UpdatedAt: time.Now().Unix(),
  214. CreatedAt: time.Now().Unix(),
  215. Remark: req.Remark,
  216. }
  217. logrus.Warnf("AdminEmailAdd data:%+v", utility.DumpToJSON(data))
  218. if err = query.Use(config.DB).AdminEmail.WithContext(ctx).Create(data); err != nil {
  219. return serializer.ParamErr(err.Error(), err)
  220. }
  221. logrus.Infof("新增邮件内容:%+v", utility.DumpToJSON(data))
  222. // 立即发送
  223. if status == consts.EmailStatusIn {
  224. q := query.Use(config.DB).AdminEmail
  225. if err = s.SendEmailToWorld(data); err != nil {
  226. logrus.Warnf("邮件发送失败:%+v", err)
  227. _, err2 := q.WithContext(ctx).Where(q.ID.Eq(data.ID)).Updates(model.AdminEmail{Status: consts.EmailStatusErr})
  228. if err2 != nil {
  229. logrus.Warnf("邮件更新失败:%+v", err2)
  230. }
  231. return serializer.ParamErr(err.Error(), err)
  232. }
  233. // 发送成功
  234. _, err2 := q.WithContext(ctx).Where(q.ID.Eq(data.ID)).Updates(model.AdminEmail{
  235. Status: consts.EmailStatusSent,
  236. SendAt: time.Now().Unix(),
  237. })
  238. if err2 != nil {
  239. logrus.Warnf("邮件更新失败-2:%+v", err2)
  240. }
  241. }
  242. return serializer.Suc(nil)
  243. }
  244. // DecodeExtData 解析奖励道具
  245. func (s *sAdminEmail) DecodeExtData(es string) (data []*model2.DropedItem, err error) {
  246. type Extra struct {
  247. Id string `json:"id"`
  248. Num string `json:"num"`
  249. Type int64 `json:"type"`
  250. }
  251. var (
  252. extra []*Extra
  253. )
  254. if err = json.Unmarshal([]byte(es), &extra); err != nil {
  255. return []*model2.DropedItem{}, err
  256. }
  257. for _, it := range extra {
  258. data = append(data, &model2.DropedItem{
  259. Id: cast.ToInt64(it.Id),
  260. Num: cast.ToInt64(it.Num),
  261. Type: it.Type,
  262. })
  263. }
  264. return
  265. }
  266. // SendEmailToWorld 发送邮件到游戏服务器
  267. func (s *sAdminEmail) SendEmailToWorld(params *model.AdminEmail) (err error) {
  268. letter := &model2.MailGlobal{
  269. MailType: 1,
  270. MaxPlayerId: 0,
  271. Title: params.Title,
  272. Content: params.Content,
  273. ExtraInfo: nil,
  274. CreateTime: time.Now(),
  275. ExpireTime: time.Now().AddDate(0, 0, int(params.Expired)),
  276. }
  277. letter.Extra, err = s.DecodeExtData(params.Ext)
  278. if err != nil {
  279. return err
  280. }
  281. switch params.ReceiptType {
  282. case 1: // 全服
  283. msg := msg2.GMLetter{
  284. MsgId: character.GenerateMsgId(),
  285. Letter: letter,
  286. Players: []int64{},
  287. OperatorId: params.OperatorID,
  288. }
  289. rpc_share.MsgMap[msg.MsgId] = fmt.Sprintf("%s,GM邮件(编号 %d) 投递成功,全服投递",
  290. utility.FormatSecond(time.Now()),
  291. params.ID)
  292. for _, serverId := range ServerOption.GetServerIds() {
  293. DB, err := player.GetDBByServerID(serverId)
  294. if err != nil {
  295. logrus.Warnf("sendLetterToWorld GetDBByServerID err:%+v", err)
  296. continue
  297. }
  298. var resp *msg2.ResponseGMLetter
  299. res, err := config.GmNats.GmRequest(DB, "GMLetter", msg)
  300. if err != nil {
  301. logrus.Warnf("sendLetterToWorld GmRequest err:%+v", err)
  302. continue
  303. }
  304. if err = json.Unmarshal(res, &resp); err != nil {
  305. logrus.Warnf("sendLetterToWorld nats Unmarshal err:%+v", err)
  306. continue
  307. }
  308. rpc_share.LogChan <- rpc_share.LogMsg{
  309. MsgID: msg.MsgId,
  310. Data: resp,
  311. }
  312. }
  313. case 2: // 指定服
  314. var serverIds []int32
  315. if err = json.Unmarshal([]byte(params.ServerIds), &serverIds); err != nil {
  316. return err
  317. }
  318. for _, serverId := range serverIds {
  319. sId := cast.ToInt(serverId)
  320. if sId > 0 {
  321. DB, err := player.GetDBByServerID(sId)
  322. if err != nil {
  323. logrus.Warnf("sendLetterToWorld2 GetDBByServerID2 err:%+v", err)
  324. continue
  325. }
  326. msg := msg2.GMLetter{
  327. MsgId: character.GenerateMsgId(),
  328. Letter: letter,
  329. Players: []int64{},
  330. OperatorId: params.OperatorID,
  331. }
  332. rpc_share.MsgMap[msg.MsgId] = fmt.Sprintf("%s,GM邮件(编号 %d) 投递成功,投递服务器ID:%v",
  333. utility.FormatSecond(time.Now()), params.ID, sId)
  334. var resp *msg2.ResponseGMLetter
  335. res, err := config.GmNats.GmRequest(DB, "GMLetter", msg)
  336. if err != nil {
  337. logrus.Warnf("sendLetterToWorld2 GmRequest err:%+v", err)
  338. continue
  339. }
  340. if err = json.Unmarshal(res, &resp); err != nil {
  341. logrus.Warnf("sendLetterToWorld2 nats Unmarshal err:%+v", err)
  342. continue
  343. }
  344. rpc_share.LogChan <- rpc_share.LogMsg{
  345. MsgID: msg.MsgId,
  346. Data: resp,
  347. }
  348. }
  349. }
  350. case 3: // 指定玩家
  351. var playerIds []string
  352. if err = json.Unmarshal([]byte(params.PlayerIds), &playerIds); err != nil {
  353. return err
  354. }
  355. lineMap := make(map[int][]int64)
  356. errPlayerIds := make([]int64, 0)
  357. for _, v := range playerIds {
  358. playerID := cast.ToInt64(v)
  359. if playerID <= 0 {
  360. errPlayerIds = append(errPlayerIds, playerID)
  361. continue
  362. }
  363. db, err := player.GetDBByUserId(playerID)
  364. if err != nil {
  365. errPlayerIds = append(errPlayerIds, playerID)
  366. logrus.Warnf("sendLetterToWorld3 GetDBByUserId err:%+v", err)
  367. continue
  368. }
  369. if _, ok := lineMap[db]; ok {
  370. lineMap[db] = append(lineMap[db], playerID)
  371. } else {
  372. lineMap[db] = []int64{playerID}
  373. }
  374. }
  375. if len(errPlayerIds) > 0 {
  376. logrus.Warnf("sendLetterToWorld3 errPlayerIds:%v", errPlayerIds)
  377. }
  378. for line, ids := range lineMap {
  379. msg := msg2.GMLetter{
  380. MsgId: character.GenerateMsgId(),
  381. Letter: letter,
  382. Players: ids,
  383. OperatorId: params.OperatorID,
  384. }
  385. rpc_share.MsgMap[msg.MsgId] = fmt.Sprintf("%s,GM邮件(编号 %d) 投递成功,投递玩家ID:%v",
  386. utility.FormatSecond(time.Now()), params.ID, ids)
  387. var resp *msg2.ResponseGMLetter
  388. res, err := config.GmNats.GmRequest(line, "GMLetter", msg)
  389. if err != nil {
  390. logrus.Warnf("sendLetterToWorld3 GmRequest err:%+v", err)
  391. continue
  392. }
  393. if err = json.Unmarshal(res, &resp); err != nil {
  394. logrus.Warnf("sendLetterToWorld3 nats Unmarshal err:%+v", err)
  395. continue
  396. }
  397. rpc_share.LogChan <- rpc_share.LogMsg{
  398. MsgID: msg.MsgId,
  399. Data: resp,
  400. }
  401. }
  402. }
  403. return
  404. }
  405. func (s *sAdminEmail) Export(ctx *gin.Context, list []*Ret) error {
  406. f := excelize.NewFile()
  407. f.SetColWidth("Sheet1", "A", "A", 15)
  408. f.SetColWidth("Sheet1", "B", "B", 15)
  409. f.SetColWidth("Sheet1", "C", "C", 15)
  410. f.SetColWidth("Sheet1", "D", "D", 20)
  411. f.SetColWidth("Sheet1", "E", "E", 25)
  412. f.SetColWidth("Sheet1", "F", "F", 30)
  413. f.SetColWidth("Sheet1", "G", "G", 30)
  414. f.SetColWidth("Sheet1", "H", "H", 15)
  415. f.SetColWidth("Sheet1", "I", "I", 15)
  416. f.SetColWidth("Sheet1", "J", "J", 15)
  417. f.SetColWidth("Sheet1", "K", "K", 15)
  418. // 创建一个工作表
  419. f.SetCellValue("Sheet1", "A1", "序号")
  420. f.SetCellValue("Sheet1", "B1", "标题")
  421. f.SetCellValue("Sheet1", "C1", "收件人")
  422. f.SetCellValue("Sheet1", "D1", "有效期")
  423. f.SetCellValue("Sheet1", "E1", "邮件内容")
  424. f.SetCellValue("Sheet1", "F1", "邮件备注")
  425. f.SetCellValue("Sheet1", "G1", "发送道具")
  426. f.SetCellValue("Sheet1", "H1", "预计发送时间")
  427. f.SetCellValue("Sheet1", "I1", "发送状态")
  428. f.SetCellValue("Sheet1", "J1", "创建人")
  429. f.SetCellValue("Sheet1", "K1", "创建时间")
  430. //获取道具和装备信息
  431. materials := gmdata.MaterialsDict //道具
  432. equipments := gmdata.EquipmentDict //装备
  433. materialMap := make(map[int64]gmdata.Material)
  434. equipmentMap := make(map[int64]gmdata.Equipment)
  435. for _, item := range materials {
  436. materialMap[int64(item.ID)] = item
  437. }
  438. for _, item := range equipments {
  439. equipmentMap[item.LevelId] = item
  440. }
  441. data := make([]Ext, 0)
  442. sendStatus := map[int32]string{1: "已发送", 2: "等待发送", 3: "待审核", 4: "已取消", 5: "发送中", 6: "发送出错"}
  443. uIds := make([]int64, len(list))
  444. uMap := make(map[int64]*model.AdminUser)
  445. for i, v := range list {
  446. if v.OperatorID > 0 {
  447. uIds[i] = v.OperatorID
  448. }
  449. }
  450. u := query.Use(config.DB).AdminUser
  451. usrs, err := u.WithContext(ctx).Where(u.ID.In(uIds...)).Find()
  452. if err != nil {
  453. return err
  454. }
  455. for _, usr := range usrs {
  456. uMap[usr.ID] = usr
  457. }
  458. type props struct {
  459. Name string `json:"name"`
  460. Count string `json:"count"`
  461. }
  462. for i, v := range list {
  463. f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+2), v.ID)
  464. f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+2), v.Title)
  465. if v.ReceiptType == 1 {
  466. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), "全服")
  467. } else if v.ReceiptType == 2 {
  468. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), fmt.Sprintf("指定服%s", v.ServerIds))
  469. } else if v.ReceiptType == 3 {
  470. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), fmt.Sprintf("指定玩家%s", v.PlayerIds))
  471. }
  472. f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+2), fmt.Sprintf("%d天", v.Expired))
  473. f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+2), v.Content)
  474. f.SetCellValue("Sheet1", fmt.Sprintf("F%d", i+2), v.Remark)
  475. //装备或者道具
  476. err := json.Unmarshal([]byte(v.Ext), &data)
  477. if err != nil {
  478. return err
  479. }
  480. propsArr := make([]props, 0)
  481. propsStr := ""
  482. for _, item := range data {
  483. //装备id大于10000000
  484. id, _ := strconv.ParseInt(item.Id, 10, 64)
  485. if id > 1000000 {
  486. if equipment, ok := equipmentMap[id]; ok {
  487. propsArr = append(propsArr, props{Name: equipment.Name, Count: item.Count})
  488. }
  489. } else if id > 0 && id < 1000000 {
  490. if material, ok := materialMap[id]; ok {
  491. propsArr = append(propsArr, props{
  492. Name: material.Name,
  493. Count: item.Count,
  494. })
  495. }
  496. }
  497. marshal, err := json.Marshal(propsArr)
  498. if err != nil {
  499. return err
  500. }
  501. propsStr = string(marshal)
  502. }
  503. f.SetCellValue("Sheet1", fmt.Sprintf("G%d", i+2), propsStr)
  504. if v.SendAt < 1 {
  505. f.SetCellValue("Sheet1", fmt.Sprintf("H%d", i+2), "-")
  506. } else {
  507. f.SetCellValue("Sheet1", fmt.Sprintf("H%d", i+2), utility.FormatSecond(time.Unix(v.SendAt, 0)))
  508. }
  509. f.SetCellValue("Sheet1", fmt.Sprintf("I%d", i+2), sendStatus[v.Status])
  510. f.SetCellValue("Sheet1", fmt.Sprintf("J%d", i+2), uMap[v.OperatorID].Nickname)
  511. f.SetCellValue("Sheet1", fmt.Sprintf("K%d", i+2), utility.FormatSecond(time.Unix(v.CreatedAt, 0)))
  512. }
  513. // 设置工作簿的默认工作表
  514. f.SetActiveSheet(1)
  515. ctx.Header("Content-Type", "application/vnd.ms-excel")
  516. ctx.Header("Content-Disposition", fmt.Sprintf("attachment;filename=订单记录导出%s.xlsx", time.Now().Format("20060102150405")))
  517. f.WriteTo(ctx.Writer)
  518. return nil
  519. }