report.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package api
  2. import (
  3. "box-cost/db/model"
  4. "box-cost/db/repo"
  5. "box-cost/log"
  6. "errors"
  7. "fmt"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/go-redis/redis/v8"
  11. "github.com/xuri/excelize/v2"
  12. "go.mongodb.org/mongo-driver/bson"
  13. "go.mongodb.org/mongo-driver/bson/primitive"
  14. )
  15. // 统计报表
  16. func Report(r *GinRouter) {
  17. r.POST("/report/list", ReportList)
  18. r.POST("/report/download", ReportDownload)
  19. }
  20. type ReportListReq struct {
  21. Supplier string
  22. TimeRange []time.Time
  23. PackIds []primitive.ObjectID
  24. PlanIds []primitive.ObjectID
  25. Page int64
  26. Size int64
  27. }
  28. func ReportList(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  29. // 财务管理】 添加统计报表功能。按 时间范围, 供应商(单选) 包装(多选) 计划(多选) 四个维度进行过滤,形成报表。可以下载
  30. var form ReportListReq
  31. err := c.ShouldBindJSON(&form)
  32. if err != nil {
  33. return nil, errors.New("参数错误")
  34. }
  35. var page int64 = 1
  36. var size int64 = 10
  37. if form.Page > 0 {
  38. page = form.Page
  39. } else {
  40. page = 1
  41. }
  42. if form.Size > 0 {
  43. size = form.Size
  44. } else {
  45. size = 10
  46. }
  47. start := (page - 1) * size
  48. end := page*size - 1
  49. // 条件处理
  50. query := make(map[string]interface{}, 0)
  51. if form.Supplier != "" {
  52. query["supplier"] = form.Supplier
  53. }
  54. // 时间范围
  55. if len(form.TimeRange) == 2 {
  56. start, end := getTimeRange(form.TimeRange[0], form.TimeRange[1])
  57. query["createTime"] = bson.M{"$gte": start, "$lte": end}
  58. }
  59. // 包装
  60. if len(form.PackIds) > 0 {
  61. packQuery := []bson.M{}
  62. for _, packId := range form.PackIds {
  63. packQuery = append(packQuery, bson.M{"packId": packId})
  64. }
  65. query["$or"] = packQuery
  66. }
  67. // 计划
  68. if len(form.PlanIds) > 0 {
  69. planQuery := bson.A{}
  70. for _, planId := range form.PlanIds {
  71. planQuery = append(planQuery, bson.M{"planId": planId})
  72. }
  73. query["$or"] = planQuery
  74. }
  75. // 获取采购单符合条件的信息
  76. purchases := []model.PurchaseBill{}
  77. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  78. CollectName: repo.CollectionBillPurchase,
  79. Query: query,
  80. }, &purchases)
  81. // 获取加工单符合条件的信息
  82. produces := []model.ProduceBill{}
  83. repo.RepoDocsSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{
  84. CollectName: repo.CollectionBillProduce,
  85. Query: query,
  86. }, &produces)
  87. // 组装数据
  88. cacheKey := "report:list"
  89. apictx.Svc.Redis.Del(apictx.CreateRepoCtx().Ctx, cacheKey)
  90. // key存在时
  91. // if apictx.Svc.Redis.Exists(apictx.CreateRepoCtx().Ctx, cacheKey).Val() == 1 {
  92. // ret := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, start, end)
  93. // retList = ret.Val()
  94. // } else {
  95. // }
  96. mlen := len(purchases) + len(produces)
  97. type MapList map[string]interface{}
  98. lists := make([]MapList, mlen)
  99. if len(purchases) > 0 {
  100. for _, purchase := range purchases {
  101. apictx.Svc.Redis.ZAdd(apictx.CreateRepoCtx().Ctx, cacheKey, &redis.Z{
  102. Score: float64(purchase.CreateTime.Unix()),
  103. Member: purchase.Id.Hex(),
  104. })
  105. list := MapList{purchase.Id.Hex(): purchase, "type": "purchase"}
  106. lists = append(lists, list)
  107. }
  108. }
  109. if len(produces) > 0 {
  110. for _, produce := range produces {
  111. apictx.Svc.Redis.ZAdd(apictx.CreateRepoCtx().Ctx, cacheKey, &redis.Z{
  112. Score: float64(produce.CreateTime.Unix()),
  113. Member: produce.Id.Hex(),
  114. })
  115. list := MapList{produce.Id.Hex(): produce, "type": "produce"}
  116. lists = append(lists, list)
  117. }
  118. }
  119. // 当前key存在时
  120. retList := make([]map[string]interface{}, 0)
  121. // 所有id
  122. ids := make([]map[string]string, 0)
  123. if apictx.Svc.Redis.Exists(apictx.CreateRepoCtx().Ctx, cacheKey).Val() == 1 {
  124. // ret := apictx.Svc.Redis.ExpireLT(apictx.CreateRepoCtx().Ctx, cacheKey, 20*time.Second)
  125. // 按创建时间升序排
  126. result := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, start, end)
  127. if result.Err() != nil {
  128. log.Error(err)
  129. return nil, errors.New("缓存数据内部错误")
  130. }
  131. retids := apictx.Svc.Redis.ZRange(apictx.CreateRepoCtx().Ctx, cacheKey, 0, -1)
  132. // 所有id
  133. if len(retids.Val()) > 0 {
  134. for _, id := range retids.Val() {
  135. for _, item := range lists {
  136. if _, ok := item[id]; ok {
  137. ids = append(ids, map[string]string{"id": id, "type": item["type"].(string)})
  138. }
  139. }
  140. }
  141. }
  142. // 返回的列表
  143. if len(result.Val()) > 0 {
  144. for _, id := range result.Val() {
  145. for _, item := range lists {
  146. if _, ok := item[id]; ok {
  147. retList = append(retList, item)
  148. }
  149. }
  150. }
  151. }
  152. }
  153. type PageResult struct {
  154. List []map[string]interface{} `json:"list"`
  155. Total int64 `json:"total"`
  156. Page int64 `json:"page"`
  157. Size int64 `json:"size"`
  158. Ids []map[string]string `json:"ids"`
  159. }
  160. out := &PageResult{
  161. List: retList,
  162. Total: int64(mlen),
  163. Page: page,
  164. Size: size,
  165. Ids: ids,
  166. }
  167. return out, nil
  168. }
  169. type ReportDownloadReq struct {
  170. Id string
  171. Type string
  172. }
  173. func ReportDownload(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  174. var form []ReportDownloadReq
  175. err := c.ShouldBindJSON(&form)
  176. if err != nil {
  177. return nil, errors.New("参数错误")
  178. }
  179. if len(form) > 0 {
  180. info := model.Setting{}
  181. repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  182. CollectName: "infos",
  183. }, &info)
  184. f := excelize.NewFile()
  185. // Create a new sheet.
  186. index := f.NewSheet("Sheet1")
  187. f.SetActiveSheet(index)
  188. f.SetDefaultFont("宋体")
  189. offset := 0
  190. for _, req := range form {
  191. // 是采购单
  192. if req.Type == "purchase" {
  193. purchaseId, err := primitive.ObjectIDFromHex(req.Id)
  194. if err == nil {
  195. purchase := model.PurchaseBill{}
  196. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  197. CollectName: repo.CollectionBillPurchase,
  198. Query: repo.Map{"_id": purchaseId},
  199. }, &purchase)
  200. if found {
  201. purchaseExcel := NewPurchaseBill(f)
  202. purchaseExcel.Content = &purchase
  203. purchaseExcel.Title = fmt.Sprintf("%s原材料采购单", info.CompanyName)
  204. //设置对应的数据
  205. purchaseExcel.Offset = offset
  206. purchaseExcel.Draws()
  207. offset += 15
  208. }
  209. }
  210. }
  211. // 是加工单
  212. if req.Type == "produce" {
  213. produceId, err := primitive.ObjectIDFromHex(req.Id)
  214. if err == nil {
  215. produce := model.ProduceBill{}
  216. found, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  217. CollectName: repo.CollectionBillProduce,
  218. Query: repo.Map{"_id": produceId},
  219. }, &produce)
  220. if found {
  221. produceExcel := NewProduceBill(f)
  222. produceExcel.Content = &produce
  223. produceExcel.Title = fmt.Sprintf("%s加工单", info.CompanyName)
  224. //设置对应的数据
  225. produceExcel.Offset = offset
  226. produceExcel.Draws()
  227. offset += 15
  228. }
  229. }
  230. }
  231. }
  232. c.Header("Content-Type", "application/octet-stream")
  233. c.Header("Content-Disposition", "attachment; filename="+"report.xlsx")
  234. c.Header("Content-Transfer-Encoding", "binary")
  235. err = f.Write(c.Writer)
  236. if err != nil {
  237. return nil, err
  238. }
  239. }
  240. return nil, nil
  241. }