plan-process-track.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. package api
  2. import (
  3. "box-cost/db/model"
  4. "box-cost/db/repo"
  5. "box-cost/log"
  6. "errors"
  7. "fmt"
  8. "regexp"
  9. "strings"
  10. "time"
  11. "github.com/gin-gonic/gin"
  12. "github.com/xuri/excelize/v2"
  13. "go.mongodb.org/mongo-driver/bson/primitive"
  14. )
  15. type PlanIds struct {
  16. Ids []primitive.ObjectID `json:"ids"`
  17. }
  18. func DownloadPlanTrack(c *gin.Context, apictx *ApiSession) (interface{}, error) {
  19. var form PlanIds
  20. err := c.ShouldBindJSON(&form)
  21. if err != nil {
  22. return nil, err
  23. }
  24. if len(form.Ids) == 0 {
  25. return nil, errors.New("ids为空")
  26. }
  27. plans := []*model.ProductPlan{}
  28. for _, objId := range form.Ids {
  29. fmt.Println(objId.Hex())
  30. plan := &model.ProductPlan{}
  31. _, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  32. CollectName: repo.CollectionProductPlan,
  33. Query: repo.Map{"_id": objId},
  34. }, plan)
  35. if err != nil {
  36. fmt.Println(err)
  37. log.Info(err)
  38. continue
  39. }
  40. plans = append(plans, plan)
  41. }
  42. f := excelize.NewFile()
  43. index := f.NewSheet("Sheet1")
  44. f.SetActiveSheet(index)
  45. f.SetDefaultFont("宋体")
  46. planTrackExcel := NewPlanProcessTrackExcel(f)
  47. planStatusInfos, err := handlPlanStatus(apictx, plans)
  48. if err != nil {
  49. return nil, err
  50. }
  51. planTrackExcel.Content = planStatusInfos
  52. //设置对应的数据
  53. planTrackExcel.Draws()
  54. date := time.Now().Format("2006年01月02日_150405")
  55. fileName := fmt.Sprintf("礼盒加工追踪表_%s.xlsx", date)
  56. c.Header("Content-Type", "application/octet-stream")
  57. c.Header("Content-Disposition", "attachment; filename="+fileName)
  58. c.Header("Content-Transfer-Encoding", "binary")
  59. err = f.Write(c.Writer)
  60. if err != nil {
  61. return nil, err
  62. }
  63. return nil, nil
  64. }
  65. const (
  66. EXCEL_TMPLATE_FILE = "tmplate/tmplate.xlsx"
  67. CELL_BACKGROUND = "808080"
  68. )
  69. var needChangeCol = map[string]string{
  70. "部件": "E",
  71. "下单": "F",
  72. "纸张": "G",
  73. "印刷": "H",
  74. "覆膜": "I",
  75. "烫金": "J",
  76. "丝印": "K",
  77. "对裱": "L",
  78. "压纹": "M",
  79. "裱瓦": "N",
  80. "模切": "O",
  81. "粘盒": "P",
  82. "组装": "Q",
  83. "交货": "R",
  84. }
  85. func MatchString(targetStr string, regexPattern string) bool {
  86. // 编译正则表达式
  87. re := regexp.MustCompile(regexPattern)
  88. // 检查目标字符串是否包含匹配的子串
  89. return re.MatchString(targetStr)
  90. }
  91. type PlanStatusInfo struct {
  92. PlanName string `json:"planName"`
  93. PlanUnit string `json:"planUnit"`
  94. PlanCount int `json:"planCount"`
  95. PlanRowStart int `json:"planRowStart"`
  96. PlanRowEnd int `json:"planRowEnd"`
  97. PlanCompStatus []map[string]string `json:"planCompStatus"`
  98. }
  99. func handlPlanStatus(apictx *ApiSession, plans []*model.ProductPlan) ([]*PlanStatusInfo, error) {
  100. row := 5
  101. planStatusInfos := make([]*PlanStatusInfo, 0)
  102. planCompStatus := []map[string]string{}
  103. for _, plan := range plans {
  104. startRow := row
  105. for _, comp := range plan.Pack.Components {
  106. // ""代表该部件没有该工艺 "〇"代表正在进行的工艺
  107. // "808080"背景颜色代表部件所含未进行工艺 √代表已完成工序
  108. compStatus := map[string]string{
  109. "部件": " ",
  110. "行数": "5",
  111. // 部件中只要有一个订单就说明下单了
  112. "下单": " ",
  113. // 采购单中type为纸张 订单对应状态为完成
  114. "纸张": " ",
  115. // 遍历工艺单,工序中包含印刷
  116. "印刷": " ",
  117. // 遍历工艺单,工序中包含覆膜
  118. "覆膜": " ",
  119. // 遍历工艺单,工序中包含烫金
  120. "烫金": " ",
  121. // 遍历工艺单,工序中包含丝印
  122. "丝印": " ",
  123. // 遍历工艺单,工序中包含对裱
  124. "对裱": " ",
  125. // 遍历工艺单,工序中包含压纹
  126. "压纹": " ",
  127. // 遍历工艺单,工序中包含裱瓦
  128. "裱瓦": " ",
  129. // 遍历工艺单,工序中包含模切
  130. "模切": " ",
  131. // 遍历工艺单,工序中包含粘盒
  132. "粘盒": " ",
  133. // 遍历工艺单,工序中包含组装
  134. "组装": " ",
  135. "交货": " ",
  136. }
  137. fmt.Println(plan.Name)
  138. fmt.Println(comp.Name)
  139. fmt.Println(row)
  140. fmt.Println("------------------------------------")
  141. compStatus["部件"] = comp.Name
  142. compStatus["行数"] = fmt.Sprintf("%d", row)
  143. row++
  144. // 去重获取所有订单
  145. seen := make(map[string]bool)
  146. tbills := make([]string, 0, len(comp.Stages)) // 结果数组,容量初始化为原数组的长度
  147. // ???:1 最后一个工序没下单
  148. // isBill := true
  149. // lastStage := comp.Stages[len(comp.Stages)-1]
  150. // if len(lastStage.BillId) < 24 {
  151. // isBill = false
  152. // }
  153. for _, stage := range comp.Stages {
  154. if len(stage.BillId) > 0 {
  155. value := fmt.Sprintf("%d_%s", stage.BillType, stage.BillId)
  156. if _, ok := seen[value]; !ok {
  157. // 标记为已出现
  158. seen[value] = true
  159. // 添加到结果数组
  160. tbills = append(tbills, value)
  161. }
  162. } else {
  163. // 产品中填写了这个工序但是没有下单 黑色背景
  164. for k := range compStatus {
  165. if k == "下单" || k == "交货" || k == "部件" || k == "行数" {
  166. continue
  167. }
  168. // 纸张 只要是采购单就设置纸张状态
  169. if stage.Type == 1 {
  170. compStatus["纸张"] = CELL_BACKGROUND
  171. }
  172. // 匹配工艺关键字 匹配到就设置状态为黑背景
  173. if MatchString(stage.Name, k) {
  174. compStatus[k] = CELL_BACKGROUND
  175. }
  176. }
  177. }
  178. }
  179. // fmt.Println(tbills)
  180. // 如果tbills为空,说明该部件没有订单
  181. if len(tbills) == 0 {
  182. // 该部件没有订单,跳过
  183. planCompStatus = append(planCompStatus, compStatus)
  184. continue
  185. }
  186. // 查询数据库获取bill详细信息
  187. // 最后工序订单号
  188. lastBillType := tbills[len(tbills)-1]
  189. for _, billType := range tbills {
  190. compStatus["下单"] = "√"
  191. bt := strings.Split(billType, "_")[0]
  192. billId, _ := primitive.ObjectIDFromHex(strings.Split(billType, "_")[1])
  193. if bt == "1" {
  194. // 查询采购单
  195. bill := &model.PurchaseBill{}
  196. _, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  197. CollectName: repo.CollectionBillPurchase,
  198. Query: repo.Map{"_id": billId},
  199. }, bill)
  200. if err != nil {
  201. fmt.Printf("billId:%s---%s", billId.Hex(), err.Error())
  202. return nil, errors.New("采购单不存在")
  203. }
  204. // if bill.Type == "纸张" {
  205. // compStatus["纸张"] = "〇"
  206. // if bill.Status == "complete" {
  207. // compStatus["纸张"] = "√"
  208. // }
  209. // }
  210. compStatus["纸张"] = "〇"
  211. if bill.Status == "complete" {
  212. compStatus["纸张"] = "√"
  213. }
  214. // if !isBill {
  215. // continue
  216. // }
  217. if lastBillType == billType {
  218. for _, paper := range bill.Paper {
  219. compStatus["交货"] = fmt.Sprintf("%d", paper.ConfirmCount)
  220. }
  221. }
  222. }
  223. if bt == "2" {
  224. // 查询工艺单
  225. bill := &model.ProduceBill{}
  226. _, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  227. CollectName: repo.CollectionBillProduce,
  228. Query: repo.Map{"_id": billId},
  229. }, bill)
  230. if err != nil {
  231. fmt.Printf("billId:%s---%s", billId.Hex(), err.Error())
  232. return nil, errors.New("工艺单不存在")
  233. }
  234. for _, produce := range bill.Produces {
  235. for k := range compStatus {
  236. if k == "下单" || k == "纸张" || k == "交货" || k == "部件" || k == "行数" {
  237. continue
  238. }
  239. if MatchString(produce.Name, k) {
  240. compStatus[k] = "〇"
  241. if bill.Status == "complete" {
  242. compStatus[k] = "√"
  243. }
  244. }
  245. // 直接赋值,如果这个订单是最后一个,则状态覆盖
  246. // ???思考:如果最后一个工序没有生成订单的话,是按最后一个工序还是最后一个订单?这里是最后一个订单
  247. // ???:1
  248. // if !isBill {
  249. // continue
  250. // }
  251. compStatus["交货"] = fmt.Sprintf("%d", produce.ConfirmCount)
  252. }
  253. }
  254. }
  255. // 暂时没有状态标定
  256. if bt == "3" {
  257. // 查询成品单
  258. bill := &model.ProductBill{}
  259. _, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{
  260. CollectName: repo.CollectionBillProduct,
  261. Query: repo.Map{"_id": billId},
  262. }, bill)
  263. if err != nil {
  264. fmt.Printf("billId:%s---%s", billId.Hex(), err.Error())
  265. return nil, errors.New("成品单不存在")
  266. }
  267. // fmt.Println(bill)
  268. // ?? 这里需不需要 影响正确数据吗?
  269. // if !isBill {
  270. // continue
  271. // }
  272. if lastBillType == billType {
  273. for _, product := range bill.Products {
  274. compStatus["交货"] = fmt.Sprintf("%d", product.ConfirmCount)
  275. }
  276. }
  277. }
  278. }
  279. planCompStatus = append(planCompStatus, compStatus)
  280. }
  281. // fmt.Println(plan.Name)
  282. // fmt.Println("rowstart:", startRow)
  283. // fmt.Println("rowend:", row-1)
  284. planStatusInfos = append(planStatusInfos, &PlanStatusInfo{
  285. PlanName: plan.Name,
  286. // !这个规格好像没有
  287. PlanUnit: "",
  288. PlanCount: plan.Total,
  289. PlanRowStart: startRow,
  290. PlanRowEnd: row - 1,
  291. PlanCompStatus: planCompStatus,
  292. })
  293. }
  294. return planStatusInfos, nil
  295. }