Ver código fonte

add:first commit

zoie 3 semanas atrás
commit
34a81c347b
100 arquivos alterados com 25976 adições e 0 exclusões
  1. 128 0
      .gitignore
  2. 56 0
      ColdVerify_server.go
  3. 531 0
      Nats/Nats.go
  4. 112 0
      Nats/NatsServer/NatsColdApi.go
  5. 50 0
      Nats/NatsServer/NatsLocal.go
  6. 115 0
      Nats/NatsServer/NatsQiniu.go
  7. 18 0
      README.md
  8. 38 0
      TimeTask/OrmLog.go
  9. 132 0
      TimeTask/TaskList.go
  10. 6 0
      TimeTask/TimeTask.go
  11. 8 0
      Z_Build.bat
  12. 50 0
      conf/app.conf
  13. 50 0
      conf/app_prod.conf
  14. 48 0
      conf/app_test.conf
  15. 50 0
      conf/config.go
  16. 404 0
      controllers/Account.go
  17. 676 0
      controllers/AllotTask.go
  18. 479 0
      controllers/Certificate.go
  19. 284 0
      controllers/Device.go
  20. 991 0
      controllers/DeviceClass.go
  21. 310 0
      controllers/Distributor.go
  22. 95 0
      controllers/ERP.go
  23. 642 0
      controllers/InfoTemplate.go
  24. 86 0
      controllers/Logs.go
  25. 79 0
      controllers/News.go
  26. 3459 0
      controllers/Task.go
  27. 1481 0
      controllers/TaskData.go
  28. 220 0
      controllers/Template.go
  29. 72 0
      controllers/UpFile.go
  30. 565 0
      controllers/User.go
  31. 1406 0
      controllers/VerifyTemplate.go
  32. 623 0
      controllers/infoCollection.go
  33. 75 0
      go.mod
  34. 821 0
      go.sum
  35. 59 0
      lib/Aes.go
  36. 95 0
      lib/Qiniu.go
  37. 270 0
      lib/albb/DescribeInstances.go
  38. 70 0
      lib/albb/RunInstances.go
  39. 26 0
      lib/albb/inte.go
  40. 616 0
      lib/lib.go
  41. 97 0
      lib/libString.go
  42. 151 0
      lib/wx/qywx.go
  43. 58 0
      logs/LogPrintln.go
  44. 7 0
      logs/nohup.sh
  45. 252 0
      models/Account/Admin.go
  46. 132 0
      models/Account/Power.go
  47. 130 0
      models/Account/Tokey.go
  48. 643 0
      models/Account/User.go
  49. 151 0
      models/Account/UserSignature.go
  50. 439 0
      models/AllotTask/AllotTask.go
  51. 213 0
      models/Certificate/Certificate.go
  52. 195 0
      models/Certificate/CertificatePdf.go
  53. 256 0
      models/Device/Device.go
  54. 169 0
      models/Device/DeviceClass.go
  55. 489 0
      models/Device/DeviceClassList.go
  56. 613 0
      models/Device/DeviceData.go
  57. 240 0
      models/Distributor/Distributor.go
  58. 179 0
      models/Distributor/DistributorVerifyTemplate.go
  59. 350 0
      models/InfoCollection/InfoCollection.go
  60. 181 0
      models/InfoCollection/InfoTemplate.go
  61. 320 0
      models/InfoCollection/InfoTemplateClass.go
  62. 202 0
      models/InfoCollection/VerifyTemplateMap.go
  63. 200 0
      models/InfoCollection/VerifyTemplateMapData.go
  64. 74 0
      models/System/Logs.go
  65. 147 0
      models/System/News.go
  66. 77 0
      models/System/UserLogs.go
  67. 1487 0
      models/Task/Task.go
  68. 111 0
      models/Task/TaskCopy.go
  69. 411 0
      models/Task/TaskData.go
  70. 91 0
      models/Task/TaskLogs.go
  71. 188 0
      models/Task/TaskTime.go
  72. 271 0
      models/Template/Template.go
  73. 215 0
      models/VerifyTemplate/VerifyTemplate.go
  74. 380 0
      models/VerifyTemplate/VerifyTemplateClass.go
  75. 259 0
      models/VerifyTemplate/VerifyTemplateMap.go
  76. 422 0
      models/VerifyTemplate/VerifyTemplateMapData.go
  77. 238 0
      models/VerifyTemplate/VerifyTemplateMapDataHistory.go
  78. 39 0
      routers/Account.go
  79. 22 0
      routers/AllotTask.go
  80. 21 0
      routers/Certificate.go
  81. 41 0
      routers/Device.go
  82. 19 0
      routers/Distributor.go
  83. 41 0
      routers/InfoCollection.go
  84. 11 0
      routers/Logs.go
  85. 77 0
      routers/Task.go
  86. 23 0
      routers/User.go
  87. 44 0
      routers/VerifyTemplate.go
  88. 86 0
      routers/openapi.go
  89. 5 0
      routers/router.go
  90. 2 0
      run.sh
  91. 120 0
      script/add_signature.py
  92. 47 0
      script/add_watermark.py
  93. BIN
      script/watermark.pdf
  94. BIN
      script/报告专用章.png
  95. BIN
      static/commonSeal.jpg
  96. BIN
      static/fonts/MiSans-Medium.ttf
  97. BIN
      static/fonts/iconfont.eot
  98. 44 0
      static/fonts/iconfont.svg
  99. BIN
      static/fonts/iconfont.ttf
  100. BIN
      static/fonts/iconfont.woff

+ 128 - 0
.gitignore

@@ -0,0 +1,128 @@
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+# VisualStudioCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# local
+.idea
+/_
+/.cache
+.vscode/
+/logs/logx
+lastupdate.tmp
+ColdVerify_server
+ColdVerify_server6300
+ofile
+Makefile

+ 56 - 0
ColdVerify_server.go

@@ -0,0 +1,56 @@
+package main
+
+import (
+	"ColdVerify_server/TimeTask"
+	"ColdVerify_server/conf"
+	_ "ColdVerify_server/routers"
+	"fmt"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/filter/cors"
+	_ "github.com/go-sql-driver/mysql"
+	"runtime"
+	"strconv"
+)
+
+func init() {
+	fmt.Println(runtime.GOOS)
+	orm.RegisterDriver("mysql", orm.DRMySQL)
+	//orm.RegisterDataBase("default", "mysql", "zdxq:7e5853d9178edfcc@tcp(47.108.133.234:3306)/zdxq?charset=utf8",100,200)
+	orm.RegisterDataBase("default", "mysql",
+		conf.MysqlServer_Username+":"+conf.MysqlServer_Password+"@tcp("+conf.MysqlServer_UrlPort+")/"+conf.MysqlServer_Database+"?charset=utf8mb4&loc=Local&parseTime=True",
+		conf.MysqlServer_MaxIdleConnections, conf.MysqlServer_MaxOpenConnections)
+	orm.RunSyncdb("default", false, true) // 创建数据库
+	orm2.Debug = true
+
+}
+
+func main() {
+
+	HTTPPort, _ := beego.AppConfig.String("HTTPPort")
+	HTTPPort_int, _ := strconv.Atoi(HTTPPort)
+
+	beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
+		// 允许访问所有源
+		AllowAllOrigins: true,
+		// 可选参数"GET", "POST", "PUT", "DELETE", "OPTIONS" (*为所有)
+		AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
+		// 指的是允许的Header的种类
+		AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
+		// 公开的HTTP标头列表
+		ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
+		// 如果设置,则允许共享身份验证凭据,例如cookie
+		AllowCredentials: true,
+	}))
+
+	beego.BConfig.AppName = conf.AppName                    // 项目名
+	beego.BConfig.ServerName = conf.AppName + conf.HTTPPort //server  名称
+	beego.BConfig.RunMode = "dev"                           //  应用的运行模式
+	beego.BConfig.Listen.HTTPPort = HTTPPort_int            //监听端口  本地:8518  线上:8528
+
+	go TimeTask.Init() // 定时任务
+
+	beego.Run()
+
+}

+ 531 - 0
Nats/Nats.go

@@ -0,0 +1,531 @@
+package Nats
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Certificate"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"fmt"
+	"github.com/nats-io/nats.go"
+	"github.com/vmihailenco/msgpack/v5"
+	"strings"
+	"sync"
+)
+
+func init() {
+
+	logs.Println("============Nats init============")
+	var err error
+	// 连接Nats服务器
+	lib.Nats, err = nats.Connect("nats://" + conf.NatsServer_Url)
+	if err != nil {
+		logs.Error("nats 连接失败!")
+		panic(any(err))
+	}
+	logs.Println("nats OK!")
+	// 本地测试,屏蔽本地nats
+	if !conf.NatsForbidden {
+		go NatsInit()
+	}
+}
+
+type Extract_TaskData_Back struct {
+	T_uuid          string                   `xml:"T_uuid"` // 任务主键id
+	Time_start      string                   `xml:"Time_start"`
+	Time_end        string                   `xml:"Time_end"`
+	DeviceClassList []Device.DeviceClassList `xml:"DeviceClassList"` // 泛型
+	Task            Task.Task                `xml:"Task"`            // 泛型
+}
+
+func NatsInit() {
+
+	// 发布-订阅 模式,打包数据
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Extract_TaskData_Back", "Extract_TaskData", func(m *nats.Msg) {
+		logs.Debug("Extract_TaskData_Back message: \n", string(m.Data))
+
+		var resp Extract_TaskData_Back
+
+		err := msgpack.Unmarshal(m.Data, &resp)
+		if err != nil {
+			System.Add_Logs("Nats", "msgpack Unmarshal err", string(m.Data))
+			return
+		}
+
+		Task_r := resp.Task
+		// 清空表
+		Task.Truncate_TaskData(Task_r.T_task_id)
+
+		//失败重试5次
+		DeviceClassList := new(sync.Map)
+		var count int
+		for _, v := range resp.DeviceClassList {
+			if strings.Contains(v.T_sn, "-") || len(v.T_sn) == 0 {
+				// 从3.0平台导入
+				continue
+			}
+			DeviceClassList.Store(fmt.Sprintf("%s|%s", v.T_sn, v.T_id), 5)
+			//err = Task.Import_TaskData_Back(v.T_sn, v.T_id, resp.Task.T_task_id, resp.Time_start, resp.Time_end)
+			//count++
+			//time.Sleep(5 * time.Second)
+		}
+		DeviceClassList.Range(func(k, v interface{}) bool {
+			count++
+			return true
+		})
+
+		for count > 0 {
+			DeviceClassList.Range(func(k, v any) bool {
+				T_snid := strings.Split(k.(string), "|")
+				T_sn := T_snid[0]
+				T_id := T_snid[1]
+				temp := v.(int)
+				temp--
+				DeviceClassList.Store(k, temp)
+
+				err = Task.Import_TaskData_Back(T_sn, T_id, resp.Task.T_task_id, resp.Time_start, resp.Time_end)
+				if err == nil || strings.Contains(err.Error(), "doesn't exist") {
+					DeviceClassList.Delete(k)
+					count--
+				} else {
+					logs.Error("设备数据同步到任务数据失败", err)
+					DeviceClassList.Delete(k)
+					count--
+				}
+				return true
+			})
+		}
+
+		//TaskData_Num := Task.Read_TaskData_Count(Task_r.T_task_id)
+
+		//if TaskData_Num == 0 {
+		//	Task_r.T_collection_num = 0
+		//	if !Task.Update_Task(Task_r, "T_collection_state") {
+		//		logs.Error(lib.FuncName(), "后台执行修改任务数据失败")
+		//	}
+		//	return
+		//}
+
+		// 导入到本地数据---
+		//NatsServer.Import_TaskData(resp.T_uuid, Task_r.T_task_id, TaskData_Num)
+
+		System.Add_UserLogs_T(resp.T_uuid, "任务", "修改", Task_r)
+
+		System.Add_UserLogs(resp.T_uuid, "提取数据", "提取数据"+Task_r.T_name, Task_r.T_task_id+"|"+resp.Time_start+"|"+resp.Time_end)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Update_Task", "Update_Task", func(m *nats.Msg) {
+
+		var t_Req Task.Task
+		var t_R lib.JSONS
+		err := msgpack.Unmarshal(m.Data, &t_Req)
+		if err != nil {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		logs.Debug(fmt.Sprintf("ColdVerify_Server_Update_Task message: %+v\n", t_Req))
+
+		col := []string{}
+		if t_Req.T_delivery_state > 0 {
+			col = append(col, "T_delivery_state")
+		}
+
+		if t_Req.T_collection_state > 0 {
+			col = append(col, "T_collection_state")
+		}
+		if !Task.Update_Task(t_Req, col...) {
+			logs.Error("Nats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+		Task.Add_TaskLogs_T("nats", t_Req.T_task_id, "任务管理", "修改状态", t_Req)
+		System.Add_UserLogs_T("nats", "任务管理", "修改状态", t_Req)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Read_Task", "Read_Task", func(m *nats.Msg) {
+		logs.Println("ColdVerify_Server_Read_Task message: %+v\n", string(m.Data))
+
+		var t_R lib.JSONS
+		task, is := Task.Read_Task(string(m.Data))
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+		t_R.Data = task
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Device_Class_List", "Device_Class_List", func(m *nats.Msg) {
+		logs.Println("ColdVerify_Server_Device_Class_List message: %+v\n", string(m.Data))
+
+		var t_R lib.JSONS
+		task, is := Task.Read_Task(string(m.Data))
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		List, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", "", 0, 9999)
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+		t_R.Data = List
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Read_User", "Read_User", func(m *nats.Msg) {
+		logs.Println("ColdVerify_Server_Read_User message: %+v\n", string(m.Data))
+
+		var t_R lib.JSONS
+		err, user := Account.Read_User_ByT_uuid(string(m.Data))
+		if err != nil {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+		t_R.Data = user
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Read_Admin", "Read_Admin", func(m *nats.Msg) {
+		logs.Println("ColdVerify_Server_Read_User message: %+v\n", string(m.Data))
+
+		var t_R lib.JSONS
+		err, admin := Account.Read_Admin_ByT_uuid(string(m.Data))
+		if err != nil {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+		t_R.Data = admin
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Add_DeviceClassList", "Add_DeviceClassList", func(m *nats.Msg) {
+
+		type T_Req struct {
+			T_task_id string `xml:"T_task_id"` // 任务主键id
+			T_sn      string `xml:"T_sn"`
+			T_id      string `xml:"T_id"`
+		}
+
+		var t_Req T_Req
+		var t_R lib.JSONS
+		err := msgpack.Unmarshal(m.Data, &t_Req)
+		if err != nil {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		logs.Debug(fmt.Sprintf("ColdVerify_Server_Add_DeviceClassList message: %+v\n", t_Req))
+
+		Task_r, is := Task.Read_Task(t_Req.T_task_id)
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "T_task_id 错误!"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		// 判断是否已存在sn
+		dc, is := Device.Read_DeviceClassList_T_class_T_sn(Task_r.T_class, t_Req.T_sn)
+		// 添加的id和数据库已存在id相同
+		if is && dc.T_id == t_Req.T_id {
+			t_R.Code = 200
+			t_R.Msg = "ok"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		var pdf Certificate.CertificatePdf
+		//pdfList, _ := Certificate.Read_CertificatePdf_Newest(T_sn)
+		pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(t_Req.T_id, "")
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		}
+		// 相同sn 添加的id和数据库已存在id不同
+		if is && dc.T_id != t_Req.T_id {
+			dc2, is := Device.Read_DeviceClassList_T_class_T_id(Task_r.T_class, t_Req.T_id)
+			if is {
+				logs.Error("Mats", lib.FuncName())
+				t_R.Code = 202
+				t_R.Msg = fmt.Sprintf("编号[%s]已被[%s]关联,请重试", t_Req.T_id, dc2.T_sn)
+				b, _ := msgpack.Marshal(&t_R)
+				_ = lib.Nats.Publish(m.Reply, b)
+				return
+			}
+			dc.T_id = t_Req.T_id
+			dc.T_failure_time = pdf.T_failure_time
+			dc.T_pdf = pdf.T_pdf
+			dc.T_Certificate_sn = pdf.T_Certificate_sn
+			if !Device.Update_DeviceClassList(dc, "T_id", "T_failure_time", "T_pdf", "T_Certificate_sn") {
+				logs.Error("Mats", lib.FuncName())
+				t_R.Code = 202
+				t_R.Msg = "修改编号失败!"
+				b, _ := msgpack.Marshal(&t_R)
+				_ = lib.Nats.Publish(m.Reply, b)
+				return
+			} else {
+				t_R.Code = 200
+				t_R.Msg = "ok"
+
+				b, _ := msgpack.Marshal(&t_R)
+				_ = lib.Nats.Publish(m.Reply, b)
+				Task.Add_TaskLogs_T("nats", t_Req.T_task_id, "任务管理", "添加设备列表", t_Req)
+				System.Add_UserLogs_T("nats", "任务管理", "添加设备列表", t_Req)
+				return
+			}
+		}
+
+		var_ := Device.DeviceClassList{
+			T_class:          Task_r.T_class,
+			T_id:             t_Req.T_id,
+			T_sn:             t_Req.T_sn,
+			T_failure_time:   pdf.T_failure_time,
+			T_pdf:            pdf.T_pdf,
+			T_Certificate_sn: pdf.T_Certificate_sn,
+			T_remark:         "",
+			T_State:          1,
+		}
+
+		_, is = Device.Add_DeviceClassList(var_)
+
+		if !is {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+		Task.Add_TaskLogs_T("nats", t_Req.T_task_id, "任务管理", "添加设备编号", t_Req)
+		System.Add_UserLogs_T("nats", "任务管理", "添加设备编号", t_Req)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Edit_DeviceClassList", "Edit_DeviceClassList", func(m *nats.Msg) {
+
+		type T_Req struct {
+			T_task_id string `xml:"T_task_id"` // 任务主键id
+			T_sn      string `xml:"T_sn"`
+			T_id      string `xml:"T_id"`
+		}
+
+		var t_Req T_Req
+		var t_R lib.JSONS
+		err := msgpack.Unmarshal(m.Data, &t_Req)
+		if err != nil {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		logs.Debug(fmt.Sprintf("ColdVerify_Server_Edit_DeviceClassList message: %+v\n", t_Req))
+
+		Task_r, is := Task.Read_Task(t_Req.T_task_id)
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "T_task_id 错误!"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		// 判断是否已存在sn
+		dc, is := Device.Read_DeviceClassList_T_class_T_sn(Task_r.T_class, t_Req.T_sn)
+		// 添加的id和数据库已存在id相同
+		if is && dc.T_id == t_Req.T_id {
+			t_R.Code = 200
+			t_R.Msg = "ok"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		// 相同sn 添加的id和数据库已存在id不同
+		if is && dc.T_id != t_Req.T_id {
+			dc2, is := Device.Read_DeviceClassList_T_class_T_id(Task_r.T_class, t_Req.T_id)
+			if is {
+				logs.Error("Mats", lib.FuncName())
+				t_R.Code = 202
+				t_R.Msg = fmt.Sprintf("编号[%s]已被[%s]关联,请重试", t_Req.T_id, dc2.T_sn)
+				b, _ := msgpack.Marshal(&t_R)
+				_ = lib.Nats.Publish(m.Reply, b)
+				return
+			}
+			var pdf Certificate.CertificatePdf
+			pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(t_Req.T_id, "")
+			if len(pdfList) > 0 {
+				pdf = pdfList[0]
+			}
+			dc.T_id = t_Req.T_id
+			dc.T_failure_time = pdf.T_failure_time
+			dc.T_pdf = pdf.T_pdf
+			dc.T_Certificate_sn = pdf.T_Certificate_sn
+			if !Device.Update_DeviceClassList(dc, "T_id", "T_failure_time", "T_pdf", "T_Certificate_sn") {
+				logs.Error("Mats", lib.FuncName())
+				t_R.Code = 202
+				t_R.Msg = "修改编号失败!"
+				b, _ := msgpack.Marshal(&t_R)
+				_ = lib.Nats.Publish(m.Reply, b)
+				return
+			}
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+		Task.Add_TaskLogs_T("nats", t_Req.T_task_id, "任务管理", "修改设备列表", t_Req)
+		System.Add_UserLogs_T("nats", "任务管理", "修改设备列表", t_Req)
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Del_TaskData_ByT_BindDeviceDataTime", "Del_TaskData_ByT_BindDeviceDataTime", func(m *nats.Msg) {
+
+		var t_R lib.JSONS
+		task, is := Task.Read_Task(string(m.Data))
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		dcList, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", "", 0, 9999)
+		for _, v := range dcList {
+			if !lib.IsNumeric(v.T_id) {
+				// 删除任务表指定时间数据
+				Task.Del_TaskData_t_idByT_BindDeviceDataTime(task.T_task_id, v.T_id, task.T_BindDeviceDataStartTime, task.T_BindDeviceDataEndTime)
+			} else {
+				Task.Del_TaskData_t_idByT_BindDeviceDataTime(task.T_task_id, v.T_id, task.T_VerifyDeviceDataStartTime, task.T_VerifyDeviceDataEndTime)
+
+			}
+		}
+
+	})
+
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Update_Task_BySN", "Update_Task_BySN", func(m *nats.Msg) {
+		type T_Req struct {
+			T_sn              string `xml:"T_sn"`
+			T_CalibrationTime string `xml:"T_CalibrationTime"`
+		}
+		var t_Req T_Req
+		var t_R lib.JSONS
+		err := msgpack.Unmarshal(m.Data, &t_Req)
+		if err != nil {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		logs.Debug(fmt.Sprintf("ColdVerify_Server_Update_Task_BySN message: %+v\n", t_Req))
+
+		task, err := Task.Read_Task_BySN(t_Req.T_sn)
+		if err != nil && err.Error() != "record not found" {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		col := []string{}
+		if len(t_Req.T_CalibrationTime) > 0 {
+			task.T_CalibrationExpirationTime = t_Req.T_CalibrationTime[0:10]
+			col = append(col, "T_CalibrationExpirationTime")
+		}
+
+		if !Task.Update_Task(task, col...) {
+			logs.Error("Mats", lib.FuncName(), err)
+			t_R.Code = 202
+			t_R.Msg = err.Error()
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+
+		t_R.Code = 200
+		t_R.Msg = "ok"
+
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+
+		Task.Add_TaskLogs_T("nats", task.T_task_id, "任务管理", "修改校准时间", t_Req)
+		System.Add_UserLogs_T("nats", "任务管理", "修改校准时间", t_Req)
+
+	})
+
+}

+ 112 - 0
Nats/NatsServer/NatsColdApi.go

@@ -0,0 +1,112 @@
+package NatsServer
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"errors"
+	"github.com/vmihailenco/msgpack/v5"
+	"time"
+)
+
+
+type Device struct {
+	T_sn              string    // 设备序列号
+	T_pid             int       // Account.Company 绑定公司
+	T_devName         string    // 设备名称  20字
+	T_protocol        int       // 冷链通讯协议 1 :1.0协议   2 :2.0协议    3 :3.0协议
+	T_mqttid          string    // MQTT 服务ID
+	T_VerifyTime      time.Time // 验证时间
+	T_CalibrationTime time.Time // 校准时间
+	T_PatrolTime      time.Time // 巡检时间
+	T_abandonTime     time.Time // 弃用时间
+	T_ist             int       // 温度   1开启   2关闭
+	T_ish             int       // 湿度   1开启   2关闭
+
+	T_State int // 0 屏蔽   1 正常  (屏蔽后 只有内部管理员才能看到,用户 输入SN\名称 搜索时 也能看到)
+
+	// 设备同步参数
+	T_Dattery  int    // 电量
+	T_Site     string // GPS
+	T_monitor  int    // 监控状态 0 未监控 1 监控  停止记录
+	T_online   int    // 在线状态 0 未启用  1 在线  2 离线
+	T_online_s int    // 在线状态-备用  0 未启用  1 在线  2 离线
+
+	// 硬件信息
+	T_model string // KF200BG  设备型号
+	T_sver  string // "1.0.0",//软件版本
+	T_hver  string // "1.0.0",//硬件版本
+	T_imei  string // "867387060327718",//模组imei
+	T_iccid string // "89860477102170049750",//sim卡号
+	T_rssi  string // "80",//信号强度
+
+	CreateTime time.Time //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+
+func Cold_UpdateDevice_CalibrationTime(T_sn, T_CalibrationExpirationTime string) error {
+	logs.Println("Nats =>", lib.FuncName(), T_sn, T_CalibrationExpirationTime)
+
+	type T_Req struct {
+		T_sn              string
+		T_CalibrationTime string
+	}
+	t_r := T_Req{
+		T_sn:              T_sn,
+		T_CalibrationTime: T_CalibrationExpirationTime,
+	}
+
+	b, err := msgpack.Marshal(&t_r)
+	if err != nil {
+		logs.Error("Nats =>", "msgpack Marshal err", err)
+		return err
+	}
+
+	msg, err := lib.Nats.Request("Cold_UpdateDevice_CalibrationTime", b, 3*time.Second)
+	if err != nil {
+		return err
+	}
+
+	type T_R struct {
+		Code int16       `xml:"Code"`
+		Msg  string      `xml:"Msg"`
+		Data interface{} `xml:"Data"`
+	}
+	var t_R T_R
+
+	err = msgpack.Unmarshal(msg.Data, &t_R)
+	if err != nil {
+		return err
+	}
+	if t_R.Code != 200 {
+		return errors.New(t_R.Msg)
+	}
+	return nil
+}
+
+func Cold_ReadDeviceByT_sn(T_sn string) (data Device, err error) {
+
+	msg, err := lib.Nats.Request("Cold_ReadDeviceByT_sn", []byte(T_sn), 3*time.Second)
+	if err != nil {
+		return
+	}
+
+	type T_R struct {
+		Code int16  `xml:"Code"`
+		Msg  string `xml:"Msg"`
+		Data Device `xml:"Data"` // 泛型
+	}
+	var t_R T_R
+
+	err = msgpack.Unmarshal(msg.Data, &t_R)
+	if err != nil {
+		return
+	}
+	if t_R.Code != 200 {
+		err = errors.New(t_R.Msg)
+		return
+	}
+	data = t_R.Data
+
+	return data, nil
+}

+ 50 - 0
Nats/NatsServer/NatsLocal.go

@@ -0,0 +1,50 @@
+package NatsServer
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/vmihailenco/msgpack/v5"
+)
+
+func Import_TaskData(T_uuid, T_task_id string, TaskData_Num int) {
+	logs.Println("Nats =>", lib.FuncName(), T_uuid, T_uuid)
+
+	type T_R struct {
+		T_uuid       string `xml:"T_uuid"`
+		T_task_id    string `xml:"T_task_id"`
+		TaskData_Num int    `xml:"TaskData_Num"`
+	}
+	t_r := T_R{
+		T_uuid:       T_uuid,
+		T_task_id:    T_task_id,
+		TaskData_Num: TaskData_Num,
+	}
+
+	b, err := msgpack.Marshal(&t_r)
+	if err != nil {
+		logs.Error("Nats =>", "msgpack Marshal err", err)
+	}
+
+	err = lib.Nats.Publish("ColdVerify_Local_Import_TaskData", b)
+	if err != nil {
+		logs.Error("Nats =>", lib.FuncName(), err)
+	}
+}
+func Create_Local_Table(T_task_id string) {
+	logs.Println("Nats =>", lib.FuncName(), T_task_id)
+
+	err := lib.Nats.Publish("ColdVerify_Local_Create_Table", []byte(T_task_id))
+	if err != nil {
+		logs.Error("Nats =>", lib.FuncName(), err)
+	}
+}
+
+// 同步2。8数据
+func Sync1_TaskData(T_task_id string) {
+	logs.Println("Nats =>", lib.FuncName(), T_task_id)
+
+	err := lib.Nats.Publish("ColdVerify_Local_Sync1_TaskData", []byte(T_task_id))
+	if err != nil {
+		logs.Error("Nats =>", lib.FuncName(), err)
+	}
+}

+ 115 - 0
Nats/NatsServer/NatsQiniu.go

@@ -0,0 +1,115 @@
+package NatsServer
+
+import (
+	"ColdVerify_server/lib"
+	"context"
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/qiniu/go-sdk/v7/auth/qbox"
+	"github.com/qiniu/go-sdk/v7/storage"
+	"github.com/vmihailenco/msgpack/v5"
+	"strings"
+	"time"
+)
+
+func Qiniu_UploadToken(T_suffix string, T_MimeLimit string) (string, bool) {
+	type Qiniu_UploadToken struct {
+		T_suffix    string
+		T_MimeLimit string
+	}
+
+	b, err := msgpack.Marshal(&Qiniu_UploadToken{
+		T_suffix:    T_suffix,
+		T_MimeLimit: T_MimeLimit,
+	})
+	if err != nil {
+		panic(any(err))
+	}
+
+	// 请求-响应, 向 test3 发布一个 `help me` 请求数据,设置超时间3秒,如果有多个响应,只接收第一个收到的消息
+	msg, err := lib.Nats.Request("Qiniu_UploadToken", b, 3*time.Second)
+	if err != nil {
+		logs.Error(err)
+	} else {
+		logs.Debug(fmt.Sprintf("Qiniu_UploadToken : %s\n", string(msg.Data)))
+		return string(msg.Data), true
+	}
+
+	return string(msg.Data), false
+}
+
+//func Qiniu_UploadFile(localFile string, name string) (string, bool) {
+//	logs.Info("Nats =>", lib.FuncName(), localFile, name)
+//	type Qiniu_UploadFile struct {
+//		File string
+//		Name string
+//	}
+//	RR := Qiniu_UploadFile{File: localFile, Name: name}
+//	println(":", RR.File)
+//	b, err := msgpack.Marshal(&RR)
+//	if err != nil {
+//		panic(any(err))
+//	}
+//
+//	// 请求-响应, 向 test3 发布一个 `help me` 请求数据,设置超时间3秒,如果有多个响应,只接收第一个收到的消息
+//	msg, err := lib.Nats.Request("Qiniu_UploadFile", b, 3*time.Second)
+//	if err != nil {
+//		logs.Error(err)
+//	} else {
+//		logs.Debug(fmt.Sprintf("Qiniu_UploadFile : %s\n", string(msg.Data)))
+//		return string(msg.Data), true
+//	}
+//
+//	return string(msg.Data), false
+//}
+
+func Qiniu_UploadFile(localFile string, name string) (string, bool) {
+	logs.Info("Qiniu_UploadFile =>", localFile, name)
+
+	// 获取 七牛云的 配置信息
+	msg, err := lib.Nats.Request("Qiniu_Token", []byte(""), 3*time.Second)
+	if err != nil {
+		return string(msg.Data), false
+	}
+	logs.Debug(fmt.Sprintf("Qiniu_Token : %s\n", string(msg.Data)))
+	Qiniu_cs := strings.Split(string(msg.Data), "|")
+	Qiniu_AccessKey := Qiniu_cs[0]
+	Qiniu_SecretKey := Qiniu_cs[1]
+	Qiniu_BUCKET := Qiniu_cs[2]
+	Qiniu_Url := Qiniu_cs[3]
+
+	// 开始上传 七牛云
+	Qiniu := qbox.NewMac(Qiniu_AccessKey, Qiniu_SecretKey)
+	// 自定义返回值结构体
+	type MyPutRet struct {
+		Key    string
+		Hash   string
+		Fsize  int
+		Bucket string
+		Name   string
+	}
+	//key := "your file save key"
+	// 使用 returnBody 自定义回复格式
+	putPolicy := storage.PutPolicy{
+		Scope:      Qiniu_BUCKET,
+		ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}`,
+	}
+	//mac := qbox.NewMac(conf.Qiniu_AccessKey, conf.Qiniu_SecretKey)
+	upToken := putPolicy.UploadToken(Qiniu)
+	cfg := storage.Config{}
+	formUploader := storage.NewFormUploader(&cfg)
+	ret := MyPutRet{}
+	putExtra := storage.PutExtra{
+		Params: map[string]string{
+			"x:name": "github logo",
+		},
+	}
+	err = formUploader.PutFile(context.Background(), &ret, upToken, name, localFile, &putExtra)
+	if err != nil {
+		logs.Info("七牛云", "上传文件失败 "+localFile, err.Error())
+		return "", false
+	}
+	fmt.Println(ret.Bucket, ret.Key, ret.Fsize, ret.Hash, ret.Name)
+	return Qiniu_Url + name, true
+
+}

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+# ColdVerify_server
+
+冷链验证报告系统
+
+## 项目部署
+安装python依赖
+```bash
+pip install PyPDF2
+```
+
+### 1、修改配置文件
+conf/app.conf
+
+### 2、打包linux二进制包
+GOOS=linux GOARCH=amd64 go build ColdVerify_server.go
+
+### 3、启动服务
+./ColdVerify_server

+ 38 - 0
TimeTask/OrmLog.go

@@ -0,0 +1,38 @@
+package TimeTask
+
+//import (
+//	"fmt"
+//	"io/ioutil"
+//	"os"
+//	"time"
+//)
+//
+//var OrmLogOrmLog *os.File
+//// ORM 日志清理
+//func OrmLog()  {
+//	crontab := cron.New(cron.WithSeconds())
+//	ss := "1 1 1 * * *"
+//	_, err := crontab.AddFunc(ss, OrmLog_MonitorScanStatus)
+//	if err != nil {
+//		fmt.Printf("err: %v\n", err)
+//		fmt.Println("初始化成功")
+//	}
+//	crontab.Start()
+//	defer crontab.Stop()
+//	select {}
+//}
+//func OrmLog_MonitorScanStatus()  {
+//
+//	fmt.Println("------- ORM 日志清理 --------")
+//	data, err := ioutil.ReadFile(OrmLogOrmLog.Name())
+//	if err != nil {
+//		fmt.Printf("文件打开失败=%v\n", err)
+//		return
+//	}
+//	err = ioutil.WriteFile("logs/orm/logx_"+time.Now().Format("2006-01-02") +".log", data, 0666)
+//	if err != nil {
+//		fmt.Printf("文件打开失败=%v\n", err)
+//	}
+//	fmt.Println("清空:",os.Truncate(OrmLogOrmLog.Name(), 0))
+//
+//}

+ 132 - 0
TimeTask/TaskList.go

@@ -0,0 +1,132 @@
+package TimeTask
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/lib/wx"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/AllotTask"
+	"ColdVerify_server/models/InfoCollection"
+	"ColdVerify_server/models/Task"
+	"fmt"
+
+	"time"
+
+	"github.com/robfig/cron/v3"
+)
+
+func TaskList() {
+	crontab := cron.New(cron.WithSeconds())
+
+	// 现有的任务回款检查 - 每天上午10点执行
+	ss := "0 10 * * * *"
+	_, err := crontab.AddFunc(ss, TaskList_return)
+	if err != nil {
+		fmt.Printf("TaskList_return cron err: %v\n", err)
+	}
+
+	// 新增的AllotTask超时检查 - 每30分钟执行一次
+	allotTaskCron := "0 */30 * * * *" // 每30分钟执行一次
+	_, err2 := crontab.AddFunc(allotTaskCron, AllotTask_Timeout_Check)
+	if err2 != nil {
+		fmt.Printf("AllotTask_Timeout_Check cron err: %v\n", err2)
+	}
+
+	crontab.Start()
+	defer crontab.Stop()
+	select {}
+}
+
+// 回款
+func TaskList_return() {
+
+	logs.Println("------- 任务回款 定时任务 --------")
+	List, _ := Task.Read_Task_List_All()
+
+	for _, T := range List {
+
+		logs.Println("任务ID:", T.Id)
+
+		var InfoCollection_r InfoCollection.InfoCollection //信息采集
+		if len(T.T_InfoCollection_id) == 0 {
+			logs.Println("信息采集表获取 为空!!")
+			continue
+		}
+		var is bool
+		InfoCollection_r, is = InfoCollection.Read_InfoCollection(T.T_InfoCollection_id)
+		if !is {
+			logs.Println("信息采集表获取错误 T_InfoCollection_id ", T.T_InfoCollection_id)
+			continue
+		}
+
+		if InfoCollection_r.T_State == 5 {
+			logs.Println("已经回款")
+			continue
+		}
+		if len(T.T_reporting_end_time) == 0 {
+			logs.Println("正在进行中")
+			continue
+		}
+
+		T_collection_time_interval, _ := lib.MinutesDifference(T.T_reporting_end_time, time.Now().Format("2006-01-02 15:04:05"))
+		T_collection_time_interval = T_collection_time_interval / 60 / 24
+		logs.Println("用时 天:", T_collection_time_interval)
+		if T_collection_time_interval <= 30 {
+			logs.Println("未超时!!!")
+			continue
+		}
+		_, company_r := Account.Read_User_ByT_uuid(T.T_uuid)
+		//AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+		//go System.Send_Weichat_News(AdminMap[T.T_scheme], fmt.Sprintf("【项目回款】项目回款已经超过%d天【%s-%s】", int(T_collection_time_interval) ,company_r.T_name, T.T_name), "")
+		go wx.WxSend(T.T_scheme, fmt.Sprintf("【项目回款】项目回款已经超过%d天【%s-%s】", int(T_collection_time_interval), company_r.T_name, T.T_name))
+
+	}
+
+}
+
+// AllotTask超时检查 - 每30分钟执行一次
+func AllotTask_Timeout_Check() {
+	logs.Println("------- AllotTask超时检查 定时任务 --------")
+
+	// 获取超时的AllotTask列表
+	timeoutTasks, err := AllotTask.Read_AllotTask_Timeout_List()
+	if err != nil {
+		logs.Error("AllotTask_Timeout_Check 获取超时任务失败:", err)
+		return
+	}
+
+	if len(timeoutTasks) == 0 {
+		logs.Println("AllotTask_Timeout_Check: 没有超时的任务")
+		return
+	}
+
+	logs.Println(fmt.Sprintf("AllotTask_Timeout_Check: 找到 %d 个超过24小时未接收的任务", len(timeoutTasks)))
+
+	// 处理每个超时任务
+	for _, task := range timeoutTasks {
+		logs.Println(fmt.Sprintf("处理超时任务 ID: %s, 名称: %s, 创建时间: %s",
+			task.T_allot_task_id, task.T_name, task.CreateTime.Format("2006-01-02 15:04:05")))
+
+		// 更新状态为已拒绝并添加拒绝记录
+		reason := fmt.Sprintf("任务派发超过24小时未接收,系统自动拒绝 (创建时间: %s)",
+			task.CreateTime.Format("2006-01-02 15:04:05"))
+
+		if AllotTask.Update_AllotTask_To_Refused(task, reason) {
+			logs.Println(fmt.Sprintf("成功将任务 %s 更新为已拒绝状态", task.T_allot_task_id))
+
+			// 发送企业微信通知给实施方案负责人
+			if len(task.T_scheme) > 0 {
+				_, company_r := Account.Read_User_ByT_uuid(task.T_uuid)
+				notificationMsg := fmt.Sprintf("【任务超时拒绝】任务「%s-%s」已超过24小时未接收,系统已自动拒绝",
+					company_r.T_name, task.T_name)
+				go wx.WxSend(task.T_scheme, notificationMsg)
+				logs.Println(fmt.Sprintf("已发送企业微信通知给负责人: %s", task.T_scheme))
+			}
+		} else {
+			logs.Error(fmt.Sprintf("更新任务 %s 状态失败", task.T_allot_task_id))
+		}
+	}
+
+	logs.Println("------- AllotTask超时检查 定时任务完成 --------")
+}

+ 6 - 0
TimeTask/TimeTask.go

@@ -0,0 +1,6 @@
+package TimeTask
+
+func Init() {
+	go TaskList()
+
+}

+ 8 - 0
Z_Build.bat

@@ -0,0 +1,8 @@
+cd %~dp0
+set GOARCH=amd64
+set GOOS=linux
+set GOPATH=C:\Users\SIKED\go
+set GO111MODULE=auto
+
+
+go build -o ColdVerify_server6300 ColdVerify_server.go

+ 50 - 0
conf/app.conf

@@ -0,0 +1,50 @@
+appname = ColdVerify_server6300
+HTTPPort = 6300
+runmode = dev
+Graceful = true
+EnableDocs = true
+copyrequestbody = true
+
+# Nats
+NatsServer_Url = "8.148.211.203:4222"
+NatsForbidden = true
+
+MysqlServer_UrlPort = "8.148.211.203:3306"
+MysqlServer_Database = "coldverify"
+MysqlServer_Username = "coldverify"
+MysqlServer_Password = "Bd3d34yJ7aibiEi"
+MysqlServer_MaxIdleConnections = 100
+MysqlServer_MaxOpenConnections = 200
+
+
+# Redis
+Redis_address = "8.148.211.203:6379"
+Redis_password = "redis_JJ56d5"
+Redis_dbNum = "2"
+
+
+
+# 静态资源
+Qiniu_AccessKey = "-8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo"
+Qiniu_SecretKey = "KFhkYxTAJ2ZPN3ZS3euTsfWk8-C92rKgkhAMkDRN"
+Qiniu_BUCKET = "bzdcoldverify"
+Oss = "https://bzdcoldverifyoss.baozhida.cn"
+
+
+# 发送微信通知
+WechatNews_GroupName = "宝智达-软件组"
+WechatNews_Url = "http://111.85.177.202:12088/send"
+
+# 老板 uuid
+BoosUuid = "fa5be10f-5be1-42be-a8dc-8d142e006266"
+# 冷链验证 报告负责人
+VdelUuid = "1c13436c-4511-4030-8b26-baadad88445a"
+
+OpenApi_Key = "coldverify"
+OpenApi_Secret = "H3L9OPQR2VX8ZZYN7STKFG5JMWB1CV4D"
+
+PdfProcessingHost = "https://coldverify-u.coldbaozhida.com/PdfProcessing"
+
+UseVerifyTemplateMapDataHistoryTime = "2025-09-25 23:59:59"
+
+DeviceListMaximum = 600

+ 50 - 0
conf/app_prod.conf

@@ -0,0 +1,50 @@
+appname = ColdVerify_server6300
+HTTPPort = 6300
+runmode = dev
+Graceful = true
+EnableDocs = true
+copyrequestbody = true
+
+# Nats
+NatsServer_Url = "182.44.114.34:4222"
+NatsForbidden = true
+
+MysqlServer_UrlPort = "182.44.114.34:3306"
+MysqlServer_Database = "coldverify"
+MysqlServer_Username = "root"
+MysqlServer_Password = "mysql_Ks7WAX"
+MysqlServer_MaxIdleConnections = 100
+MysqlServer_MaxOpenConnections = 200
+
+
+# Redis
+Redis_address = "182.44.114.34:6379"
+Redis_password = "redis_F2tj7p"
+Redis_dbNum = "2"
+
+
+UseVerifyTemplateMapDataHistoryTime = "2025-08-25 23:59:59"
+
+
+# 静态资源
+Qiniu_AccessKey = "-8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo"
+Qiniu_SecretKey = "KFhkYxTAJ2ZPN3ZS3euTsfWk8-C92rKgkhAMkDRN"
+Qiniu_BUCKET = "bzdcoldverify"
+Oss = "https://bzdcoldverifyoss.baozhida.cn"
+
+
+# 发送微信通知
+WechatNews_GroupName = "宝智达-软件组"
+WechatNews_Url = "http://111.85.177.202:12088/send"
+
+# 老板 uuid
+BoosUuid = "fa5be10f-5be1-42be-a8dc-8d142e006266"
+# 冷链验证 报告负责人
+VdelUuid = "1c13436c-4511-4030-8b26-baadad88445a"
+
+OpenApi_Key = "coldverify"
+OpenApi_Secret = "H3L9OPQR2VX8ZZYN7STKFG5JMWB1CV4D"
+
+PdfProcessingHost = "https://coldverify-u.coldbaozhida.com/PdfProcessing"
+
+UseVerifyTemplateMapDataHistoryTime = "2025-08-25 23:59:59"

+ 48 - 0
conf/app_test.conf

@@ -0,0 +1,48 @@
+appname = ColdVerify_server6300
+HTTPPort = 6300
+runmode = dev
+Graceful = true
+EnableDocs = true
+copyrequestbody = true
+
+# Nats
+NatsServer_Url = "203.34.49.130:4222"
+NatsForbidden = true
+
+MysqlServer_UrlPort = "203.34.49.130:3306"
+MysqlServer_Database = "coldverify"
+MysqlServer_Username = "coldverify"
+MysqlServer_Password = "Bd3d34yJ7aibiEi"
+MysqlServer_MaxIdleConnections = 100
+MysqlServer_MaxOpenConnections = 200
+
+
+# Redis
+Redis_address = "203.34.49.130:6379"
+Redis_password = "redis_JJ56d5"
+Redis_dbNum = "2"
+
+
+
+# 静态资源
+Qiniu_AccessKey = "-8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo"
+Qiniu_SecretKey = "KFhkYxTAJ2ZPN3ZS3euTsfWk8-C92rKgkhAMkDRN"
+Qiniu_BUCKET = "bzdcoldverify"
+Oss = "https://bzdcoldverifyoss.baozhida.cn"
+
+
+# 发送微信通知
+WechatNews_GroupName = "宝智达-软件组"
+WechatNews_Url = "http://111.85.177.202:12088/send"
+
+# 老板 uuid
+BoosUuid = "fa5be10f-5be1-42be-a8dc-8d142e006266"
+# 冷链验证 报告负责人
+VdelUuid = "1c13436c-4511-4030-8b26-baadad88445a"
+
+OpenApi_Key = "coldverify"
+OpenApi_Secret = "H3L9OPQR2VX8ZZYN7STKFG5JMWB1CV4D"
+
+PdfProcessingHost = "https://coldverify-u.coldbaozhida.com/PdfProcessing"
+
+UseVerifyTemplateMapDataHistoryTime = "2025-08-25 23:59:59"

+ 50 - 0
conf/config.go

@@ -0,0 +1,50 @@
+package conf
+
+import (
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+// Nats
+var NatsServer_Url, _ = beego.AppConfig.String("NatsServer_Url")
+var NatsForbidden = beego.AppConfig.DefaultBool("NatsForbidden", false)
+
+var HTTPPort, _ = beego.AppConfig.String("HTTPPort")
+var AppName, _ = beego.AppConfig.String("appname")
+var RunMode, _ = beego.AppConfig.String("runmode")
+
+var Page_size = 10
+
+// Mysql
+var MysqlServer_UrlPort, _ = beego.AppConfig.String("MysqlServer_UrlPort")
+var MysqlServer_Database, _ = beego.AppConfig.String("MysqlServer_Database")
+var MysqlServer_Username, _ = beego.AppConfig.String("MysqlServer_Username")
+var MysqlServer_Password, _ = beego.AppConfig.String("MysqlServer_Password")
+var MysqlServer_MaxIdleConnections, _ = beego.AppConfig.Int("MysqlServer_MaxIdleConnections")
+var MysqlServer_MaxOpenConnections, _ = beego.AppConfig.Int("MysqlServer_MaxOpenConnections")
+
+// Redis
+var Redis_address, _ = beego.AppConfig.String("Redis_address")
+var Redis_password, _ = beego.AppConfig.String("Redis_password")
+var Redis_dbNum, _ = beego.AppConfig.String("Redis_dbNum")
+
+// Qiniu
+var Qiniu_AccessKey, _ = beego.AppConfig.String("Qiniu_AccessKey")
+var Qiniu_SecretKey, _ = beego.AppConfig.String("Qiniu_SecretKey")
+var Qiniu_BUCKET, _ = beego.AppConfig.String("Qiniu_BUCKET")
+var OssQiniu = "https://bzdcoldverifyoss.baozhida.cn"
+var Oss, _ = beego.AppConfig.String("Oss")
+var Oss_file, _ = beego.AppConfig.String("Oss_file")
+
+// 微信消息群通知
+var WechatNews_GroupName, _ = beego.AppConfig.String("WechatNews_GroupName")
+var WechatNews_Url, _ = beego.AppConfig.String("WechatNews_Url")
+var BoosUuid, _ = beego.AppConfig.String("BoosUuid")
+var VdelUuid, _ = beego.AppConfig.String("VdelUuid")
+
+var OpenApi_Key, _ = beego.AppConfig.String("OpenApi_Key")
+var OpenApi_Secret, _ = beego.AppConfig.String("OpenApi_Secret")
+
+var PdfProcessingHost, _ = beego.AppConfig.String("PdfProcessingHost")
+
+var UseVerifyTemplateMapDataHistoryTime, _ = beego.AppConfig.String("UseVerifyTemplateMapDataHistoryTime")
+var DeviceListMaximum, _ = beego.AppConfig.String("DeviceListMaximum")

+ 404 - 0
controllers/Account.go

@@ -0,0 +1,404 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/System"
+	beego "github.com/beego/beego/v2/server/web"
+	uuid "github.com/satori/go.uuid"
+	"math"
+	"time"
+)
+
+type AccountController struct {
+	beego.Controller
+}
+
+// 验证登录
+func (c *AccountController) Login_verification() {
+	Admin_user := c.GetString("bzd_username")
+	Admin_pass := c.GetString("bzd_password")
+
+	println("Login_verification", Admin_user, Admin_pass)
+	err, user_r := Account.Read_User_verification(Admin_user, Admin_pass)
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "登录失败-请检查账号密码"}
+	} else {
+		User_tokey := Account.Add_Tokey(user_r.T_uuid)
+		c.Ctx.SetCookie("User_tokey", User_tokey, time.Second*60*60)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "OK!", Data: User_tokey}
+
+		System.Add_UserLogs(user_r.T_uuid, "登陆", "用户登陆", "")
+
+	}
+
+	c.ServeJSON()
+	return
+
+}
+
+// 验证登录
+func (c *AccountController) Login_Admin_verification() {
+	Admin_user := c.GetString("bzd_username")
+	Admin_pass := c.GetString("bzd_password")
+
+	println("Login_Admin_verification", Admin_user, Admin_pass)
+	err, user_r := Account.Read_Admin_verification(Admin_user, Admin_pass)
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "登录失败-请检查账号密码"}
+	} else {
+		User_tokey := Account.Add_Tokey(user_r.T_uuid)
+		c.Ctx.SetCookie("User_tokey", User_tokey, time.Second*60*60)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "OK!", Data: User_tokey}
+
+		System.Add_UserLogs(user_r.T_uuid, "登陆", "管理员登陆", "")
+
+	}
+
+	c.ServeJSON()
+	return
+
+}
+
+// --------------------------------------------------------------------------------------------------------------
+// 管理员-列表-
+func (c *AccountController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_Distributor_id := c.GetString("T_Distributor_id")
+	if len(T_Distributor_id) == 0 {
+		T_Distributor_id = User_r.T_Distributor_id
+	}
+
+	var cnt int
+	PowerList := Account.Read_Power_List_ALL_1()
+	PowerMap := Account.UserPowerListToPowerMap(PowerList)
+	List, cnt := Account.Read_Admin_List(T_Distributor_id, T_name, page, page_z, PowerMap)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 管理员-详情
+func (c *AccountController) Get() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	type User struct {
+		Account.Admin
+		Permission string
+	}
+	var u User
+	u.Admin = User_r
+	// 内部管理员
+	if len(User_r.T_Distributor_id) == 0 {
+		if User_r.T_power <= 2 {
+			u.Permission = "NBGLY" //内部管理员
+		} else {
+			u.Permission = "NBPTYH" //内部普通用户
+		}
+	} else {
+		if User_r.T_power <= 2 {
+			u.Permission = "JXSGLY" //经销商管理员
+		} else {
+			u.Permission = "JXSPTYH" //经销商普通用户
+		}
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: u}
+	c.ServeJSON()
+	return
+}
+func (c *AccountController) Delivery() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: conf.VdelUuid}
+	c.ServeJSON()
+	return
+}
+
+// 管理员-添加-
+func (c *AccountController) Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_uuid := uuid.NewV4().String()
+	T_power, _ := c.GetInt("T_power")
+	T_name := c.GetString("T_name")
+	T_user := c.GetString("T_user")
+	T_pass := c.GetString("T_pass")
+	T_wxname := c.GetString("T_wxname")
+	T_Distributor_id := c.GetString("T_Distributor_id")
+	T_signature_img := c.GetString("T_signature_img")
+	if len(T_Distributor_id) == 0 {
+		T_Distributor_id = User_r.T_Distributor_id
+	}
+	if T_power <= 1 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := Account.Admin{
+		T_uuid:           T_uuid,
+		T_power:          T_power,
+		T_name:           T_name,
+		T_user:           T_user,
+		T_pass:           T_pass,
+		T_wxname:         T_wxname,
+		T_State:          1,
+		T_Distributor_id: T_Distributor_id, // 分销商id,内部管理员为空
+		T_signature_img:  T_signature_img,
+	}
+
+	if err, _ := Account.Read_Admin_ByT_user(T_user); err == nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "登录账号已存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := Account.Add_Admin(var_)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "管理员用户", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+
+	return
+}
+
+// 管理员-修改-
+func (c *AccountController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_uuid := c.GetString("T_uuid")
+	T_power, _ := c.GetInt("T_power")
+	T_name := c.GetString("T_name")
+	T_user := c.GetString("T_user")
+	T_pass := c.GetString("T_pass")
+	T_wxname := c.GetString("T_wxname")
+	T_signature_img := c.GetString("T_signature_img")
+
+	err, r := Account.Read_Admin_ByT_uuid(T_uuid)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	err, r2 := Account.Read_Admin_ByT_user(T_user)
+	if err == nil && T_uuid != r2.T_uuid {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "用户名已存在!"}
+		c.ServeJSON()
+		return
+	}
+	if T_power > 0 {
+		r.T_power = T_power
+	}
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(T_user) > 0 {
+		r.T_user = T_user
+	}
+	if len(T_pass) > 0 {
+		r.T_pass = T_pass
+	}
+	if len(T_wxname) > 0 {
+		r.T_wxname = T_wxname
+	}
+	if len(T_signature_img) > 0 {
+		r.T_signature_img = T_signature_img
+	}
+
+	if !Account.Update_Admin(r, "T_power", "T_name", "T_user", "T_pass", "T_wxname", "T_signature_img") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "管理员用户", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 管理员-删除-
+func (c *AccountController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+	T_uuid := c.GetString("T_uuid")
+
+	if User_r.T_uuid == T_uuid {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "禁止删除自己!"}
+		c.ServeJSON()
+		return
+	}
+	if err, r := Account.Read_Admin_ByT_uuid(T_uuid); err == nil {
+		if !Account.Delete_Admin_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "管理员用户", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 用户权限-所有列表-
+func (c *AccountController) UserPower_List_All() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+	var r_jsons lib.R_JSONS
+	r_jsons.List = Account.Read_Power_List_ALL_Admin_Power(User_r.T_power)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 管理员-全部列表-
+func (c *AccountController) List_All() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	if User_r.T_power > 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+	PowerList := Account.Read_Power_List_ALL_1()
+	PowerMap := Account.UserPowerListToPowerMap(PowerList)
+
+	var r_jsons lib.R_JSONS
+	r_jsons.List = Account.Read_Admin_List_ALL_Power(User_r.T_Distributor_id, "", PowerMap)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 修改密码
+func (c *AccountController) UpPassword() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	T_oldpass := c.GetString("T_oldpass")
+	T_pass := c.GetString("T_pass")
+
+	if T_oldpass != user_r.T_pass {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "旧密码错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_pass) > 0 {
+		user_r.T_pass = T_pass
+	}
+
+	if !Account.Update_Admin(user_r, "T_pass") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	user_r.T_pass = "********"
+	System.Add_UserLogs_T(user_r.T_uuid, "管理员管理", "修改密码", user_r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}

+ 676 - 0
controllers/AllotTask.go

@@ -0,0 +1,676 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/lib/wx"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/AllotTask"
+	"ColdVerify_server/models/InfoCollection"
+	"ColdVerify_server/models/System"
+	"encoding/json"
+	"fmt"
+	"math"
+	"time"
+
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+type AllotTaskController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *AllotTaskController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_company := c.GetString("T_company") // 公司名称
+	T_uuid := c.GetString("T_uuid")
+
+	T_scheme := c.GetString("T_scheme")         // 实施方案 负责人UUID
+	T_project := c.GetString("T_project")       // 实施方案 负责人UUID
+	T_collection := c.GetString("T_collection") // 数据采集 负责人UUID
+	T_reporting := c.GetString("T_reporting")   // 报告编写 负责人UUID
+	T_delivery := c.GetString("T_delivery")     // 交付审核 负责人UUID
+	T_status, _ := c.GetInt("T_status")
+
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var T_company_list []string
+	if len(T_company) > 0 {
+		T_company_list = Account.Read_User_T_uuid_ListByT_name(T_company)
+	}
+
+	var T_admin string
+	if User_r.T_power > 2 {
+		T_admin = User_r.T_uuid
+	}
+	// 经销商下管理员可查看自己经销商下所有的任务
+	// 经销商下其他角色只能查看分配给自己的任务
+	if len(User_r.T_Distributor_id) > 0 && User_r.T_power <= 2 {
+		T_admin = ""
+	}
+
+	var cnt int
+
+	List, cnt := AllotTask.Read_AllotTask_List(User_r.T_Distributor_id, T_admin, T_uuid, T_name, T_project, T_scheme, T_collection, T_reporting, T_delivery,
+		T_status, T_company_list, UserMap, AdminMap, page, page_z)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 获取-
+func (c *AllotTaskController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	r, is := AllotTask.Read_AllotTask(T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	userMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	adminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: AllotTask.AllotTaskToAllotTask_(r, userMap, adminMap)}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *AllotTaskController) Add() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_uuid := c.GetString("T_uuid")                   // 用户uuid
+	T_approach_time := c.GetString("T_approach_time") // 用户uuid
+	T_scheme := c.GetString("T_scheme")
+	T_collection := c.GetString("T_collection")
+	T_reporting := c.GetString("T_reporting")
+	T_delivery := c.GetString("T_delivery")
+
+	T_project := c.GetString("T_project")             // 项目 负责人UUID
+	T_province := c.GetString("T_province")           // 省
+	T_city := c.GetString("T_city")                   // 市
+	T_district := c.GetString("T_district")           // 区
+	T_province_code := c.GetString("T_province_code") // 省 code
+	T_city_code := c.GetString("T_city_code")         // 市 code
+	T_district_code := c.GetString("T_district_code") // 区 code
+	T_category := c.GetString("T_category")           // 类别
+	T_attachment := c.GetString("T_attachment")       // 合同附件
+
+	// 查询信息采集信息
+	user, is := Account.Read_User(T_uuid)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_uuid 错误!"}
+		c.ServeJSON()
+		return
+	}
+	var_ := AllotTask.AllotTask{
+		T_Distributor_id: user.T_Distributor_id,
+		T_uuid:           T_uuid,
+		T_name:           T_name,
+		T_approach_time:  T_approach_time,
+		T_scheme:         T_scheme,
+		T_collection:     T_collection,
+		T_reporting:      T_reporting,
+		T_delivery:       T_delivery,
+
+		T_project:       T_project,
+		T_province:      T_province,
+		T_city:          T_city,
+		T_district:      T_district,
+		T_province_code: T_province_code,
+		T_city_code:     T_city_code,
+		T_district_code: T_district_code,
+		T_category:      T_category,
+		T_attachment:    T_attachment,
+
+		T_state:  1,
+		T_status: AllotTask.AllotTaskStatusWaitReceive,
+
+		T_allot_time: time.Now(),
+	}
+
+	T_sllot_task_id, is := AllotTask.Add_AllotTask(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 通知
+	_, company_r := Account.Read_User_ByT_uuid(var_.T_uuid)
+	go wx.WxSend(var_.T_collection, fmt.Sprintf("【%s-%s】采集任务已派发,进场时间:%s,请及时接收并提交信息确认表", company_r.T_name, var_.T_name, T_approach_time))
+
+	System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_sllot_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *AllotTaskController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_approach_time := c.GetString("T_approach_time")
+	T_scheme := c.GetString("T_scheme")
+	T_collection := c.GetString("T_collection")
+	T_reporting := c.GetString("T_reporting")
+	T_delivery := c.GetString("T_delivery")
+	T_project := c.GetString("T_project")             // 项目 负责人UUID
+	T_province := c.GetString("T_province")           // 省
+	T_city := c.GetString("T_city")                   // 市
+	T_district := c.GetString("T_district")           // 区
+	T_province_code := c.GetString("T_province_code") // 省 code
+	T_city_code := c.GetString("T_city_code")         // 市 code
+	T_district_code := c.GetString("T_district_code") // 区 code
+	T_category := c.GetString("T_category")           // 类别
+	T_attachment := c.GetString("T_attachment")       // 合同附件
+
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	r, is := AllotTask.Read_AllotTask(T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	old_collection := r.T_collection
+	// .......
+	clos := make([]string, 0)
+	r.T_attachment = T_attachment
+	if len(T_name) > 0 {
+		r.T_name = T_name
+		clos = append(clos, "T_name")
+	}
+	if len(T_approach_time) > 0 {
+		r.T_approach_time = T_approach_time
+		clos = append(clos, "T_approach_time")
+	}
+
+	if len(T_scheme) > 0 {
+		r.T_scheme = T_scheme
+		clos = append(clos, "T_scheme")
+
+	}
+	if len(T_collection) > 0 {
+		r.T_collection = T_collection
+		clos = append(clos, "T_collection")
+	}
+	if len(T_reporting) > 0 {
+		r.T_reporting = T_reporting
+		clos = append(clos, "T_reporting")
+	}
+	if len(T_delivery) > 0 {
+		r.T_delivery = T_delivery
+		clos = append(clos, "T_delivery")
+	}
+
+	if len(T_project) > 0 {
+		r.T_project = T_project
+		clos = append(clos, "T_project")
+	}
+	if len(T_province) > 0 {
+		r.T_province = T_province
+		clos = append(clos, "T_province")
+	}
+	if len(T_city) > 0 {
+		r.T_city = T_city
+		clos = append(clos, "T_city")
+	}
+	if len(T_district) > 0 {
+		r.T_district = T_district
+		clos = append(clos, "T_district")
+	}
+	if len(T_province_code) > 0 {
+		r.T_province_code = T_province_code
+		clos = append(clos, "T_province_code")
+	}
+	if len(T_city_code) > 0 {
+		r.T_city_code = T_city_code
+		clos = append(clos, "T_city_code")
+	}
+	if len(T_district_code) > 0 {
+		r.T_district_code = T_district_code
+		clos = append(clos, "T_district_code")
+	}
+	if len(T_category) > 0 {
+		r.T_category = T_category
+		clos = append(clos, "T_category")
+	}
+	if len(T_attachment) > 0 {
+		r.T_attachment = T_attachment
+		clos = append(clos, "T_attachment")
+	}
+
+	if r.T_status == AllotTask.AllotTaskStatusRefused {
+		r.T_status = AllotTask.AllotTaskStatusWaitReceive
+		r.T_allot_time = time.Now()
+		clos = append(clos, "T_status")
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】采集任务已派发,进场时间:%s,请及时接收并提交信息确认表", company_r.T_name, r.T_name, T_approach_time))
+
+	} else if r.T_collection != old_collection {
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】采集任务已派发,进场时间:%s,请及时接收并提交信息确认表", company_r.T_name, r.T_name, T_approach_time))
+
+	}
+
+	if !AllotTask.Update_AllotTask(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *AllotTaskController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	if r, is := AllotTask.Read_AllotTask(T_allot_task_id); is {
+		if !AllotTask.Delete_AllotTask(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		// 添加任务操作日志
+		System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 复制-
+func (c *AllotTaskController) Copy() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_approach_time := c.GetString("T_approach_time")
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	r, is := AllotTask.Read_AllotTask(T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := AllotTask.AllotTask{
+		T_Distributor_id: r.T_Distributor_id,
+		T_uuid:           r.T_uuid,
+		T_name:           T_name,
+		T_approach_time:  T_approach_time,
+		T_scheme:         r.T_scheme,
+		T_collection:     r.T_collection,
+		T_reporting:      r.T_reporting,
+		T_delivery:       r.T_delivery,
+		T_project:        r.T_project,
+		T_province:       r.T_province,
+		T_city:           r.T_city,
+		T_district:       r.T_district,
+		T_province_code:  r.T_province_code,
+		T_city_code:      r.T_city_code,
+		T_district_code:  r.T_district_code,
+		T_category:       r.T_category,
+		T_state:          1,
+		T_status:         AllotTask.AllotTaskStatusWaitReceive,
+		T_allot_time:     time.Now(),
+	}
+
+	// 通知
+	_, company_r := Account.Read_User_ByT_uuid(var_.T_uuid)
+	go wx.WxSend(var_.T_collection, fmt.Sprintf("【%s-%s】采集任务已派发,进场时间:%s,请及时接收并提交信息确认表", company_r.T_name, var_.T_name, T_approach_time))
+	T_sllot_task_id, is := AllotTask.Add_AllotTask(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "复制", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_sllot_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 接收
+func (c *AllotTaskController) Receive() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_status, _ := c.GetInt("T_status") // 2-接收 3-拒绝
+	T_reason := c.GetString("T_reason")
+
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	r, is := AllotTask.Read_AllotTask(T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 验证权限
+	if User_r.T_uuid != r.T_collection {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "您不是该任务单的接收人!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 获取r.T_record,转换为json,添加新的记录
+	var existingRecords = make([]AllotTask.AllotTaskRecord, 0)
+	if len(r.T_record) > 0 {
+		json.Unmarshal([]byte(r.T_record), &existingRecords)
+	}
+
+	// 创建新的记录条目
+	newRecord := AllotTask.AllotTaskRecord{
+		T_collection: User_r.T_uuid,
+		T_status:     T_status,
+		T_reason:     T_reason,
+		T_time:       time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	existingRecords = append(existingRecords, newRecord)
+
+	// 将更新后的记录数组转换为JSON字符串
+	updatedRecordsJSON, err := json.Marshal(existingRecords)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "记录更新失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 更新r.T_record字段
+	r.T_record = string(updatedRecordsJSON)
+	r.T_status = T_status
+	if r.T_status == AllotTask.AllotTaskStatusRefused && len(T_reason) > 0 {
+		r.T_reason = T_reason
+	}
+
+	// 更新数据库中的记录
+	if !AllotTask.Update_AllotTask(r, "T_record", "T_status", "T_reason") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "更新记录失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 添加任务操作日志
+	System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "接收", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+
+}
+
+// 上传信息确认表
+func (c *AllotTaskController) UploadConfirmForm() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_confirm_form := c.GetString("T_confirm_form")
+
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	r, is := AllotTask.Read_AllotTask(T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_confirm_form) > 0 {
+		r.T_confirm_form = T_confirm_form
+		if r.T_status == AllotTask.AllotTaskStatusReceived {
+			r.T_status = AllotTask.AllotTaskStatusSubmit // 修改为已提交
+		}
+		if len(r.T_submit_time) == 0 {
+			r.T_submit_time = time.Now().Format("2006-01-02 15:04:05") // 设置提交时间
+		}
+	}
+
+	// 获取r.T_record,转换为json,添加新的记录
+	var existingRecords = make([]AllotTask.AllotTaskRecord, 0)
+	if len(r.T_record) > 0 {
+		json.Unmarshal([]byte(r.T_record), &existingRecords)
+	}
+
+	// 创建新的记录条目
+	newRecord := AllotTask.AllotTaskRecord{
+		T_collection: User_r.T_uuid,
+		T_status:     AllotTask.AllotTaskStatusSubmit,
+		T_reason:     "",
+		T_time:       time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	existingRecords = append(existingRecords, newRecord)
+
+	// 将更新后的记录数组转换为JSON字符串
+	updatedRecordsJSON, err := json.Marshal(existingRecords)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "记录更新失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 更新r.T_record字段
+	r.T_record = string(updatedRecordsJSON)
+
+	if !AllotTask.Update_AllotTask(r, "T_confirm_form", "T_status", "T_submit_time", "T_record") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "采集任务管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 采集任务统计
+func (c *AllotTaskController) Statistics() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	List, cnt := AllotTask.Read_AllotTask_List(User_r.T_Distributor_id, User_r.T_uuid, "", "", "", "", "", "", "",
+		0, []string{}, map[string]string{}, map[string]string{}, 0, 9999)
+
+	res := make(map[int]int)
+	for k, _ := range AllotTask.AllotTaskStateMap {
+		res[k] = 0
+	}
+	res[0] = cnt
+	for _, r := range List {
+		res[r.T_status] += 1
+	}
+
+	// 按指定格式返回统计结果
+	result := []map[string]interface{}{
+		{
+			"name":     "全部",
+			"num":      res[0],
+			"T_status": 0,
+		},
+		{
+			"name":     "待接收",
+			"num":      res[AllotTask.AllotTaskStatusWaitReceive],
+			"T_status": AllotTask.AllotTaskStatusWaitReceive,
+		},
+		{
+			"name":     "已接收",
+			"num":      res[AllotTask.AllotTaskStatusReceived],
+			"T_status": AllotTask.AllotTaskStatusReceived,
+		},
+		{
+			"name":     "已提交",
+			"num":      res[AllotTask.AllotTaskStatusSubmit],
+			"T_status": AllotTask.AllotTaskStatusSubmit,
+		},
+		{
+			"name":     "已拒绝",
+			"num":      res[AllotTask.AllotTaskStatusRefused],
+			"T_status": AllotTask.AllotTaskStatusRefused,
+		},
+	}
+
+	c.Data["json"] = lib.JSONS{Data: result, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 获取任务负责人列表
+func (c *AllotTaskController) GetAllotTaskUserList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_type := c.GetString("T_type") // T_project项目 T_scheme方案 T_collection数据采集 T_reporting报告
+
+	list := AllotTask.Get_AllotTask_UserList(T_type)
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var User_list []Account.Admin_R
+	for _, v := range list {
+		if len(v) == 0 {
+			continue
+		}
+		User_list = append(User_list, Account.Admin_R{T_uuid: v, T_name: AdminMap[v]})
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: User_list}
+	c.ServeJSON()
+	return
+}
+
+// 通过信息采集ID获取指派任务详情
+func (c *AllotTaskController) GetByInfoCollectionId() {
+	// 验证登录
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	if len(T_InfoCollection_id) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "信息采集ID不能为空!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 先通过信息采集ID获取信息采集详情
+	infoCollection, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "信息采集ID错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 检查是否有关联的指派任务ID
+	if len(infoCollection.T_allot_task_id) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Data: AllotTask.AllotTask_{}, Msg: "该信息采集没有关联的指派任务!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 通过指派任务ID获取指派任务详情
+	allotTask, is := AllotTask.Read_AllotTask(infoCollection.T_allot_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "指派任务不存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	allotTaskDetail := AllotTask.AllotTaskToAllotTask_(allotTask, map[string]string{}, map[string]string{})
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: allotTaskDetail}
+	c.ServeJSON()
+	return
+}

+ 479 - 0
controllers/Certificate.go

@@ -0,0 +1,479 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Certificate"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type CertificateController struct {
+	beego.Controller
+}
+
+// 列表-
+func (c *CertificateController) List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	//T_sn := c.GetString("T_sn")
+	T_Certificate_sn := c.GetString("T_Certificate_sn")
+	T_layout_no := c.GetString("T_layout_no")
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_release_time_sort, _ := c.GetInt("T_release_time_sort") // 1 升序 2 降序
+	T_failure_time_sort, _ := c.GetInt("T_failure_time_sort") // 1 升序 2 降序
+	T_layout_no_sort, _ := c.GetInt("T_layout_no_sort")       // 1 升序 2 降序
+
+	if len(Time_start) > 0 && !lib.IsDateStr(Time_start) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(Time_end) > 0 && !lib.IsDateStr(Time_end) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var cnt int
+	List, cnt := Certificate.Read_Certificate_List(T_Certificate_sn, T_layout_no, Time_start, Time_end, T_release_time_sort, T_failure_time_sort, T_layout_no_sort, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+func (c *CertificateController) ListWithoutDeviceList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "任务id错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	var list []Certificate.Certificate_
+	var cnt int
+	certificateList, _ := Certificate.Read_Certificate_List("", "", "", "", 0, 0, 0, 0, 9999)
+	DeviceList, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", "", 0, 9999)
+	var deviceMap = make(map[string]struct{})
+	for _, v := range DeviceList {
+		deviceMap[v.T_id] = struct{}{}
+	}
+
+	for _, certificate := range certificateList {
+		if _, ok := deviceMap[certificate.T_layout_no]; ok {
+			continue
+		}
+		list = append(list, certificate)
+		cnt += 1
+
+	}
+
+	r_jsons.List = list
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *CertificateController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_layout_no := c.GetString("T_layout_no")
+	if _, is := Certificate.Read_Certificate(T_layout_no); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "布局编号不存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, err := Certificate.Read_CertificatePdf_Newest(T_layout_no)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "查询失败!"}
+		c.ServeJSON()
+		return
+	}
+	if len(r) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "证书不存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Certificate.CertificatePdfToCertificatePdf_R(r[0])}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *CertificateController) Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_layout_no := c.GetString("T_layout_no")
+
+	var_ := Certificate.Certificate{
+		T_layout_no: T_layout_no,
+		T_State:     1,
+	}
+
+	if _, is := Certificate.Read_Certificate(T_layout_no); is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "设备编号重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, is := Certificate.Add_Certificate(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "校准证书管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+
+	return
+}
+
+// 添加-
+func (c *CertificateController) Edit() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Certificate.Read_Certificate_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	old_T_layout_no := r.T_layout_no
+	T_layout_no := c.GetString("T_layout_no")
+
+	if _, is = Certificate.Read_Certificate(T_layout_no); is && r.T_layout_no != T_layout_no {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "设备编号重复!"}
+		c.ServeJSON()
+		return
+	}
+	r.T_layout_no = T_layout_no
+	is = Certificate.Update_Certificate(r, "T_layout_no")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	pdfList, _ := Certificate.Read_CertificatePdf_List(old_T_layout_no, 0, 9999)
+	for _, pdf := range pdfList {
+		// 修改pdf
+		var_ := Certificate.CertificatePdf{
+			Id:          pdf.Id,
+			T_layout_no: T_layout_no,
+		}
+		if !Certificate.Update_CertificatePdf(var_, "T_layout_no") {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	System.Add_UserLogs_T(user_r.T_uuid, "校准证书管理", "编辑", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+
+	return
+}
+
+// 删除-
+func (c *CertificateController) Del() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Certificate.Read_Certificate_ById(Id); is {
+		if !Certificate.Delete_Certificate_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(user_r.T_uuid, "校准证书管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表-
+func (c *CertificateController) Pdf_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	//T_Certificate_sn := c.GetString("T_Certificate_sn")
+	T_layout_no := c.GetString("T_layout_no")
+
+	var cnt int64
+	List, cnt := Certificate.Read_CertificatePdf_List(T_layout_no, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *CertificateController) Pdf_Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_layout_no := c.GetString("T_layout_no")           // 布局编号
+	T_Certificate_sn := c.GetString("T_Certificate_sn") // 证书编号
+	T_release_time := c.GetString("T_release_time")
+	T_failure_time := c.GetString("T_failure_time")
+	T_pdf := c.GetString("T_pdf")
+	if len(T_layout_no) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "布局编号不能为空"}
+		c.ServeJSON()
+		return
+	}
+
+	if !lib.IsDateStr(T_release_time) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if !lib.IsDateStr(T_failure_time) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := Certificate.CertificatePdf{
+		T_layout_no:      T_layout_no,
+		T_Certificate_sn: T_Certificate_sn,
+		T_release_time:   T_release_time,
+		T_failure_time:   T_failure_time,
+		T_pdf:            T_pdf,
+		T_State:          1,
+	}
+
+	if _, err := Certificate.Read_CertificatePdf(T_Certificate_sn, T_release_time, T_failure_time); err == nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "证书编号重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, is := Certificate.Add_CertificatePdf(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "校准证书Pdf", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+
+	return
+}
+
+// 修改-
+func (c *CertificateController) Pdf_Up() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_Certificate_sn := c.GetString("T_Certificate_sn")
+	T_release_time := c.GetString("T_release_time")
+	T_failure_time := c.GetString("T_failure_time")
+	T_pdf := c.GetString("T_pdf")
+
+	if !lib.IsDateStr(T_release_time) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if !lib.IsDateStr(T_failure_time) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Certificate.Read_CertificatePdf_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	_, err = Certificate.Read_CertificatePdf(T_Certificate_sn, T_release_time, T_failure_time)
+	if err == nil && r.T_failure_time != T_failure_time && r.T_release_time != T_release_time {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据已存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_Certificate_sn) > 0 {
+		r.T_Certificate_sn = T_Certificate_sn
+	}
+	if len(T_release_time) > 0 {
+		r.T_release_time = T_release_time
+	}
+	if len(T_failure_time) > 0 {
+		r.T_failure_time = T_failure_time
+	}
+	if len(T_pdf) > 0 {
+		r.T_pdf = T_pdf
+	}
+	if !Certificate.Update_CertificatePdf(r, "T_Certificate_sn", "T_release_time", "T_failure_time", "T_pdf") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "校准证书Pdf", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *CertificateController) Pdf_Del() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Certificate.Read_CertificatePdf_ById(Id); is {
+		if !Certificate.Delete_CertificatePdf_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(user_r.T_uuid, "校准证书Pdf", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}

+ 284 - 0
controllers/Device.go

@@ -0,0 +1,284 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/System"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type DeviceController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *DeviceController) List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_sn := c.GetString("T_sn")
+	T_MSISDN := c.GetString("T_MSISDN")
+
+	var cnt int64
+	List, cnt := Device.Read_Device_List(T_sn, T_MSISDN, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *DeviceController) Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn := c.GetString("T_sn")
+	T_MSISDN := c.GetString("T_MSISDN")
+
+	var_ := Device.Device{
+		T_sn:     T_sn,
+		T_MSISDN: T_MSISDN,
+		T_State:  1,
+	}
+
+	if _, is := Device.Read_Device(T_sn); is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "重复添加!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, is := Device.Add_Device(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "设备管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *DeviceController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn := c.GetString("T_sn")
+
+	r, is := Device.Read_Device(T_sn)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Device.DeviceToDevice_R(r, "0")}
+	c.ServeJSON()
+	return
+}
+
+func (c *DeviceController) Up() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn := c.GetString("T_sn")
+	T_MSISDN := c.GetString("T_MSISDN")
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Device.Read_Device_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r.T_sn = T_sn
+	r.T_MSISDN = T_MSISDN
+	// .......
+	if !Device.Update_Device(r, "T_sn", "T_MSISDN") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "设备管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *DeviceController) Del() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Device.Read_Device_ById(Id); is {
+		if !Device.Delete_Device(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(user_r.T_uuid, "设备管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 - 分类设备
+func (c *DeviceController) Device_Class() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS_s
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	T_sn := c.GetString("T_sn")
+
+	r, is := Device.Read_DeviceClass_ById(T_class)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 1202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var cnt int64
+	//DeviceList, cnt := Device.Read_DeviceClassList_List(T_class, T_sn, page, 9999)
+	DeviceList, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, "", "", page, 9999)
+
+	for _, v := range DeviceList {
+		Device_r, _ := Device.Read_Device(v.T_sn)
+		Device_r.T_note_file_num = Device.Read_DeviceSensorData_List_z(v.T_sn, r.CreateTime.Format("2006-01-02 15:04:05"))
+		r_jsons.List = append(r_jsons.List, Device.DeviceToDevice_R(Device_r, v.T_id))
+	}
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 列表 - 分类设备
+func (c *DeviceController) Device_Data() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	type R_JSONS_s struct {
+		//必须的大写开头
+		List      []Device.DeviceData_
+		Num       int
+		Page      int
+		Page_size int
+		Pages     []lib.Page_T
+	}
+
+	var r_jsons R_JSONS_s
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_sn := c.GetString("T_sn")
+	Time_start := c.GetString("Time_start")
+	Time_and := c.GetString("Time_end")
+
+	var cnt int
+	r_jsons.List, cnt = Device.Read_DeviceSensorData_List(T_sn, Time_start, Time_and, page, page_z)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}

+ 991 - 0
controllers/DeviceClass.go

@@ -0,0 +1,991 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Certificate"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"ColdVerify_server/models/VerifyTemplate"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+	"strconv"
+	"strings"
+)
+
+type DeviceClassController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *DeviceClassController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+
+	var cnt int64
+	List, cnt := Device.Read_DeviceClass_List(User_r.T_uuid, T_name, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 获取-
+func (c *DeviceClassController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Device.Read_DeviceClass_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *DeviceClassController) Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	var_ := Device.DeviceClass{
+		T_uuid:  User_r.T_uuid,
+		T_name:  T_name,
+		T_State: 1,
+	}
+
+	Id, is := Device.Add_DeviceClass(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *DeviceClassController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Device.Read_DeviceClass_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+
+	// .......
+	if !Device.Update_DeviceClass(r, "T_name") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *DeviceClassController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Device.Read_DeviceClass_ById(Id); is {
+
+		if !Device.Delete_DeviceClass_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "删除", r)
+
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+//--------------------------
+
+// 列表 -
+func (c *DeviceClassController) List_List() {
+	// 验证登录 User_is, User_r
+	//_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	//if !User_is {
+	//	c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	T_sn := c.GetString("T_sn")
+	T_remark := c.GetString("T_remark")
+
+	_, is := Device.Read_DeviceClass_ById(T_class)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var cnt int64
+	//List, cnt := Device.Read_DeviceClassList_List(T_class, T_sn, page, 9999)
+	List, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, "", T_remark, page, 9999)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加- 旧功能
+func (c *DeviceClassController) List_Add1() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	//方式1:001,002,003,004,005,008
+	//方式2:001~005,008
+	T_layout_no_list := c.GetString("T_layout_no_list")
+	//T_sn := c.GetString("T_sn")
+	T_remark := c.GetString("T_remark")
+
+	_, is := Device.Read_DeviceClass_ById(T_class)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误"}
+		c.ServeJSON()
+		return
+	}
+
+	list := strings.Split(strings.TrimRight(T_layout_no_list, ","), ",")
+	snMap := make(map[string]string)
+	excludeId := make(map[string]struct{})
+	errList := []string{}
+	var successNum int // 成功数量
+	for _, v := range list {
+		if strings.Contains(v, "!") {
+			excludeId[fmt.Sprintf("%03d", lib.To_int(strings.TrimLeft(strings.Trim(v, "!"), "0")))] = struct{}{}
+			continue
+		}
+		// 001~005
+		if strings.Contains(v, "~") {
+			vlist := strings.Split(v, "~")
+			if len(vlist) != 2 {
+				c.Data["json"] = lib.JSONS{Code: 202, Msg: "布局编号格式错误!"}
+				c.ServeJSON()
+				return
+			}
+			vstart, vend := lib.To_int(strings.TrimLeft(vlist[0], "0")), lib.To_int(strings.TrimLeft(vlist[1], "0"))
+			for i := vstart; i < vend+1; i++ {
+				T_id := fmt.Sprintf("%03d", i)
+				cert, is := Certificate.Read_Certificate_ByT_layout_no(T_id)
+				if !is {
+					//c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", T_id)}
+					//c.ServeJSON()
+					//return
+
+					errList = append(errList, fmt.Sprintf("%s布局编号不存在!", T_id))
+					continue
+				}
+				snMap[T_id] = cert.T_sn
+			}
+		} else {
+			// 001,002
+			cert, is := Certificate.Read_Certificate_ByT_layout_no(v)
+			if !is {
+				//c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", v)}
+				//c.ServeJSON()
+				//return
+
+				errList = append(errList, v)
+				continue
+			}
+			snMap[v] = cert.T_sn
+		}
+
+	}
+	errList2 := []string{}
+	succesId := []string{}
+	for T_id, T_sn := range snMap {
+		if _, ok := excludeId[T_id]; ok {
+			continue
+		}
+
+		//if _, is = Device.Read_Device(T_sn); !is {
+		//	c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn 不存在!"}
+		//	c.ServeJSON()
+		//	return
+		//}
+
+		if dc, is := Device.Read_DeviceClassList_T_class_T_sn(T_class, T_sn); is && dc.Id > 0 {
+			successNum += 1
+			continue
+		}
+
+		var pdf Certificate.CertificatePdf
+		pdfList, _ := Certificate.Read_CertificatePdf_Newest(T_id)
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		}
+
+		var_ := Device.DeviceClassList{
+			T_class:        T_class,
+			T_id:           T_id,
+			T_sn:           T_sn,
+			T_failure_time: pdf.T_failure_time,
+			T_pdf:          pdf.T_pdf,
+			T_remark:       T_remark,
+			T_State:        1,
+		}
+
+		_, is = Device.Add_DeviceClassList(var_)
+		if !is {
+			//c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+			//c.ServeJSON()
+			//return
+
+			errList2 = append(errList2, T_id)
+			continue
+		}
+		successNum += 1
+		succesId = append(succesId, T_id)
+		System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "添加", var_)
+	}
+
+	if len(errList) == 0 && len(errList2) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: successNum}
+		c.ServeJSON()
+		return
+	}
+	var errStr string
+	if len(errList) > 0 {
+		errStr += strings.Join(errList, ",") + "编号不存在"
+	}
+	if len(errList2) > 0 {
+		if len(errStr) > 0 {
+			errStr += ","
+		}
+		errStr += strings.Join(errList2, ",") + "添加失败"
+	}
+	//if len(succesId) > 0 {
+	//	if len(errStr) > 0 {
+	//		errStr += ","
+	//	}
+	//	errStr += strings.Join(succesId, ",") + "添加成功"
+	//}
+
+	c.Data["json"] = lib.JSONS{Code: 210, Msg: errStr, Data: successNum}
+	c.ServeJSON()
+	return
+}
+func (c *DeviceClassController) List_Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	T_sn_id_list := c.GetString("T_sn_id_list")
+
+	// 根据 | 分割数据
+	items := strings.Split(T_sn_id_list, "|")
+
+	// 创建一个 map 来去重
+	uniqueItems := make(map[string]struct{})
+
+	for _, item := range items {
+		// 如果不为空,则添加到 map 中
+		if item != "" {
+			uniqueItems[item] = struct{}{}
+		}
+	}
+
+	// 将唯一项拼接成字符串
+	result := ""
+
+	for item := range uniqueItems {
+		result += item + "|"
+	}
+
+	// 移除最后的 | 字符
+	if len(result) > 0 {
+		result = result[:len(result)-1]
+	}
+	T_sn_id_list = result
+
+	list := strings.Split(strings.TrimRight(T_sn_id_list, "|"), "|")
+	T_remark := c.GetString("T_remark")
+
+	_, is := Device.Read_DeviceClass_ById(T_class)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误"}
+		c.ServeJSON()
+		return
+	}
+
+	var successNum int // 成功数量
+	errList := []string{}
+	errList2 := []string{}
+	succesId := []string{}
+	for _, sn_id := range list {
+		T_sn := strings.Split(sn_id, ",")[0]
+		T_id := strings.Split(sn_id, ",")[1]
+		if len(T_sn) == 0 || len(T_id) == 0 {
+			errList = append(errList, sn_id)
+			continue
+		}
+		// 判断是否已存在sn
+		dc, is := Device.Read_DeviceClassList_T_class_T_sn(T_class, T_sn)
+		// 添加的id和数据库已存在id相同
+		if is && dc.T_id == T_id {
+			successNum += 1
+			continue
+		}
+		// 添加的id和数据库已存在id不同
+		if is && dc.T_id != T_id {
+			_, is = Device.Read_DeviceClassList_T_class_T_id(T_class, T_id)
+			if is {
+				errList2 = append(errList2, sn_id)
+				continue
+			}
+			dc.T_id = T_id
+			dc.T_remark = T_remark
+			if !Device.Update_DeviceClassList(dc, "T_id", "T_remark") {
+				errList = append(errList, sn_id)
+			} else {
+				successNum += 1
+			}
+			continue
+		}
+
+		if !is {
+			_, is = Device.Read_DeviceClassList_T_class_T_id(T_class, T_id)
+			if is {
+				errList2 = append(errList2, sn_id)
+				continue
+			}
+		}
+
+		var pdf Certificate.CertificatePdf
+		//pdfList, _ := Certificate.Read_CertificatePdf_Newest(T_sn)
+		pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(T_id, "")
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		}
+
+		var_ := Device.DeviceClassList{
+			T_class:          T_class,
+			T_id:             T_id,
+			T_sn:             T_sn,
+			T_failure_time:   pdf.T_failure_time,
+			T_pdf:            pdf.T_pdf,
+			T_Certificate_sn: pdf.T_Certificate_sn,
+			T_remark:         T_remark,
+			T_State:          1,
+		}
+
+		_, is = Device.Add_DeviceClassList(var_)
+		if !is {
+			errList = append(errList, sn_id)
+			continue
+		}
+		successNum += 1
+		succesId = append(succesId, sn_id)
+		System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "添加", var_)
+	}
+
+	if len(errList) == 0 && len(errList2) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: successNum}
+		c.ServeJSON()
+		return
+	}
+	var errStr string
+	if len(errList2) > 0 {
+		errStr += strings.Join(errList2, ",") + "编号已存在"
+	}
+	if len(errList) > 0 {
+		if len(errStr) > 0 {
+			errStr += ","
+		}
+		errStr += strings.Join(errList, ",") + "添加失败"
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 210, Msg: errStr, Data: successNum}
+	c.ServeJSON()
+	return
+}
+func (c *DeviceClassController) List_Copy() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_copy_task_id := c.GetString("T_copy_task_id")
+	copy_task, is := Task.Read_Task(T_copy_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_copy_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_paste_task_id := c.GetString("T_paste_task_id")
+	paste_task, is := Task.Read_Task(T_paste_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_paste_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	errList := []string{}
+	pasteList, cnt := Device.Read_DeviceClassList_OrderList(paste_task.T_class, "", "", "", 0, 9999)
+	for _, ds := range pasteList {
+		if !Device.Delete_DeviceClassList_(ds) {
+			errList = append(errList, ds.T_id)
+			continue
+		}
+	}
+
+	// 删除旧的设备列表
+
+	copyList, cnt := Device.Read_DeviceClassList_OrderList(copy_task.T_class, "", "", "", 0, 9999)
+	var successNum int // 成功数量
+
+	for _, v := range copyList {
+		// 不存在则添加
+		var pdf Certificate.CertificatePdf
+		pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(v.T_id, "")
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		}
+
+		var_ := Device.DeviceClassList{
+			T_class:          paste_task.T_class,
+			T_id:             v.T_id,
+			T_sn:             v.T_sn,
+			T_failure_time:   pdf.T_failure_time,
+			T_pdf:            pdf.T_pdf,
+			T_Certificate_sn: pdf.T_Certificate_sn,
+			T_remark:         v.T_remark,
+			T_terminal:       v.T_terminal,
+			T_State:          1,
+		}
+
+		_, is = Device.Add_DeviceClassList(var_)
+		if !is {
+			errList = append(errList, v.T_id)
+			continue
+		}
+
+	}
+
+	if len(errList) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: cnt}
+		c.ServeJSON()
+		return
+	}
+	var errStr string
+	if len(errList) > 0 {
+		if len(errStr) > 0 {
+			errStr += ","
+		}
+		errStr += strings.Join(errList, ",") + "粘贴失败"
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 210, Msg: errStr, Data: successNum}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *DeviceClassController) List_Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id := c.GetString("T_id")
+	T_remark := c.GetString("T_remark")
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Device.Read_DeviceClassList_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	_, is = Device.Read_DeviceClass_ById(r.T_class)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	_, is = Device.Read_DeviceClassList_T_class_T_id(r.T_class, T_id)
+	if is && T_id != r.T_id {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: T_id + "编号已存在!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_id) > 0 {
+		r.T_id = T_id
+		// 修改布局编号对应的证书
+		var pdf Certificate.CertificatePdf
+		pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(T_id, r.CreateTime.Format("2006-01-02"))
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		}
+		r.T_failure_time = pdf.T_failure_time
+		r.T_pdf = pdf.T_pdf
+		r.T_Certificate_sn = pdf.T_Certificate_sn
+	}
+	if len(T_remark) > 0 {
+		r.T_remark = T_remark
+	}
+
+	if !Device.Update_DeviceClassList(r, "T_id", "T_remark", "T_failure_time", "T_pdf", "T_Certificate_sn") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改终端
+func (c *DeviceClassController) List_Up_terminal() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_terminal, _ := c.GetInt("T_terminal")
+	T_task_id := c.GetString("T_task_id")
+	T_id := c.GetString("T_id")
+
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取任务失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Device.Read_DeviceClassList_T_class_T_id(task.T_class, T_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取设备失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	if T_terminal > 0 {
+		r.T_terminal = T_terminal
+	}
+
+	if !Device.Update_DeviceClassList(r, "T_terminal") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "修改终端标识", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *DeviceClassController) List_Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Device.Read_DeviceClassList_ById(Id); is {
+
+		_, is = Device.Read_DeviceClass_ById(r.T_class)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+			c.ServeJSON()
+			return
+		}
+
+		if !Device.Delete_DeviceClassList_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "删除", r)
+
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 添加设备列表。模版下载
+func (c *DeviceClassController) List_Template_Download() {
+
+	// 返回生成的 Excel 文件
+	c.Ctx.Output.Download("static/添加设备列表模版.xlsx")
+}
+
+func (c *DeviceClassController) List_Del_Duplication() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "任务id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Device.Del_DeviceClassList_Duplication(r.T_class)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 同步证书到设备列表
+func (c *DeviceClassController) Sync_CertificatePdf_ToList() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	CreateTime := c.GetString("CreateTime")
+	list := Device.Read_DeviceClassList_List_ByT_Certificate_sn_null(CreateTime)
+	for _, v := range list {
+		var pdf Certificate.CertificatePdf
+		pdfList, _ := Certificate.Read_CertificatePdf_T_layout_no(v.T_id, v.CreateTime.Format("2006-01-02"))
+		if len(pdfList) > 0 {
+			pdf = pdfList[0]
+		} else {
+			continue
+		}
+
+		v.T_Certificate_sn = pdf.T_Certificate_sn
+		v.T_failure_time = pdf.T_failure_time
+		v.T_pdf = pdf.T_pdf
+		if !Device.Update_DeviceClassList(v, "T_failure_time", "T_pdf", "T_Certificate_sn") {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+			c.ServeJSON()
+			return
+		}
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "同步证书到设备列表", CreateTime)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 自动填写设备备注
+func (c *DeviceClassController) Auto_fill_Remark() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	verifyTemplate, is := VerifyTemplate.Read_VerifyTemplate(task.T_VerifyTemplate_id)
+	verifyTemplate_R := VerifyTemplate.VerifyTemplateToVerifyTemplate_R(verifyTemplate)
+	T_deploy_list := verifyTemplate_R.T_deploy_list
+
+	// 循环查询布点
+	deviceClassRemarkMap := make(map[int][]string)
+	deviceClassList := Device.Read_DeviceClassList_List_id_By_Terminal(task.T_class, false)
+	for _, deploy := range T_deploy_list {
+		if len(deploy.T_scope) > 0 {
+			dcl := FilterByRange(deviceClassList, deploy.T_scope)
+			for _, dc := range dcl {
+				deviceClassRemarkMap[dc.Id] = append(deviceClassRemarkMap[dc.Id], deploy.T_name)
+
+			}
+		}
+	}
+
+	for _, deviceClass := range deviceClassList {
+		if remark, ok := deviceClassRemarkMap[deviceClass.Id]; ok {
+			deviceClass.T_remark = strings.Join(remark, "|")
+			if !Device.Update_DeviceClassList(deviceClass, "T_remark") {
+				c.Data["json"] = lib.JSONS{Code: 200, Msg: "修改备注失败!"}
+				c.ServeJSON()
+				return
+			}
+
+		}
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "设备备注", "自动填写", T_task_id)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+func (c *DeviceClassController) List_Maximum() {
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: conf.DeviceListMaximum}
+	c.ServeJSON()
+	return
+}
+
+func FilterByRange(data []Device.DeviceClassList, condition string) []Device.DeviceClassList {
+	var result []Device.DeviceClassList
+	parts := strings.Split(condition, ",")
+
+	for _, part := range parts {
+		if strings.Contains(part, "-") {
+			// 处理范围 如1-16
+			rangeParts := strings.Split(part, "-")
+			if len(rangeParts) != 2 {
+				continue
+			}
+			start, err1 := strconv.Atoi(rangeParts[0])
+			end, err2 := strconv.Atoi(rangeParts[1])
+			if err1 != nil || err2 != nil || start > end {
+				continue
+			}
+
+			// 转换为0-based索引
+			startIdx := start - 1
+			endIdx := end - 1
+
+			// 确保索引在有效范围内
+			if startIdx < 0 {
+				startIdx = 0
+			}
+			if endIdx >= len(data) {
+				endIdx = len(data) - 1
+			}
+
+			for i := startIdx; i <= endIdx; i++ {
+				result = append(result, data[i])
+			}
+		} else {
+			// 处理单个数字 如2,5
+			num, err := strconv.Atoi(part)
+			if err != nil {
+				continue
+			}
+
+			// 转换为0-based索引
+			idx := num - 1
+
+			// 确保索引在有效范围内
+			if idx >= 0 && idx < len(data) {
+				result = append(result, data[idx])
+			}
+		}
+	}
+
+	return result
+}
+
+// 验证工具统计
+func (c *DeviceClassController) Stat() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_company := c.GetString("T_company") // 公司名称
+	var T_company_list []string
+	if len(T_company) > 0 {
+		T_company_list = Account.Read_User_T_uuid_ListByT_name(T_company)
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_name := c.GetString("T_name")
+	T_sn := c.GetString("T_sn")
+	T_distinct, _ := c.GetBool("T_distinct")
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+
+	var cnt int64
+	List, cnt := Device.Read_DeviceClass_Stat(T_company_list, T_name, T_sn, Time_start, Time_end, T_distinct, UserMap, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}

+ 310 - 0
controllers/Distributor.go

@@ -0,0 +1,310 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Distributor"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/VerifyTemplate"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type DistributorController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *DistributorController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 || len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+
+	var cnt int64
+	List, cnt := Distributor.Read_Distributor_List(T_name, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *DistributorController) Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 || len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	var_ := Distributor.Distributor{
+		T_name:  T_name,
+		T_State: 1,
+	}
+
+	Id, is := Distributor.Add_Distributor(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "经销商管理", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *DistributorController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 || len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_Distributor_id := c.GetString("T_Distributor_id")
+
+	r, is := Distributor.Read_Distributor(T_Distributor_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+
+	if !Distributor.Update_Distributor(r, "T_name") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "经销商管理", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *DistributorController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	if User_r.T_power > 2 || len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_Distributor_id := c.GetString("T_Distributor_id")
+
+	r, is := Distributor.Read_Distributor(T_Distributor_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if !Distributor.Delete_Distributor(r) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+	// TODO 删除经销商下的用户
+	System.Add_UserLogs_T(User_r.T_uuid, "经销商管理", "删除", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 管理员-全部列表-
+func (c *DistributorController) List_All() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权操作!"}
+		c.ServeJSON()
+		return
+	}
+	T_name := c.GetString("T_name")
+
+	var r_jsons lib.R_JSONS
+	r_jsons.List = Distributor.Read_Distributor_List_ALL(T_name)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 绑定模板
+func (c *DistributorController) BindVerifyTemplate() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_Distributor_id := c.GetString("T_Distributor_id")
+	T_VerifyTemplate_ids := c.GetString("T_VerifyTemplate_ids")
+	idList := lib.SplitStringSeparator(T_VerifyTemplate_ids, "|")
+
+	var list []Distributor.DistributorVerifyTemplate
+	for _, id := range idList {
+		verifyTemplate, is := VerifyTemplate.Read_VerifyTemplate(id)
+		if !is {
+			continue
+		}
+		list = append(list, Distributor.DistributorVerifyTemplate{
+			T_Distributor_id:         T_Distributor_id,
+			T_VerifyTemplate_id:      verifyTemplate.T_VerifyTemplate_id,
+			T_VerifyTemplateClass_id: verifyTemplate.T_class,
+		})
+	}
+	// 删除旧模版
+	Distributor.Delete_DistributorVerifyTemplate(T_Distributor_id)
+
+	// 绑定新模版
+	Id, is := Distributor.Add_DistributorVerifyTemplate(list)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版", "经销商绑定", list)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 绑定模版分类
+func (c *DistributorController) ReadVerifyTemplateClass() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	T_Distributor_id := c.GetString("T_Distributor_id")
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Distributor.Read_DistributorVerifyTemplateClass_List(T_Distributor_id)}
+	c.ServeJSON()
+	return
+}
+
+// 绑定模板
+func (c *DistributorController) ReadVerifyTemplate() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_Distributor_id := c.GetString("T_Distributor_id")
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	if T_class <= 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	var cnt int64
+	List, cnt := Distributor.Read_DistributorVerifyTemplate_List(T_Distributor_id, T_class, T_name, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+func (c *DistributorController) VerifyTemplateClass_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: VerifyTemplate.Read_VerifyTemplateClass_List_For_Distributor()}
+	c.ServeJSON()
+	return
+}

+ 95 - 0
controllers/ERP.go

@@ -0,0 +1,95 @@
+package controllers
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Distributor"
+	"ColdVerify_server/models/Task"
+)
+
+// 获取管理员 关联ERP
+func (c *AccountController) Account_List_All_For_ERP() {
+
+	PowerList := Account.Read_Power_List_ALL_1()
+	PowerMap := Account.UserPowerListToPowerMap(PowerList)
+	T_name := c.GetString("T_name")
+	var r_jsons lib.R_JSONS
+	r_jsons.List = Account.Read_Admin_List_ALL_Power("", T_name, PowerMap)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 获取公司列表
+func (c *UserController) User_List_All_For_ERP() {
+
+	T_name := c.GetString("T_name")
+	CreateDate := c.GetString("CreateDate")
+	if len(CreateDate) > 0 && !lib.IsDateStr(CreateDate) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "日期格式错误!"}
+		c.ServeJSON()
+		return
+	}
+	distributorList := Distributor.Read_Distributor_List_ALL("")
+	distributorMap := Distributor.DistributorListToMap(distributorList)
+	List, _ := Account.List_All_For_ERP(T_name, CreateDate, distributorMap)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: List}
+	c.ServeJSON()
+	return
+}
+
+func (c *TaskController) Task_List_All_For_ERP() {
+
+	start_time := c.GetString("T_reporting_pass_start_time")
+	end_time := c.GetString("T_reporting_pass_end_time")
+	if _, is := lib.TimeStrToTime(start_time); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "开始时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+	if _, is := lib.TimeStrToTime(end_time); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "结束时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+	List, _ := Task.Read_Task_List_For_ERP(start_time, end_time)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: List}
+	c.ServeJSON()
+	return
+}
+
+func (c *TaskController) Task_List2_All_For_ERP() {
+
+	T_type := c.GetString("T_type")
+	if T_type != "collection" && T_type != "reporting" {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "类型错误!"}
+		c.ServeJSON()
+		return
+	}
+	start_time := c.GetString("T_start_time")
+	end_time := c.GetString("T_end_time")
+	if _, is := lib.TimeStrToTime(start_time); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "开始时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+	if _, is := lib.TimeStrToTime(end_time); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "结束时间格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var List []Task.Task_
+	if T_type == "collection" {
+		List, _ = Task.Read_Task_List_For_ERP_By_Type(T_type, start_time, end_time)
+	}
+	if T_type == "reporting" {
+		List, _ = Task.Read_Task_List_For_ERP_By_Type(T_type, start_time, end_time)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: List}
+	c.ServeJSON()
+	return
+}

+ 642 - 0
controllers/InfoTemplate.go

@@ -0,0 +1,642 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/InfoCollection"
+	"ColdVerify_server/models/System"
+	"encoding/json"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type InfoTemplateController struct {
+	beego.Controller
+	User_r Account.Admin // 登陆的用户
+}
+
+func (c *InfoTemplateController) Prepare() {
+	GetCookie := c.Ctx.GetCookie("User_tokey")
+	GetString := c.GetString("User_tokey")
+	// 此接口单独从body获取token验证,此处不做验证
+	if strings.Contains(c.Ctx.Request.URL.Path, "/InfoTemplateMapData/Pu") {
+		return
+	}
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(GetCookie, GetString)
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 经销商只能访问列表接口,不能操作
+
+	//if len(User_r.T_Distributor_id) > 0 {
+	//	checkUrl := []string{"Add", "Up", "Del", "Copy"}
+	//	for _, v := range checkUrl {
+	//		if strings.Contains(c.Ctx.Request.URL.Path, v) {
+	//			c.Data["json"] = lib.JSONS{Code: 202, Msg: "没有操作权限!"}
+	//			c.ServeJSON()
+	//			return
+	//		}
+	//	}
+	//}
+
+	c.User_r = User_r
+}
+
+// 列表 -
+func (c *InfoTemplateController) List() {
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	if T_class <= 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	var cnt int64
+	List, cnt := InfoCollection.Read_InfoTemplate_List(T_class, T_name, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *InfoTemplateController) Add() {
+
+	T_name := c.GetString("T_name")
+	T_sort, _ := c.GetInt("T_sort")
+	T_class, _ := c.GetInt("T_class")
+
+	var_ := InfoCollection.InfoTemplate{
+		T_class: T_class,
+		T_name:  T_name,
+		T_sort:  T_sort,
+	}
+
+	Id, is := InfoCollection.Add_InfoTemplate(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *InfoTemplateController) Up() {
+
+	T_name := c.GetString("T_name")
+	T_sort, T_sort_err := c.GetInt("T_sort")
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+
+	r, is := InfoCollection.Read_InfoTemplate(T_InfoTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+
+	if T_sort_err == nil {
+		r.T_sort = T_sort
+	}
+
+	// .......
+	if !InfoCollection.Update_InfoTemplate(r, "T_name", "T_sort") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *InfoTemplateController) Del() {
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+
+	r, is := InfoCollection.Read_InfoTemplate(T_InfoTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if !InfoCollection.Delete_InfoTemplate(r) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	mapList, _ := InfoCollection.Read_InfoTemplateMap_List(T_InfoTemplate_id, 0, 0)
+	for _, v := range mapList {
+		if vtm, is := InfoCollection.Read_InfoTemplateMap(v.T_id); is {
+			InfoCollection.Delete_InfoTemplateMap(vtm)
+		}
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版", "删除", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+
+}
+
+// 复制-
+func (c *InfoTemplateController) Copy() {
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+	T_name := c.GetString("T_name")
+	r, is := InfoCollection.Read_InfoTemplate(T_InfoTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := InfoCollection.InfoTemplate{
+		T_class: r.T_class,
+		T_name:  T_name,
+		T_sort:  r.T_sort,
+	}
+
+	new_id, is := InfoCollection.Add_InfoTemplate(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	mapList, _ := InfoCollection.Read_InfoTemplateMap_List(T_InfoTemplate_id, 0, 0)
+	tempMap := make(map[string]struct{})
+	idList := make([]string, len(mapList))
+	// 生成mapList长度的T_id
+	for i := 0; i < len(mapList); i++ {
+		// 生成编号
+		rand_x := 0
+		T_id := ""
+		for true {
+			T_id = lib.GetRandstring(4, "", int64(rand_x))
+			_, is = InfoCollection.Read_InfoTemplateMap(T_id)
+			if !is {
+				if _, ok := tempMap[T_id]; !ok {
+					break
+				}
+			}
+			rand_x += 1
+		}
+		tempMap[T_id] = struct{}{}
+		idList[i] = T_id
+	}
+	mapInsertList := make([]InfoCollection.InfoTemplateMap, 0)
+	for i, v := range mapList {
+		vtm := InfoCollection.InfoTemplateMap{
+			T_id:              idList[i],
+			T_InfoTemplate_id: new_id,
+			T_name:            v.T_name,
+			T_text:            v.T_text,
+			T_label:           v.T_label,
+			T_sort:            v.T_sort,
+		}
+
+		mapInsertList = append(mapInsertList, vtm)
+	}
+
+	_, is = InfoCollection.Add_InfoTemplateMapMulti(mapInsertList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版", "复制", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: new_id}
+	c.ServeJSON()
+	return
+}
+
+/// -----------------------------------------------------------------------------
+
+// 标签列表 -
+func (c *InfoTemplateController) Map_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+
+	T_sort, _ := c.GetInt("T_sort")           // 排序
+	T_flow_sort, _ := c.GetInt("T_flow_sort") // 验证流程排序
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+
+	var cnt int64
+	List, cnt := InfoCollection.Read_InfoTemplateMap_List(T_InfoTemplate_id, T_sort, T_flow_sort)
+	r_jsons.List = List
+	r_jsons.Num = int(cnt)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 标签添加-
+func (c *InfoTemplateController) Map_Add() {
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+	T_name := c.GetString("T_name")
+	T_text := c.GetString("T_text")
+	T_label, _ := c.GetInt("T_label")
+	T_sort, _ := c.GetInt("T_sort")
+
+	var_ := InfoCollection.InfoTemplateMap{
+		T_InfoTemplate_id: T_InfoTemplate_id,
+		T_name:            T_name,
+		T_text:            T_text,
+		T_label:           T_label,
+		T_sort:            T_sort,
+	}
+
+	Id, is := InfoCollection.Add_InfoTemplateMap(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版标签", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 标签修改-
+func (c *InfoTemplateController) Map_Up() {
+
+	T_name := c.GetString("T_name")
+	T_text := c.GetString("T_text")
+	T_label, T_label_err := c.GetInt("T_label")
+	T_sort, T_sort_err := c.GetInt("T_sort")
+
+	T_id := c.GetString("T_id")
+
+	r, is := InfoCollection.Read_InfoTemplateMap(T_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(T_text) > 0 {
+		r.T_text = T_text
+	}
+	if T_label_err == nil {
+		r.T_label = T_label
+	}
+	if T_sort_err == nil {
+		r.T_sort = T_sort
+	}
+
+	if !InfoCollection.Update_InfoTemplateMap(r, "T_name", "T_label", "T_text", "T_sort") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版标签", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 标签删除-
+func (c *InfoTemplateController) Map_Del() {
+
+	T_id := c.GetString("T_id")
+
+	if r, is := InfoCollection.Read_InfoTemplateMap(T_id); is {
+		if !InfoCollection.Delete_InfoTemplateMap(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集信息采集模版标签", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+/// -----------------------------------------------------------------------------
+
+// 标签数据列表 -
+func (c *InfoTemplateController) Map_Data_List() {
+
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	_, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_InfoCollection_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Map_List := InfoCollection.Read_InfoTemplateMap_List_For_Data(T_InfoTemplate_id)
+	Data := InfoCollection.Read_InfoTemplateMapData_List(T_InfoCollection_id, T_InfoTemplate_id, Map_List)
+
+	type JSONS struct {
+		//必须的大写开头
+		Code int16
+		Msg  string
+		Data interface{} // 泛型
+	}
+
+	c.Data["json"] = JSONS{Code: 200, Msg: "ok!", Data: Data}
+	c.ServeJSON()
+	return
+}
+
+// 添加标签数据
+func (c *InfoTemplateController) Map_Data_Pu() {
+	//验证登录 User_is, User_r
+
+	type RequestBody struct {
+		User_tokey          string
+		T_InfoCollection_id string
+		T_InfoTemplate_id   string
+		InfoTemplateMapData []InfoCollection.InfoTemplateMapData_R
+	}
+
+	var body RequestBody
+	data := c.Ctx.Input.RequestBody
+	err := json.Unmarshal(data, &body)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "json返序列化失败:" + err.Error()}
+		c.ServeJSON()
+	}
+
+	User_r, User_is := Account.Verification_Admin(body.User_tokey, "")
+	if !User_is {
+		System.Add_UserLogs_T(User_r.T_uuid, "信息采集模版标签数据", "未登录-保存", body)
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	infoCollection, is := InfoCollection.Read_InfoCollection(body.T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_InfoCollection_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 如果信息采集开始时间为空,则设置为当前时间
+	if len(infoCollection.T_start_time) == 0 {
+		infoCollection.T_start_time = time.Now().Format("2006-01-02 15:04:05")
+		if !InfoCollection.Update_InfoCollection(infoCollection, "T_start_time") {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改信息采集开始时间失败!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	MapDataList := make([]InfoCollection.InfoTemplateMapData, 0)
+	for _, v := range body.InfoTemplateMapData {
+		val := InfoCollection.InfoTemplateMapData{
+			T_InfoCollection_id:  body.T_InfoCollection_id,
+			T_InfoTemplate_id:    body.T_InfoTemplate_id,
+			T_InfoTemplateMap_id: v.T_InfoTemplateMap_id,
+			T_value:              v.T_value,
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	ids, is := InfoCollection.AddOrUpdate_InfoTemplateMapData(MapDataList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集模版标签数据", "保存", body)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+func (c *InfoTemplateController) Map_Data_Copy() {
+
+	T_copy_InfoCollection_id := c.GetString("T_copy_InfoCollection_id")
+	copy_InfoCollection, is := InfoCollection.Read_InfoCollection(T_copy_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_copy_InfoCollection_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_paste_InfoCollection_id := c.GetString("T_paste_InfoCollection_id")
+	paste_InfoCollection, is := InfoCollection.Read_InfoCollection(T_paste_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_paste_InfoCollection_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if copy_InfoCollection.T_InfoTemplate_id != paste_InfoCollection.T_InfoTemplate_id {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "仅支持相同信息采集模版间复制!"}
+		c.ServeJSON()
+		return
+	}
+
+	list := InfoCollection.Read_MapData_List(T_copy_InfoCollection_id, copy_InfoCollection.T_InfoTemplate_id)
+
+	MapDataList := make([]InfoCollection.InfoTemplateMapData, 0)
+	for _, v := range list {
+		val := InfoCollection.InfoTemplateMapData{
+			T_InfoCollection_id:  paste_InfoCollection.T_InfoCollection_id,
+			T_InfoTemplate_id:    paste_InfoCollection.T_InfoTemplate_id,
+			T_InfoTemplateMap_id: v.T_InfoTemplateMap_id,
+			T_value:              v.T_value,
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	var ids []int64
+	ids, is = InfoCollection.AddOrUpdate_InfoTemplateMapData(MapDataList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集模版标签数据", "复制", MapDataList)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+func (c *InfoTemplateController) Class_List() {
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: InfoCollection.Read_InfoTemplateClass_List()}
+	c.ServeJSON()
+	return
+}
+func (c *InfoTemplateController) Class_Add() {
+
+	T_name := c.GetString("T_name")
+	T_fid, _ := c.GetInt("T_fid")
+
+	var_ := InfoCollection.InfoTemplateClass{
+		T_name:  T_name,
+		T_fid:   T_fid,
+		T_State: 1,
+	}
+
+	Id, err := InfoCollection.Add_InfoTemplateClass(var_)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "添加失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集模版分类", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+func (c *InfoTemplateController) Class_Up() {
+
+	T_id, _ := c.GetInt("T_id")
+	T_name := c.GetString("T_name")
+
+	R_InfoTemplateToolClass, err := InfoCollection.Read_InfoTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_name) > 0 {
+		R_InfoTemplateToolClass.T_name = T_name
+	}
+
+	if is := InfoCollection.Update_InfoTemplateClass(R_InfoTemplateToolClass, "T_name"); !is {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "修改失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集模版分类", "修改", R_InfoTemplateToolClass)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+func (c *InfoTemplateController) Class_Del() {
+
+	T_id, _ := c.GetInt("T_id")
+	R_InfoTemplateToolClass, err := InfoCollection.Read_InfoTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	ids := InfoCollection.ReadInfoTemplateClassIds_T_path(R_InfoTemplateToolClass.T_path)
+
+	if is := InfoCollection.Delete_InfoTemplateClass_ByIds(ids); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs(c.User_r.T_uuid, "信息采集模版分类", "删除", strconv.Itoa(T_id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 复制信息采集-分类-标签
+func (c *InfoTemplateController) Class_Copy() {
+
+	T_id, _ := c.GetInt("T_id") // 要复制的信息采集分类id
+	T_name := c.GetString("T_name")
+
+	// 查询要复制的信息采集分类id
+	R_InfoTemplateClass, err := InfoCollection.Read_InfoTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+	if len(T_name) > 0 && T_name != R_InfoTemplateClass.T_name {
+		R_InfoTemplateClass.T_name = T_name
+	} else {
+		R_InfoTemplateClass.T_name = R_InfoTemplateClass.T_name + "_副本"
+	}
+
+	_, err = InfoCollection.CopyInfoTemplateClassTree(R_InfoTemplateClass.T_path, R_InfoTemplateClass.T_fid, R_InfoTemplateClass.T_name)
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制信息采集模版分类失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.User_r.T_uuid, "信息采集模版分类", "复制", T_id)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}

+ 86 - 0
controllers/Logs.go

@@ -0,0 +1,86 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/System"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type LogsController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *LogsController) List() {
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	var log_jsons lib.LOG_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	Class_1 := c.GetString("Class_1")
+
+	var cnt int64
+	List, cnt := System.Read_Logs_ALL(page, page_z, Class_1)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	log_jsons.Class_1 = Class_1
+	log_jsons.Class_List = System.Read_Logs_Class()
+	log_jsons.List = List
+	log_jsons.Page = page
+	log_jsons.Page_size = int(page_size)
+	log_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	log_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: log_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *LogsController) UserLogs() {
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	var log_jsons lib.LOG_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	Class_1 := c.GetString("Class_1")
+
+	var cnt int64
+	List, cnt := System.Read_UserLogs_ALL(page, page_z, Class_1)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	log_jsons.Class_1 = Class_1
+	log_jsons.Class_List = System.Read_UserLogs_Class()
+	log_jsons.List = List
+	log_jsons.Page = page
+	log_jsons.Page_size = int(page_size)
+	log_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	log_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: log_jsons}
+	c.ServeJSON()
+	return
+}

+ 79 - 0
controllers/News.go

@@ -0,0 +1,79 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/System"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type NewsController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *NewsController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	// 分页参数 初始化
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	// 查询
+	T_title := c.GetString("T_title")
+	T_Tag, _ := c.GetInt("T_Tag")
+	T_app, _ := c.GetInt("T_app") // 1-app 0-系统
+	List, cnt := System.Read_News_List(User_r.T_uuid, T_title, T_Tag, T_app, page, page_z)
+	var r_jsons lib.R_JSONS
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+func (c *NewsController) See() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	Id, _ := c.GetInt("Id")
+
+	if Id == 0 {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	if err := System.Update_News_Tag(Id, User_r.T_uuid); err != nil {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+
+}

+ 3459 - 0
controllers/Task.go

@@ -0,0 +1,3459 @@
+package controllers
+
+import (
+	"ColdVerify_server/Nats/NatsServer"
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/lib/wx"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/InfoCollection"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"ColdVerify_server/models/VerifyTemplate"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"image/color"
+	"math"
+	"os"
+	"os/exec"
+	"strings"
+	"sync"
+	"time"
+
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/google/uuid"
+	"github.com/xuri/excelize/v2"
+	"gonum.org/v1/plot"
+	"gonum.org/v1/plot/plotter"
+	"gonum.org/v1/plot/vg"
+	"gonum.org/v1/plot/vg/draw"
+)
+
+type TaskController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *TaskController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_company := c.GetString("T_company") // 公司名称
+	T_uuid := c.GetString("T_uuid")
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+
+	T_scheme := c.GetString("T_scheme")                     // 实施方案 负责人UUID
+	T_collection := c.GetString("T_collection")             // 数据采集 负责人UUID
+	T_reporting := c.GetString("T_reporting")               // 报告编写 负责人UUID
+	T_delivery := c.GetString("T_delivery")                 // 交付审核 负责人UUID
+	T_scheme_state := c.GetString("T_scheme_state")         // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state := c.GetString("T_collection_state") // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state := c.GetString("T_reporting_state")   // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_delivery_state := c.GetString("T_delivery_state")     // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state := c.GetString("T_marking_state")       // 验证标识 状态 0 未完成 1 已完成
+	CreateTime := c.GetString("CreateTime")                 // 任务添加时间
+
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var T_company_list []string
+	if len(T_company) > 0 {
+		T_company_list = Account.Read_User_T_uuid_ListByT_name(T_company)
+	}
+
+	var T_admin string
+	if User_r.T_power > 2 {
+		T_admin = User_r.T_uuid
+	}
+	// 经销商下管理员可查看自己经销商下所有的任务
+	// 经销商下其他角色只能查看分配给自己的任务
+	if len(User_r.T_Distributor_id) > 0 && User_r.T_power <= 2 {
+		T_admin = ""
+	}
+
+	var cnt int
+
+	List, cnt := Task.Read_Task_List(User_r.T_Distributor_id, T_uuid, T_admin, T_name, T_InfoCollection_id, T_scheme, T_collection, T_reporting, T_delivery,
+		T_scheme_state, T_collection_state, T_reporting_state, T_delivery_state, T_marking_state,
+		T_company_list, UserMap, AdminMap, CreateTime, page, page_z)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 报告统计
+func (c *TaskController) Stat() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_company := c.GetString("T_company") // 公司名称
+	T_uuid := c.GetString("T_uuid")
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+
+	T_project := c.GetString("T_project")                   // 项目 负责人UUID
+	T_scheme := c.GetString("T_scheme")                     // 实施方案 负责人UUID
+	T_collection := c.GetString("T_collection")             // 数据采集 负责人UUID
+	T_reporting := c.GetString("T_reporting")               // 报告编写 负责人UUID
+	T_delivery := c.GetString("T_delivery")                 // 交付审核 负责人UUID
+	T_scheme_state := c.GetString("T_scheme_state")         // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state := c.GetString("T_collection_state") // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state := c.GetString("T_reporting_state")   // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_delivery_state := c.GetString("T_delivery_state")     // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state := c.GetString("T_marking_state")       // 验证标识 状态 0 未完成 1 已完成
+	CreateTime := c.GetString("CreateTime")                 // 任务添加时间
+
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var T_company_list []string
+	if len(T_company) > 0 {
+		T_company_list = Account.Read_User_T_uuid_ListByT_name(T_company)
+	}
+
+	var T_admin string
+	if User_r.T_power > 2 {
+		T_admin = User_r.T_uuid
+	}
+
+	var cnt int
+	List, cnt := Task.Read_Task_Stat(User_r.T_Distributor_id, T_uuid, T_admin, T_name, T_InfoCollection_id, T_project, T_scheme, T_collection, T_reporting, T_delivery,
+		T_scheme_state, T_collection_state, T_reporting_state, T_delivery_state, T_marking_state,
+		T_company_list, UserMap, AdminMap, CreateTime, page, page_z)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 报告统计 - 导出excel
+func (c *TaskController) Stat_Excel() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_company := c.GetString("T_company") // 公司名称
+	T_uuid := c.GetString("T_uuid")
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+
+	T_project := c.GetString("T_project")                   // 项目 负责人UUID
+	T_scheme := c.GetString("T_scheme")                     // 实施方案 负责人UUID
+	T_collection := c.GetString("T_collection")             // 数据采集 负责人UUID
+	T_reporting := c.GetString("T_reporting")               // 报告编写 负责人UUID
+	T_delivery := c.GetString("T_delivery")                 // 交付审核 负责人UUID
+	T_scheme_state := c.GetString("T_scheme_state")         // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state := c.GetString("T_collection_state") // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state := c.GetString("T_reporting_state")   // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_delivery_state := c.GetString("T_delivery_state")     // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state := c.GetString("T_marking_state")       // 验证标识 状态 0 未完成 1 已完成
+	CreateTime := c.GetString("CreateTime")                 // 任务添加时间
+
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var T_company_list []string
+	if len(T_company) > 0 {
+		T_company_list = Account.Read_User_T_uuid_ListByT_name(T_company)
+	}
+
+	var T_admin string
+	if User_r.T_power > 2 {
+		T_admin = User_r.T_uuid
+	}
+
+	List, _ := Task.Read_Task_Stat(User_r.T_Distributor_id, T_uuid, T_admin, T_name, T_InfoCollection_id, T_project, T_scheme, T_collection, T_reporting, T_delivery,
+		T_scheme_state, T_collection_state, T_reporting_state, T_delivery_state, T_marking_state,
+		T_company_list, UserMap, AdminMap, CreateTime, 0, 9999)
+
+	f := excelize.NewFile() // 设置单元格的值
+	line := 1
+	// 这里设置表头
+	f.MergeCell("Sheet1", fmt.Sprintf("A%d", line), fmt.Sprintf("A%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("B%d", line), fmt.Sprintf("B%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("C%d", line), fmt.Sprintf("C%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("D%d", line), fmt.Sprintf("D%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("E%d", line), fmt.Sprintf("E%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("F%d", line), fmt.Sprintf("F%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("G%d", line), fmt.Sprintf("G%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("H%d", line), fmt.Sprintf("H%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("I%d", line), fmt.Sprintf("I%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("J%d", line), fmt.Sprintf("J%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("K%d", line), fmt.Sprintf("K%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("L%d", line), fmt.Sprintf("L%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("M%d", line), fmt.Sprintf("M%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("N%d", line), fmt.Sprintf("N%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("O%d", line), fmt.Sprintf("O%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("P%d", line), fmt.Sprintf("P%d", line+1))
+	f.MergeCell("Sheet1", fmt.Sprintf("Q%d", line), fmt.Sprintf("U%d", line))
+	f.MergeCell("Sheet1", fmt.Sprintf("V%d", line), fmt.Sprintf("AA%d", line))
+	f.MergeCell("Sheet1", fmt.Sprintf("AB%d", line), fmt.Sprintf("AG%d", line))
+	f.MergeCell("Sheet1", fmt.Sprintf("AH%d", line), fmt.Sprintf("AM%d", line))
+
+	f.SetCellValue("Sheet1", fmt.Sprintf("Q%d", line), "信息表")
+	f.SetCellValue("Sheet1", fmt.Sprintf("V%d", line), "方案")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AB%d", line), "实施")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AH%d", line), "报告")
+
+	f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), "序号")
+	f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), "公司名称")
+	f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), "报告名称")
+	f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), "项目负责人")
+	f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), "地区")
+	f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), "类别")
+	f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), "设备类型")
+	f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), "规格/容积")
+	f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), "验证类型")
+	f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), "标的物名称")
+	f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), "验证温度范围")
+	f.SetCellValue("Sheet1", fmt.Sprintf("L%d", line), "报告编号")
+	f.SetCellValue("Sheet1", fmt.Sprintf("M%d", line), "项目开始时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("N%d", line), "项目用时")
+	f.SetCellValue("Sheet1", fmt.Sprintf("O%d", line), "驳回次数")
+	f.SetCellValue("Sheet1", fmt.Sprintf("P%d", line), "回款")
+	f.SetCellValue("Sheet1", fmt.Sprintf("Q%d", line+1), "编写人")
+	f.SetCellValue("Sheet1", fmt.Sprintf("R%d", line+1), "状态")
+	f.SetCellValue("Sheet1", fmt.Sprintf("S%d", line+1), "开始时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("T%d", line+1), "退回次数")
+	f.SetCellValue("Sheet1", fmt.Sprintf("U%d", line+1), "所需时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("V%d", line+1), "编写人")
+	f.SetCellValue("Sheet1", fmt.Sprintf("W%d", line+1), "状态")
+	f.SetCellValue("Sheet1", fmt.Sprintf("X%d", line+1), "开始时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("Y%d", line+1), "退回次数")
+	f.SetCellValue("Sheet1", fmt.Sprintf("Z%d", line+1), "所需时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AA%d", line+1), "超时时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AB%d", line+1), "编写人")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AC%d", line+1), "状态")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AD%d", line+1), "开始时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AE%d", line+1), "退回次数")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AF%d", line+1), "所需时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AG%d", line+1), "超时时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AH%d", line+1), "编写人")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AI%d", line+1), "状态")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AJ%d", line+1), "开始时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AK%d", line+1), "退回次数")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AL%d", line+1), "所需时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AM%d", line+1), "超时时间")
+	f.SetCellValue("Sheet1", fmt.Sprintf("AN%d", line+1), "领导备注")
+
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 7)
+	f.SetColWidth("Sheet1", "B", "B", 20)
+	f.SetColWidth("Sheet1", "C", "C", 10)
+	f.SetColWidth("Sheet1", "D", "D", 10)
+	f.SetColWidth("Sheet1", "E", "E", 12)
+	f.SetColWidth("Sheet1", "F", "F", 8)
+	f.SetColWidth("Sheet1", "G", "G", 12)
+	f.SetColWidth("Sheet1", "H", "H", 14)
+	f.SetColWidth("Sheet1", "I", "I", 12)
+	f.SetColWidth("Sheet1", "J", "J", 12)
+	f.SetColWidth("Sheet1", "K", "K", 12)
+	f.SetColWidth("Sheet1", "L", "L", 12)
+	f.SetColWidth("Sheet1", "M", "M", 12)
+	f.SetColWidth("Sheet1", "N", "N", 12)
+	f.SetColWidth("Sheet1", "O", "O", 10)
+	f.SetColWidth("Sheet1", "P", "P", 8)
+	f.SetColWidth("Sheet1", "Q", "Q", 8)
+	f.SetColWidth("Sheet1", "R", "R", 8)
+	f.SetColWidth("Sheet1", "S", "S", 12)
+	f.SetColWidth("Sheet1", "T", "T", 10)
+	f.SetColWidth("Sheet1", "U", "U", 10)
+	f.SetColWidth("Sheet1", "V", "V", 8)
+	f.SetColWidth("Sheet1", "W", "W", 8)
+	f.SetColWidth("Sheet1", "X", "X", 12)
+	f.SetColWidth("Sheet1", "Y", "Y", 10)
+	f.SetColWidth("Sheet1", "Z", "Z", 12)
+	f.SetColWidth("Sheet1", "AA", "AA", 12)
+	f.SetColWidth("Sheet1", "AB", "AB", 8)
+	f.SetColWidth("Sheet1", "AC", "AC", 8)
+	f.SetColWidth("Sheet1", "AD", "AD", 12)
+	f.SetColWidth("Sheet1", "AE", "AE", 10)
+	f.SetColWidth("Sheet1", "AF", "AF", 12)
+	f.SetColWidth("Sheet1", "AG", "AG", 12)
+	f.SetColWidth("Sheet1", "AG", "AG", 10)
+	f.SetColWidth("Sheet1", "AH", "AH", 8)
+	f.SetColWidth("Sheet1", "AI", "AI", 8)
+	f.SetColWidth("Sheet1", "AJ", "AJ", 10)
+	f.SetColWidth("Sheet1", "AK", "AK", 12)
+	f.SetColWidth("Sheet1", "AL", "AL", 12)
+	f.SetColWidth("Sheet1", "AM", "AM", 12)
+
+	Style1, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+
+	f.SetCellStyle("Sheet1", "A1", "AM2", Style1)
+	f.SetRowHeight("Sheet1", 1, 25)
+	f.SetRowHeight("Sheet1", 2, 25)
+
+	line += 1
+
+	// 循环写入数据
+	for i, v := range List {
+		line++
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.T_user_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.T_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.T_project_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), fmt.Sprintf("%s-%s-%s", v.T_province, v.T_city, v.T_district))
+		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.T_category)
+		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.T_device_type)
+		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.T_volume)
+		f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.T_verify_type)
+		f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.T_subject_matter)
+		f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.T_temp_range)
+		f.SetCellValue("Sheet1", fmt.Sprintf("L%d", line), fmt.Sprintf("%s-%s", v.T_report_type, v.T_report_number))
+		f.SetCellValue("Sheet1", fmt.Sprintf("M%d", line), v.T_start_time)
+		f.SetCellValue("Sheet1", fmt.Sprintf("N%d", line), v.T_time_interval)
+		f.SetCellValue("Sheet1", fmt.Sprintf("O%d", line), v.T_reject_times)
+		returnedMoney := "否"
+		if v.InfoCollection.T_status == InfoCollection.InfoCollectionStatusReturnedMoney {
+			returnedMoney = "是"
+		}
+		f.SetCellValue("Sheet1", fmt.Sprintf("P%d", line), returnedMoney)
+		f.SetCellValue("Sheet1", fmt.Sprintf("Q%d", line), v.InfoCollection.T_submit_uuid_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("R%d", line), InfoCollection.InfoCollectionStatusMap[v.InfoCollection.T_State])
+		f.SetCellValue("Sheet1", fmt.Sprintf("S%d", line), v.InfoCollection.T_start_time)
+		f.SetCellValue("Sheet1", fmt.Sprintf("T%d", line), v.InfoCollection.T_return_times)
+		f.SetCellValue("Sheet1", fmt.Sprintf("U%d", line), v.InfoCollection.T_time_interval)
+		f.SetCellValue("Sheet1", fmt.Sprintf("V%d", line), v.T_scheme_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("W%d", line), Task.TaskSchemeStateMap[v.T_scheme_state])
+		f.SetCellValue("Sheet1", fmt.Sprintf("X%d", line), v.T_scheme_start_time)
+		f.SetCellValue("Sheet1", fmt.Sprintf("Y%d", line), v.T_scheme_return_times)
+		f.SetCellValue("Sheet1", fmt.Sprintf("Z%d", line), v.T_scheme_time_interval)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AA%d", line), v.T_scheme_overtime)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AB%d", line), v.T_collection_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AC%d", line), Task.TaskCollectionStateMap[v.T_collection_state])
+		f.SetCellValue("Sheet1", fmt.Sprintf("AD%d", line), v.T_collection_start_time)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AE%d", line), v.T_collection_return_times)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AF%d", line), v.T_collection_time_interval)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AG%d", line), v.T_collection_overtime)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AH%d", line), v.T_reporting_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AI%d", line), Task.TaskReportingStateMap[v.T_reporting_state])
+		f.SetCellValue("Sheet1", fmt.Sprintf("AJ%d", line), v.T_reporting_start_time)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AK%d", line), v.T_reporting_return_times)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AL%d", line), v.T_reporting_time_interval)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AM%d", line), v.T_reporting_overtime)
+		f.SetCellValue("Sheet1", fmt.Sprintf("AN%d", line), v.T_record)
+	}
+
+	Style2, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 10, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+	f.SetCellStyle("Sheet1", "A2", fmt.Sprintf("AM%d", line), Style2)
+
+	StyleBlueFill, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+			Fill: excelize.Fill{Type: "pattern", Color: []string{"#DEE5F5"}, Pattern: 1},
+		})
+
+	// 粉色填充
+	StylePinkFill, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+			Fill: excelize.Fill{Type: "pattern", Color: []string{"#FBDFE2"}, Pattern: 1},
+		})
+
+	StyleOrangeFill, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+			Fill: excelize.Fill{Type: "pattern", Color: []string{"#FCE7D8"}, Pattern: 1},
+		})
+	StyleYellowFill, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+			Fill: excelize.Fill{Type: "pattern", Color: []string{"#FFF5D0"}, Pattern: 1},
+		})
+	StyleGreenFill, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+			Fill: excelize.Fill{Type: "pattern", Color: []string{"#E7F4DE"}, Pattern: 1},
+		})
+
+	f.SetCellStyle("Sheet1", "A1", "AM2", StyleBlueFill)
+	f.SetCellStyle("Sheet1", "Q1", "U1", StylePinkFill)
+	f.SetCellStyle("Sheet1", "V1", "AA1", StyleOrangeFill)
+	f.SetCellStyle("Sheet1", "AB1", "AG1", StyleYellowFill)
+	f.SetCellStyle("Sheet1", "AH1", "AM1", StyleGreenFill)
+	f.SetCellStyle("Sheet1", "AN1", "AN2", StyleBlueFill)
+
+	// 冻结1-2行
+	f.SetPanes("Sheet1", &excelize.Panes{
+		Freeze:      true,
+		Split:       false,
+		XSplit:      3,
+		YSplit:      2,
+		TopLeftCell: "A1",
+		ActivePane:  "topRight",
+	})
+
+	lib.Create_Dir("./ofile")
+
+	timeStr := time.Now().Format("20060102150405")
+	// 保存文件
+	if err := f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	if !lib.Pload_qiniu("ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx") {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "oss!"}
+		c.ServeJSON()
+		return
+	}
+	//删除目录
+	err := os.Remove("ofile/" + timeStr + ".xlsx")
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + timeStr + ".xlsx"}
+	c.ServeJSON()
+	return
+}
+
+// 获取任务负责人列表
+func (c *TaskController) GetTaskUserList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_type := c.GetString("T_type") // T_project项目 T_scheme方案 T_collection数据采集 T_reporting报告
+
+	list := Task.Get_Task_UserList(T_type)
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var User_list []Account.Admin_R
+	for _, v := range list {
+		if len(v) == 0 {
+			continue
+		}
+		User_list = append(User_list, Account.Admin_R{T_uuid: v, T_name: AdminMap[v]})
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: User_list}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TaskController) UserTaskList() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var cnt int
+	List, cnt := Task.Read_UserTask_List(User_r.T_uuid, T_name, UserMap, AdminMap, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 获取-
+func (c *TaskController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	// 添加浏览量
+	_ = Task.Add_Task_Visit(r)
+	r.T_Visit += 1
+	userMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	adminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Task.TaskToTask_Stat(r, userMap, adminMap)}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskController) Add() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	dc := Device.DeviceClass{
+		T_uuid:  User_r.T_uuid,
+		T_State: 1,
+	}
+	T_class_id, is := Device.Add_DeviceClass(dc)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加分类失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "添加", dc)
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id") // 信息采集id
+
+	T_name := c.GetString("T_name")
+	T_uuid := c.GetString("T_uuid") // 用户uuid
+	T_VerifyTemplate_class := c.GetString("T_VerifyTemplate_class")
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_deadline := c.GetString("T_deadline")
+	T_scheme := c.GetString("T_scheme")
+	T_collection := c.GetString("T_collection")
+	T_reporting := c.GetString("T_reporting")
+	T_delivery := c.GetString("T_delivery")
+
+	T_project := c.GetString("T_project")                 // 项目 负责人UUID
+	T_province := c.GetString("T_province")               // 省
+	T_city := c.GetString("T_city")                       // 市
+	T_district := c.GetString("T_district")               // 区
+	T_province_code := c.GetString("T_province_code")     // 省 code
+	T_city_code := c.GetString("T_city_code")             // 市 code
+	T_district_code := c.GetString("T_district_code")     // 区 code
+	T_category := c.GetString("T_category")               // 类别
+	T_device_type := c.GetString("T_device_type")         // 设备类型
+	T_volume := c.GetString("T_volume")                   // 规格/容积
+	T_verify_type := c.GetString("T_verify_type")         // 验证类型
+	T_subject_matter := c.GetString("T_subject_matter")   // 标的物名称
+	T_temp_range := c.GetString("T_temp_range")           // 验证温度范围
+	T_report_number := c.GetString("T_report_number")     // 报告编号
+	T_report_type := c.GetString("T_report_type")         // 报告类型
+	T_device_quantity, _ := c.GetInt("T_device_quantity") // 终端数量
+	T_cnas, _ := c.GetInt("T_cnas")                       // cnas实验室
+
+	// 查询信息采集信息
+	infoCollection, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 查询信息采集信息
+	user, is := Account.Read_User(T_uuid)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_uuid 错误!"}
+		c.ServeJSON()
+		return
+	}
+	var_ := Task.Task{
+		T_Distributor_id:       user.T_Distributor_id,
+		T_InfoCollection_id:    T_InfoCollection_id,
+		T_InfoTemplate_id:      infoCollection.T_InfoTemplate_id,
+		T_start_time:           infoCollection.T_start_time, // 项目开始时间使用信息采集开始时间
+		T_class:                int(T_class_id),
+		T_uuid:                 T_uuid,
+		T_name:                 T_name,
+		T_VerifyTemplate_class: T_VerifyTemplate_class,
+		T_VerifyTemplate_id:    T_VerifyTemplate_id,
+		T_deadline:             T_deadline,
+		T_scheme:               T_scheme,
+		T_collection:           T_collection,
+		T_reporting:            T_reporting,
+		T_delivery:             T_delivery,
+		T_Show:                 1,
+		T_State:                1,
+
+		T_project:         T_project,
+		T_province:        T_province,
+		T_city:            T_city,
+		T_district:        T_district,
+		T_province_code:   T_province_code,
+		T_city_code:       T_city_code,
+		T_district_code:   T_district_code,
+		T_category:        T_category,
+		T_device_type:     T_device_type,
+		T_volume:          T_volume,
+		T_verify_type:     T_verify_type,
+		T_subject_matter:  T_subject_matter,
+		T_temp_range:      T_temp_range,
+		T_report_number:   T_report_number,
+		T_report_type:     T_report_type,
+		T_device_quantity: T_device_quantity,
+		T_cnas:            T_cnas,
+	}
+	if T_report_number != "/" {
+		_, exist := Task.Read_TaskbyT_report_number(T_report_number)
+		if exist {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "报告编号已存在!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	T_task_id, is := Task.Add_Task(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	NatsServer.Create_Local_Table(T_task_id)
+	Task.Redis_Task_T_report_number_DelK(T_report_number) // 删除redis内的任务编号
+	// 通知
+	_, company_r := Account.Read_User_ByT_uuid(var_.T_uuid)
+	go wx.WxSend(var_.T_scheme, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_collection, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_reporting, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_delivery, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+
+	// 同步信息采集表 --------
+	InfoCollection_Map_List := InfoCollection.Read_InfoTemplateMap_List_For_Data(var_.T_InfoTemplate_id)
+	InfoCollection_Data := InfoCollection.Read_InfoTemplateMapData_List(var_.T_InfoCollection_id, var_.T_InfoTemplate_id, InfoCollection_Map_List)
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(var_.T_VerifyTemplate_id, 0, 0)
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(0, T_task_id, var_.T_VerifyTemplate_id, Map_List)
+
+	InfoCollectionDataMap := make(map[string]string)
+	for _, data := range InfoCollection_Data {
+		InfoCollectionDataMap[data.T_name] = data.T_value
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range Data {
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if InfoCollectionDataMap[v.T_name] == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               v.T_source,
+			T_task_id:              T_task_id,
+			T_VerifyTemplate_id:    var_.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: InfoCollectionDataMap[v.T_name],
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	_, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData(MapDataList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "同步信息采集表失败"}
+		c.ServeJSON()
+		return
+	}
+	// 同步信息采集表结束 --------
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "添加", var_)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 接收信息采集
+func (c *TaskController) ReceiptInfoCollection() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	// 修改信息采集状态为已接收
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	//T_status,_ := c.GetInt("T_status")
+	infoCollection, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if infoCollection.T_status != InfoCollection.InfoCollectionStatusSubmitted && infoCollection.T_status != InfoCollection.InfoCollectionStatusReceipt {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("当前状态为%s,禁止接收!", InfoCollection.InfoCollectionStatusMap[infoCollection.T_status])}
+		c.ServeJSON()
+		return
+	}
+	//infoCollection.T_status = InfoCollection.InfoCollectionStatusReceipt
+	//if len(infoCollection.T_end_time) == 0 {
+	//	infoCollection.T_end_time = time.Now().Format("2006-01-02 15:04:05")
+	//	infoCollection.T_time_interval, _ = lib.MinutesDifference(infoCollection.T_start_time, infoCollection.T_end_time)
+	//}
+
+	//if !InfoCollection.Update_InfoCollection(infoCollection, "T_status", "T_end_time", "T_time_interval") {
+	infoCollection.T_status = 3 // 已接收
+	if !InfoCollection.Update_InfoCollection(infoCollection, "T_status") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "接收信息采集", infoCollection)
+
+	//if T_status == InfoCollection.InfoCollectionStatusReturn{
+	//	// 通知 报告负责人审核
+	//	_, company_r := Account.Read_User_ByT_uuid(infoCollection.T_uuid)
+	//	System.Add_News(conf.VdelUuid, fmt.Sprintf("【%s-%s】信息采集 已退回", company_r.T_name, infoCollection.T_name), "")
+	//	go wx.WxSend(conf.VdelUuid, fmt.Sprintf("【%s-%s】信息采集 已退回", company_r.T_name, infoCollection.T_name))
+	//
+	//}
+
+	// 修改任务管理实施方案开始时间
+	//T_task_id := c.GetString("T_task_id")
+	//task, is := Task.Read_Task(T_task_id)
+	//if !is {
+	//	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+
+	// 添加任务操作日志
+	//Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "接收信息采集", task)
+	//System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "接收信息采集", task)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskController) AddData_Tool() {
+	T_uuid := "3e84dda9-9eec-42b9-9350-0894262fc8a1" // 用户uuid
+
+	T_name := c.GetString("T_name")
+	T_task_id := c.GetString("T_task_id")
+	T_task_id = strings.ToLower(T_task_id)
+
+	r, _ := Task.Read_Task(T_task_id)
+	if r.T_collection_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "数据采集中..."}
+		c.ServeJSON()
+		return
+	}
+	if r.Id > 0 {
+		// 同步1.0数据
+		NatsServer.Sync1_TaskData(T_task_id)
+
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_task_id}
+		c.ServeJSON()
+		return
+	}
+
+	dc := Device.DeviceClass{
+		T_uuid:  T_uuid,
+		T_State: 1,
+	}
+	T_class_id, is := Device.Add_DeviceClass(dc)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加分类失败!"}
+		c.ServeJSON()
+		return
+	}
+	var_ := Task.Task{
+		T_task_id:          T_task_id,
+		T_class:            int(T_class_id),
+		T_uuid:             T_uuid,
+		T_name:             T_name,
+		T_Show:             1,
+		T_State:            1,
+		T_collection_state: 2,
+	}
+
+	_, is = Task.Add_Task_Tool(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 创建本地表
+	NatsServer.Create_Local_Table(T_task_id)
+	// 同步1.0数据
+	NatsServer.Sync1_TaskData(T_task_id)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 修改采集状态-
+func (c *TaskController) UpCollectionState() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_collection_state, _ := c.GetInt("T_collection_state")
+	T_reason := c.GetString("T_reason") // 退回原因
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	r.T_collection_state = T_collection_state
+	clos := make([]string, 0)
+	clos = append(clos, "T_collection_state")
+
+	if T_collection_state == Task.TaskCollectionStateReturn {
+		r.T_collection_return_times += 1
+		clos = append(clos, "T_collection_return_times")
+	}
+
+	if T_collection_state == Task.TaskCollectionStateSubmitted ||
+		T_collection_state == Task.TaskCollectionStateReturn ||
+		T_collection_state == Task.TaskCollectionStatePass {
+		// 添加已提交状态验证报告记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_collection_audit_record, "", User_r.T_uuid, T_collection_state, T_reason, "")
+		if err != nil {
+			return
+		}
+		r.T_collection_audit_record = auditRecordJson
+		clos = append(clos, "T_collection_audit_record")
+	}
+
+	if T_collection_state == Task.TaskCollectionStatePass {
+		// 数据编辑审核通过时间为验证报告开始时间
+		r.T_reporting_start_time = time.Now().Format("2006-01-02 15:04:05")
+		clos = append(clos, "T_reporting_start_time")
+	}
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 已退回(负责人)
+	if T_collection_state == Task.TaskCollectionStateReturn {
+		System.Add_News(r.T_collection, fmt.Sprintf("【%s-%s】数据编辑 %s,%s", company_r.T_name, r.T_name, Task.TaskCollectionStateMap[T_collection_state], T_reason), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】数据编辑 %s,%s", company_r.T_name, r.T_name, Task.TaskCollectionStateMap[T_collection_state], T_reason))
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "修改采集状态", r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "修改采集状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+func (c *TaskController) UpDeliveryState() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_delivery_state, _ := c.GetInt("T_delivery_state")
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r.T_delivery_state = T_delivery_state
+
+	if !Task.Update_Task(r, "T_delivery_state") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "修改交付审核状态", r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "修改交付审核状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 更新线上数据后台执行
+func (c *TaskDataController) TaskData_Up_TaskData_Back() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 通知 报告人员
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+	infoCollection, _ := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+	System.Add_News(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】报告已完成,请及时通知客户审核", company_r.T_name, r.T_name), "")
+	go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】报告已完成,请及时通知客户审核", company_r.T_name, r.T_name))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+
+}
+
+// 修改-
+func (c *TaskController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_Show, T_Show_err := c.GetInt("T_Show")
+
+	T_VerifyTemplate_class := c.GetString("T_VerifyTemplate_class")
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_deadline := c.GetString("T_deadline")
+	T_scheme := c.GetString("T_scheme")
+	T_collection := c.GetString("T_collection")
+	T_collection_state, _ := c.GetInt("T_collection_state")
+	T_collection_signature := c.GetString("T_collection_signature") // 完成编辑签字图片
+	T_reporting := c.GetString("T_reporting")
+	T_delivery := c.GetString("T_delivery")
+	T_record := c.GetString("T_record")
+
+	T_doc1 := c.GetString("T_doc1")
+	T_pdf1 := c.GetString("T_pdf1")              // 方案
+	T_pdf1_stamp, _ := c.GetBool("T_pdf1_stamp") // 方案加盖公章
+	T_doc2 := c.GetString("T_doc2")
+	T_pdf2 := c.GetString("T_pdf2")              // 证书
+	T_pdf2_stamp, _ := c.GetBool("T_pdf2_stamp") // 报告加盖公章
+
+	T_doc3 := c.GetString("T_doc3")
+	T_pdf3 := c.GetString("T_pdf3")
+	T_pdf4 := c.GetString("T_pdf4") // 验证标识
+	T_pdf5 := c.GetString("T_pdf5") // 检测报告
+	T_pdf6 := c.GetString("T_pdf6") // 原始记录
+
+	T_VerifyDeviceDataStartTime := c.GetString("T_VerifyDeviceDataStartTime") // 验证设备数据开始时间
+	T_VerifyDeviceDataEndTime := c.GetString("T_VerifyDeviceDataEndTime")     // 验证设备数据开始时间
+	T_BindDeviceDataStartTime := c.GetString("T_BindDeviceDataStartTime")     // 绑定设备数据开始时间
+	T_BindDeviceDataEndTime := c.GetString("T_BindDeviceDataEndTime")         // 绑定设备数据结束时间
+	T_sn := c.GetString("T_sn")                                               // T_sn
+	T_CalibrationExpirationTime := c.GetString("T_CalibrationExpirationTime") // 校准到期时间
+
+	T_project := c.GetString("T_project")                 // 项目 负责人UUID
+	T_province := c.GetString("T_province")               // 省
+	T_city := c.GetString("T_city")                       // 市
+	T_district := c.GetString("T_district")               // 区
+	T_province_code := c.GetString("T_province_code")     // 省 code
+	T_city_code := c.GetString("T_city_code")             // 市 code
+	T_district_code := c.GetString("T_district_code")     // 区 code
+	T_category := c.GetString("T_category")               // 类别
+	T_device_type := c.GetString("T_device_type")         // 设备类型
+	T_volume := c.GetString("T_volume")                   // 规格/容积
+	T_verify_type := c.GetString("T_verify_type")         // 验证类型
+	T_subject_matter := c.GetString("T_subject_matter")   // 标的物名称
+	T_temp_range := c.GetString("T_temp_range")           // 验证温度范围
+	T_report_number := c.GetString("T_report_number")     // 报告编号
+	T_report_type := c.GetString("T_report_type")         // 报告编号
+	T_device_quantity, _ := c.GetInt("T_device_quantity") // 报告编号
+	T_cnas, _ := c.GetInt("T_cnas")                       // cnas实验室
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_report_number) > 0 && T_report_number != "/" {
+		t, exist := Task.Read_TaskbyT_report_number(T_report_number)
+		if exist && r.T_task_id != t.T_task_id {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "报告编号已存在!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	// .......
+	clos := make([]string, 0)
+	if len(T_name) > 0 {
+		r.T_name = T_name
+		clos = append(clos, "T_name")
+	}
+	if T_Show_err == nil {
+		r.T_Show = T_Show
+		clos = append(clos, "T_Show")
+	}
+	if len(T_VerifyTemplate_class) > 0 {
+		r.T_VerifyTemplate_class = T_VerifyTemplate_class
+		clos = append(clos, "T_VerifyTemplate_class")
+	}
+	if len(T_VerifyTemplate_id) > 0 {
+		r.T_VerifyTemplate_id = T_VerifyTemplate_id
+		clos = append(clos, "T_VerifyTemplate_id")
+	}
+	if len(T_deadline) > 0 {
+		r.T_deadline = T_deadline
+		clos = append(clos, "T_deadline")
+	}
+
+	if len(T_scheme) > 0 {
+		r.T_scheme = T_scheme
+		clos = append(clos, "T_scheme")
+	}
+	if len(T_collection) > 0 {
+		r.T_collection = T_collection
+		clos = append(clos, "T_collection")
+	}
+	if len(T_reporting) > 0 {
+		r.T_reporting = T_reporting
+		clos = append(clos, "T_reporting")
+	}
+	if len(T_delivery) > 0 {
+		r.T_delivery = T_delivery
+		clos = append(clos, "T_delivery")
+	}
+	if len(T_record) > 0 {
+		r.T_record = T_record
+		clos = append(clos, "T_record")
+	}
+
+	// 完成编辑后设置实施结束时间
+	if T_collection_state == 4 {
+		r.T_collection_state = T_collection_state
+		clos = append(clos, "T_collection_state")
+		r.T_collection_signature = T_collection_signature
+		clos = append(clos, "T_collection_signature")
+		r.T_collection_end_time = time.Now().Format("2006-01-02 15:04:05")
+		clos = append(clos, "T_collection_end_time")
+		if len(r.T_collection_start_time) > 0 {
+			r.T_collection_time_interval, _ = lib.MinutesDifference(r.T_collection_start_time, r.T_collection_end_time)
+			// 扣除暂停时间
+			Task_Compute := Task.Read_TaskTime_Compute(r.T_task_id, 1)
+			if Task_Compute > 0 {
+				r.T_collection_time_interval -= float64(Task_Compute)
+			}
+
+			clos = append(clos, "T_collection_time_interval")
+			// 所需时间 > 超时时间
+			if r.T_collection_time_interval > Task.TaskCollectionTimeLimit && len(r.T_report_type) > 0 {
+				r.T_collection_overtime = r.T_collection_time_interval - Task.TaskCollectionTimeLimit // 超时时间
+				clos = append(clos, "T_collection_overtime")
+			}
+
+			// 通知 报告人员
+			_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+			System.Add_News(r.T_reporting, fmt.Sprintf("【%s-%s】数据采集 已提交", company_r.T_name, r.T_name), "")
+			go wx.WxSend(r.T_reporting, fmt.Sprintf("【%s-%s】数据采集 已提交", company_r.T_name, r.T_name))
+
+		}
+		// 添加已提交状态数据编辑记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_collection_audit_record, "", User_r.T_uuid, r.T_collection_state, "", "")
+		if err == nil {
+			r.T_collection_audit_record = auditRecordJson
+			clos = append(clos, "T_collection_audit_record")
+		}
+	}
+
+	if len(T_doc1) > 0 {
+		r.T_doc1 = T_doc1
+		clos = append(clos, "T_doc1")
+	}
+	// 验证报告内容T_pdf1,上传后将 当前任务 验证方案 标志 为 5 (0未完成 1已完成(客户通过) 2已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人) 5已提交)
+	// 上传后设置方案结束时间,计算所需时间和超时时间
+	if len(T_pdf1) > 0 {
+		r.T_pdf1 = T_pdf1
+		clos = append(clos, "T_pdf1")
+		//r.T_pdf1_watermark = GetWatermarkPdf(r,T_pdf1,"T_pdf1")
+		//clos = append(clos, "T_pdf1_watermark")
+		go GetWatermarkPdf(r, T_pdf1, T_pdf1_stamp, "T_pdf1")
+		r.T_scheme_state = 5
+		clos = append(clos, "T_scheme_state")
+		// 添加已提交状态验证方案记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_scheme_audit_record, "", User_r.T_uuid, r.T_scheme_state, "", "")
+		if err != nil {
+			return
+		}
+		r.T_scheme_audit_record = auditRecordJson
+		clos = append(clos, "T_scheme_audit_record")
+		r.T_scheme_end_time = time.Now().Format("2006-01-02 15:04:05")
+		clos = append(clos, "T_scheme_end_time")
+
+		r.T_scheme_time_interval, _ = lib.MinutesDifference(r.T_scheme_start_time, r.T_scheme_end_time)
+		Task_Compute := Task.Read_TaskTime_Compute(r.T_task_id, 0)
+		if Task_Compute > 0 {
+			r.T_scheme_time_interval -= float64(Task_Compute)
+		}
+		clos = append(clos, "T_scheme_time_interval")
+
+		// 所需时间 > 超时时间
+		if r.T_scheme_time_interval > Task.TaskSchemeTimeLimit[r.T_report_type] && len(r.T_report_type) > 0 {
+			r.T_scheme_overtime = r.T_scheme_time_interval - Task.TaskSchemeTimeLimit[r.T_report_type] // 超时时间
+			if Task.TaskSchemeTimeLimit[r.T_report_type] == 0 {
+				r.T_scheme_overtime = 0
+			}
+			clos = append(clos, "T_scheme_overtime")
+		}
+
+		// 通知 实施人员进场
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		System.Add_News(r.T_collection, fmt.Sprintf("【%s-%s】验证方案 已提交", company_r.T_name, r.T_name), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】验证方案 已提交", company_r.T_name, r.T_name))
+
+	}
+	if len(T_doc2) > 0 {
+		r.T_doc2 = T_doc2
+		clos = append(clos, "T_doc2")
+	}
+	// 验证报告内容T_pdf2 ,上传后将 当前任务 报告编写 标志 为 1
+	// 上传后设置报告结束时间,计算所需时间和超时时间
+	if len(T_pdf2) > 0 {
+		r.T_pdf2 = T_pdf2
+		clos = append(clos, "T_pdf2")
+		//r.T_pdf2_watermark = GetWatermarkPdf(T_pdf2,"T_pdf1")
+		//clos = append(clos, "T_pdf2_watermark")
+		go GetWatermarkPdf(r, T_pdf2, T_pdf2_stamp, "T_pdf2")
+
+		r.T_reporting_state = 5
+		r.T_reporting_submit_time = time.Now().Format("2006-01-02 15:04:05")
+		clos = append(clos, "T_reporting_state", "T_reporting_submit_time")
+		// 添加已提交状态验证报告记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_reporting_audit_record, "", User_r.T_uuid, r.T_reporting_state, "", "")
+		if err == nil {
+			r.T_reporting_audit_record = auditRecordJson
+			clos = append(clos, "T_reporting_audit_record")
+			r.T_reporting_end_time = time.Now().Format("2006-01-02 15:04:05")
+			clos = append(clos, "T_reporting_end_time")
+			if len(r.T_reporting_start_time) > 0 {
+				r.T_reporting_time_interval, _ = lib.MinutesDifference(r.T_reporting_start_time, r.T_reporting_end_time)
+				clos = append(clos, "T_reporting_time_interval")
+				// 扣除暂停时间
+				Task_Compute := Task.Read_TaskTime_Compute(r.T_task_id, 2)
+				if Task_Compute > 0 {
+					r.T_reporting_time_interval -= float64(Task_Compute)
+				}
+				clos = append(clos, "T_reporting_time_interval")
+				// 所需时间 > 超时时间
+				if r.T_reporting_time_interval > Task.TaskReportingTimeLimit[r.T_report_type] && len(r.T_report_type) > 0 {
+					r.T_reporting_overtime = r.T_reporting_time_interval - Task.TaskReportingTimeLimit[r.T_report_type] // 超时时间
+					if Task.TaskReportingTimeLimit[r.T_report_type] == 0 {
+						r.T_reporting_overtime = 0
+					}
+					clos = append(clos, "T_reporting_overtime")
+				}
+
+			}
+		}
+
+		// 通知 报告人员
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		System.Add_News(r.T_delivery, fmt.Sprintf("【%s-%s】验证报告 已提交", company_r.T_name, r.T_name), "")
+		go wx.WxSend(r.T_delivery, fmt.Sprintf("【%s-%s】验证报告 已提交", company_r.T_name, r.T_name))
+
+	}
+	if len(T_doc3) > 0 {
+		r.T_doc3 = T_doc3
+		clos = append(clos, "T_doc3")
+	}
+	if len(T_pdf3) > 0 {
+		r.T_pdf3 = T_pdf3
+		clos = append(clos, "T_pdf3")
+	}
+	// 验证标识内容T_pdf4 ,上传后将 当前任务 验证标识 标志 为 1
+	if len(T_pdf4) > 0 {
+		r.T_pdf4 = T_pdf4
+		clos = append(clos, "T_pdf4")
+		r.T_marking_state = 1
+		clos = append(clos, "T_marking_state")
+	}
+	if len(T_pdf5) > 0 {
+		r.T_pdf5 = T_pdf5
+		clos = append(clos, "T_pdf5")
+		r.T_examining_report_state = 1
+		clos = append(clos, "T_examining_report_state")
+		// 添加已提交状态 检测报告记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_examining_report_audit_record, "", User_r.T_uuid, r.T_examining_report_state, "", "")
+		if err == nil {
+			r.T_examining_report_audit_record = auditRecordJson
+			clos = append(clos, "T_examining_report_audit_record")
+			r.T_examining_report_end_time = time.Now().Format("2006-01-02 15:04:05")
+			clos = append(clos, "T_examining_report_end_time")
+			if len(r.T_examining_report_start_time) > 0 {
+				r.T_examining_report_time_interval, _ = lib.MinutesDifference(r.T_examining_report_start_time, r.T_examining_report_end_time)
+				clos = append(clos, "T_examining_report_time_interval")
+				// 扣除暂停时间
+				Task_Compute := Task.Read_TaskTime_Compute(r.T_task_id, 3)
+				if Task_Compute > 0 {
+					r.T_examining_report_time_interval -= float64(Task_Compute)
+				}
+				clos = append(clos, "T_examining_report_time_interval")
+
+			}
+		}
+
+		// 通知 报告人员
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		System.Add_News(r.T_delivery, fmt.Sprintf("【%s-%s】检测报告 已提交", company_r.T_name, r.T_name), "")
+		go wx.WxSend(r.T_delivery, fmt.Sprintf("【%s-%s】检测报告 已提交", company_r.T_name, r.T_name))
+	}
+	if len(T_pdf6) > 0 {
+		r.T_pdf6 = T_pdf6
+		clos = append(clos, "T_pdf6")
+		r.T_examining_report_state = 1
+		clos = append(clos, "T_original_record_state")
+		// 添加已提交状态 原始记录 记录
+		auditRecordJson, err := Task.Add_AuditRecord(r.T_original_record_audit_record, "", User_r.T_uuid, r.T_original_record_state, "", "")
+		if err == nil {
+			r.T_original_record_audit_record = auditRecordJson
+			clos = append(clos, "T_original_record_audit_record")
+			r.T_original_record_end_time = time.Now().Format("2006-01-02 15:04:05")
+			clos = append(clos, "T_original_record_end_time")
+			if len(r.T_reporting_start_time) > 0 {
+				r.T_original_record_time_interval, _ = lib.MinutesDifference(r.T_original_record_start_time, r.T_original_record_end_time)
+				clos = append(clos, "T_original_record_time_interval")
+				// 扣除暂停时间
+				Task_Compute := Task.Read_TaskTime_Compute(r.T_task_id, 2)
+				if Task_Compute > 0 {
+					r.T_original_record_time_interval -= float64(Task_Compute)
+				}
+				clos = append(clos, "T_original_record_time_interval")
+
+			}
+		}
+
+		// 通知 报告人员
+		_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+		System.Add_News(r.T_delivery, fmt.Sprintf("【%s-%s】原始记录 已提交", company_r.T_name, r.T_name), "")
+		go wx.WxSend(r.T_delivery, fmt.Sprintf("【%s-%s】原始记录 已提交", company_r.T_name, r.T_name))
+	}
+
+	if len(T_VerifyDeviceDataStartTime) > 0 {
+		r.T_VerifyDeviceDataStartTime = T_VerifyDeviceDataStartTime
+		clos = append(clos, "T_VerifyDeviceDataStartTime")
+	}
+	if len(T_VerifyDeviceDataEndTime) > 0 {
+		r.T_VerifyDeviceDataEndTime = T_VerifyDeviceDataEndTime
+		clos = append(clos, "T_VerifyDeviceDataEndTime")
+	}
+	if len(T_BindDeviceDataStartTime) > 0 {
+		r.T_BindDeviceDataStartTime = T_BindDeviceDataStartTime
+		clos = append(clos, "T_BindDeviceDataStartTime")
+	}
+	if len(T_BindDeviceDataEndTime) > 0 {
+		r.T_BindDeviceDataEndTime = T_BindDeviceDataEndTime
+		clos = append(clos, "T_BindDeviceDataEndTime")
+	}
+	if len(T_sn) > 0 {
+		T_sn = strings.TrimSpace(T_sn)
+		r.T_sn = T_sn
+		clos = append(clos, "T_sn")
+	}
+	if len(T_CalibrationExpirationTime) > 0 {
+		r.T_CalibrationExpirationTime = T_CalibrationExpirationTime
+		clos = append(clos, "T_CalibrationExpirationTime")
+	}
+
+	// 从3.0获取校准时间
+	if len(T_sn) > 0 && len(T_CalibrationExpirationTime) == 0 {
+
+		go func(r Task.Task, T_sn, T_CalibrationExpirationTime string) {
+			NatsServer.Cold_UpdateDevice_CalibrationTime(T_sn, T_CalibrationExpirationTime)
+			device, err := NatsServer.Cold_ReadDeviceByT_sn(T_sn)
+			if err == nil {
+				if !device.T_CalibrationTime.IsZero() {
+					r.T_CalibrationExpirationTime = device.T_CalibrationTime.Format("2006-01-02")
+					clos = append(clos, "T_CalibrationExpirationTime")
+					Task.Update_Task(r, "T_CalibrationExpirationTime")
+				}
+			}
+		}(r, T_sn, T_CalibrationExpirationTime)
+
+	}
+
+	if len(T_project) > 0 {
+		r.T_project = T_project
+		clos = append(clos, "T_project")
+	}
+	if len(T_province) > 0 {
+		r.T_province = T_province
+		clos = append(clos, "T_province")
+	}
+	if len(T_city) > 0 {
+		r.T_city = T_city
+		clos = append(clos, "T_city")
+	}
+	if len(T_district) > 0 {
+		r.T_district = T_district
+		clos = append(clos, "T_district")
+	}
+	if len(T_province_code) > 0 {
+		r.T_province_code = T_province_code
+		clos = append(clos, "T_province_code")
+	}
+	if len(T_city_code) > 0 {
+		r.T_city_code = T_city_code
+		clos = append(clos, "T_city_code")
+	}
+	if len(T_district_code) > 0 {
+		r.T_district_code = T_district_code
+		clos = append(clos, "T_district_code")
+	}
+	if len(T_category) > 0 {
+		r.T_category = T_category
+		clos = append(clos, "T_category")
+	}
+	if len(T_device_type) > 0 {
+		r.T_device_type = T_device_type
+		clos = append(clos, "T_device_type")
+	}
+	if len(T_volume) > 0 {
+		r.T_volume = T_volume
+		clos = append(clos, "T_volume")
+	}
+	if len(T_verify_type) > 0 {
+		r.T_verify_type = T_verify_type
+		clos = append(clos, "T_verify_type")
+	}
+	if len(T_subject_matter) > 0 {
+		r.T_subject_matter = T_subject_matter
+		clos = append(clos, "T_subject_matter")
+	}
+	if len(T_temp_range) > 0 {
+		r.T_temp_range = T_temp_range
+		clos = append(clos, "T_temp_range")
+	}
+	if len(T_report_number) > 0 {
+		r.T_report_number = T_report_number
+		clos = append(clos, "T_report_number")
+	}
+	if len(T_report_type) > 0 {
+		r.T_report_type = T_report_type
+		clos = append(clos, "T_report_type")
+	}
+	if T_device_quantity > 0 {
+		r.T_device_quantity = T_device_quantity
+		clos = append(clos, "T_device_quantity")
+	}
+
+	r.T_cnas = T_cnas
+	clos = append(clos, "T_cnas")
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "修改", r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 保存电子签名pdf
+func (c *TaskController) SaveElectronicSignaturePDF() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_pdf1 := c.GetString("T_pdf1") // 方案
+	T_pdf2 := c.GetString("T_pdf2") // 证书
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	clos := make([]string, 0)
+	// 验证报告内容T_pdf1,上传后将 当前任务 验证方案 标志 为 5 (0未完成 1已完成(客户通过) 2已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人) 5已提交)
+	// 上传后设置方案结束时间,计算所需时间和超时时间
+	if len(T_pdf1) > 0 {
+		r.T_pdf1_elec_signature = T_pdf1
+		clos = append(clos, "T_pdf1")
+		go GetWatermarkPdf(r, T_pdf1, false, "T_pdf1")
+	}
+
+	// 验证报告内容T_pdf2 ,上传后将 当前任务 报告编写 标志 为 1
+	// 上传后设置报告结束时间,计算所需时间和超时时间
+	if len(T_pdf2) > 0 {
+		r.T_pdf1_elec_signature = T_pdf2
+		clos = append(clos, "T_pdf2")
+		go GetWatermarkPdf(r, T_pdf2, false, "T_pdf2")
+
+	}
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "保存电子签名方案/报告", r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "保存电子签名方案/报告", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改验证方案状态
+func (c *TaskController) UpSchemeState() {
+	Admin_r, Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	operate_uuid := ""
+	if Admin_is {
+		operate_uuid = Admin_r.T_uuid
+	}
+	if User_is {
+		operate_uuid = User_r.T_uuid
+	}
+
+	T_scheme_state, _ := c.GetInt("T_scheme_state") // 1 已完成(客户通过) 5已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人)
+	T_reason := c.GetString("T_reason")             // 退回原因
+	T_signature := c.GetString("T_signature")       // 通过后客户签名图片链接
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	clos := make([]string, 0)
+	if T_scheme_state > 0 {
+		r.T_scheme_state = T_scheme_state
+		clos = append(clos, "T_scheme_state")
+	}
+	if len(T_signature) > 0 {
+		r.T_scheme_signature = T_signature
+		clos = append(clos, "T_scheme_signature")
+	}
+
+	if T_scheme_state == Task.TaskSchemeStateClientReturn || T_scheme_state == Task.TaskSchemeStateReturn {
+		r.T_scheme_return_times += 1
+		clos = append(clos, "T_scheme_return_times")
+		// 客户退回时新增驳回次数和驳回记录
+		if T_scheme_state == Task.TaskSchemeStateClientReturn {
+			r.T_reject_times += 1
+			var rejectRecordList []Task.AuditRecord
+			if len(r.T_reject_record) > 0 {
+				err := json.Unmarshal([]byte(r.T_reject_record), &rejectRecordList)
+				if err != nil {
+					logs.Error("JSON 反序列化失败:", err)
+					return
+				}
+			}
+
+			rejectRecordList = append(rejectRecordList, Task.AuditRecord{
+				T_uuid:   User_r.T_uuid,
+				T_state:  T_scheme_state,
+				T_reason: T_reason,
+				T_time:   time.Now().Format("2006-01-02 15:04:05"),
+				T_type:   "scheme",
+			})
+			rejectRecordJson, err := json.Marshal(rejectRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+			r.T_reject_record = string(rejectRecordJson)
+			clos = append(clos, "T_reject_times")
+			clos = append(clos, "T_reject_record")
+		}
+
+	}
+
+	auditRecordJson, err := Task.Add_AuditRecord(r.T_scheme_audit_record, User_r.T_uuid, Admin_r.T_uuid, T_scheme_state, T_reason, "")
+	if err != nil {
+		return
+	}
+	r.T_scheme_audit_record = auditRecordJson
+	clos = append(clos, "T_scheme_audit_record")
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	//AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	// 已提交
+	if T_scheme_state == Task.TaskSchemeStateSubmitted {
+		System.Add_News(r.T_collection, fmt.Sprintf("【%s-%s】验证方案 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state]), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】验证方案 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state]))
+	}
+
+	// 已通过
+	if T_scheme_state == Task.TaskSchemeStatePass {
+		infoCollection, _ := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+		System.Add_News(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】验证方案 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state]), "")
+		go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】验证方案 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state]))
+	}
+
+	// 已退回(负责人)
+	if T_scheme_state == Task.TaskSchemeStateReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason))
+	}
+
+	//  已退回(客户)
+	if T_scheme_state == Task.TaskSchemeStateClientReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("!!!【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("!!!【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason))
+
+		System.Add_News(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason), "")
+		go wx.WxSend(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason))
+
+		go wx.WxSend(conf.BoosUuid, fmt.Sprintf("!!!【%s-%s】验证方案 %s,%s", company_r.T_name, r.T_name, Task.TaskSchemeStateMap[T_scheme_state], T_reason))
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(operate_uuid, T_task_id, "任务管理", "修改验证方案状态", r)
+	System.Add_UserLogs_T(operate_uuid, "任务管理", "修改验证方案状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改验证报告状态
+func (c *TaskController) UpReportingState() {
+	Admin_r, Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	operate_uuid := ""
+	if Admin_is {
+		operate_uuid = Admin_r.T_uuid
+	}
+	if User_is {
+		operate_uuid = User_r.T_uuid
+	}
+
+	T_reporting_state, _ := c.GetInt("T_reporting_state") // 1 已完成(客户通过) 5已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人)
+	T_reason := c.GetString("T_reason")                   // 退回原因
+	T_signature := c.GetString("T_signature")             // 通过后客户签名图片链接
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	//_, user_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	clos := make([]string, 0)
+	if T_reporting_state > 0 {
+		r.T_reporting_state = T_reporting_state
+		clos = append(clos, "T_reporting_state")
+	}
+	if T_reporting_state == Task.TaskReportingStatePass {
+		r.T_reporting_pass_time = time.Now().Format("2006-01-02 15:04:05")
+		clos = append(clos, "T_reporting_pass_time")
+	}
+	if len(T_signature) > 0 {
+		r.T_reporting_signature = T_signature
+		clos = append(clos, "T_reporting_signature")
+	}
+
+	if T_reporting_state == Task.TaskReportingStateClientReturn || T_reporting_state == Task.TaskReportingStateReturn {
+		r.T_reporting_return_times += 1
+		clos = append(clos, "T_reporting_return_times")
+		// 客户退回时新增驳回次数和驳回记录
+		if T_reporting_state == Task.TaskReportingStateClientReturn {
+			r.T_reject_times += 1
+			var rejectRecordList []Task.AuditRecord
+			if len(r.T_reject_record) > 0 {
+				err := json.Unmarshal([]byte(r.T_reject_record), &rejectRecordList)
+				if err != nil {
+					logs.Error("JSON 反序列化失败:", err)
+					return
+				}
+			}
+
+			rejectRecordList = append(rejectRecordList, Task.AuditRecord{
+				T_uuid:   User_r.T_uuid,
+				T_state:  T_reporting_state,
+				T_reason: T_reason,
+				T_time:   time.Now().Format("2006-01-02 15:04:05"),
+				T_type:   "reporting",
+			})
+			rejectRecordJson, err := json.Marshal(rejectRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+			r.T_reject_record = string(rejectRecordJson)
+			clos = append(clos, "T_reject_times")
+			clos = append(clos, "T_reject_record")
+		}
+
+	}
+
+	auditRecordJson, err := Task.Add_AuditRecord(r.T_reporting_audit_record, User_r.T_uuid, Admin_r.T_uuid, T_reporting_state, T_reason, "")
+	if err != nil {
+		return
+	}
+
+	r.T_reporting_audit_record = auditRecordJson
+
+	clos = append(clos, "T_reporting_audit_record")
+	// 查询信息采集信息
+	infoCollection, is := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 验证报告客户审核通过后设置结束时间
+	if T_reporting_state == Task.TaskReportingStateClientPass {
+		r.T_end_time = time.Now().Format("2006-01-02 15:04:05")
+		r.T_time_interval, err = lib.MinutesDifference(infoCollection.T_start_time, r.T_end_time)
+		if err != nil {
+			logs.Error("UpReportingState:", err.Error())
+		}
+		clos = append(clos, "T_end_time")
+		clos = append(clos, "T_time_interval")
+	}
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 已通过
+	if T_reporting_state == Task.TaskReportingStatePass {
+		System.Add_News(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】验证报告 %s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]), "")
+		go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】验证报告 %s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]))
+
+		System.Add_News(r.T_reporting, fmt.Sprintf("【%s-%s】验证报告 %s,请及时 打印报告", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]), "")
+		go wx.WxSend(r.T_reporting, fmt.Sprintf("【%s-%s】验证报告 %s,请及时 打印报告", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]))
+	}
+	// 已退回
+	if T_reporting_state == Task.TaskReportingStateReturn {
+		System.Add_News(r.T_reporting, fmt.Sprintf("【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason), "")
+		go wx.WxSend(r.T_reporting, fmt.Sprintf("【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+	}
+	// 已通过(客户)  通知销售
+	if T_reporting_state == Task.TaskReportingStateClientPass {
+		go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】 %s,请尽快安排客户回款", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]))
+	}
+
+	if T_reporting_state == Task.TaskReportingStateClientReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+
+		System.Add_News(r.T_collection, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+
+		System.Add_News(r.T_reporting, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason), "")
+		go wx.WxSend(r.T_reporting, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+
+		//System.Add_News(r.T_delivery, fmt.Sprintf("!!!【%s-%s】验证报告 %s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state]), "")
+		//go wx.WxSend(r.T_delivery, fmt.Sprintf("!!!【%s-%s】验证报告 %s", infoCollection.T_name, r.T_name,Task.TaskReportingStateMap[T_reporting_state]))
+
+		System.Add_News(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason), "")
+		go wx.WxSend(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+
+		go wx.WxSend(conf.BoosUuid, fmt.Sprintf("!!!【%s-%s】验证报告 %s,%s", infoCollection.T_name, r.T_name, Task.TaskReportingStateMap[T_reporting_state], T_reason))
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(operate_uuid, T_task_id, "任务管理", "修改验证报告状态", r)
+	System.Add_UserLogs_T(operate_uuid, "任务管理", "修改验证报告状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改检测报告状态
+func (c *TaskController) UpExaminingReportState() {
+	Admin_r, Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	operate_uuid := ""
+	if Admin_is {
+		operate_uuid = Admin_r.T_uuid
+	}
+	if User_is {
+		operate_uuid = User_r.T_uuid
+	}
+
+	T_examining_report_state, _ := c.GetInt("T_examining_report_state") // 1 已完成(客户通过) 5已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人)
+	T_reason := c.GetString("T_reason")                                 // 退回原因
+	T_signature := c.GetString("T_signature")                           // 通过后客户签名图片链接
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	clos := make([]string, 0)
+	if T_examining_report_state > 0 {
+		r.T_examining_report_state = T_examining_report_state
+		clos = append(clos, "T_examining_report_state")
+	}
+	if len(T_signature) > 0 {
+		r.T_examining_report_signature = T_signature
+		clos = append(clos, "T_examining_report_signature")
+	}
+
+	if T_examining_report_state == Task.TaskExaminingReportStateClientReturn || T_examining_report_state == Task.TaskExaminingReportStateReturn {
+		r.T_examining_report_return_times += 1
+		clos = append(clos, "T_examining_report_return_times")
+		// 客户退回时新增驳回次数和驳回记录
+		if T_examining_report_state == Task.TaskExaminingReportStateClientReturn {
+			r.T_reject_times += 1
+			var rejectRecordList []Task.AuditRecord
+			if len(r.T_reject_record) > 0 {
+				err := json.Unmarshal([]byte(r.T_reject_record), &rejectRecordList)
+				if err != nil {
+					logs.Error("JSON 反序列化失败:", err)
+					return
+				}
+			}
+
+			rejectRecordList = append(rejectRecordList, Task.AuditRecord{
+				T_uuid:   User_r.T_uuid,
+				T_state:  T_examining_report_state,
+				T_reason: T_reason,
+				T_time:   time.Now().Format("2006-01-02 15:04:05"),
+				T_type:   "examining_report",
+			})
+			rejectRecordJson, err := json.Marshal(rejectRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+			r.T_reject_record = string(rejectRecordJson)
+			clos = append(clos, "T_reject_times")
+			clos = append(clos, "T_reject_record")
+		}
+
+	}
+
+	auditRecordJson, err := Task.Add_AuditRecord(r.T_examining_report_audit_record, User_r.T_uuid, Admin_r.T_uuid, T_examining_report_state, T_reason, "")
+	if err != nil {
+		return
+	}
+	r.T_examining_report_audit_record = auditRecordJson
+	clos = append(clos, "T_examining_report_audit_record")
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 已提交
+	if T_examining_report_state == Task.TaskExaminingReportStateSubmitted {
+		System.Add_News(r.T_collection, fmt.Sprintf("【%s-%s】检测报告 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state]), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】检测报告 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state]))
+	}
+
+	// 已通过
+	if T_examining_report_state == Task.TaskExaminingReportStatePass {
+		infoCollection, _ := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+		System.Add_News(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】检测报告 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state]), "")
+		go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】检测报告 %s,请尽快与客户沟通确定", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state]))
+	}
+
+	// 已退回(负责人)
+	if T_examining_report_state == Task.TaskExaminingReportStateReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason))
+	}
+
+	//  已退回(客户)
+	if T_examining_report_state == Task.TaskExaminingReportStateClientReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("!!!【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("!!!【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason))
+
+		System.Add_News(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason), "")
+		go wx.WxSend(conf.VdelUuid, fmt.Sprintf("!!!【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason))
+
+		go wx.WxSend(conf.BoosUuid, fmt.Sprintf("!!!【%s-%s】检测报告 %s,%s", company_r.T_name, r.T_name, Task.TaskExaminingReportStateMap[T_examining_report_state], T_reason))
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(operate_uuid, T_task_id, "任务管理", "修改检测报告状态", r)
+	System.Add_UserLogs_T(operate_uuid, "任务管理", "修改检测报告状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改原始数据状态
+func (c *TaskController) UpOriginalRecordState() {
+	Admin_r, Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	operate_uuid := ""
+	if Admin_is {
+		operate_uuid = Admin_r.T_uuid
+	}
+	if User_is {
+		operate_uuid = User_r.T_uuid
+	}
+
+	T_original_record_state, _ := c.GetInt("T_original_record_state") // 1 已完成(客户通过) 5已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人)
+	T_reason := c.GetString("T_reason")                               // 退回原因
+	T_signature := c.GetString("T_signature")                         // 通过后客户签名图片链接
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	clos := make([]string, 0)
+	if T_original_record_state > 0 {
+		r.T_original_record_state = T_original_record_state
+		clos = append(clos, "T_original_record_state")
+	}
+	if len(T_signature) > 0 {
+		r.T_original_record_signature = T_signature
+		clos = append(clos, "T_original_record_signature")
+	}
+
+	if T_original_record_state == Task.TaskOriginalRecordStateReturn {
+		r.T_original_record_return_times += 1
+		clos = append(clos, "T_original_record_return_times")
+	}
+
+	auditRecordJson, err := Task.Add_AuditRecord(r.T_original_record_audit_record, User_r.T_uuid, Admin_r.T_uuid, T_original_record_state, T_reason, "")
+	if err != nil {
+		return
+	}
+	r.T_original_record_audit_record = auditRecordJson
+	clos = append(clos, "T_original_record_audit_record")
+
+	if !Task.Update_Task(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 已提交
+	if T_original_record_state == Task.TaskOriginalRecordStateSubmitted {
+		System.Add_News(r.T_collection, fmt.Sprintf("【%s-%s】原始数据 %s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state]), "")
+		go wx.WxSend(r.T_collection, fmt.Sprintf("【%s-%s】原始数据 %s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state]))
+	}
+
+	// 已通过
+	if T_original_record_state == Task.TaskOriginalRecordStatePass {
+		infoCollection, _ := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+		System.Add_News(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】原始数据 %s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state]), "")
+		go wx.WxSend(infoCollection.T_submit_uuid, fmt.Sprintf("【%s-%s】原始数据 %s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state]))
+	}
+
+	// 已退回(负责人)
+	if T_original_record_state == Task.TaskOriginalRecordStateReturn {
+		System.Add_News(r.T_scheme, fmt.Sprintf("【%s-%s】原始数据 %s,%s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state], T_reason), "")
+		go wx.WxSend(r.T_scheme, fmt.Sprintf("【%s-%s】原始数据 %s,%s", company_r.T_name, r.T_name, Task.TaskOriginalRecordStateMap[T_original_record_state], T_reason))
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(operate_uuid, T_task_id, "任务管理", "修改原始数据状态", r)
+	System.Add_UserLogs_T(operate_uuid, "任务管理", "修改原始数据状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 进场  改成 方案开始
+func (c *TaskController) EnterArea() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 方案开始
+	if len(r.T_scheme_start_time) == 0 {
+		r.T_scheme_start_time = time.Now().Format("2006-01-02 15:04:05")
+		Task.Update_Task(r, "T_scheme_start_time")
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "方案开始", r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "方案开始", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 开始验证
+func (c *TaskController) StartVerify() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	T_time := c.GetString("T_time") // 进场时间
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(r.T_collection_start_time) == 0 {
+		r.T_collection_start_time = T_time
+		if !Task.Update_Task(r, "T_collection_start_time") {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改实施开始时间失败!"}
+			c.ServeJSON()
+			return
+		}
+		// 添加任务操作日志
+		Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "开始验证", r)
+		System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "开始验证", r)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *TaskController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	if r, is := Task.Read_Task(T_task_id); is {
+		if !Task.Delete_Task(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		// 添加任务操作日志
+		Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "删除", r)
+		System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TaskController) Logs_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_task_id := c.GetString("T_task_id")
+
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	var cnt int
+	List, cnt := Task.Read_TaskLogs_List(T_task_id, AdminMap, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 查询图片生成状态
+func (c *TaskController) DeviceData_JPGState() {
+
+	T_task_id := c.GetString("T_task_id")
+	T_remark := c.GetString("T_remark")
+	jpg, is := Device.Redis_DeviceDataJPG_Get(T_task_id + T_remark)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 1202, Msg: "暂无图片正在生成"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: jpg}
+	c.ServeJSON()
+	return
+}
+
+// 生成温度图片
+func (c *TaskController) DeviceData_JPG() {
+	StartTime := c.GetString("StartTime")
+	if len(StartTime) > 0 {
+		_, ok := lib.TimeStrToTime(StartTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	EndTime := c.GetString("EndTime")
+	if len(EndTime) > 0 {
+		_, ok := lib.TimeStrToTime(EndTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	} else {
+		EndTime = time.Now().Format("2006-01-02 15:04:05")
+	}
+	T_remark := c.GetString("T_remark")
+
+	TemperatureMin, _ := c.GetFloat("TemperatureMin") // 最低温度
+	TemperatureMax, _ := c.GetFloat("TemperatureMax") // 最高温度
+	if TemperatureMin == 0 {
+		TemperatureMin = 2
+	}
+	if TemperatureMax == 0 {
+		TemperatureMax = 8
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if Task_r.T_collection_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+
+	deviceClassList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", T_remark, 0, 9999)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Device.Redis_DeviceDataJPG_Del(T_task_id + T_remark)
+
+	// 生成图片
+	go DeviceDataJPG(StartTime, EndTime, T_task_id, T_remark, deviceClassList, TemperatureMin, TemperatureMax)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// SyncInfoCollection 同步信息采集表
+func (c *TaskController) SyncInfoCollection() {
+	T_task_id := c.GetString("T_task_id")
+	T_source, _ := c.GetInt("T_source")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 获取信息采集表模版信息
+	InfoCollection_Map_List := InfoCollection.Read_InfoTemplateMap_List_For_Data(task.T_InfoTemplate_id)
+	InfoCollection_Data := InfoCollection.Read_InfoTemplateMapData_List(task.T_InfoCollection_id, task.T_InfoTemplate_id, InfoCollection_Map_List)
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(task.T_VerifyTemplate_id, T_source, 0)
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, T_task_id, task.T_VerifyTemplate_id, Map_List)
+
+	InfoCollectionDataMap := make(map[string]string)
+	for _, data := range InfoCollection_Data {
+		InfoCollectionDataMap[data.T_name] = data.T_value
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range Data {
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if InfoCollectionDataMap[v.T_name] == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               T_source,
+			T_task_id:              task.T_task_id,
+			T_VerifyTemplate_id:    task.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: InfoCollectionDataMap[v.T_name],
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	var ids []int64
+	ids, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData(MapDataList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Data: ids, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 退回记录列表
+func (c *TaskController) AuditRecordList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	T_type := c.GetString("T_type") // T_task任务 T_scheme方案 T_collection数据采集 T_reporting报告
+	//T_task       驳回记录
+	//T_scheme     实施方案状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	//T_collection 数据采集状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	//T_reporting  报告编写状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_state, _ := c.GetInt("T_state") // -1 获取全部
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	var auditRecordList []Task.AuditRecord
+
+	switch T_type {
+	case "T_task":
+		T_state = -1
+		if len(r.T_reject_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_reject_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	case "T_scheme":
+		if len(r.T_scheme_audit_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_scheme_audit_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	case "T_collection":
+		if len(r.T_collection_audit_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_collection_audit_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	case "T_reporting":
+		if len(r.T_reporting_audit_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_reporting_audit_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	case "T_examining_report":
+		if len(r.T_examining_report_audit_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_examining_report_audit_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	case "T_original_record":
+		if len(r.T_original_record_audit_record) > 0 {
+			err := json.Unmarshal([]byte(r.T_original_record_audit_record), &auditRecordList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+	}
+
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	var auditRecordList2 []Task.AuditRecord
+
+	// 返回全部
+	if T_state == -1 {
+		for i := 0; i < len(auditRecordList); i++ {
+			auditRecordList[i].T_admin_name = AdminMap[auditRecordList[i].T_admin]
+			auditRecordList[i].T_uuid_name = UserMap[auditRecordList[i].T_uuid]
+			auditRecordList2 = append(auditRecordList2, auditRecordList[i])
+		}
+		c.Data["json"] = lib.JSONS{Data: auditRecordList2, Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	if T_state == -2 {
+		for i := 0; i < len(auditRecordList); i++ {
+			if auditRecordList[i].T_state == 2 || auditRecordList[i].T_state == 4 {
+				auditRecordList[i].T_admin_name = AdminMap[auditRecordList[i].T_admin]
+				auditRecordList[i].T_uuid_name = UserMap[auditRecordList[i].T_uuid]
+				auditRecordList2 = append(auditRecordList2, auditRecordList[i])
+			}
+		}
+		c.Data["json"] = lib.JSONS{Data: auditRecordList2, Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	for i := 0; i < len(auditRecordList); i++ {
+		if auditRecordList[i].T_state == T_state {
+			auditRecordList[i].T_admin_name = AdminMap[auditRecordList[i].T_admin]
+			auditRecordList[i].T_uuid_name = UserMap[auditRecordList[i].T_uuid]
+			auditRecordList2 = append(auditRecordList2, auditRecordList[i])
+		}
+	}
+	c.Data["json"] = lib.JSONS{Data: auditRecordList2, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 存档生成图片
+func DeviceDataJPG(StartTime, EndTime, T_task_id, T_remark string, deviceList []Device.DeviceClassList, TemperatureMin, TemperatureMax float64) {
+	Device.Redis_DeviceDataJPG_Set(T_task_id+T_remark, Device.DeviceDataJPG{
+		State: 1,
+		Msg:   "图片生成中",
+		Url:   "",
+	})
+	msg := ""
+	state := 2
+	url := ""
+
+	if TemperatureMin == 0 {
+		TemperatureMin = 2
+	}
+	if TemperatureMax == 0 {
+		TemperatureMax = 8
+	}
+	var ymin, ymax float64
+	var xminT, xmaxT time.Time
+	if len(deviceList) > 0 {
+		ymin, ymax, xminT, xmaxT = Device.Read_DeviceData_T_Min_Max_Time_Min_Max(deviceList[0].T_sn, StartTime, EndTime)
+	}
+
+	// 创建一个新的绘图
+	p := plot.New()
+
+	// 设置绘图标题和标签
+	p.Title.Text = "温度折线图"
+	//p.Legend.ThumbnailWidth = 5 * vg.Inch
+	p.X.Label.Text = "时间"
+	p.Y.Label.Text = "温度"
+
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	var device = make([]Device.DeviceCount, len(deviceList))
+
+	// 创建温度线
+	for i := 0; i < len(deviceList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			//go func(index int, wg *sync.WaitGroup, p *plot.Plot) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceList[index].T_sn, deviceList[index].T_id
+			ymin_, ymax_, minTime_, maxTime_ := Device.Read_DeviceData_T_Min_Max_Time_Min_Max(sn, StartTime, EndTime)
+
+			if ymin > ymin_ {
+				ymin = ymin_
+			}
+			if ymax < ymax_ {
+				ymax = ymax_
+			}
+
+			if xminT.After(minTime_) && !minTime_.IsZero() {
+				xminT = minTime_
+			}
+
+			if xmaxT.Before(maxTime_) && !maxTime_.IsZero() {
+				xmaxT = maxTime_
+			}
+
+			r_maps, r_maps_num := Device.Read_DeviceSensorData_ById_List(sn, StartTime, EndTime, 0, 9999)
+			device[index] = Device.DeviceCount{
+				T_id: id,
+				T_sn: sn,
+				Num:  r_maps_num,
+			}
+			if r_maps_num == 0 {
+				return
+			}
+
+			pts := make(plotter.XYs, len(r_maps))
+			for j, d := range r_maps {
+				t, _ := lib.TimeStrToTime(d.T_time)
+				pts[j].X = float64(t.Unix())
+				pts[j].Y = float64(d.T_t)
+			}
+
+			line, err := plotter.NewLine(pts)
+			if err != nil {
+				return
+			}
+			line.Color = randomColor(index)
+			p.Add(line)
+		}(i)
+	}
+	jobGroup.Wait()
+
+	xmin, xmax := float64(xminT.Unix()), float64(xmaxT.Unix())
+	// 添加最高,最低标准线 用红色虚线标识
+	p.Add(horizontalLine(xmin, xmax, TemperatureMin))
+
+	p.Add(horizontalLine(xmin, xmax, TemperatureMax))
+
+	if ymax < 8 {
+		ymax = 8
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+	p.Y.Min, p.Y.Max = ymin, ymax
+
+	p.X.Min, p.X.Max = xmin, xmax
+	p.Y.Tick.Marker = commaTicks{}
+	//p.X.Tick.Marker = plot.TimeTicks{Format: "2006-01-02 15:04:05"}
+	p.X.Tick.Marker = timeTicks{}
+	p.X.Tick.Label.Rotation = math.Pi / 5
+	p.X.Tick.Label.YAlign = draw.YCenter
+	p.X.Tick.Label.XAlign = draw.XRight
+
+	filename := "jpg" + time.Now().Format("20060102150405")
+	// 保存文件
+	if err := p.Save(10*vg.Inch, 4*vg.Inch, "ofile/"+filename+".jpg"); err != nil {
+		Device.Redis_DeviceDataJPG_Set(T_task_id+T_remark, Device.DeviceDataJPG{
+			State: 3,
+			Msg:   "图片生成失败",
+			Url:   url,
+		})
+		logs.Error(lib.FuncName(), "生成图片失败", err)
+		return
+	}
+	if !lib.Pload_qiniu("ofile/"+filename+".jpg", "ofile/"+filename+".jpg") {
+		Device.Redis_DeviceDataJPG_Set(T_task_id+T_remark, Device.DeviceDataJPG{
+			State: 3,
+			Msg:   "图片上传七牛云失败",
+			Url:   url,
+		})
+		logs.Error(lib.FuncName(), "上传七牛云失败")
+		return
+	}
+	//删除目录
+	os.Remove("ofile/" + filename + ".jpg")
+
+	msg = "图片生成成功"
+	url = "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg"
+
+	Device.Redis_DeviceDataJPG_Set(T_task_id+T_remark, Device.DeviceDataJPG{
+		State:  state,
+		Msg:    msg,
+		Url:    url,
+		Device: device,
+	})
+	return
+
+}
+
+func horizontalLine(xmin, xmax, y float64) *plotter.Line {
+	pts := make(plotter.XYs, 2)
+	pts[0].X = xmin
+	pts[0].Y = y
+	pts[1].X = xmax
+	pts[1].Y = y
+	line, err := plotter.NewLine(pts)
+	if err != nil {
+		panic(any(err))
+	}
+	line.LineStyle.Dashes = []vg.Length{vg.Points(8), vg.Points(5), vg.Points(1), vg.Points(5)}
+	line.Color = color.RGBA{R: 255, A: 255}
+	return line
+}
+
+type timeTicks struct{}
+
+func (timeTicks) Ticks(min, max float64) []plot.Tick {
+	tks := plot.TimeTicks{}.Ticks(min, max)
+	for i, t := range tks {
+		//if t.Label == "" { // Skip minor ticks, they are fine.
+		//	continue
+		//}
+		tks[i].Label = time.Unix(int64(t.Value), 0).Format("2006-01-02 15:04:05")
+	}
+
+	return tks
+}
+
+type commaTicks struct{}
+
+// Ticks computes the default tick marks, but inserts commas
+// into the labels for the major tick marks.
+func (commaTicks) Ticks(min, max float64) []plot.Tick {
+	tks := plot.DefaultTicks{}.Ticks(min, max)
+	for i, t := range tks {
+		//if t.Label == "" { // Skip minor ticks, they are fine.
+		//	continue
+		//}
+		tks[i].Label = fmt.Sprintf("%.0f", t.Value)
+	}
+
+	return tks
+}
+
+// 生成随机颜色的辅助函数
+func randomColor(i int) color.RGBA {
+	var colors []color.RGBA
+	colors = append(colors,
+		color.RGBA{R: 52, G: 152, B: 219, A: 255},
+		color.RGBA{R: 230, G: 126, B: 34, A: 255},
+		color.RGBA{R: 142, G: 68, B: 173, A: 255},
+		color.RGBA{R: 211, G: 84, B: 0, A: 255},
+		color.RGBA{R: 231, G: 76, B: 60, A: 255},
+		color.RGBA{R: 26, G: 188, B: 156, A: 255},
+		color.RGBA{R: 243, G: 156, B: 18, A: 255},
+		color.RGBA{R: 22, G: 160, B: 133, A: 255},
+		color.RGBA{R: 46, G: 204, B: 113, A: 255},
+		color.RGBA{R: 39, G: 174, B: 96, A: 255},
+		color.RGBA{R: 41, G: 128, B: 185, A: 255},
+		color.RGBA{R: 155, G: 89, B: 182, A: 255},
+		color.RGBA{R: 192, G: 57, B: 43, A: 255},
+		color.RGBA{R: 241, G: 196, B: 15, A: 255},
+	)
+
+	return colors[i%len(colors)]
+}
+
+// 获取加完水印的pdf
+func GetWatermarkPdf_command(task Task.Task, pdfURL string, flag string) (pdf string) {
+	if len(pdfURL) == 0 {
+		return
+	}
+
+	currentDirectory := lib.GetCurrentDirectory()
+
+	scriptPath := currentDirectory + "/script"
+	pdf_file_out_name := uuid.New().String() + ".pdf"
+	pdfFilename := currentDirectory + "/ofile/" + uuid.New().String() + ".pdf"
+	pdf_file_out := currentDirectory + "/ofile/watermark" + pdf_file_out_name
+	watermark_pdf := currentDirectory + "/script/watermark.pdf"
+
+	// 执行Python脚本
+	cmd := exec.Command("python3", "add_watermark.py", pdfURL, pdfFilename, pdf_file_out, watermark_pdf)
+	cmd.Dir = scriptPath
+	// 获取命令输出
+	_, err := cmd.CombinedOutput()
+	if err != nil {
+		logs.Error("执行python脚本添加水印错误:", err)
+		return
+	}
+	lib.Pload_qiniu(pdf_file_out, pdf_file_out_name)
+	if !lib.Pload_qiniu(pdf_file_out, pdf_file_out) {
+		err = errors.New("上传水印pdf失败")
+		return
+	}
+	defer func() {
+		os.Remove(pdfFilename)
+		os.Remove(pdf_file_out)
+	}()
+
+	pdf = "https://bzdcoldverifyoss.baozhida.cn/" + pdf_file_out_name
+
+	switch flag {
+	case "T_pdf1":
+		task.T_pdf1_watermark = pdf
+		Task.Update_Task(task, "T_pdf1_watermark")
+	case "T_pdf2":
+		task.T_pdf2_watermark = pdf
+		Task.Update_Task(task, "T_pdf2_watermark")
+	}
+
+	return
+}
+func GetSignaturePdf_command(task Task.Task, pdfURL string, flag string) (pdf string) {
+	if len(pdfURL) == 0 {
+		return
+	}
+
+	currentDirectory := lib.GetCurrentDirectory()
+	scriptPath := currentDirectory + "/script"
+	pdf_file_out_name := uuid.New().String() + ".pdf"
+	pdfFilename := currentDirectory + "/ofile/" + uuid.New().String() + ".pdf"
+	pdf_file_out := currentDirectory + "/ofile/signature" + pdf_file_out_name
+	signature_img := currentDirectory + "/script/报告专用章.png"
+
+	// 执行Python脚本
+	cmd := exec.Command("python3", "add_signature.py", pdfURL, pdfFilename, signature_img, pdf_file_out)
+	cmd.Dir = scriptPath
+	// 获取命令输出
+	_, err := cmd.CombinedOutput()
+	if err != nil {
+		logs.Error("执行python脚本添加公章错误:", err)
+		return
+	}
+
+	_, err = os.Stat(pdf_file_out)
+	if os.IsNotExist(err) {
+		return ""
+	}
+
+	lib.Pload_qiniu(pdf_file_out, pdf_file_out_name)
+	if !lib.Pload_qiniu(pdf_file_out, pdf_file_out) {
+		err = errors.New("上传水印pdf失败")
+		return
+	}
+	defer func() {
+		os.Remove(pdfFilename)
+		os.Remove(pdf_file_out)
+	}()
+
+	pdf = "https://bzdcoldverifyoss.baozhida.cn/" + pdf_file_out_name
+
+	switch flag {
+	case "T_pdf1":
+		task.T_pdf1_signature = pdf
+		Task.Update_Task(task, "T_pdf1_signature")
+	case "T_pdf2":
+		task.T_pdf2_signature = pdf
+		Task.Update_Task(task, "T_pdf2_signature")
+	}
+
+	return
+}
+
+func GetWatermarkPdf(task Task.Task, pdfURL string, stamp bool, flag string) (pdf string) {
+	if len(pdfURL) == 0 {
+		return
+	}
+
+	// 添加公章 T_pdf5为CNAS实验室 ,不添加公章
+	var signaturePdf, watermarkPdf string
+	var err error
+	if flag != "T_pdf5" {
+		if stamp {
+			signaturePdf, err = lib.GetSignaturePdf(pdfURL)
+			if err != nil {
+				logs.Error("获取加报告章pdf失败:", err)
+				return
+			}
+		} else {
+			signaturePdf = pdfURL
+		}
+	}
+
+	// 添加水印
+	watermarkPdf, err = lib.GetWatermarkPdf(pdfURL)
+	if err != nil {
+		logs.Error("获取加水印pdf失败:", err)
+		return
+	}
+	switch flag {
+	case "T_pdf1":
+		task.T_pdf1_watermark = watermarkPdf
+		task.T_pdf1_signature = signaturePdf
+		Task.Update_Task(task, "T_pdf1_watermark", "T_pdf1_signature")
+	case "T_pdf2":
+		task.T_pdf2_watermark = watermarkPdf
+		task.T_pdf2_signature = signaturePdf
+		Task.Update_Task(task, "T_pdf2_watermark", "T_pdf2_signature")
+	case "T_pdf5":
+		task.T_pdf5_watermark = watermarkPdf
+		Task.Update_Task(task, "T_pdf5_watermark")
+	}
+
+	return
+}
+
+// 暂停申请
+// 列表 -
+func (c *TaskController) TaskTimeList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+
+	T_task_id := c.GetString("T_task_id")
+	T_task_type, _ := c.GetInt("T_task_type", 0)
+
+	var cnt int64
+	List, cnt := Task.Read_TaskTime_List(T_task_id, T_task_type)
+
+	r_jsons.List = List
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskController) TaskTimeAdd() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	dc := Device.DeviceClass{
+		T_uuid:  User_r.T_uuid,
+		T_State: 1,
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "任务暂停", "暂停申请", dc)
+
+	T_task_id := c.GetString("T_task_id")
+
+	T_task_type, _ := c.GetInt("T_task_type", 0) // 公司名称
+	T_aaa := c.GetString("T_aaa")
+
+	var_ := Task.TaskTime{
+		T_task_id:    T_task_id,
+		T_task_type:  T_task_type,
+		T_uuid:       User_r.T_uuid,
+		T_remarks:    T_aaa,
+		T_start_time: time.Now().Format("2006-01-02 15:04:05"),
+	}
+	List, _ := Task.Read_TaskTime_List(T_task_id, T_task_type)
+	if len(List) > 0 {
+		if len(List[len(List)-1].T_end_time) == 0 {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "上一个任务还没结束!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	is := Task.Add_TaskTime(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务暂停", "暂停申请", var_)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务暂停", "暂停申请", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskController) TaskTimeEnd() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	dc := Device.DeviceClass{
+		T_uuid:  User_r.T_uuid,
+		T_State: 1,
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "任务暂停", "暂停结束", dc)
+
+	Id, _ := c.GetInt("Id", 0)
+
+	TaskTime_r, is := Task.Read_TaskTime_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	TaskTime_r.T_end_time = time.Now().Format("2006-01-02 15:04:05")
+	is = Task.Update_TaskTime(TaskTime_r, "T_end_time")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, TaskTime_r.T_task_id, "任务暂停", "暂停结束", TaskTime_r)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务暂停", "暂停结束", TaskTime_r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: TaskTime_r.T_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 列表 - 统计排名
+func (c *TaskController) StatisticalRanking() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_power, _ := c.GetInt("T_power", 0) // 5	数据采集工程师   6	验证报告工程师
+	type Admin_T struct {
+		T_name string
+
+		T_scheme           int    // 实施方案
+		T_scheme_returnnum int    // 退回
+		T_scheme_overnum   int    // 超时
+		T_scheme_log       string // 日志
+
+		T_collection           int    // 数据采集
+		T_collection_returnnum int    // 退回
+		T_collection_overnum   int    // 超时
+		T_collection_log       string // 日志
+
+		T_reporting           int    // 报告编写
+		T_reporting_returnnum int    // 退回
+		T_reporting_overnum   int    // 超时
+		T_reporting_log       string // 日志
+
+		T_rejectdnum int // 驳回数量
+
+	}
+
+	var Admin_T_List []Admin_T
+	Admin_List := Account.Read_Admin_List_ALL_T_power(T_power)
+	for _, A := range Admin_List {
+		Admin_t := Admin_T{T_name: A.T_name}
+
+		// 方案
+		Task_List := Task.Read_UserTask_StatisticalRanking(A.T_uuid, "T_scheme") //T_scheme   T_collection   T_reporting
+		for _, T := range Task_List {
+			if len(T.T_scheme_end_time) > 0 {
+				if is, _ := lib.IsInCurrentMonth(T.T_scheme_end_time); !is {
+					continue // 不是本月
+				}
+				Admin_t.T_scheme += 1
+				Admin_t.T_scheme_log += T.T_name
+				// 退回
+				if T.T_scheme_return_times > 0 {
+					Admin_t.T_scheme_returnnum += T.T_scheme_return_times
+					Admin_t.T_scheme_log += " | 退回" + lib.To_string(int(T.T_scheme_return_times))
+				}
+				// 超时
+				if T.T_scheme_overtime > 0 {
+					Admin_t.T_scheme_overnum += 1
+					Admin_t.T_scheme_log += " | 超时" + lib.ConvertMinutesToDHM(int(T.T_scheme_overtime))
+				}
+				// 驳回
+				if T.T_reject_times > 0 {
+					Admin_t.T_rejectdnum += T.T_reject_times
+					Admin_t.T_scheme_log += " | 驳回" + lib.To_string(int(T.T_reject_times))
+				}
+
+				Admin_t.T_scheme_log += "\n"
+			}
+		}
+		// 实施
+		Task_List = Task.Read_UserTask_StatisticalRanking(A.T_uuid, "T_collection") //T_scheme   T_collection   T_reporting
+		for _, T := range Task_List {
+			if len(T.T_collection_end_time) > 0 {
+				if is, _ := lib.IsInCurrentMonth(T.T_collection_end_time); !is {
+					continue // 不是本月
+				}
+				Admin_t.T_collection += 1
+				Admin_t.T_collection_log += T.T_name
+				// 退回
+				if T.T_collection_return_times > 0 {
+					Admin_t.T_collection_returnnum += T.T_collection_return_times
+					Admin_t.T_collection_log += " | 退回" + lib.To_string(int(T.T_collection_return_times))
+				}
+				// 超时
+				if T.T_collection_overtime > 0 {
+					Admin_t.T_collection_overnum += 1
+					Admin_t.T_collection_log += " | 超时" + lib.ConvertMinutesToDHM(int(T.T_collection_overtime))
+				}
+				// 驳回
+				if T.T_reject_times > 0 {
+					Admin_t.T_rejectdnum += T.T_reject_times
+					Admin_t.T_collection_log += " | 驳回" + lib.To_string(int(T.T_reject_times))
+				}
+
+				Admin_t.T_collection_log += "\n"
+			}
+		}
+		// 报告
+		Task_List = Task.Read_UserTask_StatisticalRanking(A.T_uuid, "T_reporting") //T_scheme   T_collection   T_reporting
+		for _, T := range Task_List {
+			if len(T.T_reporting_end_time) > 0 {
+				if is, _ := lib.IsInCurrentMonth(T.T_reporting_end_time); !is {
+					continue // 不是本月
+				}
+				Admin_t.T_reporting += 1
+				Admin_t.T_reporting_log += T.T_name
+				// 退回
+				if T.T_reporting_return_times > 0 {
+					Admin_t.T_reporting_returnnum += T.T_reporting_return_times
+					Admin_t.T_reporting_log += " | 退回" + lib.To_string(int(T.T_reporting_return_times))
+				}
+				// 超时
+				if T.T_reporting_overtime > 0 {
+					Admin_t.T_reporting_overnum += 1
+					Admin_t.T_reporting_log += " | 超时" + lib.ConvertMinutesToDHM(int(T.T_reporting_overtime))
+				}
+				// 驳回
+				if T.T_reject_times > 0 {
+					Admin_t.T_rejectdnum += T.T_reject_times
+					Admin_t.T_reporting_log += " | 驳回" + lib.To_string(int(T.T_reject_times))
+				}
+				Admin_t.T_reporting_log += "\n"
+			}
+		}
+		Admin_T_List = append(Admin_T_List, Admin_t)
+	}
+
+	var r_jsons lib.R_JSONS
+	r_jsons.List = Admin_T_List
+	r_jsons.Page = 0
+	r_jsons.Page_size = 0
+	r_jsons.Pages = lib.Func_page(int64(0), int64(0))
+	r_jsons.Num = 0
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 复制-
+func (c *TaskController) Copy() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_task_id := c.GetString("T_task_id")
+	r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
+		c.ServeJSON()
+		return
+	}
+	dc := Device.DeviceClass{
+		T_uuid:  User_r.T_uuid,
+		T_State: 1,
+	}
+	T_class_id, is := Device.Add_DeviceClass(dc)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加分类失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "添加", dc)
+	// 查询信息采集信息
+	infoCollection, is := InfoCollection.Read_InfoCollection(r.T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
+		c.ServeJSON()
+		return
+	}
+	var_ := Task.Task{
+		T_Distributor_id:       r.T_Distributor_id,
+		T_InfoCollection_id:    r.T_InfoCollection_id,
+		T_InfoTemplate_id:      infoCollection.T_InfoTemplate_id,
+		T_start_time:           infoCollection.T_start_time, // 项目开始时间使用信息采集开始时间
+		T_class:                int(T_class_id),
+		T_uuid:                 r.T_uuid,
+		T_name:                 T_name,
+		T_VerifyTemplate_class: r.T_VerifyTemplate_class,
+		T_VerifyTemplate_id:    r.T_VerifyTemplate_id,
+		T_deadline:             r.T_deadline,
+		T_scheme:               r.T_scheme,
+		T_collection:           r.T_collection,
+		T_reporting:            r.T_reporting,
+		T_delivery:             r.T_delivery,
+		T_Show:                 1,
+		T_State:                1,
+
+		T_project:         r.T_project,
+		T_province:        r.T_province,
+		T_city:            r.T_city,
+		T_district:        r.T_district,
+		T_province_code:   r.T_province_code,
+		T_city_code:       r.T_city_code,
+		T_district_code:   r.T_district_code,
+		T_category:        r.T_category,
+		T_device_type:     r.T_device_type,
+		T_volume:          r.T_volume,
+		T_verify_type:     r.T_verify_type,
+		T_subject_matter:  T_name,
+		T_temp_range:      r.T_temp_range,
+		T_report_type:     r.T_report_type,
+		T_device_quantity: r.T_device_quantity,
+		T_cnas:            r.T_cnas,
+	}
+	var_.T_report_number, _ = Task.GenerateNextT_report_number(var_.T_device_type)
+	T_paste_task_id, is := Task.Add_Task(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	NatsServer.Create_Local_Table(T_paste_task_id)
+	Task.Redis_Task_T_report_number_DelK(var_.T_report_number) // 删除redis内的任务编号
+
+	// 复制验证模版数据
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(r.T_VerifyTemplate_id, 0, 0)
+	copy_task_Data := VerifyTemplate.Read_VerifyTemplateMapData_List(0, T_task_id, r.T_VerifyTemplate_id, Map_List)
+
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(0, T_paste_task_id, r.T_VerifyTemplate_id, Map_List)
+
+	copyDataMap := make(map[string]string)
+	for _, data := range copy_task_Data {
+		copyDataMap[data.T_name] = data.T_value
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range Data {
+		// 已有值则不复制
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if copyDataMap[v.T_name] == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               v.T_source,
+			T_task_id:              T_paste_task_id,
+			T_VerifyTemplate_id:    r.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: copyDataMap[v.T_name],
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	_, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, 0, "复制", 0, 0, 1)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "复制标签数据", MapDataList)
+
+	// 通知
+	_, company_r := Account.Read_User_ByT_uuid(var_.T_uuid)
+	go wx.WxSend(var_.T_scheme, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_collection, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_reporting, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+	go wx.WxSend(var_.T_delivery, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+
+	// 添加任务操作日志
+	Task.Add_TaskLogs_T(User_r.T_uuid, T_paste_task_id, "任务管理", "复制", var_)
+	System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "复制", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_paste_task_id}
+	c.ServeJSON()
+	return
+}
+
+// 生成报告编号 设备类型+年+季度+递增编号
+func (c *TaskController) GenT_report_number() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_device_type := c.GetString("T_device_type")
+
+	number, err := Task.GenerateNextT_report_number(T_device_type)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: number}
+	c.ServeJSON()
+	return
+}
+
+// 自动填写布点
+func (c *TaskController) Auto_fill_deploy() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	T_source, _ := c.GetInt("T_source")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	verifyTemplate, is := VerifyTemplate.Read_VerifyTemplate(task.T_VerifyTemplate_id)
+	verifyTemplate_R := VerifyTemplate.VerifyTemplateToVerifyTemplate_R(verifyTemplate)
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(task.T_VerifyTemplate_id, T_source, 0)
+	MapData := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, T_task_id, task.T_VerifyTemplate_id, Map_List)
+	T_deploy_list := verifyTemplate_R.T_deploy_list
+	//if len(T_deploy_list) == 0 {
+	//	// 解析设备列表备注的布点
+	//	deviceClassList := Device.Read_DeviceClassList_List_ByT_remark(task.T_class, "")
+	//	for _, v := range deviceClassList {
+	//		splitList := lib.SplitStringSeparator(v.T_remark, "|")
+	//		for _, T_name := range splitList {
+	//			T_deploy_list = append(T_deploy_list, VerifyTemplate.VerifyTemplateDeploy{T_name: T_name})
+	//		}
+	//	}
+	//}
+
+	// 循环查询布点
+	deployMap := make(map[string]string)
+	for _, deploy := range T_deploy_list {
+		deviceClassList := Device.Read_DeviceClassList_List_ByT_remark(task.T_class, deploy.T_name)
+		var snList []string
+		for _, v := range deviceClassList {
+			snList = append(snList, v.T_sn)
+		}
+		deployMap[deploy.T_name] = strings.Join(snList, "|")
+	}
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+
+	for _, v := range MapData {
+		if snList, ok := deployMap[v.T_name]; ok {
+			val := VerifyTemplate.VerifyTemplateMapData{
+				T_source:               v.T_source,
+				T_task_id:              task.T_task_id,
+				T_VerifyTemplate_id:    task.T_VerifyTemplate_id,
+				T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+				T_Required:             v.T_Required,
+				T_Construction:         v.T_Construction,
+				T_flow_sort:            v.T_flow_sort,
+				T_max_time:             v.T_max_time,
+				T_min_time:             v.T_min_time,
+
+				T_value:      snList,
+				T_start_time: v.T_start_time,
+			}
+			MapDataList = append(MapDataList, val)
+		}
+	}
+
+	ids, is := VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, T_source, User_r.T_uuid, 0, 0, 0)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "自动填写", ids)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+// SyncVerifyTemplateMapData 根据标签名称同步模版数据
+func (c *TaskController) SyncVerifyTemplateMapData() {
+	T_copy_task_id := c.GetString("T_copy_task_id")
+	T_paste_task_id := c.GetString("T_paste_task_id")
+	T_source, _ := c.GetInt("T_source")
+	copy_task, is := Task.Read_Task(T_copy_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	paste_task, is := Task.Read_Task(T_paste_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	copy_task_Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(copy_task.T_VerifyTemplate_id, 0, 0)
+	copy_task_Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, T_copy_task_id, copy_task.T_VerifyTemplate_id, copy_task_Map_List)
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(paste_task.T_VerifyTemplate_id, 0, 0)
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, T_paste_task_id, paste_task.T_VerifyTemplate_id, Map_List)
+
+	copyDataMap := make(map[string]string)
+	for _, data := range copy_task_Data {
+		copyDataMap[data.T_name] = data.T_value
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range Data {
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if copyDataMap[v.T_name] == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               v.T_source,
+			T_task_id:              paste_task.T_task_id,
+			T_VerifyTemplate_id:    paste_task.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: copyDataMap[v.T_name],
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	var ids []int64
+	ids, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, 0, "", 0, 0, 0)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Data: ids, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+func (c *TaskController) TaskData_Stat() {
+	StartTime := c.GetString("StartTime")
+	if len(StartTime) > 0 {
+		_, ok := lib.TimeStrToTime(StartTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	EndTime := c.GetString("EndTime")
+	if len(EndTime) > 0 {
+		_, ok := lib.TimeStrToTime(EndTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	} else {
+		EndTime = time.Now().Format("2006-01-02 15:04:05")
+	}
+	T_remark := c.GetString("T_remark")
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if Task_r.T_collection_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+
+	deviceList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", T_remark, 0, 9999)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	var device = make([]Device.DeviceCount, len(deviceList))
+
+	// 创建温度线
+	for i := 0; i < len(deviceList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			//go func(index int, wg *sync.WaitGroup, p *plot.Plot) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceList[index].T_sn, deviceList[index].T_id
+
+			_, r_maps_num := Device.Read_DeviceSensorData_ById_List(sn, StartTime, EndTime, 0, 9999)
+			device[index] = Device.DeviceCount{
+				T_id: id,
+				T_sn: sn,
+				Num:  r_maps_num,
+			}
+			if r_maps_num == 0 {
+				return
+			}
+
+		}(i)
+	}
+	jobGroup.Wait()
+
+	c.Data["json"] = lib.JSONS{Data: device, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// SyncPDFWatermark 同步水印
+func (c *TaskController) SyncPDFWatermark() {
+	List, _ := Task.Read_Task_List_For_Watermark("pdf1")
+	for _, task := range List {
+		GetWatermarkPdf_command(task, task.T_pdf1, "T_pdf1")
+		GetSignaturePdf_command(task, task.T_pdf1, "T_pdf1")
+	}
+	List2, _ := Task.Read_Task_List_For_Watermark("pdf2")
+	for _, task := range List2 {
+		GetWatermarkPdf_command(task, task.T_pdf2, "T_pdf2")
+		GetSignaturePdf_command(task, task.T_pdf2, "T_pdf2")
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}

+ 1481 - 0
controllers/TaskData.go

@@ -0,0 +1,1481 @@
+package controllers
+
+import (
+	"ColdVerify_server/Nats"
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"errors"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/signintech/gopdf"
+	"github.com/xuri/excelize/v2"
+	"log"
+	"math"
+	"os"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+)
+
+type TaskDataController struct {
+	beego.Controller
+}
+
+// 获取-
+func (c *TaskDataController) Extract_TaskData() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	DeviceClass_List := Device.Read_DeviceClassList_List_id(Task_r.T_class)
+	if len(DeviceClass_List) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_Class_id 分类设备列表 为空!"}
+		c.ServeJSON()
+		return
+	}
+
+	logs.Println("----导入 :", DeviceClass_List)
+	// 清空表
+	Task.Truncate_TaskData(Task_r.T_task_id)
+	// 插入 数据
+	for _, v := range DeviceClass_List {
+		logs.Println("---- :", v.T_sn, Task_r.T_task_id, Time_start, Time_end)
+		Task.Import_TaskData(v.T_sn, v.T_id, Task_r.T_task_id, Time_start, Time_end)
+	}
+
+	// 提取数据后 将 当前任务 数据采集 标志 为 1
+	Task_r.T_collection_state = 1
+	if !Task.Update_Task(Task_r, "T_collection_state") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "任务", "修改", Task_r)
+
+	System.Add_UserLogs(user_r.T_uuid, "提取数据", "提取数据"+Task_r.T_name, Task_r.T_task_id+"|"+Time_start+"|"+Time_end)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 后台导出数据
+func (c *TaskDataController) Extract_TaskData_Back() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_task_id := c.GetString("T_task_id")
+
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 采集中
+	if Task_r.T_collection_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据正采集中,请勿重复提交!"}
+		c.ServeJSON()
+		return
+	}
+
+	DeviceClass_List := Device.Read_DeviceClassList_List_id(Task_r.T_class)
+	if len(DeviceClass_List) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "设备列表为空,请先添加设备!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 更新状态为采集中
+	Task_r.T_collection_state = 2
+	if !Task.Update_Task(Task_r, "T_collection_state") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "导出数据失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	resp := Nats.Extract_TaskData_Back{
+		T_uuid:          user_r.T_uuid,
+		Time_start:      Time_start,
+		Time_end:        Time_end,
+		DeviceClassList: DeviceClass_List,
+		Task:            Task_r,
+	}
+	// 后台执行打包数据
+	//b, _ := msgpack.Marshal(&data)
+	//_ = lib.Nats.Publish("ColdVerify_Server_Extract_TaskData_Back", b)
+	go func(resp Nats.Extract_TaskData_Back, Task_r Task.Task) {
+		Task_rname := resp.Task
+		// 清空表
+		Task.Truncate_TaskData(Task_rname.T_task_id)
+
+		//失败重试5次
+		DeviceClassList := new(sync.Map)
+		var count int
+		for _, v := range resp.DeviceClassList {
+			if strings.Contains(v.T_sn, "-") || len(v.T_sn) == 0 {
+				// 从3.0平台导入
+				continue
+			}
+			DeviceClassList.Store(fmt.Sprintf("%s|%s", v.T_sn, v.T_id), 5)
+			//err = Task.Import_TaskData_Back(v.T_sn, v.T_id, resp.Task.T_task_id, resp.Time_start, resp.Time_end)
+			//count++
+			//time.Sleep(5 * time.Second)
+		}
+		DeviceClassList.Range(func(k, v interface{}) bool {
+			count++
+			return true
+		})
+
+		for count > 0 {
+			DeviceClassList.Range(func(k, v any) bool {
+				T_snid := strings.Split(k.(string), "|")
+				T_sn := T_snid[0]
+				T_id := T_snid[1]
+				temp := v.(int)
+				temp--
+				DeviceClassList.Store(k, temp)
+
+				err := Task.Import_TaskData_Back(T_sn, T_id, resp.Task.T_task_id, resp.Time_start, resp.Time_end)
+				if err == nil || strings.Contains(err.Error(), "doesn't exist") {
+					DeviceClassList.Delete(k)
+					count--
+				} else {
+					logs.Error("设备数据同步到任务数据失败", err)
+					DeviceClassList.Delete(k)
+					count--
+				}
+				return true
+			})
+		}
+		// 提取数据后 将 当前任务 数据采集 标志 为 1
+		Task_r.T_collection_state = 1
+		if !Task.Update_Task(Task_r, "T_collection_state") {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+			c.ServeJSON()
+			return
+		}
+
+		err := Task.CorrectionSecond(T_task_id)
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			return
+		}
+
+		// 删除重复数据
+		_, err = Task.DeleteDeduplicate(T_task_id)
+		if err != nil {
+			logs.Error(lib.FuncName(), "sql 删除重复数据失败")
+			return
+		}
+
+	}(resp, Task_r)
+
+	System.Add_UserLogs_T(resp.T_uuid, "任务", "修改", Task_r)
+	System.Add_UserLogs(resp.T_uuid, "提取数据", "提取数据"+Task_r.T_name, Task_r.T_task_id+"|"+resp.Time_start+"|"+resp.Time_end)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TaskDataController) TaskData_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+	T_layout_no := c.GetString("T_layout_no") // 替换之前的T_id
+	if len(T_layout_no) > 0 {
+		T_id = T_layout_no
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if Task_r.T_delivery_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+	// 查询设备列表
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", "", page, 9999)
+	// 保存布局编号和校准证书对应关系
+	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
+	for _, v := range dcList {
+		deviceCertificateMap[v.T_id] = v.T_Certificate_sn
+	}
+
+	var cnt int64
+	List, cnt := Task.Read_TaskData_ById_List(Task_r.T_task_id, T_sn, T_id, Time_start, Time_end, page, page_z)
+	for i := 0; i < len(List); i++ {
+		List[i].T_Certificate_sn = deviceCertificateMap[List[i].T_id]
+	}
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TaskDataController) UserTaskData_List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+	T_layout_no := c.GetString("T_layout_no") // 替换之前的T_id
+	if len(T_layout_no) > 0 {
+		T_id = T_layout_no
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if Task_r.T_delivery_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+
+	if Task_r.T_uuid != User_r.T_uuid {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "无权访问!"}
+		c.ServeJSON()
+		return
+	}
+	if len(Time_start) == 0 {
+		Time_start = Task_r.T_VerifyDeviceDataStartTime
+	}
+	if len(Time_end) == 0 {
+		Time_end = Task_r.T_VerifyDeviceDataEndTime
+	}
+
+	// 查询设备列表
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", "", page, 9999)
+	// 保存布局编号和校准证书对应关系
+	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
+	for _, v := range dcList {
+		deviceCertificateMap[v.T_id] = v.T_Certificate_sn
+	}
+
+	var cnt int64
+	List, cnt := Task.Read_TaskData_ById_List(Task_r.T_task_id, T_sn, T_id, Time_start, Time_end, page, page_z)
+	for i := 0; i < len(List); i++ {
+		List[i].T_Certificate_sn = deviceCertificateMap[List[i].T_id]
+	}
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TaskDataController) TaskDataClass_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if Task_r.T_delivery_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+
+	List := Task.Read_TaskData_ById_ClassList(Task_r.T_task_id)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: List}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskDataController) TaskData_AddS() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	//T_sn|T_id|T_t|T_rh|T_time?
+
+	T_Data := c.GetString("T_Data")
+	if len(T_Data) < 5 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "err T_Data!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_Data_list := strings.Split(T_Data, "?")
+	println(len(T_Data_list), "len(T_Data_list)")
+	var T_Data_list_x = 0
+	for _, v := range T_Data_list {
+		// 2022-08-09 14:25:00|27.7|55.2
+		if len(v) < 5 {
+			println(v, "len(v) < 5")
+			continue
+		}
+		v_list := strings.Split(v, "|")
+		is = Task.Add_TaskData(Task_r.T_task_id, v_list[0], v_list[1], v_list[2], v_list[3], v_list[4])
+		if is {
+			T_Data_list_x += 1
+		}
+	}
+
+	System.Add_UserLogs(user_r.T_uuid, "任务数据", "添加数据"+Task_r.T_name, Task_r.T_task_id+"结果:"+string(len(T_Data_list))+"/"+string(T_Data_list_x)+"|=> "+T_Data)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: strconv.Itoa(T_Data_list_x)}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TaskDataController) TaskData_Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn := c.GetString("T_sn")
+	T_id, _ := c.GetInt("T_id")
+	T_t, _ := c.GetFloat("T_t")
+	T_rh, _ := c.GetFloat("T_rh")
+	T_time := c.GetString("T_time")
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	is = Task.Add_TaskData(Task_r.T_task_id, T_sn, strconv.Itoa(T_id), fmt.Sprintf("%.2f", T_t), fmt.Sprintf("%.2f", T_rh), T_time)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs(user_r.T_uuid, "任务数据", "添加数据"+Task_r.T_name, Task_r.T_task_id+"|"+T_sn+"|"+strconv.Itoa(T_id)+"|"+fmt.Sprintf("%.2f", T_t)+"|"+fmt.Sprintf("%.2f", T_rh)+T_time)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *TaskDataController) TaskData_Up() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_t, err := c.GetFloat("T_t")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_t 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_rh, err := c.GetFloat("T_rh")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_rh 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_time := c.GetString("T_time")
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	is = Task.Up_TaskData(Task_r.T_task_id, strconv.Itoa(Id), fmt.Sprintf("%.2f", T_t), fmt.Sprintf("%.2f", T_rh), T_time)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs(user_r.T_uuid, "任务数据", "修改数据"+Task_r.T_name, Task_r.T_task_id+"|"+strconv.Itoa(Id)+"|"+fmt.Sprintf("%.2f", T_t)+"|"+fmt.Sprintf("%.2f", T_rh)+T_time)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *TaskDataController) TaskData_Del() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	is = Task.Del_TaskData(Task_r.T_task_id, strconv.Itoa(Id))
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs(user_r.T_uuid, "任务数据", "删除"+Task_r.T_name, Task_r.T_task_id+"|"+strconv.Itoa(Id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *TaskDataController) TaskData_Del_t_id() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	is = Task.Del_TaskData_t_id(Task_r.T_task_id, strconv.Itoa(Id))
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs(user_r.T_uuid, "任务数据", "删除"+Task_r.T_name, Task_r.T_task_id+"|"+strconv.Itoa(Id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 - 接口
+func (c *TaskDataController) Export_Data_Excel() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn_str := c.GetString("T_sn_list") //865901058809339,865901058815849,865901058818991,865901058810568
+	//T_id, err := c.GetInt("T_id")
+	//if err != nil {
+	//	T_id = -1
+	//
+	//}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn_list := strings.Split(T_sn_str, ",")
+	DeviceSensor_data_list := []Task.TaskData_{}
+	for _, v := range T_sn_list {
+		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, "", Time_start, Time_end, 1, 9999)
+		DeviceSensor_data_list = append(DeviceSensor_data_list, DeviceSensor_data...)
+	}
+
+	f := excelize.NewFile() // 设置单元格的值
+	// 这里设置表头
+	f.SetCellValue("Sheet1", "A1", "编号")
+	f.SetCellValue("Sheet1", "B1", "SN")
+	f.SetCellValue("Sheet1", "C1", "温度℃")
+	f.SetCellValue("Sheet1", "D1", "湿度%")
+	f.SetCellValue("Sheet1", "E1", "记录时间")
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 7)
+	f.SetColWidth("Sheet1", "B", "B", 20)
+	f.SetColWidth("Sheet1", "C", "C", 10)
+	f.SetColWidth("Sheet1", "D", "D", 10)
+	f.SetColWidth("Sheet1", "E", "E", 22)
+
+	line := 1
+
+	// 循环写入数据
+	for _, v := range DeviceSensor_data_list {
+		line++
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), v.T_id)
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.T_sn)
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), strconv.FormatFloat(float64(v.T_t), 'f', 1, 64))
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), strconv.FormatFloat(float64(v.T_rh), 'f', 1, 64))
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.T_time)
+
+	}
+	logs.Println("DeviceSensor_data:", len(DeviceSensor_data_list))
+
+	lib.Create_Dir("./ofile")
+
+	timeStr := time.Now().Format("20060102150405")
+	// 保存文件
+	if err := f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	if !lib.Pload_qiniu("ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx") {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "oss!"}
+		c.ServeJSON()
+		return
+	}
+	//删除目录
+	//err = os.Remove("ofile/" + timeStr + ".xlsx")
+	//if err != nil {
+	//	logs.Error(lib.FuncName(),err)
+	//}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + timeStr + ".xlsx"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 - 接口
+func (c *TaskDataController) Export_Data_PDF() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn_str := c.GetString("T_sn_list") //865901058809339,865901058815849,865901058818991,865901058810568
+	//T_id, err := c.GetInt("T_id")
+	//if err != nil {
+	//	T_id = -1
+	//
+	//}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", "", 0, 9999)
+	// 查询设备列表
+	// 保存布局编号和校准证书对应关系
+	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
+	for _, v := range dcList {
+		deviceCertificateMap[v.T_id] = v.T_Certificate_sn
+	}
+
+	T_sn_list := strings.Split(T_sn_str, ",")
+	DeviceSensor_data_list := []Task.TaskData_{}
+	for _, v := range T_sn_list {
+		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, "", Time_start, Time_end, 1, 9999)
+		DeviceSensor_data_list = append(DeviceSensor_data_list, DeviceSensor_data...)
+		for i := 0; i < len(DeviceSensor_data_list); i++ {
+			DeviceSensor_data_list[i].T_Certificate_sn = deviceCertificateMap[DeviceSensor_data_list[i].T_id]
+		}
+	}
+
+	//------
+
+	var err error
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
+	//err = GetFont(pdf, "LiberationSerif-Regular.ttf")
+	//if err != nil {
+	//	log.Fatalln(err)
+	//}
+	//err = pdf.SetFont("Ubuntu-L", "", 14)
+	//if err != nil {
+	//	log.Fatalln(err)
+	//}
+
+	err = pdf.AddTTFFont("simsun", "static/fonts/三极行楷简体-粗.ttf")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 204, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+	err = pdf.SetFont("simsun", "", 24)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 205, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+
+	pdf.SetGrayFill(0.5)
+
+	pdf.SetMargins(0, 20, 0, 20)
+	pdf.AddPage()
+
+	//use path
+	//pdf.Image("logo.png", 100, 50, &gopdf.Rect{W: 50, H: 50})
+
+	textw, _ := pdf.MeasureTextWidth(Task_r.T_name)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(40)
+	pdf.Text(Task_r.T_name)
+
+	// 线
+	pdf.SetLineWidth(2)
+	pdf.SetLineType("dashed")
+	pdf.Line(10, 60, 585, 60)
+
+	err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 206, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+	err = pdf.SetFont("wts", "", 12)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 207, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+	t_ := Time_start + " / " + Time_end
+	if len(Time_start) == 0 {
+		t_ = "所有数据"
+	}
+	//fmt.Sprintf(" %.1f ", v.T_t)
+	lib.RectFillColor(pdf, "提取数据时间段["+t_+"]", 14, 22, 80, 550, 40, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+	lib.RectFillColor(pdf, "布局编号", 12, 22, 120, 80, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	lib.RectFillColor(pdf, "证书编号", 12, 92, 120, 150, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	lib.RectFillColor(pdf, "温度℃", 12, 242, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	lib.RectFillColor(pdf, "湿度%", 12, 342, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+	//lib.RectFillColor(pdf, "温度范围", 12, 272, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	//lib.RectFillColor(pdf, "湿度范围", 12, 362, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	lib.RectFillColor(pdf, "记录时间", 12, 442, 120, 130, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+	var y float64 = 140
+
+	err = pdf.SetFont("wts", "", 10)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 207, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+	for _, v := range DeviceSensor_data_list {
+		//text := fmt.Sprintf(" %d ", i+1)
+		var textH float64 = 25 // if text height is 25px.
+		pdf.SetNewY(y, textH)
+		y = pdf.GetY()
+		//pdf.SetX(x) // must after pdf.SetNewY() called.
+		//err = pdf.Text(text)
+		//if err != nil {
+		//	log.Fatalln(err)
+		//}
+
+		T_t := fmt.Sprintf(" %.1f ", v.T_t)
+		T_rh := fmt.Sprintf(" %.1f ", v.T_rh)
+		T_time := fmt.Sprintf("%s", v.T_time)
+
+		lib.RectFillColor(pdf, v.T_id, 10, 22, y, 80, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		lib.RectFillColor(pdf, v.T_Certificate_sn, 10, 92, y, 150, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		lib.RectFillColor(pdf, T_t, 10, 242, y, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		lib.RectFillColor(pdf, T_rh, 10, 342, y, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		lib.RectFillColor(pdf, T_time, 10, 442, y, 130, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		y += 20
+	}
+
+	timeStr := "ofile/" + time.Now().Format("20060102150405") + ".pdf"
+
+	err = pdf.WritePdf(timeStr)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 207, Msg: "ok!", Data: err}
+		c.ServeJSON()
+		return
+	}
+
+	if !lib.Pload_qiniu(timeStr, timeStr) {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "oss!"}
+		c.ServeJSON()
+		return
+	}
+	//删除目录
+	err = os.Remove(timeStr)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: "https://bzdcoldverifyoss.baozhida.cn/" + timeStr}
+	c.ServeJSON()
+	return
+
+}
+
+// 列表 - 接口
+func (c *TaskDataController) Check() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	type R_JSONS struct {
+		T_sn               string // SN
+		T_id               string // 编号
+		T_unm              int    // 数据量
+		T_time_interval    int64  // 时间间隔
+		Time_start         string // 开始
+		Time_end           string //  结束
+		Result             int    //  200 OK, 201 可以补 , 202 不能补
+		Result_str         string //  提示内容
+		Result_Time_start  string //  2022-8-05 21:01
+		Result_Time_defect int64  //  缺失时间间隔
+	}
+	var r_jsons []R_JSONS
+
+	List := Task.Read_TaskData_ById_ClassList(Task_r.T_task_id)
+	for _, v := range List {
+		var r_json R_JSONS
+		r_json.T_sn = v.T_sn
+
+		r_json.Result = 200
+
+		DeviceSensor_data := Task.Read_TaskData_ById_List_(Task_r.T_task_id, v.T_sn)
+		r_json.T_unm = len(DeviceSensor_data)
+
+		if r_json.T_unm > 2 {
+			r_json.T_id = DeviceSensor_data[0].T_id
+			r_json.Time_end = DeviceSensor_data[len(DeviceSensor_data)-1].T_time
+			r_json.Time_start = DeviceSensor_data[0].T_time
+
+			formatTime_a, _ := time.Parse("2006-1-2 15:04", DeviceSensor_data[0].T_time)
+			formatTime_b, _ := time.Parse("2006-1-2 15:04", DeviceSensor_data[1].T_time)
+			formatTime_x := formatTime_b.Unix() - formatTime_a.Unix()
+			r_json.T_time_interval = formatTime_x
+			println("formatTime_x:", v.T_id, v.T_sn, formatTime_x)
+			if formatTime_x > 60*30 || formatTime_x < 60 {
+				r_json.Result = 202
+				r_json.Result_str = "数据异常(数据的第一个时间与第二个时间相差 " + strconv.FormatInt(formatTime_x, 10) + "秒),必须大于60秒,小于30分钟"
+				r_jsons = append(r_jsons, r_json)
+				continue
+			}
+			for data_i := 2; data_i < len(DeviceSensor_data); data_i++ {
+				formatTime_a = formatTime_b
+				formatTime_b, _ = time.Parse("2006-1-2 15:04", DeviceSensor_data[data_i].T_time)
+				formatTime_ := formatTime_b.Unix() - formatTime_a.Unix()
+				println("formatTime_x-:", formatTime_)
+				if formatTime_ < formatTime_x {
+					r_json.Result = 202
+					r_json.Result_str = "开始时间:" + DeviceSensor_data[data_i-1].T_time + "  离下一条时间间隔:" + strconv.FormatInt(formatTime_, 10) + "秒,间隔小于时间间隔,不能自动补充"
+					break
+				}
+				if formatTime_x != formatTime_ {
+					if formatTime_ > 60*30 {
+						r_json.Result = 202
+						r_json.Result_str = "开始时间:" + DeviceSensor_data[data_i-1].T_time + "  离下一条时间间隔:" + strconv.FormatInt(formatTime_, 10) + "秒,相差时间大于30分钟,不能自动补充"
+						break
+					}
+					r_json.Result = 201
+					r_json.Result_str = "开始时间:" + DeviceSensor_data[data_i-1].T_time + "  离下一条时间间隔:" + strconv.FormatInt(formatTime_, 10) + "秒"
+					r_json.Result_Time_start = DeviceSensor_data[data_i-1].T_time
+					r_json.Result_Time_defect = formatTime_
+					println(r_json.Result_str)
+					break
+				}
+
+			}
+		} else {
+			r_json.Result = 202
+			r_json.Result_str = "数据量太少 必须大于 2条以上!"
+		}
+
+		r_jsons = append(r_jsons, r_json)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+func (c *TaskDataController) TaskData_Temperature_Pdf() {
+	// 验证登录管理员 User_is, User_r
+	_, User_Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	// 验证登录用户 User_is, User_r
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	if !User_Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+
+	T_task_id := c.GetString("T_task_id")
+
+	err := c.TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, Task.Temperature)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+}
+func (c *TaskDataController) TaskData_Humidity_Pdf() {
+	// 验证登录管理员 User_is, User_r
+	_, User_Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	// 验证登录用户 User_is, User_r
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	if !User_Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+
+	T_task_id := c.GetString("T_task_id")
+
+	err := c.TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, Task.Humidity)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+}
+func (c *TaskDataController) TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, T_type string) (err error) {
+
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		return errors.New("T_task_id 错误!")
+	}
+	user, is := Account.Read_User(Task_r.T_uuid)
+	if !is {
+		return errors.New("Task uuid 错误!")
+	}
+
+	if Task_r.T_delivery_state == 2 {
+		return errors.New("数据采集中,请稍后!")
+	}
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
+
+	err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf")
+	if err != nil {
+		return
+	}
+	err = pdf.SetFont("wts", "", 15)
+	if err != nil {
+		return
+	}
+
+	pdf.SetGrayFill(0.5)
+
+	pdf.SetMargins(0, 20, 0, 20)
+	pdf.AddPage()
+	imgH, _ := gopdf.ImageHolderByPath("./static/logo.jpg")
+	err = pdf.ImageByHolder(imgH, 10, 10, &gopdf.Rect{W: 93, H: 32})
+	name := user.T_name
+
+	var y float64 = 40
+	textw, _ := pdf.MeasureTextWidth(name)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(name)
+
+	y += 20
+	T_type_name := ""
+	if T_type == Task.Temperature {
+		T_type_name = "温度"
+	}
+	if T_type == Task.Humidity {
+		T_type_name = "湿度"
+	}
+	title := Task_r.T_name + T_type_name + "验证数据"
+	textw, _ = pdf.MeasureTextWidth(title)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(title)
+
+	// 查询设备列表
+	//dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, T_id, "", 0, 9999)
+	dcList := []Device.DeviceClassList{}
+	dataList, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, T_sn, T_id, Time_start, Time_end, 0, 9999)
+	dataListMap := make(map[string][]Task.TaskData_)
+	dcListMap := make(map[string]string)
+	dataMap := make(map[string]string)
+	timeMap := make(map[string]bool)
+	for _, data := range dataList {
+		dataListMap[data.T_id] = append(dataListMap[data.T_id], data)
+		if _, ok := dcListMap[data.T_id]; !ok {
+			dcListMap[data.T_id] = data.T_sn
+		}
+		k := fmt.Sprintf("%s,%s", data.T_time, data.T_id)
+		if T_type == Task.Temperature {
+			dataMap[k] = fmt.Sprintf("%.1f", data.T_t)
+		}
+		if T_type == Task.Humidity {
+			dataMap[k] = fmt.Sprintf("%.1f", data.T_rh)
+		}
+		if _, ok := timeMap[data.T_time]; !ok {
+			timeMap[data.T_time] = true
+		}
+	}
+	for id, sn := range dcListMap {
+		dcList = append(dcList, Device.DeviceClassList{T_id: id, T_sn: sn})
+	}
+	for id, list := range dataListMap {
+		sort.Slice(list, func(i, j int) bool {
+			return list[i].T_time < list[j].T_time
+		})
+		dataListMap[id] = list
+	}
+
+	var timeList []string
+	for k, _ := range timeMap {
+		timeList = append(timeList, k)
+	}
+	sort.Slice(timeList, func(i, j int) bool {
+		return timeList[i] < timeList[j]
+	})
+	err = pdf.SetFont("wts", "", 12)
+	if err != nil {
+		return
+	}
+	if len(timeList) > 0 {
+		y += 20
+		timeStr := fmt.Sprintf("%s - %s", timeList[0], timeList[len(timeList)-1])
+		textw, _ = pdf.MeasureTextWidth(timeStr)
+		pdf.SetX((595 / 2) - (textw / 2))
+		pdf.SetY(y)
+		pdf.Text(timeStr)
+	}
+
+	//y += 20
+	var x float64 = 10
+	var w float64 = 120
+
+	err = pdf.SetFont("wts", "", 10)
+	if err != nil {
+		return
+	}
+	idWidthMap := make(map[string]float64)
+	dcList1 := make([]Device.DeviceClassList, 0)
+	for _, list := range dcList {
+		idw, _ := pdf.MeasureTextWidth(list.T_id)
+		if !lib.IsNumeric(list.T_id) {
+			dcList1 = append(dcList1, list)
+		}
+		if idw > 20 {
+			idWidthMap[list.T_id] = idw + 12
+		} else {
+			idWidthMap[list.T_id] = 30.3
+		}
+	}
+	sort.Slice(dcList1, func(i, j int) bool {
+		return dcList1[i].T_id < dcList1[j].T_id
+	})
+	dcList2 := listSubtract(dcList, dcList1)
+	// 获取探头时间
+	var timeList2 []string
+	timeMap2 := make(map[string]struct{})
+	for _, list := range dcList2 {
+		dataList2, ok := dataListMap[list.T_id]
+		if ok {
+			for _, data := range dataList2 {
+				if _, ok = timeMap2[data.T_time]; !ok {
+					timeMap2[data.T_time] = struct{}{}
+				}
+			}
+		}
+	}
+	for k, _ := range timeMap2 {
+		timeList2 = append(timeList2, k)
+	}
+	sort.Slice(timeList2, func(i, j int) bool {
+		return timeList2[i] < timeList2[j]
+	})
+	var temp int
+	for index, dc := range dcList1 {
+
+		dataList2, _ := dataListMap[dc.T_id]
+
+		err = pdf.SetFont("wts", "", 15)
+		if err != nil {
+			return
+		}
+		y += 30
+
+		var textH float64 = 20 // if text height is 25px.
+		if y >= 790 {
+			addStampImage(pdf, 455, y-150)
+			// AddWatermark(Task_r, pdf)
+			pdf.AddPage()
+			y = 30
+		} else {
+			if index > 0 {
+				y += 10
+			}
+		}
+
+		textw, _ = pdf.MeasureTextWidth(dc.T_id)
+		pdf.SetX((595 / 2) - (textw / 2))
+		pdf.SetY(y)
+		pdf.Text(dc.T_id)
+		y += 10
+
+		err = pdf.SetFont("wts", "", 10)
+		if err != nil {
+			return
+		}
+
+		if y < 790 {
+			x = 10
+			for i := 0; i < 4; i++ {
+				w = 113.8
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30
+				lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		} else {
+			addStampImage(pdf, 455, y-150)
+			// AddWatermark(Task_r, pdf)
+			pdf.AddPage()
+			y = 20
+			x = 10
+			for i := 0; i < 4; i++ {
+				w = 113.8
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30
+				lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		}
+
+		for i := 0; i < len(dataList2); i++ {
+			if y > 790 {
+				addStampImage(pdf, 455, y-130)
+				// AddWatermark(Task_r, pdf)
+				pdf.AddPage()
+				y = pdf.GetY()
+				x = 10
+				for k := 0; k < 4; k++ {
+					w = 113.8
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+					w = 30
+					lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+			}
+
+			temp = i % 4
+			// 每页添加表头
+			if y == 20 && temp == 0 {
+				x = 10
+				for k := 0; k < 4; k++ {
+					w = 113.8
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+					w = 30
+					lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+			}
+
+			x = 10 + 143.8*float64(temp)
+			w = 113.8
+
+			lib.RectFillColor(pdf, dataList2[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30
+			if T_type == Task.Temperature {
+				lib.RectFillColor(pdf, fmt.Sprintf("%.1f", dataList2[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			if T_type == Task.Humidity {
+				lib.RectFillColor(pdf, fmt.Sprintf("%.1f", dataList2[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			//if y > 760 {
+			//	fmt.Println("=====y:", y)
+			//}
+			//if y > 790 {
+			//	addStampImage(pdf, 455, y-130)
+			//}
+			if temp == 3 {
+				y += 20
+				pdf.SetNewY(y, textH)
+				y = pdf.GetY()
+			}
+
+		}
+
+	}
+
+	if len(dcList2) > 0 {
+		if temp != 3 {
+			y += 20
+		}
+		y += 40
+	}
+	sort.Slice(dcList2, func(i, j int) bool {
+		return dcList2[i].T_id < dcList2[j].T_id
+	})
+	chunks := splitData(dcList2, 454.5, idWidthMap)
+	for i, list := range chunks {
+
+		if i > 0 {
+			y += 40
+		}
+		if y < 790 {
+			x = 10
+			w = 120.7
+			lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30.3
+			for _, v2 := range list {
+				w = idWidthMap[v2.T_id]
+				lib.RectFillColor(pdf, v2.T_id, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		} else {
+			addStampImage(pdf, 455, y-150)
+			// AddWatermark(Task_r, pdf)
+			pdf.AddPage()
+			y = 20
+		}
+
+		StampImageX := x
+		for j, t := range timeList2 {
+			if j > 0 {
+				y += 20
+			}
+
+			if y >= 790 {
+				addStampImage(pdf, StampImageX-130, y-130)
+				// AddWatermark(Task_r, pdf)
+				pdf.AddPage()
+				y = pdf.GetY()
+				x = 10
+				w = 120.7
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30.3
+				for _, v2 := range list {
+					w = idWidthMap[v2.T_id]
+					lib.RectFillColor(pdf, v2.T_id, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+				x = 10
+			}
+			x = 10
+			if y == 20 {
+				w = 120.7
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30.3
+				for _, v2 := range list {
+					w = idWidthMap[v2.T_id]
+					lib.RectFillColor(pdf, v2.T_id, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+				x = 10
+			}
+			w = 120.7
+			lib.RectFillColor(pdf, t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30.3
+			for _, v := range list {
+				t_t := dataMap[fmt.Sprintf("%s,%s", t, v.T_id)]
+				w = idWidthMap[v.T_id]
+				lib.RectFillColor(pdf, t_t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			StampImageX = x
+		}
+	}
+
+	if y <= 790 {
+		if y < 150 {
+			y = 20
+		} else {
+			y = y - 145
+		}
+		x = x - 135
+		if len(dcList2) == 0 {
+			x = 455
+		}
+		addStampImage(pdf, x, y)
+		// AddWatermark(Task_r, pdf)
+
+	} else if y > 790 && len(dcList2) == 0 {
+		if y < 150 {
+			y = 20
+		} else {
+			y = y - 145
+		}
+		addStampImage(pdf, 455, y)
+
+	}
+	filename := time.Now().Format("20060102150405") + ".pdf"
+	timeStr := "ofile/" + T_type_name + filename
+
+	err = pdf.WritePdf(timeStr)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	// 上传 OSS
+	//url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr, timeStr)
+	//url, is := NatsServer.Qiniu_UploadFile("/Users/zoie/work/bzd_project/ColdVerify_server/"+timeStr, timeStr)
+	//if !is {
+	//	err = errors.New("oss!")
+	//	return
+	//}
+
+	defer func() {
+		//删除目录
+		os.Remove(timeStr)
+	}()
+
+	c.Ctx.Output.Download(timeStr)
+	//c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	//c.ServeJSON()
+	//return
+	return nil
+
+}
+
+// 添加公章图片
+func addStampImage(pdf *gopdf.GoPdf, x, y float64) {
+	imagePath := "./static/commonSeal.jpg"
+	if x < 10 {
+		x = 10
+	}
+	if y < 20 {
+		y = 20
+	}
+	err := pdf.Image(imagePath, x, y, &gopdf.Rect{W: 123, H: 128.6})
+	if err != nil {
+		log.Print(err.Error())
+	}
+}
+func listSubtract(sliceA, sliceB []Device.DeviceClassList) []Device.DeviceClassList {
+	// 创建一个集合用于存储 sliceB 的元素
+	elementsToRemove := make(map[string]Device.DeviceClassList)
+	for _, item := range sliceB {
+		elementsToRemove[item.T_id] = item
+	}
+
+	// 构建新切片,包含 sliceA 中不在 elementsToRemove 中的元素
+	var result []Device.DeviceClassList
+	for _, item := range sliceA {
+		if _, found := elementsToRemove[item.T_id]; !found {
+			result = append(result, item)
+		}
+	}
+
+	return result
+}
+
+func splitData(data []Device.DeviceClassList, threshold float64, idWidthMap map[string]float64) [][]Device.DeviceClassList {
+	var result [][]Device.DeviceClassList
+	var currentBatch []Device.DeviceClassList
+	var currentSum float64
+
+	for _, item := range data {
+		wd := idWidthMap[item.T_id]
+		if currentSum+wd > threshold+0.1 {
+			// 当前批次超过阈值,切分
+			result = append(result, currentBatch)
+			// 重置当前批次和当前总和
+			currentBatch = []Device.DeviceClassList{}
+			currentSum = 0
+		}
+		currentBatch = append(currentBatch, item)
+		currentSum += wd
+	}
+
+	// 添加最后一批
+	if len(currentBatch) > 0 {
+		result = append(result, currentBatch)
+	}
+
+	return result
+}

+ 220 - 0
controllers/Template.go

@@ -0,0 +1,220 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Template"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+)
+
+type TemplateController struct {
+	beego.Controller
+}
+
+// 二级页面
+func (c *TemplateController) List_() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, _ := c.GetInt("Id")
+	c.Data["Id"] = Id
+	if Id > 0 {
+		c.Data["Date"], _ = Template.Read_Template_ById(Id)
+		//c.Data["FormulaList"] = Formula.ReadFormulaListByid_List(id)
+	}
+
+	c.TplName = "Template/Template-.html"
+}
+
+// 获取-
+func (c *TemplateController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Template.Read_Template_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *TemplateController) List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_class, _ := c.GetInt("T_class")
+
+	var cnt int64
+	List, cnt := Template.Read_Template_List(T_name, T_class, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *TemplateController) Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_class, _ := c.GetInt("T_class")
+	//T_img := c.GetString("T_img")
+	//T_int, _ := c.GetInt("T_int")
+	//T_text := c.GetString("T_text")
+
+	var_ := Template.Template{
+		T_name:  T_name,
+		T_class: T_class,
+		T_State: 1,
+	}
+
+	Id, is := Template.Add_Template(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "模版管理", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *TemplateController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_class, T_class_err := c.GetInt("T_class")
+	//T_img := c.GetString("T_img")
+	//T_int, _ := c.GetInt("T_int")
+	//T_text := c.GetString("T_text")
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Template.Read_Template_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if T_class_err == nil {
+		r.T_class = T_class
+	}
+
+	// .......
+	if !Template.Update_Template(r, "T_name", "T_class") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "模版管理", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *TemplateController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if r, is := Template.Read_Template_ById(Id); is {
+		if !Template.Delete_Template(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "模版管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}

+ 72 - 0
controllers/UpFile.go

@@ -0,0 +1,72 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"crypto/md5"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"math/rand"
+	"os"
+	"path"
+	"time"
+)
+
+type UpFileController struct {
+	beego.Controller
+}
+
+func (c *UpFileController) UpFile() {
+
+	f, h, _ := c.GetFile("file") //获取上传的文件
+	ext := path.Ext(h.Filename)
+	//验证后缀名是否符合要求
+	var AllowExtMap map[string]bool = map[string]bool{
+		".jpg":  true,
+		".jpeg": true,
+		".png":  true,
+		".pdf":  true,
+	}
+	if _, ok := AllowExtMap[ext]; !ok {
+		c.Ctx.WriteString("后缀名不符合上传要求")
+		return
+	}
+	//创建目录
+	uploadDir := conf.Oss_file // + time.Now().Format("2006/01/02/")
+	err := os.MkdirAll(uploadDir, 777)
+	if err != nil {
+		c.Ctx.WriteString(fmt.Sprintf("%v", err))
+		return
+	}
+	//构造文件名称
+	rand.Seed(time.Now().UnixNano())
+	randNum := fmt.Sprintf("%d", rand.Intn(9999)+1000)
+	hashName := md5.Sum([]byte(time.Now().Format("2006_01_02_15_04_05_") + randNum))
+
+	fileName := fmt.Sprintf("%x", hashName) + ext
+	//this.Ctx.WriteString(  fileName )
+
+	fpath := uploadDir + fileName
+	println(fpath)
+	defer f.Close() //关闭上传的文件,不然的话会出现临时文件不能清除的情况
+	err = c.SaveToFile("file", fpath)
+	if err != nil {
+		c.Ctx.WriteString(fmt.Sprintf("%v", err))
+	}
+	c.Ctx.WriteString("{\n  \"code\": 0\n  ,\"msg\": \"ok!\"\n  ,\"data\": {\n    \"src\": \"" + conf.Oss + fileName + "\"\n  }\n}       ")
+}
+
+// 列表 -
+func (c *UpFileController) ConfigUpFileToken() {
+	// 验证登录 User_r, User_x
+	//b_, User_r, _ := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	//if !b_ {
+	//	c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: lib.UploadToken(c.GetString("T_suffix"))}
+	c.ServeJSON()
+	return
+}

+ 565 - 0
controllers/User.go

@@ -0,0 +1,565 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Distributor"
+	"ColdVerify_server/models/System"
+	"math"
+
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+type UserController struct {
+	beego.Controller
+}
+
+// 获取-
+func (c *UserController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, err := c.GetInt("Id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r, is := Account.Read_User_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *UserController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	var T_Distributor_id string
+	// 优先使用经销商id
+	if len(User_r.T_Distributor_id) > 0 {
+		T_Distributor_id = User_r.T_Distributor_id
+	} else {
+		T_Distributor_id = c.GetString("T_Distributor_id")
+	}
+
+	var cnt int64
+	distributorList := Distributor.Read_Distributor_List_ALL("")
+	distributorMap := Distributor.DistributorListToMap(distributorList)
+	List, cnt := Account.Read_User_List(T_Distributor_id, T_name, page, page_z, distributorMap)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *UserController) Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	//T_power, _ := c.GetInt("T_power")
+	T_name := c.GetString("T_name")
+	T_pass := c.GetString("T_pass")
+	T_passstr := c.GetString("T_passstr")
+	T_Distributor_id := c.GetString("T_Distributor_id")
+	T_pid, _ := c.GetInt("T_pid") // 父级ID
+
+	// 如果T_pid大于0,则需要获取该T_pid的公司的T_Distributor_id
+	if T_pid > 0 {
+		parentUser, is := Account.Read_User_ById(T_pid)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "父级公司不存在!"}
+			c.ServeJSON()
+			return
+		}
+		T_Distributor_id = parentUser.T_Distributor_id
+	} else if len(user_r.T_Distributor_id) > 0 {
+		T_Distributor_id = user_r.T_Distributor_id
+	}
+
+	var_ := Account.User{
+		//T_power:   T_power,
+		T_name:           T_name,
+		T_pass:           T_pass,
+		T_passstr:        T_passstr,
+		T_Show:           1,
+		T_State:          1,
+		T_Distributor_id: T_Distributor_id, // 经销商id
+		T_pid:            T_pid,            // 父级ID
+	}
+
+	if _, is := Account.Read_UserByT_name(T_name); is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "公司名称重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, is := Account.Add_User(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 更新路径
+	err := Account.UpdateUserPath(int(Id))
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "更新路径失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *UserController) Up() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	//T_power, T_power_err := c.GetInt("T_power")
+	T_name := c.GetString("T_name")
+	T_pass := c.GetString("T_pass")
+	T_passstr := c.GetString("T_passstr")
+	T_Show, T_Show_err := c.GetInt("T_Show")
+
+	T_uuid := c.GetString("T_uuid")
+	r, is := Account.Read_User(T_uuid)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if _, is := Account.Read_UserByT_name(T_name); is && r.T_name != T_name {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "公司名称重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	//if T_power_err == nil {
+	//	r.T_power = T_power
+	//}
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(T_pass) > 0 {
+		r.T_pass = T_pass
+	}
+	if len(T_passstr) > 0 {
+		r.T_passstr = T_passstr
+	}
+	if T_Show_err == nil {
+		r.T_Show = T_Show
+	}
+
+	// .......
+	if !Account.Update_User(r, "T_name", "T_pass", "T_passstr", "T_Show") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 更新路径
+	err := Account.UpdateUserPath(r.Id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "更新路径失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *UserController) Del() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_uuid := c.GetString("T_uuid")
+
+	if r, is := Account.Read_User(T_uuid); is {
+		if !Account.Delete_User_(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *UserController) UpPassword() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_oldpass := c.GetString("T_oldpass")
+	T_pass := c.GetString("T_pass")
+	T_passstr := c.GetString("T_passstr")
+
+	if T_oldpass != user_r.T_pass {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "旧密码错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_pass) > 0 {
+		user_r.T_pass = T_pass
+	}
+	if len(T_passstr) > 0 {
+		user_r.T_passstr = T_passstr
+	}
+
+	// .......
+	if !Account.Update_User(user_r, "T_pass", "T_passstr") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "修改密码", user_r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 列表 -
+func (c *UserController) Signature_List() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_type, _ := c.GetInt("T_type")
+
+	var cnt int64
+	var distributorMap map[string]string
+	//distributorList := Distributor.Read_Distributor_List_ALL("")
+	//distributorMap := Distributor.DistributorListToMap(distributorList)
+	List, cnt := Account.Read_UserSignature_List(user_r.T_uuid, T_name, T_type, page, page_z, distributorMap)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *UserController) Signature_Add() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_signature := c.GetString("T_signature")
+	T_type, _ := c.GetInt("T_type")
+	var is_seal bool
+	if T_type == 2 {
+		is_seal = true
+	}
+
+	signature_pdf, err := lib.ProcessImage(T_signature, is_seal)
+	if err != nil {
+		signature_pdf = T_signature
+	}
+
+	if _, is := Account.Read_UserSignatureByT_name(user_r.T_uuid, T_name); is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "名称重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := Account.UserSignature{
+		T_name:           T_name,
+		T_signature:      signature_pdf,
+		T_State:          1,
+		T_uuid:           user_r.T_uuid,
+		T_Distributor_id: user_r.T_Distributor_id,
+		T_type:           T_type,
+	}
+	Id, is := Account.Add_UserSignature(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "添加签名", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *UserController) Signature_Up() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, _ := c.GetInt("Id")
+	T_name := c.GetString("T_name")
+	T_signature := c.GetString("T_signature")
+	T_type, _ := c.GetInt("T_type")
+	var is_seal bool
+	if T_type == 2 {
+		is_seal = true
+	}
+
+	signature_pdf, err := lib.ProcessImage(T_signature, is_seal)
+	if err != nil {
+		signature_pdf = T_signature
+	}
+
+	r, is := Account.Read_UserSignature_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if r2, is := Account.Read_UserSignatureByT_name(user_r.T_uuid, T_name); is && r2.Id != r.Id {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "名称重复!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	//if T_power_err == nil {
+	//	r.T_power = T_power
+	//}
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(signature_pdf) > 0 {
+		r.T_signature = signature_pdf
+	}
+
+	// .......
+	if !Account.Update_UserSignature(r, "T_name", "T_signature") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "修改签名", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *UserController) Signature_Del() {
+	user_r, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Id, _ := c.GetInt("Id")
+
+	r, is := Account.Read_UserSignature_ById(Id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if !Account.Delete_UserSignature(r) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "删除签名", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+
+	return
+}
+
+// 树形结构展示公司列表
+func (c *UserController) TreeList() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var T_Distributor_id string
+	// 优先使用经销商id
+	if len(User_r.T_Distributor_id) > 0 {
+		T_Distributor_id = User_r.T_Distributor_id
+	} else {
+		T_Distributor_id = c.GetString("T_Distributor_id")
+	}
+
+	// 获取名称搜索参数
+	T_name := c.GetString("T_name")
+
+	// 获取分销商映射
+	distributorList := Distributor.Read_Distributor_List_ALL("")
+	distributorMap := Distributor.DistributorListToMap(distributorList)
+
+	// 获取所有用户数据(支持名称过滤)
+	var users []Account.User_R
+	var err error
+	if len(T_name) > 0 {
+		users, err = Account.Read_User_Tree_List_WithFilter(T_Distributor_id, T_name, distributorMap)
+	} else {
+		users, err = Account.Read_User_Tree_List(T_Distributor_id, distributorMap)
+	}
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取数据失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 构建树形结构
+	tree := Account.BuildUserTree(users)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: tree}
+	c.ServeJSON()
+	return
+}
+
+// 移动公司到另一个公司下面
+func (c *UserController) MoveToParent() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id, err := c.GetInt("T_id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "用户ID错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_pid, err := c.GetInt("T_pid")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "父级ID错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 执行移动操作
+	err = Account.MoveUserToParent(T_id, T_pid)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "移动公司", map[string]interface{}{
+		"Id":          T_id,
+		"newParentId": T_pid,
+	})
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "移动成功!"}
+	c.ServeJSON()
+	return
+}

+ 1406 - 0
controllers/VerifyTemplate.go

@@ -0,0 +1,1406 @@
+package controllers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/Distributor"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"ColdVerify_server/models/VerifyTemplate"
+	"encoding/json"
+	"errors"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type VerifyTemplateController struct {
+	beego.Controller
+	User_r Account.Admin // 登陆的用户
+}
+
+func (c *VerifyTemplateController) Prepare() {
+	GetCookie := c.Ctx.GetCookie("User_tokey")
+	GetString := c.GetString("User_tokey")
+	fmt.Println(c.Ctx.Request.URL.Path)
+	if strings.Contains(c.Ctx.Request.URL.Path, "/VerifyTemplateMapData/Pu") {
+		return
+	}
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(GetCookie, GetString)
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 经销商只能访问列表接口,不能操作
+
+	//if len(User_r.T_Distributor_id) > 0 {
+	//	checkUrl := []string{"Add", "Up", "Del"}
+	//	for _, v := range checkUrl {
+	//		if strings.Contains(c.Ctx.Request.URL.Path, v) {
+	//			c.Data["json"] = lib.JSONS{Code: 202, Msg: "没有操作权限!"}
+	//			c.ServeJSON()
+	//			return
+	//		}
+	//	}
+	//}
+
+	c.User_r = User_r
+}
+
+// 列表 -
+func (c *VerifyTemplateController) List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_class, _ := c.GetInt("T_class")
+	if T_class <= 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+
+	logs.Debug("经销商id", User_r.T_Distributor_id)
+	if len(User_r.T_Distributor_id) > 0 {
+		var cnt int64
+		List, cnt := Distributor.Read_DistributorVerifyTemplate_List(User_r.T_Distributor_id, T_class, T_name, page, page_z)
+		page_size := math.Ceil(float64(cnt) / float64(page_z))
+		r_jsons.List = List
+		r_jsons.Page = page
+		r_jsons.Page_size = int(page_size)
+		r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+		r_jsons.Num = int(cnt)
+
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+		c.ServeJSON()
+		return
+	}
+
+	var cnt int64
+	List, cnt := VerifyTemplate.Read_VerifyTemplate_List(T_class, T_name, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = int(cnt)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *VerifyTemplateController) Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_sort, _ := c.GetInt("T_sort")
+	T_class, _ := c.GetInt("T_class")
+
+	var_ := VerifyTemplate.VerifyTemplate{
+		T_class: T_class,
+		T_name:  T_name,
+		T_sort:  T_sort,
+	}
+
+	Id, is := VerifyTemplate.Add_VerifyTemplate(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *VerifyTemplateController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_sort, T_sort_err := c.GetInt("T_sort")
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+
+	T_scheme := c.GetString("T_scheme")
+	T_reporting := c.GetString("T_reporting")
+	T_inspect := c.GetString("T_inspect")
+	T_marking := c.GetString("T_marking")
+	T_cover := c.GetString("T_cover")
+	T_deploy := c.GetString("T_deploy")
+	T_examining_report := c.GetString("T_examining_report")
+	T_original_record := c.GetString("T_original_record")
+
+	r, is := VerifyTemplate.Read_VerifyTemplate(T_VerifyTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(T_scheme) > 0 {
+		r.T_scheme = T_scheme
+	}
+	if len(T_reporting) > 0 {
+		r.T_reporting = T_reporting
+	}
+	if len(T_inspect) > 0 {
+		r.T_inspect = T_inspect
+	}
+	if len(T_marking) > 0 {
+		r.T_marking = T_marking
+	}
+	if len(T_cover) > 0 {
+		r.T_cover = T_cover
+	}
+	if len(T_examining_report) > 0 {
+		r.T_examining_report = T_examining_report
+	}
+	if len(T_original_record) > 0 {
+		r.T_original_record = T_original_record
+	}
+	if len(T_deploy) > 0 {
+
+		var deployList []VerifyTemplate.VerifyTemplateDeploy
+		// 将 布点1|布点2|布点3| 格式替换为 [{"T_name":"布点1","T_scope":"布点范围1"},{"T_name":"布点2","T_scope":"布点范围2"}]
+		if strings.Contains(T_deploy, "|") {
+			deploys := strings.Split(strings.Trim(T_deploy, "|"), "|")
+			for _, v := range deploys {
+				deployList = append(deployList, VerifyTemplate.VerifyTemplateDeploy{T_name: v})
+			}
+			deploy, err := json.Marshal(deployList)
+			if err != nil {
+				logs.Error("JSON 序列化失败:", err)
+				return
+			}
+			T_deploy = string(deploy)
+		} else {
+			err := json.Unmarshal([]byte(T_deploy), &deployList)
+			if err != nil {
+				logs.Error("JSON 反序列化失败:", err)
+				return
+			}
+		}
+		r.T_deploy = T_deploy
+	}
+	if T_sort_err == nil {
+		r.T_sort = T_sort
+	}
+
+	// .......
+	if !VerifyTemplate.Update_VerifyTemplate(r, "T_name", "T_sort", "T_scheme", "T_reporting", "T_inspect", "T_marking", "T_cover", "T_deploy", "T_examining_report", "T_original_record") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *VerifyTemplateController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+
+	r, is := VerifyTemplate.Read_VerifyTemplate(T_VerifyTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if !VerifyTemplate.Delete_VerifyTemplate(r) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	mapList, _ := VerifyTemplate.Read_VerifyTemplateMap_List(T_VerifyTemplate_id, 0, 0)
+	for _, v := range mapList {
+		if vtm, is := VerifyTemplate.Read_VerifyTemplateMap(v.T_id); is {
+			VerifyTemplate.Delete_VerifyTemplateMap(vtm)
+		}
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版", "删除", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+
+}
+
+// 删除-
+func (c *VerifyTemplateController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+
+	r, is := VerifyTemplate.Read_VerifyTemplate(T_VerifyTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: VerifyTemplate.VerifyTemplateToVerifyTemplate_R(r)}
+	c.ServeJSON()
+	return
+
+}
+
+// 复制-
+func (c *VerifyTemplateController) Copy() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_name := c.GetString("T_name")
+	r, is := VerifyTemplate.Read_VerifyTemplate(T_VerifyTemplate_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := VerifyTemplate.VerifyTemplate{
+		T_class:  r.T_class,
+		T_name:   T_name,
+		T_sort:   r.T_sort,
+		T_deploy: r.T_deploy,
+	}
+
+	new_id, is := VerifyTemplate.Add_VerifyTemplate(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	mapList, _ := VerifyTemplate.Read_VerifyTemplateMap_List(T_VerifyTemplate_id, 0, 0)
+	tempMap := make(map[string]struct{})
+	idList := make([]string, len(mapList))
+	// 生成mapList长度的T_id
+	for i := 0; i < len(mapList); i++ {
+		// 生成编号
+		rand_x := 0
+		T_id := ""
+		for true {
+			T_id = lib.GetRandstring(4, "", int64(rand_x))
+			_, is = VerifyTemplate.Read_VerifyTemplateMap(T_id)
+			if !is {
+				if _, ok := tempMap[T_id]; !ok {
+					break
+				}
+			}
+			rand_x += 1
+		}
+		tempMap[T_id] = struct{}{}
+		idList[i] = T_id
+	}
+	mapInsertList := make([]VerifyTemplate.VerifyTemplateMap, 0)
+	for i, v := range mapList {
+		vtm := VerifyTemplate.VerifyTemplateMap{
+			T_id:                idList[i],
+			T_VerifyTemplate_id: new_id,
+			T_name:              v.T_name,
+			T_text:              v.T_text,
+			T_label:             v.T_label,
+			T_source:            v.T_source,
+			T_sort:              v.T_sort,
+			T_Required:          v.T_Required,
+			T_Construction:      v.T_Construction,
+			T_flow_sort:         v.T_flow_sort,
+			T_max_time:          v.T_max_time,
+			T_min_time:          v.T_min_time,
+		}
+
+		mapInsertList = append(mapInsertList, vtm)
+	}
+
+	_, is = VerifyTemplate.Add_VerifyTemplateMapMulti(mapInsertList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版", "复制", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: new_id}
+	c.ServeJSON()
+	return
+}
+
+/// -----------------------------------------------------------------------------
+
+// 标签列表 -
+func (c *VerifyTemplateController) Map_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+
+	// page, _ := c.GetInt("page")
+	//
+	//	if page < 1 {
+	//		page = 1
+	//	}
+	//
+	// page_z, _ := c.GetInt("page_z")
+	//
+	//	if page_z < 1 {
+	//		page_z = conf.Page_size
+	//	}
+	T_sort, _ := c.GetInt("T_sort")           // 排序
+	T_flow_sort, _ := c.GetInt("T_flow_sort") // 验证流程排序
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+
+	var cnt int64
+	List, cnt := VerifyTemplate.Read_VerifyTemplateMap_List(T_VerifyTemplate_id, T_sort, T_flow_sort)
+	r_jsons.List = List
+	r_jsons.Num = int(cnt)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 标签添加-
+func (c *VerifyTemplateController) Map_Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_name := c.GetString("T_name")
+	T_text := c.GetString("T_text")
+	T_label, _ := c.GetInt("T_label")
+	T_source, _ := c.GetInt("T_source")
+	T_sort, _ := c.GetInt("T_sort")
+	T_Required, _ := c.GetInt("T_Required")
+	T_Construction, _ := c.GetInt("T_Construction")
+	T_flow_sort, _ := c.GetInt("T_flow_sort")
+	T_max_time, _ := c.GetInt("T_max_time")
+	T_min_time, _ := c.GetInt("T_min_time")
+
+	var_ := VerifyTemplate.VerifyTemplateMap{
+		T_VerifyTemplate_id: T_VerifyTemplate_id,
+		T_name:              T_name,
+		T_text:              T_text,
+		T_label:             T_label,
+		T_source:            T_source,
+		T_sort:              T_sort,
+		T_Required:          T_Required,
+		T_Construction:      T_Construction,
+		T_flow_sort:         T_flow_sort,
+		T_max_time:          T_max_time,
+		T_min_time:          T_min_time,
+	}
+
+	Id, is := VerifyTemplate.Add_VerifyTemplateMap(var_)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+
+// 标签修改-
+func (c *VerifyTemplateController) Map_Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_text := c.GetString("T_text")
+	T_label, T_label_err := c.GetInt("T_label")
+	T_sort, T_sort_err := c.GetInt("T_sort")
+	T_source, T_source_err := c.GetInt("T_source")
+	T_Required, _ := c.GetInt("T_Required")
+	T_Construction, _ := c.GetInt("T_Construction")
+
+	T_min_time, T_min_time_err := c.GetInt("T_min_time")
+	T_max_time, T_max_time_err := c.GetInt("T_max_time")
+	T_flow_sort, T_flow_sort_err := c.GetInt("T_flow_sort")
+
+	T_id := c.GetString("T_id")
+
+	r, is := VerifyTemplate.Read_VerifyTemplateMap(T_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	if len(T_name) > 0 {
+		r.T_name = T_name
+	}
+	if len(T_text) > 0 {
+		r.T_text = T_text
+	}
+	if T_label_err == nil {
+		r.T_label = T_label
+	}
+	if T_sort_err == nil {
+		r.T_sort = T_sort
+	}
+	if T_source_err == nil {
+		r.T_source = T_source
+	}
+
+	if T_min_time_err == nil {
+		r.T_min_time = T_min_time
+	}
+	if T_max_time_err == nil {
+		r.T_max_time = T_max_time
+	}
+	if T_flow_sort_err == nil {
+		r.T_flow_sort = T_flow_sort
+	}
+	r.T_Required = T_Required
+	r.T_Construction = T_Construction
+	if !VerifyTemplate.Update_VerifyTemplateMap(r, "T_name", "T_label", "T_text", "T_sort", "T_source", "T_min_time", "T_max_time", "T_flow_sort", "T_Required", "T_Construction") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签", "修改", r)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 标签删除-
+func (c *VerifyTemplateController) Map_Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id := c.GetString("T_id")
+
+	if r, is := VerifyTemplate.Read_VerifyTemplateMap(T_id); is {
+		if !VerifyTemplate.Delete_VerifyTemplateMap(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+/// -----------------------------------------------------------------------------
+
+// 标签数据列表 -
+func (c *VerifyTemplateController) Map_Data_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_source, _ := c.GetInt("T_source")
+
+	T_flow, _ := c.GetInt("T_flow") // app 时间流程
+
+	if T_flow == 0 && T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(T_VerifyTemplate_id, T_source, T_flow)
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, T_task_id, T_VerifyTemplate_id, Map_List)
+
+	type JSONS struct {
+		//必须的大写开头
+		Code   int16
+		Msg    string
+		Data   interface{} // 泛型
+		T_step int
+	}
+
+	c.Data["json"] = JSONS{Code: 200, Msg: "ok!", Data: Data, T_step: task.T_step}
+	c.ServeJSON()
+	return
+}
+
+// 添加标签数据
+func (c *VerifyTemplateController) Map_Data_Pu() {
+	//验证登录 User_is, User_r
+	var err error
+	//token := c.Ctx.Request.Header.Get("user_tokey")
+	//User_r, User_is := Account.Verification_Admin(token, "")
+	//if !User_is {
+	//	c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+	//err = albb.DescribeInstances()
+	////err := RunInstances(tea.StringSlice(os.Args[1:]))
+	//if err != nil {
+	//	c.Data["json"] = lib.JSONS{Code: 202, Msg: "服务启动失败!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+
+	type RequestBody struct {
+		User_tokey            string
+		T_source              int
+		T_task_id             string
+		T_VerifyTemplate_id   string
+		T_step                int // 进行步骤下标
+		T_submit              int // 1-app 2-报告生成
+		T_history             int // 0不保存历史 1保存历史
+		VerifyTemplateMapData []VerifyTemplate.VerifyTemplateMapData_R
+	}
+
+	var body RequestBody
+	data := c.Ctx.Input.RequestBody
+	err = json.Unmarshal(data, &body)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "json返序列化失败:" + err.Error()}
+		c.ServeJSON()
+	}
+
+	logs.Println(fmt.Sprintf("%+v", body))
+
+	User_r, User_is := Account.Verification_Admin(body.User_tokey, "")
+	if !User_is {
+		System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "未登录-保存", body)
+
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	task, is := Task.Read_Task(body.T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_reporting_state := task.T_reporting_state
+	task.T_step = body.T_step
+	// 点击报告生成时保存
+	if body.T_submit == 2 && T_reporting_state == 0 {
+		task.T_reporting_state = Task.TaskExaminingReportStateClickGenerate
+	}
+	// app 提交
+	if body.T_submit == 1 && task.T_collection_state == Task.TaskCollectionStateWaitSubmit {
+		// 手机app提交修改采集状态为已提交
+		task.T_collection_state = Task.TaskCollectionStateSubmitted
+		task.T_collection_submit_time = time.Now().Format("2006-01-02 15:04:05")
+	}
+	if !Task.Update_Task(task, "T_step", "T_reporting_state", "T_collection_state", "T_collection_submit_time") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改任务步骤失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 判断旧的模版id与任务id的模版是否一致,如果不一致则复制旧模板数据到新模板
+	if task.T_VerifyTemplate_id != body.T_VerifyTemplate_id {
+		copy_task := task
+		copy_task.T_VerifyTemplate_id = body.T_VerifyTemplate_id
+		_, err = CopyMapData(copy_task, task, 0)
+		if err != nil {
+			logs.Error("复制旧模板数据到新模板失败", err)
+		}
+
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range body.VerifyTemplateMapData {
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               v.T_source,
+			T_task_id:              body.T_task_id,
+			T_VerifyTemplate_id:    body.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+			T_flow_sort:            v.T_flow_sort,
+			T_max_time:             v.T_max_time,
+			T_min_time:             v.T_min_time,
+
+			T_value:      v.T_value,
+			T_start_time: v.T_start_time,
+		}
+		MapDataList = append(MapDataList, val)
+
+		if v.T_label == 16 && len(v.T_value) > 0 {
+			// 判断验证模版标签-描述是否存在该值,不存在则添加
+			verifyTemplateMap, exist := VerifyTemplate.Read_VerifyTemplateMap(v.T_VerifyTemplateMap_id)
+			if exist {
+				// 用|分割成列表
+				options := lib.SplitStringSeparator(verifyTemplateMap.T_text, "|")
+
+				// 检查是否存在
+				found := false
+				for _, opt := range options {
+					if opt == v.T_value {
+						found = true
+						break
+					}
+				}
+
+				if !found {
+					verifyTemplateMap.T_text = verifyTemplateMap.T_text + "|" + v.T_value
+					VerifyTemplate.Update_VerifyTemplateMap(verifyTemplateMap, "T_text")
+				}
+			}
+		}
+	}
+	var T_cover int
+	if body.T_submit == 1 && T_reporting_state > 0 {
+		T_cover = 1
+	}
+	ids, is := VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, body.T_source, User_r.T_uuid, body.T_submit, T_cover, body.T_history)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+
+	// 手机app提交,发送消息通知
+	if body.T_submit == 1 {
+		_, company_r := Account.Read_User_ByT_uuid(task.T_uuid)
+		_, admin_r := Account.Read_Admin_ByT_uuid(task.T_collection)
+		System.Add_App_News(task.T_reporting, fmt.Sprintf("【%s-%s】数据采集工程师 %s 已提交", company_r.T_name, task.T_name, admin_r.T_name), "")
+
+	}
+
+	// 报告生成,备份数据
+	if body.T_submit == 2 {
+		var_ := Task.TaskCopy{
+			T_task_id: task.T_task_id,
+			T_time:    "报告生成数据",
+			T_State:   2,
+		}
+
+		T_copy_id, is2 := Task.Add_TaskCopy(var_)
+		if !is2 {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+			c.ServeJSON()
+			return
+		}
+		// 创建数据表
+		Task.CREATE_TaskDataCopy("default", T_copy_id)
+		// 将数据表存档
+		Task.TaskData_Arhiving(task.T_task_id, T_copy_id)
+
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "保存", body)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+// 相同模版id复制标签数据
+func (c *VerifyTemplateController) Map_Data_Copy2() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_source, _ := c.GetInt("T_source")
+
+	T_flow, _ := c.GetInt("T_flow")
+
+	if T_flow == 0 && T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_copy_task_id := c.GetString("T_copy_task_id")
+	copy_task, is := Task.Read_Task(T_copy_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_copy_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_paste_task_id := c.GetString("T_paste_task_id")
+	paste_task, is := Task.Read_Task(T_paste_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_paste_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	if copy_task.T_VerifyTemplate_id != paste_task.T_VerifyTemplate_id {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "仅支持相同模版间复制!"}
+		c.ServeJSON()
+		return
+	}
+
+	list := VerifyTemplate.Read_MapData_List(T_source, T_copy_task_id, copy_task.T_VerifyTemplate_id)
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range list {
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               T_source,
+			T_task_id:              paste_task.T_task_id,
+			T_VerifyTemplate_id:    paste_task.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: v.T_value,
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	var ids []int64
+	ids, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, T_source, User_r.T_uuid, 0, 0, 0)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "复制", MapDataList)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+// 通过标签名称复制标签数据
+func (c *VerifyTemplateController) Map_Data_Copy() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_source, _ := c.GetInt("T_source")
+
+	T_flow, _ := c.GetInt("T_flow")
+
+	if T_flow == 0 && T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_copy_task_id := c.GetString("T_copy_task_id")
+	copy_task, is := Task.Read_Task(T_copy_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_copy_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	T_paste_task_id := c.GetString("T_paste_task_id")
+	paste_task, is := Task.Read_Task(T_paste_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_paste_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	ids, err := CopyMapData(copy_task, paste_task, T_source)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "通过标签名称复制", fmt.Sprintf("copy_task_id:%s | paste_task_id:%s", T_copy_task_id, T_paste_task_id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+// 添加标签数据
+func (c *VerifyTemplateController) Map_Data_History_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	T_task_id := c.GetString("T_task_id")
+	T_source, _ := c.GetInt("T_source")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+
+	UseVerifyTemplateMapDataHistoryTime, _ := lib.TimeStrToTime(conf.UseVerifyTemplateMapDataHistoryTime)
+	var Data []VerifyTemplate.VerifyTemplateMapDataHistory_History_List_Res
+	if len(conf.UseVerifyTemplateMapDataHistoryTime) > 0 && task.CreateTime.After(UseVerifyTemplateMapDataHistoryTime) {
+		Data = VerifyTemplate.Read_VerifyTemplateMapDataHistory_History_List2(T_task_id, T_source, AdminMap)
+	} else {
+		Data = VerifyTemplate.Read_VerifyTemplateMapDataHistory_History_List(T_task_id, T_source, AdminMap)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Data}
+	c.ServeJSON()
+	return
+}
+
+// 标签数据列表 -
+func (c *VerifyTemplateController) Map_Data_History_Data_List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_time := c.GetString("T_time")
+	if len(T_time) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "请选择时间点!"}
+		c.ServeJSON()
+		return
+	}
+	T_source, _ := c.GetInt("T_source")
+
+	if T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(task.T_VerifyTemplate_id, T_source, 0)
+	Data := VerifyTemplate.Read_VerifyTemplateMapDataHistory_List(T_source, T_task_id, task.T_VerifyTemplate_id, T_time, Map_List)
+
+	type JSONS struct {
+		//必须的大写开头
+		Code   int16
+		Msg    string
+		Data   interface{} // 泛型
+		T_step int
+	}
+
+	c.Data["json"] = JSONS{Code: 200, Msg: "ok!", Data: Data, T_step: task.T_step}
+	c.ServeJSON()
+	return
+}
+
+// 清除数据
+func (c *VerifyTemplateController) Map_Data_Clear_Value() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_VerifyTemplate_id := c.GetString("T_VerifyTemplate_id")
+	T_VerifyTemplateMap_id := c.GetString("T_VerifyTemplateMap_id")
+
+	T_task_id := c.GetString("T_task_id")
+	_, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	VerifyTemplate.Clear_VerifyTemplateMapData_T_value(T_task_id, T_VerifyTemplate_id, T_VerifyTemplateMap_id)
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "清除数据", fmt.Sprintf("T_task_id:%s T_VerifyTemplate_id:%s T_VerifyTemplateMap_id:%s", T_task_id, T_VerifyTemplate_id, T_VerifyTemplateMap_id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 历史数据恢复
+func (c *VerifyTemplateController) Map_Data_History_Recover() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_time := c.GetString("T_time")
+	if len(T_time) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "请选择时间点!"}
+		c.ServeJSON()
+		return
+	}
+	T_source, _ := c.GetInt("T_source")
+
+	if T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	HistoryList := VerifyTemplate.Read_MapDataHistory_List(T_source, T_task_id, task.T_VerifyTemplate_id, T_time)
+
+	list := VerifyTemplate.Read_MapData_List(T_source, T_task_id, task.T_VerifyTemplate_id)
+	HistoryListMap := make(map[string]VerifyTemplate.VerifyTemplateMapDataHistory)
+	for _, data := range HistoryList {
+		HistoryListMap[data.T_VerifyTemplateMap_id] = data
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range list {
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if HistoryListMap[v.T_VerifyTemplateMap_id].T_value == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               T_source,
+			T_task_id:              task.T_task_id,
+			T_VerifyTemplate_id:    task.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: HistoryListMap[v.T_VerifyTemplateMap_id].T_value,
+		}
+		MapDataList = append(MapDataList, val)
+	}
+	var ids []int64
+	ids, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData(MapDataList)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "恢复", MapDataList)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+// 覆盖数据
+func (c *VerifyTemplateController) Map_Data_Cover() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_cover, _ := c.GetInt("T_cover") // 1覆盖 0不覆盖
+
+	T_time := c.GetString("T_time")
+	if len(T_time) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "请选择时间点!"}
+		c.ServeJSON()
+		return
+	}
+	T_source, _ := c.GetInt("T_source")
+
+	if T_source == 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_source Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_task_id := c.GetString("T_task_id")
+	task, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	var ids []int64
+	if T_cover == 1 {
+		HistoryList := VerifyTemplate.Read_MapDataHistory_List(T_source, T_task_id, task.T_VerifyTemplate_id, T_time)
+
+		list := VerifyTemplate.Read_MapData_List(T_source, T_task_id, task.T_VerifyTemplate_id)
+		HistoryListMap := make(map[string]VerifyTemplate.VerifyTemplateMapDataHistory)
+		for _, data := range HistoryList {
+			HistoryListMap[data.T_VerifyTemplateMap_id] = data
+		}
+
+		MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+		for _, v := range list {
+			if len(v.T_value) > 0 {
+				continue
+			}
+			if HistoryListMap[v.T_VerifyTemplateMap_id].T_value == "" {
+				continue
+			}
+			val := VerifyTemplate.VerifyTemplateMapData{
+				T_source:               T_source,
+				T_task_id:              task.T_task_id,
+				T_VerifyTemplate_id:    task.T_VerifyTemplate_id,
+				T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+				T_Required:             v.T_Required,
+				T_Construction:         v.T_Construction,
+
+				T_flow_sort: v.T_flow_sort,
+				T_max_time:  v.T_max_time,
+				T_min_time:  v.T_min_time,
+
+				T_value: HistoryListMap[v.T_VerifyTemplateMap_id].T_value,
+			}
+			MapDataList = append(MapDataList, val)
+		}
+
+		ids, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData(MapDataList)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "验证模版标签数据", "覆盖", MapDataList)
+	}
+
+	task.T_cover = 0
+	task.T_backup = ""
+	Task.Update_Task(task, "T_cover", "T_backup")
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: ids}
+	c.ServeJSON()
+	return
+}
+
+func (c *VerifyTemplateController) Class_List() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	logs.Debug("经销商id", User_r.T_Distributor_id)
+	if len(User_r.T_Distributor_id) > 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Distributor.Read_DistributorVerifyTemplateClass_List(User_r.T_Distributor_id)}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: VerifyTemplate.Read_VerifyTemplateClass_List()}
+	c.ServeJSON()
+	return
+}
+func (c *VerifyTemplateController) Class_Add() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_fid, _ := c.GetInt("T_fid")
+
+	var_ := VerifyTemplate.VerifyTemplateClass{
+		T_name:  T_name,
+		T_fid:   T_fid,
+		T_State: 1,
+	}
+
+	Id, err := VerifyTemplate.Add_VerifyTemplateClass(var_)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "添加失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "模版分类", "添加", var_)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
+	c.ServeJSON()
+	return
+}
+func (c *VerifyTemplateController) Class_Up() {
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id, _ := c.GetInt("T_id")
+	T_name := c.GetString("T_name")
+
+	R_VerifyTemplateToolClass, err := VerifyTemplate.Read_VerifyTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	if len(T_name) > 0 {
+		R_VerifyTemplateToolClass.T_name = T_name
+	}
+
+	if is := VerifyTemplate.Update_VerifyTemplateClass(R_VerifyTemplateToolClass, "T_name"); !is {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "修改失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "模版分类", "修改", R_VerifyTemplateToolClass)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+func (c *VerifyTemplateController) Class_Del() {
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id, _ := c.GetInt("T_id")
+	R_VerifyTemplateToolClass, err := VerifyTemplate.Read_VerifyTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	ids := VerifyTemplate.ReadVerifyTemplateClassIds_T_path(R_VerifyTemplateToolClass.T_path)
+
+	if is := VerifyTemplate.Delete_VerifyTemplateClass_ByIds(ids); !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs(User_r.T_uuid, "模版分类", "删除", strconv.Itoa(T_id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 复制验证模版-分类-标签
+func (c *VerifyTemplateController) Class_Copy() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id, _ := c.GetInt("T_id") // 要复制的信息采集分类id
+	T_name := c.GetString("T_name")
+
+	// 查询要复制的信息采集分类id
+	R_VerifyTemplateClass, err := VerifyTemplate.Read_VerifyTemplateClass_ById(T_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 203, Msg: "T_id Err!"}
+		c.ServeJSON()
+		return
+	}
+	if len(T_name) > 0 && T_name != R_VerifyTemplateClass.T_name {
+		R_VerifyTemplateClass.T_name = T_name
+	} else {
+		R_VerifyTemplateClass.T_name = R_VerifyTemplateClass.T_name + "_副本"
+	}
+
+	_, err = VerifyTemplate.CopyVerifyTemplateClassTree(R_VerifyTemplateClass.T_path, R_VerifyTemplateClass.T_fid, R_VerifyTemplateClass.T_name)
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "复制验证模版分类失败"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "验证模版分类", "复制", T_id)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+func CopyMapData(copy_task, paste_task Task.Task, T_source int) (ids []int64, err error) {
+	copy_task_Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(copy_task.T_VerifyTemplate_id, T_source, 0)
+	copy_task_Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, copy_task.T_task_id, copy_task.T_VerifyTemplate_id, copy_task_Map_List)
+
+	Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(paste_task.T_VerifyTemplate_id, T_source, 0)
+	Data := VerifyTemplate.Read_VerifyTemplateMapData_List(T_source, paste_task.T_task_id, paste_task.T_VerifyTemplate_id, Map_List)
+
+	copyDataMap := make(map[string]string)
+	for _, data := range copy_task_Data {
+		copyDataMap[data.T_name] = data.T_value
+	}
+
+	MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+	for _, v := range Data {
+		// 已有值则不复制
+		if len(v.T_value) > 0 {
+			continue
+		}
+		if copyDataMap[v.T_name] == "" {
+			continue
+		}
+		val := VerifyTemplate.VerifyTemplateMapData{
+			T_source:               v.T_source,
+			T_task_id:              paste_task.T_task_id,
+			T_VerifyTemplate_id:    paste_task.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_Required:             v.T_Required,
+			T_Construction:         v.T_Construction,
+
+			T_flow_sort: v.T_flow_sort,
+			T_max_time:  v.T_max_time,
+			T_min_time:  v.T_min_time,
+
+			T_value: copyDataMap[v.T_name],
+		}
+		MapDataList = append(MapDataList, val)
+	}
+
+	ids, is := VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, 0, "", 0, 0, 0)
+	if !is {
+		return ids, errors.New("保存复制数据失败")
+	}
+	return nil, err
+}

+ 623 - 0
controllers/infoCollection.go

@@ -0,0 +1,623 @@
+package controllers
+
+import (
+	"ColdVerify_server/Nats/NatsServer"
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/lib/wx"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"ColdVerify_server/models/AllotTask"
+	"ColdVerify_server/models/Device"
+	"ColdVerify_server/models/InfoCollection"
+	"ColdVerify_server/models/System"
+	"ColdVerify_server/models/Task"
+	"ColdVerify_server/models/VerifyTemplate"
+	"encoding/json"
+	"fmt"
+	beego "github.com/beego/beego/v2/server/web"
+	"math"
+	"time"
+)
+
+type InfoCollectionController struct {
+	beego.Controller
+}
+
+// 列表 -
+func (c *InfoCollectionController) List() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_uuid := c.GetString("T_uuid")
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	T_status, _ := c.GetInt("T_status")
+
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	InfoTemplateMap := InfoCollection.InfoTemplateListToMap(InfoCollection.Read_InfoTemplate_List_ALL())
+	InfoTemplateClassMap := InfoCollection.InfoTemplateClassListToMap(InfoCollection.Read_InfoTemplateClass_List_ALL())
+
+	var cnt int
+	List, cnt := InfoCollection.Read_InfoCollection_List(T_uuid, T_allot_task_id, T_name, T_status, UserMap, AdminMap, InfoTemplateMap, InfoTemplateClassMap, page, page_z)
+
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 用户列表
+func (c *InfoCollectionController) UserList() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	T_status, _ := c.GetInt("T_status")
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	InfoTemplateMap := InfoCollection.InfoTemplateListToMap(InfoCollection.Read_InfoTemplate_List_ALL())
+	InfoTemplateClassMap := InfoCollection.InfoTemplateClassListToMap(InfoCollection.Read_InfoTemplateClass_List_ALL())
+
+	var cnt int
+	List, cnt := InfoCollection.Read_UserInfoCollection_List(T_allot_task_id, User_r.T_uuid, T_name, T_status, UserMap, AdminMap, InfoTemplateMap, InfoTemplateClassMap, page, page_z)
+	page_size := math.Ceil(float64(cnt) / float64(page_z))
+	r_jsons.List = List
+	r_jsons.Page = page
+	r_jsons.Page_size = int(page_size)
+	r_jsons.Pages = lib.Func_page(int64(page), int64(page_size))
+	r_jsons.Num = cnt
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 获取-
+func (c *InfoCollectionController) Get() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	r, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
+		c.ServeJSON()
+		return
+	}
+	UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1())
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	InfoTemplateMap := InfoCollection.InfoTemplateListToMap(InfoCollection.Read_InfoTemplate_List_ALL())
+	InfoTemplateClassMap := InfoCollection.InfoTemplateClassListToMap(InfoCollection.Read_InfoTemplateClass_List_ALL())
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: InfoCollection.InfoCollectionToInfoCollection_R(r, UserMap, AdminMap, InfoTemplateMap, InfoTemplateClassMap)}
+	c.ServeJSON()
+	return
+}
+
+// 添加-
+func (c *InfoCollectionController) Add() {
+
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_uuid := c.GetString("T_uuid") // 用户uuid
+	T_InfoTemplate_class := c.GetString("T_InfoTemplate_class")
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+	T_allot_task_id := c.GetString("T_allot_task_id")
+
+	if len(T_allot_task_id) > 0 {
+		allotTask, is := AllotTask.Read_AllotTask(T_allot_task_id)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取采集任务信息失败!"}
+			c.ServeJSON()
+			return
+		}
+		T_uuid = allotTask.T_uuid
+	}
+
+	var_ := InfoCollection.InfoCollection{
+		T_uuid:               T_uuid,
+		T_name:               T_name,
+		T_InfoTemplate_class: T_InfoTemplate_class,
+		T_InfoTemplate_id:    T_InfoTemplate_id,
+		T_status:             1,
+		T_State:              1,
+		T_submit_uuid:        User_r.T_uuid,
+		T_allot_task_id:      T_allot_task_id,
+	}
+
+	T_InfoCollection_id, err := InfoCollection.Add_InfoCollection(var_)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "添加", var_)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_InfoCollection_id}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *InfoCollectionController) Up() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_InfoTemplate_class := c.GetString("T_InfoTemplate_class")
+	T_InfoTemplate_id := c.GetString("T_InfoTemplate_id")
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	T_status, _ := c.GetInt("T_status")
+	r, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// .......
+	clos := make([]string, 0)
+	if len(T_name) > 0 {
+		r.T_name = T_name
+		clos = append(clos, "T_name")
+	}
+	if T_status > 0 {
+		r.T_status = T_status
+		clos = append(clos, "T_status")
+	}
+	if len(T_InfoTemplate_class) > 0 {
+		r.T_InfoTemplate_class = T_InfoTemplate_class
+		clos = append(clos, "T_InfoTemplate_class")
+	}
+	if T_InfoTemplate_id != r.T_InfoTemplate_id {
+		// 修改任务信息采集模版
+		Task.Update_Task_T_InfoTemplate_id(T_InfoCollection_id, T_InfoTemplate_id)
+	}
+	if len(T_InfoTemplate_id) > 0 {
+		r.T_InfoTemplate_id = T_InfoTemplate_id
+		clos = append(clos, "T_InfoTemplate_id")
+	}
+
+	if !InfoCollection.Update_InfoCollection(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "修改", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除-
+func (c *InfoCollectionController) Del() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	if r, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id); is {
+		if !InfoCollection.Delete_InfoCollection(r) {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "删除", r)
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改状态
+func (c *InfoCollectionController) UpStatus() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	T_status, _ := c.GetInt("T_status")
+	T_reason := c.GetString("T_reason") //退回原因
+	r, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	//_, user_r := Account.Read_User_ByT_uuid(r.T_uuid)
+
+	if T_status == InfoCollection.InfoCollectionStatusSubmitted && (r.T_status != InfoCollection.InfoCollectionStatusWaitSubmit && r.T_status != InfoCollection.InfoCollectionStatusReturn) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("当前状态为%s,禁止提交为%s", InfoCollection.InfoCollectionStatusMap[r.T_status], InfoCollection.InfoCollectionStatusMap[T_status])}
+		c.ServeJSON()
+		return
+	}
+
+	if T_status == InfoCollection.InfoCollectionStatusReturnedMoney && r.T_status != InfoCollection.InfoCollectionStatusReceipt {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("当前状态为%s,禁止提交为%s", InfoCollection.InfoCollectionStatusMap[r.T_status], InfoCollection.InfoCollectionStatusMap[T_status])}
+		c.ServeJSON()
+		return
+	}
+
+	if T_status == InfoCollection.InfoCollectionStatusReturn && (r.T_status != InfoCollection.InfoCollectionStatusSubmitted && r.T_status != InfoCollection.InfoCollectionStatusReturn) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("当前状态为%s,禁止提交为%s", InfoCollection.InfoCollectionStatusMap[r.T_status], InfoCollection.InfoCollectionStatusMap[T_status])}
+		c.ServeJSON()
+		return
+	}
+
+	if T_status == InfoCollection.InfoCollectionStatusReceipt && (r.T_status != InfoCollection.InfoCollectionStatusSubmitted && r.T_status != InfoCollection.InfoCollectionStatusReceipt) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("当前状态为%s,禁止提交为%s", InfoCollection.InfoCollectionStatusMap[r.T_status], InfoCollection.InfoCollectionStatusMap[T_status])}
+		c.ServeJSON()
+		return
+	}
+
+	// 1待提交 2已提交 3已接收 4已退回 5已回款
+	clos := make([]string, 0)
+	if T_status > 0 {
+		r.T_status = T_status
+		clos = append(clos, "T_status")
+	}
+	//  2已提交  ,计算时间
+	if T_status == InfoCollection.InfoCollectionStatusSubmitted {
+		if len(r.T_end_time) == 0 {
+			r.T_end_time = time.Now().Format("2006-01-02 15:04:05")
+			r.T_time_interval, _ = lib.MinutesDifference(r.T_start_time, r.T_end_time)
+			clos = append(clos, "T_end_time")
+			clos = append(clos, "T_time_interval")
+		}
+	}
+	if T_status == InfoCollection.InfoCollectionStatusReturn {
+		r.T_return_times += 1
+		clos = append(clos, "T_return_times")
+	}
+
+	var returnRecordList []InfoCollection.AuditRecord
+	if len(r.T_audit_record) > 0 {
+		err := json.Unmarshal([]byte(r.T_audit_record), &returnRecordList)
+		if err != nil {
+			logs.Error("JSON 反序列化失败:", err)
+			return
+		}
+	}
+	returnRecordList = append(returnRecordList, InfoCollection.AuditRecord{
+		T_uuid:   User_r.T_uuid,
+		T_status: T_status,
+		T_reason: T_reason,
+		T_time:   time.Now().Format("2006-01-02 15:04:05"),
+	})
+	returnRecordJson, err := json.Marshal(returnRecordList)
+	if err != nil {
+		logs.Error("JSON 反序列化失败:", err)
+		return
+	}
+	r.T_audit_record = string(returnRecordJson)
+	clos = append(clos, "T_audit_record")
+
+	if !InfoCollection.Update_InfoCollection(r, clos...) {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	//AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	_, company_r := Account.Read_User_ByT_uuid(r.T_uuid)
+	// 已提交   [报告负责人]
+	if T_status == InfoCollection.InfoCollectionStatusSubmitted {
+		go wx.WxSend(conf.VdelUuid, fmt.Sprintf("【%s-%s】信息采集 %s", company_r.T_name, r.T_name, InfoCollection.InfoCollectionStatusMap[T_status]))
+	}
+
+	// 已退回
+	if T_status == InfoCollection.InfoCollectionStatusReturn {
+		System.Add_News(r.T_submit_uuid, fmt.Sprintf("【%s-%s】信息采集 %s,%s", company_r.T_name, r.T_name, InfoCollection.InfoCollectionStatusMap[T_status], T_reason), "")
+		go wx.WxSend(r.T_submit_uuid, fmt.Sprintf("【%s-%s】信息采集 %s,%s", company_r.T_name, r.T_name, InfoCollection.InfoCollectionStatusMap[T_status], T_reason))
+	}
+
+	if T_status == InfoCollection.InfoCollectionStatusReturnedMoney {
+		go wx.WxSend(conf.BoosUuid, fmt.Sprintf("【%s-%s】已回款", company_r.T_name, r.T_name))
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "修改状态", r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 退回记录列表
+func (c *InfoCollectionController) AuditRecordList() {
+	// 验证登录 User_is, User_r
+	_, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id")
+	T_status, _ := c.GetInt("T_status")
+	r, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var auditRecordList []InfoCollection.AuditRecord
+	if len(r.T_audit_record) > 0 {
+		err := json.Unmarshal([]byte(r.T_audit_record), &auditRecordList)
+		if err != nil {
+			logs.Error("JSON 反序列化失败:", err)
+			return
+		}
+	}
+	AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1())
+	var auditRecordList2 []InfoCollection.AuditRecord
+
+	if T_status == 0 {
+		for i := 0; i < len(auditRecordList); i++ {
+			auditRecordList[i].T_uuid_name = AdminMap[auditRecordList[i].T_uuid]
+			auditRecordList2 = append(auditRecordList2, auditRecordList[i])
+		}
+		c.Data["json"] = lib.JSONS{Data: auditRecordList2, Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
+
+	for i := 0; i < len(auditRecordList); i++ {
+		if auditRecordList[i].T_status == T_status {
+			auditRecordList[i].T_uuid_name = AdminMap[auditRecordList[i].T_uuid]
+			auditRecordList2 = append(auditRecordList2, auditRecordList[i])
+		}
+	}
+	c.Data["json"] = lib.JSONS{Data: auditRecordList2, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 信息采集统计
+func (c *InfoCollectionController) Statistics() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+	T_allot_task_id := c.GetString("T_allot_task_id")
+	List, cnt := InfoCollection.Read_UserInfoCollection_List(T_allot_task_id, User_r.T_uuid, "", 0, map[string]string{}, map[string]string{}, map[string]string{}, map[string]string{}, 0, 9999)
+	res := make(map[int]int)
+	for k, _ := range InfoCollection.InfoCollectionStatusMap {
+		res[k] = 0
+	}
+	res[0] = cnt
+	for _, r := range List {
+		res[r.T_status] += 1
+	}
+
+	c.Data["json"] = lib.JSONS{Data: res, Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 修改-
+func (c *InfoCollectionController) Copy() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_name := c.GetString("T_name")
+	T_InfoCollection_id := c.GetString("T_InfoCollection_id") // 信息采集id
+	info, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	var_ := InfoCollection.InfoCollection{
+		T_uuid:               info.T_uuid,
+		T_name:               T_name,
+		T_InfoTemplate_class: info.T_InfoTemplate_class,
+		T_InfoTemplate_id:    info.T_InfoTemplate_id,
+		T_status:             1,
+		T_State:              1,
+		T_submit_uuid:        User_r.T_uuid,
+		T_allot_task_id:      info.T_allot_task_id,
+		T_start_time:         time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	T_InfoCollection_id, err := InfoCollection.Add_InfoCollection(var_)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	// 查询信息采集下的任务列表
+	taskList, _ := Task.Read_Task_List_By_T_InfoCollection_id(info.T_InfoCollection_id)
+	for _, r := range taskList {
+		dc := Device.DeviceClass{
+			T_uuid:  User_r.T_uuid,
+			T_State: 1,
+		}
+		T_class_id, is2 := Device.Add_DeviceClass(dc)
+		if !is2 {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加分类失败!"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "分类管理", "添加", dc)
+
+		ta := Task.Task{
+			T_Distributor_id:       r.T_Distributor_id,
+			T_InfoCollection_id:    T_InfoCollection_id,
+			T_InfoTemplate_id:      info.T_InfoTemplate_id,
+			T_start_time:           time.Now().Format("2006-01-02 15:04:05"), // 项目开始时间使用信息采集开始时间
+			T_class:                int(T_class_id),
+			T_uuid:                 r.T_uuid,
+			T_name:                 r.T_name,
+			T_VerifyTemplate_class: r.T_VerifyTemplate_class,
+			T_VerifyTemplate_id:    r.T_VerifyTemplate_id,
+			T_deadline:             r.T_deadline,
+			T_scheme:               r.T_scheme,
+			T_collection:           r.T_collection,
+			T_reporting:            r.T_reporting,
+			T_delivery:             r.T_delivery,
+			T_Show:                 1,
+			T_State:                1,
+
+			T_project:         r.T_project,
+			T_province:        r.T_province,
+			T_city:            r.T_city,
+			T_district:        r.T_district,
+			T_province_code:   r.T_province_code,
+			T_city_code:       r.T_city_code,
+			T_district_code:   r.T_district_code,
+			T_category:        r.T_category,
+			T_device_type:     r.T_device_type,
+			T_volume:          r.T_volume,
+			T_verify_type:     r.T_verify_type,
+			T_subject_matter:  r.T_subject_matter,
+			T_temp_range:      r.T_temp_range,
+			T_report_type:     r.T_report_type,
+			T_device_quantity: r.T_device_quantity,
+			T_cnas:            r.T_cnas,
+		}
+		ta.T_report_number, _ = Task.GenerateNextT_report_number(ta.T_device_type)
+		T_paste_task_id, is := Task.Add_Task(ta)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+			c.ServeJSON()
+			return
+		}
+		NatsServer.Create_Local_Table(T_paste_task_id)
+		Task.Redis_Task_T_report_number_DelK(ta.T_report_number) // 删除redis内的任务编号
+
+		// 复制验证模版数据
+		Map_List := VerifyTemplate.Read_VerifyTemplateMap_List_For_Data(r.T_VerifyTemplate_id, 0, 0)
+		copy_task_Data := VerifyTemplate.Read_VerifyTemplateMapData_List(0, r.T_task_id, r.T_VerifyTemplate_id, Map_List)
+
+		Data := VerifyTemplate.Read_VerifyTemplateMapData_List(0, T_paste_task_id, r.T_VerifyTemplate_id, Map_List)
+
+		copyDataMap := make(map[string]string)
+		for _, data := range copy_task_Data {
+			copyDataMap[data.T_name] = data.T_value
+		}
+
+		MapDataList := make([]VerifyTemplate.VerifyTemplateMapData, 0)
+		for _, v := range Data {
+			// 已有值则不复制
+			if len(v.T_value) > 0 {
+				continue
+			}
+			if copyDataMap[v.T_name] == "" {
+				continue
+			}
+			val := VerifyTemplate.VerifyTemplateMapData{
+				T_source:               v.T_source,
+				T_task_id:              T_paste_task_id,
+				T_VerifyTemplate_id:    r.T_VerifyTemplate_id,
+				T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+				T_Required:             v.T_Required,
+				T_Construction:         v.T_Construction,
+
+				T_flow_sort: v.T_flow_sort,
+				T_max_time:  v.T_max_time,
+				T_min_time:  v.T_min_time,
+
+				T_value: copyDataMap[v.T_name],
+			}
+			MapDataList = append(MapDataList, val)
+		}
+		_, is = VerifyTemplate.AddOrUpdate_VerifyTemplateMapData_ADD_History(MapDataList, 0, "复制", 0, 0, 1)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "保存失败"}
+			c.ServeJSON()
+			return
+		}
+		System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "复制标签数据", MapDataList)
+
+		// 通知
+		_, company_r := Account.Read_User_ByT_uuid(var_.T_uuid)
+		go wx.WxSend(ta.T_scheme, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+		go wx.WxSend(ta.T_collection, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+		go wx.WxSend(ta.T_reporting, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+		go wx.WxSend(ta.T_delivery, fmt.Sprintf("【%s-%s】任务派发", company_r.T_name, var_.T_name))
+
+		// 添加任务操作日志
+		Task.Add_TaskLogs_T(User_r.T_uuid, T_paste_task_id, "任务管理", "复制", var_)
+		System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "复制", var_)
+	}
+
+	System.Add_UserLogs_T(User_r.T_uuid, "信息采集管理", "复制", info)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}

+ 75 - 0
go.mod

@@ -0,0 +1,75 @@
+module ColdVerify_server
+
+go 1.23
+
+require (
+	github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
+	github.com/alibabacloud-go/openapi-util v0.1.1
+	github.com/alibabacloud-go/tea v1.3.1
+	github.com/alibabacloud-go/tea-utils/v2 v2.0.7
+	github.com/astaxie/beego v1.12.3
+	github.com/beego/beego/v2 v2.0.7
+	github.com/go-resty/resty/v2 v2.11.0
+	github.com/go-sql-driver/mysql v1.7.0
+	github.com/google/uuid v1.2.0
+	github.com/nats-io/nats.go v1.27.0
+	github.com/qiniu/go-sdk/v7 v7.14.0
+	github.com/robfig/cron/v3 v3.0.1
+	github.com/satori/go.uuid v1.2.0
+	github.com/signintech/gopdf v0.15.1
+	github.com/vmihailenco/msgpack/v5 v5.3.5
+	github.com/xuri/excelize/v2 v2.7.0
+	gonum.org/v1/plot v0.13.0
+)
+
+require (
+	git.sr.ht/~sbinet/gg v0.4.1 // indirect
+	github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
+	github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
+	github.com/alibabacloud-go/debug v1.0.1 // indirect
+	github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
+	github.com/aliyun/credentials-go v1.3.10 // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/clbanning/mxj/v2 v2.7.0 // indirect
+	github.com/go-fonts/liberation v0.3.1 // indirect
+	github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 // indirect
+	github.com/go-pdf/fpdf v0.8.0 // indirect
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
+	github.com/gomodule/redigo v2.0.0+incompatible // indirect
+	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.16.5 // indirect
+	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+	github.com/nats-io/nats-server/v2 v2.9.20 // indirect
+	github.com/nats-io/nkeys v0.4.4 // indirect
+	github.com/nats-io/nuid v1.0.1 // indirect
+	github.com/phpdave11/gofpdi v1.0.13 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/prometheus/client_golang v1.14.0 // indirect
+	github.com/prometheus/client_model v0.3.0 // indirect
+	github.com/prometheus/common v0.37.0 // indirect
+	github.com/prometheus/procfs v0.8.0 // indirect
+	github.com/richardlehane/mscfb v1.0.4 // indirect
+	github.com/richardlehane/msoleps v1.0.3 // indirect
+	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
+	github.com/tjfoc/gmsm v1.4.1 // indirect
+	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+	github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
+	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
+	golang.org/x/crypto v0.25.0 // indirect
+	golang.org/x/image v0.20.0 // indirect
+	golang.org/x/net v0.27.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.22.0 // indirect
+	golang.org/x/text v0.18.0 // indirect
+	google.golang.org/protobuf v1.28.1 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
+	gopkg.in/yaml.v2 v2.4.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+)

+ 821 - 0
go.sum

@@ -0,0 +1,821 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo=
+git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE=
+git.sr.ht/~sbinet/gg v0.4.1 h1:YccqPPS57/TpqX2fFnSRlisrqQ43gEdqVm3JtabPrp0=
+git.sr.ht/~sbinet/gg v0.4.1/go.mod h1:xKrQ22W53kn8Hlq+gzYeyyohGMwR8yGgSMlVpY/mHGc=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
+github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
+github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
+github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
+github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
+github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
+github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
+github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
+github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
+github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
+github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
+github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
+github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
+github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
+github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
+github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
+github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
+github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
+github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
+github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
+github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
+github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
+github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
+github.com/alibabacloud-go/openapi-util v0.1.1 h1:ujGErJjG8ncRW6XtBBMphzHTvCxn4DjrVw4m04HsS28=
+github.com/alibabacloud-go/openapi-util v0.1.1/go.mod h1:/UehBSE2cf1gYT43GV4E+RxTdLRzURImCYY0aRmlXpw=
+github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
+github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
+github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
+github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
+github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
+github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
+github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
+github.com/alibabacloud-go/tea v1.3.1 h1:qdRKlZWj1b7agUnmMEYku+Mzjo37IJh3YmwUmIEzRC4=
+github.com/alibabacloud-go/tea v1.3.1/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
+github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
+github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
+github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
+github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
+github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
+github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
+github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
+github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA=
+github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
+github.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=
+github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
+github.com/beego/beego/v2 v2.0.7 h1:9KNnUM40tn3pbCOFfe6SJ1oOL0oTi/oBS/C/wCEdAXA=
+github.com/beego/beego/v2 v2.0.7/go.mod h1:f0uOEkmJWgAuDTlTxUdgJzwG3PDSIf3UWF3NpMohbFE=
+github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
+github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
+github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
+github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
+github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
+github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
+github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
+github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ=
+github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
+github.com/go-fonts/latin-modern v0.3.1 h1:/cT8A7uavYKvglYXvrdDw4oS5ZLkcOU22fa2HJ1/JVM=
+github.com/go-fonts/latin-modern v0.3.1/go.mod h1:ysEQXnuT/sCDOAONxC7ImeEDVINbltClhasMAqEtRK0=
+github.com/go-fonts/liberation v0.3.1 h1:9RPT2NhUpxQ7ukUvz3jeUckmN42T9D9TpjtQcqK/ceM=
+github.com/go-fonts/liberation v0.3.1/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs=
+github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-pdf/fpdf v0.8.0 h1:IJKpdaagnWUeSkUFUjTcSzTppFxmv8ucGQyNPQWxYOQ=
+github.com/go-pdf/fpdf v0.8.0/go.mod h1:gfqhcNwXrsd3XYKte9a7vM3smvU/jB4ZRDrmWSxpfdc=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
+github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
+github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
+github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
+github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
+github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
+github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
+github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
+github.com/nats-io/nats-server/v2 v2.9.20 h1:bt1dW6xsL1hWWwv7Hovm+EJt5L6iplyqlgEFkoEUk0k=
+github.com/nats-io/nats-server/v2 v2.9.20/go.mod h1:aTb/xtLCGKhfTFLxP591CMWfkdgBmcUUSkiSOe5A3gw=
+github.com/nats-io/nats.go v1.27.0 h1:3o9fsPhmoKm+yK7rekH2GtWoE+D9jFbw8N3/ayI1C00=
+github.com/nats-io/nats.go v1.27.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
+github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
+github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
+github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
+github.com/phpdave11/gofpdi v1.0.11/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/phpdave11/gofpdi v1.0.13 h1:o61duiW8M9sMlkVXWlvP92sZJtGKENvW3VExs6dZukQ=
+github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
+github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
+github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
+github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
+github.com/qiniu/go-sdk/v7 v7.14.0 h1:6icihMTKHoKMmeU1mqtIoHUv7c1LrLjYm8wTQaYDqmw=
+github.com/qiniu/go-sdk/v7 v7.14.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w=
+github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
+github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
+github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
+github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
+github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
+github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
+github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
+github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
+github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
+github.com/signintech/gopdf v0.15.1 h1:8lFdW+UX0oUkrADJv5HmhyhRP9YzMvJzkw7iSNX/35U=
+github.com/signintech/gopdf v0.15.1/go.mod h1:a+E8HlIuBwghPyoo7UaoB5UaL7zklDzmYVIAHoW/Rlw=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
+github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
+github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
+github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
+github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
+github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
+github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c=
+github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
+github.com/xuri/excelize/v2 v2.7.0 h1:Hri/czwyRCW6f6zrCDWXcXKshlq4xAZNpNOpdfnFhEw=
+github.com/xuri/excelize/v2 v2.7.0/go.mod h1:ebKlRoS+rGyLMyUx3ErBECXs/HNYqyj+PbkkKRK5vSI=
+github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M=
+github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4=
+golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
+golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
+golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM=
+gonum.org/v1/gonum v0.13.0/go.mod h1:/WPYRckkfWrhWefxyYTfrTtQR0KH4iyHNuzxqXAKyAU=
+gonum.org/v1/plot v0.13.0 h1:yb2Z/b8bY5h/xC4uix+ujJ+ixvPUvBmUOtM73CJzpsw=
+gonum.org/v1/plot v0.13.0/go.mod h1:mV4Bpu4PWTgN2CETURNF8hCMg7EtlZqJYCcmYo/t4Co=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

+ 59 - 0
lib/Aes.go

@@ -0,0 +1,59 @@
+package lib
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"encoding/base64"
+)
+
+func AesEncryptCBC(orig string, key string) string {
+	// 转成字节数组
+	origData := []byte(orig)
+	k := []byte(key)
+	// 分组秘钥
+	// NewCipher该函数限制了输入k的长度必须为16, 24或者32
+	block, _ := aes.NewCipher(k)
+	// 获取秘钥块的长度
+	blockSize := block.BlockSize()
+	// 补全码
+	origData = PKCS7Padding(origData, blockSize)
+	// 加密模式
+	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
+	// 创建数组
+	cryted := make([]byte, len(origData))
+	// 加密
+	blockMode.CryptBlocks(cryted, origData)
+	return base64.StdEncoding.EncodeToString(cryted)
+}
+func AesDecryptCBC(cryted string, key string) string {
+	// 转成字节数组
+	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
+	k := []byte(key)
+	// 分组秘钥
+	block, _ := aes.NewCipher(k)
+	// 获取秘钥块的长度
+	blockSize := block.BlockSize()
+	// 加密模式
+	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
+	// 创建数组
+	orig := make([]byte, len(crytedByte))
+	// 解密
+	blockMode.CryptBlocks(orig, crytedByte)
+	// 去补全码
+	orig = PKCS7UnPadding(orig)
+	return string(orig)
+}
+//补码
+//AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
+func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
+	padding := blocksize - len(ciphertext)%blocksize
+	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
+	return append(ciphertext, padtext...)
+}
+//去码
+func PKCS7UnPadding(origData []byte) []byte {
+	length := len(origData)
+	unpadding := int(origData[length-1])
+	return origData[:(length - unpadding)]
+}

+ 95 - 0
lib/Qiniu.go

@@ -0,0 +1,95 @@
+package lib
+
+// 存储相关功能的引入包只有这两个,后面不再赘述
+
+// 存储相关功能的引入包只有这两个,后面不再赘述
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/System"
+	"context"
+	"github.com/qiniu/go-sdk/v7/auth/qbox"
+	"github.com/qiniu/go-sdk/v7/storage"
+	uuid "github.com/satori/go.uuid"
+	"strconv"
+	"time"
+)
+
+var Qiniu *qbox.Mac
+
+// var (
+//
+//	//BUCKET是你在存储空间的名称
+//	accessKey = "-8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo"
+//	secretKey = "KFhkYxTAJ2ZPN3ZS3euTsfWk8-C92rKgkhAMkDRN"
+//	BUCKET    = "bzdcoldoss"
+//
+// )
+func init() {
+	Qiniu = qbox.NewMac(conf.Qiniu_AccessKey, conf.Qiniu_SecretKey)
+}
+
+// if !lib.Pload_qiniu("ofile/"+timeStr+".xlsx","ofile/"+timeStr+".xlsx"){
+// c.Data["json"] = lib.JSONS{Code: 203, Msg: "oss!"}
+// c.ServeJSON()
+// return
+// }
+func Pload_qiniu(localFile string, name string) bool {
+	//localFile := "C:\\Users\\Administrator\\Downloads\\kodo-browser-Windows-x64-v1.0.15.zip"
+	//key := "kodo-browser-Windows-x64-v1.0.15.zip"
+	// 自定义返回值结构体
+	type MyPutRet struct {
+		Key    string
+		Hash   string
+		Fsize  int
+		Bucket string
+		Name   string
+	}
+
+	//key := "your file save key"
+	// 使用 returnBody 自定义回复格式
+	putPolicy := storage.PutPolicy{
+		Scope:      conf.Qiniu_BUCKET,
+		ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}`,
+	}
+
+	upToken := putPolicy.UploadToken(Qiniu)
+	cfg := storage.Config{}
+	formUploader := storage.NewFormUploader(&cfg)
+	ret := MyPutRet{}
+	putExtra := storage.PutExtra{
+		Params: map[string]string{
+			"x:name": "github logo",
+		},
+	}
+	err := formUploader.PutFile(context.Background(), &ret, upToken, name, localFile, &putExtra)
+	if err != nil {
+		logs.Error(FuncName(), err)
+		System.Add_Logs("七牛云", "上传文件失败"+localFile, err.Error())
+		return false
+	}
+	logs.Println(ret.Bucket, ret.Key, ret.Fsize, ret.Hash, ret.Name)
+	return true
+}
+
+func UploadToken(T_suffix string) string {
+	Tokey := strconv.FormatInt(time.Now().Unix(), 10) + uuid.NewV4().String()
+	if len(T_suffix) == 0 {
+		T_suffix = ".png"
+	}
+	putPolicy := storage.PutPolicy{
+		Scope:      conf.Qiniu_BUCKET,
+		InsertOnly: 1,    // 仅能以新增模式上传文件。
+		Expires:    7200, //示例2小时有效期
+		ReturnBody: `{"key":"` + conf.OssQiniu + `/$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)"}`,
+		//{"key":"github-x.png","hash":"FqKXVdTvIx_mPjOYdjDyUSy_H1jr","fsize":6091,"bucket":"if-pbl","name":"github logo"}
+		//{"key":"` + conf.Oss + `/$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}
+		ForceSaveKey: true,
+		SaveKey:      "UpImage/" + Tokey + "." + T_suffix,
+		FsizeLimit:   1024 * 1024 * 50,
+		MimeLimit:    "image/*;application/pdf;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;application/vnd.openxmlformats-officedocument.wordprocessingml.document;application/msword;application/vnd.ms-excel",
+	}
+
+	upToken := putPolicy.UploadToken(Qiniu)
+	return upToken
+}

+ 270 - 0
lib/albb/DescribeInstances.go

@@ -0,0 +1,270 @@
+// This file is auto-generated, don't edit it. Thanks.
+package albb
+
+import (
+	"encoding/json"
+	"fmt"
+	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
+	openapiutil "github.com/alibabacloud-go/openapi-util/service"
+	util "github.com/alibabacloud-go/tea-utils/v2/service"
+	"github.com/alibabacloud-go/tea/tea"
+	"strings"
+	"time"
+)
+//查询实例的详细信息列表
+func ModifyInstanceAutoReleaseTime (InstanceId,AutoReleaseTime string) (_err error) {
+	fmt.Println("ModifyInstanceAutoReleaseTime:",InstanceId,AutoReleaseTime )
+	client, _err := CreateClient()
+	if _err != nil {
+		return _err
+	}
+
+	params := &openapi.Params{
+		// 接口名称
+		Action: tea.String("ModifyInstanceAutoReleaseTime"),
+		// 接口版本
+		Version: tea.String("2014-05-26"),
+		// 接口协议
+		Protocol: tea.String("HTTPS"),
+		// 接口 HTTP 方法
+		Method: tea.String("POST"),
+		AuthType: tea.String("AK"),
+		Style: tea.String("RPC"),
+		// 接口 PATH
+		Pathname: tea.String("/"),
+		// 接口请求体内容格式
+		ReqBodyType: tea.String("json"),
+		// 接口响应体内容格式
+		BodyType: tea.String("json"),
+	}
+	println("AutoReleaseTime:",AutoReleaseTime)
+
+	// query params
+	queries := map[string]interface{}{}
+	queries["RegionId"] = tea.String("cn-hangzhou")
+	queries["InstanceId"] = tea.String(InstanceId)
+	queries["AutoReleaseTime"] = tea.String(AutoReleaseTime)
+	// runtime options
+	runtime := &util.RuntimeOptions{}
+	request := &openapi.OpenApiRequest{
+		Query: openapiutil.Query(queries),
+	}
+	// 复制代码运行请自行打印 API 的返回值
+	// 返回值实际为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
+	_result, _err := client.CallApi(params, request, runtime)
+	if _err != nil {
+		return _err
+	}
+	data, _ := json.Marshal(_result)
+	fmt.Println(string(data))
+	//fmt.Println("ccc",_result["body"].(map[string]interface{})["Instances"].(map[string]interface{})["Instance"])
+
+	return _err
+}
+//查询实例的详细信息列表
+func DescribeInstances () (_err error) {
+	client, _err := CreateClient()
+	if _err != nil {
+		return _err
+	}
+
+	params := &openapi.Params{
+		// 接口名称
+		Action: tea.String("DescribeInstances"),
+		// 接口版本
+		Version: tea.String("2014-05-26"),
+		// 接口协议
+		Protocol: tea.String("HTTPS"),
+		// 接口 HTTP 方法
+		Method: tea.String("POST"),
+		AuthType: tea.String("AK"),
+		Style: tea.String("RPC"),
+		// 接口 PATH
+		Pathname: tea.String("/"),
+		// 接口请求体内容格式
+		ReqBodyType: tea.String("json"),
+		// 接口响应体内容格式
+		BodyType: tea.String("json"),
+	}
+	// query params
+	queries := map[string]interface{}{}
+	queries["RegionId"] = tea.String("cn-hangzhou")
+	// runtime options
+	runtime := &util.RuntimeOptions{}
+	request := &openapi.OpenApiRequest{
+		Query: openapiutil.Query(queries),
+	}
+	// 复制代码运行请自行打印 API 的返回值
+	// 返回值实际为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
+	_result, _err := client.CallApi(params, request, runtime)
+	if _err != nil {
+		return _err
+	}
+	data, _ := json.Marshal(_result)
+	fmt.Println(string(data))
+	//fmt.Println("ccc",_result["body"].(map[string]interface{})["Instances"].(map[string]interface{})["Instance"])
+	fmt.Println("len",len(_result["body"].(map[string]interface{})["Instances"].(map[string]interface{})["Instance"].([]interface {})))
+	find_ecs := false
+	for _,v := range _result["body"].(map[string]interface{})["Instances"].(map[string]interface{})["Instance"].([]interface {}){
+		fmt.Println("InstanceName:",v.(map[string]interface{})["InstanceName"],"InstanceId:",v.(map[string]interface{})["InstanceId"])
+		// 使用 strings.Contains 检查字符串是否包含子字符串
+		if strings.Contains(v.(map[string]interface{})["InstanceName"].(string), "ecs-verify") {
+			find_ecs = true
+			now := time.Now()
+			oneHourLater := now.Add(time.Minute * 58)
+			//oneHourLater = oneHourLater.Add(-time.Hour * 8)
+			AutoReleaseTime := oneHourLater.Format(time.RFC3339)
+			fmt.Println("延期:", v.(map[string]interface{})["InstanceName"].(string),v.(map[string]interface{})["InstanceId"].(string),AutoReleaseTime)
+
+			ModifyInstanceAutoReleaseTime(v.(map[string]interface{})["InstanceId"].(string),AutoReleaseTime)
+		}
+	}
+
+
+	// 判断是否要创建
+	if !find_ecs {
+		err := RunInstances()
+		if err != nil {
+			panic(any(err))
+		}
+	}
+
+
+	return _err
+}
+
+/*
+{
+  "body": {
+    "Instances": {
+      "Instance": [{
+        "AdditionalInfo": {},
+        "AutoReleaseTime": "",
+        "ClusterId": "",
+        "Cpu": 2,
+        "CpuOptions": {
+          "CoreCount": 1,
+          "Numa": "ON",
+          "ThreadsPerCore": 2
+        },
+        "CreationTime": "2024-11-23T03:56Z",
+        "CreditSpecification": "",
+        "DedicatedHostAttribute": {
+          "DedicatedHostClusterId": "",
+          "DedicatedHostId": "",
+          "DedicatedHostName": ""
+        },
+        "DedicatedInstanceAttribute": {
+          "Affinity": "",
+          "Tenancy": ""
+        },
+        "DeletionProtection": false,
+        "DeploymentSetId": "",
+        "Description": "",
+        "DeviceAvailable": true,
+        "EcsCapacityReservationAttr": {
+          "CapacityReservationId": "",
+          "CapacityReservationPreference": ""
+        },
+        "EipAddress": {
+          "AllocationId": "",
+          "InternetChargeType": "",
+          "IpAddress": ""
+        },
+        "ExpiredTime": "2025-12-07T16:00Z",
+        "GPUAmount": 0,
+        "GPUSpec": "",
+        "HibernationOptions": {
+          "Configured": false
+        },
+        "HostName": "iZbp1as4p3kp4bip8dgrveZ",
+        "ImageId": "centos_7_9_x64_20G_alibase_20240628.vhd",
+        "ImageOptions": {},
+        "InnerIpAddress": {
+          "IpAddress": []
+        },
+        "InstanceChargeType": "PrePaid",
+        "InstanceId": "i-bp1as4p3kp4bip8dgrve",
+        "InstanceName": "冷链服务器",
+        "InstanceNetworkType": "vpc",
+        "InstanceType": "ecs.u1-c1m2.large",
+        "InstanceTypeFamily": "ecs.u1",
+        "InternetChargeType": "PayByBandwidth",
+        "InternetMaxBandwidthIn": 1000,
+        "InternetMaxBandwidthOut": 5,
+        "IoOptimized": true,
+        "Memory": 4096,
+        "MetadataOptions": {
+          "HttpEndpoint": "",
+          "HttpTokens": ""
+        },
+        "NetworkInterfaces": {
+          "NetworkInterface": [{
+            "MacAddress": "00:16:3e:01:0f:62",
+            "NetworkInterfaceId": "eni-bp156zuduohi3pw9j7th",
+            "PrimaryIpAddress": "172.20.11.83",
+            "PrivateIpSets": {
+              "PrivateIpSet": [{
+                "Primary": true,
+                "PrivateIpAddress": "172.20.11.83"
+              }]
+            },
+            "Type": "Primary"
+          }]
+        },
+        "OSName": "CentOS  7.9 64位",
+        "OSNameEn": "CentOS  7.9 64 bit",
+        "OSType": "linux",
+        "OperationLocks": {
+          "LockReason": []
+        },
+        "PrivateDnsNameOptions": {},
+        "PublicIpAddress": {
+          "IpAddress": ["47.97.103.163"]
+        },
+        "Recyclable": false,
+        "RegionId": "cn-hangzhou",
+        "ResourceGroupId": "",
+        "SaleCycle": "",
+        "SecurityGroupIds": {
+          "SecurityGroupId": ["sg-bp156zuduohi3pw66zbm"]
+        },
+        "SerialNumber": "7c66d46a-ddef-451d-b542-c518b819d54e",
+        "SpotPriceLimit": 0.0,
+        "SpotStrategy": "NoSpot",
+        "StartTime": "2024-12-22T11:47Z",
+        "Status": "Running",
+        "StoppedMode": "Not-applicable",
+        "VlanId": "",
+        "VpcAttributes": {
+          "NatIpAddress": "",
+          "PrivateIpAddress": {
+            "IpAddress": ["172.20.11.83"]
+          },
+          "VSwitchId": "vsw-bp11bjxe8djsv3c254bur",
+          "VpcId": "vpc-bp14wz0vpzqhssnuezw1j"
+        },
+        "ZoneId": "cn-hangzhou-h"
+      }]
+    },
+    "NextToken": "",
+    "PageNumber": 1,
+    "PageSize": 10,
+    "RequestId": "A3F8B366-6F44-59BD-AE01-805090689456",
+    "TotalCount": 1
+  },
+  "headers": {
+    "access-control-allow-origin": "*",
+    "access-control-expose-headers": "*",
+    "connection": "keep-alive",
+    "content-type": "application/json;charset=utf-8",
+    "date": "Thu, 20 Feb 2025 01:04:22 GMT",
+    "keep-alive": "timeout=25",
+    "vary": "Accept-Encoding",
+    "x-acs-request-id": "A3F8B366-6F44-59BD-AE01-805090689456",
+    "x-acs-trace-id": "c3aef4e6346f739c859a7d7a93723893"
+  },
+  "statusCode": 200
+}
+
+*/

+ 70 - 0
lib/albb/RunInstances.go

@@ -0,0 +1,70 @@
+// This file is auto-generated, don't edit it. Thanks.
+package albb
+
+import (
+	"encoding/json"
+	"fmt"
+	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
+	openapiutil "github.com/alibabacloud-go/openapi-util/service"
+	util "github.com/alibabacloud-go/tea-utils/v2/service"
+	"github.com/alibabacloud-go/tea/tea"
+	"time"
+)
+
+
+func RunInstances () (_err error) {
+	fmt.Println("RunInstances New")
+	client, _err := CreateClient()
+	if _err != nil {
+		return _err
+	}
+
+	params := &openapi.Params{
+		// 接口名称
+		Action: tea.String("RunInstances"),
+		// 接口版本
+		Version: tea.String("2014-05-26"),
+		// 接口协议
+		Protocol: tea.String("HTTPS"),
+		// 接口 HTTP 方法
+		Method: tea.String("POST"),
+		AuthType: tea.String("AK"),
+		Style: tea.String("RPC"),
+		// 接口 PATH
+		Pathname: tea.String("/"),
+		// 接口请求体内容格式
+		ReqBodyType: tea.String("json"),
+		// 接口响应体内容格式
+		BodyType: tea.String("json"),
+	}
+	// query params
+	queries := map[string]interface{}{}
+	queries["RegionId"] = tea.String("cn-hangzhou")
+	// 获取当前时间
+	now := time.Now()
+	// 向后推移一个小时
+	oneHourLater := now.Add(time.Minute * 58)
+	//oneHourLater = oneHourLater.Add(-time.Hour * 8)
+	println("AutoReleaseTime:",oneHourLater.Format("2006-01-02T15:04:05Z"))
+	//queries["AutoReleaseTime"] = tea.String("2025-02-19T21:05:00Z")
+	queries["AutoReleaseTime"] = tea.String(oneHourLater.Format(time.RFC3339) )
+	//queries["LaunchTemplateId"] = tea.String("lt-bp17ecmtdol5eq0skeff")
+	queries["LaunchTemplateName"] = tea.String("ecs-verify")
+	queries["LaunchTemplateVersion"] = tea.Int(1)
+	// runtime options
+	runtime := &util.RuntimeOptions{}
+	request := &openapi.OpenApiRequest{
+		Query: openapiutil.Query(queries),
+	}
+
+	// 复制代码运行请自行打印 API 的返回值
+	// 返回值实际为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。
+	_result, _err := client.CallApi(params, request, runtime)
+	if _err != nil {
+		return _err
+	}
+	data, _ := json.Marshal(_result)
+	fmt.Println(string(data))
+	return _err
+}
+

+ 26 - 0
lib/albb/inte.go

@@ -0,0 +1,26 @@
+package albb
+
+import (
+	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
+	"github.com/alibabacloud-go/tea/tea"
+)
+
+var _result_sdk = &openapi.Client{}
+var _result_is bool
+func CreateClient () (_result_sdk *openapi.Client,_err  error) {
+	if _result_is {
+		return _result_sdk, _err
+	}
+	// The project code leakage may result in the leakage of AccessKey, posing a threat to the security of all resources under the account. The following code examples are for reference only.
+	// It is recommended to use the more secure STS credential. For more credentials, please refer to: https://www.alibabacloud.com/help/en/alibaba-cloud-sdk-262060/latest/configure-credentials-378661.
+	config := &openapi.Config{
+		// Required, please ensure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_ID is set.
+		AccessKeyId: tea.String("LTAI5tFYbEUnUBH3sh7wV8Fj"),
+		// Required, please ensure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_SECRET is set.
+		AccessKeySecret: tea.String("D2LXL9oMNKUtpp2xqoH1CVIrEHy2vi"),
+	}
+	// See https://api.alibabacloud.com/product/Ecs.
+	config.Endpoint = tea.String("ecs.cn-hangzhou.aliyuncs.com")
+	_result_sdk, _err = openapi.NewClient(config)
+	return _result_sdk, _err
+}

+ 616 - 0
lib/lib.go

@@ -0,0 +1,616 @@
+package lib
+
+import (
+	"ColdVerify_server/conf"
+	"encoding/json"
+	"fmt"
+	"io"
+	"math/rand"
+	"net/http"
+	"os"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/nats-io/nats.go"
+	"github.com/signintech/gopdf"
+)
+
+var Nats *nats.Conn
+
+type JSONS struct {
+	//必须的大写开头
+	Code int16
+	Msg  string
+	Data interface{} // 泛型
+}
+
+type R_JSONS struct {
+	//必须的大写开头
+	List      interface{}
+	Num       int
+	Page      int
+	Page_size int
+	Pages     []Page_T
+}
+type R_JSONS_s struct {
+	//必须的大写开头
+	List      []interface{}
+	Num       int
+	Page      int
+	Page_size int
+	Pages     []Page_T
+}
+
+type LOG_JSONS struct {
+	//必须的大写开头
+	Class_1    string
+	Class_List interface{}
+	List       interface{}
+	Num        int
+	Page       int
+	Page_size  int
+	Pages      []Page_T
+}
+
+// func_page 分页   [{3 1} {4 2} {4 3} {4 4} {4 5} {4 6} {4 7} {4 8} {4 9} {5 2}]-
+type Page_T struct {
+	A int
+	V int64
+}
+
+func Func_page(Page int64, Page_size int64) (page_t_list []Page_T) {
+	if Page > 1 {
+		page_t_list = append(page_t_list, Page_T{A: 1, V: Page - 1})
+	}
+	i := int64(0)
+	for aa := int64(1); aa < 5; aa++ {
+		if Page-aa <= 0 {
+			break
+		}
+		page_t_list = append(page_t_list, Page_T{A: 2, V: Page - aa})
+		i++
+	}
+	page_t_list = append(page_t_list, Page_T{A: 3, V: Page})
+
+	for aa := int64(1); aa < 10-i; aa++ {
+		if Page_size < Page+aa {
+			break
+		}
+		page_t_list = append(page_t_list, Page_T{A: 4, V: Page + aa})
+	}
+	sort.Slice(page_t_list, func(i, j int) bool {
+		if page_t_list[i].V < page_t_list[j].V {
+			return true
+		}
+		return false
+	})
+	sort.Slice(page_t_list, func(i, j int) bool {
+		if page_t_list[i].A < page_t_list[j].A {
+			return true
+		}
+		return false
+
+	})
+	if Page < Page_size {
+		page_t_list = append(page_t_list, Page_T{A: 5, V: Page + 1})
+	}
+
+	return page_t_list
+}
+
+func Strval(value interface{}) string {
+	var key string
+	if value == nil {
+		return key
+	}
+
+	switch value.(type) {
+	case float64:
+		ft := value.(float64)
+		key = strconv.FormatFloat(ft, 'f', -1, 64)
+	case float32:
+		ft := value.(float32)
+		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
+	case int:
+		it := value.(int)
+		key = strconv.Itoa(it)
+	case uint:
+		it := value.(uint)
+		key = strconv.Itoa(int(it))
+	case int8:
+		it := value.(int8)
+		key = strconv.Itoa(int(it))
+	case uint8:
+		it := value.(uint8)
+		key = strconv.Itoa(int(it))
+	case int16:
+		it := value.(int16)
+		key = strconv.Itoa(int(it))
+	case uint16:
+		it := value.(uint16)
+		key = strconv.Itoa(int(it))
+	case int32:
+		it := value.(int32)
+		key = strconv.Itoa(int(it))
+	case uint32:
+		it := value.(uint32)
+		key = strconv.Itoa(int(it))
+	case int64:
+		it := value.(int64)
+		key = strconv.FormatInt(it, 10)
+	case uint64:
+		it := value.(uint64)
+		key = strconv.FormatUint(it, 10)
+	case string:
+		key = value.(string)
+	case []byte:
+		key = string(value.([]byte))
+	default:
+		newValue, _ := json.Marshal(value)
+		key = string(newValue)
+	}
+
+	return key
+}
+
+func To_int(value interface{}) int {
+	var key int
+	if value == nil {
+		return key
+	}
+	switch value.(type) {
+	case float64:
+		key = int(value.(float64))
+	case float32:
+		key = int(value.(float32))
+	case int:
+		key = int(value.(int))
+	case uint:
+		key = int(value.(uint))
+	case int8:
+		key = int(value.(int8))
+	case uint8:
+		key = int(value.(uint8))
+	case int16:
+		key = int(value.(int16))
+	case uint16:
+		key = int(value.(uint16))
+	case int32:
+		key = int(value.(int32))
+	case uint32:
+		key = int(value.(uint32))
+	case int64:
+		key = int(value.(int64))
+	case uint64:
+		key = int(value.(uint64))
+	case string:
+		key, _ = strconv.Atoi(value.(string))
+	case []byte:
+		key, _ = strconv.Atoi(string(value.([]byte)))
+	default:
+		newValue, _ := json.Marshal(value)
+		key, _ = strconv.Atoi(string(newValue))
+	}
+	return key
+}
+
+func To_float32(value interface{}) float32 {
+	var key float32
+	if value == nil {
+		return key
+	}
+
+	switch value.(type) {
+	case float64:
+		key = float32(value.(float64))
+	case float32:
+		key = float32(value.(float32))
+	case int:
+		key = float32(value.(int))
+	case uint:
+		key = float32(value.(uint))
+	case int8:
+		key = float32(value.(int8))
+	case uint8:
+		key = float32(value.(uint8))
+	case int16:
+		key = float32(value.(int16))
+	case uint16:
+		key = float32(value.(uint16))
+	case int32:
+		key = float32(value.(int32))
+	case uint32:
+		key = float32(value.(uint32))
+	case int64:
+		key = float32(value.(int64))
+	case uint64:
+		key = float32(value.(uint64))
+	case string:
+		key_float64, _ := strconv.ParseFloat(value.(string), 32/64)
+		key = float32(key_float64)
+	case []byte:
+		key_float64, _ := strconv.ParseFloat(string(value.([]byte)), 32/64)
+		key = float32(key_float64)
+	default:
+		newValue, _ := json.Marshal(value)
+		key_float64, _ := strconv.ParseFloat(string(newValue), 32/64)
+		key = float32(key_float64)
+	}
+
+	key_float64, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", key), 32/64)
+	key = float32(key_float64)
+
+	return key
+}
+
+func To_string(value interface{}) string {
+	var key string
+	if value == nil {
+		return key
+	}
+
+	switch value.(type) {
+	case float64:
+		ft := value.(float64)
+		key = strconv.FormatFloat(ft, 'f', -1, 64)
+	case float32:
+		ft := value.(float32)
+		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
+	case int:
+		it := value.(int)
+		key = strconv.Itoa(it)
+	case uint:
+		it := value.(uint)
+		key = strconv.Itoa(int(it))
+	case int8:
+		it := value.(int8)
+		key = strconv.Itoa(int(it))
+	case uint8:
+		it := value.(uint8)
+		key = strconv.Itoa(int(it))
+	case int16:
+		it := value.(int16)
+		key = strconv.Itoa(int(it))
+	case uint16:
+		it := value.(uint16)
+		key = strconv.Itoa(int(it))
+	case int32:
+		it := value.(int32)
+		key = strconv.Itoa(int(it))
+	case uint32:
+		it := value.(uint32)
+		key = strconv.Itoa(int(it))
+	case int64:
+		it := value.(int64)
+		key = strconv.FormatInt(it, 10)
+	case uint64:
+		it := value.(uint64)
+		key = strconv.FormatUint(it, 10)
+	case string:
+		key = value.(string)
+	case []byte:
+		key = string(value.([]byte))
+	default:
+		newValue, _ := json.Marshal(value)
+		key = string(newValue)
+	}
+	return key
+}
+
+func Random(min, max int) int {
+	rand.Seed(time.Now().Unix()) //Seed生成的随机数
+	return rand.Intn(max-min) + min
+}
+
+// 取文本(字符串)中间
+func GetBetweenStr(str, start, end string) string {
+	n := strings.Index(str, start)
+	if n == -1 {
+		n = 0
+	} else {
+		n = n + len(start) // 增加了else,不加的会把start带上
+	}
+	str = string([]byte(str)[n:])
+	m := strings.Index(str, end)
+	if m == -1 {
+		m = len(str)
+	}
+	str = string([]byte(str)[:m])
+	return str
+}
+
+// getYearMonthToDay 查询指定年份指定月份有多少天
+// @params year int 指定年份
+// @params month int 指定月份
+func GetYearMonthToDay(year int, month int) int {
+	// 有31天的月份
+	day31 := map[int]bool{
+		1:  true,
+		3:  true,
+		5:  true,
+		7:  true,
+		8:  true,
+		10: true,
+		12: true,
+	}
+	if day31[month] == true {
+		return 31
+	}
+	// 有30天的月份
+	day30 := map[int]bool{
+		4:  true,
+		6:  true,
+		9:  true,
+		11: true,
+	}
+	if day30[month] == true {
+		return 30
+	}
+	// 计算是平年还是闰年
+	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
+		// 得出2月的天数
+		return 29
+	}
+	// 得出2月的天数
+	return 28
+}
+
+const (
+	AlignLeft   = 4
+	AlignCenter = 5
+	AlignRight  = 6
+)
+const (
+	ValignTop    = 1
+	ValignMiddle = 2
+	ValignBottom = 3
+)
+
+func RectFillColor(pdf *gopdf.GoPdf,
+	text string,
+	fontSize int,
+	x, y, w, h float64,
+	r, g, b uint8,
+	align, valign int,
+) {
+
+	pdf.SetLineWidth(0.1)
+	pdf.SetFillColor(r, g, b) //setup fill color
+	pdf.SetLineType("")       // 线条样式
+	pdf.RectFromUpperLeftWithStyle(x, y, w, h, "FD")
+	pdf.SetFillColor(0, 0, 0)
+
+	if align == AlignCenter {
+		textw, _ := pdf.MeasureTextWidth(text)
+		x = x + (w / 2) - (textw / 2)
+	} else if align == AlignRight {
+		textw, _ := pdf.MeasureTextWidth(text)
+		x = x + w - textw
+	}
+
+	pdf.SetX(x)
+
+	if valign == ValignMiddle {
+		y = y + (h / 2) - (float64(fontSize) / 2)
+	} else if valign == ValignBottom {
+		y = y + h - float64(fontSize)
+	}
+
+	pdf.SetY(y)
+	pdf.Cell(nil, text)
+}
+
+func Create_Dir(path string) error {
+	_, err := os.Stat(path)
+	// 如果返回的错误为nil,说明文件或文件夹存在
+	if err == nil {
+		return nil
+	}
+	if err = os.Mkdir(path, 0777); err != nil {
+		return err
+	}
+	return nil
+}
+
+// 获取正在运行的函数名
+func FuncName() string {
+	pc := make([]uintptr, 1)
+	runtime.Callers(2, pc)
+	f := runtime.FuncForPC(pc[0])
+	return f.Name()
+}
+
+// golang获取程序运行路径
+func GetCurrentDirectory() string {
+	if conf.RunMode == "dev" {
+		currentPath, err := os.Getwd()
+		if err != nil {
+			logs.Error("获取程序运行路径失败", err)
+		}
+		return currentPath
+	}
+	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
+	return strings.Replace(dir, "\\", "/", -1)
+}
+
+func ConvertMinutesToDHM(minutes int) string {
+	if minutes == 0 {
+		return ""
+	}
+	days := minutes / 1440           // 1天 = 1440分钟
+	hours := (minutes % 1440) / 60   // 1小时 = 60分钟
+	remainingMinutes := minutes % 60 // 剩余分钟
+
+	if minutes < 60 {
+		return fmt.Sprintf("%dm", remainingMinutes)
+	}
+
+	if minutes < 1440 && minutes >= 60 {
+		return fmt.Sprintf("%dh%dm", hours, remainingMinutes)
+	}
+
+	return fmt.Sprintf("%dd%dh%dm", days, hours, remainingMinutes)
+}
+
+// 判断是否是本月的
+func IsInCurrentMonth(dateStr string) (bool, error) {
+	// 定义时间格式
+	layout := "2006-01-02 15:04:05"
+
+	// 解析字符串时间
+	parsedTime, err := time.Parse(layout, dateStr)
+	if err != nil {
+		return false, err
+	}
+
+	// 获取当前时间
+	now := time.Now()
+
+	// 判断年份和月份是否相同
+	return parsedTime.Year() == now.Year() && parsedTime.Month() == now.Month(), nil
+}
+
+func GetWatermarkPdf(pdfURL string) (string, error) {
+	url := conf.PdfProcessingHost + "/add_watermark"
+	method := "POST"
+
+	payload := strings.NewReader(fmt.Sprintf(`{"pdf_url": "%s"}`, pdfURL))
+
+	client := &http.Client{}
+	req, err := http.NewRequest(method, url, payload)
+
+	if err != nil {
+		return "", err
+	}
+	req.Header.Add("Content-Type", "application/json")
+
+	res, err := client.Do(req)
+	if err != nil {
+		return "", err
+	}
+	defer res.Body.Close()
+
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", err
+	}
+
+	// 解析JSON响应
+	var result struct {
+		Success         bool   `json:"success"`
+		Error           string `json:"error"`
+		WatermarkPdfURL string `json:"watermark_pdf_url"`
+	}
+
+	if err = json.Unmarshal(body, &result); err != nil {
+		return "", err
+	}
+
+	if !result.Success {
+		return "", fmt.Errorf(result.Error)
+	}
+	return result.WatermarkPdfURL, nil
+}
+func GetSignaturePdf(pdfURL string) (string, error) {
+	url := conf.PdfProcessingHost + "/add_signature"
+	method := "POST"
+
+	payload := strings.NewReader(fmt.Sprintf(`{"pdf_url": "%s"}`, pdfURL))
+
+	client := &http.Client{}
+	req, err := http.NewRequest(method, url, payload)
+
+	if err != nil {
+		return "", err
+	}
+	req.Header.Add("Content-Type", "application/json")
+
+	res, err := client.Do(req)
+	if err != nil {
+		return "", err
+	}
+	defer res.Body.Close()
+
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", err
+	}
+
+	// 解析JSON响应
+	var result struct {
+		Success         bool   `json:"success"`
+		Error           string `json:"error"`
+		SignaturePdfURL string `json:"signature_pdf_url"`
+	}
+
+	if err = json.Unmarshal(body, &result); err != nil {
+		return "", err
+	}
+
+	if !result.Success {
+		return "", fmt.Errorf(result.Error)
+	}
+	return result.SignaturePdfURL, nil
+}
+
+// ProcessImage 处理图片,传入图片链接和是否加盖印章,返回处理后的图片链接
+func ProcessImage(imageURL string, isSeal bool) (string, error) {
+	url := conf.PdfProcessingHost + "/process_image"
+	method := "POST"
+
+	// 构建请求体
+	requestBody := struct {
+		ImageURL string `json:"image_url"`
+		IsSeal   bool   `json:"is_seal"`
+	}{
+		ImageURL: imageURL,
+		IsSeal:   isSeal,
+	}
+
+	jsonData, err := json.Marshal(requestBody)
+	if err != nil {
+		return "", fmt.Errorf("构建请求参数失败: %v", err)
+	}
+
+	payload := strings.NewReader(string(jsonData))
+
+	client := &http.Client{}
+	req, err := http.NewRequest(method, url, payload)
+	if err != nil {
+		return "", fmt.Errorf("创建请求失败: %v", err)
+	}
+	req.Header.Add("Content-Type", "application/json")
+
+	res, err := client.Do(req)
+	if err != nil {
+		return "", fmt.Errorf("请求失败: %v", err)
+	}
+	defer res.Body.Close()
+
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", fmt.Errorf("读取响应失败: %v", err)
+	}
+
+	// 解析JSON响应
+	var result struct {
+		Success  bool   `json:"success"`
+		Message  string `json:"message"`
+		ImageURL string `json:"image_url"`
+	}
+
+	if err = json.Unmarshal(body, &result); err != nil {
+		return "", fmt.Errorf("解析响应失败: %v", err)
+	}
+
+	if !result.Success {
+		return "", fmt.Errorf("图片处理失败: %s", result.Message)
+	}
+
+	return result.ImageURL, nil
+}

+ 97 - 0
lib/libString.go

@@ -0,0 +1,97 @@
+package lib
+
+import (
+	"fmt"
+	"math"
+	"math/rand"
+	"regexp"
+	"strings"
+	"time"
+)
+
+// #取得随机字符串:通过打乱slice来操作
+func GetRandstring(length int, char string, rand_x int64) string {
+	if length < 1 {
+		return ""
+	}
+
+	if len(char) <= 6 || len(char) <= length {
+		char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+	}
+
+	charArr := strings.Split(char, "")
+	ran := rand.New(rand.NewSource(time.Now().UnixMilli() + rand_x))
+
+	l := len(charArr)
+	for i := l - 1; i > 0; i-- {
+		r := ran.Intn(i)
+		charArr[r], charArr[i] = charArr[i], charArr[r]
+	}
+	rchar := charArr[:length]
+	return strings.Join(rchar, "")
+}
+
+// 检查日期格式
+func IsDateStr(date string) bool {
+	if _, err := time.Parse("2006-01-02", date); err != nil {
+		return false
+	}
+	return true
+}
+
+// 转化
+func TimeStrToTime(T_time string) (time.Time, bool) {
+	stamp, err := time.ParseInLocation("2006-01-02 15:04:05", T_time, time.Local) // +8
+	if err != nil {
+		return time.Time{}, false
+	}
+
+	return stamp, true
+}
+
+func TimeStrToTime2(T_time string) (time.Time, bool) {
+	stamp, err := time.ParseInLocation("2006-01-02 15:04:05", T_time, time.Local) // +8
+	if err != nil {
+		return time.Time{}, false
+	}
+
+	return stamp, true
+}
+
+// 判断字符串是否为纯数字
+func IsNumeric(str string) bool {
+	// 定义一个正则表达式来匹配纯数字字符串
+	re := regexp.MustCompile(`^\d+$`)
+	return re.MatchString(str)
+}
+
+// 计算两个时间字符串之间的分钟差
+func MinutesDifference(startTime, endTime string) (float64, error) {
+	layout := "2006-01-02 15:04:05"
+
+	st, err := time.Parse(layout, startTime)
+	if err != nil {
+		return 0, fmt.Errorf("error parsing timeStr1: %w", err)
+	}
+
+	et, err := time.Parse(layout, endTime)
+	if err != nil {
+		return 0, fmt.Errorf("error parsing timeStr2: %w", err)
+	}
+	duration := et.Sub(st)
+	minutes := math.Ceil(duration.Minutes())
+	return minutes, nil
+}
+
+// 切割
+func SplitStringSeparator(str string, separator string) (r []string) {
+	if len(str) == 0 {
+		return r
+	}
+	if !strings.Contains(str, separator) {
+		return []string{str}
+	}
+	r = strings.Split(strings.Trim(str, separator), separator)
+
+	return r
+}

+ 151 - 0
lib/wx/qywx.go

@@ -0,0 +1,151 @@
+package wx
+
+import (
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+	"time"
+)
+
+var Qytoken string
+func init() {
+	go func() {
+		gettoken()
+		time.Sleep(time.Hour * 24)
+	}()
+}
+
+func gettoken() {
+
+	url := "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ww0befb06f19910467&corpsecret=83STGNLwghXsjYRacRhUHPL-fkkO1jwsMgabjXcRLyg"
+	method := "GET"
+
+	client := &http.Client {
+	}
+	req, err := http.NewRequest(method, url, nil)
+
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+
+	res, err := client.Do(req)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	defer res.Body.Close()
+
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	fmt.Println(string(body))
+
+	// Product _
+	type Product struct {
+		Access_token      string  `json:"access_token"`
+		Errcode    int     `json:"errcode"`
+	}
+
+	p := &Product{}
+	err = json.Unmarshal(body, p)
+	if err != nil {
+		time.Sleep(time.Second * 1)
+		gettoken()
+	}
+	if p.Errcode != 0 {
+		time.Sleep(time.Second * 1)
+		gettoken()
+	}
+
+	Qytoken = p.Access_token
+
+}
+// Message represents the JSON structure
+type Message struct {
+	Touser           string `json:"touser"`
+	Toparty          string `json:"toparty"`
+	Totag            string `json:"totag"`
+	Msgtype          string `json:"msgtype"`
+	Agentid          int    `json:"agentid"`
+	Text             Text    `json:"text"`
+	Safe             int    `json:"safe"`
+	EnableIDTrans    int    `json:"enable_id_trans"`
+	EnableDuplicateCheck int `json:"enable_duplicate_check"`
+}
+
+// Text represents the text component of the message
+type Text struct {
+	Content string `json:"content"`
+}
+// @all  LiKeHui|xxxx
+func WxSend(User,Content string) {
+	if len(User) == 0 {
+		logs.Println("Error User 为空")
+		return
+	}
+	User = Account.AdminWXListToMap(Account.Read_Admin_List_ALL_1())[User]
+	if len(User) == 0 {
+		logs.Println("Error User 为空")
+		return
+	}
+	url := "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+Qytoken
+	method := "POST"
+
+	// Example of creating and marshaling the struct to JSON
+	message := Message{
+		Touser:           User,
+		Toparty:          "@all",
+		Totag:            "@all",
+		Msgtype:          "text",
+		Agentid:          1000008,
+		Text:             Text{Content: Content},
+		Safe:             0,
+		EnableIDTrans:    0,
+		EnableDuplicateCheck: 0,
+	}
+
+	jsonData, err := json.Marshal(message)
+	if err != nil {
+		logs.Println("Error marshalling to JSON:", err)
+		return
+	}
+	logs.Println(string(jsonData))
+	payload := strings.NewReader(string(jsonData))
+
+	client := &http.Client {
+	}
+	req, err := http.NewRequest(method, url, payload)
+
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	req.Header.Add("Content-Type", "application/json")
+
+	res, err := client.Do(req)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	defer res.Body.Close()
+
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	logs.Println("WxSend:",string(body))
+	if strings.Contains(string(body),"access_token expired"){
+		gettoken()
+		time.Sleep(time.Second * 1)
+		WxSend(User,Content)
+	}
+
+}

+ 58 - 0
logs/LogPrintln.go

@@ -0,0 +1,58 @@
+package logs
+
+import (
+	"ColdVerify_server/conf"
+	"github.com/astaxie/beego/logs"
+)
+
+var logx *logs.BeeLogger
+
+func init() {
+	logx = logs.NewLogger()
+	logx.SetLogger(logs.AdapterFile, `{"filename":"logs/logx/logx.log"}`)
+	logx.EnableFuncCallDepth(true)
+	logx.SetLogFuncCallDepth(3)
+	if conf.RunMode == "dev" {
+		logx.SetLogger(logs.AdapterConsole)
+	}
+}
+
+func Println(format string, v ...interface{}) {
+	for _, _ = range v {
+		format += " %v"
+	}
+	logx.Info(format, v...)
+}
+
+// Debug Log DEBUG level message.
+func Debug(format string, v ...interface{}) {
+	for _, _ = range v {
+		format += " %v"
+	}
+	logx.Debug(format, v...)
+}
+
+// Info Log ERROR level message.
+func Info(format string, v ...interface{}) {
+	for _, _ = range v {
+		format += " %v"
+	}
+	logx.Info(format, v...)
+}
+
+// Error Log ERROR level message.
+func Error(format string, v ...interface{}) {
+	for _, _ = range v {
+		format += " %v"
+	}
+
+	logx.Error(format, v...)
+}
+
+// Warning Log WARNING level message.
+func Warning(format string, v ...interface{}) {
+	for _, _ = range v {
+		format += " %v"
+	}
+	logx.Warning(format, v...)
+}

+ 7 - 0
logs/nohup.sh

@@ -0,0 +1,7 @@
+#!/bin/sh 
+#获取前一天的日期 
+date=`date -d "yesterday" +%Y_%m_%d` 
+#复制原始nohup.out到备份目录,并以前一天的日期进行命名 
+cp /bzd/project/ColdVerify_server/log/nohup.out /bzd/project/ColdVerify_server/log/$date.out 
+#清空原始nohup.out中的内容
+cat /dev/null > /bzd/project/ColdVerify_server/log/nohup.out

+ 252 - 0
models/Account/Admin.go

@@ -0,0 +1,252 @@
+package Account
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type Admin struct {
+	Id              int    `orm:"column(ID);size(11);auto;pk"`
+	T_uuid          string `orm:"size(256);null"`      //
+	T_power         int    `orm:"size(2);;default(0)"` // 权限  0
+	T_name          string `orm:"size(256);null"`      // 姓名
+	T_user          string `orm:"size(256);null"`      // 用户名
+	T_pass          string `orm:"size(256);null"`      // 密码
+	T_wxname        string `orm:"size(256);null"`      // 微信name
+	T_signature_img string `orm:"size(256);null"`      // 签名图片
+
+	T_State          int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
+	T_Distributor_id string    `orm:"size(256);null"`                                        // 分销商
+	CreateTime       time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime       time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+type Admin_R struct {
+	T_uuid           string
+	T_power          int    // 权限
+	T_power_name     string // 权限
+	T_name           string // 姓名
+	T_user           string // 用户名
+	T_wxname         string // 企业微信
+	T_Distributor_id string // 经销商id
+	T_signature_img  string // 签名图片
+}
+
+func (t *Admin) TableName() string {
+	return "admin" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(Admin))
+
+}
+func AdminToAdmin_R(T Admin, powerMap map[int]string) (T_r Admin_R) {
+	T_r.T_uuid = T.T_uuid
+	T_r.T_power = T.T_power
+	T_r.T_name = T.T_name
+	T_r.T_user = T.T_user
+	T_r.T_wxname = T.T_wxname
+	T_r.T_power_name = powerMap[T.T_power]
+	T_r.T_Distributor_id = T.T_Distributor_id
+	T_r.T_signature_img = T.T_signature_img
+	return T_r
+}
+
+// 获取 ByT_user
+func Read_Admin_ByT_user(T_user string) (e error, r Admin) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Admin))
+	e = qs.Filter("T_user", T_user).Filter("T_State", 1).One(&r)
+	return e, r
+}
+
+// 获取 ByT_uuid
+func Read_Admin_ByT_uuid(T_uuid string) (e error, r Admin) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Admin))
+	e = qs.Filter("T_uuid", T_uuid).Filter("T_State", 1).One(&r)
+	return e, r
+}
+
+// 添加
+func Add_Admin(m Admin) (id int64, err error) {
+	o := orm.NewOrm()
+
+	id, err = o.Insert(&m)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return id, err
+}
+
+func Read_Admin_verification(T_user string, T_pass string) (error, Admin) {
+	o := orm.NewOrm()
+	r := Admin{T_user: T_user, T_pass: T_pass, T_State: 1}
+	err := o.Read(&r, "T_user", "T_pass", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return err, r
+}
+
+// 获取列表
+func Read_Admin_List(T_Distributor_id string, T_name string, page int, page_z int, powerMap map[int]string) ([]Admin_R, int) {
+
+	o := orm.NewOrm()
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = (page - 1) * page_z
+	}
+	qs := o.QueryTable(new(Admin))
+	var r []Admin
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).AndCond(cond.Or("T_name__icontains", T_name).Or("T_user__icontains", T_name))
+	if len(T_Distributor_id) > 0 {
+		// 查询经销商用户数据
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	} else {
+		// 只查询内部管理员数据
+		cond1 = cond1.AndCond(cond1.Or("T_Distributor_id__isnull", true).Or("T_Distributor_id", ""))
+	}
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var Admin_r []Admin_R
+	for _, v := range r {
+		Admin_r = append(Admin_r, AdminToAdmin_R(v, powerMap))
+	}
+
+	return Admin_r, int(cnt)
+
+}
+
+// 修改
+func Update_Admin(m Admin, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+
+		return true
+	}
+	return false
+}
+
+// 删除
+func Delete_Admin(v Admin) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_Admin_(v Admin) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 获取全部列表
+func Read_Admin_List_ALL() (maps []Admin) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Admin))
+
+	qs.Filter("T_State", 1).OrderBy("Id").All(&maps)
+	return maps
+}
+
+// 获取全部列表-包括软删除数据
+func Read_Admin_List_ALL_1() (maps []Admin) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Admin))
+
+	qs.OrderBy("Id").All(&maps)
+	return maps
+}
+
+// 获取全部列表
+func Read_Admin_List_ALL_Power(T_Distributor_id string, T_name string, PowerMaps map[int]string) (maps []AdminPower_R) {
+
+	o := orm.NewOrm()
+	var r []Admin
+	qs := o.QueryTable(new(Admin))
+	if len(T_Distributor_id) > 0 {
+		qs = qs.Filter("T_Distributor_id", T_Distributor_id)
+	}
+	if len(T_name) > 0 {
+		qs = qs.Filter("T_name__icontains", T_name)
+	}
+	qs.Filter("T_State", 1).OrderBy("Id").All(&r)
+	// 转换
+	var Admin_Power_r []AdminPower_R
+	for _, v := range r {
+		Admin_Power_r = append(Admin_Power_r, AdminToAdminPower_R(v, PowerMaps))
+	}
+	return Admin_Power_r
+}
+
+// {"uuid":"name"}
+func AdminListToMap(A []Admin) map[string]string {
+	maps := make(map[string]string, len(A))
+	for _, v := range A {
+		maps[v.T_uuid] = v.T_name
+	}
+	return maps
+}
+
+func AdminWXListToMap(A []Admin) map[string]string {
+	maps := make(map[string]string, len(A))
+	for _, v := range A {
+		maps[v.T_uuid] = v.T_wxname
+	}
+	return maps
+}
+
+type AdminPower_R struct {
+	T_uuid       string `orm:"column(t_uuid)"`
+	T_name       string `orm:"column(t_name)"`       // 姓名
+	T_power_name string `orm:"column(t_power_name)"` // 权限
+}
+
+// PowerMaps {1:'管理员'}
+func AdminToAdminPower_R(T Admin, PowerMaps map[int]string) (T_r AdminPower_R) {
+	T_power_name, ok := PowerMaps[T.T_power]
+	if !ok {
+		T_power_name = ""
+	}
+	T_r.T_uuid = T.T_uuid
+	T_r.T_name = T.T_name
+	T_r.T_power_name = T_power_name
+	return T_r
+}
+
+// 获取全部列表
+func Read_Admin_List_ALL_T_power(T_power int) []Admin {
+
+	o := orm.NewOrm()
+	var r []Admin
+	qs := o.QueryTable(new(Admin))
+
+	qs.Filter("T_power", T_power).Filter("T_State", 1).OrderBy("Id").All(&r)
+
+	return r
+}

+ 132 - 0
models/Account/Power.go

@@ -0,0 +1,132 @@
+package Account
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	"time"
+)
+
+type UserPower struct {
+	Id     int    `orm:"column(ID);size(11);auto;pk"`
+	T_name string `orm:"size(256);null"` //  权限名称
+
+	Logs_Sys_r  int `orm:"size(2);;default(0)"` //  系统日志
+	Logs_User_r int `orm:"size(2);;default(0)"` //  用户日志
+
+	T_State    int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+func (t *UserPower) TableName() string {
+	return "user_power" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(UserPower))
+
+}
+
+// 修改
+func Update_UserPower_ById_Basics(m UserPower) (err error) {
+	o := orm.NewOrm()
+	v := UserPower{Id: m.Id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		m.Id = v.Id
+		if num, err = o.Update(&m, "Power_name", "Power_Administration", "Power_User_r", "Power_User_entry", "Power_Device_r", "Power_Device_a", "Power_Device_Parameter_e", "Power_DeviceSensor_Class", "Power_DeviceSensor_Parameter_e", "Power_DeviceSensor_Compensate_e", "Power_Device_Bind_e", "Power_DataScreen_r", "Logs_Sys_r", "Logs_User_r"); err == nil {
+			logs.Println("Number of records updated in database:", num)
+		}
+	}
+	return err
+}
+
+// 添加
+func Add_UserPower(m UserPower) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(&m)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return id, err
+}
+
+// 获取 ById
+func Read_UserPower_ById(Id int) (r UserPower, err error) {
+	o := orm.NewOrm()
+	r = UserPower{Id: Id}
+	err = o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return r, err
+}
+
+// 获取列表
+func Read_Power_List_ALL_1() (maps []UserPower) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(UserPower))
+
+	qs.Filter("T_State", 1).OrderBy("Id").All(&maps)
+
+	return maps
+}
+
+// 获取列表
+func Read_Power_List_ALL_Admin_Power(T_power int) (maps []UserPower) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(UserPower))
+
+	qs.Filter("T_State", 1).Filter("Id__gte", T_power).OrderBy("Id").All(&maps)
+
+	return maps
+}
+
+// 获取列表
+func Read_Power_List_ALL(page int, Power_name string) (maps []UserPower, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(UserPower))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * conf.Page_size)
+	}
+
+	qs.Limit(conf.Page_size, offset).Filter("Power_name__icontains", Power_name).Filter("T_State", 1).OrderBy("Id").All(&maps)
+	cnt, _ = qs.Filter("Power_name__icontains", Power_name).Filter("T_State", 1).Count()
+
+	return maps, cnt
+}
+
+// 修改
+func Update_Delete_UserPower_Byid(Id int) (err error) {
+	o := orm.NewOrm()
+	v := UserPower{Id: Id}
+	// ascertain id exists in the database
+	if err = o.Read(&v); err == nil {
+		var num int64
+		v.T_State = 0
+		if num, err = o.Update(&v, "T_State"); err == nil {
+			logs.Println("Number of records updated in database:", num)
+		}
+	}
+	return err
+}
+
+func UserPowerListToPowerMap(T []UserPower) map[int]string {
+	maps := make(map[int]string, len(T))
+	for _, v := range T {
+		maps[v.Id] = v.T_name
+	}
+	return maps
+}

+ 130 - 0
models/Account/Tokey.go

@@ -0,0 +1,130 @@
+package Account
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/logs"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	uuid "github.com/satori/go.uuid"
+	"log"
+	"time"
+)
+
+var redisCache_Tokey cache.Cache
+
+func init() {
+	//注册模型
+	//orm.RegisterModel(new(Tokey))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_Tokey", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_Tokey, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_Tokey == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+	}
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_Tokey_Set(key string, r string) (err error) {
+	err = redisCache_Tokey.Put(key, r, 24*7*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", r, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_Tokey_Get(key string) (r string, is bool) {
+	if redisCache_Tokey.IsExist(key) {
+		//println("找到key:",key)
+		v := redisCache_Tokey.Get(key)
+		value := string(v.([]byte))
+		return value, true
+	}
+	//println("没有 找到key:",key)
+	return "", false
+}
+
+func Redis_DelK(key string) (err error) {
+	err = redisCache_Tokey.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 验证 TOKEY
+func Read_Tokey(User_tokey string) (string, bool) {
+
+	return Redis_Tokey_Get(User_tokey)
+}
+
+// 添加 Tokey
+func Add_Tokey(User_uuid string) (Tokey string) {
+
+	for true {
+		Tokey = uuid.NewV4().String()
+		_, is := Redis_Tokey_Get(Tokey)
+		if !is {
+			break
+		}
+		logs.Info("申请 TOKEY 重复!重新生成。", Tokey)
+	}
+	Redis_Tokey_Set(Tokey, User_uuid)
+
+	return Tokey
+}
+
+// 登录验证
+func Verification(GetCookie string, GetString string) (User, bool) {
+	// 自适应 参数
+	User_tokey := GetCookie
+	if len(User_tokey) == 0 {
+		User_tokey = GetString
+	}
+	if len(User_tokey) == 0 {
+		return User{}, false
+	}
+	// 判断 tokey 是否存在
+	tokey, is := Read_Tokey(User_tokey)
+	if !is {
+		return User{}, false
+	}
+
+	err, user_r := Read_User_ByT_uuid(tokey)
+	if err != nil {
+		return User{}, false
+	}
+	log.Println("登录 User_name 为:", user_r.T_name)
+	return user_r, true
+}
+
+// 登录验证
+func Verification_Admin(GetCookie string, GetString string) (Admin, bool) {
+	// 自适应 参数
+	User_tokey := GetCookie
+	if len(User_tokey) == 0 {
+		User_tokey = GetString
+	}
+	if len(User_tokey) == 0 {
+		return Admin{}, false
+	}
+	// 判断 tokey 是否存在
+	tokey, is := Read_Tokey(User_tokey)
+	if !is {
+		return Admin{}, false
+	}
+
+	err, user_r := Read_Admin_ByT_uuid(tokey)
+	if err != nil {
+		return Admin{}, false
+	}
+	log.Println("登录 Admin_name 为:", user_r.T_name)
+	return user_r, true
+}

+ 643 - 0
models/Account/User.go

@@ -0,0 +1,643 @@
+package Account
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"errors"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	uuid "github.com/satori/go.uuid"
+)
+
+type User struct {
+	Id               int    `orm:"column(ID);size(11);auto;pk"`
+	T_Distributor_id string `orm:"size(256);null"` // 分销商id
+	T_uuid           string `orm:"size(256);null"` //
+	//T_power    int       `orm:"size(2);default(0)"`                                    // 权限
+	T_name    string `orm:"size(256);null"`      // 某某公司名称
+	T_pass    string `orm:"size(256);null"`      // 密码 MD5
+	T_passstr string `orm:"size(256);null"`      // 密码明文
+	T_pid     int    `orm:"size(11);default(0)"` // 父级ID
+	T_path    string `orm:"size(1000);null"`     // 路径,如:1/2/3
+
+	T_Show     int       `orm:"size(200);default(1)"`                                  // 0隐藏  1公开
+	T_State    int       `orm:"size(200);default(1)"`                                  // 0删除  1正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+type User_R struct {
+	Id                 int    // ID
+	T_uuid             string //
+	T_Distributor_id   string //
+	T_Distributor_name string //
+	//T_power   int    // 权限
+	T_name    string // 某某公司名称
+	T_passstr string // 密码明文
+	T_pid     int    // 父级ID
+	T_path    string // 路径
+	T_Show    int    //  0  1
+	T_State   int    //  0  1
+}
+
+func (t *User) TableName() string {
+	return "user" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(User))
+
+}
+
+// -------------------------------------------------------------
+func UserToUser_R(T User, distributorMap map[string]string) (T_r User_R) {
+	T_r.Id = T.Id
+	T_r.T_uuid = T.T_uuid
+	T_r.T_Distributor_id = T.T_Distributor_id
+	T_Distributor_name, ok := distributorMap[T.T_Distributor_id]
+	if !ok {
+		T_Distributor_name = ""
+	}
+	T_r.T_Distributor_name = T_Distributor_name
+	//T_r.T_power = T.T_power
+	T_r.T_name = T.T_name
+	T_r.T_passstr = T.T_passstr
+	T_r.T_pid = T.T_pid
+	T_r.T_path = T.T_path
+	T_r.T_Show = T.T_Show
+	T_r.T_State = T.T_State
+
+	//......
+	return T_r
+}
+
+// 获取 ById
+func Read_User_ByT_uuid(T_uuid string) (e error, r User) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(User))
+	e = qs.Filter("T_uuid", T_uuid).Filter("T_State", 1).One(&r)
+	return e, r
+}
+
+func Read_User_verification(T_user string, T_pass string) (error, User) {
+	o := orm.NewOrm()
+	r := User{T_name: T_user, T_pass: T_pass, T_State: 1}
+	err := o.Read(&r, "T_name", "T_pass", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return err, r
+}
+
+// ----------------
+
+// 获取 ById
+func Read_User_ById(id int) (r User, is bool) {
+	o := orm.NewOrm()
+	r = User{Id: id, T_State: 1}
+	err := o.Read(&r, "Id", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_User(T_uuid string) (r User, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(User))
+	err := qs.Filter("T_uuid", T_uuid).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 获取 By T_name
+func Read_UserByT_name(T_name string) (r User, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(User))
+	err := qs.Filter("T_name", T_name).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_User(r User) (id int64, is bool) {
+	o := orm.NewOrm()
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_uuid = uuid.NewV4().String()
+		err := o.Read(&r, "T_uuid") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 删除
+func Delete_User(v User) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_User_(v User) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		log.Println("Number of records updated in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_User(m User, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		log.Println("Number of records updated in database:", num)
+
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_User_List(T_Distributor_id string, T_name string, page int, page_z int, distributorMap map[string]string) ([]User_R, int64) {
+	o := orm.NewOrm()
+
+	// 也可以直接使用 Model 结构体作为表名
+	var r []User
+	qs := o.QueryTable(new(User))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+
+	// 如果有名称搜索,获取包含所有子公司的ID列表
+	if len(T_name) > 0 {
+		userIds, err := GetUserIdsByNameWithChildren(T_Distributor_id, T_name)
+		if err == nil && len(userIds) > 0 {
+			cond1 = cond1.And("Id__in", userIds)
+		} else {
+			// 如果没有匹配结果,使用原来的模糊搜索
+			cond1 = cond1.And("T_name__icontains", T_name)
+		}
+	}
+
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, cnt
+}
+func List_All_For_ERP(T_name string, CreateTime string, distributorMap map[string]string) ([]User_R, int64) {
+	o := orm.NewOrm()
+
+	// 也可以直接使用 Model 结构体作为表名
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+	if len(T_name) > 0 {
+		cond1 = cond1.And("T_name__icontains", T_name)
+	}
+	if len(CreateTime) > 0 {
+		start := CreateTime + " 00:00:00"
+		end := CreateTime + " 23:59:59"
+		log.Println("CreateTime_s:", start, end)
+		cond1 = cond1.And("CreateTime__gte", start).And("CreateTime__lte", end)
+	}
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, cnt
+}
+
+// 获取全部列表
+func Read_User_List_ALL() (maps []User) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Admin))
+
+	qs.Filter("T_State", 1).OrderBy("Id").All(&maps)
+	return maps
+}
+
+// 获取全部列表-包括软删除数据
+func Read_User_List_ALL_1() (maps []User) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(User))
+
+	qs.OrderBy("Id").All(&maps)
+	return maps
+}
+
+// {"uuid":"name"}
+func UserListToMap(T []User) map[string]string {
+	maps := make(map[string]string, len(T))
+	for _, v := range T {
+		maps[v.T_uuid] = v.T_name
+	}
+	return maps
+}
+
+func Read_User_T_uuid_ListByT_name(T_name string) (list []string) {
+	o := orm.NewOrm()
+
+	// 也可以直接使用 Model 结构体作为表名
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).AndCond(cond.Or("T_name__icontains", T_name))
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	// 转换
+	for _, v := range r {
+		list = append(list, v.T_uuid)
+	}
+
+	return list
+}
+
+// 树形结构相关函数
+
+// 根据公司名称获取公司ID列表(包含所有子公司)
+func GetUserIdsByNameWithChildren(T_Distributor_id string, T_name string) ([]int, error) {
+	if T_name == "" {
+		return nil, nil
+	}
+
+	o := orm.NewOrm()
+	var matchedUsers []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).And("T_name__icontains", T_name)
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).All(&matchedUsers)
+	if err != nil {
+		return nil, err
+	}
+
+	// 收集所有匹配的公司ID及其子公司ID
+	userIds := make([]int, 0)
+	for _, user := range matchedUsers {
+		userIds = append(userIds, user.Id)
+		// 获取所有子公司ID
+		childIds, err := getChildUserIds(o, user.Id)
+		if err == nil {
+			userIds = append(userIds, childIds...)
+		}
+	}
+
+	return userIds, nil
+}
+
+// 递归获取所有子公司ID
+func getChildUserIds(o orm.Ormer, parentId int) ([]int, error) {
+	var children []User
+	_, err := o.QueryTable(new(User)).Filter("T_pid", parentId).Filter("T_State", 1).All(&children)
+	if err != nil {
+		return nil, err
+	}
+
+	childIds := make([]int, 0)
+	for _, child := range children {
+		childIds = append(childIds, child.Id)
+		// 递归获取子公司的子公司
+		subChildIds, err := getChildUserIds(o, child.Id)
+		if err == nil {
+			childIds = append(childIds, subChildIds...)
+		}
+	}
+
+	return childIds, nil
+}
+
+// 获取所有用户用于构建树形结构
+func Read_User_Tree_List(T_Distributor_id string, distributorMap map[string]string) ([]User_R, error) {
+	o := orm.NewOrm()
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_pid", "Id").All(&r)
+	if err != nil {
+		return nil, err
+	}
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, nil
+}
+
+// 获取指定公司的所有子公司(用于树形展示的过滤)
+func Read_User_Tree_List_WithFilter(T_Distributor_id string, T_name string, distributorMap map[string]string) ([]User_R, error) {
+	o := orm.NewOrm()
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+
+	// 如果有名称搜索,获取包含所有子公司的ID列表
+	if len(T_name) > 0 {
+		userIds, err := GetUserIdsByNameWithChildren(T_Distributor_id, T_name)
+		if err == nil && len(userIds) > 0 {
+			cond1 = cond1.And("Id__in", userIds)
+		} else {
+			// 如果没有匹配结果,返回空列表
+			return []User_R{}, nil
+		}
+	}
+
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_pid", "Id").All(&r)
+	if err != nil {
+		return nil, err
+	}
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, nil
+}
+
+// 构建树形结构
+type UserTreeNode struct {
+	User_R
+	Children []UserTreeNode `json:"children"`
+}
+
+// 内部使用的指针版本
+type userTreeNodePtr struct {
+	User_R
+	Children []*userTreeNodePtr
+}
+
+func BuildUserTree(users []User_R) []UserTreeNode {
+	// 创建ID到节点的映射(使用指针以便修改)
+	nodeMap := make(map[int]*userTreeNodePtr)
+	var rootNodes []*userTreeNodePtr
+
+	// 首先创建所有节点
+	for i := range users {
+		node := &userTreeNodePtr{
+			User_R:   users[i],
+			Children: make([]*userTreeNodePtr, 0),
+		}
+		nodeMap[users[i].Id] = node
+	}
+
+	// 然后建立父子关系(使用指针)
+	for i := range users {
+		node := nodeMap[users[i].Id]
+		if users[i].T_pid == 0 {
+			// 根节点
+			rootNodes = append(rootNodes, node)
+		} else {
+			// 子节点 - 将指针添加到父节点的Children
+			if parent, exists := nodeMap[users[i].T_pid]; exists {
+				parent.Children = append(parent.Children, node)
+			}
+		}
+	}
+
+	// 递归转换为值类型返回
+	result := make([]UserTreeNode, len(rootNodes))
+	for i, node := range rootNodes {
+		result[i] = convertNodeToValue(node)
+	}
+
+	return result
+}
+
+// 递归将指针类型的节点树转换为值类型
+func convertNodeToValue(node *userTreeNodePtr) UserTreeNode {
+	valueNode := UserTreeNode{
+		User_R:   node.User_R,
+		Children: make([]UserTreeNode, len(node.Children)),
+	}
+
+	// 递归转换所有子节点
+	for i, child := range node.Children {
+		valueNode.Children[i] = convertNodeToValue(child)
+	}
+
+	return valueNode
+}
+
+// 更新用户路径
+func UpdateUserPath(userId int) error {
+	o := orm.NewOrm()
+
+	// 获取当前用户
+	var user User
+	err := o.QueryTable(new(User)).Filter("Id", userId).One(&user)
+	if err != nil {
+		return err
+	}
+
+	// 构建路径
+	var path string
+	if user.T_pid == 0 {
+		path = strconv.Itoa(userId)
+	} else {
+		// 获取父级路径
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", user.T_pid).One(&parent)
+		if err != nil {
+			return err
+		}
+		if parent.T_path != "" {
+			path = parent.T_path + "/" + strconv.Itoa(userId)
+		} else {
+			path = strconv.Itoa(user.T_pid) + "/" + strconv.Itoa(userId)
+		}
+	}
+
+	// 更新当前用户路径
+	user.T_path = path
+	_, err = o.Update(&user, "T_path")
+	if err != nil {
+		return err
+	}
+
+	// 递归更新所有子节点的路径
+	return updateChildrenPath(o, userId)
+}
+
+// 递归更新子节点路径
+func updateChildrenPath(o orm.Ormer, parentId int) error {
+	var children []User
+	_, err := o.QueryTable(new(User)).Filter("T_pid", parentId).All(&children)
+	if err != nil {
+		return err
+	}
+
+	for _, child := range children {
+		// 获取父级路径
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", child.T_pid).One(&parent)
+		if err != nil {
+			continue
+		}
+
+		// 构建新的路径
+		var newPath string
+		if parent.T_path != "" {
+			newPath = parent.T_path + "/" + strconv.Itoa(child.Id)
+		} else {
+			newPath = strconv.Itoa(child.T_pid) + "/" + strconv.Itoa(child.Id)
+		}
+
+		// 更新子节点路径
+		child.T_path = newPath
+		_, err = o.Update(&child, "T_path")
+		if err != nil {
+			continue
+		}
+
+		// 递归更新子节点的子节点
+		updateChildrenPath(o, child.Id)
+	}
+
+	return nil
+}
+
+// 移动公司到另一个公司下面
+func MoveUserToParent(userId int, newParentId int) error {
+	o := orm.NewOrm()
+
+	// 获取要移动的用户
+	var user User
+	err := o.QueryTable(new(User)).Filter("Id", userId).One(&user)
+	if err != nil {
+		return err
+	}
+
+	// 检查新父级是否存在(如果newParentId不为0)
+
+	if newParentId != 0 {
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", newParentId).Filter("T_State", 1).One(&parent)
+		if err != nil {
+			return err
+		}
+		if user.T_Distributor_id != parent.T_Distributor_id {
+			return errors.New("不能将公司移动到不同经销商下面")
+		}
+	}
+
+	// 检查是否会造成循环引用
+	if newParentId != 0 {
+		if isCircularReference(o, userId, newParentId) {
+			return errors.New("不能将公司移动到其子级公司下面")
+		}
+	}
+
+	// 更新父级ID
+	user.T_pid = newParentId
+	_, err = o.Update(&user, "T_pid")
+	if err != nil {
+		return err
+	}
+
+	// 更新路径
+	return UpdateUserPath(userId)
+}
+
+// 检查是否会造成循环引用
+func isCircularReference(o orm.Ormer, userId int, newParentId int) bool {
+	// 获取新父级的路径
+	var parent User
+	err := o.QueryTable(new(User)).Filter("Id", newParentId).One(&parent)
+	if err != nil {
+		return false
+	}
+
+	// 如果新父级的路径包含当前用户ID,则会造成循环引用
+	if parent.T_path != "" {
+		pathParts := strings.Split(parent.T_path, "/")
+		for _, part := range pathParts {
+			if part == strconv.Itoa(userId) {
+				return true
+			}
+		}
+	}
+
+	return false
+}

+ 151 - 0
models/Account/UserSignature.go

@@ -0,0 +1,151 @@
+package Account
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"log"
+	"time"
+
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+type UserSignature struct {
+	Id               int       `orm:"column(ID);size(11);auto;pk"`
+	T_Distributor_id string    `orm:"size(256);null"`                                        // 分销商id
+	T_uuid           string    `orm:"size(256);null"`                                        // 公司uuid
+	T_name           string    `orm:"size(256);null"`                                        // 姓名
+	T_type           int       `orm:"size(256);default(1)"`                                  // 1-签名 2-公章
+	T_signature      string    `orm:"size(256);null"`                                        // 签名
+	T_State          int       `orm:"size(200);default(1)"`                                  // 0删除  1正常
+	CreateTime       time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime       time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+type UserSignature_R struct {
+	Id                 int
+	T_Distributor_id   string
+	T_Distributor_name string
+	T_uuid             string
+	T_name             string
+	T_signature        string
+	T_type             int
+}
+
+func (t *UserSignature) TableName() string {
+	return "user_signature" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(UserSignature))
+
+}
+
+// -------------------------------------------------------------
+func UserSignatureToUserSignature_R(T UserSignature, distributorMap map[string]string) (T_r UserSignature_R) {
+	T_r.Id = T.Id
+	T_r.T_uuid = T.T_uuid
+	T_r.T_Distributor_id = T.T_Distributor_id
+	T_Distributor_name, ok := distributorMap[T.T_Distributor_id]
+	if !ok {
+		T_Distributor_name = ""
+	}
+	T_r.T_Distributor_name = T_Distributor_name
+	T_r.T_name = T.T_name
+	T_r.T_signature = T.T_signature
+	T_r.T_type = T.T_type
+
+	return T_r
+}
+
+// 获取 ById
+func Read_UserSignature_ById(id int) (r UserSignature, is bool) {
+	o := orm.NewOrm()
+	r = UserSignature{Id: id, T_State: 1}
+	err := o.Read(&r, "T_State", "Id") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By T_name
+func Read_UserSignatureByT_name(T_uuid, T_name string) (r UserSignature, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(UserSignature))
+	err := qs.Filter("T_uuid", T_uuid).Filter("T_name", T_name).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_UserSignature(r UserSignature) (id int64, is bool) {
+	o := orm.NewOrm()
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 删除
+func Delete_UserSignature(v UserSignature) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		log.Println("Number of records updated in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_UserSignature(m UserSignature, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		log.Println("Number of records updated in database:", num)
+
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_UserSignature_List(T_uuid string, T_name string, T_type, page int, page_z int, distributorMap map[string]string) ([]UserSignature_R, int64) {
+	o := orm.NewOrm()
+
+	// 也可以直接使用 Model 结构体作为表名
+	var r []UserSignature
+	qs := o.QueryTable(new(UserSignature))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).And("T_uuid", T_uuid).AndCond(cond.Or("T_name__icontains", T_name))
+	if T_type > 0 {
+		cond1 = cond1.And("T_type", T_type)
+	}
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var UserSignature_r []UserSignature_R
+	for _, v := range r {
+		UserSignature_r = append(UserSignature_r, UserSignatureToUserSignature_R(v, distributorMap))
+	}
+
+	return UserSignature_r, cnt
+}

+ 439 - 0
models/AllotTask/AllotTask.go

@@ -0,0 +1,439 @@
+package AllotTask
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+var (
+	AllotTaskStatusWaitReceive = 1 // 待接收
+	AllotTaskStatusReceived    = 2 // 已接收
+	AllotTaskStatusRefused     = 3 // 已拒绝
+	AllotTaskStatusSubmit      = 4 // 已提交
+	AllotTaskStateMap          = map[int]string{
+		AllotTaskStatusWaitReceive: "待接收",
+		AllotTaskStatusReceived:    "已接收",
+		AllotTaskStatusRefused:     "已拒绝",
+		AllotTaskStatusSubmit:      "已提交",
+	}
+)
+
+// 模版
+type AllotTask struct {
+	Id               int    `orm:"column(ID);size(11);auto;pk"`
+	T_Distributor_id string `orm:"size(256);null"` // 分销商id
+	T_allot_task_id  string `orm:"size(256);null"` // 分配任务ID
+	T_uuid           string `orm:"size(256);null"` // 公司 UUID
+	T_name           string `orm:"size(256);null"` // 标题
+
+	T_approach_time string    `orm:"size(256);null"`        // 进场时间
+	T_scheme        string    `orm:"size(256);null"`        // 实施方案 负责人UUID
+	T_collection    string    `orm:"size(256);null"`        // 数据采集 负责人UUID
+	T_reporting     string    `orm:"size(256);null"`        // 报告编写 负责人UUID
+	T_delivery      string    `orm:"size(256);null"`        // 交付审核 负责人UUID
+	T_project       string    `orm:"size(256);null"`        // 项目 负责人UUID
+	T_province      string    `orm:"size(256);null"`        // 省
+	T_city          string    `orm:"size(256);null"`        // 市
+	T_district      string    `orm:"size(256);null"`        // 区
+	T_province_code string    `orm:"size(256);null"`        // 省 code
+	T_city_code     string    `orm:"size(256);null"`        // 市 code
+	T_district_code string    `orm:"size(256);null"`        // 区 code
+	T_category      string    `orm:"size(256);null"`        // 类别
+	T_attachment    string    `orm:"type(text);null"`       // 附件
+	T_confirm_form  string    `orm:"type(text);null"`       // 信息确认表
+	T_submit_time   string    `orm:"type(text);null"`       // 信息确认表提交时间
+	T_status        int       `orm:"size(2);default(0)"`    // 状态 1待接收 2已接收 3已拒绝 4已提交
+	T_state         int       `orm:"size(2);default(1)"`    // 0 删除  1 正常
+	T_record        string    `orm:"type(text);null"`       // 记录
+	T_reason        string    `orm:"type(text);null"`       // 拒绝原因
+	T_allot_time    time.Time `orm:"type(timestamp);null;"` // 派发时间
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type AllotTask_ struct {
+	Id                int
+	T_Distributor_id  string   // 分销商id
+	T_allot_task_id   string   // 分配任务ID
+	T_uuid            string   // 公司 UUID
+	T_user_name       string   // 公司 名称
+	T_name            string   // 标题
+	T_approach_time   string   // 进场时间
+	T_scheme          string   // 实施方案 负责人UUID
+	T_collection      string   // 数据采集 负责人UUID
+	T_reporting       string   // 报告编写 负责人UUID
+	T_delivery        string   // 交付审核 负责人UUID
+	T_project         string   // 项目 负责人UUID
+	T_scheme_name     string   // 实施方案 负责人姓名
+	T_collection_name string   // 数据采集 负责人姓名
+	T_reporting_name  string   // 报告编写 负责人姓名
+	T_delivery_name   string   // 交付审核 负责人姓名
+	T_project_name    string   // 项目 负责人姓名
+	T_province        string   // 省
+	T_city            string   // 市
+	T_district        string   // 区
+	T_province_code   string   // 省 code
+	T_city_code       string   // 市 code
+	T_district_code   string   // 区 code
+	T_area            []string // 省市区
+	T_area_code       []string // 省市区
+	T_category        string   // 类别
+	T_attachment      []string // 合同附件
+	T_confirm_form    []string // 信息确认表图片
+	T_submit_time     string   // 信息确认表提交时间
+	T_status          int      // 状态 1待接收 2已接收 3已拒绝
+	T_state           int      // 0 删除  1 正常
+	T_record          []AllotTaskRecord
+	T_reason          string
+	T_allot_time      string //指派时间
+	CreateTime        string //auto_now_add 第一次保存时才设置时间
+	UpdateTime        string //auto_now 每次 model 保存时都会对时间自动更新
+}
+type AllotTaskRecord struct {
+	T_collection      string
+	T_collection_name string
+	T_status          int
+	T_reason          string
+	T_time            string
+}
+
+func AllotTaskToAllotTask_(T AllotTask, userMap, adminMap map[string]string) (T_ AllotTask_) {
+	T_.Id = T.Id
+	T_.T_Distributor_id = T.T_Distributor_id
+
+	T_.T_allot_task_id = T.T_allot_task_id
+	T_.T_uuid = T.T_uuid
+	T_.T_user_name = userMap[T.T_uuid]
+	T_.T_name = T.T_name
+	T_.T_approach_time = T.T_approach_time
+	T_.T_scheme = T.T_scheme
+	T_.T_collection = T.T_collection
+	T_.T_reporting = T.T_reporting
+	T_.T_delivery = T.T_delivery
+	T_.T_project = T.T_project
+	T_.T_scheme_name = adminMap[T.T_scheme]
+	T_.T_collection_name = adminMap[T.T_collection]
+	T_.T_reporting_name = adminMap[T.T_reporting]
+	T_.T_delivery_name = adminMap[T.T_delivery]
+	T_.T_project_name = adminMap[T.T_project]
+
+	T_.T_province = T.T_province
+	T_.T_city = T.T_city
+	T_.T_district = T.T_district
+	T_.T_area = []string{T.T_province, T.T_city, T.T_district}
+	T_.T_province_code = T.T_province_code
+	T_.T_city_code = T.T_city_code
+	T_.T_district_code = T.T_district_code
+	T_.T_area_code = []string{T.T_province_code, T.T_city_code, T.T_district_code}
+	T_.T_category = T.T_category
+	T_.T_reason = T.T_reason
+
+	T_.T_state = T.T_state
+	T_.T_status = T.T_status
+	T_.T_attachment = lib.SplitStringSeparator(T.T_attachment, "|")
+	T_.T_confirm_form = lib.SplitStringSeparator(T.T_confirm_form, "|")
+	T_.T_submit_time = T.T_submit_time
+	json.Unmarshal([]byte(T.T_record), &T_.T_record)
+	for i, record := range T_.T_record {
+		T_.T_record[i].T_collection_name = adminMap[record.T_collection]
+	}
+
+	if !T.T_allot_time.IsZero() {
+		T_.T_allot_time = T.T_allot_time.Format("2006-01-02 15:04")
+	}
+	if !T.CreateTime.IsZero() {
+		T_.CreateTime = T.CreateTime.Format("2006-01-02 15:04:05")
+	}
+	if !T.UpdateTime.IsZero() {
+		T_.UpdateTime = T.UpdateTime.Format("2006-01-02 15:04:05")
+	}
+	return T_
+}
+
+var redisCache_AllotTask cache.Cache
+
+func (t *AllotTask) TableName() string {
+	return "allot_task" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(AllotTask))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"AllotTask", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_AllotTask, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_AllotTask == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+	}
+}
+
+func Redis_AllotTask_Set(key string, r AllotTask) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_AllotTask.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+func Redis_AllotTask_Get(key string) (r AllotTask, is bool) {
+	if redisCache_AllotTask.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_AllotTask.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return AllotTask{}, false
+}
+func Redis_AllotTask_DelK(key string) (err error) {
+	err = redisCache_AllotTask.Delete(key)
+	return
+}
+
+// 添加
+func Add_AllotTask(r AllotTask) (string, bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_allot_task_id = lib.GetRandstring(12, "abcdefghijklmnopqrstuvwxyz0123456789", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_allot_task_id")                                                             // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+	Redis_AllotTask_Set(r.T_allot_task_id, r)
+	return r.T_allot_task_id, true
+}
+
+func Update_AllotTask(m AllotTask, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_AllotTask_Set(m.T_allot_task_id, m)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 删除
+func Delete_AllotTask(v AllotTask) bool {
+	o := orm.NewOrm()
+	v.T_state = 0
+	if num, err := o.Update(&v, "T_state"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_AllotTask_DelK(v.T_allot_task_id)
+	return true
+}
+
+// 获取 By
+func Read_AllotTask(T_allot_task_id string) (r AllotTask, is bool) {
+	if r, is = Redis_AllotTask_Get(T_allot_task_id); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(AllotTask))
+	//err := qs.Filter("T_allot_task_id", T_allot_task_id).Filter("T_State", 1).One(&r)
+	err := qs.Filter("T_allot_task_id", T_allot_task_id).Filter("T_state", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	Redis_AllotTask_Set(T_allot_task_id, r)
+	return r, true
+}
+
+// 获取任务列表
+func Read_AllotTask_List(T_Distributor_id, T_admin, T_uuid, T_name, T_project, T_scheme, T_collection, T_reporting, T_delivery string, T_status int,
+	T_company_list []string, userMap, adminMap map[string]string, page int, page_z int) ([]AllotTask_, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(AllotTask))
+	var r []AllotTask
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_state", 1)
+	if len(T_name) > 0 {
+		cond1 = cond1.And("T_name__icontains", T_name)
+	}
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+	if len(T_uuid) > 0 {
+		cond1 = cond1.And("T_uuid", T_uuid)
+	}
+	if len(T_admin) > 0 {
+		cond1 = cond1.AndCond(cond.Or("T_scheme", T_admin).Or("T_collection", T_admin).
+			Or("T_reporting", T_admin).Or("T_delivery", T_admin))
+	}
+
+	if T_status > 0 {
+		cond1 = cond1.And("T_status", T_status)
+	}
+
+	if len(T_company_list) > 0 {
+		cond1 = cond1.And("T_uuid__in", T_company_list)
+	}
+
+	if len(T_project) > 0 {
+		cond1 = cond1.And("T_project", T_project)
+	}
+	if len(T_scheme) > 0 {
+		cond1 = cond1.And("T_scheme", T_scheme)
+	}
+	if len(T_collection) > 0 {
+		cond1 = cond1.And("T_collection", T_collection)
+	}
+	if len(T_reporting) > 0 {
+		cond1 = cond1.And("T_reporting", T_reporting)
+	}
+	if len(T_delivery) > 0 {
+		cond1 = cond1.And("T_delivery", T_delivery)
+	}
+
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var AllotTaskList []AllotTask_
+	for _, v := range r {
+		AllotTaskList = append(AllotTaskList, AllotTaskToAllotTask_(v, userMap, adminMap))
+	}
+
+	return AllotTaskList, int(cnt)
+}
+
+// 获取超时未接收的任务列表 (超过24小时)
+func Read_AllotTask_Timeout_List() ([]AllotTask, error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(AllotTask))
+	var r []AllotTask
+
+	// 计算24小时前的时间
+	timeout := time.Now().Add(-24 * time.Hour)
+
+	// 查询CreateTime超过24小时且状态为待接收的任务
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_state", 1). // 正常状态
+						And("T_status", AllotTaskStatusWaitReceive). // 待接收状态
+						And("T_allot_time__lt", timeout)             // 创建时间早于24小时前
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return nil, err
+	}
+
+	return r, nil
+}
+
+// 更新任务为已拒绝状态并添加拒绝记录
+func Update_AllotTask_To_Refused(task AllotTask, reason string) bool {
+	o := orm.NewOrm()
+
+	// 获取现有记录
+	var existingRecords = make([]AllotTaskRecord, 0)
+	if len(task.T_record) > 0 {
+		json.Unmarshal([]byte(task.T_record), &existingRecords)
+	}
+
+	// 创建新的拒绝记录
+	newRecord := AllotTaskRecord{
+		T_collection: task.T_collection, // 系统自动拒绝
+		T_status:     AllotTaskStatusRefused,
+		T_reason:     reason,
+		T_time:       time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	existingRecords = append(existingRecords, newRecord)
+
+	// 转换为JSON字符串
+	updatedRecordsJSON, err := json.Marshal(existingRecords)
+	if err != nil {
+		logs.Error(lib.FuncName(), "JSON marshal error:", err)
+		return false
+	}
+
+	// 更新任务状态和记录
+	task.T_record = string(updatedRecordsJSON)
+	task.T_status = AllotTaskStatusRefused
+	task.T_reason = reason
+
+	if num, err := o.Update(&task, "T_record", "T_status", "T_reason"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		// 更新Redis缓存
+		Redis_AllotTask_Set(task.T_allot_task_id, task)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取项目负责人列表
+func Get_AllotTask_UserList(T_type string) []string {
+	o := orm.NewOrm()
+	var err error
+	var pl_lists []string
+	switch T_type {
+	case "T_project":
+		_, err = o.Raw("SELECT DISTINCT t_project FROM allot_task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_scheme":
+		_, err = o.Raw("SELECT DISTINCT t_scheme FROM allot_task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_collection":
+		_, err = o.Raw("SELECT DISTINCT t_collection FROM allot_task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_reporting":
+		_, err = o.Raw("SELECT DISTINCT t_reporting FROM allot_task LIMIT 0,1000").QueryRows(&pl_lists)
+
+	}
+	if err != nil {
+		logs.Error("获取项目负责人列表失败:", err)
+	}
+	return pl_lists
+}

+ 213 - 0
models/Certificate/Certificate.go

@@ -0,0 +1,213 @@
+package Certificate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type Certificate struct {
+	Id          int    `orm:"column(ID);size(11);auto;pk"`
+	T_sn        string `orm:"size(256);null"` // 证书编号
+	T_layout_no string `orm:"size(256);null"` // 布局编号
+
+	T_State    int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+type Certificate_R struct {
+	T_sn string `orm:"size(256);null"` // 编号
+}
+
+func (t *Certificate) TableName() string {
+	return "certificate" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(Certificate))
+
+}
+
+// ----------------
+
+// 获取 ById
+func Read_Certificate_ById(id int) (r Certificate, is bool) {
+	o := orm.NewOrm()
+	r = Certificate{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_Certificate(T_layout_no string) (r Certificate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Certificate))
+	err := qs.Filter("T_layout_no", T_layout_no).Filter("T_State", 1).One(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+
+	return r, true
+}
+
+// 获取 By
+func Read_Certificate_ByT_layout_no(T_layout_no string) (r Certificate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Certificate))
+	err := qs.Filter("T_layout_no", T_layout_no).Filter("T_State", 1).One(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_Certificate(r Certificate) (id int64, is bool) {
+	o := orm.NewOrm()
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+	return id, true
+}
+
+// 删除
+func Delete_Certificate(v Certificate) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_Certificate_(v Certificate) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_Certificate(m Certificate, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+type Certificate_ struct {
+	Id int `orm:"column(ID)"`
+	//T_sn             string // 编号
+	T_Certificate_sn string // 编号
+	T_layout_no      string // 布局编号
+	T_release_time   string `orm:"column(t_release_time)"` // 发布时间
+	T_failure_time   string `orm:"column(t_failure_time)"` // 失效时间
+	T_pdf            string // pdf链接
+}
+
+// 获取列表
+func Read_Certificate_List(T_Certificate_sn, T_layout_no, Time_start, Time_end string, T_release_time_sort, T_failure_time_sort, T_layout_no_sort, page int, page_z int) ([]Certificate_, int) {
+
+	o := orm.NewOrm()
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = (page - 1) * page_z
+	}
+
+	var maps_z []orm2.ParamsList
+	var maps []Certificate_
+
+	sqlWhere := ""
+	if len(T_Certificate_sn) > 0 {
+		sqlWhere += " AND pdf.t__certificate_sn like \"%" + T_Certificate_sn + "%\""
+	}
+	if len(T_layout_no) > 0 {
+		sqlWhere += " AND c.t_layout_no like \"%" + T_layout_no + "%\""
+	}
+	if len(Time_start) > 0 {
+		sqlWhere += " AND t_failure_time >= \"" + Time_start + "\""
+	}
+	if len(Time_end) > 0 {
+		sqlWhere += " AND t_failure_time <= \"" + Time_end + "\""
+	}
+
+	// 获取总条数
+	sql := "SELECT COUNT(c.ID)   FROM certificate AS c   LEFT JOIN (      SELECT           t_layout_no,          MAX(t_release_time) AS max_release_time,          MAX(t_failure_time) AS max_failure_time,          GROUP_CONCAT(t_pdf) AS pdf_list,        MAX(t__certificate_sn) AS latest_certificate_sn     FROM           (SELECT DISTINCT * FROM certificate_pdf WHERE t__state=1 ORDER BY id DESC) f       GROUP BY           t_layout_no  ) AS pdf ON pdf.t_layout_no = c.t_layout_no   WHERE c.t__state = 1;"
+	sql = sql + sqlWhere
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return maps, 0
+	}
+	if len(maps_z) == 0 {
+		return maps, 0
+	}
+	//sql = "SELECT * FROM Certificate AS c LEFT JOIN (SELECT any_value(t_release_time) t_release_time,any_value(t_failure_time) t_failure_time,any_value(t_pdf) t_pdf,t__certificate_sn FROM (SELECT DISTINCT * FROM `CertificatePdf` WHERE t__state=1 ORDER BY id DESC) f GROUP BY t__certificate_sn) AS pdf ON pdf.t__certificate_sn=c.t_sn WHERE t__state=1"
+	sql = "WITH RankedCertificates AS (      SELECT           *,          ROW_NUMBER() OVER (PARTITION BY t_layout_no ORDER BY id DESC) AS rn      FROM           certificate_pdf      WHERE           t__state = 1  )  SELECT       c.*,       pdf.t_layout_no AS t_layout_no,      pdf.t_release_time,      pdf.t_failure_time,      pdf.t_pdf,      pdf.t__certificate_sn  FROM       certificate AS c   LEFT JOIN RankedCertificates AS pdf ON pdf.t_layout_no = c.t_layout_no AND pdf.rn = 1  WHERE       c.t__state = 1"
+
+	sql = sql + sqlWhere
+	sqlOrder := make([]string, 0)
+
+	if T_release_time_sort == 1 {
+		sqlOrder = append(sqlOrder, "pdf.t_release_time ASC")
+	} else if T_release_time_sort == 2 {
+		sqlOrder = append(sqlOrder, "pdf.t_release_time DESC")
+	}
+
+	if T_failure_time_sort == 1 {
+		sqlOrder = append(sqlOrder, "pdf.t_failure_time ASC")
+	} else if T_failure_time_sort == 2 {
+		sqlOrder = append(sqlOrder, "pdf.t_failure_time DESC")
+	}
+	if T_layout_no_sort == 1 {
+		sqlOrder = append(sqlOrder, "c.t_layout_no ASC")
+	} else if T_layout_no_sort == 2 {
+		sqlOrder = append(sqlOrder, "c.t_layout_no DESC")
+	}
+
+	if len(sqlOrder) > 0 {
+		sql += " ORDER BY " + strings.Join(sqlOrder, ", ")
+	}
+	if page_z != 9999 {
+		sql += " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(page_z)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&maps)
+
+	cnt, _ := strconv.Atoi(maps_z[0][0].(string))
+	return maps, cnt
+}

+ 195 - 0
models/Certificate/CertificatePdf.go

@@ -0,0 +1,195 @@
+package Certificate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+type CertificatePdf struct {
+	Id               int    `orm:"column(ID);size(11);auto;pk"`
+	T_layout_no      string `orm:"size(256);null"`                               // 布局编号
+	T_Certificate_sn string `orm:"size(256);null"`                               // 证书编号
+	T_release_time   string `orm:"column(t_release_time);type(timestamp);null;"` // 发布时间
+	T_failure_time   string `orm:"column(t_failure_time);type(timestamp);null;"` // 失效时间
+	T_pdf            string `orm:"size(256);null"`                               // pdf链接
+
+	T_State    int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+type CertificatePdf_R struct {
+	Id               int
+	T_layout_no      string // 布局编号
+	T_Certificate_sn string // 证书编号 TODO后期删除
+	T_release_time   string // 发布时间
+	T_failure_time   string // 失效时间
+	T_pdf            string // pdf链接
+}
+
+func (t *CertificatePdf) TableName() string {
+	return "certificate_pdf" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(CertificatePdf))
+
+}
+
+// -------------------------------------------------------------
+func CertificatePdfToCertificatePdf_R(T CertificatePdf) (T_r CertificatePdf_R) {
+	T_r.Id = T.Id
+	T_r.T_layout_no = T.T_layout_no
+	T_r.T_Certificate_sn = T.T_Certificate_sn
+	T_r.T_release_time = T.T_release_time
+	T_r.T_failure_time = T.T_failure_time
+	T_r.T_pdf = T.T_pdf
+	return T_r
+}
+
+// ----------------
+
+// 获取 ById
+func Read_CertificatePdf_ById(id int) (r CertificatePdf, is bool) {
+	o := orm.NewOrm()
+	r = CertificatePdf{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_CertificatePdf(T_Certificate_sn, T_release_time, T_failure_time string) (r CertificatePdf, err error) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(CertificatePdf))
+	err = qs.Filter("T_Certificate_sn", T_Certificate_sn).Filter("T_release_time", T_release_time).Filter("T_failure_time", T_failure_time).Filter("T_State", 1).One(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+	}
+	return r, err
+}
+
+// 获取最新的校准证书
+func Read_CertificatePdf_Newest(T_layout_no string) (r []CertificatePdf, err error) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(CertificatePdf))
+	_, err = qs.Limit(1, 0).Filter("T_layout_no", T_layout_no).Filter("T_State", 1).OrderBy("-T_failure_time").All(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+	}
+	return r, err
+}
+
+// 通过T_layout_no获取对应时间的证书
+func Read_CertificatePdf_T_layout_no(T_layout_no, operation_time string) (r []CertificatePdf, err error) {
+	if len(operation_time) == 0 {
+		operation_time = time.Now().Format("2006-01-02")
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(CertificatePdf))
+	_, err = qs.Limit(1, 0).Filter("T_layout_no", T_layout_no).
+		Filter("T_release_time__lte", operation_time).
+		Filter("T_failure_time__gte", operation_time).
+		Filter("T_State", 1).OrderBy("-T_failure_time").All(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+	}
+	return r, err
+}
+
+// 添加
+func Add_CertificatePdf(r CertificatePdf) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	err := o.Read(&r, "T_Certificate_sn", "T_release_time", "T_failure_time", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err == nil {
+		return 0, false
+	}
+
+	id, err = o.Insert(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 删除
+func Delete_CertificatePdf(v CertificatePdf) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_CertificatePdf_(v CertificatePdf) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_CertificatePdf(m CertificatePdf, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	} else {
+		logs.Println(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取列表
+func Read_CertificatePdf_List(T_layout_no string, page int, page_z int) ([]CertificatePdf_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []CertificatePdf
+	qs := o.QueryTable(new(CertificatePdf))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_layout_no", T_layout_no).And("T_State", 1)
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+	// 转换
+	var CertificatePdf_r []CertificatePdf_R
+	for _, v := range r {
+		CertificatePdf_r = append(CertificatePdf_r, CertificatePdfToCertificatePdf_R(v))
+	}
+
+	return CertificatePdf_r, cnt
+}

+ 256 - 0
models/Device/Device.go

@@ -0,0 +1,256 @@
+package Device
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	orm2 "github.com/beego/beego/v2/client/orm"
+
+	"encoding/json"
+	"fmt"
+
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type Device struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_sn string `orm:"size(256);null"` // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+
+	T_id   int       `orm:"size(256);null"`        // 编号
+	T_t    float32   `orm:"size(10);null"`         // 温度
+	T_rh   float32   `orm:"size(10);null"`         // 湿度
+	T_time time.Time `orm:"type(timestamp);null;"` // 采集时间
+
+	T_MSISDN             string `orm:"size(256);null"`     // 物联网卡
+	T_version            int    `orm:"size(2);default(1)"` // 版本
+	T_signal             int    `orm:"size(2);default(1)"` // 信号强度
+	T_electric           int    `orm:"size(2);default(1)"` // 电量百分比
+	T_up_time_interval   int    `orm:"size(2);default(1)"` // 上传时间间隔
+	T_note_time_interval int    `orm:"size(2);default(1)"` // 记录时间间隔
+	T_note_file_num      int    `orm:"size(2);default(1)"` // 记录文件数量
+
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+type Device_R struct {
+	Id                   int
+	T_sn                 string  // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+	T_id                 string  // 编号
+	T_t                  float32 // 温度
+	T_rh                 float32 // 湿度
+	T_time               string  // 采集时间
+	T_MSISDN             string  // 物联网卡
+	T_version            int     // 版本
+	T_signal             int     // 信号强度
+	T_electric           int     // 电量百分比
+	T_up_time_interval   int     // 上传时间间隔
+	T_note_time_interval int     // 记录时间间隔
+	T_note_file_num      int     // 记录文件数量
+	T_State              int     // 0 删除   1 正常
+	UpdateTime           string  // 采集时间
+}
+
+func DeviceToDevice_R(t Device, T_id string) (r Device_R) {
+	r.Id = t.Id
+	r.T_sn = t.T_sn
+	//r.T_id = T_id
+	r.T_t = t.T_t
+	r.T_rh = t.T_rh
+	if !t.T_time.IsZero() {
+		r.T_time = t.T_time.Format("2006-01-02 15:04:05")
+	}
+	r.T_MSISDN = t.T_MSISDN
+	r.T_version = t.T_version
+	r.T_signal = t.T_signal
+	r.T_electric = t.T_electric
+	r.T_up_time_interval = t.T_up_time_interval
+	r.T_note_time_interval = t.T_note_time_interval
+	r.T_note_file_num = t.T_note_file_num
+	r.T_State = t.T_State
+	if !t.UpdateTime.IsZero() {
+		r.UpdateTime = t.UpdateTime.Format("2006-01-02 15:04:05")
+	}
+	return r
+}
+
+func (t *Device) TableName() string {
+	return "device" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_Device cache.Cache
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(Device))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"Device", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_Device, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_Device == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_Device_Set(key string, r Device) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_Device.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_Device_Get(key string) (r Device, is bool) {
+	if redisCache_Device.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_Device.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return Device{}, false
+}
+func Redis_Device_DelK(key string) (err error) {
+	err = redisCache_Device.Delete(key)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_Device_ById(id int) (r Device, is bool) {
+	o := orm.NewOrm()
+	r = Device{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_Device(T_sn string) (r Device, is bool) {
+	if r, is = Redis_Device_Get(T_sn); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Device))
+	err := qs.Filter("T_sn", T_sn).One(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, false
+	}
+
+	Redis_Device_Set(T_sn, r)
+	return r, true
+}
+
+// 添加
+func Add_Device(r Device) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+	CREATE_DeviceData(r.T_sn)
+	Redis_Device_Set(r.T_sn, r)
+	return id, true
+}
+
+// 删除
+func Delete_Device(v Device) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_Device_DelK(v.T_sn)
+	return true
+}
+
+// 删除
+func Delete_Device_(v Device) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_Device_DelK(v.T_sn)
+	return true
+}
+
+// 修改
+func Update_Device(m Device, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_Device_Set(m.T_sn, m)
+		return true
+	} else {
+		logs.Println(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取列表
+func Read_Device_List(T_sn string, T_MSISDN string, page int, page_z int) (r []Device_R, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(Device))
+	var offset int64
+	var map_r []Device
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_MSISDN__icontains", T_MSISDN).And("T_sn__icontains", T_sn).And("T_State", 1) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&map_r)
+	cnt, _ = qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	for _, v := range map_r {
+		r = append(r, DeviceToDevice_R(v, "0"))
+	}
+
+	return r, cnt
+}

+ 169 - 0
models/Device/DeviceClass.go

@@ -0,0 +1,169 @@
+package Device
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type DeviceClass struct {
+	Id     int    `orm:"column(ID);size(11);auto;pk"`
+	T_uuid string `orm:"size(256);null"` // 管理员 UUID
+	T_name string `orm:"size(256);null"` // 标题
+
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+func (t *DeviceClass) TableName() string {
+	return "device_class" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_DeviceClass cache.Cache
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(DeviceClass))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"DeviceClass", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_DeviceClass, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_DeviceClass == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_DeviceClass_Set(key string, r DeviceClass) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_DeviceClass.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_DeviceClass_Get(key string) (r DeviceClass, is bool) {
+	if redisCache_DeviceClass.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_DeviceClass.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return DeviceClass{}, false
+}
+func Redis_DeviceClass_DelK(key string) (err error) {
+	err = redisCache_DeviceClass.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_DeviceClass_ById(id int) (r DeviceClass, is bool) {
+	o := orm.NewOrm()
+	r = DeviceClass{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 添加
+func Add_DeviceClass(r DeviceClass) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 删除
+func Delete_DeviceClass(v DeviceClass) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_DeviceClass_(v DeviceClass) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_DeviceClass(m DeviceClass, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	} else {
+		logs.Println(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取列表
+func Read_DeviceClass_List(T_uuid string, T_name string, page int, page_z int) (r []DeviceClass, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClass))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_uuid", T_uuid).And("T_name__icontains", T_name).And("T_State", 1) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ = qs.SetCond((*orm2.Condition)(cond1)).Count()
+	return r, cnt
+}

+ 489 - 0
models/Device/DeviceClassList.go

@@ -0,0 +1,489 @@
+package Device
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"time"
+)
+
+// 模版
+type DeviceClassList struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_class          int    `orm:"size(200);null"`     // 分类
+	T_id             string `orm:"size(20);null"`      // 设备id
+	T_sn             string `orm:"size(256);null"`     // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+	T_terminal       int    `orm:"size(2);default(1)"` // 1-验证工具 2-终端
+	T_failure_time   string `orm:"size(256);null"`     // 失效时间
+	T_pdf            string `orm:"size(256);null"`     // pdf链接
+	T_Certificate_sn string `orm:"size(256);null"`     // 证书编号
+	T_remark         string `orm:"type(text);null"`    // 备注
+
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type DeviceClassStat struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_class    int    `orm:"size(200);null"`     // 分类
+	T_id       string `orm:"size(20);null"`      // 设备id
+	T_sn       string `orm:"size(256);null"`     // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+	T_terminal int    `orm:"size(2);default(1)"` // 1-测点 2-终端
+	T_State    int    `orm:"size(2);default(1)"` // 0 删除   1 正常
+
+	T_task_id   string `orm:"size(256);null"`      // 任务ID
+	T_uuid      string `orm:"size(256);null"`      // 用户 UUID
+	T_user_name string `orm:"size(256);null"`      // 用户 UUID
+	T_name      string `orm:"size(256);null"`      // 标题
+	CreateTime  string `orm:"column(create_time)"` //auto_now_add 第一次保存时才设置时间
+}
+
+func DeviceClassStatToDeviceClassStat(T DeviceClassStat, userMap map[string]string) (T_ DeviceClassStat) {
+	T_ = T
+	T_.T_user_name = userMap[T.T_uuid]
+	if len(T.CreateTime) > 19 {
+		T_.CreateTime = T.CreateTime[0:19]
+	}
+	return T_
+}
+
+func (t *DeviceClassList) TableName() string {
+	return "device_class_list" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_DeviceClassList cache.Cache
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(DeviceClassList))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"DeviceClassList", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_DeviceClassList, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_DeviceClassList == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_DeviceClassList_Set(key string, r DeviceClassList) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_DeviceClassList.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_DeviceClassList_Get(key string) (r DeviceClassList, is bool) {
+	if redisCache_DeviceClassList.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_DeviceClassList.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return DeviceClassList{}, false
+}
+func Redis_DeviceClassList_DelK(key string) (err error) {
+	err = redisCache_DeviceClassList.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_DeviceClassList_ById(id int) (r DeviceClassList, is bool) {
+	o := orm.NewOrm()
+	r = DeviceClassList{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_DeviceClassList(T_sn string) (r DeviceClassList, is bool) {
+	if r, is = Redis_DeviceClassList_Get(T_sn); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(DeviceClassList))
+	err := qs.Filter("T_sn", T_sn).One(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, false
+	}
+
+	Redis_DeviceClassList_Set(T_sn, r)
+	return r, true
+}
+
+// 添加
+func Read_DeviceClassList_T_class_T_sn(T_class int, T_sn string) (r DeviceClassList, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(DeviceClassList))
+	err := qs.Filter("T_sn", T_sn).Filter("T_class", T_class).Filter("T_State", 1).One(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+func Read_DeviceClassList_T_class_T_id(T_class int, T_id string) (r DeviceClassList, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(DeviceClassList))
+	err := qs.Filter("T_id", T_id).Filter("T_class", T_class).Filter("T_State", 1).One(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 添加
+func Add_DeviceClassList(r DeviceClassList) (id int64, is bool) {
+	o := orm.NewOrm()
+	//r.T_State = 1
+	//err := o.Read(&r, "T_class", "T_sn", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	//if err == nil {
+	//	if r.Id > 0 {
+	//		logs.Println("重复添加", r.T_class, r.T_sn)
+	//		return 0, false
+	//	}
+	//}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	Redis_DeviceClassList_Set(r.T_sn, r)
+	return id, true
+}
+
+// 删除
+func Delete_DeviceClassList(v DeviceClassList) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_DeviceClassList_DelK(v.T_sn)
+	return true
+}
+
+// 删除
+func Delete_DeviceClassList_(v DeviceClassList) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Println(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_DeviceClassList_DelK(v.T_sn)
+	return true
+}
+
+// 修改
+func Update_DeviceClassList(m DeviceClassList, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_DeviceClassList_Set(m.T_sn, m)
+		return true
+	} else {
+		logs.Println(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取列表
+func Read_DeviceClassList_List(T_class int, T_sn string, page int, page_z int) (r []DeviceClassList, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClassList))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_class", T_class).And("T_sn__icontains", T_sn).And("T_State", 1) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("T_id").All(&r)
+	}
+	cnt, _ = qs.SetCond((*orm2.Condition)(cond1)).Count()
+	return r, cnt
+}
+func Read_DeviceClassList_OrderList(T_class int, T_sn, T_id, T_remark string, page int, page_z int) (r []DeviceClassList, cnt int64) {
+
+	o := orm.NewOrm()
+	var maps_z []orm2.ParamsList
+	pagez := page_z
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * pagez
+	}
+
+	sqlWhere := "t_class = " + strconv.Itoa(T_class) + " AND t__state = 1"
+	if len(T_sn) > 1 {
+		sqlWhere += " AND t_sn like \"%" + T_sn + "%\""
+	}
+	if len(T_id) > 1 {
+		sqlWhere += " AND T_id like \"%" + T_id + "%\""
+	}
+	if len(T_remark) > 0 {
+		sqlWhere += " AND t_remark like \"%" + T_remark + "%\""
+	}
+
+	sql := "SELECT COUNT(ID) FROM device_class_list WHERE " + sqlWhere
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return r, 0
+	}
+	if len(maps_z) == 0 {
+		return r, 0
+	}
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql = "SELECT *  FROM device_class_list WHERE " + sqlWhere + " ORDER BY t_id+0 "
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, 0
+	}
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return r, int64(key)
+}
+
+// 获取列表
+func Read_DeviceClassList_List_id(T_class_Id int) (r []DeviceClassList) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClassList))
+
+	qs.Filter("T_class", T_class_Id).Filter("T_State", 1).All(&r)
+
+	return r
+}
+
+// 删除重复设备列表
+func Del_DeviceClassList_Duplication(T_class int) error {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "DELETE FROM device_class_list WHERE ID NOT IN (" +
+		"SELECT * FROM (SELECT MIN(ID) FROM device_class_list WHERE t__state = 1 AND t_class = " + strconv.Itoa(T_class) +
+		" GROUP BY t_class, t_id, t_sn) AS keep_ids) " +
+		" AND t__state = 1 AND t_class = " + strconv.Itoa(T_class)
+
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Debug(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	num, _ := res.RowsAffected()
+
+	logs.Debug("删除重复设备列表: ", num)
+	return nil
+}
+
+// 获取列表,用于自动填写布点
+func Read_DeviceClassList_List_ByT_remark(T_class_Id int, T_remark string) (r []DeviceClassList) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClassList))
+
+	qs.Filter("T_class", T_class_Id).Filter("T_State", 1).Filter("T_remark__icontains", T_remark).All(&r)
+	return r
+}
+
+// 获取空证书列表,用于同步证书
+func Read_DeviceClassList_List_ByT_Certificate_sn_null(CreateTime string) (r []DeviceClassList) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClassList))
+
+	qs.Filter("CreateTime__gte", CreateTime).Filter("T_failure_time", "").All(&r)
+
+	return r
+}
+
+// 排除终端
+func Read_DeviceClassList_List_id_By_Terminal(T_class_Id int, T_Terminal bool) (r []DeviceClassList) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	//qs := o.QueryTable(new(DeviceClassList))
+	//
+	//if T_Terminal == true {
+	//	qs.Filter("T_class", T_class_Id).Filter("T_State", 1).Filter("T_terminal", 2).OrderBy("t_id+0").All(&r)
+	//	return r
+	//}
+	//// T_terminal = 1,0 测点
+	//qs.Filter("T_class", T_class_Id).Filter("T_State", 1).Filter("T_terminal__lt", 2).OrderBy("t_id+0").All(&r)
+	//return r
+
+	sqlWhere := "t_class = " + strconv.Itoa(T_class_Id) + " AND t__state = 1"
+	if T_Terminal == true {
+		sqlWhere += " AND t_terminal = 2"
+	} else {
+		sqlWhere += " AND t_terminal <= 1"
+	}
+
+	sql := "SELECT *  FROM device_class_list WHERE " + sqlWhere + " ORDER BY t_id+0 "
+
+	logs.Println(sql)
+	_, err := o.Raw(sql).QueryRows(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	return r
+
+}
+
+func Read_DeviceClass_Stat(T_company_list []string, T_name, T_sn, Time_start, Time_end string, T_distinct bool, userMap map[string]string, page int, page_z int) (r []DeviceClassStat, cnt int64) {
+
+	o := orm.NewOrm()
+	var maps_z []orm2.ParamsList
+	pagez := page_z
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * pagez
+	}
+
+	sqlWhere := "dcl.t__state = 1 AND dcl.t_terminal < 2 AND dcl.t_sn IS NOT NULL AND dcl.t_sn != ''"
+
+	if len(Time_start) > 1 {
+		sqlWhere += " AND dcl.create_time >= '" + Time_start + "'"
+	}
+
+	if len(Time_end) > 1 {
+		sqlWhere += " AND dcl.create_time <= '" + Time_end + "'"
+	}
+	if len(T_sn) > 1 {
+		sqlWhere += " AND dcl.t_sn like \"%" + T_sn + "%\""
+	}
+	if len(T_name) > 1 {
+		sqlWhere += " AND task.t_name like \"%" + T_name + "%\""
+	}
+	if len(T_company_list) > 0 {
+
+		// 构建 SQL 查询
+		query := " AND task.T_uuid IN ("
+		// 动态添加每个 id
+		for i, id := range T_company_list {
+			query += "'" + id + "'"
+			if i < len(T_company_list)-1 {
+				query += ", " // 添加逗号分隔
+			}
+		}
+		query += ") " // 结束 SQL 查询
+		sqlWhere += query
+	}
+
+	sql := "SELECT COUNT(*) FROM device_class_list dcl LEFT JOIN task ON dcl.t_class = task.t_class WHERE " + sqlWhere
+	if T_distinct {
+		sql = "SELECT COUNT(DISTINCT dcl.t_sn) FROM device_class_list dcl LEFT JOIN task ON dcl.t_class = task.t_class WHERE " + sqlWhere
+	}
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return r, 0
+	}
+	if len(maps_z) == 0 {
+		return r, 0
+	}
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql = "SELECT dcl.*,task.t_task_id,task.t_uuid,task.t_name FROM device_class_list dcl LEFT JOIN task ON dcl.t_class = task.t_class WHERE " + sqlWhere + " ORDER BY dcl.create_time DESC "
+	if T_distinct {
+		sql = "SELECT * FROM (SELECT dcl.*,task.t_task_id,task.t_uuid,task.t_name,ROW_NUMBER() OVER (PARTITION BY dcl.t_sn ORDER BY dcl.create_time ASC) AS rn FROM device_class_list dcl LEFT JOIN task ON dcl.t_class=task.t_class WHERE " + sqlWhere + ") AS ranked WHERE rn=1 ORDER BY ranked.create_time DESC "
+	}
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r, 0
+	}
+
+	var list []DeviceClassStat
+	for _, v := range r {
+		list = append(list, DeviceClassStatToDeviceClassStat(v, userMap))
+	}
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return list, int64(key)
+}

+ 613 - 0
models/Device/DeviceData.go

@@ -0,0 +1,613 @@
+package Device
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// 模版
+type DeviceData struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_id   string    `orm:"size(256);null"`        // 标题
+	T_t    float32   `orm:"size(10);null"`         // 温度
+	T_rh   float32   `orm:"size(10);null"`         // 湿度
+	T_time time.Time `orm:"type(timestamp);null;"` // 采集时间
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间 UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`   //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+func (t *DeviceData) TableName() string {
+	return "device_data" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_DeviceData cache.Cache
+var redisCache_DeviceDataJPG cache.Cache
+
+func init() {
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_DeviceData", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+
+	configJPG := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_DeviceDataJPG", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_DeviceData, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_DeviceData == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+
+	redisCache_DeviceDataJPG, err = cache.NewCache("redis", configJPG)
+	if err != nil || redisCache_DeviceDataJPG == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+func DeviceData_Set(key string) (err error) {
+
+	err = redisCache_DeviceData.Put(key, "", 2*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, err)
+	}
+	return
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func RedisDeviceData_Set(key string, r DeviceData_New) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	err = redisCache_DeviceData.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func RedisDeviceData_Get(key string) (r DeviceData_New, is bool) {
+	v := redisCache_DeviceData.Get(key)
+	json.Unmarshal(v.([]byte), &r)
+	return r, true
+}
+
+type DeviceCount struct {
+	T_id string `json:"T_id"`
+	T_sn string `json:"T_sn"`
+	Num  int    `json:"Num"`
+}
+
+type DeviceDataJPG struct {
+	State  int           `json:"State"` //1:生成中 2:已完成 3:失败
+	Msg    string        `json:"Msg"`
+	Url    string        `json:"Url"` //url
+	Device []DeviceCount `json:"Device"`
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_DeviceDataJPG_Set(key string, r DeviceDataJPG) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_DeviceDataJPG.Put(key, str, 5*time.Minute)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_DeviceDataJPG_Get(key string) (r DeviceDataJPG, is bool) {
+	if redisCache_DeviceDataJPG.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_DeviceDataJPG.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return DeviceDataJPG{}, false
+}
+func Redis_DeviceDataJPG_Del(key string) (err error) {
+	err = redisCache_DeviceDataJPG.Delete(key)
+	return
+}
+
+// 创建数据库  Device.CREATE_DeviceData("")
+func CREATE_DeviceData(SN string) bool {
+	o := orm.NewOrm()
+
+	sql := "CREATE TABLE IF NOT EXISTS `z_device_data_" + SN + "` ( " +
+		"  `ID` int(11) NOT NULL AUTO_INCREMENT," +
+		"	`t_id` int(11) NULL DEFAULT NULL," +
+		"	`t_t` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_rh` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_time` datetime(0) NULL DEFAULT NULL," +
+		"	`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0)," +
+		"	PRIMARY KEY (`ID`) USING BTREE" +
+		") ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;"
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
+// ---------------- 特殊方法 -------------------
+// 获取 ById
+//func Read_List_ById(id int) (r DeviceData) {
+//	o := orm.NewOrm()
+//
+//	return r
+//}
+//
+//// 添加
+//func Add_DeviceData(SN string, t_id string, t_t string, t_rh string, t_time string) bool {
+//	key := SN + "|" + t_id + "|" + t_time
+//	//logs.Println(key)
+//	if redisCache_DeviceData.IsExist(key) {
+//		//println("找到key:",key)
+//		return true
+//	}
+//	//println("没有 找到key:",key)
+//
+//	o := orm.NewOrm()
+//	//  查看是否 有记录
+//	var maps_z []orm2.ParamsList
+//
+//	sql := "SELECT COUNT(*) FROM z_devicedata_" + SN + " WHERE t_time = '" + t_time + "' AND t_id = " + t_id
+//	//logs.Println(sql)
+//	_, err := o.Raw(sql).ValuesList(&maps_z)
+//
+//	if err != nil {
+//		logs.Error(lib.FuncName(),err)
+//		return false
+//	}
+//	//logs.Println("maps_z[0][0]:",maps_z[0][0])
+//	if lib.To_int(maps_z[0][0]) > 0 {
+//		// 存在 写入 redis
+//		DeviceData_Set(key)
+//		return true
+//	}
+//	// 开始插入数据
+//	sql = "INSERT INTO z_devicedata_" + SN + " (`t_id`, `t_t`, `t_rh`, `t_time`) VALUES (" + t_id + ", " + t_t + ", " + t_rh + ", '" + t_time + "')"
+//	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+//	//logs.Println(sql)
+//	res, err := o.Raw(sql).Exec()
+//	if err != nil {
+//		logs.Error(lib.FuncName(),err)
+//		return false
+//	}
+//	res.RowsAffected()
+//	// 存在 写入 redis
+//	DeviceData_Set(key)
+//	//logs.Println("mysql row affected nums: ", num)
+//	return true
+//}
+
+type DeviceData_ struct {
+	T_t    float32 `orm:"column(t_t);size(10);null"`            // 温度
+	T_rh   float32 `orm:"column(t_rh);size(10);null"`           // 湿度
+	T_time string  `orm:"column(t_time);type(timestamp);null;"` // 采集时间
+}
+type DeviceData_New struct {
+	T_id   int       `orm:"column(t_id);size(10);null"`           // ID
+	T_t    float32   `orm:"column(t_t);size(10);null"`            // 温度
+	T_rh   float32   `orm:"column(t_rh);size(10);null"`           // 湿度
+	T_time time.Time `orm:"column(t_time);type(timestamp);null;"` // 采集时间
+}
+
+func Read_DeviceSensorData_ById_List(SN string, Time_start_ string, Time_end_ string, page int, page_z int) ([]DeviceData_, int) {
+
+	o := orm.NewOrm()
+	var maps []DeviceData_
+	var maps_z []orm2.ParamsList
+	pagez := page_z
+
+	if len(SN) == 0 {
+		return maps, 0
+	}
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * pagez
+	}
+
+	sql_time := ""
+
+	if len(Time_start_) > 1 {
+		sql_time += " t_time >= '" + Time_start_ + "' AND "
+	}
+
+	if len(Time_end_) > 1 {
+		sql_time += " t_time <= '" + Time_end_ + "' AND "
+	}
+
+	if len(sql_time) > 0 {
+		sql_time = strings.TrimRight(sql_time, "AND ")
+	}
+
+	sql := "SELECT COUNT(*) FROM z_devicedata_" + SN
+	if len(sql_time) > 0 {
+		sql += " WHERE " + sql_time
+	}
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return maps, 0
+	}
+	if len(maps_z) == 0 {
+		return maps, 0
+	}
+	//logs.Println("maps_z;",maps_z[0][0])
+	//sql = "SELECT t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN
+	sql = "SELECT t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN
+	if len(sql_time) > 0 {
+		sql += " WHERE " + sql_time
+	}
+	sql += " ORDER BY t_time"
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&maps)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return maps, 0
+	}
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return maps, key
+}
+
+func Read_DeviceData_By_snid(SN string, T_id int, Time_start_ string, Time_end_ string, offset, limit int) ([]DeviceData_, int) {
+	var maps []DeviceData_
+	o := orm.NewOrm()
+
+	if len(SN) == 0 {
+		return maps, 0
+	}
+
+	sql_time := ""
+
+	if len(Time_start_) > 1 {
+		sql_time += " t_time >= '" + Time_start_ + "' AND "
+	}
+
+	if len(Time_end_) > 1 {
+		sql_time += " t_time <= '" + Time_end_ + "' AND "
+	}
+
+	//sql := "SELECT t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN + " WHERE " + sql_time + " t_id = " + strconv.Itoa(T_id) + " ORDER BY t_time DESC "
+	sql := "SELECT t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN + " WHERE " + sql_time + " t_id = " + strconv.Itoa(T_id) + " ORDER BY t_time DESC "
+	sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(limit)
+	logs.Println(sql)
+	_, err := o.Raw(sql).QueryRows(&maps)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return maps, 0
+	}
+
+	return maps, 0
+}
+
+func Read_DeviceData_Count_By_snid(SN string, T_id int, Time_start_ string, Time_end_ string) int {
+	if len(SN) == 0 {
+		return 0
+	}
+	o := orm.NewOrm()
+	var maps_z []orm2.ParamsList
+
+	sql_time := ""
+
+	if len(Time_start_) > 1 {
+		sql_time += " t_time >= '" + Time_start_ + "' AND "
+	}
+
+	if len(Time_end_) > 1 {
+		sql_time += " t_time <= '" + Time_end_ + "' AND "
+	}
+
+	sql := "SELECT COUNT(*) FROM z_devicedata_" + SN + " WHERE " + sql_time + " t_id = " + strconv.Itoa(T_id)
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return 0
+	}
+	if len(maps_z) == 0 {
+		return 0
+	}
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return key
+}
+
+func Read_DeviceSensorData_List(SN string, Time_start_ string, Time_end_ string, page int, page_z int) ([]DeviceData_, int) {
+	o := orm.NewOrm()
+	var maps []DeviceData_
+	var maps_z []orm2.ParamsList
+	pagez := page_z
+	if len(SN) == 0 {
+		return maps, 0
+	}
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * pagez
+	}
+
+	sql_time := ""
+
+	if len(Time_start_) > 1 && len(Time_end_) > 1 {
+		sql_time = "WHERE "
+		sql_time += " t_time >= '" + Time_start_ + "' AND "
+		sql_time += " t_time <= '" + Time_end_ + "' "
+	}
+
+	sql := "SELECT COUNT(*) FROM z_devicedata_" + SN + " " + sql_time
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return maps, 0
+	}
+	if len(maps_z) == 0 {
+		return maps, 0
+	}
+	//logs.Println("maps_z;",maps_z[0][0])
+	//sql = "SELECT t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN + " " + sql_time + " ORDER BY t_time DESC "
+	sql = "SELECT t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN + " " + sql_time + " ORDER BY t_time DESC "
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&maps)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return maps, 0
+	}
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return maps, key
+}
+
+func Read_DeviceSensorData_List_z(SN string, Time_start_ string) int {
+	if len(SN) == 0 {
+		return 0
+	}
+	o := orm.NewOrm()
+	var maps_z []orm2.ParamsList
+
+	sql_time := ""
+	if len(Time_start_) > 1 {
+		sql_time = "WHERE "
+		sql_time += " t_time >= '" + Time_start_ + "' "
+		//sql_time += " t_time <= '" + Time_end_ + "' AND "
+	}
+
+	sql := "SELECT COUNT(*) FROM z_devicedata_" + SN + " " + sql_time
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return 0
+	}
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return key
+}
+
+// 获取最新数据
+func Read_DeviceSensorData_ById_New(SN string, T_id int) (DeviceData_New, bool) {
+	o := orm.NewOrm()
+	var maps DeviceData_New
+	if len(SN) == 0 {
+		return maps, false
+	}
+
+	key_data := SN + "|" + strconv.Itoa(T_id)
+	if redisCache_DeviceData.IsExist(key_data) {
+		r, _ := RedisDeviceData_Get(key_data)
+		//println("Redis_Get  OK")
+		return r, true
+	}
+
+	//logs.Println("maps_z;",maps_z[0][0])
+	//sql := "SELECT t_id,t_t,t_rh,t_time  FROM z_devicedata_" + SN + " WHERE " + " t_id = " + strconv.Itoa(T_id) + " ORDER BY t_time DESC "
+	sql := "SELECT t_t,t_rh,t_time  FROM z_devicedata_" + SN + " WHERE " + " t_id = " + strconv.Itoa(T_id) + " ORDER BY t_time DESC "
+	sql = sql + " LIMIT 0,1 "
+
+	logs.Println(sql)
+	err := o.Raw(sql).QueryRow(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return maps, false
+	}
+	logs.Println("T_time:", maps.T_time)
+	RedisDeviceData_Set(key_data, maps)
+	return maps, true
+}
+
+func Read_DeviceSensorData_By_T_snid_List(T_snid string, Time_start_ string, Time_end_ string, page int, page_z int) ([]DeviceData_, int) {
+	T_snid_list := strings.Split(T_snid, "|")
+	var maps []DeviceData_
+	var maps_num int
+	var offset, offset_z int
+	for _, v := range T_snid_list {
+		sn_id := strings.Split(v, ",")
+
+		if len(sn_id) == 2 {
+			r_maps, r_maps_num := Read_DeviceSensorData_ById_List(sn_id[0], Time_start_, Time_end_, 0, 9999)
+			maps = append(maps, r_maps...)
+			maps_num = maps_num + r_maps_num
+
+			logs.Println("加载数据:", sn_id[0], sn_id[1], r_maps_num)
+		}
+	}
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * page_z
+	}
+
+	offset_z = offset + page_z
+	if maps_num < offset_z {
+		offset_z = maps_num
+	}
+
+	if page_z == 9999 {
+		logs.Println("总数据:", maps_num, " 导出")
+		return maps, maps_num
+	}
+	logs.Println("总数据:", maps_num, " 截取", offset, offset+page_z)
+	return maps[offset:offset_z], maps_num
+}
+
+func Read_DeviceData_ById_Year_List(SN string) []orm2.ParamsList {
+	o := orm.NewOrm()
+
+	var maps_z []orm2.ParamsList
+	if len(SN) == 0 {
+		return maps_z
+	}
+
+	//sql = "SELECT t_name,t_t,t_rh,t_tl,t_tu,t_rhl,t_rhu,t_site,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_"+SN+" WHERE "+sql_time+" t_id = "+ strconv.Itoa(T_id) +" ORDER BY t_time DESC "
+	sql := "SELECT DATE_FORMAT(t_time,\"%m\") AS m ,DATE_FORMAT(t_time,\"%d\") AS d FROM z_devicedata_" + SN + "  WHERE t_time > '" + strconv.Itoa(time.Now().Year()) + "-0-0 00:00:00' GROUP BY DATE_FORMAT(t_time,\"%m\");"
+	logs.Println(sql)
+	num, err := o.Raw(sql).ValuesList(&maps_z)
+	if err == nil && num > 0 {
+		logs.Println("", maps_z[0][0]) // slene
+	}
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	//key,_ := strconv.Atoi(maps_z[0][0].(string))
+	return maps_z
+} //
+func Read_DeviceData_ById_Month_List(SN string) []orm2.ParamsList {
+	o := orm.NewOrm()
+
+	var maps_z []orm2.ParamsList
+	if len(SN) == 0 {
+		return maps_z
+	}
+	currentTime := time.Now() //获取当前时间,类型是Go的时间类型Time
+
+	time_x := currentTime.Format("2006-01") + "-00 00:00:00"
+
+	//sql = "SELECT t_name,t_t,t_rh,t_tl,t_tu,t_rhl,t_rhu,t_site,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_"+SN+" WHERE "+sql_time+" t_id = "+ strconv.Itoa(T_id) +" ORDER BY t_time DESC "
+	sql := "SELECT DATE_FORMAT(t_time,\"%d\") AS d FROM z_devicedata_" + SN + "  WHERE t_time > '" + time_x + "' GROUP BY DATE_FORMAT(t_time,\"%d\");"
+	logs.Println(sql)
+	o.Raw(sql).ValuesList(&maps_z)
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	//key,_ := strconv.Atoi(maps_z[0][0].(string))
+	return maps_z
+}
+func Read_DeviceSensorData_ById_Day_List(SN string) []orm2.ParamsList {
+	o := orm.NewOrm()
+
+	var maps_z []orm2.ParamsList
+	if len(SN) == 0 {
+		return maps_z
+	}
+	currentTime := time.Now() //获取当前时间,类型是Go的时间类型Time
+
+	time_x := currentTime.Format("2006-01-02") + " 00:00:00"
+
+	//sql = "SELECT t_name,t_t,t_rh,t_tl,t_tu,t_rhl,t_rhu,t_site,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_"+SN+" WHERE "+sql_time+" t_id = "+ strconv.Itoa(T_id) +" ORDER BY t_time DESC "
+	sql := "SELECT DATE_FORMAT(t_time,\"%H\") AS m FROM z_devicedata_" + SN + "  WHERE t_time > '" + time_x + "' GROUP BY DATE_FORMAT(t_time,\"%H\");"
+	logs.Println(sql)
+	o.Raw(sql).ValuesList(&maps_z)
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	//key,_ := strconv.Atoi(maps_z[0][0].(string))
+	return maps_z
+}
+
+func Read_DeviceSensorData_List_GROUP_BY_t_time(SN string, Time_start_ string, Time_end_ string) []orm2.ParamsList {
+	o := orm.NewOrm()
+
+	var maps_z []orm2.ParamsList
+	if len(SN) == 0 {
+		return maps_z
+	}
+
+	sql_time := ""
+	if len(Time_start_) > 1 {
+		sql_time += " t_time >= '" + Time_start_ + "' AND " + " t_time <= '" + Time_end_ + "' "
+	}
+
+	sql := "SELECT DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time FROM z_devicedata_" + SN + " WHERE " + sql_time + "   GROUP BY t_time  ORDER BY t_time DESC "
+	logs.Println(sql)
+	o.Raw(sql).ValuesList(&maps_z)
+	return maps_z
+}
+
+func Read_DeviceData_T_Min_Max_Time_Min_Max(SN string, Time_start_ string, Time_end_ string) (minT, maxT float64, minTime, maxTime time.Time) {
+	o := orm.NewOrm()
+	if len(SN) == 0 {
+		return
+	}
+
+	sql_condition := ""
+
+	if len(Time_start_) > 1 {
+		sql_condition += " AND t_time >= '" + Time_start_ + "'"
+	}
+
+	if len(Time_end_) > 1 {
+		sql_condition += " AND t_time <= '" + Time_end_ + "'"
+	}
+
+	if len(sql_condition) > 0 {
+		sql_condition = " WHERE " + strings.TrimLeft(sql_condition, " AND ")
+	}
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql := "SELECT MIN(t_t) AS min_t, MAX(t_t) AS max_t,MIN(t_time) AS min_time, MAX(t_time) AS max_time FROM z_devicedata_" + SN + sql_condition
+
+	logs.Println(sql)
+	err := o.Raw(sql).QueryRow(&minT, &maxT, &minTime, &maxTime)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return
+
+}

+ 240 - 0
models/Distributor/Distributor.go

@@ -0,0 +1,240 @@
+package Distributor
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 分销商
+type Distributor struct {
+	Id               int       `orm:"column(ID);size(11);auto;pk"`
+	T_name           string    `orm:"size(256);null"`                                        // 名称
+	T_Distributor_id string    `orm:"size(256);null"`                                        // 分销商id
+	T_State          int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
+	CreateTime       time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime       time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+type Distributor_R struct {
+	T_name           string
+	T_Distributor_id string
+	T_VerifyTemplate []string
+}
+
+func (t *Distributor) TableName() string {
+	return "distributor" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_Distributor cache.Cache
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(Distributor))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"distributor", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_Distributor, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_Distributor == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+// -------------------------------------------------------------
+func DistributorToDistributor_R(T Distributor) (T_r Distributor_R) {
+	T_r.T_name = T.T_name
+	T_r.T_Distributor_id = T.T_Distributor_id
+	T_r.T_VerifyTemplate = Read_DistributorVerifyTemplate(T.T_Distributor_id)
+
+	//......
+	return T_r
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_Distributor_Set(key string, r Distributor) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_Distributor.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_Distributor_Get(key string) (r Distributor, is bool) {
+	if redisCache_Distributor.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_Distributor.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return Distributor{}, false
+}
+func Redis_Distributor_DelK(key string) (err error) {
+	err = redisCache_Distributor.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_Distributor_ById(id int) (r Distributor, is bool) {
+	o := orm.NewOrm()
+	r = Distributor{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_Distributor(T_Distributor_id string) (r Distributor, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Distributor))
+	err := qs.Filter("T_Distributor_id", T_Distributor_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_Distributor(r Distributor) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_Distributor_id = lib.GetRandstring(4, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_Distributor_id")                                                            // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	Redis_Distributor_Set(r.T_name, r)
+	return id, true
+}
+
+// 删除
+func Delete_Distributor(v Distributor) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	Redis_Distributor_DelK(v.T_name)
+	return true
+}
+
+// 删除
+func Delete_Distributor_(v Distributor) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		return false
+	}
+
+	Redis_Distributor_DelK(v.T_name)
+	return true
+}
+
+// 修改
+func Update_Distributor(m Distributor, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_Distributor_Set(m.T_name, m)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_Distributor_List(T_name string, page int, page_z int) ([]Distributor_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []Distributor
+	qs := o.QueryTable(new(Distributor))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var Distributor_r []Distributor_R
+	for _, v := range r {
+		Distributor_r = append(Distributor_r, DistributorToDistributor_R(v))
+	}
+
+	return Distributor_r, cnt
+}
+
+// 获取列表
+func Read_Distributor_List_ALL(T_name string) (maps []Distributor) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Distributor))
+	if len(T_name) > 0 {
+		qs = qs.Filter("T_name__icontains", T_name)
+	}
+
+	qs.Filter("T_State", 1).OrderBy("Id").All(&maps)
+
+	return maps
+}
+
+func DistributorListToMap(T []Distributor) map[string]string {
+	maps := make(map[string]string, len(T))
+	for _, v := range T {
+		maps[v.T_Distributor_id] = v.T_name
+	}
+	return maps
+}

+ 179 - 0
models/Distributor/DistributorVerifyTemplate.go

@@ -0,0 +1,179 @@
+package Distributor
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/VerifyTemplate"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// 分销商验证模版
+type DistributorVerifyTemplate struct {
+	Id                       int       `orm:"column(ID);size(11);auto;pk"`
+	T_Distributor_id         string    `orm:"size(200);default(1)"`                                  // 分销商 int id
+	T_VerifyTemplate_id      string    `orm:"size(200);default(1)"`                                  // 验证模版 int id
+	T_VerifyTemplateClass_id int       `orm:"size(200);default(1)"`                                  // 验证模版分类 int id
+	CreateTime               time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime               time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+func (t *DistributorVerifyTemplate) TableName() string {
+	return "distributor_verify_template" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(DistributorVerifyTemplate))
+}
+
+// 添加
+func Add_DistributorVerifyTemplate(r []DistributorVerifyTemplate) (id int64, is bool) {
+	o := orm.NewOrm()
+	id, err := o.InsertMulti(len(r), r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 删除
+func Delete_DistributorVerifyTemplate(T_Distributor_id string) bool {
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(DistributorVerifyTemplate))
+	if num, err := qs.Filter("T_Distributor_id", T_Distributor_id).Delete(); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+func Read_DistributorVerifyTemplate(T_Distributor_id string) (list []string) {
+	o := orm.NewOrm()
+	var map_r []DistributorVerifyTemplate
+	qs := o.QueryTable(new(DistributorVerifyTemplate))
+	qs.Filter("T_Distributor_id", T_Distributor_id).All(&map_r)
+	for _, v := range map_r {
+		list = append(list, v.T_VerifyTemplate_id)
+	}
+	return
+}
+
+// 获取列表
+func Read_DistributorVerifyTemplateClass_List(T_Distributor_id string) (r []VerifyTemplate.VerifyTemplateClass) {
+
+	o := orm.NewOrm()
+	var map_r []VerifyTemplate.VerifyTemplateClass
+	// 也可以直接使用 Model 结构体作为表名
+	sql := "SELECT vtc.* FROM verify_template_class vtc LEFT JOIN distributor_verify_template dvt ON vtc.id = dvt.t__verify_template_class_id" +
+		" WHERE vtc.t__state = 1 and t__distributor_id = '" + T_Distributor_id + "' group by vtc.id order by vtc.id"
+
+	logs.Println(sql)
+
+	_, err := o.Raw(sql).QueryRows(&map_r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return r
+	}
+
+	uniqueMap := make(map[int]struct{})
+	var result []int
+
+	for _, v := range map_r {
+		parents := GetParentIDsByPath(v.T_path)
+		for _, id := range parents {
+			if id == 0 {
+				continue
+			}
+			if _, exists := uniqueMap[id]; !exists {
+				uniqueMap[id] = struct{}{}
+				result = append(result, id)
+			}
+		}
+	}
+	var map_r2 []VerifyTemplate.VerifyTemplateClass
+	qs := o.QueryTable(new(VerifyTemplate.VerifyTemplateClass))
+	qs.Filter("Id__in", result).All(&map_r2)
+
+	r = VerifyTemplate.VerifyTemplateClass_Call(map_r2, 0)
+
+	return r
+
+}
+
+func GetParentIDsByPath(path string) []int {
+	cleaned := strings.Trim(path, "/")
+	if cleaned == "" {
+		return nil
+	}
+	segments := strings.Split(cleaned, "/")
+	parents := make([]int, 0, len(segments))
+	for _, seg := range segments {
+		id, _ := strconv.Atoi(seg)
+		parents = append(parents, id)
+	}
+	return parents
+}
+
+func Read_DistributorVerifyTemplate_List(T_Distributor_id string, T_class int, T_name string, page int, page_z int) ([]VerifyTemplate.VerifyTemplate_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplate.VerifyTemplate
+	var VerifyTemplate_r []VerifyTemplate.VerifyTemplate_R
+	var offset int
+	pagez := page_z
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = (page - 1) * page_z
+	}
+	sqlWhere := "vt.t_class = " + strconv.Itoa(T_class) + " AND t__distributor_id = '" + T_Distributor_id + "'"
+	if len(T_name) > 1 {
+		sqlWhere += " AND vt.t_name like \"%" + T_name + "%\""
+	}
+	sql := "SELECT COUNT(vt.id) FROM verify_template vt LEFT JOIN distributor_verify_template dvt ON vt.t__verify_template_id = dvt.t__verify_template_id COLLATE utf8mb4_general_ci " +
+		"WHERE " + sqlWhere
+	logs.Println(sql)
+	var maps_z []orm2.ParamsList
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		return VerifyTemplate_r, 0
+	}
+	if len(maps_z) == 0 {
+		return VerifyTemplate_r, 0
+	}
+
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	sql = "SELECT vt.* FROM verify_template vt LEFT JOIN distributor_verify_template dvt ON vt.t__verify_template_id = dvt.t__verify_template_id COLLATE utf8mb4_general_ci " +
+		"WHERE " + sqlWhere + " order by vt.t_name"
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&r)
+	if err != nil {
+		logs.Println(lib.FuncName(), err)
+		return VerifyTemplate_r, 0
+	}
+
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+
+	for _, v := range r {
+		VerifyTemplate_r = append(VerifyTemplate_r, VerifyTemplate.VerifyTemplateToVerifyTemplate_R(v))
+	}
+
+	return VerifyTemplate_r, int64(key)
+}

+ 350 - 0
models/InfoCollection/InfoCollection.go

@@ -0,0 +1,350 @@
+package InfoCollection
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strings"
+	"time"
+)
+
+var (
+	InfoCollectionStatusWaitSubmit    = 1 // 待提交
+	InfoCollectionStatusSubmitted     = 2 // 已提交
+	InfoCollectionStatusReceipt       = 3 // 已接收
+	InfoCollectionStatusReturn        = 4 // 已退回
+	InfoCollectionStatusReturnedMoney = 5 // 已回款
+	InfoCollectionStatusMap           = map[int]string{
+		InfoCollectionStatusWaitSubmit:    "待提交",
+		InfoCollectionStatusSubmitted:     "已提交",
+		InfoCollectionStatusReceipt:       "已接收",
+		InfoCollectionStatusReturn:        "已退回",
+		InfoCollectionStatusReturnedMoney: "已回款",
+	}
+)
+
+type AuditRecord struct {
+	T_uuid      string `orm:"size(256);null"`     // 提交人 UUID
+	T_uuid_name string `orm:"size(256);null"`     // 提交人名称
+	T_status    int    `orm:"size(2);default(0)"` // 状态 1待提交 2已提交 3已接收 4已退回 5已回款
+	T_reason    string `orm:"type(text)"`         // 原因
+	T_time      string `orm:"type(256)"`          // 时间
+}
+
+// 模版
+type InfoCollection struct {
+	Id                   int     `orm:"column(ID);size(11);auto;pk"`
+	T_allot_task_id      string  `orm:"size(256);null"`     // 采集任务ID
+	T_InfoCollection_id  string  `orm:"size(256);null"`     // 信息采集ID
+	T_uuid               string  `orm:"size(256);null"`     // 公司 UUID
+	T_name               string  `orm:"size(256);null"`     // 标题
+	T_InfoTemplate_class string  `orm:"size(256);null"`     // 模版分类
+	T_InfoTemplate_id    string  `orm:"size(256);null"`     // 模版id
+	T_status             int     `orm:"size(2);default(0)"` // 状态 1待提交 2已提交 3已接收 4已退回 5已回款
+	T_State              int     `orm:"size(2);default(1)"` // 0 删除  1 正常
+	T_submit_uuid        string  `orm:"size(256);null"`     // 提交人 UUID
+	T_start_time         string  `orm:"size(256);null"`     // 开始时间
+	T_end_time           string  `orm:"size(256);null"`     // 结束时间
+	T_time_interval      float64 `orm:"size(256);null"`     // 时间间隔
+
+	T_return_times int    `orm:"size(200);null"` // 退回次数
+	T_audit_record string `orm:"type(text)"`
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type InfoCollection_R struct {
+	Id                        int
+	T_allot_task_id           string  // 采集任务ID
+	T_InfoCollection_id       string  // 信息采集ID
+	T_uuid                    string  // 用户 UUID
+	T_uuid_name               string  // 用户姓名
+	T_name                    string  // 标题
+	T_InfoTemplate_class      string  // 模版分类
+	T_InfoTemplate_class_name string  // 模版分类名称
+	T_InfoTemplate_id         string  // 模版id
+	T_InfoTemplate_name       string  // 模版名称
+	T_status                  int     // 状态
+	T_status_str              string  // 状态字符串
+	T_State                   int     // 0 删除   1 正常
+	T_submit_uuid             string  // 提交人uuid
+	T_submit_uuid_name        string  // 提交人姓名
+	T_start_time              string  // 开始时间
+	T_end_time                string  // 结束时间
+	T_time_interval           float64 // 时间间隔
+	T_return_times            int     // 退回次数
+	T_audit_record            string
+	CreateTime                string
+	UpdateTime                string
+}
+
+func (t *InfoCollection) TableName() string {
+	return "info_collection" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_InfoCollection cache.Cache
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(InfoCollection))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"InfoCollection", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_InfoCollection, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_InfoCollection == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+	}
+}
+
+// -------------------------------------------------------------
+func InfoCollectionToInfoCollection_R(T InfoCollection, userMap, adminMap, infoTemplateMap, infoTemplateClassMap map[string]string) (T_r InfoCollection_R) {
+	T_r.Id = T.Id
+	T_r.T_allot_task_id = T.T_allot_task_id
+	T_r.T_InfoCollection_id = T.T_InfoCollection_id
+	T_r.T_uuid = T.T_uuid
+	T_r.T_name = T.T_name
+	T_r.T_InfoTemplate_class = T.T_InfoTemplate_class
+	T_r.T_InfoTemplate_id = T.T_InfoTemplate_id
+	T_r.T_status = T.T_status
+	T_r.T_status_str = InfoCollectionStatusMap[T.T_status]
+	T_r.T_State = T.T_State
+	T_r.T_uuid_name = userMap[T.T_uuid]
+	T_r.T_submit_uuid = T.T_submit_uuid
+	T_r.T_submit_uuid_name = adminMap[T.T_submit_uuid]
+
+	T_r.T_InfoTemplate_name = infoTemplateMap[T.T_InfoTemplate_id]
+	classList := strings.Split(strings.Trim(T.T_InfoTemplate_class, "/"), "/")
+	for _, s := range classList {
+		T_r.T_InfoTemplate_class_name += infoTemplateClassMap[s] + "/"
+	}
+	T_r.T_InfoTemplate_class_name = strings.TrimRight(T_r.T_InfoTemplate_class_name, "/")
+
+	T_r.T_start_time = T.T_start_time
+	T_r.T_end_time = T.T_end_time
+	T_r.T_time_interval = T.T_time_interval
+	T_r.T_return_times = T.T_return_times
+	T_r.T_audit_record = T.T_audit_record
+
+	T_r.UpdateTime = T.UpdateTime.Format("2006-01-02 15:04:05")
+	T_r.CreateTime = T.CreateTime.Format("2006-01-02 15:04:05")
+
+	//......
+	return T_r
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_InfoCollection_Set(key string, r InfoCollection) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_InfoCollection.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_InfoCollection_Get(key string) (r InfoCollection, is bool) {
+	if redisCache_InfoCollection.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_InfoCollection.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return InfoCollection{}, false
+}
+func Redis_InfoCollection_DelK(key string) (err error) {
+	err = redisCache_InfoCollection.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_InfoCollection_ById(id int) (r InfoCollection, is bool) {
+	o := orm.NewOrm()
+	r = InfoCollection{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_InfoCollection(T_InfoCollection_id string) (r InfoCollection, is bool) {
+	if r, is = Redis_InfoCollection_Get(T_InfoCollection_id); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoCollection))
+	err := qs.Filter("T_InfoCollection_id", T_InfoCollection_id).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	Redis_InfoCollection_Set(T_InfoCollection_id, r)
+	return r, true
+}
+
+// 添加
+func Add_InfoCollection(r InfoCollection) (string, error) {
+	o := orm.NewOrm()
+	// 查询标题是否重复
+	qs := o.QueryTable(new(InfoCollection))
+	err := qs.Filter("T_name", r.T_name).Filter("T_uuid", r.T_uuid).Filter("T_State", 1).One(&r)
+	if err == nil {
+		return "", errors.New("信息采集标题重复")
+	}
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_InfoCollection_id = lib.GetRandstring(12, "abcdefghijklmnopqrstuvwxyz0123456789", int64(rand_x)) // 1,336,336
+		err = o.Read(&r, "T_InfoCollection_id")                                                              // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+	_, err = o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", errors.New("添加失败")
+	}
+	Redis_InfoCollection_Set(r.T_InfoCollection_id, r)
+	return r.T_InfoCollection_id, nil
+}
+
+// 删除
+func Delete_InfoCollection(v InfoCollection) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_InfoCollection_DelK(v.T_InfoCollection_id)
+	return true
+}
+
+// 修改
+func Update_InfoCollection(m InfoCollection, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_InfoCollection_Set(m.T_InfoCollection_id, m)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取用户信息采集列表
+func Read_UserInfoCollection_List(T_allot_task_id, T_admin string, T_name string, T_status int, userMap, adminMap, infoTemplateMap, infoTemplateClassMap map[string]string, page int, page_z int) ([]InfoCollection_R, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(InfoCollection))
+	var r []InfoCollection
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1).And("T_submit_uuid", T_admin)
+
+	if len(T_allot_task_id) > 0 {
+		cond1 = cond1.And("T_allot_task_id", T_allot_task_id)
+	}
+
+	if T_status > 0 {
+		cond1 = cond1.And("T_status", T_status)
+	}
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var InfoCollectionList []InfoCollection_R
+	for _, v := range r {
+		InfoCollectionList = append(InfoCollectionList, InfoCollectionToInfoCollection_R(v, userMap, adminMap, infoTemplateMap, infoTemplateClassMap))
+	}
+
+	return InfoCollectionList, int(cnt)
+}
+
+// 获取信息采集列表
+func Read_InfoCollection_List(T_uuid, T_allot_task_id, T_name string, T_status int, userMap, adminMap, infoTemplateMap, infoTemplateClassMap map[string]string, page int, page_z int) ([]InfoCollection_R, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(InfoCollection))
+	var r []InfoCollection
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.AndCond(cond.Or("T_name__icontains", T_name).Or("T_InfoCollection_id", T_name)).And("T_State", 1)
+
+	if len(T_uuid) > 0 {
+		cond1 = cond1.And("T_uuid", T_uuid)
+	}
+	if len(T_allot_task_id) > 0 {
+		cond1 = cond1.And("T_allot_task_id", T_allot_task_id)
+	}
+
+	if T_status > 0 {
+		cond1 = cond1.And("T_status", T_status)
+	}
+
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var InfoCollectionList []InfoCollection_R
+	for _, v := range r {
+		InfoCollectionList = append(InfoCollectionList, InfoCollectionToInfoCollection_R(v, userMap, adminMap, infoTemplateMap, infoTemplateClassMap))
+	}
+
+	return InfoCollectionList, int(cnt)
+}

+ 181 - 0
models/InfoCollection/InfoTemplate.go

@@ -0,0 +1,181 @@
+package InfoCollection
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type InfoTemplate struct {
+	Id      int `orm:"column(ID);size(11);auto;pk"`
+	T_class int `orm:"size(8);default(0)"` // 分类
+
+	T_InfoTemplate_id string `orm:"size(256);null"`     // id
+	T_name            string `orm:"size(256);null"`     // 标题
+	T_sort            int    `orm:"size(2);default(1)"` // 排序
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type InfoTemplate_R struct {
+	T_InfoTemplate_id string `orm:"size(256);null"` // id
+	T_name            string `orm:"size(256);null"` // 标题
+	T_sort            int    `orm:"size(200);null"` // 分类
+}
+
+func (t *InfoTemplate) TableName() string {
+	return "info_template" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(InfoTemplate))
+
+}
+
+// -------------------------------------------------------------
+func InfoTemplateToInfoTemplate_R(T InfoTemplate) (T_r InfoTemplate_R) {
+	T_r.T_InfoTemplate_id = T.T_InfoTemplate_id
+	T_r.T_name = T.T_name
+	T_r.T_sort = T.T_sort
+
+	return T_r
+}
+
+func Read_InfoTemplate_List_ALL() (maps []InfoTemplate) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplate))
+
+	qs.OrderBy("Id").All(&maps)
+	return maps
+}
+func InfoTemplateListToMap(A []InfoTemplate) map[string]string {
+	maps := make(map[string]string, len(A))
+	for _, v := range A {
+		maps[v.T_InfoTemplate_id] = v.T_name
+	}
+	return maps
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_InfoTemplate_ById(id int) (r InfoTemplate, is bool) {
+	o := orm.NewOrm()
+	r = InfoTemplate{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_InfoTemplate(T_InfoTemplate_id string) (r InfoTemplate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplate))
+	err := qs.Filter("T_InfoTemplate_id", T_InfoTemplate_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+func Read_InfoTemplate_T_name(T_name string) (r InfoTemplate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplate))
+	err := qs.Filter("T_name", T_name).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_InfoTemplate(r InfoTemplate) (T_InfoTemplate_id string, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_InfoTemplate_id = lib.GetRandstring(4, "", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_InfoTemplate_id")                        // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+
+	return r.T_InfoTemplate_id, true
+}
+
+// 删除
+func Delete_InfoTemplate(v InfoTemplate) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_InfoTemplate(m InfoTemplate, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_InfoTemplate_List(T_class int, T_name string, page int, page_z int) ([]InfoTemplate_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []InfoTemplate
+	qs := o.QueryTable(new(InfoTemplate))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_class", T_class).And("T_name__icontains", T_name) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_name").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("T_name").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+	// 转换
+	var InfoTemplate_r []InfoTemplate_R
+	for _, v := range r {
+		InfoTemplate_r = append(InfoTemplate_r, InfoTemplateToInfoTemplate_R(v))
+	}
+
+	return InfoTemplate_r, cnt
+}

+ 320 - 0
models/InfoCollection/InfoTemplateClass.go

@@ -0,0 +1,320 @@
+package InfoCollection
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"errors"
+	"fmt"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+)
+
+// 模版
+type InfoTemplateClass struct {
+	Id     int    `orm:"column(ID);size(11);auto;pk"`
+	T_fid  int    `orm:"size(200);null"` // 父级分类ID,主类 为 0
+	T_name string `orm:"size(256);null"` // 标题
+	T_path string `orm:"size(256);null"` // 路径
+
+	T_State int `orm:"size(2);default(1)"` // 0 删除(伪删除)   1 正常
+
+	Children []InfoTemplateClass `orm:"-"`
+}
+
+func (t *InfoTemplateClass) TableName() string {
+	return "info_template_class" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(InfoTemplateClass))
+}
+
+type InfoTemplateClass_R struct {
+	Id       int
+	T_fid    int                 // 项目 id, InfoTemplateClass.ID
+	T_name   string              // 名称
+	T_State  int                 // 0 删除(伪删除)   1 正常(已交付)     2 开发中
+	Children []InfoTemplateClass `orm:"-"`
+}
+
+func Read_InfoTemplateClass_List_ALL() (maps []InfoTemplateClass) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateClass))
+
+	qs.OrderBy("Id").All(&maps)
+	return maps
+}
+func InfoTemplateClassListToMap(A []InfoTemplateClass) map[string]string {
+	maps := make(map[string]string, len(A))
+	for _, v := range A {
+		maps[strconv.Itoa(v.Id)] = v.T_name
+	}
+	return maps
+}
+
+// 获取 ById
+func Read_InfoTemplateClass_ById(id int) (r InfoTemplateClass, err error) {
+	o := orm.NewOrm()
+	r = InfoTemplateClass{Id: id, T_State: 1}
+	err = o.Read(&r, "Id", "T_State")
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, err
+	}
+	return r, err
+}
+
+// 添加
+func Add_InfoTemplateClass(var_ InfoTemplateClass) (id int64, err error) {
+	o := orm.NewOrm()
+	o.Begin()
+	id, err = o.Insert(&var_)
+	if err != nil {
+		o.Rollback()
+		return id, err
+	}
+
+	T_Path := "/0/" + strconv.Itoa(int(id)) + "/"
+	if var_.T_fid != 0 {
+		class_r, err := Read_InfoTemplateClass_ById(var_.T_fid)
+		if err != nil {
+			o.Rollback()
+			return id, err
+		}
+		T_Path = class_r.T_path + strconv.Itoa(int(id)) + "/"
+	}
+
+	var_.Id = int(id)
+	var_.T_path = T_Path
+	_, err = o.Update(&var_, "T_path")
+	if err != nil {
+		o.Rollback()
+		return id, err
+	}
+	o.Commit()
+
+	return id, err
+}
+
+// 修改
+func Update_InfoTemplateClass(r InfoTemplateClass, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&r, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 批量删除
+func Delete_InfoTemplateClass_ByIds(ids []int) bool {
+	o := orm.NewOrm()
+	o.Begin()
+	for _, id := range ids {
+		v := InfoTemplateClass{Id: id, T_State: 0}
+		if _, err := o.Update(&v, "T_State"); err != nil {
+			o.Rollback()
+			return false
+		}
+	}
+
+	o.Commit()
+	return true
+}
+
+// 获取列表
+func Read_InfoTemplateClass_List() (r []InfoTemplateClass) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var map_r []InfoTemplateClass
+	qs := o.QueryTable(new(InfoTemplateClass))
+
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_State", 1)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&map_r)
+
+	r = InfoTemplateClass_Call(map_r, 0)
+
+	return r
+
+}
+
+func InfoTemplateClass_Call(list []InfoTemplateClass, parentId int) []InfoTemplateClass {
+	res := make([]InfoTemplateClass, 0)
+	for _, v := range list {
+		if v.T_fid == parentId {
+			v.Children = InfoTemplateClass_Call(list, v.Id)
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
+// 通过T_pid查询所有子id
+func ReadInfoTemplateClassIds_T_path(T_path string) (InfoTemplateClassIds []int) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateClass))
+	var InfoTemplateClassList []InfoTemplateClass
+	qs.Filter("T_path__startswith", T_path).Filter("T_State", 1).All(&InfoTemplateClassList)
+	for _, v := range InfoTemplateClassList {
+		InfoTemplateClassIds = append(InfoTemplateClassIds, v.Id)
+	}
+	return InfoTemplateClassIds
+}
+
+// 通过T_path查询所有子信息采集分类
+func ReadInfoTemplateClassList_T_path(T_path string, parentId int) (r []InfoTemplateClass) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateClass))
+	var InfoTemplateClassList []InfoTemplateClass
+	qs.Filter("T_path__startswith", T_path).Filter("T_State", 1).All(&InfoTemplateClassList)
+	r = InfoTemplateClass_Call(InfoTemplateClassList, parentId)
+	return r
+}
+
+// 递归复制节点
+func copyInfoTemplateClass(o orm.Ormer, r *InfoTemplateClass, newParentId int, parentPath string) (*InfoTemplateClass, error) {
+
+	// 创建新节点
+	infoTemplateClass := InfoTemplateClass{
+		T_fid:   newParentId,
+		T_name:  r.T_name, // 添加副本标识
+		T_State: 1,
+		// T_path 将在插入后更新
+	}
+
+	// 插入数据库
+	newInfoTemplateClassId, err := o.Insert(&infoTemplateClass)
+	if err != nil {
+		return nil, err
+	}
+
+	newPath := parentPath + strconv.Itoa(infoTemplateClass.Id) + "/"
+
+	// 更新路径
+	infoTemplateClass.Id = int(newInfoTemplateClassId)
+	infoTemplateClass.T_path = newPath
+	_, err = o.Update(&infoTemplateClass, "T_path")
+	if err != nil {
+		return nil, err
+	}
+
+	// 复制子节点
+	for _, child := range r.Children {
+		_, err = copyInfoTemplateClass(o, &child, infoTemplateClass.Id, newPath)
+		if err != nil {
+			return nil, err
+		}
+	}
+	// 分类1
+	//  ----模版
+	//	--------标签
+	// 分类2
+	//   -- 子分类
+	// 2 复制分类下的模版
+	// 3 复制模版下的标签
+	infoTemplateList, _ := Read_InfoTemplate_List(r.Id, "", 0, 9999)
+	for _, v := range infoTemplateList {
+		infoTemplate, is := Read_InfoTemplate(v.T_InfoTemplate_id)
+		if !is {
+			return nil, errors.New("查询信息采集模版失败")
+		}
+
+		newInfoTemplate := InfoTemplate{
+			T_class: infoTemplateClass.Id, // 新的分类id
+			T_name:  infoTemplate.T_name,
+			T_sort:  infoTemplate.T_sort,
+		}
+
+		newInfoTemplateId, is := Add_InfoTemplate(newInfoTemplate)
+		if !is {
+			return nil, errors.New("复制信息采集模版失败")
+		}
+
+		// 复制模版下面的标签
+		mapList, _ := Read_InfoTemplateMap_List(v.T_InfoTemplate_id, 0, 0)
+		tempMap := make(map[string]struct{})
+		idList := make([]string, len(mapList))
+		// 生成mapList长度的T_id
+		for i := 0; i < len(mapList); i++ {
+			// 生成编号
+			rand_x := 0
+			T_id := ""
+			for rand_x < 100 {
+				T_id = lib.GetRandstring(4, "", int64(rand_x))
+				_, is = Read_InfoTemplateMap(T_id)
+				if !is {
+					if _, ok := tempMap[T_id]; !ok {
+						break
+					}
+				}
+				rand_x += 1
+			}
+			tempMap[T_id] = struct{}{}
+			idList[i] = T_id
+		}
+		mapInsertList := make([]InfoTemplateMap, 0)
+		for i, m := range mapList {
+			vtm := InfoTemplateMap{
+				T_id:              idList[i],
+				T_InfoTemplate_id: newInfoTemplateId,
+				T_name:            m.T_name,
+				T_text:            m.T_text,
+				T_label:           m.T_label,
+				T_sort:            m.T_sort,
+			}
+
+			mapInsertList = append(mapInsertList, vtm)
+		}
+
+		_, is = Add_InfoTemplateMapMulti(mapInsertList)
+		if !is {
+			return nil, errors.New("复制信息采集模版标签失败")
+		}
+	}
+
+	return &infoTemplateClass, nil
+}
+
+func CopyInfoTemplateClassTree(T_path string, parentId int, T_name string) (newRoot *InfoTemplateClass, err error) {
+	// 获取原始节点及其子树
+	o := orm.NewOrm()
+	srcNode := ReadInfoTemplateClassList_T_path(T_path, parentId)
+
+	if len(srcNode) == 0 {
+		return nil, errors.New("查询信息采集分类失败")
+	}
+	srcNode[0].T_name = T_name
+	// 开启事务
+	err = o.Begin()
+	if err != nil {
+		o.Rollback()
+		return nil, fmt.Errorf("事务启动失败: %v", err)
+	}
+
+	s := strings.Split(strings.Trim(T_path, "/"), "/")
+	parentPath := fmt.Sprintf("/%s/", strings.Join(s[:len(s)-1], "/"))
+	// 递归复制
+	newRoot, err = copyInfoTemplateClass(o, &srcNode[0], parentId, parentPath) // 假设复制到根目录
+	if err != nil {
+		o.Rollback()
+		return nil, err
+	}
+
+	// 提交事务
+	if err = o.Commit(); err != nil {
+		o.Rollback()
+		return nil, fmt.Errorf("事务提交失败: %v", err)
+	}
+
+	return newRoot, nil
+}

+ 202 - 0
models/InfoCollection/VerifyTemplateMap.go

@@ -0,0 +1,202 @@
+package InfoCollection
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"log"
+	"time"
+)
+
+// 模版
+type InfoTemplateMap struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_id              string `orm:"index,size(256);null"` // 标题
+	T_InfoTemplate_id string `orm:"size(256);null"`       // 标题
+	T_label           int    `orm:"size(2);default(1)"`   // 数据类型
+
+	//1:文本
+	//2:数值
+	//3:设备多选 (1|2|3|4|5|6|)
+	//4:设备单选 (1)
+	//7:当期时间(2022年01月19日)
+	//9:当期时间(开始与结束时间)(2022-01-01 13:08|2022-01-02 13:08)
+	//10:图片
+	//11:CAD
+	T_name string `orm:"size(256);null"`     // 标签名称
+	T_text string `orm:"size(256);null"`     // 描述
+	T_sort int    `orm:"size(2);default(1)"` // 排序
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type InfoTemplateMap_R struct {
+	T_id    string
+	T_label int    // 来源
+	T_name  string // 标签名称
+	T_text  string // 描述
+	T_sort  int    // 排序
+}
+
+func (t *InfoTemplateMap) TableName() string {
+	return "info_template_map" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(InfoTemplateMap))
+
+}
+
+// -------------------------------------------------------------
+func InfoTemplateMapToInfoTemplateMap_R(T InfoTemplateMap) (T_r InfoTemplateMap_R) {
+	T_r.T_id = T.T_id
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_sort = T.T_sort
+	return T_r
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_InfoTemplateMap_ById(id int) (r InfoTemplateMap, is bool) {
+	o := orm.NewOrm()
+	r = InfoTemplateMap{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_InfoTemplateMap(T_id string) (r InfoTemplateMap, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateMap))
+	err := qs.Filter("T_id", T_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_InfoTemplateMap(r InfoTemplateMap) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_id = lib.GetRandstring(4, "", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_id")                        // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 添加
+func Add_InfoTemplateMapMulti(r []InfoTemplateMap) (id int64, is bool) {
+	o := orm.NewOrm()
+	n, err := o.InsertMulti(len(r), r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return n, false
+	}
+
+	return n, true
+}
+
+// 删除
+func Delete_InfoTemplateMap(v InfoTemplateMap) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_InfoTemplateMap(m InfoTemplateMap, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		log.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_InfoTemplateMap_List(T_InfoTemplate_id string, T_sort, T_flow_sort int) ([]InfoTemplateMap_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []InfoTemplateMap
+	qs := o.QueryTable(new(InfoTemplateMap))
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_InfoTemplate_id", T_InfoTemplate_id) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	// 排序 默认升序
+
+	if T_sort == 2 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-T_sort").All(&r)
+		//} else if T_flow_sort == 1 {
+		//	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_flow_sort").All(&r)
+		//} else if T_flow_sort == 2 {
+		//	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-T_flow_sort").All(&r)
+	} else {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_sort").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var InfoTemplateMap_r []InfoTemplateMap_R
+	for _, v := range r {
+		InfoTemplateMap_r = append(InfoTemplateMap_r, InfoTemplateMapToInfoTemplateMap_R(v))
+	}
+
+	return InfoTemplateMap_r, cnt
+}
+
+func Read_InfoTemplateMap_List_For_Data(T_InfoTemplate_id string) []InfoTemplateMap {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []InfoTemplateMap
+	qs := o.QueryTable(new(InfoTemplateMap))
+
+	cond := orm.NewCondition()
+	cond = cond.And("T_InfoTemplate_id", T_InfoTemplate_id)
+	qs.SetCond((*orm2.Condition)(cond)).OrderBy("T_sort").All(&r)
+
+	return r
+}
+
+func InfoTemplateMap_RToMap(T []InfoTemplateMap_R) map[string]string {
+	maps := make(map[string]string, len(T))
+	for _, v := range T {
+		maps[v.T_id] = v.T_name
+	}
+	return maps
+}

+ 200 - 0
models/InfoCollection/VerifyTemplateMapData.go

@@ -0,0 +1,200 @@
+package InfoCollection
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"fmt"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type InfoTemplateMapData struct {
+	Id                   int    `orm:"column(ID);size(11);auto;pk"`
+	T_InfoCollection_id  string `orm:"index,size(256);null"` // 信息采集id
+	T_InfoTemplate_id    string `orm:"index,size(256);null"` // 模版id
+	T_InfoTemplateMap_id string `orm:"index,size(256);null"` // 标签id
+	T_value              string `orm:"size(1024);null"`      // 内容
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type InfoTemplateMapData_R struct {
+	T_id                 int
+	T_InfoTemplateMap_id string // 标签id
+	T_label              int    //
+	T_name               string // 标题
+	T_text               string // 标题
+	T_value              string //
+}
+
+func (t *InfoTemplateMapData) TableName() string {
+	return "info_template_map_data" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(InfoTemplateMapData))
+
+}
+
+// -------------------------------------------------------------
+func InfoTemplateMapToInfoTemplateMapData_R(T InfoTemplateMap) (T_r InfoTemplateMapData_R) {
+	T_r.T_InfoTemplateMap_id = T.T_id
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+
+	T_r.T_value = ""
+	return T_r
+}
+
+func InfoTemplateMapDataToInfoTemplateMapData_R(T InfoTemplateMap, InfoTemplateMapData map[string]InfoTemplateMapData) (T_r InfoTemplateMapData_R) {
+	T_r.T_InfoTemplateMap_id = T.T_id
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+
+	T_r.T_value = ""
+	if v, ok := InfoTemplateMapData[T.T_id]; ok {
+		T_r.T_value = v.T_value
+	}
+	return T_r
+}
+
+// ---------------- 特殊方法 -------------------
+// 添加
+func AddOrUpdate_InfoTemplateMapData(List []InfoTemplateMapData) (ids []int64, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateMapData))
+	o.Begin()
+	for _, v := range List {
+		var r InfoTemplateMapData
+		// 创建验证模版数据,有则更新,没有则创建
+		if v.T_InfoTemplateMap_id == "gVqW" {
+			fmt.Println(v.T_value)
+		}
+		err := qs.Filter("T_InfoCollection_id", v.T_InfoCollection_id).Filter("T_InfoTemplate_id", v.T_InfoTemplate_id).Filter("T_InfoTemplateMap_id", v.T_InfoTemplateMap_id).One(&r)
+		if err != nil {
+			if err.Error() == orm.ErrNoRows.Error() {
+				id, err := o.Insert(&v)
+				if err != nil {
+					logs.Error(lib.FuncName(), err)
+					o.Rollback()
+					return ids, false
+				}
+				ids = append(ids, id)
+			} else {
+				logs.Error(lib.FuncName(), err)
+				o.Rollback()
+				return ids, false
+			}
+		}
+
+		// 更新验证模版数据
+		if r.Id > 0 && len(v.T_value) > 0 {
+
+			v.Id = r.Id
+			//_, err = o.Update(&v, "T_flow_sort", "T_max_time", "T_min_time", "T_value")
+			_, err = o.QueryTable(new(InfoTemplateMapData)).Filter("T_InfoCollection_id", v.T_InfoCollection_id).Filter("T_InfoTemplate_id", v.T_InfoTemplate_id).
+				Filter("T_InfoTemplateMap_id", v.T_InfoTemplateMap_id).Update(orm2.Params{"T_value": v.T_value})
+			if err != nil {
+				logs.Error(lib.FuncName(), err)
+				o.Rollback()
+				return ids, false
+			}
+			ids = append(ids, int64(r.Id))
+		}
+
+	}
+
+	o.Commit()
+
+	return ids, true
+}
+
+// 获取列表
+func Read_InfoTemplateMapData_List(T_InfoCollection_id, T_InfoTemplate_id string, Map_List []InfoTemplateMap) []InfoTemplateMapData_R {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []InfoTemplateMapData
+	qs := o.QueryTable(new(InfoTemplateMapData))
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_InfoCollection_id", T_InfoCollection_id).And("T_InfoTemplate_id", T_InfoTemplate_id)
+
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	if len(r) == 0 {
+		// 转换
+		var InfoTemplateMapData_r []InfoTemplateMapData_R
+		for k, v := range Map_List {
+			Data_r := InfoTemplateMapToInfoTemplateMapData_R(v)
+			Data_r.T_id = k
+			InfoTemplateMapData_r = append(InfoTemplateMapData_r, Data_r)
+		}
+
+		return InfoTemplateMapData_r
+	}
+
+	// 转换
+	var InfoTemplateMapData_r []InfoTemplateMapData_R
+	for k, v := range Map_List {
+		Data_r := InfoTemplateMapDataToInfoTemplateMapData_R(v, InfoTemplateMapDataToMap(r))
+		Data_r.T_id = k
+		InfoTemplateMapData_r = append(InfoTemplateMapData_r, Data_r)
+	}
+	return InfoTemplateMapData_r
+}
+
+// 获取列表
+func Read_MapData_List(T_InfoCollection_id, T_InfoTemplate_id string) []InfoTemplateMapData {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []InfoTemplateMapData
+	qs := o.QueryTable(new(InfoTemplateMapData))
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_InfoCollection_id", T_InfoCollection_id).And("T_InfoTemplate_id", T_InfoTemplate_id)
+
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	return r
+}
+
+func InfoTemplateMapDataToMap(T []InfoTemplateMapData) map[string]InfoTemplateMapData {
+	maps := make(map[string]InfoTemplateMapData, len(T))
+	for _, v := range T {
+		if _, ok := maps[v.T_InfoTemplateMap_id]; ok {
+			continue
+		}
+		maps[v.T_InfoTemplateMap_id] = v
+	}
+	return maps
+}
+
+// 清除T_value数据
+func Clear_InfoTemplateMapData_T_value(T_InfoCollection_id, T_InfoTemplate_id, T_InfoTemplateMap_id string) (err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(InfoTemplateMapData))
+
+	var r InfoTemplateMapData
+	// 创建验证模版数据,有则更新,没有则创建
+	err = qs.Filter("T_InfoCollection_id", T_InfoCollection_id).Filter("T_InfoTemplate_id", T_InfoTemplate_id).Filter("T_InfoTemplateMap_id", T_InfoTemplateMap_id).One(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	r.T_value = ""
+	_, err = o.Update(&r, "T_value")
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	return nil
+}

+ 74 - 0
models/System/Logs.go

@@ -0,0 +1,74 @@
+package System
+
+import (
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type Logs struct {
+	Id         int    `orm:"column(ID);size(11);auto;pk"`
+	Logs_class string `orm:"size(256);null"`  //
+	Logs_Title string `orm:"size(256);null"`  // 标题
+	Logs_Txt   string `orm:"type(text);null"` // 详情
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+type L_JSON struct {
+}
+
+func (t *Logs) TableName() string {
+	return "logs" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(Logs))
+
+}
+
+// 添加  System.Add_Logs("MqttServer","参数请求 [Rt_Parameter]","base")
+func Add_Logs(Logs_class string, Logs_Title string, Logs_Txt string) {
+	o := orm.NewOrm()
+	m := Logs{Logs_class: Logs_class, Logs_Title: Logs_Title, Logs_Txt: Logs_Txt}
+	o.Insert(&m)
+}
+
+// 获取列表
+func Read_Logs_ALL(page, page_z int, Logs_class string) (r []Logs, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(Logs))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	qs.Limit(page_z, offset).Filter("Logs_class__icontains", Logs_class).OrderBy("-Id").All(&r)
+	cnt, _ = qs.Filter("Logs_class__icontains", Logs_class).Count()
+
+	return r, cnt
+}
+
+type CLASS_lists struct {
+	Logs_class string
+}
+
+// 获取列表
+func Read_Logs_Class() (lists orm2.ParamsList) {
+	o := orm.NewOrm()
+	var pl_lists orm2.ParamsList
+	num, err := o.Raw("SELECT DISTINCT logs_class FROM Logs LIMIT 0,1000").ValuesFlat(&pl_lists)
+	if err == nil {
+		logs.Println("user nums: ", num)
+	}
+
+	return pl_lists
+}

+ 147 - 0
models/System/News.go

@@ -0,0 +1,147 @@
+package System
+
+import (
+	"ColdVerify_server/conf"
+	"fmt"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"github.com/go-resty/resty/v2"
+	"time"
+)
+
+type News struct {
+	Id         int       `orm:"column(ID);size(11);auto;pk"`
+	T_uuid     string    `orm:"size(256);null"`                                        //
+	T_Title    string    `orm:"size(256);null"`                                        // 标题
+	T_Url      string    `orm:"size(256);null"`                                        // 地址
+	T_Tag      int       `orm:"size(2);null"`                                          // 标记   0未阅读   1 已阅读
+	T_app      int       `orm:"size(2);null"`                                          // app提交   0 其他   1 app
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+}
+type News_R struct {
+	Id         int
+	T_uuid     string
+	T_Title    string
+	T_Url      string
+	T_Tag      int
+	CreateTime string
+}
+
+func (t *News) TableName() string {
+	return "news" // 数据库名称
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(News))
+}
+func NewsToNews_R(r News) (m News_R) {
+	m.Id = r.Id
+	m.T_uuid = r.T_uuid
+	m.T_Title = r.T_Title
+	m.T_Url = r.T_Url
+	m.T_Tag = r.T_Tag
+	m.CreateTime = r.CreateTime.Format("2006-01-02 15:04:05")
+	return
+}
+
+// 添加
+func Add_News(T_uuid, T_Title, T_Url string) {
+	r := News{T_uuid: T_uuid, T_Title: T_Title, T_Url: T_Url}
+
+	o := orm.NewOrm()
+
+	r.T_Tag = 0
+	o.Insert(&r)
+	//id, err = o.Insert(&r)
+	//if err != nil {
+	//	fmt.Println(err)
+	//}
+	//return id, err
+}
+func Add_App_News(T_uuid, T_Title, T_Url string) {
+	r := News{T_uuid: T_uuid, T_Title: T_Title, T_Url: T_Url, T_app: 1}
+
+	o := orm.NewOrm()
+
+	r.T_Tag = 0
+	o.Insert(&r)
+	//id, err = o.Insert(&r)
+	//if err != nil {
+	//	fmt.Println(err)
+	//}
+	//return id, err
+}
+
+// 发送微信通知
+func Send_Weichat_News(T_admin_name, T_Title, T_Url string) {
+	// 微信通知
+	client := resty.New()
+	client.R().
+		SetFormData(map[string]string{
+			"name": conf.WechatNews_GroupName,
+			"data": fmt.Sprintf("@%s %s", T_admin_name, T_Title),
+		}).
+		Post(conf.WechatNews_Url)
+
+}
+
+// 获取列表
+func Read_News_List(T_uuid string, T_Title string, T_Tag, T_app int, page int, page_z int) (r_ []News_R, cnt int64) {
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	qs := o.QueryTable(new(News))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	// 过滤
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_uuid", T_uuid) //  .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	if T_app == 1 {
+		cond1 = cond1.And("T_app", 1)
+	} else {
+		cond1 = cond1.AndNot("T_app", 1)
+	}
+
+	if len(T_Title) > 0 {
+		//cond1.AndCond(cond.And("T_class", class))
+		cond1 = cond1.And("T_Title__icontains", T_Title)
+	}
+	if T_Tag == 0 {
+		cond1 = cond1.And("T_Tag", 0)
+	}
+	var r []News
+	// 查询
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ = qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	for _, v := range r {
+		r_ = append(r_, NewsToNews_R(v))
+	}
+
+	return r_, cnt
+}
+
+// 修改 排序
+func Update_News_Tag(Id int, T_uuid string) (err error) {
+	o := orm.NewOrm()
+	v := News{Id: Id}
+
+	if err = o.Read(&v, "Id"); err == nil {
+		var num int64
+		if v.T_uuid != T_uuid {
+			return
+		}
+
+		v.T_Tag = 1
+		if num, err = o.Update(&v, "T_Tag"); err == nil {
+			fmt.Println("Number of records updated in database:", num)
+		}
+	}
+
+	return
+}

+ 77 - 0
models/System/UserLogs.go

@@ -0,0 +1,77 @@
+package System
+
+import (
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type UserLogs struct {
+	Id         int    `orm:"column(ID);size(11);auto;pk"`
+	Logs_uuid  string `orm:"size(256);null"`  //
+	Logs_class string `orm:"size(256);null"`  //
+	Logs_Title string `orm:"size(256);null"`  // 标题
+	Logs_Txt   string `orm:"type(text);null"` // 详情
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+func (t *UserLogs) TableName() string {
+	return "user_logs" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(UserLogs))
+
+}
+
+// 添加  System.Add_UserLogs(user_r.T_user,"登陆", "管理员登陆", "")
+func Add_UserLogs(Logs_uuid string, Logs_class string, Logs_Title string, Logs_Txt string) {
+	o := orm.NewOrm()
+	m := UserLogs{Logs_uuid: Logs_uuid, Logs_class: Logs_class, Logs_Title: Logs_Title, Logs_Txt: Logs_Txt}
+	o.Insert(&m)
+}
+func Add_UserLogs_T(Logs_uuid string, Logs_class string, Logs_Title string, Logs_Txt_T interface{}) {
+	o := orm.NewOrm()
+	jsonStu, err := json.Marshal(Logs_Txt_T)
+	if err != nil {
+		logs.Println("Add_UserLogs_T JSON ,err=", err)
+	}
+	m := UserLogs{Logs_uuid: Logs_uuid, Logs_class: Logs_class, Logs_Title: Logs_Title, Logs_Txt: string(jsonStu)}
+	o.Insert(&m)
+}
+
+// 获取列表
+func Read_UserLogs_ALL(page, page_z int, Logs_class string) (r []UserLogs, cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(UserLogs))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	qs.Limit(page_z, offset).Filter("Logs_class__icontains", Logs_class).OrderBy("-Id").All(&r)
+	cnt, _ = qs.Filter("Logs_class__icontains", Logs_class).Count()
+
+	return r, cnt
+}
+
+// 获取列表
+func Read_UserLogs_Class() (lists orm2.ParamsList) {
+	o := orm.NewOrm()
+	var pl_lists orm2.ParamsList
+	num, err := o.Raw("SELECT DISTINCT logs_class FROM UserLogs LIMIT 0,1000").ValuesFlat(&pl_lists)
+	if err == nil {
+		logs.Println("user nums: ", num)
+	}
+	return pl_lists
+}

+ 1487 - 0
models/Task/Task.go

@@ -0,0 +1,1487 @@
+package Task
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/InfoCollection"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+var (
+	TaskSchemeStateWaitSubmit   = 0 // 待提交
+	TaskSchemeStateSubmitted    = 5 // 已提交
+	TaskSchemeStateClientPass   = 1 // 已通过(客户)
+	TaskSchemeStateClientReturn = 2 // 已退回(客户)
+	TaskSchemeStatePass         = 3 // 已通过(负责人)
+	TaskSchemeStateReturn       = 4 // 已退回(负责人)
+	TaskSchemeStateMap          = map[int]string{
+		TaskSchemeStateWaitSubmit:   "待提交",
+		TaskSchemeStateSubmitted:    "已提交",
+		TaskSchemeStateClientPass:   "已通过(客户)",
+		TaskSchemeStateClientReturn: "已驳回(客户)",
+		TaskSchemeStatePass:         "已通过",
+		TaskSchemeStateReturn:       "已退回",
+	}
+
+	// 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(报告负责人) 6已退回(报告负责人)
+	TaskCollectionStateWaitSubmit = 0 // 待提交
+	TaskCollectionStateFinish     = 1 // 已完成
+	TaskCollectionStateInProgress = 2 // 处理中
+	TaskCollectionStateNoData     = 3 // 已采集-无数据
+	TaskCollectionStateSubmitted  = 4 // 已提交
+	TaskCollectionStatePass       = 5 // 已通过(负责人)
+	TaskCollectionStateReturn     = 6 // 已退回(负责人)
+	TaskCollectionStateMap        = map[int]string{
+		TaskCollectionStateWaitSubmit: "待提交",
+		TaskCollectionStateFinish:     "已完成",
+		TaskCollectionStateInProgress: "处理中",
+		TaskCollectionStateNoData:     "已采集-无数据",
+		TaskCollectionStateSubmitted:  "APP已提交",
+		TaskCollectionStatePass:       "已通过",
+		TaskCollectionStateReturn:     "已退回",
+	}
+
+	TaskReportingStateWaitSubmit   = 0 // 待提交
+	TaskReportingStateSubmitted    = 5 // 已提交
+	TaskReportingStateClientPass   = 1 // 已通过(客户)
+	TaskReportingStateClientReturn = 2 // 已退回(客户)
+	TaskReportingStatePass         = 3 // 已通过
+	TaskReportingStateReturn       = 4 // 已退回
+	TaskReportingStateMap          = map[int]string{
+		TaskReportingStateWaitSubmit:   "待提交",
+		TaskReportingStateSubmitted:    "已提交",
+		TaskReportingStateClientPass:   "已通过(客户)",
+		TaskReportingStateClientReturn: "已驳回(客户)",
+		TaskReportingStatePass:         "已通过",
+		TaskReportingStateReturn:       "已退回",
+	}
+
+	TaskExaminingReportStateWaitSubmit    = 0 // 待提交
+	TaskExaminingReportStateSubmitted     = 5 // 已提交
+	TaskExaminingReportStateClientPass    = 1 // 已通过(客户)
+	TaskExaminingReportStateClientReturn  = 2 // 已退回(客户)
+	TaskExaminingReportStatePass          = 3 // 已通过
+	TaskExaminingReportStateReturn        = 4 // 已退回
+	TaskExaminingReportStateClickGenerate = 6 // 已退回
+	TaskExaminingReportStateMap           = map[int]string{
+		TaskExaminingReportStateWaitSubmit:    "待提交",
+		TaskExaminingReportStateSubmitted:     "已提交",
+		TaskExaminingReportStateClientPass:    "已通过(客户)",
+		TaskExaminingReportStateClientReturn:  "已驳回(客户)",
+		TaskExaminingReportStatePass:          "已通过",
+		TaskExaminingReportStateReturn:        "已退回",
+		TaskExaminingReportStateClickGenerate: "已点击报告生成",
+	}
+
+	TaskOriginalRecordStateWaitSubmit = 0 // 待提交
+	TaskOriginalRecordStateSubmitted  = 5 // 已提交
+	TaskOriginalRecordStatePass       = 3 // 已通过
+	TaskOriginalRecordStateReturn     = 4 // 已退回
+	TaskOriginalRecordStateMap        = map[int]string{
+		TaskOriginalRecordStateWaitSubmit: "待提交",
+		TaskOriginalRecordStateSubmitted:  "已提交",
+		TaskOriginalRecordStatePass:       "已通过",
+		TaskOriginalRecordStateReturn:     "已退回",
+	}
+
+	TaskDeliveryStateUnfinished = 0 // 未完成
+	TaskDeliveryStateFinished   = 1 // 已完成
+	TaskDeliveryStateGoing      = 2 // 进行中
+	TaskDeliveryStateMap        = map[int]string{
+		TaskDeliveryStateUnfinished: "未完成",
+		TaskDeliveryStateFinished:   "已完成",
+		TaskDeliveryStateGoing:      "处理中",
+	}
+
+	TaskMarkingStateUnfinished = 0 // 未完成
+	TaskMarkingStateFinished   = 1 // 已完成
+	TaskMarkingStateMap        = map[int]string{
+		TaskMarkingStateUnfinished: "未完成",
+		TaskMarkingStateFinished:   "已完成",
+	}
+)
+
+var (
+	TaskSchemeTimeLimit = map[string]float64{
+		"BWX":   30, // 保温箱
+		"LDX":   30, // 冷冻箱
+		"LCG":   30, // 冷藏柜
+		"LDG":   30, // 冷冻柜
+		"YLG":   30, // 阴凉柜
+		"LDC":   60, // 冷藏车
+		"LK":    60, // 冷库
+		"BG":    60, // 冰柜
+		"DWBWX": 60, // 低温保存箱
+		"XT":    30, // 系统验证
+		"WZ":    80, // 位置
+		"XJ":    0,  // 巡检
+		"PX":    0,  // 培训
+		"QT":    0,  // 其他
+	}
+
+	TaskReportingTimeLimit = map[string]float64{
+		"BWX":   180, // 保温箱
+		"LDX":   180, // 冷冻箱
+		"LCG":   210, // 冷藏柜
+		"LDG":   210, // 冷冻柜
+		"YLG":   210, // 阴凉柜
+		"LDC":   300, // 冷藏车
+		"LK":    390, // 冷库
+		"BG":    210, // 冰柜
+		"DWBWX": 180, // 低温保存箱
+		"XT":    300, // 系统验证
+		"WZ":    240, // 位置
+		"XJ":    0,   // 巡检
+		"PX":    0,   // 培训
+		"QT":    0,   // 其他
+
+	}
+
+	TaskCollectionTimeLimit float64 = 7 * 24 * 60
+)
+
+type AuditRecord struct {
+	T_uuid       string `orm:"size(256);null"`     // 提交人(客户)UUID
+	T_uuid_name  string `orm:"size(256);null"`     // 提交人名称
+	T_admin      string `orm:"size(256);null"`     // 提交人(报告负责人)UUID
+	T_admin_name string `orm:"size(256);null"`     // 提交人名称
+	T_state      int    `orm:"size(2);default(0)"` // 状态 1 已完成(客户通过) 2已退回(客户) 3已通过(报告负责人) 4已退回(报告负责人) 5已提交
+	T_reason     string `orm:"type(text)"`         // 原因
+	T_time       string `orm:"type(256)"`          // 时间
+	T_type       string `orm:"type(256)"`          // 退回类型 scheme方案 reporting报告
+}
+
+// 模版
+type Task struct {
+	Id                  int    `orm:"column(ID);size(11);auto;pk"`
+	T_Distributor_id    string `orm:"size(256);null"`       // 分销商id
+	T_class             int    `orm:"size(200);default(0)"` // 分类id
+	T_InfoCollection_id string `orm:"size(256);null"`       // 信息采集ID
+	T_InfoTemplate_id   string `orm:"size(256);null"`       // 信息采集模版ID
+
+	T_task_id                string `orm:"size(256);null"`     // 任务ID
+	T_uuid                   string `orm:"size(256);null"`     // 用户 UUID
+	T_name                   string `orm:"size(256);null"`     // 标题
+	T_VerifyTemplate_class   string `orm:"size(256);null"`     // 模版id
+	T_VerifyTemplate_id      string `orm:"size(256);null"`     // 模版id
+	T_deadline               string `orm:"size(256);null"`     // 截止时间
+	T_scheme                 string `orm:"size(256);null"`     // 实施方案 负责人UUID
+	T_collection             string `orm:"size(256);null"`     // 数据采集 负责人UUID
+	T_reporting              string `orm:"size(256);null"`     // 报告编写 负责人UUID
+	T_delivery               string `orm:"size(256);null"`     // 交付审核 负责人UUID
+	T_scheme_state           int    `orm:"size(2);default(0)"` // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state       int    `orm:"size(2);default(0)"` // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4 APP已提交 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state        int    `orm:"size(2);default(0)"` // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交 6已点报告生成
+	T_delivery_state         int    `orm:"size(2);default(0)"` // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state          int    `orm:"size(2);default(0)"` // 验证标识 状态 0 未完成 1 已完成
+	T_examining_report_state int    `orm:"size(2);default(0)"` // 检测报告 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_original_record_state  int    `orm:"size(2);default(0)"` // 原始记录 状态 0 未完成 3 已通过(负责人) 4已退回(负责人) 5已提交
+	T_record                 string `orm:"type(text)"`         // 领导备注
+
+	T_collection_submit_time string `orm:"size(256);null"` // 数据采集 提交时间
+	T_reporting_submit_time  string `orm:"size(256);null"` // 报告编写 提交时间
+
+	T_VerifyDeviceDataStartTime string `orm:"size(256);null"` // 验证设备数据开始时间
+	T_VerifyDeviceDataEndTime   string `orm:"size(256);null"` // 验证设备数据结束时间
+	T_BindDeviceDataStartTime   string `orm:"size(256);null"` // 绑定设备数据开始时间
+	T_BindDeviceDataEndTime     string `orm:"size(256);null"` // 绑定设备数据结束时间
+
+	T_doc1                string `orm:"type(text);null"` // 封面
+	T_pdf1                string `orm:"type(text);null"` // 验证方案
+	T_pdf1_watermark      string `orm:"type(text);null"` // 验证方案 带水印
+	T_pdf1_signature      string `orm:"type(text);null"` // 验证方案 带公章
+	T_pdf1_elec_signature string `orm:"type(text);null"` // 验证方案 带电子签名及公章
+	T_doc2                string `orm:"type(text);null"` // 报告
+	T_pdf2                string `orm:"type(text);null"` // 验证报告
+	T_pdf2_watermark      string `orm:"type(text);null"` // 验证报告 带水印
+	T_pdf2_signature      string `orm:"type(text);null"` // 验证报告 带公章
+	T_pdf2_elec_signature string `orm:"type(text);null"` // 验证报告 带电子签名及公章
+	T_doc3                string `orm:"type(text);null"` // 证书
+	T_pdf3                string `orm:"type(text);null"` // 证书
+	T_pdf4                string `orm:"type(text);null"` // 验证标识
+	T_pdf5                string `orm:"type(text);null"` // 检测报告
+	T_pdf5_watermark      string `orm:"type(text);null"` // 检测报告 带水印
+	T_pdf6                string `orm:"type(text);null"` // 原始记录
+
+	T_Show  int `orm:"size(2);default(1)"`   // 0 隐藏   1 公开
+	T_Visit int `orm:"size(200);default(0)"` // 浏览量
+	T_State int `orm:"size(2);default(1)"`   // 0 删除   1 正常
+
+	T_step int `orm:"size(2);default(-1)"` // 验证步骤
+
+	T_sn                        string `orm:"size(256);null"` // sn
+	T_CalibrationExpirationTime string `orm:"size(256);null"` // 校准到期时间
+
+	T_project        string `orm:"size(256);null"` // 项目 负责人UUID
+	T_province       string `orm:"size(256);null"` // 省
+	T_city           string `orm:"size(256);null"` // 市
+	T_district       string `orm:"size(256);null"` // 区
+	T_province_code  string `orm:"size(256);null"` // 省 code
+	T_city_code      string `orm:"size(256);null"` // 市 code
+	T_district_code  string `orm:"size(256);null"` // 区 code
+	T_category       string `orm:"size(256);null"` // 类别
+	T_device_type    string `orm:"size(256);null"` // 设备类型
+	T_volume         string `orm:"size(256);null"` // 规格/容积
+	T_verify_type    string `orm:"size(256);null"` // 验证类型
+	T_subject_matter string `orm:"size(256);null"` // 标的物名称
+	T_temp_range     string `orm:"size(256);null"` // 验证温度范围
+	T_report_number  string `orm:"size(256);null"` // 报告编号
+	T_report_type    string `orm:"size(256);null"` // 报告类型
+
+	T_start_time    string  `orm:"size(256);null"` // 项目开始时间
+	T_end_time      string  `orm:"size(256);null"` // 结束时间 报告审核通过时间
+	T_time_interval float64 `orm:"size(256);null"` // 时间间隔 单位分钟
+	T_reject_times  int     `orm:"size(256);null"` // 驳回次数 客户退回方案和报告时
+	T_reject_record string  `orm:"type(text)"`     // 驳回记录
+
+	// 方案
+	T_scheme_start_time    string  `orm:"size(256);null"` // 验证方案开始时间 接收信息采集表的时间
+	T_scheme_end_time      string  `orm:"size(256);null"` // 验证方案结束时间 负责人审核通过后最后一次上传时间
+	T_scheme_time_interval float64 `orm:"size(256);null"` // 时间间隔 单位分钟
+	T_scheme_overtime      float64 `orm:"size(256);null"` // 验证方案超时时间 单位分钟
+	T_scheme_signature     string  `orm:"type(text)"`     // 验证方案客户签字确认图片
+	T_scheme_return_times  int     `orm:"size(256);null"` // 验证方案退回次数
+	T_scheme_audit_record  string  `orm:"type(text)"`     // 验证方案审核记录
+
+	// 实施
+	T_enter_area_time          string  `orm:"size(256);null"`  // 进场时间
+	T_collection_start_time    string  `orm:"size(256);null"`  // 实施开始时间(app开始验证时间)
+	T_collection_end_time      string  `orm:"size(256);null"`  // 实施结束时间 (审核通过后签字确认提交时间)
+	T_collection_time_interval float64 `orm:"size(256);null"`  // 时间间隔 单位分钟
+	T_collection_overtime      float64 `orm:"size(256);null"`  // 实施超时时间 单位分钟
+	T_collection_signature     string  `orm:"type(text)"`      // 实施人员签字确认图片
+	T_collection_return_times  int     `orm:"size(256);null"`  // 实施方案退回次数
+	T_collection_audit_record  string  `orm:"type(text);null"` // 实施方案审核记录
+
+	// 报告
+	T_reporting_start_time    string  `orm:"size(256);null"`  // 验证报告开始时间 接收信息采集表的时间
+	T_reporting_end_time      string  `orm:"size(256);null"`  // 验证报告结束时间 负责人审核通过前最后一次上传时间
+	T_reporting_time_interval float64 `orm:"size(256);null"`  // 时间间隔 单位分钟
+	T_reporting_overtime      float64 `orm:"size(256);null"`  // 验证报告超时时间 单位分钟
+	T_reporting_signature     string  `orm:"type(text)"`      // 验证报告客户签字确认图片
+	T_reporting_return_times  int     `orm:"size(256);null"`  // 验证报告退回次数
+	T_reporting_audit_record  string  `orm:"type(text);null"` // 验证报告审核记录
+	T_reporting_pass_time     string  `orm:"size(256);null"`  // 验证报告负责人通过时间
+
+	// 检测报告
+	T_examining_report_start_time    string  `orm:"size(256);null"`  // 检测报告开始时间 接收信息采集表的时间
+	T_examining_report_end_time      string  `orm:"size(256);null"`  // 检测报告结束时间 负责人审核通过前最后一次上传时间
+	T_examining_report_time_interval float64 `orm:"size(256);null"`  // 时间间隔 单位分钟
+	T_examining_report_signature     string  `orm:"type(text)"`      // 检测报告客户签字确认图片
+	T_examining_report_return_times  int     `orm:"size(256);null"`  // 检测报告退回次数
+	T_examining_report_audit_record  string  `orm:"type(text);null"` // 检测报告审核记录
+
+	// 原始记录
+	T_original_record_start_time    string  `orm:"size(256);null"`  // 原始记录开始时间 接收信息采集表的时间
+	T_original_record_end_time      string  `orm:"size(256);null"`  // 原始记录结束时间 负责人审核通过前最后一次上传时间
+	T_original_record_time_interval float64 `orm:"size(256);null"`  // 时间间隔 单位分钟
+	T_original_record_signature     string  `orm:"type(text)"`      // 原始记录客户签字确认图片
+	T_original_record_return_times  int     `orm:"size(256);null"`  // 原始记录退回次数
+	T_original_record_audit_record  string  `orm:"type(text);null"` // 原始记录审核记录
+
+	T_device_quantity int `orm:"size(20);default(0)"`  //  终端数量 T_device_type=WZ 必填
+	T_cnas            int `orm:"size(256);default(0)"` // 0-否 1-是
+
+	T_cover  int    `orm:"size(20);default(0)"` // 是否覆盖询问
+	T_backup string `orm:"size(256);null"`      // 历史数据记录
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type Task_ struct {
+	Id                       int
+	T_Distributor_id         string // 信息采集ID
+	T_class                  int    // 分类ID
+	T_InfoCollection_id      string // 信息采集ID
+	T_task_id                string // 任务ID
+	T_uuid                   string // 用户 UUID
+	T_user_name              string // 用户 UUID
+	T_name                   string // 标题
+	T_VerifyTemplate_class   string // 任务模版id
+	T_VerifyTemplate_id      string // 任务模版id
+	T_deadline               string // 截止时间
+	T_scheme                 string // 实施方案 负责人UUID
+	T_collection             string // 数据采集 负责人UUID
+	T_reporting              string // 报告编写 负责人UUID
+	T_delivery               string // 交付审核 负责人UUID
+	T_scheme_state           int    // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state       int    // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state        int    // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_delivery_state         int    // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state          int    // 验证标识 状态 0 未完成 1 已完成
+	T_examining_report_state int    // 检测报告 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_original_record_state  int    // 原始记录 状态 0 未完成 3 已通过(负责人) 4已退回(负责人) 5已提交
+
+	T_scheme_state_str           string // 实施方案 状态 字符串
+	T_collection_state_str       string // 数据采集 状态 字符串
+	T_reporting_state_str        string // 报告编写 状态 字符串
+	T_delivery_state_str         string // 交付审核 状态 字符串
+	T_marking_state_str          string // 验证标识 状态 字符串
+	T_examining_report_state_str string // 检测报告 状态 字符串
+	T_original_record_state_str  string // 原始记录 状态 字符串
+	T_scheme_name                string // 实施方案 负责人姓名
+	T_collection_name            string // 数据采集 负责人姓名
+	T_reporting_name             string // 报告编写 负责人姓名
+	T_delivery_name              string // 交付审核 负责人姓名
+	T_VerifyDeviceDataStartTime  string
+	T_VerifyDeviceDataEndTime    string
+	T_VerifyDeviceDataTime       [2]string // 验证设备数据开始-结束时间
+	T_BindDeviceDataTime         [2]string // 绑定设备数据开始-结束时间
+	T_doc1                       string    // 封面
+	T_pdf1                       string    // 验证方案
+	T_pdf1_signature             string    // 验证方案 带公章
+	T_doc2                       string    // 报告
+	T_pdf2                       string    // 报告
+	T_pdf2_signature             string    // 报告 带公章
+	T_doc3                       string    // 证书
+	T_pdf3                       string    // 证书
+	T_pdf4                       string    // 验证标识
+	T_pdf5                       string    // 检测报告
+
+	T_Show                      int    // 0 公开 1 隐藏
+	T_Visit                     int    // 浏览量
+	T_State                     int    // 0 删除 1 正常
+	T_sn                        string // sn
+	T_CalibrationExpirationTime string // 校准到期时间
+
+	T_project       string                        // 项目 负责人UUID
+	T_project_name  string                        // 项目 负责人姓名
+	T_province      string                        // 省
+	T_city          string                        // 市
+	T_district      string                        // 区
+	T_area          []string                      // 省市区
+	T_province_code string                        // 省 code
+	T_city_code     string                        // 市 code
+	T_district_code string                        // 区 code
+	T_area_code     []string                      // 省市区
+	InfoCollection  InfoCollection.InfoCollection //信息采集
+	T_record        string                        //
+
+	T_device_type         string
+	T_verify_type         string
+	T_reporting_pass_time string
+
+	T_device_quantity int
+	T_cnas            int // cnas实验室
+
+	T_cover  int    // 是否覆盖询问
+	T_backup string // 历史数据记录
+
+}
+
+type Task_Stat struct {
+	Id                  int
+	T_Distributor_id    string // 信息采集ID
+	T_class             int    // 分类ID
+	T_InfoCollection_id string // 信息采集ID
+	T_InfoTemplate_id   string // 信息采集模版ID
+
+	T_task_id                    string // 任务ID
+	T_uuid                       string // 用户 UUID
+	T_user_name                  string // 用户 UUID
+	T_name                       string // 标题
+	T_VerifyTemplate_class       string // 任务模版id
+	T_VerifyTemplate_id          string // 任务模版id
+	T_deadline                   string // 截止时间
+	T_scheme                     string // 实施方案 负责人UUID
+	T_collection                 string // 数据采集 负责人UUID
+	T_reporting                  string // 报告编写 负责人UUID
+	T_delivery                   string // 交付审核 负责人UUID
+	T_scheme_state               int    // 实施方案 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_collection_state           int    // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成(已提交) 5已通过(负责人) 6已退回(负责人)
+	T_reporting_state            int    // 报告编写 状态 0 未完成 1 已完成(客户通过) 2已退回(客户) 3已通过(负责人) 4已退回(负责人) 5已提交
+	T_delivery_state             int    // 交付审核 状态 0 未完成 1 已完成 2 处理中
+	T_marking_state              int    // 验证标识 状态 0 未完成 1 已完成
+	T_scheme_state_str           string // 实施方案 状态 字符串
+	T_collection_state_str       string // 数据采集 状态 字符串
+	T_reporting_state_str        string // 报告编写 状态 字符串
+	T_delivery_state_str         string // 交付审核 状态 字符串
+	T_marking_state_str          string // 验证标识 状态 字符串
+	T_examining_report_state_str string // 检测报告 状态 字符串
+	T_original_record_state_str  string // 原始记录 状态 字符串
+	T_scheme_name                string // 实施方案 负责人姓名
+	T_collection_name            string // 数据采集 负责人姓名
+	T_reporting_name             string // 报告编写 负责人姓名
+	T_delivery_name              string // 交付审核 负责人姓名
+
+	T_VerifyDeviceDataTime [2]string // 验证设备数据开始-结束时间
+	T_BindDeviceDataTime   [2]string // 绑定设备数据开始-结束时间
+
+	T_doc1 string // 封面
+	T_pdf1 string // 验证方案
+	T_doc2 string // 报告
+	T_pdf2 string // 报告
+	T_doc3 string // 证书
+	T_pdf3 string // 证书
+	T_pdf4 string // 验证标识
+
+	T_Show                      int    // 0 公开 1 隐藏
+	T_Visit                     int    // 浏览量
+	T_State                     int    // 0 删除 1 正常
+	T_sn                        string // sn
+	T_CalibrationExpirationTime string // 校准到期时间
+
+	T_project        string   // 项目 负责人UUID
+	T_project_name   string   // 项目 负责人姓名
+	T_province       string   // 省
+	T_city           string   // 市
+	T_district       string   // 区
+	T_area           []string // 省市区
+	T_province_code  string   // 省 code
+	T_city_code      string   // 市 code
+	T_district_code  string   // 区 code
+	T_area_code      []string // 省市区
+	T_category       string   // 类别
+	T_device_type    string   // 设备类型
+	T_volume         string   // 规格/容积
+	T_verify_type    string   // 验证类型
+	T_subject_matter string   // 标的物名称
+	T_temp_range     string   // 验证温度范围
+	T_report_number  string   // 报告编号
+	T_report_type    string   // 报告类型
+	T_start_time     string   // 项目开始时间
+	T_end_time       string   // 结束时间 报告审核通过时间
+	T_time_interval  string   // 时间间隔 单位分钟
+	T_reject_times   int      // 驳回次数 客户退回方案和报告时
+	T_reject_record  string   // 驳回记录
+	// 方案
+	T_scheme_start_time    string // 验证方案开始时间 接收信息采集表的时间
+	T_scheme_end_time      string // 验证方案结束时间
+	T_scheme_time_interval string // 时间间隔 单位分钟
+	T_scheme_overtime      string // 验证方案超时时间 单位分钟
+	T_scheme_signature     string // 验证方案客户签字确认图片
+	T_scheme_return_times  int    // 验证方案退回次数
+	T_scheme_audit_record  string // 验证方案审核记录
+	// 实施
+	T_enter_area_time          string // 进场时间
+	T_collection_start_time    string // 实施开始时间(app开始验证时间)
+	T_collection_end_time      string // 实施结束时间 (签字确认提交时间)
+	T_collection_time_interval string // 时间间隔 单位分钟
+	T_collection_overtime      string // 实施超时时间 单位分钟
+	T_collection_signature     string // 实施人员签字确认图片
+	T_collection_return_times  int    // 实施方案退回次数
+	T_collection_audit_record  string // 实施方案审核记录
+	// 报告
+	T_reporting_start_time    string                          // 验证报告开始时间 接收信息采集表的时间
+	T_reporting_end_time      string                          // 验证报告结束时间
+	T_reporting_time_interval string                          // 时间间隔 单位分钟
+	T_reporting_overtime      string                          // 验证报告超时时间 单位分钟
+	T_reporting_signature     string                          // 验证报告客户签字确认图片
+	T_reporting_return_times  int                             // 验证报告退回次数
+	T_reporting_audit_record  string                          // 验证报告审核记录
+	InfoCollection            InfoCollection.InfoCollection_R //信息菜鸡
+
+	T_record string //
+
+	T_device_quantity int
+	T_cnas            int // cnas实验室
+
+	T_cover  int    // 是否覆盖询问
+	T_backup string // 历史数据记录
+
+}
+
+func (t *Task) TableName() string {
+	return "task" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_Task cache.Cache
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(Task))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"Task", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_Task, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_Task == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+	}
+}
+
+// -------------------------------------------------------------
+
+// selectPdf 根据条件选择PDF文件
+// 返回选中的PDF和signature PDF
+func selectPdf(watermark, original, signature, elecSignature string, isReturnedMoney bool, hasInfoCollection bool) (selectedPdf, selectedSignature string) {
+	// 默认使用watermark版本
+	selectedPdf = watermark
+
+	// 如果满足以下任一条件,使用原始版本:退款状态、无InfoCollection、watermark为空
+	if isReturnedMoney || !hasInfoCollection || len(watermark) == 0 {
+		selectedPdf = original
+
+		// 如果是退款状态,优先选择签名版本(电子签名优先于普通签名)
+		if isReturnedMoney {
+			if len(elecSignature) > 0 {
+				selectedPdf = elecSignature
+			} else if len(signature) > 0 {
+				selectedPdf = signature
+			}
+		}
+	}
+
+	// 设置signature,如果为空则使用原始版本
+	selectedSignature = signature
+	if len(selectedSignature) == 0 {
+		selectedSignature = original
+	}
+
+	return selectedPdf, selectedSignature
+}
+
+func TaskToTask_(T Task, userMap, adminMap map[string]string) (T_ Task_) {
+	T_.Id = T.Id
+	T_.T_Distributor_id = T.T_Distributor_id
+	T_.T_class = T.T_class
+	T_.T_InfoCollection_id = T.T_InfoCollection_id
+	if len(T.T_InfoCollection_id) > 0 {
+		T_.InfoCollection, _ = InfoCollection.Read_InfoCollection(T.T_InfoCollection_id)
+	}
+
+	T_.T_task_id = T.T_task_id
+	T_.T_uuid = T.T_uuid
+	T_.T_user_name = userMap[T.T_uuid]
+	T_.T_name = T.T_name
+	T_.T_VerifyTemplate_class = T.T_VerifyTemplate_class
+	T_.T_VerifyTemplate_id = T.T_VerifyTemplate_id
+	T_.T_deadline = T.T_deadline
+	T_.T_scheme = T.T_scheme
+	T_.T_collection = T.T_collection
+	T_.T_reporting = T.T_reporting
+	T_.T_delivery = T.T_delivery
+	T_.T_project = T.T_project
+	T_.T_scheme_state = T.T_scheme_state
+	T_.T_collection_state = T.T_collection_state
+	T_.T_reporting_state = T.T_reporting_state
+	T_.T_delivery_state = T.T_delivery_state
+	T_.T_marking_state = T.T_marking_state
+	T_.T_scheme_state_str = TaskSchemeStateMap[T.T_scheme_state]
+	T_.T_collection_state_str = TaskCollectionStateMap[T.T_collection_state]
+	T_.T_reporting_state_str = TaskReportingStateMap[T.T_reporting_state]
+	T_.T_delivery_state_str = TaskDeliveryStateMap[T.T_delivery_state]
+	T_.T_marking_state_str = TaskMarkingStateMap[T.T_marking_state]
+	T_.T_examining_report_state_str = TaskExaminingReportStateMap[T.T_examining_report_state]
+	T_.T_original_record_state_str = TaskOriginalRecordStateMap[T.T_original_record_state]
+	T_.T_scheme_name = adminMap[T.T_scheme]
+	T_.T_collection_name = adminMap[T.T_collection]
+	T_.T_reporting_name = adminMap[T.T_reporting]
+	T_.T_delivery_name = adminMap[T.T_delivery]
+	T_.T_project_name = adminMap[T.T_project]
+	T_.T_VerifyDeviceDataStartTime = T.T_VerifyDeviceDataStartTime
+	T_.T_VerifyDeviceDataEndTime = T.T_VerifyDeviceDataEndTime
+	T_.T_VerifyDeviceDataTime = [2]string{T.T_VerifyDeviceDataStartTime, T.T_VerifyDeviceDataEndTime}
+	T_.T_BindDeviceDataTime = [2]string{T.T_BindDeviceDataStartTime, T.T_BindDeviceDataEndTime}
+	T_.T_doc1 = T.T_doc1
+	T_.T_doc2 = T.T_doc2
+	T_.T_doc3 = T.T_doc3
+
+	// 处理PDF1和PDF2的选择逻辑
+	isReturnedMoney := T_.InfoCollection.T_status == InfoCollection.InfoCollectionStatusReturnedMoney
+	hasInfoCollection := len(T.T_InfoCollection_id) > 0
+
+	T_.T_pdf1, T_.T_pdf1_signature = selectPdf(
+		T.T_pdf1_watermark,
+		T.T_pdf1,
+		T.T_pdf1_signature,
+		T.T_pdf1_elec_signature,
+		isReturnedMoney,
+		hasInfoCollection,
+	)
+
+	T_.T_pdf2, T_.T_pdf2_signature = selectPdf(
+		T.T_pdf2_watermark,
+		T.T_pdf2,
+		T.T_pdf2_signature,
+		T.T_pdf2_elec_signature,
+		isReturnedMoney,
+		hasInfoCollection,
+	)
+	T_.T_pdf3 = T.T_pdf3
+	T_.T_pdf4 = T.T_pdf4
+	T_.T_pdf5 = T.T_pdf5_watermark
+	if T_.InfoCollection.T_status == InfoCollection.InfoCollectionStatusReturnedMoney || len(T.T_InfoCollection_id) == 0 || len(T.T_pdf2_watermark) == 0 {
+	}
+	T_.T_Show = T.T_Show
+	T_.T_Visit = T.T_Visit
+	T_.T_State = T.T_State
+
+	T_.T_sn = T.T_sn
+	T_.T_CalibrationExpirationTime = T.T_CalibrationExpirationTime
+	T_.T_record = T.T_record
+
+	T_.T_device_type = T.T_device_type
+	T_.T_verify_type = T.T_verify_type
+	T_.T_reporting_pass_time = T.T_reporting_pass_time
+	T_.T_device_quantity = T.T_device_quantity
+	T_.T_cnas = T.T_cnas
+
+	T_.T_cover = T.T_cover
+	T_.T_backup = T.T_backup
+
+	return T_
+}
+func TaskToTask_Stat(T Task, userMap, adminMap map[string]string) (T_ Task_Stat) {
+	T_.Id = T.Id
+	T_.T_Distributor_id = T.T_Distributor_id
+	T_.T_class = T.T_class
+	T_.T_InfoCollection_id = T.T_InfoCollection_id
+	if len(T.T_InfoCollection_id) > 0 {
+		infoCollection, _ := InfoCollection.Read_InfoCollection(T.T_InfoCollection_id)
+		T_.InfoCollection = InfoCollection.InfoCollectionToInfoCollection_R(infoCollection, userMap, adminMap, map[string]string{}, map[string]string{})
+	}
+
+	T_.T_task_id = T.T_task_id
+	T_.T_uuid = T.T_uuid
+	T_.T_user_name = userMap[T.T_uuid]
+	T_.T_name = T.T_name
+	T_.T_VerifyTemplate_class = T.T_VerifyTemplate_class
+	T_.T_VerifyTemplate_id = T.T_VerifyTemplate_id
+	T_.T_deadline = T.T_deadline
+	T_.T_scheme = T.T_scheme
+	T_.T_collection = T.T_collection
+	T_.T_reporting = T.T_reporting
+	T_.T_delivery = T.T_delivery
+	T_.T_scheme_state = T.T_scheme_state
+	T_.T_collection_state = T.T_collection_state
+	T_.T_reporting_state = T.T_reporting_state
+	T_.T_delivery_state = T.T_delivery_state
+	T_.T_marking_state = T.T_marking_state
+	T_.T_scheme_state_str = TaskSchemeStateMap[T.T_scheme_state]
+	T_.T_collection_state_str = TaskCollectionStateMap[T.T_collection_state]
+	T_.T_reporting_state_str = TaskReportingStateMap[T.T_reporting_state]
+	T_.T_delivery_state_str = TaskDeliveryStateMap[T.T_delivery_state]
+	T_.T_marking_state_str = TaskMarkingStateMap[T.T_marking_state]
+	T_.T_examining_report_state_str = TaskExaminingReportStateMap[T.T_examining_report_state]
+	T_.T_original_record_state_str = TaskOriginalRecordStateMap[T.T_original_record_state]
+
+	T_.T_project_name = adminMap[T.T_project]
+	T_.T_scheme_name = adminMap[T.T_scheme]
+	T_.T_collection_name = adminMap[T.T_collection]
+	T_.T_reporting_name = adminMap[T.T_reporting]
+	T_.T_delivery_name = adminMap[T.T_delivery]
+	T_.T_VerifyDeviceDataTime = [2]string{T.T_VerifyDeviceDataStartTime, T.T_VerifyDeviceDataEndTime}
+	T_.T_BindDeviceDataTime = [2]string{T.T_BindDeviceDataStartTime, T.T_BindDeviceDataEndTime}
+	T_.T_doc1 = T.T_doc1
+	T_.T_doc2 = T.T_doc2
+	T_.T_doc3 = T.T_doc3
+
+	T_.T_pdf1 = T.T_pdf1_watermark
+	if T_.InfoCollection.T_status == InfoCollection.InfoCollectionStatusReturnedMoney || len(T.T_InfoCollection_id) == 0 || len(T.T_pdf1_watermark) == 0 {
+		T_.T_pdf1 = T.T_pdf1
+	}
+	T_.T_pdf2 = T.T_pdf2_watermark
+	if T_.InfoCollection.T_status == InfoCollection.InfoCollectionStatusReturnedMoney || len(T.T_InfoCollection_id) == 0 || len(T.T_pdf2_watermark) == 0 {
+		T_.T_pdf2 = T.T_pdf2
+	}
+	T_.T_pdf3 = T.T_pdf3
+	T_.T_pdf4 = T.T_pdf4
+	T_.T_Show = T.T_Show
+	T_.T_Visit = T.T_Visit
+	T_.T_State = T.T_State
+
+	T_.T_sn = T.T_sn
+	T_.T_CalibrationExpirationTime = T.T_CalibrationExpirationTime
+
+	T_.T_project = T.T_project
+	T_.T_province = T.T_province
+	T_.T_city = T.T_city
+	T_.T_district = T.T_district
+	T_.T_area = []string{T.T_province, T.T_city, T.T_district}
+	T_.T_province_code = T.T_province_code
+	T_.T_city_code = T.T_city_code
+	T_.T_district_code = T.T_district_code
+	T_.T_area_code = []string{T.T_province_code, T.T_city_code, T.T_district_code}
+	T_.T_category = T.T_category
+	T_.T_device_type = T.T_device_type
+	T_.T_volume = T.T_volume
+	T_.T_verify_type = T.T_verify_type
+	T_.T_subject_matter = T.T_subject_matter
+	T_.T_temp_range = T.T_temp_range
+	T_.T_report_number = T.T_report_number
+	T_.T_report_type = T.T_report_type
+	T_.T_start_time = T.T_start_time
+	T_.T_end_time = T.T_end_time
+	T_.T_time_interval = lib.ConvertMinutesToDHM(int(T.T_time_interval))
+	T_.T_reject_times = T.T_reject_times
+	T_.T_reject_record = T.T_reject_record
+
+	// 方案
+	T_.T_scheme_start_time = T.T_scheme_start_time
+	T_.T_scheme_end_time = T.T_scheme_end_time
+
+	if T.T_scheme_state == TaskSchemeStateSubmitted ||
+		T.T_scheme_state == TaskSchemeStateClientPass ||
+		T.T_scheme_state == TaskSchemeStatePass {
+		T_.T_scheme_time_interval = lib.ConvertMinutesToDHM(int(T.T_scheme_time_interval))
+		T_.T_scheme_overtime = lib.ConvertMinutesToDHM(int(T.T_scheme_overtime))
+	}
+
+	T_.T_scheme_signature = T.T_scheme_signature
+	T_.T_scheme_return_times = T.T_scheme_return_times
+	T_.T_scheme_audit_record = T.T_scheme_audit_record
+
+	// 实施
+	T_.T_enter_area_time = T.T_enter_area_time
+	T_.T_collection_start_time = T.T_collection_start_time
+	T_.T_collection_end_time = T.T_collection_end_time
+	if T.T_collection_state == TaskCollectionStatePass ||
+		T.T_collection_state == TaskCollectionStateSubmitted {
+		T_.T_collection_time_interval = lib.ConvertMinutesToDHM(int(T.T_collection_time_interval))
+		T_.T_collection_overtime = lib.ConvertMinutesToDHM(int(T.T_collection_overtime))
+	}
+	T_.T_collection_signature = T.T_collection_signature
+	T_.T_collection_return_times = T.T_collection_return_times
+	T_.T_collection_audit_record = T.T_collection_audit_record
+
+	// 报告
+	T_.T_reporting_start_time = T.T_reporting_start_time
+	T_.T_reporting_end_time = T.T_reporting_end_time
+
+	if T.T_reporting_state == TaskReportingStateClientPass ||
+		T.T_reporting_state == TaskReportingStateSubmitted ||
+		T.T_reporting_state == TaskReportingStateClientReturn ||
+		T.T_reporting_state == TaskReportingStatePass {
+		T_.T_reporting_time_interval = lib.ConvertMinutesToDHM(int(T.T_reporting_time_interval))
+		T_.T_reporting_overtime = lib.ConvertMinutesToDHM(int(T.T_reporting_overtime))
+	}
+
+	T_.T_reporting_signature = T.T_reporting_signature
+	T_.T_reporting_return_times = T.T_reporting_return_times
+	T_.T_reporting_audit_record = T.T_reporting_audit_record
+	T_.T_record = T.T_record
+	T_.T_device_quantity = T.T_device_quantity
+	T_.T_cnas = T.T_cnas
+
+	T_.T_cover = T.T_cover
+	T_.T_backup = T.T_backup
+
+	return T_
+}
+
+// ---------------- Redis -------------------
+
+func Redis_Task_Set(key string, r Task) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_Task.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+func Redis_Task_Get(key string) (r Task, is bool) {
+	if redisCache_Task.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_Task.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return Task{}, false
+}
+func Redis_Task_DelK(key string) (err error) {
+	err = redisCache_Task.Delete(key)
+	return
+}
+
+func Redis_Task_T_report_number_Set(key string) (err error) {
+	err = redisCache_Task.Put(key, "", 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key)
+	}
+	return
+}
+func Redis_Task_T_report_number_Get(key string) (is bool) {
+	if redisCache_Task.IsExist(key) {
+		return true
+	}
+	logs.Println("没有 找到key:", key)
+	return false
+}
+func Redis_Task_T_report_number_DelK(key string) (err error) {
+	err = redisCache_Task.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_Task_ById(id int) (r Task, is bool) {
+	o := orm.NewOrm()
+	r = Task{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_Task(T_task_id string) (r Task, is bool) {
+	if r, is = Redis_Task_Get(T_task_id); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Task))
+	//err := qs.Filter("T_task_id", T_task_id).Filter("T_State", 1).One(&r)
+	err := qs.Filter("T_task_id", T_task_id).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	Redis_Task_Set(T_task_id, r)
+	return r, true
+}
+
+// 添加
+func Add_Task(r Task) (string, bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_task_id = lib.GetRandstring(12, "abcdefghijklmnopqrstuvwxyz0123456789", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_task_id")                                                             // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+	if !CREATE_TaskData(r.T_task_id) {
+		return "", false
+	}
+	Redis_Task_Set(r.T_task_id, r)
+	return r.T_task_id, true
+}
+func Add_Task_Tool(r Task) (string, bool) {
+	o := orm.NewOrm()
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+	return r.T_task_id, true
+}
+
+// 删除
+func Delete_Task(v Task) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_Task_DelK(v.T_task_id)
+	return true
+}
+
+// 删除
+func Delete_Task_(v Task) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	Redis_Task_DelK(v.T_task_id)
+	return true
+}
+
+// 修改
+func Update_Task(m Task, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_Task_Set(m.T_task_id, m)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 添加浏览量
+func Add_Task_Visit(m Task) bool {
+	o := orm.NewOrm()
+	m.T_Visit += 1
+	if num, err := o.Update(&m, "T_Visit"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_Task_Set(m.T_task_id, m)
+		return true
+	} else {
+		logs.Error(lib.FuncName(), err)
+	}
+	return false
+}
+
+// 获取用户任务列表
+func Read_Task_List_All() ([]Task, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	//cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1)
+	cond1 := cond.And("T_State", 1)
+
+	qs.Limit(10, 0).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	return r, int(cnt)
+}
+
+// 获取用户任务列表
+func Read_UserTask_List(T_uuid string, T_name string, userMap, adminMap map[string]string, page int, page_z int) ([]Task_, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_name__icontains", T_name).And("T_Show", 1).And("T_State", 1)
+	if len(T_uuid) > 0 {
+		cond1 = cond1.And("T_uuid", T_uuid)
+	}
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskList []Task_
+	for _, v := range r {
+		TaskList = append(TaskList, TaskToTask_(v, userMap, adminMap))
+	}
+
+	return TaskList, int(cnt)
+}
+
+// 获取任务列表
+func Read_Task_List(T_Distributor_id, T_uuid, T_admin, T_name, T_InfoCollection_id string, T_scheme, T_collection, T_reporting, T_delivery,
+	T_scheme_state, T_collection_state, T_reporting_state, T_delivery_state, T_marking_state string,
+	T_company_list []string, userMap, adminMap map[string]string, CreateTime string, page int, page_z int) ([]Task_, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.AndCond(cond.Or("T_name__icontains", T_name).Or("T_task_id__icontains", T_name)).And("T_State", 1)
+	if len(T_uuid) > 0 {
+		cond1 = cond1.And("T_uuid", T_uuid)
+	}
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+	if len(T_InfoCollection_id) > 0 {
+		cond1 = cond1.And("T_InfoCollection_id", T_InfoCollection_id)
+	}
+	if len(T_admin) > 0 {
+		cond1 = cond1.AndCond(cond.Or("T_scheme", T_admin).Or("T_collection", T_admin).
+			Or("T_reporting", T_admin).Or("T_delivery", T_admin))
+	}
+	if len(T_company_list) > 0 {
+		cond1 = cond1.And("T_uuid__in", T_company_list)
+	}
+
+	if len(T_scheme) > 0 {
+		cond1 = cond1.And("T_scheme", T_scheme)
+	}
+	if len(T_collection) > 0 {
+		cond1 = cond1.And("T_collection", T_collection)
+	}
+	if len(T_reporting) > 0 {
+		cond1 = cond1.And("T_reporting", T_reporting)
+	}
+	if len(T_delivery) > 0 {
+		cond1 = cond1.And("T_delivery", T_delivery)
+	}
+
+	if len(T_scheme_state) > 0 {
+		cond1 = cond1.And("T_scheme_state", T_scheme_state)
+	}
+	if len(T_collection_state) > 0 {
+		cond1 = cond1.And("T_collection_state", T_collection_state)
+	}
+	if len(T_reporting_state) > 0 {
+		cond1 = cond1.And("T_reporting_state", T_reporting_state)
+	}
+	if len(T_delivery_state) > 0 {
+		cond1 = cond1.And("T_delivery_state", T_delivery_state)
+	}
+	if len(T_marking_state) > 0 {
+		cond1 = cond1.And("T_marking_state", T_marking_state)
+	}
+	if len(CreateTime) > 0 {
+		CreateTime_s := strings.Split(CreateTime, "-")
+
+		if len(CreateTime_s) == 2 {
+			// 定义开始和结束时间
+			start := time.Date(lib.To_int(CreateTime_s[0]), time.Month(lib.To_int(CreateTime_s[1])), 1, 0, 0, 0, 0, time.UTC)
+			end := start.AddDate(0, 1, 0) // 下个月的第一天
+			logs.Println("CreateTime_s:", start.Format("2006-01-02 15:04:05"), end.Format("2006-01-02 15:04:05"))
+			cond1 = cond1.And("CreateTime__gte", start).And("CreateTime__lt", end)
+		}
+
+	}
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskList []Task_
+	for _, v := range r {
+		TaskList = append(TaskList, TaskToTask_(v, userMap, adminMap))
+	}
+
+	return TaskList, int(cnt)
+}
+func Read_Task_BySN(sn string) (r Task, err error) {
+	if task, is := Redis_Task_Get(sn); is == true {
+		return task, nil
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Task))
+	err = qs.Filter("T_sn", sn).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, err
+	}
+
+	Redis_Task_Set(sn, r)
+	return r, nil
+}
+
+// 修改
+func Update_Task_T_InfoTemplate_id(T_InfoCollection_id, T_InfoTemplate_id string) error {
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+	o.Begin()
+	qs.Filter("T_InfoCollection_id", T_InfoCollection_id).All(&r)
+	for _, task := range r {
+		task.T_InfoTemplate_id = T_InfoTemplate_id
+		if _, err := o.Update(&task, "T_InfoTemplate_id"); err == nil {
+			Redis_Task_Set(task.T_task_id, task)
+		} else {
+			o.Rollback()
+			logs.Error(lib.FuncName(), err)
+			return err
+		}
+	}
+	o.Commit()
+	return nil
+
+}
+
+func Add_AuditRecord(T_audit_record string, T_uuid, T_admin string, T_scheme_state int, T_reason string, T_type string) (string, error) {
+
+	auditRecord := AuditRecord{
+		T_uuid:   T_uuid,
+		T_admin:  T_admin,
+		T_state:  T_scheme_state,
+		T_reason: T_reason,
+		T_type:   T_type,
+		T_time:   time.Now().Format("2006-01-02 15:04:05"),
+	}
+
+	var returnRecordList []AuditRecord
+	if len(T_audit_record) > 0 {
+		err := json.Unmarshal([]byte(T_audit_record), &returnRecordList)
+		if err != nil {
+			logs.Error("JSON 反序列化失败:", err)
+			return "", errors.New("JSON 反序列化失败")
+		}
+	}
+
+	returnRecordList = append(returnRecordList, auditRecord)
+	returnRecordJson, err := json.Marshal(returnRecordList)
+	if err != nil {
+		logs.Error("JSON 反序列化失败:", err)
+		return "", errors.New("JSON 反序列化失败")
+	}
+	return string(returnRecordJson), nil
+}
+
+// 获取项目负责人列表
+func Get_Task_UserList(T_type string) []string {
+	o := orm.NewOrm()
+	var err error
+	var pl_lists []string
+	switch T_type {
+	case "T_project":
+		_, err = o.Raw("SELECT DISTINCT t_project FROM task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_scheme":
+		_, err = o.Raw("SELECT DISTINCT t_scheme FROM task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_collection":
+		_, err = o.Raw("SELECT DISTINCT t_collection FROM task LIMIT 0,1000").QueryRows(&pl_lists)
+	case "T_reporting":
+		_, err = o.Raw("SELECT DISTINCT t_reporting FROM task LIMIT 0,1000").QueryRows(&pl_lists)
+
+	}
+	if err != nil {
+		logs.Error("获取项目负责人列表失败:", err)
+	}
+	return pl_lists
+}
+
+func Read_Task_Stat(T_Distributor_id, T_uuid, T_admin, T_name, T_InfoCollection_id string, T_project, T_scheme, T_collection, T_reporting, T_delivery,
+	T_scheme_state, T_collection_state, T_reporting_state, T_delivery_state, T_marking_state string,
+	T_company_list []string, userMap, adminMap map[string]string, CreateTime string, page int, page_z int) ([]Task_Stat, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.AndCond(cond.Or("T_name__icontains", T_name).Or("T_task_id__icontains", T_name)).And("T_State", 1)
+	if len(T_uuid) > 0 {
+		cond1 = cond1.And("T_uuid", T_uuid)
+	}
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+	if len(T_InfoCollection_id) > 0 {
+		cond1 = cond1.And("T_InfoCollection_id", T_InfoCollection_id)
+	}
+	if len(T_admin) > 0 {
+		cond1 = cond1.AndCond(cond.Or("T_scheme", T_admin).Or("T_collection", T_admin).
+			Or("T_reporting", T_admin).Or("T_delivery", T_admin))
+	}
+	if len(T_company_list) > 0 {
+		cond1 = cond1.And("T_uuid__in", T_company_list)
+	}
+
+	if len(T_project) > 0 {
+		cond1 = cond1.And("T_project", T_project)
+	}
+	if len(T_scheme) > 0 {
+		cond1 = cond1.And("T_scheme", T_scheme)
+	}
+	if len(T_collection) > 0 {
+		cond1 = cond1.And("T_collection", T_collection)
+	}
+	if len(T_reporting) > 0 {
+		cond1 = cond1.And("T_reporting", T_reporting)
+	}
+	if len(T_delivery) > 0 {
+		cond1 = cond1.And("T_delivery", T_delivery)
+	}
+
+	if len(T_scheme_state) > 0 {
+		cond1 = cond1.And("T_scheme_state", T_scheme_state)
+	}
+	if len(T_collection_state) > 0 {
+		cond1 = cond1.And("T_collection_state", T_collection_state)
+	}
+	if len(T_reporting_state) > 0 {
+		cond1 = cond1.And("T_reporting_state", T_reporting_state)
+	}
+	if len(T_delivery_state) > 0 {
+		cond1 = cond1.And("T_delivery_state", T_delivery_state)
+	}
+	if len(T_marking_state) > 0 {
+		cond1 = cond1.And("T_marking_state", T_marking_state)
+	}
+	if len(CreateTime) > 0 {
+		CreateTime_s := strings.Split(CreateTime, "-")
+
+		if len(CreateTime_s) == 2 {
+			// 定义开始和结束时间
+			start := time.Date(lib.To_int(CreateTime_s[0]), time.Month(lib.To_int(CreateTime_s[1])), 1, 0, 0, 0, 0, time.UTC)
+			end := start.AddDate(0, 1, 0) // 下个月的第一天
+			logs.Println("CreateTime_s:", start.Format("2006-01-02 15:04:05"), end.Format("2006-01-02 15:04:05"))
+			cond1 = cond1.And("CreateTime__gte", start).And("CreateTime__lt", end)
+		}
+
+	}
+	if page_z == 9999 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	} else {
+		qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskList []Task_Stat
+	for _, v := range r {
+		TaskList = append(TaskList, TaskToTask_Stat(v, userMap, adminMap))
+	}
+
+	return TaskList, int(cnt)
+}
+
+// 获取用户任务列表
+func Read_UserTask_StatisticalRanking(T_uuid, T_scheme string) []Task {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	//cond_T_uuid := orm.NewCondition().Or("T_scheme", T_uuid).Or("T_collection", T_uuid).Or("T_reporting", T_uuid)
+	//cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1)
+	cond1 := cond.And("T_State", 1).And(T_scheme, T_uuid)
+
+	qs.Limit(500, 0).SetCond((*orm2.Condition)(cond1)).OrderBy("-UpdateTime").All(&r)
+	qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	return r
+}
+
+// 获取任务列表
+func Read_Task_List_For_ERP(start_time, end_time string) ([]Task_, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).And("T_reporting_state", TaskReportingStatePass)
+	if len(start_time) > 0 {
+		cond1 = cond1.And("T_reporting_pass_time__gte", start_time)
+	}
+	if len(end_time) > 0 {
+		cond1 = cond1.And("T_reporting_pass_time__lte", end_time)
+	}
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskList []Task_
+	for _, v := range r {
+		TaskList = append(TaskList, TaskToTask_(v, map[string]string{}, map[string]string{}))
+	}
+
+	return TaskList, int(cnt)
+}
+
+// 获取任务列表
+func Read_Task_List_For_ERP_By_Type(T_type string, start_time, end_time string) ([]Task_, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+
+	if T_type == "collection" {
+		cond1 = cond1.And("T_collection_submit_time__gte", start_time).And("T_collection_submit_time__lte", end_time)
+	}
+	if T_type == "reporting" {
+		cond1 = cond1.And("T_reporting_submit_time__gte", start_time).And("T_reporting_submit_time__lte", end_time)
+	}
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskList []Task_
+	for _, v := range r {
+		TaskList = append(TaskList, TaskToTask_(v, map[string]string{}, map[string]string{}))
+	}
+
+	return TaskList, int(cnt)
+}
+
+// GenerateNextT_report_number 生成下一个编号
+func GenerateNextT_report_number(T_device_type string) (string, error) {
+	o := orm.NewOrm()
+
+	// 获取当前年份和季度
+	currentYear := time.Now().Year()
+	currentQuarter := int(time.Now().Month()-1)/3 + 1 // 1,2,3,4 对应 A,B,C,D
+	quarterChar := string(rune('A' + currentQuarter - 1))
+	yearQuarter := fmt.Sprintf("%s%d%s", T_device_type, currentYear, quarterChar)
+	var lastRecord Task
+	err := o.QueryTable(new(Task)).
+		Filter("T_report_number__startswith", yearQuarter).
+		OrderBy("-T_report_number").
+		Limit(1).
+		One(&lastRecord)
+	if err != nil && err.Error() != orm.ErrNoRows.Error() {
+		return "", fmt.Errorf("报告编号-查询当前年季度最后编号失败: %v", err)
+	}
+
+	// 初始化新编号
+	var newSeq = 1
+
+	if lastRecord.T_report_number != "" {
+		// 提取序号部分,例如 "2025A00001" -> "00001"
+		lastSeqStr := lastRecord.T_report_number[len(lastRecord.T_report_number)-5:]
+		lastSeq, _ := strconv.Atoi(lastSeqStr)
+		newSeq = lastSeq + 1
+	}
+
+	var newCode string
+	for {
+		// 格式化新编号
+		newCode = fmt.Sprintf("%s%05d", yearQuarter, newSeq)
+		if Redis_Task_T_report_number_Get(newCode) {
+			newSeq += 1
+		} else {
+			err = Redis_Task_T_report_number_Set(newCode)
+			if err != nil {
+				return "", fmt.Errorf("报告编号-存入redis失败: %v", err)
+			}
+			break
+		}
+	}
+
+	return newCode, nil
+}
+
+// 获取 By
+func Read_TaskbyT_report_number(T_report_number string) (r Task, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Task))
+	//err := qs.Filter("T_task_id", T_task_id).Filter("T_State", 1).One(&r)
+	err := qs.Filter("T_report_number", T_report_number).Filter("T_State", 1).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+func Read_Task_List_For_Watermark(pdfType string) ([]Task, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	if pdfType == "pdf1" {
+
+		cond = cond.And("T_State", 1).And("T_pdf1__icontains", ".pdf").And("t_pdf1_signature__isnull", true)
+	}
+
+	if pdfType == "pdf2" {
+
+		cond = cond.And("T_State", 1).And("T_pdf2__icontains", ".pdf").And("t_pdf2_signature__isnull", true)
+	}
+
+	qs.SetCond((*orm2.Condition)(cond)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond)).Count()
+
+	return r, int(cnt)
+}
+
+func Read_Task_List_By_T_InfoCollection_id(T_InfoCollection_id string) ([]Task, int) {
+
+	o := orm.NewOrm()
+
+	qs := o.QueryTable(new(Task))
+	var r []Task
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_InfoCollection_id", T_InfoCollection_id).And("T_State", 1)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	return r, int(cnt)
+}
+
+// 删除的重复数据
+func DeleteDeduplicate(T_task_id string) (int64, error) {
+	localOrm := orm.NewOrm()
+	tb_name := "z_task_data_" + T_task_id
+	var cnt int64
+	// 创建临时表
+	sqlCreate := "CREATE TABLE `tmp_table_" + T_task_id + "` AS (SELECT MIN(`ID`) AS `min_id` FROM " + tb_name + " GROUP BY `t_sn`,`t_id`,`t_time`);"
+	_, err := localOrm.Raw(sqlCreate).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return cnt, err
+	}
+	sqlDelete := "DELETE FROM " + tb_name + "  WHERE `ID` NOT IN (SELECT `min_id` FROM `tmp_table_" + T_task_id + "`);"
+	res, err := localOrm.Raw(sqlDelete).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return cnt, err
+	}
+	cnt, _ = res.RowsAffected()
+	sqlDrop := "DROP TABLE `tmp_table_" + T_task_id + "`;"
+	_, err = localOrm.Raw(sqlDrop).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return cnt, err
+	}
+	return cnt, nil
+}
+
+// 修正秒数
+func CorrectionSecond(T_task_id string) error {
+	o := orm.NewOrm()
+	tb_name := "z_task_data_" + T_task_id
+	// 创建临时表
+	sqlCreate := "UPDATE " + tb_name + " SET t_time = t_time - INTERVAL SECOND(t_time) SECOND WHERE SECOND(t_time) != 0"
+	_, err := o.Raw(sqlCreate).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+
+	return nil
+}

+ 111 - 0
models/Task/TaskCopy.go

@@ -0,0 +1,111 @@
+package Task
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// 创建数据库  Device.CREATE_TaskData("")
+func CREATE_TaskDataCopy(alias_name, T_copy_id string) bool {
+	o := orm2.NewOrmUsingDB(alias_name)
+
+	sql := "DROP TABLE IF EXISTS `z_task_data_copy_" + T_copy_id + "`"
+	o.Raw(sql).Exec()
+
+	sql = "CREATE TABLE IF NOT EXISTS `z_task_data_copy_" + T_copy_id + "` ( " +
+		"  `ID` int(11) NOT NULL AUTO_INCREMENT," +
+		"	`t_sn` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL," +
+		"	`t_id` varchar(256) DEFAULT NULL," +
+		"	`t_t` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_rh` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_time` datetime(0) NULL DEFAULT NULL," +
+		"	PRIMARY KEY (`ID`) USING BTREE," +
+		"   KEY `t_sn` (`t_sn`)," +
+		"   KEY `t_id` (`t_id`)," +
+		"   KEY `t_time` (`t_time`)" +
+		") ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;"
+
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
+type TaskCopy struct {
+	Id         int       `orm:"column(ID);size(11);auto;pk"`
+	T_task_id  string    `orm:"size(256);null"`                                        // 任务ID
+	T_copy_id  string    `orm:"size(256);null"`                                        // 复制id
+	T_time     string    `orm:"size(256);null"`                                        // 存档时间
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常 2报告生成(只能存在一份)
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+func init() {
+	orm.RegisterModel(new(TaskCopy))
+}
+
+// 添加
+func Add_TaskCopy(r TaskCopy) (string, bool) {
+	o := orm.NewOrm()
+
+	var taskCopy TaskCopy
+	// 查询是否存在报告生成时的数据存档
+	qs := o.QueryTable(new(TaskCopy))
+	err := qs.Filter("T_task_id", r.T_task_id).Filter("T_State", 2).One(&taskCopy)
+	if err != nil && err.Error() != orm.ErrNoRows.Error() {
+		return "", false
+	}
+	// 删除之前的存档
+	if taskCopy.Id > 0 {
+		// 删除之前的存档记录和数据
+		taskCopy.T_State = 0
+		_, err = o.Update(&taskCopy, "T_State")
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			return "", false
+		}
+
+		sql := "DROP TABLE IF EXISTS `z_task_data_copy_" + taskCopy.T_copy_id + "`"
+		o.Raw(sql).Exec()
+	}
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_copy_id = lib.GetRandstring(12, "abcdefghijklmnopqrstuvwxyz0123456789", int64(rand_x))
+		err = o.Read(&r, "T_copy_id")
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	_, err = o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+
+	return r.T_copy_id, true
+}
+
+// 数据存档
+func TaskData_Arhiving(T_task_id, T_copy_id string) bool {
+
+	o := orm.NewOrm()
+
+	sql := "INSERT INTO `z_task_data_copy_" + T_copy_id + "`(`t_sn`, `t_id`, `t_t`, `t_rh`, `t_time`)" +
+		" SELECT `t_sn`, `t_id`, `t_t`, `t_rh`, `t_time` FROM `z_task_data_" + T_task_id + "`"
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	return true
+}

+ 411 - 0
models/Task/TaskData.go

@@ -0,0 +1,411 @@
+package Task
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"errors"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	Temperature = "Temperature"
+	Humidity    = "Humidity"
+)
+
+// 模版
+type TaskData struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_id   string    `orm:"size(256);null"`        // 标题
+	T_t    float32   `orm:"size(10);null"`         // 温度
+	T_rh   float32   `orm:"size(10);null"`         // 湿度
+	T_time time.Time `orm:"type(timestamp);null;"` // 采集时间
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间 UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`   //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+func (t *TaskData) TableName() string {
+	return "task_data" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+}
+
+// 创建数据库  Device.CREATE_TaskData("")
+func CREATE_TaskData(T_task_id string) bool {
+	o := orm.NewOrm()
+
+	sql := "DROP TABLE `z_task_data_" + T_task_id + "`"
+	o.Raw(sql).Exec()
+
+	sql = "CREATE TABLE IF NOT EXISTS `z_task_data_" + T_task_id + "` ( " +
+		"  `ID` int(11) NOT NULL AUTO_INCREMENT," +
+		"	`t_sn` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL," +
+		"	`t_id` varchar(256) DEFAULT NULL," +
+		"	`t_t` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_rh` float(6, 1) NULL DEFAULT NULL," +
+		"	`t_time` datetime(0) NULL DEFAULT NULL," +
+		"	PRIMARY KEY (`ID`) USING BTREE," +
+		"   KEY `t_sn` (`t_sn`)," +
+		"   KEY `t_time` (`t_time`)" +
+		") ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;"
+
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		return false
+	}
+
+	return true
+}
+
+// ---------------- 特殊方法 -------------------
+// 获取 ById
+//func Read_List_ById(id int) (r TaskData) {
+//	o := orm.NewOrm()
+//
+//	return r
+//}
+
+// 清空
+func Truncate_TaskData(T_task_id string) bool {
+
+	o := orm.NewOrm()
+
+	sql := "truncate table z_task_data_" + T_task_id
+	logs.Println(sql)
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 添加
+func Import_TaskData(Sn string, T_id string, T_task_id string, Time_start string, Time_end string) bool {
+	//if conf.Server_test {
+	//	return true
+	//}
+	if len(Sn) == 0 {
+		return false
+	}
+	o := orm.NewOrm()
+
+	// 开始插入数据
+	sql := "insert into z_task_data_" + T_task_id + "(t_id,t_t,t_rh,t_time) select " + T_id + ",t_t,t_rh,t_time from z_devicedata_" + Sn
+	sql = sql + " WHERE t_time >= '" + Time_start + "' AND t_time <= '" + Time_end + "'"
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	// 强行替换  ID
+	sql = "UPDATE z_task_data_" + T_task_id + " SET `t_sn` = '" + Sn + "',`t_id` = '" + T_id + "' WHERE `t_sn` IS NULL"
+	// 设备 ID
+	//sql = "UPDATE z_task_data_"+T_task_id+" SET `t_sn` = '"+Sn+"' WHERE `t_sn` IS NULL"
+	logs.Println(sql)
+	_, err = o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	res.RowsAffected()
+	return true
+}
+
+func Import_TaskData_Back(Sn string, T_id string, T_task_id string, Time_start string, Time_end string) error {
+	if len(Sn) == 0 {
+		return errors.New("sn不能为空")
+	}
+	o := orm.NewOrm()
+	// 开始插入数据
+	sql := "insert into z_task_data_" + T_task_id + "(t_sn,t_id,t_t,t_rh,t_time) select '" + Sn + "','" + T_id + "',t_t,t_rh,t_time from z_devicedata_" + Sn
+	if len(Time_start) > 0 && len(Time_end) > 0 {
+		sql = sql + " WHERE t_time >= '" + Time_start + "' AND t_time <= '" + Time_end + "'"
+	}
+	logs.Println(sql)
+	_, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	//// 强行替换  ID
+	//sql = "UPDATE z_task_data_" + T_task_id + " SET `t_sn` = '" + Sn + "',`t_id` = '" + T_id + "' WHERE `t_sn` IS NULL"
+	//logs.Println(sql)
+	//_, err = o.Raw(sql).Exec()
+	//if err != nil {
+	//	logs.Error(lib.FuncName(), err)
+	//	return err
+	//}
+
+	return nil
+}
+
+func Read_TaskData_Count(T_task_id string) int {
+
+	var maps_z []orm2.ParamsList
+
+	o := orm.NewOrm()
+
+	sql := "SELECT COUNT(ID) FROM z_task_data_" + T_task_id
+
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0
+	}
+	if len(maps_z) == 0 {
+		return 0
+	}
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return key
+}
+
+type TaskData_ struct {
+	ID               int     `orm:"column(ID);size(100);null"`   // ID
+	T_sn             string  `orm:"column(t_sn);size(256);null"` // 标题
+	T_id             string  `orm:"column(t_id);size(256);null"` // ID
+	T_t              float32 `orm:"column(t_t);size(10);null"`   // 温度
+	T_rh             float32 `orm:"column(t_rh);size(10);null"`  // 湿度
+	T_time           string  `orm:"column(t_times);null;"`       // 采集时间
+	T_Certificate_sn string  `orm:"size(256);null"`              // 证书编号
+
+}
+type TaskDataClass_ struct {
+	T_sn string `orm:"column(t_sn);size(256);null"` // 标题
+	T_id int    `orm:"column(t_id);size(10);null"`  // ID
+}
+
+func Read_TaskData_ById_List(T_task_id string, SN string, T_id string, Time_start_ string, Time_end_ string, page int, page_z int) ([]TaskData_, int64) {
+	o := orm.NewOrm()
+	var maps []TaskData_
+	var maps_z []orm2.ParamsList
+	pagez := page_z
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		page -= 1
+		offset = page * pagez
+	}
+
+	sql_condition := ""
+	if len(Time_start_) > 1 {
+		sql_condition += " AND t_time >= '" + Time_start_ + "'"
+	}
+
+	if len(Time_end_) > 1 {
+		sql_condition += " AND t_time <= '" + Time_end_ + "'"
+	}
+
+	if len(T_id) > 0 {
+		sql_condition += " AND t_id = '" + T_id + "'"
+	}
+	if len(SN) > 0 {
+		sql_condition += " AND t_sn = '" + SN + "'"
+	}
+
+	if len(sql_condition) > 0 {
+		sql_condition = " WHERE " + strings.TrimLeft(sql_condition, " AND ")
+	}
+
+	sql := "SELECT COUNT(ID) FROM z_task_data_" + T_task_id + sql_condition
+
+	logs.Println(sql)
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return maps, 0
+	}
+	if len(maps_z) == 0 {
+		return maps, 0
+	}
+
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql = "SELECT ID,t_sn,t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_times,t_time FROM z_task_data_" + T_task_id + sql_condition + " ORDER BY t_time DESC "
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
+	}
+
+	logs.Println(sql)
+	_, err = o.Raw(sql).QueryRows(&maps)
+
+	//value, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", cnt), 64)
+	key, _ := strconv.Atoi(maps_z[0][0].(string))
+	return maps, int64(key)
+}
+
+func Read_TaskData_ById_List_(T_task_id string, SN string) []TaskData_ {
+	o := orm.NewOrm()
+	var maps []TaskData_
+
+	sql_condition := ""
+
+	//sql_condition += " t_id = " + strconv.Itoa(T_id) + " AND "
+	sql_condition += "t_sn = '" + SN + "'"
+
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql := "SELECT ID,t_sn,t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i') AS t_times,t_time  FROM z_task_data_" + T_task_id + " WHERE " + sql_condition + " ORDER BY t_time "
+
+	logs.Println(sql)
+	o.Raw(sql).QueryRows(&maps)
+
+	return maps
+}
+
+func Read_TaskData_ById_ClassList(T_task_id string) []TaskDataClass_ {
+	o := orm.NewOrm()
+	var maps []TaskDataClass_
+
+	//logs.Println("maps_z;",maps_z[0][0])
+	sql := "SELECT DISTINCT t_sn FROM z_task_data_" + T_task_id + " ORDER BY t_sn"
+
+	logs.Println(sql)
+	o.Raw(sql).QueryRows(&maps)
+
+	return maps
+}
+
+// 添加
+func Add_TaskData(T_task_id string, T_sn string, T_id string, T_t string, T_rh string, T_time string) bool {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据
+	//
+	//sql := "INSERT INTO z_task_data_" + T_task_id + " (`t_sn`, `t_id`, `t_time`) " +
+	//	"VALUES ('" + T_sn + "', " + T_id + ", '" + T_time + "') " +
+	//	"ON DUPLICATE KEY UPDATE t_t=" + T_t + ", t_rh="+ T_rh +";"
+
+	// 去重复数据
+	//sql := "DELETE FROM z_task_data_" + T_task_id + "  WHERE " + " t_id = " + T_id + " AND "+ " t_sn = '"+T_sn+"' " + "AND t_time = '" + T_time + "'  "
+	//
+	////  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	//logs.Println(sql)
+	//res, err := o.Raw(sql).Exec()
+	//if err != nil {
+	//	logs.Error(lib.FuncName(),err)
+	//	return false
+	//}
+	//res.RowsAffected()
+
+	sql := "INSERT INTO z_task_data_" + T_task_id + " (`t_sn`, `t_id`, `t_t`, `t_rh`, `t_time`) " +
+		"VALUES ('" + T_sn + "', " + T_id + ", " + T_t + "," + T_rh + ", '" + T_time + "')"
+
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}
+
+// 修改
+func Up_TaskData(T_task_id string, Id string, T_t string, T_rh string, T_time string) bool {
+
+	o := orm.NewOrm()
+	SET_str := " SET "
+	if len(T_t) > 0 {
+		SET_str = SET_str + " t_t = " + T_t + " ,"
+	}
+	if len(T_rh) > 0 {
+		SET_str = SET_str + " t_rh = " + T_rh + " ,"
+	}
+	if len(T_time) > 0 {
+		SET_str = SET_str + " t_time = '" + T_time + "' ,"
+	}
+
+	if len(SET_str) > 7 {
+		SET_str = SET_str[:(len(SET_str) - 1)]
+	}
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "UPDATE z_task_data_" + T_task_id + " " + SET_str + " WHERE ID = " + Id
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	//logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}
+
+// 添加
+func Del_TaskData(T_task_id string, Id string) bool {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "DELETE FROM z_task_data_" + T_task_id + " WHERE ID = " + Id
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}
+
+// 添加
+func Del_TaskData_t_id(T_task_id string, Id string) bool {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "DELETE FROM z_task_data_" + T_task_id + " WHERE t_id = " + Id
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}
+func Del_TaskData_t_idByT_BindDeviceDataTime(T_task_id, Id, startTime, endTime string) bool {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "DELETE FROM z_task_data_" + T_task_id + " WHERE t_id = " + Id + " AND NOT BETWEEN '" + startTime + "' AND '" + endTime + "'"
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}

+ 91 - 0
models/Task/TaskLogs.go

@@ -0,0 +1,91 @@
+package Task
+
+import (
+	"ColdVerify_server/logs"
+	"encoding/json"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+type TaskLogs struct {
+	Id         int    `orm:"column(ID);size(11);auto;pk"`
+	T_uuid     string `orm:"size(256);null"`  // 操作用户uuid
+	T_task_id  string `orm:"size(256);null"`  // 任务ID
+	Logs_class string `orm:"size(256);null"`  //
+	Logs_Title string `orm:"size(256);null"`  // 标题
+	Logs_Txt   string `orm:"type(text);null"` // 详情
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}
+
+func (t *TaskLogs) TableName() string {
+	return "task_logs" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(TaskLogs))
+
+}
+
+type TaskLogs_R struct {
+	T_uuid     string // 操作用户uuid
+	T_name     string // 操作用户name
+	T_task_id  string // 任务ID
+	Logs_class string // 分类
+	Logs_Title string // 标题
+	Logs_Txt   string // 详情
+	CreateTime string
+}
+
+func TaskLogsToTaskLogs_R(T TaskLogs, adminMap map[string]string) (T_r TaskLogs_R) {
+	T_r.T_uuid = T.T_uuid
+	T_r.T_name = adminMap[T.T_uuid]
+	T_r.T_task_id = T.T_task_id
+	T_r.Logs_class = T.Logs_class
+	T_r.Logs_Title = T.Logs_Title
+	T_r.Logs_Txt = T.Logs_Txt
+	T_r.CreateTime = T.CreateTime.Format("2006-01-02 15:04:05")
+	return T_r
+}
+
+func Add_TaskLogs_T(T_uuid string, T_task_id string, Logs_class string, Logs_Title string, Logs_Txt_T interface{}) {
+	o := orm.NewOrm()
+	jsonStu, err := json.Marshal(Logs_Txt_T)
+	if err != nil {
+		logs.Error("Add_TaskLogs_T JSON ,err=", err)
+	}
+	m := TaskLogs{T_uuid: T_uuid, T_task_id: T_task_id, Logs_class: Logs_class, Logs_Title: Logs_Title, Logs_Txt: string(jsonStu)}
+	o.Insert(&m)
+}
+
+// 获取列表
+func Read_TaskLogs_List(T_task_id string, adminMap map[string]string, page int, page_z int) ([]TaskLogs_R, int) {
+
+	o := orm.NewOrm()
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = (page - 1) * page_z
+	}
+	qs := o.QueryTable(new(TaskLogs))
+	var r []TaskLogs
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_task_id", T_task_id)
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-CreateTime").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var TaskLogsList []TaskLogs_R
+	for _, v := range r {
+		TaskLogsList = append(TaskLogsList, TaskLogsToTaskLogs_R(v, adminMap))
+	}
+
+	return TaskLogsList, int(cnt)
+}

+ 188 - 0
models/Task/TaskTime.go

@@ -0,0 +1,188 @@
+package Task
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Account"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type TaskTime struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_task_id    string `orm:"size(256);"`     // 任务ID
+	T_task_type  int    `orm:"size(256);"`     // 任务类型 方案0 实施1 报告2 检测报告3 原始记录4
+	T_uuid       string `orm:"size(256);null"` // 用户 UUID
+	T_start_time string `orm:"size(256);null"` // 开始时间
+	T_end_time   string `orm:"size(256);null"` // 结束时间
+	T_remarks    string `orm:"type(text)"`     // 备注
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+func (t *TaskTime) TableName() string {
+	return "tasktime" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(TaskTime))
+}
+
+// -------------------------------------------------------------
+type TaskTime_R struct {
+	Id           int
+	T_task_id    string // 任务ID
+	T_task_type  int    // 任务类型 方案0 实施1 报告2 检测报告3 原始记录4
+	T_uuid       string // 用户 UUID
+	T_uuid_name  string // 用户 UUID
+	T_start_time string // 开始时间
+	T_end_time   string // 结束时间
+	T_remarks    string // 验证方案客户签字确认图片
+
+}
+
+// -------------------------------------------------------------
+func TaskTimeToTaskTime_R(T TaskTime) (T_r TaskTime_R) {
+	T_r.Id = T.Id
+	T_r.T_task_id = T.T_task_id
+	T_r.T_task_type = T.T_task_type
+	T_r.T_uuid = T.T_uuid
+	if err, r := Account.Read_Admin_ByT_uuid(T.T_uuid); err == nil {
+		T_r.T_uuid_name = r.T_name
+	}
+	T_r.T_start_time = T.T_start_time
+	T_r.T_end_time = T.T_end_time
+	T_r.T_remarks = T.T_remarks
+	return T_r
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_TaskTime_ById(id int) (r TaskTime, is bool) {
+	o := orm.NewOrm()
+	r = TaskTime{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_TaskTime(T_TaskTime_id string) (r TaskTime, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(TaskTime))
+	err := qs.Filter("T_TaskTime_id", T_TaskTime_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+func Read_TaskTime_T_name(T_name string) (r TaskTime, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(TaskTime))
+	err := qs.Filter("T_name", T_name).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_TaskTime(r TaskTime) (is bool) {
+	o := orm.NewOrm()
+
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+
+	return true
+}
+
+// 删除
+func Delete_TaskTime(v TaskTime) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_TaskTime(m TaskTime, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_TaskTime_List(T_task_id string, T_task_type int) ([]TaskTime_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []TaskTime
+	qs := o.QueryTable(new(TaskTime))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_task_id", T_task_id).And("T_task_type", T_task_type)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+	// 转换
+	var TaskTime_r []TaskTime_R
+	for _, v := range r {
+		TaskTime_r = append(TaskTime_r, TaskTimeToTaskTime_R(v))
+	}
+
+	return TaskTime_r, cnt
+}
+
+// 获取项目延时
+func Read_TaskTime_Compute(T_task_id string, T_task_type int) int64 {
+	List, _ := Read_TaskTime_List(T_task_id, T_task_type)
+	var time_interval_Compute float64
+	for _, v := range List {
+		if len(v.T_end_time) == 0 {
+			continue
+		}
+
+		_, err := time.ParseInLocation("2006-01-02 15:04:05", v.T_end_time, time.Local)
+		if err != nil {
+			continue
+		}
+		_, err = time.ParseInLocation("2006-01-02 15:04:05", v.T_start_time, time.Local)
+		if err != nil {
+			continue
+		}
+		time_interval, err := lib.MinutesDifference(v.T_start_time, v.T_end_time)
+		if err != nil {
+			continue
+		}
+
+		time_interval_Compute += time_interval
+	}
+
+	logs.Println("Read_TaskTime_Compute", T_task_id, T_task_type, time_interval_Compute)
+	return int64(time_interval_Compute)
+}

+ 271 - 0
models/Template/Template.go

@@ -0,0 +1,271 @@
+package Template
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type Template struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_name  string `orm:"size(256);null"`  // 标题
+	T_class int    `orm:"size(200);null"`  // 分类
+	T_img   string `orm:"size(256);null"`  // 图片
+	T_int   int    `orm:"size(200);null"`  //  数量
+	T_text  string `orm:"type(text);null"` // 详情
+
+	T_Visit    int       `orm:"size(200);default(0)"`                                  // 浏览量
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type Template_R struct {
+	T_name  string `orm:"size(256);null"`  // 标题
+	T_class int    `orm:"size(200);null"`  // 分类
+	T_img   string `orm:"size(256);null"`  // 图片
+	T_int   int    `orm:"size(200);null"`  //  数量
+	T_text  string `orm:"type(text);null"` // 详情
+}
+
+func (t *Template) TableName() string {
+	return "template" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+var redisCache_Template cache.Cache
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(Template))
+
+	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_"+"Template", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	logs.Println(config)
+	var err error
+	redisCache_Template, err = cache.NewCache("redis", config)
+	if err != nil || redisCache_Template == nil {
+		errMsg := "failed to init redis"
+		logs.Println(errMsg, err)
+
+	}
+}
+
+// -------------------------------------------------------------
+func TemplateToTemplate_R(T Template) (T_r Template_R) {
+	T_r.T_name = T.T_name
+
+	//......
+	return T_r
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_Template_Set(key string, r Template) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_Template.Put(key, str, 24*time.Hour)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_Template_Get(key string) (r Template, is bool) {
+	if redisCache_Template.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_Template.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return Template{}, false
+}
+func Redis_Template_DelK(key string) (err error) {
+	err = redisCache_Template.Delete(key)
+	return
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_Template_ById(id int) (r Template, is bool) {
+	o := orm.NewOrm()
+	r = Template{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_Template(T_name string) (r Template, is bool) {
+	if r, is = Redis_Template_Get(T_name); is == true {
+		return r, true
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Template))
+	err := qs.Filter("T_name", T_name).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	Redis_Template_Set(T_name, r)
+	return r, true
+}
+
+// 添加
+func Add_Template(r Template) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	//rand_x := 0
+	//for true {
+	//	r.T_Product_id = lib.GetRandstring(4, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", int64(rand_x)) // 1,336,336
+	//	err := o.Read(&r, "T_Product_id") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	//	if err != nil {
+	//		break
+	//	}
+	//	rand_x += 1
+	//}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	Redis_Template_Set(r.T_name, r)
+	return id, true
+}
+
+// 删除
+func Delete_Template(v Template) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	Redis_Template_DelK(v.T_name)
+	return true
+}
+
+// 删除
+func Delete_Template_(v Template) bool {
+	o := orm.NewOrm()
+	v.T_State = 0
+	if num, err := o.Update(&v, "T_State"); err == nil {
+		logs.Println("Number of records updated in database:", num)
+	} else {
+		return false
+	}
+
+	Redis_Template_DelK(v.T_name)
+	return true
+}
+
+// 修改
+func Update_Template(m Template, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		Redis_Template_Set(m.T_name, m)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_Template_List(T_name string, T_class int, page int, page_z int) ([]Template_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []Template
+	qs := o.QueryTable(new(Template))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+
+	if T_class > 0 {
+		//cond1.AndCond(cond.And("T_class", class))
+		cond1 = cond.AndCond(cond1).OrCond(cond.And("T_class", T_class))
+	}
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var Template_r []Template_R
+	for _, v := range r {
+		Template_r = append(Template_r, TemplateToTemplate_R(v))
+	}
+
+	return Template_r, cnt
+}
+
+// 获取列表 /时间筛选  Time_start_ Time_end_    2021-12-30,所以下面要加后缀 时间
+func Read_Template_List_Time(page int, T_sn string, T_Title string, Time_start_ string, Time_end_ string) ([]Template_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []Template
+	var cnt int64
+	qs := o.QueryTable(new(Template))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * conf.Page_size)
+	}
+
+	if len(Time_start_) > 1 && len(Time_end_) > 1 {
+		logs.Println(Time_start_, Time_end_)
+		qs.Limit(conf.Page_size, offset).Filter("T_Ut__lte", Time_end_+" 23:59:59").Filter("T_Ut__gte", Time_start_+" 00:00:00").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).OrderBy("-Id").Filter("T_State", 1).All(&r)
+		cnt, _ = qs.Filter("T_Ut__lte", Time_end_+" 23:59:59").Filter("T_Ut__gte", Time_start_+" 00:00:00").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).Filter("T_State", 1).Count()
+		return []Template_R{}, cnt
+	}
+
+	if len(Time_start_) > 1 {
+		qs.Limit(conf.Page_size, offset).Filter("T_Ut__gte", Time_start_+" 00:00:00").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).OrderBy("-Id").Filter("T_State", 1).All(&r)
+		cnt, _ = qs.Filter("T_Ut__gte", Time_start_+" 00:00:00").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).Filter("T_State", 1).Count()
+		return []Template_R{}, cnt
+	} else if len(Time_end_) > 1 {
+		qs.Limit(conf.Page_size, offset).Filter("T_Ut__lte", Time_end_+" 23:59:59").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).OrderBy("-Id").Filter("T_State", 1).All(&r)
+		cnt, _ = qs.Filter("T_Ut__lte", Time_end_+" 23:59:59").Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).Filter("T_State", 1).Count()
+		return []Template_R{}, cnt
+	}
+
+	qs.Limit(conf.Page_size, offset).Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).OrderBy("-Id").Filter("T_State", 1).All(&r)
+	cnt, _ = qs.Filter("T_Title__icontains", T_Title).Filter("T_sn__icontains", T_sn).Filter("T_State", 1).Count()
+
+	var Template_r []Template_R
+	for _, v := range r {
+		Template_r = append(Template_r, TemplateToTemplate_R(v))
+	}
+
+	return Template_r, cnt
+}

+ 215 - 0
models/VerifyTemplate/VerifyTemplate.go

@@ -0,0 +1,215 @@
+package VerifyTemplate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"encoding/json"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strings"
+	"time"
+)
+
+// 模版
+type VerifyTemplate struct {
+	Id      int `orm:"column(ID);size(11);auto;pk"`
+	T_class int `orm:"size(8);default(0)"` // 分类
+
+	T_VerifyTemplate_id string `orm:"size(256);null"`     // 标题
+	T_name              string `orm:"size(256);null"`     // 标题
+	T_sort              int    `orm:"size(2);default(1)"` // 排
+
+	T_scheme           string `orm:"size(256);null"` // 方案模版
+	T_reporting        string `orm:"size(256);null"` // 报告模版
+	T_marking          string `orm:"size(256);null"` // 标识模版
+	T_inspect          string `orm:"size(256);null"` // 自检
+	T_cover            string `orm:"size(256);null"` // 封面
+	T_examining_report string `orm:"size(256);null"` // 检测报告
+	T_original_record  string `orm:"size(256);null"` // 原始记录
+
+	T_deploy string `orm:"type(text);null"` // 布点选项  格式 布点内容1/布点范围1|布点内容2|布点内容3
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+// 模版布点
+type VerifyTemplateDeploy struct {
+	T_name  string // 布点内容
+	T_scope string // 布点范围
+}
+
+type VerifyTemplate_R struct {
+	T_VerifyTemplate_id string `orm:"size(256);null"` // 标题
+	T_name              string `orm:"size(256);null"` // 标题
+	T_sort              int    `orm:"size(200);null"` // 分类
+
+	T_scheme           string                 // 方案模版
+	T_reporting        string                 // 报告模版
+	T_inspect          string                 // 自检
+	T_marking          string                 // 标识模版
+	T_cover            string                 // 封面
+	T_examining_report string                 // 检测报告
+	T_original_record  string                 // 原始记录
+	T_deploy           string                 // 布点选项  格式 布点内容1|布点内容2|布点内容3
+	T_deploy_list      []VerifyTemplateDeploy // 布点选项  格式 布点内容1|布点内容2|布点内容3
+}
+
+func (t *VerifyTemplate) TableName() string {
+	return "verify_template" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(VerifyTemplate))
+
+}
+
+// -------------------------------------------------------------
+func VerifyTemplateToVerifyTemplate_R(T VerifyTemplate) (T_r VerifyTemplate_R) {
+	T_r.T_VerifyTemplate_id = T.T_VerifyTemplate_id
+	T_r.T_name = T.T_name
+	T_r.T_sort = T.T_sort
+	T_r.T_scheme = T.T_scheme
+	T_r.T_reporting = T.T_reporting
+	T_r.T_inspect = T.T_inspect
+	T_r.T_marking = T.T_marking
+	T_r.T_cover = T.T_cover
+	T_r.T_original_record = T.T_examining_report
+	T_r.T_original_record = T.T_original_record
+	var deployList []VerifyTemplateDeploy
+	if len(T.T_deploy) > 0 {
+		if strings.Contains(strings.Trim(T.T_deploy, "|"), "|") {
+			deploys := strings.Split(T.T_deploy, "|")
+			for _, v := range deploys {
+				deployList = append(deployList, VerifyTemplateDeploy{T_name: v})
+			}
+		} else {
+			err := json.Unmarshal([]byte(T.T_deploy), &deployList)
+			if err != nil {
+				logs.Error("布点 JSON 反序列化失败:", err)
+			}
+		}
+	}
+	for _, deploy := range deployList {
+		T_r.T_deploy += deploy.T_name + "|"
+	}
+	T_r.T_deploy_list = deployList
+
+	return T_r
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_VerifyTemplate_ById(id int) (r VerifyTemplate, is bool) {
+	o := orm.NewOrm()
+	r = VerifyTemplate{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_VerifyTemplate(T_VerifyTemplate_id string) (r VerifyTemplate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplate))
+	err := qs.Filter("T_VerifyTemplate_id", T_VerifyTemplate_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+func Read_VerifyTemplate_T_name(T_name string) (r VerifyTemplate, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplate))
+	err := qs.Filter("T_name", T_name).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_VerifyTemplate(r VerifyTemplate) (T_VerifyTemplate_id string, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_VerifyTemplate_id = lib.GetRandstring(4, "", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_VerifyTemplate_id")                        // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	_, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return "", false
+	}
+
+	return r.T_VerifyTemplate_id, true
+}
+
+// 删除
+func Delete_VerifyTemplate(v VerifyTemplate) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_VerifyTemplate(m VerifyTemplate, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_VerifyTemplate_List(T_class int, T_name string, page int, page_z int) ([]VerifyTemplate_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplate
+	qs := o.QueryTable(new(VerifyTemplate))
+	var offset int64
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = int64((page - 1) * page_z)
+	}
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_class", T_class).And("T_name__icontains", T_name) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+
+	qs.Limit(page_z, offset).SetCond((*orm2.Condition)(cond1)).OrderBy("T_name").All(&r)
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+	// 转换
+	var VerifyTemplate_r []VerifyTemplate_R
+	for _, v := range r {
+		VerifyTemplate_r = append(VerifyTemplate_r, VerifyTemplateToVerifyTemplate_R(v))
+	}
+
+	return VerifyTemplate_r, cnt
+}

+ 380 - 0
models/VerifyTemplate/VerifyTemplateClass.go

@@ -0,0 +1,380 @@
+package VerifyTemplate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"errors"
+	"fmt"
+	_ "github.com/astaxie/beego/cache/redis"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strconv"
+	"strings"
+)
+
+// 模版
+type VerifyTemplateClass struct {
+	Id     int    `orm:"column(ID);size(11);auto;pk"`
+	T_fid  int    `orm:"size(200);null"` // 父级分类ID,主类 为 0
+	T_name string `orm:"size(256);null"` // 标题
+	T_path string `orm:"size(256);null"` // 路径
+
+	T_State int `orm:"size(2);default(1)"` // 0 删除(伪删除)   1 正常
+
+	Children []VerifyTemplateClass `orm:"-"`
+}
+
+func (t *VerifyTemplateClass) TableName() string {
+	return "verify_template_class" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(VerifyTemplateClass))
+}
+
+type VerifyTemplateClass_R struct {
+	Id       int
+	T_fid    int                   // 项目 id, VerifyTemplateClass.ID
+	T_name   string                // 名称
+	T_State  int                   // 0 删除(伪删除)   1 正常(已交付)     2 开发中
+	Children []VerifyTemplateClass `orm:"-"`
+}
+
+type VerifyTemplateClass_Distributor struct {
+	Id                  int
+	T_fid               int    // 项目 id, VerifyTemplateClass.ID
+	T_name              string // 名称
+	T_State             int    // 0 删除(伪删除)   1 正常(已交付)     2 开发中
+	T_path              string
+	T_VerifyTemplate_id string
+	Children            []VerifyTemplateClass_Distributor `orm:"-"`
+}
+
+// 获取 ById
+func Read_VerifyTemplateClass_ById(id int) (r VerifyTemplateClass, err error) {
+	o := orm.NewOrm()
+	r = VerifyTemplateClass{Id: id, T_State: 1}
+	err = o.Read(&r, "Id", "T_State")
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, err
+	}
+	return r, err
+}
+
+// 添加
+func Add_VerifyTemplateClass(var_ VerifyTemplateClass) (id int64, err error) {
+	o := orm.NewOrm()
+	o.Begin()
+	id, err = o.Insert(&var_)
+	if err != nil {
+		o.Rollback()
+		return id, err
+	}
+
+	T_Path := "/0/" + strconv.Itoa(int(id)) + "/"
+	if var_.T_fid != 0 {
+		class_r, err := Read_VerifyTemplateClass_ById(var_.T_fid)
+		if err != nil {
+			o.Rollback()
+			return id, err
+		}
+		T_Path = class_r.T_path + strconv.Itoa(int(id)) + "/"
+	}
+
+	var_.Id = int(id)
+	var_.T_path = T_Path
+	_, err = o.Update(&var_, "T_path")
+	if err != nil {
+		o.Rollback()
+		return id, err
+	}
+	o.Commit()
+
+	return id, err
+}
+
+// 修改
+func Update_VerifyTemplateClass(r VerifyTemplateClass, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&r, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 批量删除
+func Delete_VerifyTemplateClass_ByIds(ids []int) bool {
+	o := orm.NewOrm()
+	o.Begin()
+	for _, id := range ids {
+		v := VerifyTemplateClass{Id: id, T_State: 0}
+		if _, err := o.Update(&v, "T_State"); err != nil {
+			o.Rollback()
+			return false
+		}
+	}
+
+	o.Commit()
+	return true
+}
+
+// 获取列表
+func Read_VerifyTemplateClass_List() (r []VerifyTemplateClass) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var map_r []VerifyTemplateClass
+	qs := o.QueryTable(new(VerifyTemplateClass))
+
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_State", 1)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&map_r)
+
+	r = VerifyTemplateClass_Call(map_r, 0)
+
+	return r
+
+}
+
+func VerifyTemplateClass_Call(list []VerifyTemplateClass, parentId int) []VerifyTemplateClass {
+	res := make([]VerifyTemplateClass, 0)
+	for _, v := range list {
+		if v.T_fid == parentId {
+			v.Children = VerifyTemplateClass_Call(list, v.Id)
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
+// 通过T_pid查询所有子id
+func ReadVerifyTemplateClassIds_T_path(T_path string) (VerifyTemplateClassIds []int) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateClass))
+	var VerifyTemplateClassList []VerifyTemplateClass
+	qs.Filter("T_path__startswith", T_path).Filter("T_State", 1).All(&VerifyTemplateClassList)
+	for _, v := range VerifyTemplateClassList {
+		VerifyTemplateClassIds = append(VerifyTemplateClassIds, v.Id)
+	}
+	return VerifyTemplateClassIds
+}
+
+// 通过T_path查询所有子验证分类
+func ReadVerifyTemplateClassList_T_path(T_path string, parentId int) (r []VerifyTemplateClass) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateClass))
+	var VerifyTemplateClassList []VerifyTemplateClass
+	qs.Filter("T_path__startswith", T_path).Filter("T_State", 1).All(&VerifyTemplateClassList)
+	r = VerifyTemplateClass_Call(VerifyTemplateClassList, parentId)
+	return r
+}
+
+// 递归复制节点
+func copyVerifyTemplateClass(o orm.Ormer, r *VerifyTemplateClass, newParentId int, parentPath string) (*VerifyTemplateClass, error) {
+
+	// 创建新节点
+	verifyTemplateClass := VerifyTemplateClass{
+		T_fid:   newParentId,
+		T_name:  r.T_name, // 添加副本标识
+		T_State: 1,
+		// T_path 将在插入后更新
+	}
+
+	// 插入数据库
+	newVerifyTemplateClassId, err := o.Insert(&verifyTemplateClass)
+	if err != nil {
+		return nil, err
+	}
+
+	newPath := parentPath + strconv.Itoa(verifyTemplateClass.Id) + "/"
+
+	// 更新路径
+	verifyTemplateClass.Id = int(newVerifyTemplateClassId)
+	verifyTemplateClass.T_path = newPath
+	_, err = o.Update(&verifyTemplateClass, "T_path")
+	if err != nil {
+		return nil, err
+	}
+
+	// 复制子节点
+	for _, child := range r.Children {
+		_, err = copyVerifyTemplateClass(o, &child, verifyTemplateClass.Id, newPath)
+		if err != nil {
+			return nil, err
+		}
+	}
+	// 分类1
+	//  ----模版
+	//	--------标签
+	// 分类2
+	//   -- 子分类
+	// 2 复制分类下的模版
+	// 3 复制模版下的标签
+	VerifyTemplateList, _ := Read_VerifyTemplate_List(r.Id, "", 0, 9999)
+	for _, v := range VerifyTemplateList {
+		verifyTemplate, is := Read_VerifyTemplate(v.T_VerifyTemplate_id)
+		if !is {
+			return nil, errors.New("查询验证模版失败")
+		}
+
+		newVerifyTemplate := VerifyTemplate{
+			T_class: verifyTemplateClass.Id, // 新的分类id
+			T_name:  verifyTemplate.T_name,
+			T_sort:  verifyTemplate.T_sort,
+		}
+
+		newVerifyTemplateId, is := Add_VerifyTemplate(newVerifyTemplate)
+		if !is {
+			return nil, errors.New("复制验证模版失败")
+		}
+
+		// 复制模版下面的标签
+		mapList, _ := Read_VerifyTemplateMap_List(v.T_VerifyTemplate_id, 0, 0)
+		tempMap := make(map[string]struct{})
+		idList := make([]string, len(mapList))
+		// 生成mapList长度的T_id
+		for i := 0; i < len(mapList); i++ {
+			// 生成编号
+			rand_x := 0
+			T_id := ""
+			for true {
+				T_id = lib.GetRandstring(4, "", int64(rand_x))
+				_, is = Read_VerifyTemplateMap(T_id)
+				if !is {
+					if _, ok := tempMap[T_id]; !ok {
+						break
+					}
+				}
+				rand_x += 1
+			}
+			tempMap[T_id] = struct{}{}
+			idList[i] = T_id
+		}
+		mapInsertList := make([]VerifyTemplateMap, 0)
+		for i, m := range mapList {
+			vtm := VerifyTemplateMap{
+				T_id:                idList[i],
+				T_VerifyTemplate_id: newVerifyTemplateId,
+				T_name:              m.T_name,
+				T_text:              m.T_text,
+				T_label:             m.T_label,
+				T_sort:              m.T_sort,
+			}
+
+			mapInsertList = append(mapInsertList, vtm)
+		}
+
+		_, is = Add_VerifyTemplateMapMulti(mapInsertList)
+		if !is {
+			return nil, errors.New("复制验证模版标签失败")
+		}
+	}
+
+	return &verifyTemplateClass, nil
+}
+
+func CopyVerifyTemplateClassTree(T_path string, parentId int, T_name string) (newRoot *VerifyTemplateClass, err error) {
+	// 获取原始节点及其子树
+	o := orm.NewOrm()
+	srcNode := ReadVerifyTemplateClassList_T_path(T_path, parentId)
+	if len(srcNode) == 0 {
+		return nil, errors.New("查询验证模版分类失败")
+	}
+	srcNode[0].T_name = T_name
+	// 开启事务
+	err = o.Begin()
+	if err != nil {
+		o.Rollback()
+		return nil, fmt.Errorf("事务启动失败: %v", err)
+	}
+
+	s := strings.Split(strings.Trim(T_path, "/"), "/")
+	parentPath := fmt.Sprintf("/%s/", strings.Join(s[:len(s)-1], "/"))
+	// 递归复制
+	newRoot, err = copyVerifyTemplateClass(o, &srcNode[0], parentId, parentPath) // 假设复制到根目录
+	if err != nil {
+		o.Rollback()
+		return nil, err
+	}
+
+	// 提交事务
+	if err = o.Commit(); err != nil {
+		o.Rollback()
+		return nil, fmt.Errorf("事务提交失败: %v", err)
+	}
+
+	return newRoot, nil
+}
+
+// 获取列表
+func Read_VerifyTemplateClass_List_For_Distributor() (r []VerifyTemplateClass_Distributor) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var map_r []VerifyTemplateClass
+	qs := o.QueryTable(new(VerifyTemplateClass))
+
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_State", 1)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&map_r)
+
+	// 转换
+	for _, v := range map_r {
+		r = append(r, VerifyTemplateClass_Distributor{
+			Id:                  v.Id,
+			T_name:              v.T_name,
+			T_fid:               v.T_fid,
+			T_path:              v.T_path,
+			T_VerifyTemplate_id: strconv.Itoa(v.Id),
+		})
+	}
+
+	r = VerifyTemplateClass_Call_For_Distributor(r, 0)
+
+	return r
+
+}
+
+func VerifyTemplateClass_Call_For_Distributor(list []VerifyTemplateClass_Distributor, parentId int) []VerifyTemplateClass_Distributor {
+	res := make([]VerifyTemplateClass_Distributor, 0)
+	for _, v := range list {
+		if v.T_fid == parentId {
+			v.Children = VerifyTemplateClass_Call_For_Distributor(list, v.Id)
+			verifyTemplate_List := Read_VerifyTemplate_List_For_Distributor(v.Id)
+			v.Children = append(v.Children, verifyTemplate_List...)
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
+func Read_VerifyTemplate_List_For_Distributor(T_class int) []VerifyTemplateClass_Distributor {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplate
+	qs := o.QueryTable(new(VerifyTemplate))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_class", T_class)
+
+	qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_name").All(&r)
+	// 转换
+	var VerifyTemplate_r []VerifyTemplateClass_Distributor
+	for _, v := range r {
+		VerifyTemplate_r = append(VerifyTemplate_r, VerifyTemplateClass_Distributor{
+			T_name:              v.T_name,
+			T_VerifyTemplate_id: v.T_VerifyTemplate_id,
+		})
+	}
+
+	return VerifyTemplate_r
+}

+ 259 - 0
models/VerifyTemplate/VerifyTemplateMap.go

@@ -0,0 +1,259 @@
+package VerifyTemplate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"log"
+	"time"
+)
+
+// 模版
+type VerifyTemplateMap struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_id                string `orm:"index,size(256);null"` //
+	T_VerifyTemplate_id string `orm:"size(256);null"`       // 验证模版id
+	T_label             int    `orm:"size(2);default(1)"`   // 数据类型
+	T_source            int    `orm:"size(2);default(0)"`   // 来源 0-所有 1-方案 2-报告 3-表单(包含报告) 4-验证标识 5-检测报告 6-原始记录 7-方案/报告 8-实验室(检测报告,原始记录)
+
+	//1:文本
+	//2:数值
+	//3:设备多选 (1|2|3|4|5|6|)
+	//4:设备单选选 (1)
+	//7:当期时间(2022年01月19日)
+	//9:当期时间(开始与结束时间)(2022-01-01 13:08|2022-01-02 13:08)
+	//10:图片
+	//11:CAD
+	T_name         string `orm:"size(256);null"`     // 标签名称
+	T_text         string `orm:"size(256);null"`     // 描述
+	T_sort         int    `orm:"size(2);default(1)"` // 排序
+	T_Required     int    `orm:"size(2);default(0)"` // 必填项  1 必填   0 非必填
+	T_Construction int    `orm:"size(2);default(0)"` // 实施(是否在APP 上显示)  1 显示   0 不显示
+
+	// 验证流程
+	T_flow_sort int `orm:"size(2);default(0)"` // 验证流程排序
+	T_max_time  int `orm:"size(256);null"`     // 验证流程最大时间
+	T_min_time  int `orm:"size(256);null"`     // 验证流程最小时间
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type VerifyTemplateMap_R struct {
+	T_id           string
+	T_source       int    // 数据类型
+	T_label        int    // 来源
+	T_name         string // 标签名称
+	T_text         string // 描述
+	T_sort         int    // 排序
+	T_Required     int    // 必填项  1 必填   0 非必填
+	T_Construction int    // 实施(是否在APP 上显示)  1 显示   0 不显示
+	T_flow_sort    int    // 验证流程排序
+	T_max_time     int    // 验证流程最大时间
+	T_min_time     int    // 验证流程最小时间
+	T_start_time   int    // 任务开始时间 app
+}
+
+func (t *VerifyTemplateMap) TableName() string {
+	return "verify_template_map" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+
+	//注册模型
+	orm.RegisterModel(new(VerifyTemplateMap))
+
+}
+
+// -------------------------------------------------------------
+func VerifyTemplateMapToVerifyTemplateMap_R(T VerifyTemplateMap) (T_r VerifyTemplateMap_R) {
+	T_r.T_id = T.T_id
+	T_r.T_source = T.T_source
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_sort = T.T_sort
+	T_r.T_Required = T.T_Required
+	T_r.T_Construction = T.T_Construction
+	T_r.T_flow_sort = T.T_flow_sort
+	T_r.T_max_time = T.T_max_time
+	T_r.T_min_time = T.T_min_time
+	return T_r
+}
+
+// ---------------- 特殊方法 -------------------
+
+// 获取 ById
+func Read_VerifyTemplateMap_ById(id int) (r VerifyTemplateMap, is bool) {
+	o := orm.NewOrm()
+	r = VerifyTemplateMap{Id: id}
+	err := o.Read(&r) // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, false
+	}
+	return r, true
+}
+
+// 获取 By
+func Read_VerifyTemplateMap(T_id string) (r VerifyTemplateMap, is bool) {
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateMap))
+	err := qs.Filter("T_id", T_id).One(&r)
+	if err != nil {
+		return r, false
+	}
+
+	return r, true
+}
+
+// 添加
+func Add_VerifyTemplateMap(r VerifyTemplateMap) (id int64, is bool) {
+	o := orm.NewOrm()
+
+	// 生成编号
+	rand_x := 0
+	for true {
+		r.T_id = lib.GetRandstring(4, "", int64(rand_x)) // 1,336,336
+		err := o.Read(&r, "T_id")                        // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+		if err != nil {
+			break
+		}
+		rand_x += 1
+	}
+
+	id, err := o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0, false
+	}
+
+	return id, true
+}
+
+// 添加
+func Add_VerifyTemplateMapMulti(r []VerifyTemplateMap) (id int64, is bool) {
+	o := orm.NewOrm()
+	n, err := o.InsertMulti(len(r), r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return n, false
+	}
+
+	return n, true
+}
+
+// 删除
+func Delete_VerifyTemplateMap(v VerifyTemplateMap) bool {
+	o := orm.NewOrm()
+	if num, err := o.Delete(&v); err == nil {
+		logs.Println("Number of records deleted in database:", num)
+	} else {
+		return false
+	}
+
+	return true
+}
+
+// 修改
+func Update_VerifyTemplateMap(m VerifyTemplateMap, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&m, cols...); err == nil {
+		log.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
+// 获取列表
+func Read_VerifyTemplateMap_List(T_VerifyTemplate_id string, T_sort, T_flow_sort int) ([]VerifyTemplateMap_R, int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMap
+	qs := o.QueryTable(new(VerifyTemplateMap))
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_VerifyTemplate_id", T_VerifyTemplate_id) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
+	// 排序 默认升序
+
+	if T_sort == 2 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-T_sort").All(&r)
+	} else if T_flow_sort == 1 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_flow_sort").All(&r)
+	} else if T_flow_sort == 2 {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-T_flow_sort").All(&r)
+	} else {
+		qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_sort").All(&r)
+	}
+	cnt, _ := qs.SetCond((*orm2.Condition)(cond1)).Count()
+
+	// 转换
+	var VerifyTemplateMap_r []VerifyTemplateMap_R
+	for _, v := range r {
+		VerifyTemplateMap_r = append(VerifyTemplateMap_r, VerifyTemplateMapToVerifyTemplateMap_R(v))
+	}
+
+	return VerifyTemplateMap_r, cnt
+}
+
+// 0-所有
+// 1-方案
+// 2-报告
+// 3-表单(包含报告)
+// 4-验证标识
+// 5-检测报告
+// 6-原始记录
+// 7-方案/报告
+// 8-实验室(检测报告,原始记录)
+// 1-方案 0,1,7
+// 2-报告 0,2,3,7
+// 3-表单 3
+// 4-检测报告 0,5,8
+// 5-原始记录 0,6,8
+func Read_VerifyTemplateMap_List_For_Data(T_VerifyTemplate_id string, T_source, T_flow int) []VerifyTemplateMap {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMap
+	qs := o.QueryTable(new(VerifyTemplateMap))
+	var source []int
+	switch T_source {
+	case 1:
+		source = []int{0, 1, 7}
+	case 2:
+		source = []int{0, 2, 3, 7}
+	case 3:
+		source = []int{3}
+	case 4:
+		source = []int{0, 5, 8}
+	case 5:
+		source = []int{0, 6, 8}
+	}
+
+	cond := orm.NewCondition()
+	if T_flow == 1 {
+		// app时间流程 排序id不等于0
+		cond = cond.AndNot("T_flow_sort", 0).And("T_VerifyTemplate_id", T_VerifyTemplate_id)
+		qs.SetCond((*orm2.Condition)(cond)).OrderBy("T_flow_sort").All(&r)
+	} else {
+		if len(source) > 0 {
+			cond = cond.And("T_source__in", source)
+		}
+		cond = cond.And("T_VerifyTemplate_id", T_VerifyTemplate_id)
+		qs.SetCond((*orm2.Condition)(cond)).OrderBy("T_sort").All(&r)
+	}
+
+	return r
+}
+
+func VerifyTemplateMap_RToMap(T []VerifyTemplateMap_R) map[string]string {
+	maps := make(map[string]string, len(T))
+	for _, v := range T {
+		maps[v.T_id] = v.T_name
+	}
+	return maps
+}

+ 422 - 0
models/VerifyTemplate/VerifyTemplateMapData.go

@@ -0,0 +1,422 @@
+package VerifyTemplate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"ColdVerify_server/models/Task"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"strings"
+	"time"
+)
+
+// 模版
+type VerifyTemplateMapData struct {
+	Id                     int    `orm:"column(ID);size(11);auto;pk"`
+	T_source               int    `orm:"size(2);"`             // 来源 0-所有 1-方案 2-报告 3-表单
+	T_task_id              string `orm:"index,size(256);null"` // 任务id
+	T_VerifyTemplate_id    string `orm:"index,size(256);null"` // 模版id
+	T_VerifyTemplateMap_id string `orm:"index,size(256);null"` // 标签id
+	T_value                string `orm:"size(1024);null"`      // 内容
+	T_Required             int    `orm:"size(2);default(0)"`   // 必填项  1 必填   0 非必填
+	T_Construction         int    `orm:"size(2);default(0)"`   // 实施(是否在APP 上显示)  1 显示   0 不显示
+
+	// 验证流程
+	T_flow_sort int `orm:"size(2);default(0)"` // 验证流程排序
+	T_max_time  int `orm:"size(256);null"`     // 验证流程最大时间
+	T_min_time  int `orm:"size(256);null"`     // 验证流程最小时间
+
+	T_start_time int64 `orm:"size(256);null"` // 开始时间 app
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type VerifyTemplateMapData_R struct {
+	T_id                   int
+	T_VerifyTemplateMap_id string // 标签id
+	T_source               int
+	T_label                int    //
+	T_name                 string // 标题
+	T_text                 string // 标题
+	T_value                string //
+	T_Required             int    //
+	T_Construction         int    //
+	// 验证流程
+	T_flow_sort int // 验证流程排序
+	T_max_time  int // 验证流程最大时间
+	T_min_time  int // 验证流程最小时间
+
+	T_start_time int64 // 开始时间 app
+}
+
+func (t *VerifyTemplateMapData) TableName() string {
+	return "verify_template_map_data" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(VerifyTemplateMapData))
+
+}
+
+// -------------------------------------------------------------
+func VerifyTemplateMapToVerifyTemplateMapData_R(T VerifyTemplateMap) (T_r VerifyTemplateMapData_R) {
+	T_r.T_VerifyTemplateMap_id = T.T_id
+	T_r.T_source = T.T_source
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_Required = T.T_Required
+	T_r.T_Construction = T.T_Construction
+
+	T_r.T_flow_sort = T.T_flow_sort
+	T_r.T_max_time = T.T_max_time
+	T_r.T_min_time = T.T_min_time
+
+	T_r.T_value = ""
+	return T_r
+}
+
+func VerifyTemplateMapDataToVerifyTemplateMapData_R(T VerifyTemplateMap, VerifyTemplateMapData map[string]VerifyTemplateMapData) (T_r VerifyTemplateMapData_R) {
+	T_r.T_VerifyTemplateMap_id = T.T_id
+	T_r.T_source = T.T_source
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_Required = T.T_Required
+	T_r.T_Construction = T.T_Construction
+
+	T_r.T_flow_sort = T.T_flow_sort
+	T_r.T_max_time = T.T_max_time
+	T_r.T_min_time = T.T_min_time
+
+	T_r.T_value = ""
+	if v, ok := VerifyTemplateMapData[T.T_id]; ok {
+		T_r.T_value = v.T_value
+		if T.T_label == 3 {
+			T_r.T_value = DeleteDeduplicateValue(v.T_value)
+		}
+		T_r.T_start_time = v.T_start_time
+	}
+	return T_r
+}
+
+// 去掉重复测点
+func DeleteDeduplicateValue(input string) (output string) {
+	// 分割字符串
+	parts := lib.SplitStringSeparator(input, "|")
+
+	// 使用map去重
+	seen := make(map[string]bool)
+	var result []string
+
+	for _, part := range parts {
+		if !seen[part] {
+			seen[part] = true
+			result = append(result, part)
+		}
+	}
+
+	// 重新拼接
+	return strings.Join(result, "|")
+}
+
+// T_submit  // 1-app 2-报告生成
+// T_cover   // 是否覆盖-app 0覆盖 1不覆盖
+// T_history // 保存历史数据
+// 添加或更新模版数据 并添加历史数据
+func AddOrUpdate_VerifyTemplateMapData_ADD_History(List []VerifyTemplateMapData, T_source int, T_uuid string, T_submit, T_cover, T_history int) (ids []int64, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateMapData))
+	o.Begin()
+	T_time := time.Now().Format("2006-01-02 15:04:05")
+	var err error
+	var T_task_id string
+	for _, v := range List {
+		if len(T_task_id) == 0 {
+			T_task_id = v.T_task_id
+		}
+		var r VerifyTemplateMapData
+		// 创建验证模版数据,有则更新,没有则创建
+		err = qs.Filter("T_task_id", v.T_task_id).Filter("T_VerifyTemplate_id", v.T_VerifyTemplate_id).Filter("T_VerifyTemplateMap_id", v.T_VerifyTemplateMap_id).One(&r)
+		if err != nil {
+			if err.Error() == orm.ErrNoRows.Error() {
+				id, err := o.Insert(&v)
+				if err != nil {
+					logs.Error(lib.FuncName(), err)
+					o.Rollback()
+					return ids, false
+				}
+				ids = append(ids, id)
+			} else {
+				logs.Error(lib.FuncName(), err)
+				o.Rollback()
+				return ids, false
+			}
+		}
+		// app 不覆盖,只保存历史记录
+		if !(T_submit == 1 && T_cover == 1) {
+			// 更新验证模版数据
+			if r.Id > 0 && (len(v.T_value) > 0 || v.T_start_time > 0) {
+				if v.T_start_time == 1 {
+					v.T_start_time = 0
+				}
+				v.Id = r.Id
+				_, err = o.QueryTable(new(VerifyTemplateMapData)).Filter("T_task_id", v.T_task_id).Filter("T_VerifyTemplate_id", v.T_VerifyTemplate_id).
+					Filter("T_VerifyTemplateMap_id", v.T_VerifyTemplateMap_id).Update(orm2.Params{
+					"T_flow_sort": v.T_flow_sort, "T_max_time": v.T_max_time, "T_min_time": v.T_min_time, "T_value": v.T_value, "T_start_time": v.T_start_time,
+				})
+				if err != nil {
+					logs.Error(lib.FuncName(), err)
+					o.Rollback()
+					return ids, false
+				}
+				ids = append(ids, int64(r.Id))
+			}
+		}
+
+		// 前端第一次上传本地地址,第二次上传http地址,需要更新数据为http地址
+		if strings.Contains(r.T_value, "file:///") && strings.Contains(v.T_value, "https://") {
+			// 更新验证模版数据
+			if r.Id > 0 && (len(v.T_value) > 0 || v.T_start_time > 0) {
+				if v.T_start_time == 1 {
+					v.T_start_time = 0
+				}
+				v.Id = r.Id
+				_, err = o.QueryTable(new(VerifyTemplateMapData)).Filter("T_task_id", v.T_task_id).Filter("T_VerifyTemplate_id", v.T_VerifyTemplate_id).
+					Filter("T_VerifyTemplateMap_id", v.T_VerifyTemplateMap_id).Update(orm2.Params{
+					"T_flow_sort": v.T_flow_sort, "T_max_time": v.T_max_time, "T_min_time": v.T_min_time, "T_value": v.T_value, "T_start_time": v.T_start_time,
+				})
+				if err != nil {
+					logs.Error(lib.FuncName(), err)
+					o.Rollback()
+					return ids, false
+				}
+				ids = append(ids, int64(r.Id))
+			}
+		}
+
+		// 添加历史记录
+		_, err = o.Insert(&VerifyTemplateMapDataHistory{
+			T_source:               v.T_source,
+			T_task_id:              v.T_task_id,
+			T_time:                 T_time,
+			T_uuid:                 T_uuid,
+			T_submit_source:        T_source,
+			T_VerifyTemplate_id:    v.T_VerifyTemplate_id,
+			T_VerifyTemplateMap_id: v.T_VerifyTemplateMap_id,
+			T_value:                v.T_value,
+			T_Required:             v.T_Required,
+			T_flow_sort:            v.T_flow_sort,
+			T_Construction:         v.T_Construction,
+			T_max_time:             v.T_max_time,
+			T_min_time:             v.T_min_time,
+		})
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			o.Rollback()
+			return ids, false
+		}
+
+	}
+
+	if T_history == 1 && len(T_task_id) > 0 {
+		// 添加历史记录
+		_, err = o.Insert(&VerifyDataHistoryRecord{
+			T_task_id:       T_task_id,
+			T_time:          T_time,
+			T_uuid:          T_uuid,
+			T_submit_source: T_source,
+		})
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			o.Rollback()
+			return ids, false
+		}
+	}
+
+	// 修改覆盖数据和备份信息
+	if T_cover == 1 {
+		_, err = o.QueryTable(new(Task.Task)).Filter("T_task_id", T_task_id).Update(orm2.Params{
+			"T_cover":  1,
+			"T_backup": T_time,
+		})
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			o.Rollback()
+			return ids, false
+		}
+		Task.Redis_Task_DelK(T_task_id)
+	} else {
+
+		_, err = o.QueryTable(new(Task.Task)).Filter("T_task_id", T_task_id).Update(orm2.Params{
+			"T_cover":  0,
+			"T_backup": "",
+		})
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			o.Rollback()
+			return ids, false
+		}
+		Task.Redis_Task_DelK(T_task_id)
+	}
+
+	o.Commit()
+
+	return ids, true
+}
+
+// ---------------- 特殊方法 -------------------
+// 添加
+func AddOrUpdate_VerifyTemplateMapData(List []VerifyTemplateMapData) (ids []int64, is bool) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateMapData))
+	o.Begin()
+	for _, v := range List {
+		var r VerifyTemplateMapData
+		// 创建验证模版数据,有则更新,没有则创建
+		err := qs.Filter("T_task_id", v.T_task_id).Filter("T_VerifyTemplate_id", v.T_VerifyTemplate_id).Filter("T_VerifyTemplateMap_id", v.T_VerifyTemplateMap_id).One(&r)
+		if err != nil {
+			if err.Error() == orm.ErrNoRows.Error() {
+				id, err := o.Insert(&v)
+				if err != nil {
+					logs.Error(lib.FuncName(), err)
+					o.Rollback()
+					return ids, false
+				}
+				ids = append(ids, id)
+			} else {
+				logs.Error(lib.FuncName(), err)
+				o.Rollback()
+				return ids, false
+			}
+		}
+
+		// 更新验证模版数据
+		if r.Id > 0 && (len(v.T_value) > 0 || v.T_start_time > 0) {
+			if v.T_start_time == 1 {
+				v.T_start_time = 0
+			}
+			v.Id = r.Id
+			//_, err = o.Update(&v, "T_flow_sort", "T_max_time", "T_min_time", "T_value")
+			_, err = o.QueryTable(new(VerifyTemplateMapData)).Filter("T_task_id", v.T_task_id).Filter("T_VerifyTemplate_id", v.T_VerifyTemplate_id).
+				Filter("T_VerifyTemplateMap_id", v.T_VerifyTemplateMap_id).Update(orm2.Params{
+				"T_flow_sort": v.T_flow_sort, "T_max_time": v.T_max_time, "T_min_time": v.T_min_time, "T_value": v.T_value, "T_start_time": v.T_start_time,
+			})
+			if err != nil {
+				logs.Error(lib.FuncName(), err)
+				o.Rollback()
+				return ids, false
+			}
+			ids = append(ids, int64(r.Id))
+		}
+
+	}
+
+	o.Commit()
+
+	return ids, true
+}
+
+// 获取列表
+func Read_VerifyTemplateMapData_List(T_source int, T_task_id, T_VerifyTemplate_id string, Map_List []VerifyTemplateMap) []VerifyTemplateMapData_R {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMapData
+	qs := o.QueryTable(new(VerifyTemplateMapData))
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_task_id", T_task_id).And("T_VerifyTemplate_id", T_VerifyTemplate_id)
+
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	if len(r) == 0 {
+		// 转换
+		var VerifyTemplateMapData_r []VerifyTemplateMapData_R
+		for k, v := range Map_List {
+			Data_r := VerifyTemplateMapToVerifyTemplateMapData_R(v)
+			Data_r.T_id = k
+			VerifyTemplateMapData_r = append(VerifyTemplateMapData_r, Data_r)
+		}
+
+		return VerifyTemplateMapData_r
+	}
+
+	// 转换
+	var VerifyTemplateMapData_r []VerifyTemplateMapData_R
+	for k, v := range Map_List {
+		Data_r := VerifyTemplateMapDataToVerifyTemplateMapData_R(v, VerifyTemplateMapDataToMap(r))
+		Data_r.T_id = k
+		VerifyTemplateMapData_r = append(VerifyTemplateMapData_r, Data_r)
+	}
+	return VerifyTemplateMapData_r
+}
+
+// 获取列表
+func Read_MapData_List(T_source int, T_task_id, T_VerifyTemplate_id string) []VerifyTemplateMapData {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMapData
+	qs := o.QueryTable(new(VerifyTemplateMapData))
+	cond := orm.NewCondition()
+
+	var source []int
+	switch T_source {
+	case 1:
+		source = []int{0, 1, 7}
+	case 2:
+		source = []int{0, 2, 3, 7}
+	case 3:
+		source = []int{3}
+	case 4:
+		source = []int{0, 5, 8}
+	case 5:
+		source = []int{0, 6, 8}
+	}
+
+	cond1 := cond.And("T_task_id", T_task_id).And("T_VerifyTemplate_id", T_VerifyTemplate_id)
+
+	if len(source) > 0 {
+		cond1 = cond1.And("T_source__in", source)
+	}
+
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	return r
+}
+
+func VerifyTemplateMapDataToMap(T []VerifyTemplateMapData) map[string]VerifyTemplateMapData {
+	maps := make(map[string]VerifyTemplateMapData, len(T))
+	for _, v := range T {
+		if _, ok := maps[v.T_VerifyTemplateMap_id]; ok {
+			continue
+		}
+		maps[v.T_VerifyTemplateMap_id] = v
+	}
+	return maps
+}
+
+// 清除T_value数据
+func Clear_VerifyTemplateMapData_T_value(T_task_id, T_VerifyTemplate_id, T_VerifyTemplateMap_id string) (err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(VerifyTemplateMapData))
+
+	var r VerifyTemplateMapData
+	// 创建验证模版数据,有则更新,没有则创建
+	err = qs.Filter("T_task_id", T_task_id).Filter("T_VerifyTemplate_id", T_VerifyTemplate_id).Filter("T_VerifyTemplateMap_id", T_VerifyTemplateMap_id).One(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	r.T_value = ""
+	_, err = o.Update(&r, "T_value")
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return err
+	}
+	return nil
+}

+ 238 - 0
models/VerifyTemplate/VerifyTemplateMapDataHistory.go

@@ -0,0 +1,238 @@
+package VerifyTemplate
+
+import (
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	_ "github.com/go-sql-driver/mysql"
+	"time"
+)
+
+// 模版
+type VerifyTemplateMapDataHistory struct {
+	Id                     int    `orm:"column(ID);size(11);auto;pk"`
+	T_source               int    `orm:"size(4);"`             // 来源 0-所有 1-方案 2-报告 3-表单
+	T_task_id              string `orm:"index,size(256);null"` // 任务id
+	T_VerifyTemplate_id    string `orm:"size(256);null"`       // 模版id
+	T_VerifyTemplateMap_id string `orm:"size(256);null"`       // 标签id
+	T_value                string `orm:"type(text);null"`      // 内容
+	T_Required             int    `orm:"size(2);default(0)"`   // 必填项  1 必填   0 非必填
+	T_Construction         int    `orm:"size(2);default(0)"`   // 实施(是否在APP 上显示)  1 显示   0 不显示
+
+	T_uuid          string `orm:"index,size(256);null"` // 提交人
+	T_time          string `orm:"index,size(256);null"` // 提交时间
+	T_submit_source int    `orm:"size(4);"`             // 提交来源
+	// 验证流程
+	T_flow_sort int `orm:"size(2);default(0)"` // 验证流程排序
+	T_max_time  int `orm:"size(256);null"`     // 验证流程最大时间
+	T_min_time  int `orm:"size(256);null"`     // 验证流程最小时间
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+// 历史记录
+type VerifyDataHistoryRecord struct {
+	Id        int    `orm:"column(ID);size(11);auto;pk"`
+	T_source  int    `orm:"size(4);"`             // 来源 0-所有 1-方案 2-报告 3-表单
+	T_task_id string `orm:"index,size(256);null"` // 任务id
+
+	T_uuid          string `orm:"index,size(256);null"` // 提交人
+	T_time          string `orm:"index,size(256);null"` // 提交时间
+	T_submit_source int    `orm:"size(4);"`             // 提交来源
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type VerifyTemplateMapDataHistory_R struct {
+	T_id                   int
+	T_VerifyTemplateMap_id string // 标签id
+	T_source               int
+	T_label                int    //
+	T_name                 string // 标题
+	T_text                 string // 标题
+	T_value                string //
+	T_Required             int    //
+	T_Construction         int    //
+	// 验证流程
+	T_flow_sort int // 验证流程排序
+	T_max_time  int // 验证流程最大时间
+	T_min_time  int // 验证流程最小时间
+}
+
+func (t *VerifyTemplateMapDataHistory) TableName() string {
+	return "verify_template_map_data_history" // 数据库名称   // ************** 替换 FormulaList **************
+}
+func (t *VerifyDataHistoryRecord) TableName() string {
+	return "verify_data_history_record" // 数据库名称   // ************** 替换 FormulaList **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(VerifyTemplateMapDataHistory))
+	orm.RegisterModel(new(VerifyDataHistoryRecord))
+
+}
+
+// -------------------------------------------------------------
+func VerifyTemplateMapToVerifyTemplateMapDataHistory_R(T VerifyTemplateMap) (T_r VerifyTemplateMapDataHistory_R) {
+	T_r.T_VerifyTemplateMap_id = T.T_id
+	T_r.T_source = T.T_source
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_Required = T.T_Required
+	T_r.T_Construction = T.T_Construction
+
+	T_r.T_flow_sort = T.T_flow_sort
+	T_r.T_max_time = T.T_max_time
+	T_r.T_min_time = T.T_min_time
+
+	T_r.T_value = ""
+	return T_r
+}
+
+func VerifyTemplateMapDataToVerifyTemplateMapDataHistory_R(T VerifyTemplateMap, VerifyTemplateMapDataHistory map[string]string) (T_r VerifyTemplateMapDataHistory_R) {
+	T_r.T_VerifyTemplateMap_id = T.T_id
+	T_r.T_source = T.T_source
+	T_r.T_label = T.T_label
+	T_r.T_name = T.T_name
+	T_r.T_text = T.T_text
+	T_r.T_Required = T.T_Required
+	T_r.T_Construction = T.T_Construction
+
+	T_r.T_flow_sort = T.T_flow_sort
+	T_r.T_max_time = T.T_max_time
+	T_r.T_min_time = T.T_min_time
+
+	T_r.T_value = ""
+	if v, ok := VerifyTemplateMapDataHistory[T.T_id]; ok {
+		T_r.T_value = v
+	}
+	return T_r
+}
+
+// 获取列表
+func Read_VerifyTemplateMapDataHistory_List(T_source int, T_task_id, T_VerifyTemplate_id, T_time string,
+	Map_List []VerifyTemplateMap) []VerifyTemplateMapDataHistory_R {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMapDataHistory
+	qs := o.QueryTable(new(VerifyTemplateMapDataHistory))
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_task_id", T_task_id).And("T_VerifyTemplate_id", T_VerifyTemplate_id).And("T_time", T_time)
+
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	if len(r) == 0 {
+		// 转换
+		var VerifyTemplateMapData_r []VerifyTemplateMapDataHistory_R
+		for k, v := range Map_List {
+			Data_r := VerifyTemplateMapToVerifyTemplateMapDataHistory_R(v)
+			Data_r.T_id = k
+			VerifyTemplateMapData_r = append(VerifyTemplateMapData_r, Data_r)
+		}
+
+		return VerifyTemplateMapData_r
+	}
+
+	// 转换
+	var VerifyTemplateMapDataHistory_r []VerifyTemplateMapDataHistory_R
+	for k, v := range Map_List {
+		Data_r := VerifyTemplateMapDataToVerifyTemplateMapDataHistory_R(v, VerifyTemplateMapDataHistoryToMap(r))
+		Data_r.T_id = k
+		VerifyTemplateMapDataHistory_r = append(VerifyTemplateMapDataHistory_r, Data_r)
+	}
+	return VerifyTemplateMapDataHistory_r
+}
+
+// 获取列表
+func Read_MapDataHistory_List(T_source int, T_task_id, T_VerifyTemplate_id, T_time string) []VerifyTemplateMapDataHistory {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+	var r []VerifyTemplateMapDataHistory
+	qs := o.QueryTable(new(VerifyTemplateMapDataHistory))
+	cond := orm.NewCondition()
+
+	var source []int
+	switch T_source {
+	case 1:
+		source = []int{0, 1, 7}
+	case 2:
+		source = []int{0, 2, 3, 7}
+	case 3:
+		source = []int{3}
+	case 4:
+		source = []int{0, 5, 8}
+	case 5:
+		source = []int{0, 6, 8}
+	}
+
+	cond1 := cond.And("T_task_id", T_task_id).And("T_VerifyTemplate_id", T_VerifyTemplate_id).And("T_time", T_time)
+	if len(source) > 0 {
+		cond1 = cond1.And("T_source__in", source)
+	}
+	qs.SetCond((*orm2.Condition)(cond1)).All(&r)
+
+	return r
+}
+
+func VerifyTemplateMapDataHistoryToMap(T []VerifyTemplateMapDataHistory) map[string]string {
+	maps := make(map[string]string, len(T))
+	for _, v := range T {
+		if _, ok := maps[v.T_VerifyTemplateMap_id]; ok {
+			continue
+		}
+		maps[v.T_VerifyTemplateMap_id] = v.T_value
+	}
+	return maps
+}
+
+type VerifyTemplateMapDataHistory_History_List_Res struct {
+	T_uuid      string
+	T_time      string
+	T_uuid_name string
+}
+
+// 获取列表
+func Read_VerifyTemplateMapDataHistory_History_List(T_task_id string, T_source int, AdminMap map[string]string) (lists []VerifyTemplateMapDataHistory_History_List_Res) {
+	o := orm.NewOrm()
+
+	var pl_lists []VerifyTemplateMapDataHistory_History_List_Res
+	//_, err := o.Raw("SELECT DISTINCT t_uuid,t_time FROM verify_template_map_data_history where t_task_id = ? and t_source = ? order by t_time desc LIMIT 0,1000 ", T_task_id, T_source).
+	_, err := o.Raw("SELECT DISTINCT t_uuid,t_time FROM verify_template_map_data_history where t_task_id = ? order by t_time desc LIMIT 0,1000 ", T_task_id).
+		QueryRows(&pl_lists)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return pl_lists
+	}
+
+	for i := 0; i < len(pl_lists); i++ {
+		pl_lists[i].T_uuid_name = AdminMap[pl_lists[i].T_uuid]
+	}
+
+	return pl_lists
+}
+func Read_VerifyTemplateMapDataHistory_History_List2(T_task_id string, T_source int, AdminMap map[string]string) (lists []VerifyTemplateMapDataHistory_History_List_Res) {
+	o := orm.NewOrm()
+
+	var pl_lists []VerifyTemplateMapDataHistory_History_List_Res
+	//_, err := o.Raw("SELECT DISTINCT t_uuid,t_time FROM verify_template_map_data_history where t_task_id = ? and t_source = ? order by t_time desc LIMIT 0,1000 ", T_task_id, T_source).
+	_, err := o.Raw("SELECT t_uuid,t_time FROM verify_data_history_record where t_task_id = ? order by t_time desc LIMIT 0,1000 ", T_task_id).
+		QueryRows(&pl_lists)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return pl_lists
+	}
+
+	for i := 0; i < len(pl_lists); i++ {
+		pl_lists[i].T_uuid_name = AdminMap[pl_lists[i].T_uuid]
+	}
+
+	return pl_lists
+}

+ 39 - 0
routers/Account.go

@@ -0,0 +1,39 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	//   -----------3、用户管理
+	//3.1用户账户只可以由管理员添加。
+	//3.2管理员账户只可以有一个。
+	//3.3用户可添加和删除子账号。
+	//3.4用户可对子账号分配管理权限,包括:设备数据查看权限,设备运行参数修改权限。
+
+	//-----------
+
+	//---------管理员
+	beego.Router("/Login_Admin_verification", &controllers.AccountController{}, "*:Login_Admin_verification") // 获取未读消息
+
+	// ---- 用户
+	beego.Router("/Login_verification", &controllers.AccountController{}, "*:Login_verification") // 获取未读消息
+
+	// - 管理员
+	beego.Router("/Admin/List", &controllers.AccountController{}, "*:List")              // 管理员列表
+	beego.Router("/Admin/Add", &controllers.AccountController{}, "*:Add")                // 添加管理员
+	beego.Router("/Admin/Up", &controllers.AccountController{}, "*:Up")                  // 编辑管理员
+	beego.Router("/Admin/Get", &controllers.AccountController{}, "*:Get")                // 编辑管理员
+	beego.Router("/Admin/Del", &controllers.AccountController{}, "*:Del")                // 删除管理员
+	beego.Router("/Admin/List_All", &controllers.AccountController{}, "*:List_All")      // 管理员所有列表
+	beego.Router("/Admin/Up_Password", &controllers.AccountController{}, "*:UpPassword") // 管理员修改密码
+	beego.Router("/Admin/Delivery", &controllers.AccountController{}, "*:Delivery")      // 交付审核人
+	// - 用户权限
+	beego.Router("/UserPower/List_All", &controllers.AccountController{}, "*:UserPower_List_All") // 用户权限所有列表
+
+	//-----------消息通知
+	beego.Router("/News/List", &controllers.NewsController{}, "*:List")
+	beego.Router("/News/See", &controllers.NewsController{}, "*:See")
+
+}

+ 22 - 0
routers/AllotTask.go

@@ -0,0 +1,22 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	beego.Router("/AllotTask/List", &controllers.AllotTaskController{}, "*:List")                                   // 列表
+	beego.Router("/AllotTask/Get", &controllers.AllotTaskController{}, "*:Get")                                     // 获取
+	beego.Router("/AllotTask/Add", &controllers.AllotTaskController{}, "*:Add")                                     // 添加
+	beego.Router("/AllotTask/Up", &controllers.AllotTaskController{}, "*:Up")                                       // 编辑
+	beego.Router("/AllotTask/Del", &controllers.AllotTaskController{}, "*:Del")                                     // 删除
+	beego.Router("/AllotTask/Receive", &controllers.AllotTaskController{}, "*:Receive")                             // 接收
+	beego.Router("/AllotTask/Stat", &controllers.AllotTaskController{}, "*:Statistics")                             // 统计
+	beego.Router("/AllotTask/GetUserList", &controllers.AllotTaskController{}, "*:GetAllotTaskUserList")            // 获取任务负责人列表
+	beego.Router("/AllotTask/UploadConfirmForm", &controllers.AllotTaskController{}, "*:UploadConfirmForm")         // 上传信息确认表
+	beego.Router("/AllotTask/Copy", &controllers.AllotTaskController{}, "*:Copy")                                   // 复制
+	beego.Router("/AllotTask/GetByInfoCollectionId", &controllers.AllotTaskController{}, "*:GetByInfoCollectionId") // 通过信息采集ID获取指派任务
+
+}

+ 21 - 0
routers/Certificate.go

@@ -0,0 +1,21 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	// - 校准证书
+	beego.Router("/Certificate/List", &controllers.CertificateController{}, "*:List")                                   // 校准证书列表
+	beego.Router("/Certificate/Get", &controllers.CertificateController{}, "*:Get")                                     // 获取最新校准证书
+	beego.Router("/Certificate/Add", &controllers.CertificateController{}, "*:Add")                                     // 添加校准证书
+	beego.Router("/Certificate/Edit", &controllers.CertificateController{}, "*:Edit")                                   // 编辑校准证书
+	beego.Router("/Certificate/Del", &controllers.CertificateController{}, "*:Del")                                     // 删除校准证书
+	beego.Router("/Certificate/ListWithoutDeviceList", &controllers.CertificateController{}, "*:ListWithoutDeviceList") // 校准证书除开设备列表
+	// - 校准证书pdf
+	beego.Router("/Certificate/Pdf_List", &controllers.CertificateController{}, "*:Pdf_List") // 校准证书pdf列表
+	beego.Router("/Certificate/Pdf_Add", &controllers.CertificateController{}, "*:Pdf_Add")   // 添加校准证书pdf
+	beego.Router("/Certificate/Pdf_Up", &controllers.CertificateController{}, "*:Pdf_Up")     // 编辑校准证书pdf
+	beego.Router("/Certificate/Pdf_Del", &controllers.CertificateController{}, "*:Pdf_Del")   // 删除校准证书pdf
+}

+ 41 - 0
routers/Device.go

@@ -0,0 +1,41 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+
+	// 设备分类
+	beego.Router("/DeviceClass/List", &controllers.DeviceClassController{}, "*:List") // 设备分类列表
+	beego.Router("/DeviceClass/Get", &controllers.DeviceClassController{}, "*:Get")   // 获取设备分类
+	beego.Router("/DeviceClass/Add", &controllers.DeviceClassController{}, "*:Add")   // 添加设备分类
+	beego.Router("/DeviceClass/Up", &controllers.DeviceClassController{}, "*:Up")     // 编辑设备分类
+	beego.Router("/DeviceClass/Del", &controllers.DeviceClassController{}, "*:Del")   // 删除设备分类
+	beego.Router("/DeviceClass/Stat", &controllers.DeviceClassController{}, "*:Stat") // 设备统计
+
+	// 设备分类 - 设备列表
+	beego.Router("/DeviceClassList/List", &controllers.DeviceClassController{}, "*:List_List")                                        // 设备分类列表
+	beego.Router("/DeviceClassList/Maximum", &controllers.DeviceClassController{}, "*:List_Maximum")                                  // 设备分类列表
+	beego.Router("/DeviceClassList/Add", &controllers.DeviceClassController{}, "*:List_Add")                                          // 添加设备分类列表
+	beego.Router("/DeviceClassList/Up", &controllers.DeviceClassController{}, "*:List_Up")                                            // 编辑设备分类列表
+	beego.Router("/DeviceClassList/Up_terminal", &controllers.DeviceClassController{}, "*:List_Up_terminal")                          // 编辑设备分类列表
+	beego.Router("/DeviceClassList/Del", &controllers.DeviceClassController{}, "*:List_Del")                                          // 删除设备分类列表
+	beego.Router("/DeviceClassList/Copy", &controllers.DeviceClassController{}, "*:List_Copy")                                        // 复制
+	beego.Router("/DeviceClassList/Template_Download", &controllers.DeviceClassController{}, "*:List_Template_Download")              // 添加设备列表模版
+	beego.Router("/DeviceClassList/Del_Duplication", &controllers.DeviceClassController{}, "*:List_Del_Duplication")                  // 删除重复设备列表
+	beego.Router("/DeviceClassList/Sync_CertificatePdf_ToList", &controllers.DeviceClassController{}, "*:Sync_CertificatePdf_ToList") // 删除重复设备列表
+	beego.Router("/DeviceClassList/Auto_fill_Remark", &controllers.DeviceClassController{}, "*:Auto_fill_Remark")                     // 通过模版布点自动填写到设备备注
+
+	// - 设备管理
+	beego.Router("/Device/List", &controllers.DeviceController{}, "*:List") // 设备列表
+	beego.Router("/Device/Add", &controllers.DeviceController{}, "*:Add")   // 添加设备
+	beego.Router("/Device/Get", &controllers.DeviceController{}, "*:Get")   // 编辑设备
+	beego.Router("/Device/Up", &controllers.DeviceController{}, "*:Up")     // 编辑设备
+	beego.Router("/Device/Del", &controllers.DeviceController{}, "*:Del")   // 删除设备
+
+	beego.Router("/Device/Class", &controllers.DeviceController{}, "*:Device_Class") // 设备分类
+	beego.Router("/Device/Data", &controllers.DeviceController{}, "*:Device_Data")   // 设备数据
+
+}

+ 19 - 0
routers/Distributor.go

@@ -0,0 +1,19 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	// 模版路由
+	beego.Router("/Distributor/All", &controllers.DistributorController{}, "*:List_All")                                      // 经销商列表
+	beego.Router("/Distributor/List", &controllers.DistributorController{}, "*:List")                                         // 经销商列表
+	beego.Router("/Distributor/Add", &controllers.DistributorController{}, "*:Add")                                           // 添加经销商
+	beego.Router("/Distributor/Up", &controllers.DistributorController{}, "*:Up")                                             // 编辑经销商
+	beego.Router("/Distributor/Del", &controllers.DistributorController{}, "*:Del")                                           // 删除经销商
+	beego.Router("/Distributor/BindVerifyTemplate", &controllers.DistributorController{}, "*:BindVerifyTemplate")             // 删除经销商
+	beego.Router("/Distributor/ReadVerifyTemplate", &controllers.DistributorController{}, "*:ReadVerifyTemplate")             // 删除经销商
+	beego.Router("/Distributor/ReadVerifyTemplateClass", &controllers.DistributorController{}, "*:ReadVerifyTemplateClass")   // 删除经销商
+	beego.Router("/Distributor/VerifyTemplateClass_List", &controllers.DistributorController{}, "*:VerifyTemplateClass_List") // 删除经销商
+}

+ 41 - 0
routers/InfoCollection.go

@@ -0,0 +1,41 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	beego.Router("/InfoCollection/List", &controllers.InfoCollectionController{}, "*:List")                       // 信息采集列表
+	beego.Router("/InfoCollection/UserList", &controllers.InfoCollectionController{}, "*:UserList")               // 信息采集列表-个人
+	beego.Router("/InfoCollection/Get", &controllers.InfoCollectionController{}, "*:Get")                         // 获取信息采集
+	beego.Router("/InfoCollection/Add", &controllers.InfoCollectionController{}, "*:Add")                         // 添加信息采集
+	beego.Router("/InfoCollection/Up", &controllers.InfoCollectionController{}, "*:Up")                           // 编辑信息采集
+	beego.Router("/InfoCollection/Del", &controllers.InfoCollectionController{}, "*:Del")                         // 删除信息采集
+	beego.Router("/InfoCollection/UpStatus", &controllers.InfoCollectionController{}, "*:UpStatus")               // 修改信息采集状态
+	beego.Router("/InfoCollection/AuditRecordList", &controllers.InfoCollectionController{}, "*:AuditRecordList") // 信息采集审核记录
+	beego.Router("/InfoCollection/Statistics", &controllers.InfoCollectionController{}, "*:Statistics")           // 小程序统计
+	beego.Router("/InfoCollection/Copy", &controllers.InfoCollectionController{}, "*:Copy")                       // 复制信息采集
+
+	beego.Router("/InfoTemplate/Class_List", &controllers.InfoTemplateController{}, "*:Class_List") // 信息采集分类列表
+	beego.Router("/InfoTemplate/Class_Add", &controllers.InfoTemplateController{}, "*:Class_Add")   // 信息采集分类添加
+	beego.Router("/InfoTemplate/Class_Up", &controllers.InfoTemplateController{}, "*:Class_Up")     // 信息采集分类修改
+	beego.Router("/InfoTemplate/Class_Del", &controllers.InfoTemplateController{}, "*:Class_Del")   // 信息采集分类删除
+	beego.Router("/InfoTemplate/Class_Copy", &controllers.InfoTemplateController{}, "*:Class_Copy") // 复制信息采集分类
+
+	beego.Router("/InfoTemplate/List", &controllers.InfoTemplateController{}, "*:List") // 模版列表
+	beego.Router("/InfoTemplate/Add", &controllers.InfoTemplateController{}, "*:Add")   // 模版添加
+	beego.Router("/InfoTemplate/Up", &controllers.InfoTemplateController{}, "*:Up")     // 模版编辑
+	beego.Router("/InfoTemplate/Del", &controllers.InfoTemplateController{}, "*:Del")   // 模版修改
+	beego.Router("/InfoTemplate/Copy", &controllers.InfoTemplateController{}, "*:Copy") // 模版复制
+
+	beego.Router("/InfoTemplate/Map_List", &controllers.InfoTemplateController{}, "*:Map_List") // 标签列表
+	beego.Router("/InfoTemplate/Map_Add", &controllers.InfoTemplateController{}, "*:Map_Add")   // 标签添加
+	beego.Router("/InfoTemplate/Map_Up", &controllers.InfoTemplateController{}, "*:Map_Up")     // 标签修改
+	beego.Router("/InfoTemplate/Map_Del", &controllers.InfoTemplateController{}, "*:Map_Del")   // 标签删除
+
+	beego.Router("/InfoTemplateMapData/List", &controllers.InfoTemplateController{}, "*:Map_Data_List") // 标签数据列表
+	beego.Router("/InfoTemplateMapData/Pu", &controllers.InfoTemplateController{}, "*:Map_Data_Pu")     // 添加标签数据
+	beego.Router("/InfoTemplateMapData/Copy", &controllers.InfoTemplateController{}, "*:Map_Data_Copy") // 复制标签数据
+
+}

+ 11 - 0
routers/Logs.go

@@ -0,0 +1,11 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	beego.Router("/Logs/List", &controllers.LogsController{}, "*:List")         //日志列表
+	beego.Router("/UserLogs/List", &controllers.LogsController{}, "*:UserLogs") //用户日志列表
+}

+ 77 - 0
routers/Task.go

@@ -0,0 +1,77 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+
+	beego.Router("/UpFileToken", &controllers.UpFileController{}, "*:ConfigUpFileToken") // 上传文件
+
+	beego.Router("/Task/List", &controllers.TaskController{}, "*:List")                                             // 任务列表
+	beego.Router("/Task/Get", &controllers.TaskController{}, "*:Get")                                               // 获取任务
+	beego.Router("/Task/Add", &controllers.TaskController{}, "*:Add")                                               // 添加任务
+	beego.Router("/Task/Up", &controllers.TaskController{}, "*:Up")                                                 // 编辑任务
+	beego.Router("/Task/Del", &controllers.TaskController{}, "*:Del")                                               // 删除任务
+	beego.Router("/Task/Copy", &controllers.TaskController{}, "*:Copy")                                             // 复制任务
+	beego.Router("/Task/UpCollectionState", &controllers.TaskController{}, "*:UpCollectionState")                   // 修改任务状态
+	beego.Router("/Task/UpDeliveryState", &controllers.TaskController{}, "*:UpDeliveryState")                       // 修改交付审核状态
+	beego.Router("/Task/UpExaminingReportState", &controllers.TaskController{}, "*:UpExaminingReportState")         // 修改交付审核状态
+	beego.Router("/Task/UpOriginalRecordState", &controllers.TaskController{}, "*:UpOriginalRecordState")           // 修改交付审核状态
+	beego.Router("/Task/AddData_Tool", &controllers.TaskController{}, "*:AddData_Tool")                             // 1.0 添加任务数据
+	beego.Router("/Task/ReceiptInfoCollection", &controllers.TaskController{}, "*:ReceiptInfoCollection")           // 接收信息采集
+	beego.Router("/Task/SyncInfoCollection", &controllers.TaskController{}, "*:SyncInfoCollection")                 // 同步信息采集
+	beego.Router("/Task/UpSchemeState", &controllers.TaskController{}, "*:UpSchemeState")                           // 修改验证方案状态
+	beego.Router("/Task/EnterArea", &controllers.TaskController{}, "*:EnterArea")                                   // 进场
+	beego.Router("/Task/StartVerify", &controllers.TaskController{}, "*:StartVerify")                               // 开始验证-实施开始时间
+	beego.Router("/Task/UpReportingState", &controllers.TaskController{}, "*:UpReportingState")                     // 修改验证报告状态
+	beego.Router("/Task/AuditRecordList", &controllers.TaskController{}, "*:AuditRecordList")                       // 审核记录
+	beego.Router("/Task/GetTaskUserList", &controllers.TaskController{}, "*:GetTaskUserList")                       // 获取任务负责人列表
+	beego.Router("/Task/Stat", &controllers.TaskController{}, "*:Stat")                                             // 报告统计
+	beego.Router("/Task/Stat_Excel", &controllers.TaskController{}, "*:Stat_Excel")                                 // 报告统计-excel
+	beego.Router("/Task/StatisticalRanking", &controllers.TaskController{}, "*:StatisticalRanking")                 // 报告统计-excel
+	beego.Router("/Task/GenT_report_number", &controllers.TaskController{}, "*:GenT_report_number")                 // 生成报告编号
+	beego.Router("/Task/SyncPDFWatermark", &controllers.TaskController{}, "*:SyncPDFWatermark")                     // 生成报告编号
+	beego.Router("/Task/SaveElectronicSignaturePDF", &controllers.TaskController{}, "*:SaveElectronicSignaturePDF") // 生成报告编号
+
+	// 日志
+	beego.Router("/TaskLogs/List", &controllers.TaskController{}, "*:Logs_List")
+
+	// 提取数据
+	beego.Router("/TaskData/Extract_TaskData", &controllers.TaskDataController{}, "*:Extract_TaskData_Back")
+	beego.Router("/TaskData/Up_TaskData", &controllers.TaskDataController{}, "*:TaskData_Up_TaskData_Back")
+	beego.Router("/TaskData/TaskDataClass_List", &controllers.TaskDataController{}, "*:TaskDataClass_List") // 任务数据分类列表
+	beego.Router("/TaskData/List", &controllers.TaskDataController{}, "*:TaskData_List")                    // 任务数据列表
+	beego.Router("/TaskData/Add", &controllers.TaskDataController{}, "*:TaskData_Add")                      // 添加任务数据
+	beego.Router("/TaskData/AddS", &controllers.TaskDataController{}, "*:TaskData_AddS")                    // 批量添加任务数据
+	beego.Router("/TaskData/Up", &controllers.TaskDataController{}, "*:TaskData_Up")                        // 编辑任务数据
+	beego.Router("/TaskData/Del", &controllers.TaskDataController{}, "*:TaskData_Del")                      // 删除任务数据
+	beego.Router("/TaskData/DelTid", &controllers.TaskDataController{}, "*:TaskData_Del_t_id")              // 根据id删除任务数据
+
+	beego.Router("/TaskData/Export_Data_Excel", &controllers.TaskDataController{}, "*:Export_Data_Excel") // 导出任务数据excel
+	beego.Router("/TaskData/Export_Data_PDF", &controllers.TaskDataController{}, "*:Export_Data_PDF")     // 导出任务数据pdf
+
+	// 导出温度
+	beego.Router("/TaskData/Temperature_Pdf", &controllers.TaskDataController{}, "*:TaskData_Temperature_Pdf")
+	// 导出湿度
+	beego.Router("/TaskData/Humidity_Pdf", &controllers.TaskDataController{}, "*:TaskData_Humidity_Pdf")
+
+	// 校验
+	beego.Router("/TaskData/Check", &controllers.TaskDataController{}, "*:Check") // 检查数据
+
+	// 公司用户
+	beego.Router("/UserTask/List", &controllers.TaskController{}, "*:UserTaskList")              // 公司用户任务列表
+	beego.Router("/UserTaskData/List", &controllers.TaskDataController{}, "*:UserTaskData_List") // 公司用户任务数据列表
+
+	beego.Router("/Task/jpg", &controllers.TaskController{}, "*:DeviceData_JPG")            // 任务生成图片
+	beego.Router("/Task/JPG/State", &controllers.TaskController{}, "*:DeviceData_JPGState") // 任务 图片生成状态
+	beego.Router("/Task/TaskData/Stat", &controllers.TaskController{}, "*:TaskData_Stat")   // 统计任务数据
+
+	// 暂停申请
+	beego.Router("/TaskTime/Get", &controllers.TaskController{}, "*:TaskTimeList")              // 任务列表
+	beego.Router("/TaskTime/Add", &controllers.TaskController{}, "*:TaskTimeAdd")               // 添加任务
+	beego.Router("/TaskTime/End", &controllers.TaskController{}, "*:TaskTimeEnd")               // 编辑任务
+	beego.Router("/Task/Auto_fill_deploy", &controllers.TaskController{}, "*:Auto_fill_deploy") // 编辑任务
+
+}

+ 23 - 0
routers/User.go

@@ -0,0 +1,23 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+	beego.Router("/User/List", &controllers.UserController{}, "*:List")                 // 用户列表
+	beego.Router("/User/Add", &controllers.UserController{}, "*:Add")                   // 添加用户
+	beego.Router("/User/Up", &controllers.UserController{}, "*:Up")                     // 编辑用户
+	beego.Router("/User/Del", &controllers.UserController{}, "*:Del")                   // 删除用户
+	beego.Router("/User/Up_Password", &controllers.UserController{}, "*:UpPassword")    // 用户-修改密码
+	beego.Router("/User/TreeList", &controllers.UserController{}, "*:TreeList")         // 树形结构展示公司列表
+	beego.Router("/User/MoveToParent", &controllers.UserController{}, "*:MoveToParent") // 移动公司到另一个公司下面
+
+	beego.Router("/UserSignature/List", &controllers.UserController{}, "*:Signature_List") // 用户签名列表
+	beego.Router("/UserSignature/Add", &controllers.UserController{}, "*:Signature_Add")   // 添加用户签名
+	beego.Router("/UserSignature/Up", &controllers.UserController{}, "*:Signature_Up")     // 编辑用户签名
+	beego.Router("/UserSignature/Del", &controllers.UserController{}, "*:Signature_Del")   // 删除用户签名
+
+}

+ 44 - 0
routers/VerifyTemplate.go

@@ -0,0 +1,44 @@
+package routers
+
+import (
+	"ColdVerify_server/controllers"
+	beego "github.com/beego/beego/v2/server/web"
+)
+
+func init() {
+
+	// 模版路由
+	beego.Router("/Template/List_", &controllers.TemplateController{}, "*:List_") // 获取未读消息
+	beego.Router("/Template/List", &controllers.TemplateController{}, "*:List")   // 模版列表
+	beego.Router("/Template/Get", &controllers.TemplateController{}, "*:Get")     // 获取模版
+	beego.Router("/Template/Add", &controllers.TemplateController{}, "*:Add")     // 添加模版
+	beego.Router("/Template/Up", &controllers.TemplateController{}, "*:Up")       // 编辑模版
+	beego.Router("/Template/Del", &controllers.TemplateController{}, "*:Del")     // 删除模版
+
+	beego.Router("/VerifyTemplate/Class_List", &controllers.VerifyTemplateController{}, "*:Class_List") // 分类列表
+	beego.Router("/VerifyTemplate/Class_Add", &controllers.VerifyTemplateController{}, "*:Class_Add")   // 分类添加
+	beego.Router("/VerifyTemplate/Class_Up", &controllers.VerifyTemplateController{}, "*:Class_Up")     // 分类修改
+	beego.Router("/VerifyTemplate/Class_Del", &controllers.VerifyTemplateController{}, "*:Class_Del")   // 分类删除
+	beego.Router("/VerifyTemplate/Class_Copy", &controllers.VerifyTemplateController{}, "*:Class_Copy") // 复制信息采集分类
+
+	beego.Router("/VerifyTemplate/List", &controllers.VerifyTemplateController{}, "*:List") // 模版列表
+	beego.Router("/VerifyTemplate/Add", &controllers.VerifyTemplateController{}, "*:Add")   // 模版添加
+	beego.Router("/VerifyTemplate/Up", &controllers.VerifyTemplateController{}, "*:Up")     // 模版编辑
+	beego.Router("/VerifyTemplate/Del", &controllers.VerifyTemplateController{}, "*:Del")   // 模版修改
+	beego.Router("/VerifyTemplate/Get", &controllers.VerifyTemplateController{}, "*:Get")   // 模版修改
+	beego.Router("/VerifyTemplate/Copy", &controllers.VerifyTemplateController{}, "*:Copy") // 模版复制
+
+	beego.Router("/VerifyTemplate/Map_List", &controllers.VerifyTemplateController{}, "*:Map_List") // 标签列表
+	beego.Router("/VerifyTemplate/Map_Add", &controllers.VerifyTemplateController{}, "*:Map_Add")   // 标签添加
+	beego.Router("/VerifyTemplate/Map_Up", &controllers.VerifyTemplateController{}, "*:Map_Up")     // 标签修改
+	beego.Router("/VerifyTemplate/Map_Del", &controllers.VerifyTemplateController{}, "*:Map_Del")   // 标签删除
+
+	beego.Router("/VerifyTemplateMapData/List", &controllers.VerifyTemplateController{}, "*:Map_Data_List")                           // 标签数据列表
+	beego.Router("/VerifyTemplateMapData/Pu", &controllers.VerifyTemplateController{}, "*:Map_Data_Pu")                               // 添加标签数据
+	beego.Router("/VerifyTemplateMapData/Copy", &controllers.VerifyTemplateController{}, "*:Map_Data_Copy")                           // 复制标签数据
+	beego.Router("/VerifyTemplateMapData/Clear_Value", &controllers.VerifyTemplateController{}, "*:Map_Data_Clear_Value")             // 复制标签数据
+	beego.Router("/VerifyTemplateMapData/History_List", &controllers.VerifyTemplateController{}, "*:Map_Data_History_List")           // 历史提交列表
+	beego.Router("/VerifyTemplateMapData/History_Data_List", &controllers.VerifyTemplateController{}, "*:Map_Data_History_Data_List") // 历史提交列表
+	beego.Router("/VerifyTemplateMapData/History_Recover", &controllers.VerifyTemplateController{}, "*:Map_Data_History_Recover")     // 历史提交列表
+	beego.Router("/VerifyTemplateMapData/Map_Data_Cover", &controllers.VerifyTemplateController{}, "*:Map_Data_Cover")                // 覆盖数据
+}

+ 86 - 0
routers/openapi.go

@@ -0,0 +1,86 @@
+package routers
+
+import (
+	"ColdVerify_server/conf"
+	"ColdVerify_server/controllers"
+	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/hex"
+	"errors"
+	"strconv"
+	"time"
+
+	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
+)
+
+const apiKeyHeader = "X-API-KEY"
+const apiSignatureHeader = "X-API-SIGNATURE"
+const apiTimestampHeader = "X-API-TIMESTAMP"
+
+func isValidSignature(apiKey, signature, timestamp string) bool {
+	// 使用提供的 API Key 查找对应的 API Secret
+	if apiKey != conf.OpenApi_Key {
+		return false
+	}
+	secret := conf.OpenApi_Secret
+
+	// 计算签名,签名内容是 "apiKey + timestamp"
+	message := apiKey + timestamp
+	mac := hmac.New(sha256.New, []byte(secret))
+	mac.Write([]byte(message))
+	expectedSignature := hex.EncodeToString(mac.Sum(nil))
+	logs.Println("apiKey:", apiKey)
+	logs.Println("secret:", secret)
+	logs.Println("时间戳:", timestamp)
+	logs.Println("生成的签名:", expectedSignature)
+	logs.Println("传递的签名:", signature)
+	// 验证客户端提供的签名是否与预期签名匹配
+	return hmac.Equal([]byte(signature), []byte(expectedSignature))
+}
+func ApiKeyAuthMiddleware(ctx *context.Context) {
+	apiKey := ctx.Input.Query(apiKeyHeader)
+	signature := ctx.Input.Query(apiSignatureHeader)
+	timestamp := ctx.Input.Query(apiTimestampHeader)
+
+	// 检查 API Key, 签名和时间戳是否存在
+	if apiKey == "" || signature == "" || timestamp == "" {
+		err := errors.New("API Key, Signature, and Timestamp required")
+		data := lib.JSONS{Code: 202, Msg: err.Error()}
+		ctx.Output.JSON(data, true, false)
+		return
+	}
+
+	// 校验请求的签名是否有效
+	if !isValidSignature(apiKey, signature, timestamp) {
+		err := errors.New("Invalid Signature")
+		data := lib.JSONS{Code: 202, Msg: err.Error()}
+		ctx.Output.JSON(data, true, false)
+		return
+	}
+
+	// 校验时间戳是否在合理范围内(防止重放攻击)
+	sec, _ := strconv.ParseInt(timestamp, 10, 64)
+	reqTime := time.Unix(sec, 0)
+	if time.Since(reqTime) > 5*time.Minute {
+		err := errors.New("Request too old or invalid timestamp")
+		data := lib.JSONS{Code: 202, Msg: err.Error()}
+		ctx.Output.JSON(data, true, false)
+		return
+	}
+}
+
+func init() {
+	//beego.InsertFilter("/openapi", beego.BeforeRouter, ApiKeyAuthMiddleware)
+
+	ns := beego.NewNamespace("/openapi",
+		beego.NSBefore(ApiKeyAuthMiddleware),
+		beego.NSRouter("/admin/list", &controllers.AccountController{}, "*:Account_List_All_For_ERP"), // 管理员所有列表
+		beego.NSRouter("/company/list", &controllers.UserController{}, "*:User_List_All_For_ERP"),     // 公司所有列表
+		beego.NSRouter("/task/list", &controllers.TaskController{}, "*:Task_List_All_For_ERP"),        // 公司所有列表
+		beego.NSRouter("/task/list2", &controllers.TaskController{}, "*:Task_List2_All_For_ERP"),      // 公司所有列表
+	)
+	beego.AddNamespace(ns)
+}

+ 5 - 0
routers/router.go

@@ -0,0 +1,5 @@
+package routers
+
+func init() {
+
+}

+ 2 - 0
run.sh

@@ -0,0 +1,2 @@
+#无日志输出
+nohup ./Cold_server >/dev/null 2>&1 &

+ 120 - 0
script/add_signature.py

@@ -0,0 +1,120 @@
+import io
+import logging
+import os
+import sys
+
+import pdfplumber
+import requests
+from PIL import Image
+from PyPDF2 import PdfReader, PdfWriter
+from reportlab.lib.pagesizes import A4
+from reportlab.pdfgen import canvas
+
+# 配置日志
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+
+def find_signature_positions(pdf_path, target_texts=["签字或盖章", "技术支持单位(盖章)"]):
+    """查找所有签名位置"""
+    positions = []
+    with pdfplumber.open(pdf_path) as pdf:
+        for i, page in enumerate(pdf.pages):
+            for word in page.extract_words():
+                for target in target_texts:
+                    if target in word["text"]:
+                        x, y = word["x0"], word["top"]
+                        positions.append((i, int(x), int(y), target))
+                        logger.info(f"找到签名位置: 第{i}页, {target} at ({x}, {y})")
+
+    # 返回结果:所有"签字或盖章"和"技术支持单位(盖章)"的位置
+    if len(positions) == 0 or positions == []:
+        return None
+        # 返回结果:第二个"签字或盖章"和技术支持单位位置
+    result = []
+    if len(positions) >= 2:
+        result.append(positions[1])
+        # 第二个出现的位置(索引1)
+    else:
+        result.append(positions[0])
+
+    return result
+
+
+def add_signature_to_pdf(input_pdf, output_pdf, signature_img, positions, offset_x=30, offset_y=-10):
+    """添加签名到PDF"""
+    reader = PdfReader(input_pdf)
+    writer = PdfWriter()
+    a4_width, a4_height = A4  # (595.2, 841.68)
+    for page_index in range(len(reader.pages)):
+        page = reader.pages[page_index]
+        for pos in positions:
+            if pos[0] == page_index:
+                packet = io.BytesIO()
+                can = canvas.Canvas(packet, pagesize=A4)
+                img = Image.open(signature_img)
+                img_width, img_height = img.size
+                aspect_ratio = img_height / img_width
+                new_width = 43 * (72 / 25.4)  # 40mm ≈ 113.39点
+                new_height = new_width * aspect_ratio
+                x, y = pos[1], a4_height - pos[2]
+                if pos[3] == "技术支持单位(盖章)":
+                    y = y - new_height / 2
+                else:
+                    y = y - new_height / 3 * 2
+                x = max(0, min(x, a4_width - new_width))
+                y = max(0, min(y, a4_height - new_height))
+                can.drawImage(signature_img, x, y, width=new_width, height=new_height, mask='auto')
+                can.save()
+                packet.seek(0)
+                overlay_pdf = PdfReader(packet)
+                page.merge_page(overlay_pdf.pages[0])
+        writer.add_page(page)
+
+    with open(output_pdf, "wb") as f:
+        writer.write(f)
+
+
+def download_file(url, local_filename):
+    """下载文件到临时目录"""
+    with requests.get(url, stream=True) as r:
+        r.raise_for_status()
+        with open(local_filename, 'wb') as f:
+            for chunk in r.iter_content(chunk_size=8192):
+                f.write(chunk)
+    return local_filename
+
+
+def add_signature(url, pdfFilename, signature_img, signature_pdf):
+    """把水印添加到pdf中"""
+
+    # 下载PDF文件
+    local_pdf = download_file(url, pdfFilename)
+    # 查找签名位置(使用默认公章图片)
+    positions = find_signature_positions(local_pdf)
+    if len(positions) == 0:
+        os.remove(local_pdf)
+        return
+
+    # 生成带公章的PDF
+    add_signature_to_pdf(local_pdf, signature_pdf, signature_img, positions)
+
+
+if __name__ == '__main__':
+    if len(sys.argv) < 3:
+        print("Usage: add_watermark.py <url> <pdf_file_in> <signature_img> <signature_pdf>")
+        sys.exit(1)
+
+    pdf_file_url = sys.argv[1]
+    pdfFilename = sys.argv[2]  # 要加水印的文件名
+    signature_img = sys.argv[3]  # 要加水印的文件名
+    signature_pdf = sys.argv[4]  # 加好水印的结果文件
+
+    # name = str(uuid.uuid4()) + ".pdf"
+    # pdf_file_url = "https://bzdcoldverifyoss.baozhida.cn/UpImage/1754036272edee05b2-6032-430c-a39b-c83490764dd9.pdf"
+    # pdfFilename = "/Users/zoie/work/bzd_project/ColdVerify_server/ofile/" + name
+    # signature_img = "/Users/zoie/work/bzd_project/ColdVerify_server/script/报告专用章.png"
+    # signature_pdf = "/Users/zoie/work/bzd_project/ColdVerify_server/ofile/signature" + name
+
+    add_signature(pdf_file_url, pdfFilename, signature_img, signature_pdf)
+    print(signature_pdf)

+ 47 - 0
script/add_watermark.py

@@ -0,0 +1,47 @@
+import os
+import sys
+
+from PyPDF2 import PdfReader, PdfWriter
+import requests
+import PyPDF2
+
+
+def add_watermark(url, pdf_file_in, pdf_file_mark, pdf_file_out):
+    """把水印添加到pdf中"""
+    
+    response = requests.get(url)
+    with open(pdf_file_in, "wb") as pdf_file:
+        pdf_file.write(response.content)
+    input_stream = open(pdf_file_in, 'rb')
+    pdf_input = PdfReader(input_stream, strict=False)
+
+    # 获取PDF文件的页数
+    # pageNum = pdf_input.getNumPages()
+    pageNum = len(pdf_input.pages)
+
+    pdf_output = PdfWriter()
+    # 读入水印pdf文件
+    pdf_watermark = PdfReader(open(pdf_file_mark, 'rb'), strict=False)
+    # 给每一页打水印
+    for i in range(pageNum):
+        # page = pdf_input.getPage(i)
+        page = pdf_input.pages[i]
+        page.merge_page(pdf_watermark.pages[0])
+        page.compress_content_streams()  # 压缩内容
+        pdf_output.add_page(page)
+    pdf_output.write(open(pdf_file_out, 'wb'))
+
+
+
+if __name__ == '__main__':
+   
+    if len(sys.argv) < 3:
+        print("Usage: add_watermark.py <url> <pdf_file_in>  <pdf_file_out>  <pdf_file_mark>")
+        sys.exit(1)
+
+    pdf_file_url = sys.argv[1]
+    pdf_file_in = sys.argv[2] # 要加水印的文件名
+    pdf_file_out = sys.argv[3] # 加好水印的结果文件
+    pdf_file_mark = sys.argv[4]
+    add_watermark(pdf_file_url, pdf_file_in, pdf_file_mark, pdf_file_out)
+    print(pdf_file_out)

BIN
script/watermark.pdf


BIN
script/报告专用章.png


BIN
static/commonSeal.jpg


BIN
static/fonts/MiSans-Medium.ttf


BIN
static/fonts/iconfont.eot


Diferenças do arquivo suprimidas por serem muito extensas
+ 44 - 0
static/fonts/iconfont.svg


BIN
static/fonts/iconfont.ttf


BIN
static/fonts/iconfont.woff


Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff