waybill.go 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108
  1. package controller
  2. import (
  3. "bufio"
  4. "cold-delivery/app/admin/model"
  5. "cold-delivery/app/admin/service"
  6. "cold-delivery/app/admin/service/dto"
  7. "cold-delivery/common/actions"
  8. "cold-delivery/common/lib"
  9. "cold-delivery/common/nats/nats_server"
  10. "errors"
  11. "fmt"
  12. "github.com/beego/beego/v2/core/logs"
  13. "github.com/gin-gonic/gin"
  14. "github.com/gin-gonic/gin/binding"
  15. "github.com/golang/freetype/truetype"
  16. "github.com/pborman/uuid"
  17. "github.com/signintech/gopdf"
  18. "github.com/wcharczuk/go-chart/v2"
  19. "github.com/wcharczuk/go-chart/v2/drawing"
  20. "github.com/xuri/excelize/v2"
  21. "gogs.baozhida.cn/zoie/OAuth-core/api"
  22. "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user"
  23. _ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response"
  24. "gonum.org/v1/plot"
  25. "gonum.org/v1/plot/plotter"
  26. "gonum.org/v1/plot/vg"
  27. "gonum.org/v1/plot/vg/draw"
  28. "image/color"
  29. "log"
  30. "math"
  31. "net/url"
  32. "os"
  33. "path"
  34. "sort"
  35. "sync"
  36. "time"
  37. )
  38. type WaybillController struct {
  39. api.Api
  40. }
  41. // GetPage 获取运单列表
  42. // @Summary 获取运单列表
  43. // @Description 获取运单列表
  44. // @Tags 运单
  45. // @Param no query string false "运单号"
  46. // @Param pageSize query int false "页条数"
  47. // @Param page query int false "页码"
  48. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  49. // @Router /api/waybill [get]
  50. // @Security Bearer
  51. func (e WaybillController) GetPage(c *gin.Context) {
  52. s := service.Waybill{}
  53. userSvc := service.SysUser{}
  54. req := dto.WaybillGetPageReq{}
  55. err := e.MakeContext(c).
  56. MakeOrm().
  57. Bind(&req, binding.Query).
  58. MakeService(&s.Service).
  59. MakeService(&userSvc.Service).
  60. Errors
  61. if err != nil {
  62. e.Logger.Error(err)
  63. e.Error(500, err, err.Error())
  64. return
  65. }
  66. //数据权限检查
  67. p := actions.GetPermissionFromContext(c)
  68. var userObj model.SysUser
  69. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  70. if err != nil {
  71. e.Error(500, err, err.Error())
  72. return
  73. }
  74. list := make([]model.Waybill, 0)
  75. var count int64
  76. if userObj.Type == model.SysUserTypeSys {
  77. err = s.GetPage(&req, &list, &count, p)
  78. } else {
  79. err = s.GetUserPage(&req, &list, &count, p)
  80. }
  81. if err != nil {
  82. e.Error(500, err, err.Error())
  83. return
  84. }
  85. e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
  86. }
  87. // GetPage 获取运单列表
  88. // @Summary 获取运单列表
  89. // @Description 获取运单列表
  90. // @Tags 运单
  91. // @Param no query string false "运单号"
  92. // @Param pageSize query int false "页条数"
  93. // @Param page query int false "页码"
  94. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  95. // @Router /api/waybill [get]
  96. // @Security Bearer
  97. func (e WaybillController) Export(c *gin.Context) {
  98. s := service.Waybill{}
  99. req := dto.WaybillGetPageReq{}
  100. err := e.MakeContext(c).
  101. MakeOrm().
  102. Bind(&req, binding.Query).
  103. MakeService(&s.Service).
  104. Errors
  105. if err != nil {
  106. e.Logger.Error(err)
  107. e.Error(500, err, err.Error())
  108. return
  109. }
  110. //数据权限检查
  111. p := actions.GetPermissionFromContext(c)
  112. list := make([]model.Waybill, 0)
  113. var count int64
  114. req.PageSize = 9999
  115. err = s.GetPage(&req, &list, &count, p)
  116. if err != nil {
  117. e.Error(500, err, err.Error())
  118. return
  119. }
  120. f := excelize.NewFile() // 设置单元格的值
  121. // 这里设置表头ÒÒ
  122. f.SetCellValue("Sheet1", "A1", "序号")
  123. f.SetCellValue("Sheet1", "B1", "状态")
  124. f.SetCellValue("Sheet1", "C1", "寄件人名称")
  125. f.SetCellValue("Sheet1", "D1", "寄件人电话")
  126. f.SetCellValue("Sheet1", "E1", "寄件人地址")
  127. f.SetCellValue("Sheet1", "F1", "收件人名称")
  128. f.SetCellValue("Sheet1", "G1", "收件人电话")
  129. f.SetCellValue("Sheet1", "H1", "收件人地址")
  130. f.SetCellValue("Sheet1", "I1", "防拆标签码")
  131. f.SetCellValue("Sheet1", "J1", "运输备注")
  132. // 设置列宽
  133. f.SetColWidth("Sheet1", "A", "A", 6)
  134. f.SetColWidth("Sheet1", "B", "B", 8)
  135. f.SetColWidth("Sheet1", "C", "C", 14)
  136. f.SetColWidth("Sheet1", "D", "D", 14)
  137. f.SetColWidth("Sheet1", "E", "E", 30)
  138. f.SetColWidth("Sheet1", "F", "F", 14)
  139. f.SetColWidth("Sheet1", "G", "G", 14)
  140. f.SetColWidth("Sheet1", "H", "H", 30)
  141. f.SetColWidth("Sheet1", "I", "J", 15)
  142. f.SetColWidth("Sheet1", "K", "K", 30)
  143. line := 1
  144. // 循环写入数据
  145. for i, v := range list {
  146. line++
  147. f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
  148. f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.WaybillStatusMap[v.Status])
  149. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName)
  150. f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone)
  151. f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails)
  152. f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName)
  153. f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone)
  154. f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails)
  155. f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.DeliveryName)
  156. f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryPhone)
  157. f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.Remark)
  158. }
  159. timeStr := time.Now().Format("20060102150405")
  160. filePath := "ofile/" + "运单" + timeStr + ".xlsx"
  161. // 保存文件
  162. if err = f.SaveAs(filePath); err != nil {
  163. logs.Error("保存运单失败:", err)
  164. }
  165. defer func() {
  166. os.Remove(filePath)
  167. }()
  168. c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
  169. // PathEscape 函数对中文做处理
  170. c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx"))
  171. c.Header("Content-Transfer-Encoding", "binary")
  172. c.File(filePath)
  173. }
  174. // Home 首页统计
  175. // @Summary 首页统计
  176. // @Description 首页统计
  177. // @Tags 运单
  178. // @Param no query string false "运单号"
  179. // @Param pageSize query int false "页条数"
  180. // @Param page query int false "页码"
  181. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  182. // @Router /api/waybill [get]
  183. // @Security Bearer
  184. func (e WaybillController) Home(c *gin.Context) {
  185. s := service.Waybill{}
  186. userSvc := service.SysUser{}
  187. req := dto.WaybillStatsReq{}
  188. err := e.MakeContext(c).
  189. MakeOrm().
  190. Bind(&req, binding.Query).
  191. MakeService(&s.Service).
  192. MakeService(&userSvc.Service).
  193. Errors
  194. if err != nil {
  195. e.Logger.Error(err)
  196. e.Error(500, err, err.Error())
  197. return
  198. }
  199. //数据权限检查
  200. p := actions.GetPermissionFromContext(c)
  201. var userObj model.SysUser
  202. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  203. if err != nil {
  204. e.Error(500, err, err.Error())
  205. return
  206. }
  207. var res dto.WaybillStatsRes
  208. if userObj.Type == model.SysUserTypeSys {
  209. res = s.GetBasicsStats(&req, p)
  210. } else {
  211. res = s.GetUserBasicsStats(&req, p, service.GetUserBasicsStatsScopes(p.UserId))
  212. }
  213. e.OK(res, "查询成功")
  214. }
  215. // Home 用户运单数量统计
  216. // @Summary 首页统计
  217. // @Description 首页统计
  218. // @Tags 运单
  219. // @Param no query string false "运单号"
  220. // @Param pageSize query int false "页条数"
  221. // @Param page query int false "页码"
  222. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  223. // @Router /api/waybill [get]
  224. // @Security Bearer
  225. func (e WaybillController) UserStats(c *gin.Context) {
  226. s := service.Waybill{}
  227. userSvc := service.SysUser{}
  228. req := dto.WaybillUserStatsReq{}
  229. err := e.MakeContext(c).
  230. MakeOrm().
  231. Bind(&req, binding.JSON).
  232. MakeService(&s.Service).
  233. MakeService(&userSvc.Service).
  234. Errors
  235. if err != nil {
  236. e.Logger.Error(err)
  237. e.Error(500, err, err.Error())
  238. return
  239. }
  240. //数据权限检查
  241. p := actions.GetPermissionFromContext(c)
  242. var userObj model.SysUser
  243. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  244. if err != nil {
  245. e.Error(500, err, err.Error())
  246. return
  247. }
  248. var res []dto.WaybillUserStats
  249. if userObj.Type == model.SysUserTypeSys {
  250. res = s.GetReCheckStats(&req, p)
  251. } else {
  252. req.UserIds = []int{p.UserId}
  253. res = s.GetReCheckStats(&req, p)
  254. }
  255. e.OK(res, "查询成功")
  256. }
  257. // GetAppletPage 获取运单列表
  258. // @Summary 获取运单列表
  259. // @Description 获取运单列表
  260. // @Tags 运单
  261. // @Param no query string false "运单号"
  262. // @Param pageSize query int false "页条数"
  263. // @Param page query int false "页码"
  264. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  265. // @Router /api/waybill [get]
  266. // @Security Bearer
  267. func (e WaybillController) GetAppletPage(c *gin.Context) {
  268. s := service.Waybill{}
  269. req := dto.WaybillGetAppletPageReq{}
  270. err := e.MakeContext(c).
  271. MakeOrm().
  272. Bind(&req, binding.Query).
  273. MakeService(&s.Service).
  274. Errors
  275. if err != nil {
  276. e.Logger.Error(err)
  277. e.Error(500, err, err.Error())
  278. return
  279. }
  280. //数据权限检查
  281. p := actions.GetPermissionFromContext(c)
  282. list := make([]model.Waybill, 0)
  283. var count int64
  284. err = s.GetAppletPage(&req, &list, &count, p)
  285. if err != nil {
  286. e.Error(500, err, err.Error())
  287. return
  288. }
  289. e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
  290. }
  291. // GetAppletCount 获取app运单统计数量
  292. // @Summary 获取app运单统计数量
  293. // @Description 获取app运单统计数量
  294. // @Tags 运单
  295. // @Param no query string false "运单号"
  296. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  297. // @Router /api/waybill/applet-count [get]
  298. // @Security Bearer
  299. func (e WaybillController) GetAppletCount(c *gin.Context) {
  300. s := service.Waybill{}
  301. userSvc := service.SysUser{}
  302. req := dto.WaybillGetAppletPageReq{}
  303. err := e.MakeContext(c).
  304. MakeOrm().
  305. Bind(&req, binding.Query).
  306. MakeService(&s.Service).
  307. MakeService(&userSvc.Service).
  308. Errors
  309. if err != nil {
  310. e.Logger.Error(err)
  311. e.Error(500, err, err.Error())
  312. return
  313. }
  314. //数据权限检查
  315. p := actions.GetPermissionFromContext(c)
  316. var userObj model.SysUser
  317. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  318. if err != nil {
  319. e.Error(500, err, err.Error())
  320. return
  321. }
  322. list := make([]model.Waybill, 0)
  323. var count int64
  324. if userObj.UserType == "customer" {
  325. r := dto.WaybillGetCustomerPageReq{}
  326. r.PageSize = 9999
  327. r.CustomerId = p.UserId
  328. err = s.GetCustomerPage(&r, &list, &count, p)
  329. var statusCount = make(map[int]int)
  330. statusCount[0] = int(count)
  331. for _, waybill := range list {
  332. if _, ok := statusCount[waybill.Status]; ok {
  333. statusCount[waybill.Status] += 1
  334. } else {
  335. statusCount[waybill.Status] = 1
  336. }
  337. }
  338. e.OK(statusCount, "查询成功")
  339. return
  340. }
  341. err = s.GetAppletCount(&list, &count, p)
  342. if err != nil {
  343. e.Error(500, err, err.Error())
  344. return
  345. }
  346. var statusCount = make(map[int]int)
  347. statusCount[0] = int(count)
  348. for _, waybill := range list {
  349. if _, ok := statusCount[waybill.Status]; ok {
  350. statusCount[waybill.Status] += 1
  351. } else {
  352. statusCount[waybill.Status] = 1
  353. }
  354. }
  355. e.OK(statusCount, "查询成功")
  356. }
  357. // Get 通过id获取运单
  358. // @Summary 通过id获取运单
  359. // @Description 通过id获取运单
  360. // @Tags 运单
  361. // @Param id path string true "运单id"
  362. // @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}"
  363. // @Router /api/waybill/{id} [get]
  364. // @Security Bearer
  365. func (e WaybillController) Get(c *gin.Context) {
  366. s := service.Waybill{}
  367. req := dto.WaybillGetReq{}
  368. err := e.MakeContext(c).
  369. MakeOrm().
  370. Bind(&req, nil).
  371. MakeService(&s.Service).
  372. Errors
  373. if err != nil {
  374. e.Logger.Error(err)
  375. e.Error(500, err, err.Error())
  376. return
  377. }
  378. var object model.Waybill
  379. p := actions.GetPermissionFromContext(c)
  380. //数据权限检查
  381. err = s.Get(&req, &object, p)
  382. if err != nil {
  383. e.Error(500, err, err.Error())
  384. return
  385. }
  386. e.OK(object, "查询成功")
  387. }
  388. // GetByWaybillNo 通过id获取运单
  389. // @Summary 通过id获取运单
  390. // @Description 通过id获取运单
  391. // @Tags 运单
  392. // @Param id path string true "运单id"
  393. // @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}"
  394. // @Router /api/waybill/no [get]
  395. // @Security Bearer
  396. func (e WaybillController) GetByWaybillNo(c *gin.Context) {
  397. s := service.Waybill{}
  398. req := dto.WaybillGetByWaybillPdfReq{}
  399. err := e.MakeContext(c).
  400. MakeOrm().
  401. Bind(&req, binding.Query).
  402. MakeService(&s.Service).
  403. Errors
  404. if err != nil {
  405. e.Logger.Error(err)
  406. e.Error(500, err, err.Error())
  407. return
  408. }
  409. var object model.Waybill
  410. //数据权限检查
  411. err = s.GetByWaybillNo(&req, &object, nil)
  412. if err != nil {
  413. e.Error(500, err, err.Error())
  414. return
  415. }
  416. e.OK(object, "查询成功")
  417. }
  418. // Insert 添加运单
  419. // @Summary 添加运单
  420. // @Description 添加运单
  421. // @Tags 运单
  422. // @Accept application/json
  423. // @Product application/json
  424. // @Param data body dto.WaybillInsertReq true "data"
  425. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  426. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  427. // @Router /api/waybill [post]
  428. // @Security Bearer
  429. func (e WaybillController) Insert(c *gin.Context) {
  430. s := service.Waybill{}
  431. req := dto.WaybillInsertReq{}
  432. err := e.MakeContext(c).
  433. MakeOrm().
  434. Bind(&req, binding.JSON).
  435. MakeService(&s.Service).
  436. Errors
  437. if err != nil {
  438. e.Logger.Error(err)
  439. e.Error(500, err, err.Error())
  440. return
  441. }
  442. p := actions.GetPermissionFromContext(c)
  443. // 设置创建人
  444. req.SetCreateBy(user.GetUserId(c))
  445. req.SetDeptId(p.DeptId)
  446. err = s.Insert(&req)
  447. if err != nil {
  448. e.Error(500, err, err.Error())
  449. return
  450. }
  451. e.OK(req.GetId(), "创建成功")
  452. }
  453. // UpdateStatus 修改运单状态
  454. // @Summary 修改运单状态
  455. // @Description 修改运单状态
  456. // @Tags 运单
  457. // @Accept application/json
  458. // @Product application/json
  459. // @Param data body dto.WaybillUpdateStatusReq true "body"
  460. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  461. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  462. // @Router /api/waybill [put]
  463. // @Security Bearer
  464. func (e WaybillController) UpdateStatus(c *gin.Context) {
  465. s := service.Waybill{}
  466. req := dto.WaybillUpdateStatusReq{}
  467. err := e.MakeContext(c).
  468. MakeOrm().
  469. Bind(&req).
  470. MakeService(&s.Service).
  471. Errors
  472. if err != nil {
  473. e.Logger.Error(err)
  474. e.Error(500, err, err.Error())
  475. return
  476. }
  477. p := actions.GetPermissionFromContext(c)
  478. req.SetUpdateBy(user.GetUserId(c))
  479. err = s.UpdateStatus(&req, p)
  480. if err != nil {
  481. e.Error(500, err, err.Error())
  482. return
  483. }
  484. e.OK(req.GetId(), "更新成功")
  485. }
  486. // Update 修改运单
  487. // @Summary 修改运单
  488. // @Description 修改运单
  489. // @Tags 运单
  490. // @Accept application/json
  491. // @Product application/json
  492. // @Param data body dto.WaybillUpdateReq true "body"
  493. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  494. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  495. // @Router /api/waybill [put]
  496. // @Security Bearer
  497. func (e WaybillController) Update(c *gin.Context) {
  498. s := service.Waybill{}
  499. req := dto.WaybillUpdateReq{}
  500. err := e.MakeContext(c).
  501. MakeOrm().
  502. Bind(&req).
  503. MakeService(&s.Service).
  504. Errors
  505. if err != nil {
  506. e.Logger.Error(err)
  507. e.Error(500, err, err.Error())
  508. return
  509. }
  510. p := actions.GetPermissionFromContext(c)
  511. req.SetUpdateBy(user.GetUserId(c))
  512. err = s.Update(&req, p)
  513. if err != nil {
  514. e.Error(500, err, err.Error())
  515. return
  516. }
  517. e.OK(req.GetId(), "更新成功")
  518. }
  519. // Delivery 派单
  520. // @Summary 派单
  521. // @Description 派单
  522. // @Tags 运单
  523. // @Accept application/json
  524. // @Product application/json
  525. // @Param data body dto.WaybillDeliveryReq true "body"
  526. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  527. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  528. // @Router /api/waybill [put]
  529. // @Security Bearer
  530. func (e WaybillController) Delivery(c *gin.Context) {
  531. s := service.Waybill{}
  532. IceRaftSvc := service.IceRaft{}
  533. req := dto.WaybillDeliveryReq{}
  534. err := e.MakeContext(c).
  535. MakeOrm().
  536. Bind(&req).
  537. MakeService(&s.Service).
  538. MakeService(&IceRaftSvc.Service).
  539. Errors
  540. if err != nil {
  541. e.Logger.Error(err)
  542. e.Error(500, err, err.Error())
  543. return
  544. }
  545. p := actions.GetPermissionFromContext(c)
  546. oldIceRaftCode := make([]string, 0)
  547. missingIceRaftCode := make([]string, 0)
  548. err = IceRaftSvc.GetPageByCoolerBoxId(req.CoolerBoxId, &oldIceRaftCode, p)
  549. if err != nil {
  550. e.Error(500, err, err.Error())
  551. return
  552. }
  553. req.SetUpdateBy(user.GetUserId(c))
  554. req.OldIceRaftCode = oldIceRaftCode
  555. err = s.Delivery(&req, p)
  556. if err != nil {
  557. e.Error(500, err, err.Error())
  558. return
  559. }
  560. missingIceRaftCode = lib.FindStrListMissingData(oldIceRaftCode, req.IceRaftCode)
  561. if len(missingIceRaftCode) > 0 {
  562. c.JSON(200, map[string]interface{}{
  563. "requestId": uuid.NewUUID(),
  564. "code": 2000,
  565. "msg": "派单成功",
  566. "status": "success",
  567. "data": missingIceRaftCode,
  568. })
  569. return
  570. }
  571. e.OK(req.GetId(), "派单成功")
  572. }
  573. // Delete 删除运单
  574. // @Summary 删除运单
  575. // @Description 删除运单
  576. // @Tags 运单
  577. // @Accept application/json
  578. // @Product application/json
  579. // @Param data body dto.WaybillDeleteReq true "body"
  580. // @Success 200 {string} string "{"code": 200, "message": "删除成功"}"
  581. // @Success 200 {string} string "{"code": -1, "message": "删除失败"}"
  582. // @Router /api/waybill [delete]
  583. // @Security Bearer
  584. func (e WaybillController) Delete(c *gin.Context) {
  585. s := service.Waybill{}
  586. req := dto.WaybillDeleteReq{}
  587. userSvc := service.SysUser{}
  588. err := e.MakeContext(c).
  589. MakeOrm().
  590. Bind(&req, binding.JSON, nil).
  591. MakeService(&s.Service).
  592. MakeService(&userSvc.Service).
  593. Errors
  594. if err != nil {
  595. e.Logger.Error(err)
  596. e.Error(500, err, err.Error())
  597. return
  598. }
  599. //数据权限检查
  600. p := actions.GetPermissionFromContext(c)
  601. err = s.Remove(&req, p)
  602. if err != nil {
  603. e.Error(500, err, err.Error())
  604. return
  605. }
  606. e.OK(req.GetId(), "删除成功")
  607. }
  608. // Receipt 签收
  609. // @Summary 签收
  610. // @Description 签收
  611. // @Tags 运单
  612. // @Accept application/json
  613. // @Product application/json
  614. // @Param data body dto.WaybillInOutReq true "body"
  615. // @Success 200 {string} string "{"code": 200, "message": "删除成功"}"
  616. // @Success 200 {string} string "{"code": -1, "message": "删除失败"}"
  617. // @Router /api/waybill/car-out [post]
  618. // @Security Bearer
  619. func (e WaybillController) Receipt(c *gin.Context) {
  620. s := service.Waybill{}
  621. req := dto.WaybillReceiptReq{}
  622. err := e.MakeContext(c).
  623. MakeOrm().
  624. Bind(&req, binding.JSON, nil).
  625. MakeService(&s.Service).
  626. Errors
  627. if err != nil {
  628. e.Logger.Error(err)
  629. e.Error(500, err, err.Error())
  630. return
  631. }
  632. //数据权限检查
  633. p := actions.GetPermissionFromContext(c)
  634. err = s.Receipt(&req, p)
  635. if err != nil {
  636. e.Error(500, err, err.Error())
  637. return
  638. }
  639. e.OK(req.WaybillNo, "签收成功")
  640. }
  641. // CustomerReceipt 客户签收
  642. // @Summary 客户签收
  643. // @Description 客户签收
  644. // @Tags 运单
  645. // @Accept application/json
  646. // @Product application/json
  647. // @Param data body dto.WaybillReceiptReq true "body"
  648. // @Success 200 {string} string "{"code": 200, "message": "删除成功"}"
  649. // @Success 200 {string} string "{"code": -1, "message": "删除失败"}"
  650. // @Router /api/waybill/car-out [post]
  651. // @Security Bearer
  652. func (e WaybillController) CustomerReceipt(c *gin.Context) {
  653. s := service.Waybill{}
  654. req := dto.WaybillReceiptReq{}
  655. err := e.MakeContext(c).
  656. MakeOrm().
  657. Bind(&req, binding.JSON, nil).
  658. MakeService(&s.Service).
  659. Errors
  660. if err != nil {
  661. e.Logger.Error(err)
  662. e.Error(500, err, err.Error())
  663. return
  664. }
  665. //req.WaybillNo = lib.AesDecryptCBC(req.WaybillNo, lib.AesKey)
  666. //数据权限检查
  667. err = s.Receipt(&req, nil)
  668. if err != nil {
  669. e.Error(500, err, err.Error())
  670. return
  671. }
  672. e.OK(req.WaybillNo, "签收成功")
  673. }
  674. // GetCustomerPage 获取客户运单列表
  675. // @Summary 获取客户运单列表
  676. // @Description 获取客户运单列表
  677. // @Tags 运单
  678. // @Param no query string false "运单号"
  679. // @Param pageSize query int false "页条数"
  680. // @Param page query int false "页码"
  681. // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
  682. // @Router /api/waybill/customer [get]
  683. // @Security Bearer
  684. func (e WaybillController) GetCustomerPage(c *gin.Context) {
  685. s := service.Waybill{}
  686. req := dto.WaybillGetCustomerPageReq{}
  687. err := e.MakeContext(c).
  688. MakeOrm().
  689. Bind(&req, binding.Query).
  690. MakeService(&s.Service).
  691. Errors
  692. if err != nil {
  693. e.Logger.Error(err)
  694. e.Error(500, err, err.Error())
  695. return
  696. }
  697. //数据权限检查
  698. p := actions.GetPermissionFromContext(c)
  699. list := make([]model.Waybill, 0)
  700. var count int64
  701. req.CustomerId = p.UserId
  702. err = s.GetCustomerPage(&req, &list, &count, p)
  703. if err != nil {
  704. e.Error(500, err, err.Error())
  705. return
  706. }
  707. e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
  708. }
  709. func (e WaybillController) CustomerExport(c *gin.Context) {
  710. s := service.Waybill{}
  711. req := dto.WaybillGetCustomerPageReq{}
  712. err := e.MakeContext(c).
  713. MakeOrm().
  714. Bind(&req, binding.Query).
  715. MakeService(&s.Service).
  716. Errors
  717. if err != nil {
  718. e.Logger.Error(err)
  719. e.Error(500, err, err.Error())
  720. return
  721. }
  722. //数据权限检查
  723. p := actions.GetPermissionFromContext(c)
  724. list := make([]model.Waybill, 0)
  725. var count int64
  726. req.CustomerId = p.UserId
  727. req.PageSize = 9999
  728. err = s.GetCustomerPage(&req, &list, &count, p)
  729. if err != nil {
  730. e.Error(500, err, err.Error())
  731. return
  732. }
  733. f := excelize.NewFile() // 设置单元格的值
  734. // 这里设置表头ÒÒ
  735. f.SetCellValue("Sheet1", "A1", "序号")
  736. f.SetCellValue("Sheet1", "B1", "状态")
  737. f.SetCellValue("Sheet1", "C1", "寄件人名称")
  738. f.SetCellValue("Sheet1", "D1", "寄件人电话")
  739. f.SetCellValue("Sheet1", "E1", "寄件人地址")
  740. f.SetCellValue("Sheet1", "F1", "收件人名称")
  741. f.SetCellValue("Sheet1", "G1", "收件人电话")
  742. f.SetCellValue("Sheet1", "H1", "收件人地址")
  743. f.SetCellValue("Sheet1", "I1", "配送人姓名")
  744. f.SetCellValue("Sheet1", "J1", "配送人电话")
  745. f.SetCellValue("Sheet1", "K1", "运输备注")
  746. // 设置列宽
  747. f.SetColWidth("Sheet1", "A", "A", 6)
  748. f.SetColWidth("Sheet1", "B", "B", 8)
  749. f.SetColWidth("Sheet1", "C", "C", 14)
  750. f.SetColWidth("Sheet1", "D", "D", 14)
  751. f.SetColWidth("Sheet1", "E", "E", 30)
  752. f.SetColWidth("Sheet1", "F", "F", 14)
  753. f.SetColWidth("Sheet1", "G", "G", 14)
  754. f.SetColWidth("Sheet1", "H", "H", 30)
  755. f.SetColWidth("Sheet1", "I", "I", 15)
  756. f.SetColWidth("Sheet1", "J", "J", 15)
  757. f.SetColWidth("Sheet1", "K", "K", 15)
  758. line := 1
  759. // 循环写入数据
  760. for i, v := range list {
  761. line++
  762. f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
  763. f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.WaybillStatusMap[v.Status])
  764. f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName)
  765. f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone)
  766. f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails)
  767. f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName)
  768. f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone)
  769. f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails)
  770. f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.DeliveryName)
  771. f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryPhone)
  772. f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.Remark)
  773. }
  774. timeStr := time.Now().Format("20060102150405")
  775. filePath := "ofile/" + "运单" + timeStr + ".xlsx"
  776. defer func() {
  777. os.Remove(filePath)
  778. }()
  779. // 保存文件
  780. if err = f.SaveAs(filePath); err != nil {
  781. logs.Error("保存运单失败:", err)
  782. }
  783. c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
  784. // PathEscape 函数对中文做处理
  785. c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx"))
  786. c.Header("Content-Transfer-Encoding", "binary")
  787. c.File(filePath)
  788. }
  789. // CustomerInsert 客户添加运单
  790. // @Summary 客户添加运单
  791. // @Description 客户添加运单
  792. // @Tags 运单
  793. // @Accept application/json
  794. // @Product application/json
  795. // @Param data body dto.WaybillInsertReq true "data"
  796. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  797. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  798. // @Router /api/waybill/customer [post]
  799. // @Security Bearer
  800. func (e WaybillController) CustomerInsert(c *gin.Context) {
  801. s := service.Waybill{}
  802. userSvc := service.SysUser{}
  803. req := dto.WaybillInsertReq{}
  804. err := e.MakeContext(c).
  805. MakeOrm().
  806. Bind(&req, binding.JSON).
  807. MakeService(&s.Service).
  808. MakeService(&userSvc.Service).
  809. Errors
  810. if err != nil {
  811. e.Logger.Error(err)
  812. e.Error(500, err, err.Error())
  813. return
  814. }
  815. p := actions.GetPermissionFromContext(c)
  816. var userObj model.SysUser
  817. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  818. if err != nil {
  819. e.Error(500, err, "获取用户信息失败")
  820. return
  821. }
  822. if p.DeptId == 0 && req.DeptId == 0 {
  823. e.Error(500, err, "请先选择运输公司")
  824. return
  825. }
  826. // 设置创建人
  827. req.SetCreateBy(user.GetUserId(c))
  828. if p.DeptId > 0 {
  829. req.SetDeptId(p.DeptId)
  830. }
  831. err = s.Insert(&req)
  832. if err != nil {
  833. e.Error(500, err, err.Error())
  834. return
  835. }
  836. e.OK(req.GetId(), "创建成功")
  837. }
  838. // Import 导入运单
  839. // @Summary 导入运单
  840. // @Description 导入运单
  841. // @Tags 运单
  842. // @Accept application/json
  843. // @Product application/json
  844. // @Param data body dto.WaybillInsertReq true "data"
  845. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  846. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  847. // @Router /api/waybill/import [post]
  848. // @Security Bearer
  849. func (e WaybillController) Import(c *gin.Context) {
  850. s := service.Waybill{}
  851. userSvc := service.SysUser{}
  852. req := dto.WaybillImportReq{}
  853. err := e.MakeContext(c).
  854. MakeOrm().
  855. Bind(&req, binding.Form).
  856. MakeService(&s.Service).
  857. MakeService(&userSvc.Service).
  858. Errors
  859. if err != nil {
  860. e.Logger.Error(err)
  861. e.Error(500, err, err.Error())
  862. return
  863. }
  864. //读取第一fileName的文件
  865. fileHeader, err := c.FormFile("file")
  866. if err != nil {
  867. err = errors.New("文件格式错误" + err.Error())
  868. e.Logger.Error(err)
  869. e.Error(500, err, err.Error())
  870. return
  871. }
  872. if fileHeader.Size > 1024*1024*2 {
  873. err = errors.New("文件大小超过2M")
  874. e.Logger.Error(err)
  875. e.Error(500, err, err.Error())
  876. return
  877. }
  878. file, err := fileHeader.Open()
  879. if err != nil {
  880. err = errors.New("文件格式错误" + err.Error())
  881. e.Logger.Error(err)
  882. e.Error(500, err, err.Error())
  883. return
  884. }
  885. defer file.Close()
  886. xlsx, err := excelize.OpenReader(bufio.NewReader(file))
  887. if err != nil {
  888. err = errors.New("文件格式错误" + err.Error())
  889. e.Logger.Error(err)
  890. e.Error(500, err, err.Error())
  891. return
  892. }
  893. p := actions.GetPermissionFromContext(c)
  894. if p.DeptId == 0 {
  895. e.Error(500, err, "获取用户信息失败")
  896. return
  897. }
  898. var userObj model.SysUser
  899. err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj)
  900. if err != nil {
  901. e.Error(500, err, "获取用户信息失败")
  902. return
  903. }
  904. rows, _ := xlsx.GetRows("Sheet1")
  905. for indexRow, row := range rows {
  906. if indexRow == 0 {
  907. continue
  908. }
  909. if len(row) < 10 {
  910. for i := 0; i < 10-len(row); i++ {
  911. row = append(row, "")
  912. }
  913. }
  914. for i, colCell := range row {
  915. fmt.Println(i, ":", colCell)
  916. }
  917. //quantity, _ := strconv.Atoi(row[8])
  918. obj := dto.WaybillInsertReq{
  919. Status: 1,
  920. ConsigneeAddressName: row[0],
  921. ConsigneeAddressPhone: row[1],
  922. ConsigneeAddressDetails: row[2],
  923. TamperProofLabel: row[3], // 防拆标签
  924. Remark: row[4],
  925. ReCheckId: p.UserId,
  926. DeliveryId: p.UserId,
  927. }
  928. obj.SetDeptId(p.DeptId)
  929. obj.SetCreateBy(user.GetUserId(c))
  930. err = s.Insert(&obj)
  931. if err != nil {
  932. e.Error(500, err, err.Error())
  933. return
  934. }
  935. }
  936. e.OK(len(rows)-1, "导入成功")
  937. }
  938. // ExportTemplate 导出运单模板
  939. // @Summary 导出运单模板
  940. // @Description 导出运单模板
  941. // @Tags 运单
  942. // @Accept application/json
  943. // @Product application/json
  944. // @Param data body dto.WaybillInsertReq true "data"
  945. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  946. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  947. // @Router /api/waybill/export-template [post]
  948. // @Security Bearer
  949. func (e WaybillController) ExportTemplate(c *gin.Context) {
  950. s := service.Waybill{}
  951. err := e.MakeContext(c).
  952. MakeOrm().
  953. MakeService(&s.Service).
  954. Errors
  955. if err != nil {
  956. e.Logger.Error(err)
  957. e.Error(500, err, err.Error())
  958. return
  959. }
  960. filePath := "./ofile/运单导入模板.xlsx"
  961. //打开文件
  962. fileTmp, errByOpenFile := os.Open(filePath)
  963. defer fileTmp.Close()
  964. //获取文件的名称
  965. fileName := path.Base(filePath)
  966. if errByOpenFile != nil {
  967. e.Logger.Error(err)
  968. e.Error(500, err, err.Error())
  969. return
  970. }
  971. c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8")
  972. // PathEscape 函数对中文做处理
  973. c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fileName))
  974. c.Header("Content-Transfer-Encoding", "binary")
  975. c.File(filePath)
  976. }
  977. // TemperaturePDF 导出温度记录
  978. // @Summary 导出温度记录
  979. // @Description 导出温度记录
  980. // @Tags 运单
  981. // @Accept application/json
  982. // @Product application/json
  983. // @Param data body dto.WaybillInsertReq true "data"
  984. // @Success 200 {string} string "{"code": 200, "message": "添加成功"}"
  985. // @Success 200 {string} string "{"code": -1, "message": "添加失败"}"
  986. // @Router /api/waybill/temperature-pdf [post]
  987. // @Security Bearer
  988. func (e WaybillController) TemperaturePDF(c *gin.Context) {
  989. s := service.Waybill{}
  990. req := dto.WaybillGetByWaybillPdfReq{}
  991. err := e.MakeContext(c).
  992. MakeOrm().
  993. Bind(&req, binding.Query).
  994. MakeService(&s.Service).
  995. Errors
  996. if err != nil {
  997. e.Logger.Error(err)
  998. e.Error(500, err, err.Error())
  999. return
  1000. }
  1001. var waybill model.Waybill
  1002. //p := actions.GetPermissionFromContext(c)
  1003. //err = s.GetByWaybillNo(&req, &waybill, p)
  1004. err = s.GetByWaybillNo(&req, &waybill, nil)
  1005. if err != nil {
  1006. e.Error(500, err, err.Error())
  1007. return
  1008. }
  1009. DeviceSensor_data, waybillPDF, err := s.GetAllData(&dto.WaybillGetByWaybillNoReq{WaybillNo: req.WaybillNo})
  1010. // 最高温度、最低温度、最高湿度、最低湿度
  1011. var maxTemp, minTemp, maxHumidity, minHumidity float32
  1012. // 最高温度时间、最低温度时间、最高湿度时间、最低湿度时间
  1013. var maxTempTime, minTempTime, maxHumidityTime, minHumidityTime string
  1014. // 总温度 总湿度
  1015. var totalTemp, totalHumidity float32
  1016. // 平均温度 平均湿度
  1017. var avgTemp, avgHumidity float32
  1018. // 温度阈值,湿度阈值
  1019. var tempThreshold, humidityThreshold string
  1020. // 记录开始时间,记录结束时间
  1021. var s_time, e_time string
  1022. var lastTime string
  1023. var isFirst, isSecond = true, false
  1024. var first_column, second_column []nats_server.DeviceData_R
  1025. if len(DeviceSensor_data) > 0 {
  1026. tempThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_tl, DeviceSensor_data[0].T_tu)
  1027. humidityThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_rhl, DeviceSensor_data[0].T_rhu)
  1028. s_time = DeviceSensor_data[0].T_time
  1029. e_time = DeviceSensor_data[len(DeviceSensor_data)-1].T_time
  1030. // 最高温度及时刻
  1031. maxTemp = DeviceSensor_data[0].T_t
  1032. maxTempTime = DeviceSensor_data[0].T_time
  1033. // 最低温度及时刻
  1034. minTemp = DeviceSensor_data[0].T_t
  1035. minTempTime = DeviceSensor_data[0].T_time
  1036. // 最高湿度及时刻
  1037. maxHumidity = DeviceSensor_data[0].T_rh
  1038. maxHumidityTime = DeviceSensor_data[0].T_time
  1039. // 获取最低湿度及时刻
  1040. minHumidity = DeviceSensor_data[0].T_rh
  1041. minHumidityTime = DeviceSensor_data[0].T_time
  1042. for i := 0; i < len(DeviceSensor_data); i++ {
  1043. data := DeviceSensor_data[i]
  1044. if data.T_t > maxTemp {
  1045. maxTemp = data.T_t
  1046. maxTempTime = data.T_time
  1047. }
  1048. if data.T_t < minTemp {
  1049. minTemp = data.T_t
  1050. minTempTime = data.T_time
  1051. }
  1052. totalTemp += data.T_t
  1053. if data.T_rh > maxHumidity {
  1054. maxHumidity = data.T_rh
  1055. maxHumidityTime = data.T_time
  1056. }
  1057. if data.T_rh < minHumidity {
  1058. minHumidity = data.T_rh
  1059. minHumidityTime = data.T_time
  1060. }
  1061. totalHumidity += data.T_rh
  1062. }
  1063. var sn string
  1064. for _, w := range waybillPDF {
  1065. for _, data := range w.Data {
  1066. if len(lastTime) > 0 {
  1067. if lastTime != data.T_time && isFirst == true {
  1068. isFirst = false
  1069. isSecond = true
  1070. } else if lastTime != data.T_time && isSecond == true {
  1071. isFirst = true
  1072. isSecond = false
  1073. }
  1074. }
  1075. if len(sn) > 0 && sn != data.T_sn && len(first_column)%2 == 1 {
  1076. isFirst, isSecond = isSecond, isFirst
  1077. }
  1078. if isFirst {
  1079. first_column = append(first_column, data)
  1080. lastTime = data.T_time
  1081. sn = data.T_sn
  1082. }
  1083. if isSecond {
  1084. second_column = append(second_column, data)
  1085. lastTime = data.T_time
  1086. sn = data.T_sn
  1087. }
  1088. }
  1089. }
  1090. // 平均温度
  1091. avgTemp = totalTemp / float32(len(DeviceSensor_data))
  1092. // 平均湿度
  1093. avgHumidity = totalHumidity / float32(len(DeviceSensor_data))
  1094. }
  1095. // -------------------获取最高温湿度、温蒂温湿度、平均温湿度结束
  1096. pdf := &gopdf.GoPdf{}
  1097. pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
  1098. err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf")
  1099. if err != nil {
  1100. return
  1101. }
  1102. err = pdf.SetFont("wts", "", 20)
  1103. if err != nil {
  1104. return
  1105. }
  1106. pdf.SetGrayFill(0.5)
  1107. pdf.SetMargins(0, 20, 0, 20)
  1108. pdf.AddPage()
  1109. title := "运单" + req.WaybillNo + "温度记录"
  1110. if req.HumidityShow {
  1111. title = "运单" + req.WaybillNo + "温湿度记录"
  1112. }
  1113. var y float64 = 40
  1114. textw, _ := pdf.MeasureTextWidth(title)
  1115. pdf.SetX((595 / 2) - (textw / 2))
  1116. pdf.SetY(y)
  1117. pdf.Text(title)
  1118. //y += 30
  1119. //pdf.SetFont("wts", "", 16)
  1120. //pdf.SetXY(10, y)
  1121. //pdf.Text("实施设备信息")
  1122. //// 线
  1123. //y += 10
  1124. //pdf.SetLineWidth(0.5)
  1125. //pdf.SetStrokeColor(169, 169, 169)
  1126. //pdf.Line(10, y, 585, y)
  1127. //pdf.SetFont("wts", "", 10)
  1128. //y += 20
  1129. //pdf.SetXY(10, y)
  1130. //pdf.Text(fmt.Sprintf("主机名称:%s", device.T_devName))
  1131. //pdf.SetXY(300, y)
  1132. //pdf.Text(fmt.Sprintf("主机编号:%s", device.T_sn))
  1133. y += 25
  1134. pdf.SetFont("wts", "", 16)
  1135. pdf.SetXY(10, y)
  1136. pdf.Text("记录概要信息")
  1137. // 线
  1138. y += 10
  1139. pdf.SetLineWidth(0.5)
  1140. pdf.SetStrokeColor(169, 169, 169)
  1141. pdf.Line(10, y, 585, y)
  1142. y += 20
  1143. pdf.SetFont("wts", "", 10)
  1144. pdf.SetXY(10, y)
  1145. pdf.Text(fmt.Sprintf("记录开始时间:%s", s_time))
  1146. pdf.SetXY(240, y)
  1147. pdf.Text(fmt.Sprintf("记录结束时间:%s", e_time))
  1148. sTime, _ := lib.TimeStrToTime(s_time)
  1149. eTime, _ := lib.TimeStrToTime(e_time)
  1150. pdf.SetXY(470, y)
  1151. minutes := int(eTime.Sub(sTime).Minutes())
  1152. hours := minutes / 60
  1153. remainingMinutes := minutes % 60
  1154. pdf.Text(fmt.Sprintf("记录总时间:%dh%dmin", hours, remainingMinutes))
  1155. // -------------最高温/湿度 最低温/湿度 平均温/湿度
  1156. y += 15
  1157. pdf.SetXY(10, y)
  1158. pdf.Text(fmt.Sprintf("最高温度:%.1f℃,%s", lib.RoundToDecimal(float64(maxTemp), 1), maxTempTime))
  1159. pdf.SetXY(240, y)
  1160. pdf.Text(fmt.Sprintf("最低温度:%.1f℃,%s", lib.RoundToDecimal(float64(minTemp), 1), minTempTime))
  1161. pdf.SetXY(470, y)
  1162. pdf.Text(fmt.Sprintf("平均温度:%.1f℃", lib.RoundToDecimal(float64(avgTemp), 1)))
  1163. if req.HumidityShow {
  1164. y += 15
  1165. pdf.SetXY(10, y)
  1166. pdf.Text(fmt.Sprintf("最高湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(maxHumidity), 1), maxHumidityTime))
  1167. pdf.SetXY(240, y)
  1168. pdf.Text(fmt.Sprintf("最低湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(minHumidity), 1), minHumidityTime))
  1169. pdf.SetXY(470, y)
  1170. pdf.Text(fmt.Sprintf("平均湿度:%.1f%%RH", lib.RoundToDecimal(float64(avgHumidity), 1)))
  1171. }
  1172. // -------------温/湿度阈值
  1173. y += 15
  1174. pdf.SetXY(10, y)
  1175. pdf.Text(fmt.Sprintf("温度阈值:%s℃", tempThreshold))
  1176. if req.HumidityShow {
  1177. pdf.SetXY(240, y)
  1178. pdf.Text(fmt.Sprintf("温度阈值:%s%%", humidityThreshold))
  1179. }
  1180. //-------------发货单位,收货单位,备注
  1181. y += 15
  1182. pdf.SetXY(10, y)
  1183. T_forwarding_unit_temp := []rune(waybill.SenderAddressName)
  1184. if len(T_forwarding_unit_temp) > 17 {
  1185. pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp[0:17])))
  1186. pdf.SetXY(60, y+15)
  1187. pdf.Text(fmt.Sprintf("%s", string(T_forwarding_unit_temp[17:])))
  1188. } else {
  1189. pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp)))
  1190. }
  1191. pdf.SetXY(240, y)
  1192. T_consignee_unit_temp := []rune(waybill.ConsigneeAddressName)
  1193. if len(T_consignee_unit_temp) > 17 {
  1194. pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp[0:17])))
  1195. pdf.SetXY(290, y+15)
  1196. pdf.Text(fmt.Sprintf("%s", string(T_consignee_unit_temp[17:])))
  1197. } else {
  1198. pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp)))
  1199. }
  1200. // 承运方
  1201. y += 15
  1202. pdf.SetXY(10, y)
  1203. company_name := []rune(waybill.Dept.Name)
  1204. pdf.Text(fmt.Sprintf("承运方:%s", string(company_name)))
  1205. y += 15
  1206. pdf.SetXY(10, y)
  1207. T_remark_temp := []rune(waybill.Remark)
  1208. if len(waybill.Remark) > 35 {
  1209. pdf.Text(fmt.Sprintf("备注:%s", string(T_remark_temp[0:35])))
  1210. pdf.SetXY(10, y+15)
  1211. pdf.Text(fmt.Sprintf("%s", string(T_remark_temp[35:])))
  1212. } else {
  1213. pdf.Text(fmt.Sprintf("备注: %s", string(T_remark_temp)))
  1214. }
  1215. y += 15
  1216. //pdf.SetFont("wts", "", 16)
  1217. //pdf.SetXY(10, y)
  1218. //pdf.Text("记录曲线信息")
  1219. //// 线
  1220. //y += 10
  1221. //pdf.SetLineWidth(0.5)
  1222. //pdf.SetStrokeColor(169, 169, 169)
  1223. //pdf.Line(10, y, 585, y)
  1224. //y += 1
  1225. //
  1226. //var tempFilepath string
  1227. //tempFilepath, err = DeviceDataTemperatureJPG2(s_time, e_time, waybillPDF)
  1228. //if err == nil {
  1229. // imgH, _ := gopdf.ImageHolderByPath(tempFilepath)
  1230. // pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315})
  1231. // y += 315
  1232. //}
  1233. //
  1234. //var humidityFilepath string
  1235. //if req.HumidityShow {
  1236. // humidityFilepath, err = DeviceDataHumidityJPG2(s_time, e_time, waybillPDF)
  1237. // if err == nil {
  1238. // imgH, _ := gopdf.ImageHolderByPath(humidityFilepath)
  1239. // pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315})
  1240. // y += 315
  1241. // }
  1242. //}
  1243. if y > 841.89 {
  1244. // 图片结束直接分页
  1245. pdf.AddPage()
  1246. y = 20
  1247. }
  1248. y += 20
  1249. pdf.SetFont("wts", "", 16)
  1250. pdf.SetXY(10, y)
  1251. pdf.Text("记录数据信息")
  1252. // 线
  1253. y += 10
  1254. pdf.SetLineWidth(0.5)
  1255. pdf.SetStrokeColor(169, 169, 169)
  1256. pdf.Line(10, y, 585, y)
  1257. y += 10
  1258. pdf.SetFont("wts", "", 10)
  1259. var x float64 = 10
  1260. var w float64 = 112
  1261. lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1262. x = x + w
  1263. w = 101
  1264. lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1265. if req.HumidityShow {
  1266. x = x + w
  1267. w = 37
  1268. lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1269. x = x + w
  1270. w = 37
  1271. lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1272. } else {
  1273. x = x + w
  1274. w = 37 * 2
  1275. lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1276. }
  1277. x = x + w
  1278. w = 112
  1279. lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1280. x = x + w
  1281. w = 101
  1282. lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1283. if req.HumidityShow {
  1284. x = x + w
  1285. w = 37
  1286. lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1287. x = x + w
  1288. w = 37
  1289. lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1290. } else {
  1291. x = x + w
  1292. w = 37 * 2
  1293. lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1294. }
  1295. y += 20
  1296. var textH float64 = 25 // if text height is 25px.
  1297. for i, v := range first_column {
  1298. pdf.SetNewY(y, textH)
  1299. y = pdf.GetY()
  1300. x, w = 10, 112
  1301. lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1302. x = x + w
  1303. w = 101
  1304. lib.RectFillColor(pdf, v.T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1305. // 显示温湿度
  1306. if req.HumidityShow {
  1307. x = x + w
  1308. w = 37
  1309. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1310. x = x + w
  1311. w = 37
  1312. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1313. } else {
  1314. x = x + w
  1315. w = 37 * 2
  1316. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1317. }
  1318. if i < len(second_column) {
  1319. x = x + w
  1320. w = 112
  1321. lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1322. x = x + w
  1323. w = 101
  1324. lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1325. if req.HumidityShow {
  1326. x = x + w
  1327. w = 37
  1328. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1329. x = x + w
  1330. w = 37
  1331. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1332. } else {
  1333. x = x + w
  1334. w = 37 * 2
  1335. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1336. }
  1337. }
  1338. y += 20
  1339. }
  1340. if len(second_column) > len(first_column) {
  1341. for i := len(first_column); i < len(second_column); i++ {
  1342. pdf.SetNewY(y, textH)
  1343. y = pdf.GetY()
  1344. x, w = 297, 112
  1345. lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1346. x = x + w
  1347. w = 101
  1348. lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1349. if req.HumidityShow {
  1350. x = x + w
  1351. w = 37
  1352. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1353. x = x + w
  1354. w = 37
  1355. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1356. } else {
  1357. x = x + w
  1358. w = 37 * 2
  1359. lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
  1360. }
  1361. y += 20
  1362. }
  1363. }
  1364. filename := "运单" + req.WaybillNo + "温湿度记录" + time.Now().Format("20060102150405") + ".pdf"
  1365. filePath := "ofile/" + filename
  1366. err = pdf.WritePdf(filePath)
  1367. if err != nil {
  1368. return
  1369. }
  1370. defer func() {
  1371. //os.Remove(tempFilepath)
  1372. //os.Remove(humidityFilepath)
  1373. os.Remove(filePath)
  1374. }()
  1375. c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(filename))
  1376. c.Header("Content-Transfer-Encoding", "binary")
  1377. c.File(filePath)
  1378. }
  1379. // 获取温度图片
  1380. func DeviceDataTemperatureJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
  1381. if len(waybillPDF) == 0 {
  1382. return "", errors.New("暂无数据可生成图片")
  1383. }
  1384. // 创建一个新的绘图
  1385. p := plot.New()
  1386. // 设置绘图标题和标签
  1387. p.Title.Text = "temperature"
  1388. //p.Legend.ThumbnailWidth = 20
  1389. deviceSensorList := []nats_server.DeviceSensor_R{}
  1390. dataList := []nats_server.DeviceData_R{}
  1391. for _, w := range waybillPDF {
  1392. deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
  1393. dataList = append(dataList, w.Data...)
  1394. }
  1395. TemperatureMin := deviceSensorList[0].T_DeviceSensorParameter.T_Tlower
  1396. TemperatureMax := deviceSensorList[0].T_DeviceSensorParameter.T_Tupper
  1397. var ymin, ymax float32
  1398. for i, r := range dataList {
  1399. if i == 0 {
  1400. ymin = r.T_t
  1401. ymax = r.T_t
  1402. }
  1403. if ymin > r.T_t {
  1404. ymin = r.T_t
  1405. }
  1406. if ymax < r.T_t {
  1407. ymax = r.T_t
  1408. }
  1409. }
  1410. var chData = make(chan int, 10)
  1411. var jobGroup sync.WaitGroup
  1412. // 创建温度线
  1413. for i := 0; i < len(deviceSensorList); i++ {
  1414. chData <- 1
  1415. jobGroup.Add(1)
  1416. go func(index int) {
  1417. defer func() {
  1418. <-chData // 完成时chan取出1个
  1419. jobGroup.Done() // 完成时将等待组值减1
  1420. }()
  1421. sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
  1422. r_maps := []nats_server.DeviceData_R{}
  1423. for _, data := range dataList {
  1424. if data.T_sn == sn && data.T_id == id {
  1425. r_maps = append(r_maps, data)
  1426. }
  1427. }
  1428. fmt.Println(r_maps)
  1429. if len(r_maps) == 0 {
  1430. return
  1431. }
  1432. sort.Slice(r_maps, func(i, j int) bool {
  1433. return r_maps[i].T_time < r_maps[j].T_time
  1434. })
  1435. pts := make(plotter.XYs, len(r_maps))
  1436. for j, d := range r_maps {
  1437. t, _ := lib.TimeStrToTime(d.T_time)
  1438. pts[j].X = float64(t.Unix())
  1439. pts[j].Y = float64(d.T_t)
  1440. }
  1441. line, err := plotter.NewLine(pts)
  1442. if err != nil {
  1443. return
  1444. }
  1445. line.Color = randomColor(index)
  1446. p.Add(line)
  1447. }(i)
  1448. }
  1449. jobGroup.Wait()
  1450. st, _ := lib.TimeStrToTime(startTime)
  1451. et, _ := lib.TimeStrToTime(endTime)
  1452. xmin, xmax := float64(st.Unix()), float64(et.Unix())
  1453. // 添加最高,最低标准线 用红色虚线标识
  1454. p.Add(horizontalLine(xmin, xmax, float64(TemperatureMin)))
  1455. p.Add(horizontalLine(xmin, xmax, float64(TemperatureMax)))
  1456. if ymax < TemperatureMax {
  1457. ymax = TemperatureMax
  1458. }
  1459. if ymin > 0 {
  1460. ymin = 0
  1461. }
  1462. p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)
  1463. p.X.Min, p.X.Max = xmin, xmax
  1464. p.Y.Tick.Marker = commaTicks{}
  1465. p.X.Tick.Marker = timeTicks{}
  1466. p.X.Tick.Label.Rotation = math.Pi / 5
  1467. p.X.Tick.Label.YAlign = draw.YCenter
  1468. p.X.Tick.Label.XAlign = draw.XRight
  1469. filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg"
  1470. // 保存文件
  1471. if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {
  1472. logs.Error(lib.FuncName(), "生成图片失败", err)
  1473. return "", err
  1474. }
  1475. return filepath, nil
  1476. }
  1477. func DeviceDataTemperatureJPG2(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
  1478. if len(waybillPDF) == 0 {
  1479. return "", errors.New("暂无数据可生成图片")
  1480. }
  1481. deviceSensorList := []nats_server.DeviceSensor_R{}
  1482. dataList := []nats_server.DeviceData_R{}
  1483. for _, w := range waybillPDF {
  1484. deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
  1485. dataList = append(dataList, w.Data...)
  1486. }
  1487. TemperatureMin := deviceSensorList[0].T_DeviceSensorParameter.T_Tlower
  1488. TemperatureMax := deviceSensorList[0].T_DeviceSensorParameter.T_Tupper
  1489. var ymin, ymax float32
  1490. for i, r := range dataList {
  1491. if i == 0 {
  1492. ymin = r.T_t
  1493. ymax = r.T_t
  1494. }
  1495. if ymin > r.T_t {
  1496. ymin = r.T_t
  1497. }
  1498. if ymax < r.T_t {
  1499. ymax = r.T_t
  1500. }
  1501. }
  1502. series := make([]chart.Series, 0)
  1503. var chData = make(chan int, 10)
  1504. var jobGroup sync.WaitGroup
  1505. // 创建温度线
  1506. for i := 0; i < len(deviceSensorList); i++ {
  1507. chData <- 1
  1508. jobGroup.Add(1)
  1509. go func(index int) {
  1510. defer func() {
  1511. <-chData // 完成时chan取出1个
  1512. jobGroup.Done() // 完成时将等待组值减1
  1513. }()
  1514. sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
  1515. r_maps := []nats_server.DeviceData_R{}
  1516. for _, data := range dataList {
  1517. if data.T_sn == sn && data.T_id == id {
  1518. r_maps = append(r_maps, data)
  1519. }
  1520. }
  1521. fmt.Println(r_maps)
  1522. if len(r_maps) == 0 {
  1523. return
  1524. }
  1525. sort.Slice(r_maps, func(i, j int) bool {
  1526. return r_maps[i].T_time < r_maps[j].T_time
  1527. })
  1528. xValues := make([]time.Time, len(r_maps))
  1529. yValues := make([]float64, len(r_maps))
  1530. for j := 0; j < len(r_maps); j++ {
  1531. t, _ := lib.TimeStrToTime(r_maps[j].T_time)
  1532. xValues[j] = t
  1533. yValues[j] = float64(r_maps[j].T_t)
  1534. }
  1535. series = append(series, chart.TimeSeries{
  1536. Name: fmt.Sprintf("%s-%d", sn, id),
  1537. XValues: xValues,
  1538. YValues: yValues,
  1539. })
  1540. }(i)
  1541. }
  1542. jobGroup.Wait()
  1543. if ymax < TemperatureMax {
  1544. ymax = TemperatureMax
  1545. }
  1546. if ymin > 0 {
  1547. ymin = 0
  1548. }
  1549. if ymin > TemperatureMin {
  1550. ymin = TemperatureMin
  1551. }
  1552. st, _ := lib.TimeStrToTime(startTime)
  1553. et, _ := lib.TimeStrToTime(endTime)
  1554. series = append(series, chart.TimeSeries{
  1555. Style: chart.Style{
  1556. StrokeColor: drawing.ColorRed,
  1557. StrokeDashArray: []float64{5.0, 5.0},
  1558. },
  1559. XValues: []time.Time{st, et},
  1560. YValues: []float64{float64(TemperatureMin), float64(TemperatureMin)},
  1561. })
  1562. series = append(series, chart.TimeSeries{
  1563. Style: chart.Style{
  1564. StrokeColor: drawing.ColorRed,
  1565. StrokeDashArray: []float64{5.0, 5.0},
  1566. },
  1567. XValues: []time.Time{st, et},
  1568. YValues: []float64{float64(TemperatureMax), float64(TemperatureMax)},
  1569. })
  1570. font := getZWFont()
  1571. graph := chart.Chart{
  1572. Title: "温度记录",
  1573. TitleStyle: chart.Style{
  1574. FontSize: 15,
  1575. },
  1576. Background: chart.Style{
  1577. Padding: chart.Box{
  1578. Top: 20,
  1579. },
  1580. },
  1581. Font: font,
  1582. XAxis: chart.XAxis{
  1583. Name: "时间",
  1584. ValueFormatter: chart.TimeValueFormatterWithFormat("2006-01-02 15:04"),
  1585. },
  1586. YAxis: chart.YAxis{
  1587. Name: "温度",
  1588. Range: &chart.ContinuousRange{
  1589. Min: float64(ymin),
  1590. Max: float64(ymax + 2),
  1591. },
  1592. },
  1593. Series: series,
  1594. }
  1595. //graph.Elements = []chart.Renderable{
  1596. // chart.Legend(&graph),
  1597. //}
  1598. filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg"
  1599. f, _ := os.Create(filepath)
  1600. defer f.Close()
  1601. graph.Render(chart.PNG, f)
  1602. return filepath, nil
  1603. }
  1604. // 获取湿度图片
  1605. func DeviceDataHumidityJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
  1606. if len(waybillPDF) == 0 {
  1607. return "", errors.New("暂无数据可生成图片")
  1608. }
  1609. // 创建一个新的绘图
  1610. p := plot.New()
  1611. // 设置绘图标题和标签
  1612. p.Title.Text = "humidity"
  1613. deviceSensorList := []nats_server.DeviceSensor_R{}
  1614. dataList := []nats_server.DeviceData_R{}
  1615. for _, w := range waybillPDF {
  1616. deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
  1617. dataList = append(dataList, w.Data...)
  1618. }
  1619. humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
  1620. humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper
  1621. var ymin, ymax float32
  1622. for i, r := range dataList {
  1623. if i == 0 {
  1624. ymin = r.T_rh
  1625. ymax = r.T_rh
  1626. }
  1627. if ymin > r.T_rh {
  1628. ymin = r.T_rh
  1629. }
  1630. if ymax < r.T_rh {
  1631. ymax = r.T_rh
  1632. }
  1633. }
  1634. var chData = make(chan int, 10)
  1635. var jobGroup sync.WaitGroup
  1636. // 创建温度线
  1637. for i := 0; i < len(deviceSensorList); i++ {
  1638. chData <- 1
  1639. jobGroup.Add(1)
  1640. go func(index int) {
  1641. defer func() {
  1642. <-chData // 完成时chan取出1个
  1643. jobGroup.Done() // 完成时将等待组值减1
  1644. }()
  1645. sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
  1646. r_maps := []nats_server.DeviceData_R{}
  1647. for _, data := range dataList {
  1648. if data.T_sn == sn && data.T_id == id {
  1649. r_maps = append(r_maps, data)
  1650. }
  1651. }
  1652. if len(r_maps) == 0 {
  1653. return
  1654. }
  1655. sort.Slice(r_maps, func(i, j int) bool {
  1656. return r_maps[i].T_time < r_maps[j].T_time
  1657. })
  1658. pts := make(plotter.XYs, len(r_maps))
  1659. for j, d := range r_maps {
  1660. t, _ := lib.TimeStrToTime(d.T_time)
  1661. pts[j].X = float64(t.Unix())
  1662. pts[j].Y = float64(d.T_rh)
  1663. }
  1664. line, err := plotter.NewLine(pts)
  1665. if err != nil {
  1666. return
  1667. }
  1668. line.Color = randomColor(index)
  1669. p.Add(line)
  1670. }(i)
  1671. }
  1672. jobGroup.Wait()
  1673. st, _ := lib.TimeStrToTime(startTime)
  1674. et, _ := lib.TimeStrToTime(endTime)
  1675. xmin, xmax := float64(st.Unix()), float64(et.Unix())
  1676. // 添加最高,最低标准线 用红色虚线标识
  1677. p.Add(horizontalLine(xmin, xmax, float64(humidityMin)))
  1678. p.Add(horizontalLine(xmin, xmax, float64(humidityMax)))
  1679. if ymax < humidityMax {
  1680. ymax = humidityMax
  1681. }
  1682. if ymin > 0 {
  1683. ymin = 0
  1684. }
  1685. p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)
  1686. p.X.Min, p.X.Max = xmin, xmax
  1687. p.Y.Tick.Marker = commaTicks{}
  1688. //p.X.Tick.Marker = plot.TimeTicks{Format: "2006-01-02 15:04:05"}
  1689. p.X.Tick.Marker = timeTicks{}
  1690. p.X.Tick.Label.Rotation = math.Pi / 5
  1691. p.X.Tick.Label.YAlign = draw.YCenter
  1692. p.X.Tick.Label.XAlign = draw.XRight
  1693. filepath := "ofile/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
  1694. // 保存文件
  1695. if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {
  1696. logs.Error(lib.FuncName(), "生成图片失败", err)
  1697. return "", err
  1698. }
  1699. return filepath, nil
  1700. }
  1701. func DeviceDataHumidityJPG2(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {
  1702. if len(waybillPDF) == 0 {
  1703. return "", errors.New("暂无数据可生成图片")
  1704. }
  1705. deviceSensorList := []nats_server.DeviceSensor_R{}
  1706. dataList := []nats_server.DeviceData_R{}
  1707. for _, w := range waybillPDF {
  1708. deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
  1709. dataList = append(dataList, w.Data...)
  1710. }
  1711. humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
  1712. humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper
  1713. var ymin, ymax float32
  1714. for i, r := range dataList {
  1715. if i == 0 {
  1716. ymin = r.T_t
  1717. ymax = r.T_t
  1718. }
  1719. if ymin > r.T_t {
  1720. ymin = r.T_t
  1721. }
  1722. if ymax < r.T_t {
  1723. ymax = r.T_t
  1724. }
  1725. }
  1726. series := make([]chart.Series, 0)
  1727. var chData = make(chan int, 10)
  1728. var jobGroup sync.WaitGroup
  1729. // 创建温度线
  1730. for i := 0; i < len(deviceSensorList); i++ {
  1731. chData <- 1
  1732. jobGroup.Add(1)
  1733. go func(index int) {
  1734. defer func() {
  1735. <-chData // 完成时chan取出1个
  1736. jobGroup.Done() // 完成时将等待组值减1
  1737. }()
  1738. sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
  1739. r_maps := []nats_server.DeviceData_R{}
  1740. for _, data := range dataList {
  1741. if data.T_sn == sn && data.T_id == id {
  1742. r_maps = append(r_maps, data)
  1743. }
  1744. }
  1745. if len(r_maps) == 0 {
  1746. return
  1747. }
  1748. sort.Slice(r_maps, func(i, j int) bool {
  1749. return r_maps[i].T_time < r_maps[j].T_time
  1750. })
  1751. xValues := make([]time.Time, len(r_maps))
  1752. yValues := make([]float64, len(r_maps))
  1753. for j := 0; j < len(r_maps); j++ {
  1754. t, _ := lib.TimeStrToTime(r_maps[j].T_time)
  1755. xValues[j] = t
  1756. yValues[j] = float64(r_maps[j].T_rh)
  1757. }
  1758. series = append(series, chart.TimeSeries{
  1759. Name: fmt.Sprintf("%s-%d", sn, id),
  1760. XValues: xValues,
  1761. YValues: yValues,
  1762. })
  1763. }(i)
  1764. }
  1765. jobGroup.Wait()
  1766. if ymax < humidityMax {
  1767. ymax = humidityMax
  1768. }
  1769. if ymin > 0 {
  1770. ymin = 0
  1771. }
  1772. if ymin > humidityMin {
  1773. ymin = humidityMin
  1774. }
  1775. st, _ := lib.TimeStrToTime(startTime)
  1776. et, _ := lib.TimeStrToTime(endTime)
  1777. series = append(series, chart.TimeSeries{
  1778. Style: chart.Style{
  1779. StrokeColor: drawing.ColorRed,
  1780. StrokeDashArray: []float64{5.0, 5.0},
  1781. },
  1782. XValues: []time.Time{st, et},
  1783. YValues: []float64{float64(humidityMin), float64(humidityMin)},
  1784. })
  1785. series = append(series, chart.TimeSeries{
  1786. Style: chart.Style{
  1787. StrokeColor: drawing.ColorRed,
  1788. StrokeDashArray: []float64{5.0, 5.0},
  1789. },
  1790. XValues: []time.Time{st, et},
  1791. YValues: []float64{float64(humidityMax), float64(humidityMax)},
  1792. })
  1793. font := getZWFont()
  1794. graph := chart.Chart{
  1795. Title: "湿度记录",
  1796. TitleStyle: chart.Style{
  1797. FontSize: 15,
  1798. },
  1799. Background: chart.Style{
  1800. Padding: chart.Box{
  1801. Top: 20,
  1802. },
  1803. },
  1804. Font: font,
  1805. XAxis: chart.XAxis{
  1806. Name: "时间",
  1807. ValueFormatter: chart.TimeValueFormatterWithFormat("2006-01-02 15:04"),
  1808. },
  1809. YAxis: chart.YAxis{
  1810. Name: "湿度",
  1811. Range: &chart.ContinuousRange{
  1812. Min: float64(ymin),
  1813. Max: float64(ymax + 2),
  1814. },
  1815. },
  1816. Series: series,
  1817. }
  1818. //graph.Elements = []chart.Renderable{
  1819. // chart.Legend(&graph),
  1820. //}
  1821. filepath := "ofile/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
  1822. f, _ := os.Create(filepath)
  1823. defer f.Close()
  1824. graph.Render(chart.PNG, f)
  1825. return filepath, nil
  1826. }
  1827. func horizontalLine(xmin, xmax, y float64) *plotter.Line {
  1828. pts := make(plotter.XYs, 2)
  1829. pts[0].X = xmin
  1830. pts[0].Y = y
  1831. pts[1].X = xmax
  1832. pts[1].Y = y
  1833. line, err := plotter.NewLine(pts)
  1834. if err != nil {
  1835. panic(err)
  1836. }
  1837. line.LineStyle.Dashes = []vg.Length{vg.Points(8), vg.Points(5), vg.Points(1), vg.Points(5)}
  1838. line.Color = color.RGBA{R: 255, A: 255}
  1839. return line
  1840. }
  1841. type timeTicks struct{}
  1842. func (timeTicks) Ticks(min, max float64) []plot.Tick {
  1843. tks := plot.TimeTicks{}.Ticks(min, max)
  1844. for i, t := range tks {
  1845. //if t.Label == "" { // Skip minor ticks, they are fine.
  1846. // continue
  1847. //}
  1848. tks[i].Label = time.Unix(int64(t.Value), 0).Format("2006-01-02 15:04:05")
  1849. }
  1850. return tks
  1851. }
  1852. type commaTicks struct{}
  1853. // Ticks computes the default tick marks, but inserts commas
  1854. // into the labels for the major tick marks.
  1855. func (commaTicks) Ticks(min, max float64) []plot.Tick {
  1856. tks := plot.DefaultTicks{}.Ticks(min, max)
  1857. for i, t := range tks {
  1858. //if t.Label == "" { // Skip minor ticks, they are fine.
  1859. // continue
  1860. //}
  1861. tks[i].Label = fmt.Sprintf("%.0f", t.Value)
  1862. }
  1863. return tks
  1864. }
  1865. // 生成随机颜色的辅助函数
  1866. func randomColor(i int) color.RGBA {
  1867. var colors []color.RGBA
  1868. colors = append(colors,
  1869. color.RGBA{R: 52, G: 152, B: 219, A: 255},
  1870. color.RGBA{R: 230, G: 126, B: 34, A: 255},
  1871. color.RGBA{R: 142, G: 68, B: 173, A: 255},
  1872. color.RGBA{R: 211, G: 84, B: 0, A: 255},
  1873. color.RGBA{R: 231, G: 76, B: 60, A: 255},
  1874. color.RGBA{R: 26, G: 188, B: 156, A: 255},
  1875. color.RGBA{R: 243, G: 156, B: 18, A: 255},
  1876. color.RGBA{R: 22, G: 160, B: 133, A: 255},
  1877. color.RGBA{R: 46, G: 204, B: 113, A: 255},
  1878. color.RGBA{R: 39, G: 174, B: 96, A: 255},
  1879. color.RGBA{R: 41, G: 128, B: 185, A: 255},
  1880. color.RGBA{R: 155, G: 89, B: 182, A: 255},
  1881. color.RGBA{R: 192, G: 57, B: 43, A: 255},
  1882. color.RGBA{R: 241, G: 196, B: 15, A: 255},
  1883. )
  1884. return colors[i%len(colors)]
  1885. }
  1886. func randomColor2(i int) drawing.Color {
  1887. var colors []drawing.Color
  1888. colors = append(colors,
  1889. drawing.Color{R: 52, G: 152, B: 219, A: 255},
  1890. drawing.Color{R: 230, G: 126, B: 34, A: 255},
  1891. drawing.Color{R: 142, G: 68, B: 173, A: 255},
  1892. drawing.Color{R: 211, G: 84, B: 0, A: 255},
  1893. drawing.Color{R: 231, G: 76, B: 60, A: 255},
  1894. drawing.Color{R: 26, G: 188, B: 156, A: 255},
  1895. drawing.Color{R: 243, G: 156, B: 18, A: 255},
  1896. drawing.Color{R: 22, G: 160, B: 133, A: 255},
  1897. drawing.Color{R: 46, G: 204, B: 113, A: 255},
  1898. drawing.Color{R: 39, G: 174, B: 96, A: 255},
  1899. drawing.Color{R: 41, G: 128, B: 185, A: 255},
  1900. drawing.Color{R: 155, G: 89, B: 182, A: 255},
  1901. drawing.Color{R: 192, G: 57, B: 43, A: 255},
  1902. drawing.Color{R: 241, G: 196, B: 15, A: 255},
  1903. )
  1904. return colors[i%len(colors)]
  1905. }
  1906. // getZWFont 加载字体
  1907. func getZWFont() *truetype.Font {
  1908. fontFile := "./static/fonts/MiSans-Medium.ttf"
  1909. fontBytes, err := os.ReadFile(fontFile)
  1910. if err != nil {
  1911. log.Println(err)
  1912. return nil
  1913. }
  1914. font, err := truetype.Parse(fontBytes)
  1915. if err != nil {
  1916. log.Println(err)
  1917. return nil
  1918. }
  1919. return font
  1920. }