|
|
@@ -13,20 +13,25 @@ import (
|
|
|
"ColdVerify_server/models/System"
|
|
|
"ColdVerify_server/models/Task"
|
|
|
"ColdVerify_server/models/VerifyTemplate"
|
|
|
+ "archive/zip"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"image/color"
|
|
|
+ "io"
|
|
|
"math"
|
|
|
"os"
|
|
|
"os/exec"
|
|
|
+ "path/filepath"
|
|
|
+ "regexp"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
"time"
|
|
|
|
|
|
+ "github.com/xuri/excelize/v2"
|
|
|
+
|
|
|
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"
|
|
|
@@ -39,7 +44,7 @@ type TaskController struct {
|
|
|
|
|
|
// 导入Excel创建任务并写入模版数据
|
|
|
func (c *TaskController) Import_Tasks() {
|
|
|
- file, _, err := c.GetFile("file")
|
|
|
+ file, fileHeader, err := c.GetFile("file")
|
|
|
if err != nil {
|
|
|
c.Data["json"] = lib.JSONS{Code: 203, Msg: "读取上传文件失败!"}
|
|
|
c.ServeJSON()
|
|
|
@@ -47,19 +52,31 @@ func (c *TaskController) Import_Tasks() {
|
|
|
}
|
|
|
defer file.Close()
|
|
|
|
|
|
- xlsx, err := excelize.OpenReader(file)
|
|
|
+ // 保存上传的文件到临时位置,以便后续提取图片
|
|
|
+ lib.Create_Dir("./ofile/temp_excel")
|
|
|
+ tempExcelPath := fmt.Sprintf("./ofile/temp_excel/%d_%s", time.Now().Unix(), fileHeader.Filename)
|
|
|
+ err = c.SaveToFile("file", tempExcelPath)
|
|
|
+ if err != nil {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 203, Msg: "保存临时文件失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ defer os.Remove(tempExcelPath) // 处理完成后删除临时文件
|
|
|
+
|
|
|
+ // 重新打开文件用于读取数据(必须使用文件路径,GetPicture 等功能依赖于完整文件)
|
|
|
+ f, err := excelize.OpenFile(tempExcelPath)
|
|
|
if err != nil {
|
|
|
c.Data["json"] = lib.JSONS{Code: 203, Msg: "Excel 文件解析失败!"}
|
|
|
c.ServeJSON()
|
|
|
return
|
|
|
}
|
|
|
defer func() {
|
|
|
- _ = xlsx.Close()
|
|
|
+ _ = f.Close()
|
|
|
}()
|
|
|
|
|
|
sheetName := c.GetString("sheet")
|
|
|
if len(sheetName) == 0 {
|
|
|
- sheets := xlsx.GetSheetList()
|
|
|
+ sheets := f.GetSheetList()
|
|
|
if len(sheets) == 0 {
|
|
|
c.Data["json"] = lib.JSONS{Code: 203, Msg: "Excel 文件为空!"}
|
|
|
c.ServeJSON()
|
|
|
@@ -68,7 +85,7 @@ func (c *TaskController) Import_Tasks() {
|
|
|
sheetName = sheets[0]
|
|
|
}
|
|
|
|
|
|
- rows, err := xlsx.GetRows(sheetName)
|
|
|
+ rows, err := f.GetRows(sheetName)
|
|
|
if err != nil {
|
|
|
c.Data["json"] = lib.JSONS{Code: 203, Msg: "读取 Excel 内容失败!"}
|
|
|
c.ServeJSON()
|
|
|
@@ -85,6 +102,18 @@ func (c *TaskController) Import_Tasks() {
|
|
|
skippedRows := make([]int, 0)
|
|
|
failedRows := make([]string, 0)
|
|
|
|
|
|
+ // 从 Excel 文件中提取所有图片,建立 DISPIMG ID 到图片数据的映射
|
|
|
+ // pictureMap key格式: DISPIMG 中的 ID (例如 "ID_53A3119AC46541C694965B07E5E00F81")
|
|
|
+ pictureMap, err := c.extractPicturesFromExcel(tempExcelPath)
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("提取 Excel 图片失败: %v,将继续处理数据", err))
|
|
|
+ pictureMap = make(map[string][]byte)
|
|
|
+ }
|
|
|
+ logs.Info(fmt.Sprintf("共提取到 %d 个图片(ID映射)", len(pictureMap)))
|
|
|
+
|
|
|
+ // 缓存 InfoCollection,避免同一家公司重复查询或创建
|
|
|
+ infoCollectionCache := make(map[string]InfoCollection.InfoCollection)
|
|
|
+
|
|
|
for idx := 1; idx < len(rows); idx++ {
|
|
|
rowCells := rows[idx]
|
|
|
rowData := make(map[string]string, len(headers))
|
|
|
@@ -101,23 +130,62 @@ func (c *TaskController) Import_Tasks() {
|
|
|
if len(value) > 0 {
|
|
|
nonEmpty = true
|
|
|
}
|
|
|
+
|
|
|
+ // 处理单元格内是图片的情况:只有value包含DISPIMG时才处理
|
|
|
+ if strings.Contains(value, "DISPIMG") {
|
|
|
+ logs.Info(fmt.Sprintf("单元格 %d:%d 包含DISPIMG,可能是图片: %s", idx+1, colIdx+1, value))
|
|
|
+
|
|
|
+ // 从 DISPIMG 公式中提取 ID
|
|
|
+ // 格式: =DISPIMG("ID_53A3119AC46541C694965B07E5E00F81",1) 或 DISPIMG("ID_...",1)
|
|
|
+ var picData []byte
|
|
|
+ var foundBy string
|
|
|
+
|
|
|
+ // 通过 ID 查找图片(pictureMap 现在使用 DISPIMG ID 作为 key)
|
|
|
+ dispimgIdRe := regexp.MustCompile(`DISPIMG\s*\(\s*"([^"]+)"`)
|
|
|
+ idMatches := dispimgIdRe.FindStringSubmatch(value)
|
|
|
+ if len(idMatches) > 1 {
|
|
|
+ imageId := idMatches[1]
|
|
|
+ logs.Info(fmt.Sprintf("从 DISPIMG 公式中提取到 ID: %s", imageId))
|
|
|
+ if data, exists := pictureMap[imageId]; exists && len(data) > 0 {
|
|
|
+ picData = data
|
|
|
+ foundBy = fmt.Sprintf("ID (%s)", imageId)
|
|
|
+ logs.Info(fmt.Sprintf("通过 ID %s 找到图片数据 (大小: %d 字节)", imageId, len(picData)))
|
|
|
+ } else {
|
|
|
+ logs.Warning(fmt.Sprintf("通过 ID %s 未找到图片数据,pictureMap 中有 %d 个图片", imageId, len(pictureMap)))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果找到了图片数据,上传图片
|
|
|
+ if picData != nil && len(picData) > 0 {
|
|
|
+ imageURL, uploadErr := c.uploadImageData(picData, header)
|
|
|
+ if uploadErr == nil && len(imageURL) > 0 {
|
|
|
+ value = imageURL
|
|
|
+ nonEmpty = true
|
|
|
+ logs.Info(fmt.Sprintf("第%d行 %s 图片上传成功 (通过%s): %s", idx+1, header, foundBy, imageURL))
|
|
|
+ logs.Info(fmt.Sprintf("第%d行 %s 图片上传成功 (通过%s): %s", idx+1, header, foundBy, imageURL))
|
|
|
+ } else if uploadErr != nil {
|
|
|
+ logs.Error(fmt.Sprintf("第%d行 %s 上传单元格图片失败: %v", idx+1, header, uploadErr))
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logs.Warning(fmt.Sprintf("第%d行 %s 包含DISPIMG但未找到对应图片数据", idx+1, header))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
rowData[header] = value
|
|
|
}
|
|
|
if !nonEmpty {
|
|
|
continue
|
|
|
}
|
|
|
+
|
|
|
companyName := strings.TrimSpace(rowData["公司名称"])
|
|
|
taskName := strings.TrimSpace(rowData["任务名称"])
|
|
|
- if len(companyName) == 0 || len(taskName) == 0 {
|
|
|
- skippedRows = append(skippedRows, idx+1)
|
|
|
- continue
|
|
|
- }
|
|
|
- if rowData["布点图片"] == "" {
|
|
|
+ belongYear := strings.TrimSpace(rowData["所属年份"])
|
|
|
+ if len(companyName) == 0 || len(taskName) == 0 || len(belongYear) == 0 {
|
|
|
skippedRows = append(skippedRows, idx+1)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- taskID, err := c.importTaskRow(rowData)
|
|
|
+ taskID, err := c.importTaskRow(rowData, infoCollectionCache)
|
|
|
if err != nil {
|
|
|
failedRows = append(failedRows, fmt.Sprintf("第%d行: %v", idx+1, err))
|
|
|
continue
|
|
|
@@ -138,8 +206,8 @@ func (c *TaskController) Import_Tasks() {
|
|
|
c.ServeJSON()
|
|
|
}
|
|
|
|
|
|
-func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
- templateName := strings.TrimSpace(row["模版名称"])
|
|
|
+func (c *TaskController) importTaskRow(row map[string]string, infoCollectionCache map[string]InfoCollection.InfoCollection) (string, error) {
|
|
|
+ templateName := strings.TrimSpace(row["模板名称"])
|
|
|
lastOpenBracket := strings.LastIndex(templateName, "[")
|
|
|
lastCloseBracket := strings.LastIndex(templateName, "]")
|
|
|
if lastOpenBracket == -1 || lastCloseBracket == -1 || lastOpenBracket >= lastCloseBracket {
|
|
|
@@ -197,6 +265,22 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
user = cachedUser
|
|
|
}
|
|
|
|
|
|
+ // 根据用户信息获取或创建 InfoCollection,并使用 map 做本次导入缓存,避免重复查询
|
|
|
+ cacheKey := user.T_uuid
|
|
|
+ if len(cacheKey) == 0 {
|
|
|
+ cacheKey = user.T_name
|
|
|
+ }
|
|
|
+
|
|
|
+ infoCollectionRecord, ok := infoCollectionCache[cacheKey]
|
|
|
+ if !ok {
|
|
|
+ record, err := InfoCollection.GetOrCreate_InfoCollection(user.T_uuid, user.T_name)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("自动创建信息采集失败: %w", err)
|
|
|
+ }
|
|
|
+ infoCollectionRecord = record
|
|
|
+ infoCollectionCache[cacheKey] = infoCollectionRecord
|
|
|
+ }
|
|
|
+
|
|
|
resolveAdminUUID := func(fieldName, fallback string, strict bool) (string, error) {
|
|
|
value, ok := row[fieldName]
|
|
|
if !ok || len(strings.TrimSpace(value)) == 0 {
|
|
|
@@ -217,7 +301,6 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
if len(taskName) == 0 {
|
|
|
return "", fmt.Errorf("任务名称缺失")
|
|
|
}
|
|
|
- snValue := strings.TrimSpace(row["SN"])
|
|
|
|
|
|
classPath := ""
|
|
|
if vt.T_class > 0 {
|
|
|
@@ -287,13 +370,17 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
verifyTypeValue = verifyTypeFallback
|
|
|
}
|
|
|
|
|
|
+ belongYearValue := strings.TrimSpace(row["所属年份"])
|
|
|
+
|
|
|
+ infoCollectionID := infoCollectionRecord.T_InfoCollection_id
|
|
|
+
|
|
|
taskRecord := Task.Task{
|
|
|
T_Distributor_id: user.T_Distributor_id,
|
|
|
T_uuid: user.T_uuid,
|
|
|
T_name: taskName,
|
|
|
T_VerifyTemplate_id: templateID,
|
|
|
T_VerifyTemplate_class: classPath,
|
|
|
- T_sn: snValue,
|
|
|
+ T_InfoCollection_id: infoCollectionID,
|
|
|
T_uid: taskUID,
|
|
|
T_scheme: schemeUUID,
|
|
|
T_collection: collectionUUID,
|
|
|
@@ -303,6 +390,7 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
T_category: categoryValue,
|
|
|
T_device_type: deviceTypeValue,
|
|
|
T_verify_type: verifyTypeValue,
|
|
|
+ T_belong_year: belongYearValue,
|
|
|
}
|
|
|
|
|
|
var taskID string
|
|
|
@@ -310,7 +398,7 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
taskRecord.Id = existingTask.Id
|
|
|
taskRecord.T_task_id = existingTask.T_task_id
|
|
|
taskRecord.T_State = existingTask.T_State
|
|
|
- if ok := Task.Update_Task(taskRecord, "T_Distributor_id", "T_uuid", "T_name", "T_VerifyTemplate_id", "T_VerifyTemplate_class", "T_sn", "T_uid", "T_scheme", "T_collection", "T_reporting", "T_delivery", "T_project", "T_category", "T_device_type", "T_verify_type"); !ok {
|
|
|
+ if ok := Task.Update_Task(taskRecord, "T_Distributor_id", "T_uuid", "T_name", "T_VerifyTemplate_id", "T_VerifyTemplate_class", "T_uid", "T_scheme", "T_collection", "T_reporting", "T_delivery", "T_project", "T_category", "T_device_type", "T_verify_type", "T_belong_year"); !ok {
|
|
|
return "", fmt.Errorf("更新任务失败")
|
|
|
}
|
|
|
taskID = existingTask.T_task_id
|
|
|
@@ -350,6 +438,7 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
dataList := make([]VerifyTemplate.VerifyTemplateMapData, 0, len(row))
|
|
|
for key, val := range row {
|
|
|
if vtm, exists := labelMap[key]; exists {
|
|
|
+ logs.Println("key:", key, "val:", val)
|
|
|
dataList = append(dataList, VerifyTemplate.VerifyTemplateMapData{
|
|
|
T_source: vtm.T_source,
|
|
|
T_task_id: taskID,
|
|
|
@@ -373,6 +462,250 @@ func (c *TaskController) importTaskRow(row map[string]string) (string, error) {
|
|
|
|
|
|
return taskID, nil
|
|
|
}
|
|
|
+func (c *TaskController) extractPicturesFromExcel(filePath string) (map[string][]byte, error) {
|
|
|
+ filePath = strings.TrimSpace(filePath)
|
|
|
+ if len(filePath) == 0 {
|
|
|
+ return nil, fmt.Errorf("Excel 文件路径为空")
|
|
|
+ }
|
|
|
+
|
|
|
+ zipReader, err := zip.OpenReader(filePath)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("打开 Excel 压缩包失败: %w", err)
|
|
|
+ }
|
|
|
+ defer zipReader.Close()
|
|
|
+
|
|
|
+ return c.extractWpsDispImgPictures(zipReader), nil
|
|
|
+}
|
|
|
+
|
|
|
+// extractWpsDispImgPictures 专门处理 WPS / _xlfn.DISPIMG 的图片提取逻辑
|
|
|
+// 原理参考: `https://www.hushlll.top/?p=644`
|
|
|
+// 1. 读取 xl/cellimages.xml,找到每个图片块中的 name="ID_xxx" 和 r:embed="rIdX"
|
|
|
+// 2. 读取 xl/_rels/cellimages.xml.rels(或退回到 xl/drawings/_rels/drawing1.xml.rels),把 rId 映射到具体的图片路径(如 media/image1.jpg)
|
|
|
+// 3. 从 ZIP 中按路径取出图片数据,建立 ID -> 图片数据 的映射
|
|
|
+func (c *TaskController) extractWpsDispImgPictures(zipReader *zip.ReadCloser) map[string][]byte {
|
|
|
+ result := make(map[string][]byte)
|
|
|
+
|
|
|
+ if zipReader == nil || zipReader.File == nil {
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 找到 xl/cellimages.xml
|
|
|
+ var cellImagesFile *zip.File
|
|
|
+ for _, f := range zipReader.File {
|
|
|
+ if f != nil && f.Name == "xl/cellimages.xml" {
|
|
|
+ cellImagesFile = f
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if cellImagesFile == nil {
|
|
|
+ // 非 WPS / 无 cellimages.xml 的情况,直接返回空
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ rc, err := cellImagesFile.Open()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法打开 xl/cellimages.xml: %v", err))
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ cellImagesData, err := io.ReadAll(rc)
|
|
|
+ rc.Close()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法读取 xl/cellimages.xml: %v", err))
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ cellImagesContent := string(cellImagesData)
|
|
|
+
|
|
|
+ // 2. 读取关系文件:优先 xl/_rels/cellimages.xml.rels,找不到再尝试 xl/drawings/_rels/drawing1.xml.rels
|
|
|
+ var relsFile *zip.File
|
|
|
+ for _, f := range zipReader.File {
|
|
|
+ if f != nil && f.Name == "xl/_rels/cellimages.xml.rels" {
|
|
|
+ relsFile = f
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if relsFile == nil {
|
|
|
+ for _, f := range zipReader.File {
|
|
|
+ if f != nil && f.Name == "xl/drawings/_rels/drawing1.xml.rels" {
|
|
|
+ relsFile = f
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if relsFile == nil {
|
|
|
+ logs.Warning("未找到 cellimages 对应的关系文件 (cellimages.xml.rels / drawing1.xml.rels)")
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ rc, err = relsFile.Open()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法打开关系文件 %s: %v", relsFile.Name, err))
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ relsData, err := io.ReadAll(rc)
|
|
|
+ rc.Close()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法读取关系文件 %s: %v", relsFile.Name, err))
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ relsContent := string(relsData)
|
|
|
+
|
|
|
+ // 2.1 解析关系文件,建立 rId -> Target 的映射
|
|
|
+ relsMap := make(map[string]string)
|
|
|
+ reRel := regexp.MustCompile(`Id="([^"]+)"[^>]*Target="([^"]+)"`)
|
|
|
+ for _, m := range reRel.FindAllStringSubmatch(relsContent, -1) {
|
|
|
+ if len(m) >= 3 {
|
|
|
+ id := m[1]
|
|
|
+ target := m[2]
|
|
|
+ relsMap[id] = target
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if len(relsMap) == 0 {
|
|
|
+ logs.Warning(fmt.Sprintf("关系文件 %s 中未解析到任何图片关系", relsFile.Name))
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 从 cellimages.xml 中解析每个图片块
|
|
|
+ // 结构大致类似:
|
|
|
+ // <xdr:pic> ... <xdr:nvPicPr>...<xdr:cNvPr name="ID_XXXX".../> ...</xdr:nvPicPr> ... <a:blip r:embed="rId1"/> ... </xdr:pic>
|
|
|
+ picBlocks := regexp.MustCompile(`(?s)<xdr:pic[^>]*>.*?</xdr:pic>`).FindAllString(cellImagesContent, -1)
|
|
|
+ if len(picBlocks) == 0 {
|
|
|
+ logs.Warning("xl/cellimages.xml 中未找到任何 <xdr:pic> 图片块")
|
|
|
+ return result
|
|
|
+ }
|
|
|
+
|
|
|
+ nameRe := regexp.MustCompile(`name="(ID_[^"]+)"`)
|
|
|
+ embedRe := regexp.MustCompile(`r:embed="([^"]+)"`)
|
|
|
+
|
|
|
+ for _, block := range picBlocks {
|
|
|
+ nameMatch := nameRe.FindStringSubmatch(block)
|
|
|
+ if len(nameMatch) < 2 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ imgID := nameMatch[1]
|
|
|
+
|
|
|
+ embedMatch := embedRe.FindStringSubmatch(block)
|
|
|
+ if len(embedMatch) < 2 {
|
|
|
+ logs.Warning(fmt.Sprintf("WPS 图片块中 ID %s 未找到 r:embed 属性", imgID))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ rId := embedMatch[1]
|
|
|
+
|
|
|
+ target, ok := relsMap[rId]
|
|
|
+ if !ok {
|
|
|
+ logs.Warning(fmt.Sprintf("在关系文件中未找到 rId=%s 对应的图片路径 (ID=%s)", rId, imgID))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关系文件里的 Target 一般是 media/image1.jpg 或 ../media/image1.jpg
|
|
|
+ // 在 ZIP 中的真实路径应为 xl/<Target 去掉前导 / >
|
|
|
+ imagePathInZip := "xl/" + strings.TrimLeft(target, "/")
|
|
|
+
|
|
|
+ var imageFile *zip.File
|
|
|
+ for _, f := range zipReader.File {
|
|
|
+ if f != nil && f.Name == imagePathInZip {
|
|
|
+ imageFile = f
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if imageFile == nil {
|
|
|
+ logs.Warning(fmt.Sprintf("在 ZIP 中未找到图片文件 %s (ID=%s, rId=%s)", imagePathInZip, imgID, rId))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ rcImg, err := imageFile.Open()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法打开图片文件 %s: %v", imagePathInZip, err))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ imgData, err := io.ReadAll(rcImg)
|
|
|
+ rcImg.Close()
|
|
|
+ if err != nil {
|
|
|
+ logs.Warning(fmt.Sprintf("无法读取图片文件 %s: %v", imagePathInZip, err))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if len(imgData) == 0 {
|
|
|
+ logs.Warning(fmt.Sprintf("图片文件 %s 为空,跳过 (ID=%s)", imagePathInZip, imgID))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ result[imgID] = imgData
|
|
|
+ logs.Info(fmt.Sprintf("WPS cellimages 建立映射: ID %s -> %s (大小: %d 字节)", imgID, imagePathInZip, len(imgData)))
|
|
|
+ }
|
|
|
+
|
|
|
+ logs.Info(fmt.Sprintf("通过 WPS cellimages 共解析出 %d 个 ID->图片 映射", len(result)))
|
|
|
+ return result
|
|
|
+}
|
|
|
+
|
|
|
+// 上传图片数据到七牛云
|
|
|
+func (c *TaskController) uploadImageData(imageData []byte, headerName string) (string, error) {
|
|
|
+ if len(imageData) == 0 {
|
|
|
+ return "", fmt.Errorf("图片数据为空")
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建临时目录
|
|
|
+ tempDir := "./ofile/temp_images"
|
|
|
+ err := os.MkdirAll(tempDir, 0755)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("创建临时目录失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据图片数据的前几个字节判断图片格式
|
|
|
+ ext := ".png" // 默认扩展名
|
|
|
+ if len(imageData) >= 4 {
|
|
|
+ // PNG: 89 50 4E 47
|
|
|
+ if imageData[0] == 0x89 && imageData[1] == 0x50 && imageData[2] == 0x4E && imageData[3] == 0x47 {
|
|
|
+ ext = ".png"
|
|
|
+ } else if len(imageData) >= 2 {
|
|
|
+ // JPEG: FF D8
|
|
|
+ if imageData[0] == 0xFF && imageData[1] == 0xD8 {
|
|
|
+ ext = ".jpg"
|
|
|
+ } else if len(imageData) >= 6 {
|
|
|
+ // GIF: 47 49 46 38
|
|
|
+ if imageData[0] == 0x47 && imageData[1] == 0x49 && imageData[2] == 0x46 && imageData[3] == 0x38 {
|
|
|
+ ext = ".gif"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fileName := fmt.Sprintf("%s_%s_%d%s", headerName, uuid.New().String(), time.Now().Unix(), ext)
|
|
|
+ tempFilePath := filepath.Join(tempDir, fileName)
|
|
|
+
|
|
|
+ // 保存图片到临时文件
|
|
|
+ err = os.WriteFile(tempFilePath, imageData, 0644)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("保存图片失败: %w", err)
|
|
|
+ }
|
|
|
+ defer func() {
|
|
|
+ // 确保清理临时文件
|
|
|
+ if removeErr := os.Remove(tempFilePath); removeErr != nil {
|
|
|
+ logs.Error(fmt.Sprintf("删除临时文件失败: %s, 错误: %v", tempFilePath, removeErr))
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ // 检查文件是否存在
|
|
|
+ fileInfo, err := os.Stat(tempFilePath)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("获取文件信息失败: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传到七牛云
|
|
|
+ qiniuFileName := fmt.Sprintf("UpImage/excel_import_%s_%d%s", uuid.New().String(), time.Now().Unix(), ext)
|
|
|
+ logs.Info(fmt.Sprintf("准备上传图片: %s, 大小: %d 字节, 目标: %s", tempFilePath, fileInfo.Size(), qiniuFileName))
|
|
|
+
|
|
|
+ imageURL, success := NatsServer.Qiniu_UploadFile(tempFilePath, qiniuFileName)
|
|
|
+ if !success {
|
|
|
+ logs.Error(fmt.Sprintf("上传图片到七牛云失败: 文件=%s, 大小=%d 字节, 目标=%s", tempFilePath, fileInfo.Size(), qiniuFileName))
|
|
|
+ return "", fmt.Errorf("上传图片到七牛云失败,文件大小: %d 字节", fileInfo.Size())
|
|
|
+ }
|
|
|
+
|
|
|
+ if imageURL == "" {
|
|
|
+ return "", fmt.Errorf("上传图片后未返回URL")
|
|
|
+ }
|
|
|
+
|
|
|
+ logs.Info(fmt.Sprintf("图片上传成功: %s -> %s", tempFilePath, imageURL))
|
|
|
+ return imageURL, nil
|
|
|
+}
|
|
|
|
|
|
// 列表 -
|
|
|
func (c *TaskController) List() {
|
|
|
@@ -854,6 +1187,92 @@ func (c *TaskController) Stat_Excel() {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+// 导出唯一任务标识
|
|
|
+func (c *TaskController) ExportTaskUid() {
|
|
|
+ // 验证登录
|
|
|
+ _, 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_num, _ := c.GetInt("T_num")
|
|
|
+ if T_num <= 0 {
|
|
|
+ T_num = 10
|
|
|
+ }
|
|
|
+ if T_num > 1000 {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "单次最多生成1000个唯一标识"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ uidList := make([]string, 0, T_num)
|
|
|
+ exists := make(map[string]struct{}, T_num)
|
|
|
+ exportBatch := fmt.Sprintf("export_%d", time.Now().UnixNano())
|
|
|
+
|
|
|
+ for len(uidList) < T_num {
|
|
|
+ candidate := strings.ToUpper(strings.ReplaceAll(uuid.New().String(), "-", ""))
|
|
|
+ if len(candidate) > 16 {
|
|
|
+ candidate = candidate[:16]
|
|
|
+ }
|
|
|
+
|
|
|
+ if _, ok := exists[candidate]; ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if _, found := Task.Read_Task_ByUid(candidate); found {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if Task.TaskUidExists(candidate) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ exists[candidate] = struct{}{}
|
|
|
+ uidList = append(uidList, candidate)
|
|
|
+ }
|
|
|
+
|
|
|
+ f := excelize.NewFile()
|
|
|
+ sheet := "Sheet1"
|
|
|
+ f.SetCellValue(sheet, "A1", "序号")
|
|
|
+ f.SetCellValue(sheet, "B1", "唯一标识")
|
|
|
+ for i, uid := range uidList {
|
|
|
+ row := i + 2
|
|
|
+ f.SetCellValue(sheet, fmt.Sprintf("A%d", row), i+1)
|
|
|
+ f.SetCellValue(sheet, fmt.Sprintf("B%d", row), uid)
|
|
|
+ }
|
|
|
+ f.SetColWidth(sheet, "A", "A", 12)
|
|
|
+ f.SetColWidth(sheet, "B", "B", 30)
|
|
|
+
|
|
|
+ lib.Create_Dir("./ofile")
|
|
|
+ fileName := fmt.Sprintf("task_uid_%d.xlsx", time.Now().Unix())
|
|
|
+ localPath := "ofile/" + fileName
|
|
|
+ if err := f.SaveAs(localPath); err != nil {
|
|
|
+ logs.Error("ExportTaskUid SaveAs error:", err)
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "生成Excel失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if !lib.Pload_qiniu(localPath, localPath) {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 203, Msg: "文件上传失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if err := os.Remove(localPath); err != nil {
|
|
|
+ logs.Error("ExportTaskUid remove temp file:", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := Task.SaveTaskUids(uidList, exportBatch); err != nil {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 204, Msg: "保存唯一标识失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ url := "https://bzdcoldverifyoss.baozhida.cn/" + localPath
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
// 获取任务负责人列表
|
|
|
func (c *TaskController) GetTaskUserList() {
|
|
|
// 验证登录 User_is, User_r
|
|
|
@@ -1315,6 +1734,7 @@ func (c *TaskController) UpCollectionState() {
|
|
|
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"))
|
|
|
@@ -1847,6 +2267,181 @@ func (c *TaskController) Up() {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+// 修改-
|
|
|
+func (c *TaskController) UpInfoCollection() {
|
|
|
+ // 验证登录 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
|
|
|
+ }
|
|
|
+
|
|
|
+ T_InfoCollection_id := c.GetString("T_InfoCollection_id") // 信息采集id
|
|
|
+
|
|
|
+ // 查询信息采集信息
|
|
|
+ infoCollection, is := InfoCollection.Read_InfoCollection(T_InfoCollection_id)
|
|
|
+ if !is {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ r.T_InfoCollection_id = T_InfoCollection_id
|
|
|
+ r.T_InfoTemplate_id = infoCollection.T_InfoTemplate_id
|
|
|
+ r.T_start_time = infoCollection.T_start_time // 项目开始时间使用信息采集开始时间
|
|
|
+
|
|
|
+ if !Task.Update_Task(r, "T_InfoCollection_id", "T_InfoTemplate_id", "T_start_time") {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 添加任务操作日志
|
|
|
+ Task.Add_TaskLogs_T(User_r.T_uuid, T_task_id, "任务管理", "修改信息采集id", r)
|
|
|
+ System.Add_UserLogs_T(User_r.T_uuid, "任务管理", "修改信息采集id", r)
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// 修改任务的公司
|
|
|
+func (c *TaskController) UpdateTaskCompany() {
|
|
|
+ // 验证登录 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")
|
|
|
+ new_T_uuid := c.GetString("T_uuid") // 新公司UUID
|
|
|
+
|
|
|
+ if len(T_task_id) == 0 {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 不能为空!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(new_T_uuid) == 0 {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_uuid 不能为空!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询任务
|
|
|
+ task, is := Task.Read_Task(T_task_id)
|
|
|
+ if !is {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "任务不存在!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询原公司信息
|
|
|
+ oldUser, is := Account.Read_User(task.T_uuid)
|
|
|
+ if !is {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "原公司信息不存在!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询新公司信息
|
|
|
+ newUser, is := Account.Read_User(new_T_uuid)
|
|
|
+ if !is {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "新公司信息不存在!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询信息采集
|
|
|
+ var infoCollection InfoCollection.InfoCollection
|
|
|
+ if len(task.T_InfoCollection_id) > 0 {
|
|
|
+ infoCollection, is = InfoCollection.Read_InfoCollection(task.T_InfoCollection_id)
|
|
|
+ if !is {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "信息采集不存在!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "任务没有关联信息采集!"}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ var newInfoCollection InfoCollection.InfoCollection
|
|
|
+ var newInfoCollectionId string
|
|
|
+
|
|
|
+ // 判断信息采集名称是否和原公司名称相同
|
|
|
+ if infoCollection.T_name == oldUser.T_name {
|
|
|
+ // 如果信息采集名称和原公司名称相同,查询新公司下与新公司同名的信息采集
|
|
|
+ newInfoCollection, is = InfoCollection.Read_InfoCollection_By_T_uuid_Name(new_T_uuid, newUser.T_name)
|
|
|
+ if !is {
|
|
|
+ // 如果不存在,创建新公司下的信息采集(使用新公司名称)
|
|
|
+ var err error
|
|
|
+ newInfoCollection, err = InfoCollection.GetOrCreate_InfoCollection(new_T_uuid, newUser.T_name)
|
|
|
+ if err != nil {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "创建信息采集失败: " + err.Error()}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ newInfoCollectionId = newInfoCollection.T_InfoCollection_id
|
|
|
+ } else {
|
|
|
+ // 如果信息采集名称和原公司名称不相同,查询新公司下有没有同名的信息采集
|
|
|
+ newInfoCollection, is = InfoCollection.Read_InfoCollection_By_T_uuid_Name(new_T_uuid, infoCollection.T_name)
|
|
|
+ if !is {
|
|
|
+ // 如果不存在,创建新公司下的信息采集(使用原信息采集名称)
|
|
|
+ var err error
|
|
|
+ newInfoCollection, err = InfoCollection.GetOrCreate_InfoCollection(new_T_uuid, infoCollection.T_name)
|
|
|
+ if err != nil {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "创建信息采集失败: " + err.Error()}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ newInfoCollectionId = newInfoCollection.T_InfoCollection_id
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务的公司和信息采集
|
|
|
+ task.T_uuid = new_T_uuid
|
|
|
+ task.T_InfoCollection_id = newInfoCollectionId
|
|
|
+ if newInfoCollection.T_InfoTemplate_id != "" {
|
|
|
+ task.T_InfoTemplate_id = newInfoCollection.T_InfoTemplate_id
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新新公司的分销商ID
|
|
|
+ if newUser.T_Distributor_id != "" {
|
|
|
+ task.T_Distributor_id = newUser.T_Distributor_id
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新任务
|
|
|
+ updateCols := []string{"T_uuid", "T_InfoCollection_id", "T_InfoTemplate_id"}
|
|
|
+ if newUser.T_Distributor_id != "" {
|
|
|
+ updateCols = append(updateCols, "T_Distributor_id")
|
|
|
+ }
|
|
|
+
|
|
|
+ if !Task.Update_Task(task, updateCols...) {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改任务失败!"}
|
|
|
+ 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
|
|
|
+}
|
|
|
+
|
|
|
// 保存电子签名pdf
|
|
|
func (c *TaskController) SaveElectronicSignaturePDF() {
|
|
|
// 验证登录 User_is, User_r
|
|
|
@@ -3414,14 +4009,22 @@ func (c *TaskController) Copy() {
|
|
|
|
|
|
T_name := c.GetString("T_name")
|
|
|
T_task_id := c.GetString("T_task_id")
|
|
|
+ new_T_uuid := c.GetString("T_uuid") // 新增T_uuid参数
|
|
|
r, is := Task.Read_Task(T_task_id)
|
|
|
if !is {
|
|
|
c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取信息采集失败!"}
|
|
|
c.ServeJSON()
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+ // 确定使用的T_uuid
|
|
|
+ target_T_uuid := r.T_uuid
|
|
|
+ if len(new_T_uuid) > 0 && new_T_uuid != r.T_uuid {
|
|
|
+ target_T_uuid = new_T_uuid
|
|
|
+ }
|
|
|
+
|
|
|
dc := Device.DeviceClass{
|
|
|
- T_uuid: User_r.T_uuid,
|
|
|
+ T_uuid: target_T_uuid,
|
|
|
T_State: 1,
|
|
|
}
|
|
|
T_class_id, is := Device.Add_DeviceClass(dc)
|
|
|
@@ -3438,13 +4041,63 @@ func (c *TaskController) Copy() {
|
|
|
c.ServeJSON()
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+ // 如果T_uuid不同,需要处理信息采集
|
|
|
+ target_InfoCollection_id := r.T_InfoCollection_id
|
|
|
+ if len(new_T_uuid) > 0 && new_T_uuid != r.T_uuid {
|
|
|
+ // 查询新的T_uuid是否有同名的信息采集
|
|
|
+ newInfoCollection, found := InfoCollection.Read_InfoCollection_By_T_uuid_Name(new_T_uuid, infoCollection.T_name)
|
|
|
+ if found {
|
|
|
+ // 如果有则使用该信息采集
|
|
|
+ target_InfoCollection_id = newInfoCollection.T_InfoCollection_id
|
|
|
+ infoCollection = newInfoCollection
|
|
|
+ } else {
|
|
|
+ // 如果没有则添加
|
|
|
+ // 获取原公司和新公司的名称
|
|
|
+ _, oldCompany := Account.Read_User_ByT_uuid(r.T_uuid)
|
|
|
+ _, newCompany := Account.Read_User_ByT_uuid(new_T_uuid)
|
|
|
+ infoCollectionName := infoCollection.T_name
|
|
|
+ // 如果信息采集名称与原公司名称相同,则添加的时候需要将名称更改为新的T_uuid的公司的名称
|
|
|
+ if infoCollection.T_name == oldCompany.T_name {
|
|
|
+ infoCollectionName = newCompany.T_name
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新的信息采集
|
|
|
+ newInfoCollection := InfoCollection.InfoCollection{
|
|
|
+ T_uuid: new_T_uuid,
|
|
|
+ T_name: infoCollectionName,
|
|
|
+ T_InfoTemplate_class: infoCollection.T_InfoTemplate_class,
|
|
|
+ T_InfoTemplate_id: infoCollection.T_InfoTemplate_id,
|
|
|
+ T_status: 1,
|
|
|
+ T_State: 1,
|
|
|
+ T_start_time: infoCollection.T_start_time,
|
|
|
+ T_end_time: infoCollection.T_end_time,
|
|
|
+ T_time_interval: infoCollection.T_time_interval,
|
|
|
+ }
|
|
|
+ newInfoCollectionId, err := InfoCollection.Add_InfoCollection(newInfoCollection)
|
|
|
+ if err != nil {
|
|
|
+ c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加信息采集失败: " + err.Error()}
|
|
|
+ c.ServeJSON()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ target_InfoCollection_id = newInfoCollectionId
|
|
|
+ // 重新读取新创建的信息采集以获取完整信息
|
|
|
+ infoCollection, is = InfoCollection.Read_InfoCollection(target_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_InfoCollection_id: target_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_uuid: target_T_uuid,
|
|
|
T_name: T_name,
|
|
|
T_VerifyTemplate_class: r.T_VerifyTemplate_class,
|
|
|
T_VerifyTemplate_id: r.T_VerifyTemplate_id,
|