admin_email.go 16 KB

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