admin_email.go 15 KB

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