package controllers import ( "ColdVerify_server/Nats/NatsServer" "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" "fmt" beego "github.com/beego/beego/v2/server/web" "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg/draw" "image/color" "math" "os" "sync" "time" ) 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_uuid := c.GetString("T_uuid") UserMap := Account.UserListToMap(Account.Read_User_List_ALL_1()) AdminMap := Account.AdminListToMap(Account.Read_Admin_List_ALL_1()) var T_admin string if User_r.T_power > 2 { T_admin = User_r.T_uuid } var cnt int List, cnt := Task.Read_Task_List(T_uuid, T_admin, 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) 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 c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Task.TaskToTask_R(r)} 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_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") var_ := Task.Task{ 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_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.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) AddData_Tool() { T_uuid := "3e84dda9-9eec-42b9-9350-0894262fc8a1" // 用户uuid T_name := c.GetString("T_name") T_task_id := c.GetString("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_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_collection_state = T_collection_state if !Task.Update_Task(r, "T_collection_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 *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_reporting := c.GetString("T_reporting") T_delivery := c.GetString("T_delivery") T_doc1 := c.GetString("T_doc1") T_pdf1 := c.GetString("T_pdf1") T_doc2 := c.GetString("T_doc2") T_pdf2 := c.GetString("T_pdf2") T_doc3 := c.GetString("T_doc3") T_pdf3 := c.GetString("T_pdf3") 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_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) 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 T_collection_state == 4 { r.T_collection_state = T_collection_state clos = append(clos, "T_collection_state") } if len(T_doc1) > 0 { r.T_doc1 = T_doc1 clos = append(clos, "T_doc1") } // 验证报告内容T_pdf1 ,上传后将 当前任务 实施方案 标志 为 1 if len(T_pdf1) > 0 { r.T_pdf1 = T_pdf1 clos = append(clos, "T_pdf1") r.T_scheme_state = 1 clos = append(clos, "T_scheme_state") } 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_reporting_state = 1 clos = append(clos, "T_reporting_state") } 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") } 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") } // ....... // "T_name", "T_Show", "T_VerifyTemplate_id", "T_deadline", // "T_collection", "T_reporting", "T_delivery", // "T_collection_state", "T_reporting_state", "T_delivery_state", // "T_doc1", "T_pdf1", "T_doc2", "T_pdf2", "T_doc3", "T_pdf3" 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) 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: 202, 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 } } 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 } // 存档生成图片 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, 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(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)] }