siteInfoManageServices.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package services
  2. import (
  3. "context"
  4. "fmt"
  5. "fwh-toolbox-server/domain"
  6. "fwh-toolbox-server/dto"
  7. "fwh-toolbox-server/repositories"
  8. "fwh-toolbox-server/task/queue/fwhQueue"
  9. "fwh-toolbox-server/utils/global"
  10. "math"
  11. "regexp"
  12. "strconv"
  13. "time"
  14. "github.com/xuri/excelize/v2"
  15. "go.uber.org/zap"
  16. )
  17. var VERSION_REGEX = regexp.MustCompile(`V(\d+)R(\d+)B(\d+)D(\d+)`)
  18. // 获取更新状态
  19. func GetSiteInfoUpdateStatus() (*domain.SiteInfoUpdateRecord, error) {
  20. return repositories.GetSiteInfoUpdateNewRecord()
  21. }
  22. // 请求更新站点信息表
  23. func UpdateSiteInfoDate() error {
  24. id, err := repositories.CreateSiteInfoUpdateInfo()
  25. if err != nil {
  26. return err
  27. }
  28. if err := fwhQueue.EnqueueSiteInfoUpdateTask(domain.TaskSiteInfoUpdate{
  29. Id: *id,
  30. }); err != nil {
  31. // 入队失败时标记记录为失败,避免一直停在 pending 被当成“同步中”
  32. if e := repositories.UpdateSiteInfoUpdateResult(*id, domain.ProgressError, 0); e != nil {
  33. zap.L().Error("UpdateSiteInfoDate mark error failed.", zap.String("id", id.Hex()), zap.String("err", e.Error()))
  34. }
  35. return err
  36. }
  37. return nil
  38. }
  39. // 获取站点信息表
  40. func QuerySiteInfoDataList(para dto.SiteInfoRequest) (*dto.ResPage[dto.SiteInfoDTO], error) {
  41. res, err := repositories.GetSiteInfoManageList(para.PageNum, para.PageSize, para.Filter, para.Search)
  42. if err != nil {
  43. return nil, err
  44. }
  45. idList := []string{}
  46. for _, data := range res.Data {
  47. if data.ExtTags != nil {
  48. idList = append(idList, *data.ExtTags...)
  49. }
  50. }
  51. tagMap, err := repositories.GetSiteInfoTagsFromId(idList)
  52. if err != nil {
  53. zap.L().Error("QuerySiteInfoDataList GetSiteInfoTagsFromId failed.", zap.String("err", err.Error()), zap.Strings("idList", idList))
  54. return nil, err
  55. }
  56. result := dto.ResPage[dto.SiteInfoDTO]{
  57. Data: dto.SiteInfoDomainListToSiteInfoDTOList(res.Data, &tagMap),
  58. PageSize: res.PageSize,
  59. PageNum: res.PageNum,
  60. Total: res.Total,
  61. }
  62. return &result, nil
  63. }
  64. // 导出站点信息表
  65. func ExportSiteInfoDataList(filer *domain.SiteInfoFilter) (*excelize.File, error) {
  66. res, err := repositories.GetSiteInfoManageList(0, 0, filer, "")
  67. if err != nil {
  68. return nil, err
  69. }
  70. record, err := repositories.GetSiteInfoUpdateNewRecord()
  71. if err != nil {
  72. return nil, err
  73. }
  74. // 创建新的excel文件
  75. f := excelize.NewFile()
  76. // 写标题行
  77. f.SetCellValue("Sheet1", "A1", "SN")
  78. f.SetCellValue("Sheet1", "B1", "Installer")
  79. f.SetCellValue("Sheet1", "C1", "ActiveTime")
  80. f.SetCellValue("Sheet1", "D1", "Status")
  81. f.SetCellValue("Sheet1", "E1", "OnLineTime")
  82. f.SetCellValue("Sheet1", "F1", "OffLineTime")
  83. f.SetCellValue("Sheet1", "G1", "FhpSn")
  84. f.SetCellValue("Sheet1", "H1", "Version")
  85. f.SetCellValue("Sheet1", "I1", "SlVersion")
  86. f.SetCellValue("Sheet1", "J1", "SlVersionJson")
  87. f.SetCellValue("Sheet1", "K1", "MeterVersion")
  88. f.SetCellValue("Sheet1", "L1", "MbVersion")
  89. f.SetCellValue("Sheet1", "M1", "AwsVersion")
  90. f.SetCellValue("Sheet1", "N1", "AppVersion")
  91. f.SetCellValue("Sheet1", "O1", "ProtocolVer")
  92. f.SetCellValue("Sheet1", "P1", "SysHdVersion")
  93. f.SetCellValue("Sheet1", "Q1", "Remark")
  94. f.SetCellValue("Sheet1", "R1", "Country")
  95. f.SetCellValue("Sheet1", "S1", "Province")
  96. f.SetCellValue("Sheet1", "T1", "ManufactureDate")
  97. f.SetCellValue("Sheet1", "U1", "HardwareVersion")
  98. f.SetCellValue("Sheet1", "V1", "CveStatus")
  99. f.SetCellValue("Sheet1", "W1", "SecurityPatchLevel")
  100. f.SetCellValue("Sheet1", "X1", "TargetVersion")
  101. f.SetCellValue("Sheet1", "Y1", "LastUpgradeTime")
  102. f.SetCellValue("Sheet1", "Z1", "UpgradeStatus")
  103. f.SetCellValue("Sheet1", "AA1", "Owner/Maintainer")
  104. f.SetCellValue("Sheet1", "AB1", "DataSource")
  105. f.SetCellValue("Sheet1", "AC1", "LastUpdated")
  106. f.SetCellValue("Sheet1", "AD1", "ConnectType")
  107. f.SetCellValue("Sheet1", "AE1", "WifiSignal")
  108. f.SetCellValue("Sheet1", "AF1", "4GSignal")
  109. // 写入数据
  110. for i, d := range res.Data {
  111. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), d.Sn)
  112. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), global.Deref(d.InstallerName, ""))
  113. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), d.ActiveTime)
  114. f.SetCellValue("Sheet1", "D"+strconv.Itoa(i+2), func() string {
  115. switch d.Status {
  116. case 0:
  117. return "离线(0)"
  118. case 1:
  119. return "在线(1)"
  120. default:
  121. return fmt.Sprintf("未知(%d)", d.Status)
  122. }
  123. }())
  124. f.SetCellValue("Sheet1", "E"+strconv.Itoa(i+2), global.Deref(d.OnLineTime, ""))
  125. f.SetCellValue("Sheet1", "F"+strconv.Itoa(i+2), global.Deref(d.OffLineTime, ""))
  126. f.SetCellValue("Sheet1", "G"+strconv.Itoa(i+2), d.FhpSn)
  127. f.SetCellValue("Sheet1", "H"+strconv.Itoa(i+2), d.Version)
  128. f.SetCellValue("Sheet1", "I"+strconv.Itoa(i+2), d.SlVersion)
  129. f.SetCellValue("Sheet1", "J"+strconv.Itoa(i+2), d.SlVersionJson)
  130. f.SetCellValue("Sheet1", "K"+strconv.Itoa(i+2), global.Deref(d.MeterVersion, ""))
  131. f.SetCellValue("Sheet1", "L"+strconv.Itoa(i+2), global.Deref(d.MbVersion, ""))
  132. f.SetCellValue("Sheet1", "M"+strconv.Itoa(i+2), global.Deref(d.AwsVersion, ""))
  133. f.SetCellValue("Sheet1", "N"+strconv.Itoa(i+2), global.Deref(d.AppVersion, ""))
  134. f.SetCellValue("Sheet1", "O"+strconv.Itoa(i+2), d.ProtocolVer)
  135. f.SetCellValue("Sheet1", "P"+strconv.Itoa(i+2), d.SysHdVersion)
  136. f.SetCellValue("Sheet1", "Q"+strconv.Itoa(i+2), global.Deref(d.Remark, ""))
  137. f.SetCellValue("Sheet1", "R"+strconv.Itoa(i+2), d.Country)
  138. f.SetCellValue("Sheet1", "S"+strconv.Itoa(i+2), d.Province)
  139. var manufactureDate string = ""
  140. if len(d.Sn) > 9 {
  141. year := d.Sn[len(d.Sn)-8 : len(d.Sn)-6]
  142. week := d.Sn[len(d.Sn)-6 : len(d.Sn)-4]
  143. manufactureDate = fmt.Sprintf("%s年%s周", year, week)
  144. }
  145. f.SetCellValue("Sheet1", "T"+strconv.Itoa(i+2), manufactureDate)
  146. f.SetCellValue("Sheet1", "U"+strconv.Itoa(i+2), "V"+strconv.Itoa(d.SysHdVersion))
  147. f.SetCellValue("Sheet1", "V"+strconv.Itoa(i+2), "无")
  148. f.SetCellValue("Sheet1", "W"+strconv.Itoa(i+2), "安全")
  149. f.SetCellValue("Sheet1", "X"+strconv.Itoa(i+2), d.Version)
  150. f.SetCellValue("Sheet1", "Y"+strconv.Itoa(i+2), global.Deref(d.FirmUpgradeTime, ""))
  151. f.SetCellValue("Sheet1", "Z"+strconv.Itoa(i+2), "成功")
  152. f.SetCellValue("Sheet1", "AA"+strconv.Itoa(i+2), "Jerry Liang/LMT")
  153. f.SetCellValue("Sheet1", "AB"+strconv.Itoa(i+2), "Fleetview")
  154. f.SetCellValue("Sheet1", "AC"+strconv.Itoa(i+2), record.UpdateTime.Format(time.DateTime))
  155. f.SetCellValue("Sheet1", "AD"+strconv.Itoa(i+2), func() string {
  156. switch d.ConnType {
  157. case 0:
  158. return "未连接(0)"
  159. case 1:
  160. return "eth0(1)"
  161. case 2:
  162. return "eth1(2)"
  163. case 3:
  164. return "WIFI(3)"
  165. case 4:
  166. return "4G(4)"
  167. default:
  168. return fmt.Sprintf("未知(%d)", d.Status)
  169. }
  170. }())
  171. f.SetCellValue("Sheet1", "AE"+strconv.Itoa(i+2), func() string {
  172. s, err := strconv.ParseInt(d.WifiSignal, 10, 64)
  173. if err != nil {
  174. zap.L().Warn("WifiSignal ParseInt failed", zap.String("WifiSignal", d.WifiSignal), zap.String("err", err.Error()))
  175. return fmt.Sprintf("未知信号(%s)", d.WifiSignal)
  176. }
  177. if s < 0 {
  178. return fmt.Sprintf("Disable(%s)", d.WifiSignal)
  179. } else if s < 40 {
  180. return fmt.Sprintf("很弱/不可用(%s) %ddBm", d.WifiSignal, s/2-100)
  181. } else if s < 60 {
  182. return fmt.Sprintf("弱(%s) %ddBm", d.WifiSignal, s/2-100)
  183. } else if s < 80 {
  184. return fmt.Sprintf("中等/一般(%s) %ddBm", d.WifiSignal, s/2-100)
  185. } else {
  186. return fmt.Sprintf("强/良好(%s) > -50dBm", d.WifiSignal)
  187. }
  188. }())
  189. f.SetCellValue("Sheet1", "AF"+strconv.Itoa(i+2), func() string {
  190. if d.Signal == nil {
  191. return "Not Signal"
  192. }
  193. s, err := strconv.ParseInt(*d.Signal, 10, 64)
  194. if err != nil {
  195. zap.L().Warn("Signal ParseInt failed", zap.String("4GSignal", *d.Signal), zap.String("err", err.Error()))
  196. return fmt.Sprintf("未知信号(%s)", *d.Signal)
  197. }
  198. // 判断软件版本
  199. isNew := false
  200. if d.AppVersion != nil && *d.AppVersion != "" {
  201. match := VERSION_REGEX.FindStringSubmatch(*d.AppVersion)
  202. if match != nil {
  203. v := match[1]
  204. r := match[2]
  205. b := match[3]
  206. d := match[4]
  207. _ = d // 当前逻辑未使用
  208. if v == "10" {
  209. rInt, _ := strconv.Atoi(r)
  210. bInt, _ := strconv.Atoi(b)
  211. if rInt > 5 {
  212. isNew = true
  213. } else if rInt == 4 && bInt >= 14 {
  214. isNew = true
  215. }
  216. }
  217. }
  218. }
  219. if isNew {
  220. if s < 0 {
  221. return fmt.Sprintf("Disable(%s)", *d.Signal)
  222. } else if s <= 12 {
  223. return fmt.Sprintf("很差(%s) %ddBm", *d.Signal, int(math.Round(float64(s)/2.5-115)))
  224. } else if s <= 37 {
  225. return fmt.Sprintf("较差(%s) %ddBm", *d.Signal, int(math.Round(float64(s)/2.5-115)))
  226. } else if s <= 62 {
  227. return fmt.Sprintf("一般(%s) %ddBm", *d.Signal, int(math.Round(float64(s)/2.5-115)))
  228. } else if s <= 87 {
  229. return fmt.Sprintf("良好(%s) %ddBm", *d.Signal, int(math.Round(float64(s)/2.5-115)))
  230. } else {
  231. return fmt.Sprintf("极好(%s) %ddBm", *d.Signal, int(math.Round(float64(s)/2.5-115)))
  232. }
  233. } else {
  234. if s < 0 {
  235. return fmt.Sprintf("Disable(%s)", *d.Signal)
  236. } else if s <= 1 {
  237. return fmt.Sprintf("很差(%s) %ddBm", *d.Signal, s*2-113)
  238. } else if s <= 6 {
  239. return fmt.Sprintf("较差(%s) %ddBm", *d.Signal, s*2-113)
  240. } else if s <= 11 {
  241. return fmt.Sprintf("一般(%s) %ddBm", *d.Signal, s*2-113)
  242. } else if s <= 16 {
  243. return fmt.Sprintf("良好(%s) %ddBm", *d.Signal, s*2-113)
  244. } else {
  245. return fmt.Sprintf("极好(%s) %ddBm", *d.Signal, s*2-113)
  246. }
  247. }
  248. }())
  249. }
  250. return f, err
  251. }
  252. // 查询单个站点实时信息(同时更新单个站点数据)
  253. func GetSiteInfoData(sn string) (*dto.SiteInfoDTO, error) {
  254. res, err := repositories.QuerySiteInfoList(dto.SiteInfoPara{
  255. SN: &sn,
  256. PageSize: 10,
  257. PageNum: 1,
  258. })
  259. if err != nil {
  260. return nil, err
  261. }
  262. if res.Result == nil {
  263. return nil, fmt.Errorf("code: %s, msg: %s", strconv.Itoa(res.Code), res.Message)
  264. }
  265. if len(*res.Result) == 0 {
  266. return nil, fmt.Errorf("code: %s, msg: %s", strconv.Itoa(res.Code), res.Message)
  267. }
  268. domainData := domain.FwhSiteInfoToSiteInfoDomain(&(*res.Result)[0])
  269. // 数据插入数据库
  270. if err := repositories.InsertSiteInfoData(*domainData); err != nil {
  271. zap.L().Error("保存站点信息失败", zap.String("err", err.Error()), zap.String("sn", sn))
  272. }
  273. tagMap := make(map[string]*dto.SiteTagDTO)
  274. if domainData.ExtTags != nil {
  275. tagMap, err = repositories.GetSiteInfoTagsFromId(*domainData.ExtTags)
  276. if err != nil {
  277. zap.L().Error("GetSiteInfoData GetSiteInfoTagsFromId failed.", zap.String("err", err.Error()), zap.Strings("idList", *domainData.ExtTags))
  278. return nil, err
  279. }
  280. }
  281. dtoData := dto.SiteInfoDomainToSiteInfoDTO(domainData, &tagMap)
  282. return dtoData, nil
  283. }
  284. // 使能站点xlog
  285. func OperateSiteInfoEnableXlog(ctx context.Context, sn string) (string, error) {
  286. return repositories.FwhMqttEnableXlog(ctx, sn)
  287. }
  288. // 获取站点信息标签列表
  289. func GetSiteInfoTags(page uint, size uint, search string) (*dto.ResPage[dto.SiteTagDTO], error) {
  290. tags, err := repositories.GetSiteInfoTags(page, size, search)
  291. if err != nil {
  292. return nil, err
  293. }
  294. result := dto.ResPage[dto.SiteTagDTO]{
  295. Data: []dto.SiteTagDTO{},
  296. PageSize: tags.PageSize,
  297. PageNum: tags.PageNum,
  298. Total: tags.Total,
  299. }
  300. for _, tag := range tags.Data {
  301. result.Data = append(result.Data, *dto.SiteTagDomainToSiteTagDTO(&tag))
  302. }
  303. return &result, nil
  304. }
  305. // 创建或更新站点信息标签
  306. func UpdateSiteInfoTag(tag dto.SiteTagDTO) error {
  307. return repositories.UpdateSiteInfoTag(*dto.SiteSiteTagDTOToTagDomain(&tag))
  308. }