Sfoglia il codice sorgente

Merge branch 'master' into feature/eta1.6.5_edb_calculate

xyxie 1 anno fa
parent
commit
da59409ee7
83 ha cambiato i file con 9599 aggiunte e 1313 eliminazioni
  1. 36 15
      controllers/banner.go
  2. 28 14
      controllers/cloud_disk.go
  3. 511 5
      controllers/commodity_trade_base_index.go
  4. 411 36
      controllers/data_manage/chart_info.go
  5. 6 0
      controllers/data_manage/chart_theme.go
  6. 166 88
      controllers/data_manage/edb_info.go
  7. 634 0
      controllers/data_manage/edb_info_refresh.go
  8. 8 1
      controllers/data_manage/excel/custom_analysis_edb.go
  9. 169 113
      controllers/data_manage/excel/excel_classify.go
  10. 171 137
      controllers/data_manage/excel/excel_info.go
  11. 227 16
      controllers/data_manage/excel/mixed_table.go
  12. 492 0
      controllers/data_manage/fenwei_data.go
  13. 33 19
      controllers/data_manage/future_good/future_good_chart_info.go
  14. 416 0
      controllers/data_source/guagnzhouqihuo.go
  15. 329 0
      controllers/data_source/icpi.go
  16. 2 18
      controllers/english_report/english_auth.go
  17. 1 4
      controllers/english_report/report.go
  18. 32 20
      controllers/ppt_english.go
  19. 32 20
      controllers/ppt_v2.go
  20. 46 24
      controllers/report.go
  21. 191 104
      controllers/resource.go
  22. 27 15
      controllers/smart_report/smart_report.go
  23. 44 0
      controllers/user_login.go
  24. 26 14
      controllers/voice.go
  25. 3 0
      go.mod
  26. 13 0
      go.sum
  27. 3 3
      models/business_conf.go
  28. 144 0
      models/data_manage/base_from_fenwei.go
  29. 55 0
      models/data_manage/base_from_fenwei_classify.go
  30. 236 0
      models/data_manage/base_from_mtjh.go
  31. 8 1
      models/data_manage/chart_edb_mapping.go
  32. 89 11
      models/data_manage/chart_info.go
  33. 8 0
      models/data_manage/edb_classify.go
  34. 6 2
      models/data_manage/edb_data_base.go
  35. 39 0
      models/data_manage/edb_data_gz.go
  36. 39 0
      models/data_manage/edb_data_icpi.go
  37. 108 6
      models/data_manage/edb_info.go
  38. 3 1
      models/data_manage/edb_info_calculate_mapping.go
  39. 239 0
      models/data_manage/edb_refresh/edb_refresh_config.go
  40. 138 0
      models/data_manage/edb_refresh/edb_refresh_default_config.go
  41. 68 0
      models/data_manage/edb_refresh/edb_refresh_mapping.go
  42. 51 0
      models/data_manage/edb_refresh/edb_refresh_source.go
  43. 52 0
      models/data_manage/edb_refresh/request/edb_info_refresh.go
  44. 25 6
      models/data_manage/excel/excel_classify.go
  45. 30 0
      models/data_manage/excel/excel_edb_mapping.go
  46. 13 4
      models/data_manage/excel/excel_info.go
  47. 7 2
      models/data_manage/excel/request/excel_classify.go
  48. 69 8
      models/data_manage/excel/request/mixed_table.go
  49. 126 0
      models/data_manage/mysteel_chemical_index.go
  50. 119 0
      models/data_manage/smm_data.go
  51. 134 0
      models/data_source/guagnzhouqihuo.go
  52. 114 0
      models/data_source/icpi.go
  53. 14 0
      models/db.go
  54. 1 1
      models/english_report_email.go
  55. 4 3
      models/roadshow/calendar.go
  56. 1 1
      models/system/sys_role_admin.go
  57. 1 1
      models/target.go
  58. 298 1
      routers/commentsRouter.go
  59. 6 0
      routers/router.go
  60. 130 0
      services/aws_s3.go
  61. 8 0
      services/data/base_edb_lib.go
  62. 531 21
      services/data/chart_info.go
  63. 19 3
      services/data/chart_theme.go
  64. 24 38
      services/data/edb_data.go
  65. 8 1
      services/data/edb_info.go
  66. 638 0
      services/data/edb_info_refresh.go
  67. 429 0
      services/data/excel/excel_classify.go
  68. 15 4
      services/data/excel/excel_op.go
  69. 519 67
      services/data/excel/mixed_table.go
  70. 4 3
      services/data/future_good/chart_info.go
  71. 1 1
      services/data/future_good/profit_chart_info.go
  72. 225 0
      services/email.go
  73. 3 3
      services/english_policy_report.go
  74. 1 1
      services/excel_info.go
  75. 23 12
      services/file.go
  76. 399 290
      services/minio.go
  77. 149 104
      services/oss.go
  78. 45 26
      services/report.go
  79. 44 25
      services/video.go
  80. 18 0
      utils/calculate.go
  81. 27 0
      utils/common.go
  82. 28 0
      utils/config.go
  83. 9 0
      utils/constants.go

+ 36 - 15
controllers/banner.go

@@ -51,22 +51,43 @@ func (this *BannerController) Upload() {
 		return
 	}
 	resourceUrl := ``
-	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
+
+	//resourceUrl, err = services.UploadImgToMinIoTest(fileName, fpath)
+	//if err != nil {
+	//	br.Msg = "文件上传失败"
+	//	br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//	return
+	//}
+
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
 	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	////上传到阿里云 和 minio
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//}
 
 	defer func() {
 		os.Remove(fpath)

+ 28 - 14
controllers/cloud_disk.go

@@ -584,21 +584,35 @@ func (this *CloudDiskController) ResourceUpload() {
 
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, e = services.UploadMinIoToDir(ossFileName, filePath, ossDir, "")
-		if e != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败, Err:" + e.Error()
-			return
-		}
-	} else {
-		resourceUrl, e = services.UploadAliyunToDir(ossFileName, filePath, ossDir, "")
-		if e != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败, Err:" + e.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, e = services.UploadMinIoToDir(ossFileName, filePath, ossDir, "")
+	//	if e != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败, Err:" + e.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, e = services.UploadAliyunToDir(ossFileName, filePath, ossDir, "")
+	//	if e != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败, Err:" + e.Error()
+	//		return
+	//	}
+	//}
+	savePath := ossDir + time.Now().Format("200601/20060102/") + ossFileName
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, e = ossClient.UploadFile(ossFileName, filePath, savePath)
+	if e != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + e.Error()
+		return
 	}
+
 	// 新增云盘资源
 	extMap := services.GetCloudDiskResourceFileTypeExtMap()
 	resourceIcon := extMap[ext]

+ 511 - 5
controllers/commodity_trade_base_index.go

@@ -1,12 +1,12 @@
 package controllers
 
 import (
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"github.com/tealeg/xlsx"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/tealeg/xlsx"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -1204,7 +1204,7 @@ func (this *TradeCommonController) CoalMineClassify() {
 	var child data_manage.CoalChild
 
 	list, err := data_manage.GetCoalmineClassifyList()
-	if err!= nil {
+	if err != nil {
 		br.Msg = "获取煤炭分类数据失败"
 		br.ErrMsg = "获取煤炭度分类数据失败,Err: " + err.Error()
 		return
@@ -1303,7 +1303,6 @@ func (this *TradeCommonController) CoalMineClassify() {
 			coalList = append(coalList, coal)
 		}
 
-
 		if v.Suffix == "inland_index" {
 			suffix = "inland_index"
 			groups = []*string{}
@@ -2549,3 +2548,510 @@ func (this *TradeCommonController) EicDataListV2() {
 	br.Msg = "获取成功"
 	br.Data = data
 }
+
+// CoalMineClassify
+// @title	获取煤炭江湖分类列表
+// @Description	获取煤炭江湖分类列表
+// @Success 200 {object} models.
+// @router /data/mtjh/classify [get]
+func (this *TradeCommonController) MtjhClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	list, err := data_manage.GetMtjhClassifyList()
+	if err != nil {
+		br.Msg = "获取煤炭分类数据失败"
+		br.ErrMsg = "获取煤炭度分类数据失败,Err: " + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// CoalMineData
+// @title	获取煤炭江湖详细数据列表
+// @Description	获取煤炭江湖详细数据接口
+// @Param	ClassifyId query int true	"数据id"
+// @Param	GroupName query string true	"分组名"
+// @Param	Frequency query string true	"频度"
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} []data_manage.CoalmineDataResp
+// @router /data/mtjh/data [get]
+func (this *TradeCommonController) MtjhData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	area := this.GetString("Area")
+	if area == "" {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	//获取指标
+	var condition string
+	var pars []interface{}
+
+	if area != "" {
+		condition += ` AND area=? `
+		pars = append(pars, area)
+	}
+
+	mtjhList, err := data_manage.GetMtjhMapping(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	resultList := make([]*data_manage.BaseFromMtjhIndexList, 0)
+	for _, v := range mtjhList {
+		product := new(data_manage.BaseFromMtjhIndexList)
+		product.BaseFromMtjhMappingId = v.BaseFromMtjhMappingId
+		product.Unit = v.Unit
+		product.IndexCode = v.IndexCode
+		product.IndexName = v.IndexName
+		product.Port = v.Port
+		product.Area = v.Area
+		product.Variety = v.Variety
+		product.Frequency = v.Frequency
+		product.CreateTime = v.CreateTime
+
+		modifyTime, err := data_manage.GetMtjhIndexLatestDate(v.IndexCode)
+		if err != nil  && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取更新时间失败"
+			br.ErrMsg = "获取更新时间失败,Err:" + err.Error()
+			return
+		}
+		product.ModifyTime = modifyTime
+
+		total, err := data_manage.GetMtjhIndexDataCount(v.IndexCode)
+		if err != nil {
+			br.Msg = "获取总数失败"
+			br.ErrMsg = "获取总数失败,Err:" + err.Error()
+			return
+		}
+		page := paging.GetPaging(currentIndex, pageSize, total)
+		dataList, err := data_manage.GetMtjhIndexData(v.IndexCode, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		if dataList == nil {
+			dataList = make([]*data_manage.BaseFromMtjhIndexItem, 0)
+		}
+		product.DataList = dataList
+		product.Paging = page
+		resultList = append(resultList, product)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resultList
+	return
+}
+
+// CoalSearchList
+// @Title 煤炭江湖模糊搜索
+// @Description 煤炭江湖模糊搜索
+// @Param   Keyword   query   string  ture       "关键字搜索"
+// @Success 200 {object} models.BaseResponse
+// @router /data/mtjh/search [get]
+func (this *TradeCommonController) MtjhSearchList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	//关键字
+	keyword := this.GetString("Keyword")
+
+	list, err := data_manage.GetMtjhItemList(keyword)
+	if err != nil {
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		br.Msg = "获取失败"
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// CoalSingleData
+// @Title 获取煤炭江湖单条数据
+// @Description 获取煤炭江湖单条数据
+// @Param   IndexCode   query   string  true       "指标唯一编码"
+// @Success 200 {object} []data_manage.CoalmineSingalDataResp
+// @router  /data/mtjh/single_data [get]
+func (this *TradeCommonController) MtjhSingleData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	indexCode := this.GetString("IndexCode")
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	mapping, err := data_manage.GetMtjhMappingItemByCode(indexCode)
+	if err != nil {
+		br.Msg = "获取煤炭数据失败"
+		br.ErrMsg = "获取煤炭度数据失败,Err:" + err.Error()
+		return
+	}
+	items, err := data_manage.GetMtjhIndexData(indexCode, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取煤炭数据失败"
+		br.ErrMsg = "获取煤炭度数据失败,Err:" + err.Error()
+		return
+	}
+
+	modifyTime, err := data_manage.GetMtjhIndexLatestDate(indexCode)
+	if err != nil {
+		br.Msg = "获取更新时间失败"
+		br.ErrMsg = "获取更新时间失败,Err:" + err.Error()
+		return
+	}
+
+	total, err := data_manage.GetMtjhIndexDataCount(indexCode)
+	if err != nil {
+		br.Msg = "获取总数失败"
+		br.ErrMsg = "获取总数失败,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := data_manage.BaseFromMtjhIndexList{
+		BaseFromMtjhMappingId: mapping.BaseFromMtjhMappingId,
+		IndexName:             mapping.IndexName,
+		IndexCode:             mapping.IndexCode,
+		Area:                  mapping.Area,
+		Port:                  mapping.Port,
+		Unit:                  mapping.Unit,
+		Frequency:             mapping.Frequency,
+		CreateTime:            mapping.CreateTime,
+		ModifyTime:            modifyTime,
+		Variety:               mapping.Variety,
+		DataList:              items,
+		Paging:                page,
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+	return
+}
+
+// MtjhFrequency
+// @title	获取煤炭江湖频度
+// @Description	获取煤炭江湖频度
+// @Param	ClassifyId query int true	"数据id"
+// @Success 200 {object} models.
+// @router /data/mtjh/frequency [get]
+func (this *TradeCommonController) MtjhFrequency() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	area := this.GetString("Area")
+
+	list, err := data_manage.GetMtjhFrequencyByArea(area)
+	if err != nil {
+		br.Msg = "获取煤炭频度数据失败"
+		br.ErrMsg = "获取煤炭频度数据失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// ExportCoalList
+// @Title 导出煤炭江湖数据
+// @Description 导出煤炭江湖数据
+// @Param	ClassifyId query int true	"数据id"
+// @Param   IndexName   query   string  true       "名称关键词"
+// @Param   IndexCode   query   string  true       "指标唯一编码"
+// @Param   TypeName   query   string  true       "分类"
+// @Param   Frequency   query   string  false       "频度"
+// @Param   UnitName   query   string  false       "单位"
+// @Success 200  导出成功
+// @router /export/mtjh [get]
+func (this *TradeCommonController) ExportMtjhList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	area := this.GetString("Area")
+	indexCode := this.GetString("IndexCode") //指标唯一编码
+
+	secNameList := make([]*models.EdbdataExportList, 0)
+
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+
+	//不为空就是导出分类表
+	if indexCode == "" {
+		//获取指标
+		var secNameList []*string
+		var err error
+
+		secNameList, err = data_manage.GetClassifyMtjhByArea(area)
+		if err != nil {
+			fmt.Println("获取数据失败,Err:" + err.Error())
+			return
+		}
+
+		if len(secNameList) <= 0 {
+			fmt.Println("secNameList长度为0")
+			return
+		}
+		sheetNew, err := xlsxFile.AddSheet(area)
+
+		if err != nil {
+			fmt.Println("新增Sheet失败", err.Error())
+			return
+		}
+		//sheetNew.SetColWidth()
+		//获取指标数据
+		windRow := sheetNew.AddRow()
+		secNameRow := sheetNew.AddRow()
+		indexCodeRow := sheetNew.AddRow()
+		frequencyRow := sheetNew.AddRow()
+		unitRow := sheetNew.AddRow()
+		lastModifyDateRow := sheetNew.AddRow()
+		//获取分类下指标最大数据量
+		var dataMax int
+
+		dataMax, err = data_manage.GetCoalMtjhMaxCount(area)
+		if err != nil {
+			fmt.Println("获取指标最大数据量失败", err.Error())
+			return
+		}
+
+		setRowIndex := 6
+		for k, sv := range secNameList {
+			//获取数据
+			dataList, err := data_manage.GetBaseFromMtjhIndexByCode(*sv)
+			if err != nil {
+				br.Msg = "获取数据失败"
+				br.ErrMsg = "获取数据失败,Err:" + err.Error()
+				return
+			}
+			windRow.AddCell().SetValue(area)
+			secNameRow.AddCell().SetValue("指标名称")
+			indexCodeRow.AddCell().SetValue("指标ID")
+			frequencyRow.AddCell().SetValue("频率")
+			unitRow.AddCell().SetValue("单位")
+			lastModifyDateRow.AddCell().SetValue("更新时间")
+
+			secNameRow.AddCell().SetValue(dataList[0].IndexName)
+			indexCodeRow.AddCell().SetValue(dataList[0].IndexCode)
+			frequencyRow.AddCell().SetValue(dataList[0].Frequency)
+			unitRow.AddCell().SetValue(dataList[0].Unit)
+			lastModifyDateRow.AddCell().SetValue(dataList[0].ModifyTime)
+
+			windRow.AddCell()
+			windRow.AddCell()
+			secNameRow.AddCell()
+			indexCodeRow.AddCell()
+			frequencyRow.AddCell()
+			unitRow.AddCell()
+			lastModifyDateRow.AddCell()
+			min := k * 3
+			sheetNew.SetColWidth(min, min, 15)
+
+			if len(dataList) <= 0 {
+				for n := 0; n < dataMax; n++ {
+					rowIndex := setRowIndex + n
+					row := sheetNew.Row(rowIndex)
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+				}
+			} else {
+				endRowIndex := 0
+				for rk, dv := range dataList {
+					rowIndex := setRowIndex + rk
+					row := sheetNew.Row(rowIndex)
+
+					displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
+					displayDateCell := row.AddCell()
+					style := new(xlsx.Style)
+					style.ApplyAlignment = true
+					style.Alignment.WrapText = true
+					displayDateCell.SetStyle(style)
+					displayDateCell.SetDate(displayDate)
+
+					row.AddCell().SetValue(dv.DealValue)
+					row.AddCell()
+					endRowIndex = rowIndex
+				}
+				if len(dataList) < dataMax {
+					dataLen := dataMax - len(dataList)
+					for n := 0; n < dataLen; n++ {
+						rowIndex := (endRowIndex + 1) + n
+						row := sheetNew.Row(rowIndex)
+						row.AddCell()
+						row.AddCell()
+						row.AddCell()
+					}
+				}
+			}
+		}
+	} else {
+		sheet, err := xlsxFile.AddSheet("指标")
+		if err != nil {
+			br.Msg = "新增Sheet失败"
+			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
+			return
+		}
+		//获取数据
+		dataList, err := data_manage.GetBaseFromMtjhIndexByCode(indexCode)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		mapping, err := data_manage.GetMtjhMappingItemByCode(indexCode)
+		if err != nil {
+			br.Msg = "获取煤炭数据失败"
+			br.ErrMsg = "获取煤炭度数据失败,Err:" + err.Error()
+			return
+		}
+		//获取指标数据
+		windRow := sheet.AddRow()
+		windRow.AddCell().SetValue("煤炭江湖")
+		rowSecName := sheet.AddRow()
+		celSecName := rowSecName.AddCell()
+		celSecName.SetValue("指标名称")
+		cellSenName := rowSecName.AddCell()
+		cellSenName.SetValue(mapping.IndexName)
+		indexCodeRow := sheet.AddRow()
+		indexCodeRow.AddCell().SetValue("指标ID")
+		indexCodeRow.AddCell().SetValue(indexCode)
+
+		rowFrequency := sheet.AddRow()
+		celFrequency := rowFrequency.AddCell()
+		celFrequency.SetValue("频率")
+		rowFrequency.AddCell().SetValue(mapping.Frequency)
+
+		rowUnit := sheet.AddRow()
+		celUnit := rowUnit.AddCell()
+		celUnit.SetValue("单位")
+		cellUnit := rowUnit.AddCell()
+		cellUnit.SetValue(mapping.Unit)
+
+		rowModifyDate := sheet.AddRow()
+		rowModifyCell := rowModifyDate.AddCell()
+		rowModifyCell.SetValue("更新时间")
+		rowModifyCell = rowModifyDate.AddCell()
+		rowModifyCell.SetValue(dataList[len(dataList)-1].ModifyTime)
+
+		fmt.Println("len(dataList):", len(dataList))
+		dataMax, err := data_manage.GetMtjhCount(indexCode)
+		if err != nil {
+			fmt.Println("获取指标最大数据量失败", err.Error())
+			return
+		}
+		fmt.Println("dataMax:", dataMax)
+		if len(dataList) <= 0 {
+			for n := 0; n < dataMax; n++ {
+				rowIndex := 6 + n
+				row := sheet.Row(rowIndex)
+				row.AddCell()
+				row.AddCell()
+				row.AddCell()
+			}
+		} else {
+			endRowIndex := 0
+			for rk, dv := range dataList {
+				rowIndex := 6 + rk
+				row := sheet.Row(rowIndex)
+				displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
+				displayDateCell := row.AddCell()
+				style := new(xlsx.Style)
+				style.ApplyAlignment = true
+				style.Alignment.WrapText = true
+				displayDateCell.SetStyle(style)
+				displayDateCell.SetDate(displayDate)
+
+				row.AddCell().SetValue(dv.DealValue)
+				row.AddCell()
+				endRowIndex = rowIndex
+			}
+			if len(dataList) < dataMax {
+				dataLen := dataMax - len(dataList)
+				for n := 0; n < dataLen; n++ {
+					rowIndex := (endRowIndex + 1) + n
+					row := sheet.Row(rowIndex)
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+				}
+			}
+		}
+	}
+
+	err := xlsxFile.Save(downLoadnFilePath)
+	if err != nil {
+		br.Msg = "保存文件失败"
+		br.ErrMsg = "保存文件失败"
+		return
+	}
+	fileName := `煤炭江湖数据`
+	if len(secNameList) > 0 {
+		fileName = secNameList[0].ClassifyName
+	}
+	fileName += time.Now().Format(utils.FormatDateUnSpace) + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+
+}

+ 411 - 36
controllers/data_manage/chart_info.go

@@ -910,7 +910,7 @@ func (this *ChartInfoController) ChartInfoDetail() {
 			}
 		}
 	}
-	
+
 	// 图表的指标来源
 	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
 	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
@@ -1030,6 +1030,13 @@ func (this *ChartInfoController) PreviewChartInfoDetail() {
 				}
 			}
 		}
+		if req.ChartEdbInfoList[k].IsConvert == 1 {
+			v.IsConvert = 1
+			v.ConvertType = req.ChartEdbInfoList[k].ConvertType
+			v.ConvertValue = req.ChartEdbInfoList[k].ConvertValue
+			v.ConvertUnit = req.ChartEdbInfoList[k].ConvertUnit
+			v.ConvertEnUnit = req.ChartEdbInfoList[k].ConvertEnUnit
+		}
 		mappingList[k] = v
 	}
 
@@ -2233,7 +2240,7 @@ func (this *ChartInfoController) ChartInfoBase64Upload() {
 		}
 	}
 
-	var saveToOssPath string
+	//var saveToOssPath string
 	randStr := utils.GetRandStringNoSpecialChar(28)
 	var fileName, outFileName string
 	fileName = randStr + ".txt"
@@ -2277,29 +2284,42 @@ func (this *ChartInfoController) ChartInfoBase64Upload() {
 
 	defer func() {
 		os.Remove(fileName)
+		os.Remove(outFileName)
 	}()
 
-	saveToOssPath = uploadDir + time.Now().Format("200601/20060102/")
-	saveToOssPath += outFileName
+	//saveToOssPath = uploadDir + time.Now().Format("200601/20060102/")
+	//saveToOssPath += outFileName
 
 	//上传到阿里云 和 minio
 	resourceUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadFileToMinIo("", outFileName, saveToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.MinIoImghost + saveToOssPath
-	} else {
-		err = services.UploadFileToAliyun("", outFileName, saveToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.Imghost + saveToOssPath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadFileToMinIo("", outFileName, saveToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + saveToOssPath
+	//} else {
+	//	err = services.UploadFileToAliyun("", outFileName, saveToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + saveToOssPath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
 	resp.ResourceUrl = resourceUrl
@@ -2512,6 +2532,8 @@ func (this *ChartInfoController) CopyChartInfo() {
 		ExtraConfig:       oldChartInfo.ExtraConfig,
 		SeasonExtraConfig: oldChartInfo.SeasonExtraConfig,
 		StartYear:         oldChartInfo.StartYear,
+		Unit:              oldChartInfo.Unit,
+		UnitEn:            oldChartInfo.UnitEn,
 		ChartThemeId:      oldChartInfo.ChartThemeId,
 		SourcesFrom:       oldChartInfo.SourcesFrom,
 		Instructions:      oldChartInfo.Instructions,
@@ -2533,22 +2555,28 @@ func (this *ChartInfoController) CopyChartInfo() {
 			timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 			mapItem := &data_manage.ChartEdbMapping{
 				//ChartEdbMappingId: 0,
-				ChartInfoId: chartInfo.ChartInfoId,
-				EdbInfoId:   v.EdbInfoId,
-				CreateTime:  time.Now(),
-				ModifyTime:  time.Now(),
-				UniqueCode:  utils.MD5(utils.CHART_PREFIX + "_" + timestamp),
-				MaxData:     v.MaxData,
-				MinData:     v.MinData,
-				IsOrder:     v.IsOrder,
-				IsAxis:      v.IsAxis,
-				EdbInfoType: v.EdbInfoType,
-				LeadValue:   v.LeadValue,
-				LeadUnit:    v.LeadUnit,
-				ChartStyle:  v.ChartStyle,
-				ChartColor:  v.ChartColor,
-				ChartWidth:  v.ChartWidth,
-				Source:      v.Source,
+				ChartInfoId:   chartInfo.ChartInfoId,
+				EdbInfoId:     v.EdbInfoId,
+				CreateTime:    time.Now(),
+				ModifyTime:    time.Now(),
+				UniqueCode:    utils.MD5(utils.CHART_PREFIX + "_" + timestamp),
+				MaxData:       v.MaxData,
+				MinData:       v.MinData,
+				IsOrder:       v.IsOrder,
+				IsAxis:        v.IsAxis,
+				EdbInfoType:   v.EdbInfoType,
+				LeadValue:     v.LeadValue,
+				LeadUnit:      v.LeadUnit,
+				ChartStyle:    v.ChartStyle,
+				ChartColor:    v.ChartColor,
+				ChartWidth:    v.ChartWidth,
+				Source:        v.Source,
+				EdbAliasName:  v.EdbAliasName,
+				IsConvert:     v.IsConvert,
+				ConvertType:   v.ConvertType,
+				ConvertValue:  v.ConvertValue,
+				ConvertUnit:   v.ConvertEnUnit,
+				ConvertEnUnit: v.ConvertEnUnit,
 			}
 			mapList = append(mapList, mapItem)
 		}
@@ -2649,8 +2677,16 @@ func (this *ChartInfoController) PreviewBarChartInfo() {
 
 	//edbInfoIdList := make([]int, 0)
 	edbInfoIdsList := make([]string, 0)
+	convertMap := make(map[int]*data_manage.ChartEdbInfoMapping, 0)
 	for _, v := range req.EdbInfoIdList {
 		edbInfoIdsList = append(edbInfoIdsList, strconv.Itoa(v.EdbInfoId))
+		convertMap[v.EdbInfoId] = &data_manage.ChartEdbInfoMapping{
+			IsConvert:     v.IsConvert,
+			ConvertType:   v.ConvertType,
+			ConvertValue:  v.ConvertValue,
+			ConvertUnit:   v.ConvertUnit,
+			ConvertEnUnit: v.ConvertEnUnit,
+		}
 	}
 	mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoId(strings.Join(edbInfoIdsList, ","))
 	if err != nil {
@@ -2658,6 +2694,15 @@ func (this *ChartInfoController) PreviewBarChartInfo() {
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
+	for i, item := range mappingList {
+		if _, ok := convertMap[item.EdbInfoId]; ok {
+			mappingList[i].ConvertValue = convertMap[item.EdbInfoId].ConvertValue
+			mappingList[i].ConvertUnit = convertMap[item.EdbInfoId].ConvertUnit
+			mappingList[i].ConvertEnUnit = convertMap[item.EdbInfoId].ConvertEnUnit
+			mappingList[i].ConvertType = convertMap[item.EdbInfoId].ConvertType
+			mappingList[i].IsConvert = convertMap[item.EdbInfoId].IsConvert
+		}
+	}
 
 	// 获取图表中的指标数据
 	edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetChartEdbData(0, chartType, "", "", "", mappingList, string(this.Ctx.Input.RequestBody), "")
@@ -3122,3 +3167,333 @@ func (this *EdbInfoController) GetBatchChartRefreshResult() {
 //		data.EsAddOrEditMyChartInfoByChartInfoId(v.ChartInfoId)
 //	}
 //}
+
+// PreviewRadarChartInfo
+// @Title 图表-获取预览的雷达图
+// @Description 图表-获取预览的雷达图
+// @Param	ExtraConfig	body data_manage.PreviewRadarChartReq true "type json string"
+// @Success 200 {object} data_manage.ChartEdbInfoDetailResp
+// @router /chart_info/preview/radar [post]
+func (this *ChartInfoController) PreviewRadarChartInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req data_manage.PreviewRadarChartReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	chartInfo := new(data_manage.ChartInfoView)
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	chartType := utils.CHART_TYPE_RADAR
+	if len(req.ChartEdbInfoList) <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	edbInfoIdArr := make([]int, 0)
+	edbInfoNameMap := make(map[int]string)
+	for _, v := range req.ChartEdbInfoList {
+		edbInfoIdArr = append(edbInfoIdArr, v.EdbInfoId)
+		edbInfoNameMap[v.EdbInfoId] = v.EdbAliasName
+	}
+	mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdArr)
+	for _, v := range mappingList {
+		if name, ok := edbInfoNameMap[v.EdbInfoId]; ok {
+			v.EdbAliasName = name
+		}
+	}
+	// 获取图表中的指标数据
+	edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetChartEdbData(0, chartType, "", "", "", mappingList, req.ExtraConfig, "")
+	if err != nil {
+		br.Msg = "获取失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	warnEdbList := make([]string, 0)
+	for _, v := range edbList {
+		if v.IsNullData {
+			warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")
+		}
+	}
+	if len(warnEdbList) > 0 {
+		chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+	//判断是否需要展示英文标识
+	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList, utils.CHART_SOURCE_DEFAULT, chartType)
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+	resp := new(data_manage.ChartInfoDetailResp)
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.XEdbIdValue = xEdbIdValue
+	resp.YDataList = yDataList
+	resp.DataResp = dataResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ChartInfoDetail
+// @Title 获取图表详情-数据转换
+// @Description 获取图表详情接口-数据转换
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Param   DateType   query   int  true       "日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间"
+// @Param   StartDate   query   string  true       "自定义开始日期"
+// @Param   EndDate   query   string  true       "自定义结束日期"
+// @Param   Calendar   query   string  true       "公历/农历"
+// @Param   SeasonStartDate   query   string  true       "季节性图开始日期"
+// @Param   SeasonEndDate   query   string  true       "季节性图结束日期"
+// @Param   EdbInfoId   query   string  true       "指标ID,多个用英文逗号隔开"
+// @Param   ChartType   query   int  true       "生成样式:1:曲线图,2:季节性图"
+// @Success 200 {object} data_manage.ChartInfoDetailResp
+// @router /chart_info/convert/detail [get]
+func (this *ChartInfoController) ChartInfoConvertDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	chartInfoId, _ := this.GetInt("ChartInfoId")
+
+	dateType, _ := this.GetInt("DateType")
+	fmt.Println("dateType:", dateType)
+	if dateType <= 0 {
+		dateType = 3
+	}
+
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+	startYear, _ := this.GetInt("StartYear")
+
+	edbInfoId := this.GetString("EdbInfoId")
+	chartType, _ := this.GetInt("ChartType")
+
+	calendar := this.GetString("Calendar")
+	if calendar == "" {
+		calendar = "公历"
+	}
+
+	isConvert, _ := this.GetInt("IsConvert")
+	convertType, _ := this.GetInt("ConvertType")
+	convertValue, _ := this.GetFloat("ConvertValue")
+	convertUnit := this.GetString("ConvertUnit")
+	convertEnUnit := this.GetString("ConvertEnUnit")
+
+	var err error
+	chartInfo := new(data_manage.ChartInfoView)
+	if chartInfoId > 0 {
+		chartInfo, err = data_manage.GetChartInfoViewById(chartInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "该图表已删除,自动查看下一图表"
+				br.ErrMsg = "该图表已删除,自动查看下一图表,Err:" + err.Error()
+				br.Ret = 406
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+			return
+		}
+		chartType = chartInfo.ChartType
+
+		// 获取主题样式
+		chartTheme, err := data.GetChartThemeConfig(chartInfo.ChartThemeId, chartInfo.Source, chartInfo.ChartType)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取主题信息失败,Err:" + err.Error()
+			return
+		}
+		chartInfo.ChartThemeStyle = chartTheme.Config
+		chartInfo.ChartThemeId = chartTheme.ChartThemeId
+	}
+
+	mappingList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	if chartInfoId > 0 {
+		mappingList, err = data_manage.GetChartEdbMappingList(chartInfoId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		if edbInfoId != "" {
+			mappingList, err = data_manage.GetChartEdbMappingListByEdbInfoId(edbInfoId)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+				return
+			}
+			if isConvert == 1 && len(mappingList) > 0 {
+				for i, _ := range mappingList {
+					mappingList[i].IsConvert = 1
+					mappingList[i].ConvertType = convertType
+					mappingList[i].ConvertValue = convertValue
+					mappingList[i].ConvertUnit = convertUnit
+					mappingList[i].ConvertEnUnit = convertEnUnit
+				}
+			}
+		}
+	}
+
+	// 图表额外数据参数
+	extraConfigStr := chartInfo.ExtraConfig
+	// 柱方图的一些配置
+	var barConfig data_manage.BarChartInfoReq
+	if chartInfo != nil && chartInfo.ChartType == 7 {
+		if chartInfo.BarConfig == `` {
+			br.Msg = "柱方图未配置"
+			br.ErrMsg = "柱方图未配置"
+			return
+		}
+		err := json.Unmarshal([]byte(chartInfo.BarConfig), &barConfig)
+		if err != nil {
+			br.Msg = "柱方图配置异常"
+			br.ErrMsg = "柱方图配置异常"
+			return
+		}
+		extraConfigStr = chartInfo.BarConfig
+	}
+	yearMax := 0
+	if dateType == utils.DateTypeNYears {
+		for _, v := range mappingList {
+			if v.LatestDate != "" {
+				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
+				if tErr != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
+					return
+				}
+				if lastDateT.Year() > yearMax {
+					yearMax = lastDateT.Year()
+				}
+			}
+		}
+	}
+	// 开始/结束日期
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+
+	// 获取图表中的指标数据
+	edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetChartConvertEdbData(chartInfoId, chartType, calendar, startDate, endDate, mappingList, extraConfigStr, chartInfo.SeasonExtraConfig)
+	if err != nil {
+		br.Msg = "获取失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	// 单位
+	if chartType == utils.CHART_TYPE_BAR && len(yDataList) > 0 {
+		chartInfo.Unit = yDataList[0].Unit
+		chartInfo.UnitEn = yDataList[0].UnitEn
+	}
+	warnEdbList := make([]string, 0)
+	for _, v := range edbList {
+		if v.IsNullData {
+			warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")
+		}
+	}
+	if len(warnEdbList) > 0 {
+		chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
+	}
+	if chartInfoId > 0 && chartInfo != nil {
+		//判断是否加入我的图库
+		{
+			var myChartCondition string
+			var myChartPars []interface{}
+			myChartCondition += ` AND a.admin_id=? `
+			myChartPars = append(myChartPars, sysUser.AdminId)
+			myChartCondition += ` AND a.chart_info_id=? `
+			myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+			myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+				return
+			}
+			if myChartList != nil && len(myChartList) > 0 {
+				chartInfo.IsAdd = true
+				chartInfo.MyChartId = myChartList[0].MyChartId
+				chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+			}
+		}
+		if chartInfo.ChartType == 2 {
+			if chartInfo.SeasonStartDate != "" {
+				chartInfo.StartDate = chartInfo.SeasonStartDate
+				chartInfo.EndDate = chartInfo.SeasonEndDate
+				if chartInfo.DateType == 3 {
+					chartInfo.DateType = 5
+				}
+			}
+		}
+	}
+
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+	//判断是否需要展示英文标识
+	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList, chartInfo.Source, chartInfo.ChartType)
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp := new(data_manage.ChartInfoDetailResp)
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.XEdbIdValue = xEdbIdValue
+	resp.YDataList = yDataList
+	resp.BarChartInfo = barConfig
+	resp.DataResp = dataResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 6 - 0
controllers/data_manage/chart_theme.go

@@ -166,6 +166,12 @@ func (c *ChartThemeController) GetThemePreviewData() {
 		edbInfoIdList = []int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
 		extraConfigStr = `{"XName":"123","XNameEn":"123","XUnitName":"无","XUnitNameEn":"none","YName":"321","YNameEn":"321","YUnitName":"无","YUnitNameEn":"none","XMinValue":"230","XMaxValue":"395","YMinValue":"380","YMaxValue":"850","SeriesList":[{"Name":"2021-11-21","NameEn":"2021-11-21","IsNameDefault":true,"Color":"","EdbInfoList":[{"XEdbInfoId":9,"YEdbInfoId":14,"Name":"指标1","NameEn":"","XDateType":1,"XDate":"","XDateValue":0,"YDateType":1,"YDate":"","YDateValue":0,"IsShow":false},{"XEdbInfoId":10,"YEdbInfoId":15,"Name":"指标2","NameEn":"指标2","XDateType":1,"XDate":"","XDateValue":0,"YDateType":1,"YDate":"","YDateValue":0,"IsShow":false},{"XEdbInfoId":11,"YEdbInfoId":16,"Name":"指标3","NameEn":"","XDateType":1,"XDate":"","XDateValue":0,"YDateType":1,"YDate":"","YDateValue":0,"IsShow":false},{"XEdbInfoId":12,"YEdbInfoId":17,"Name":"指标4","NameEn":"指标4","XDateType":1,"XDate":"","XDateValue":0,"YDateType":1,"YDate":"","YDateValue":0,"IsShow":false},{"XEdbInfoId":13,"YEdbInfoId":18,"Name":"指标5","NameEn":"","XDateType":1,"XDate":"","XDateValue":0,"YDateType":1,"YDate":"","YDateValue":0,"IsShow":false}],"ShowTrendLine":false,"ShowFitEquation":false,"ShowRSquare":false}]}`
 		chartInfo.ChartName = "截面散点图"
+	case utils.CHART_TYPE_RADAR:
+		edbInfoIdList = []int{19, 20, 21, 22, 23, 24}
+		chartInfo.LeftMin = "10000"
+		chartInfo.LeftMax = "60000"
+		extraConfigStr = `{"DateList":[{"Type":3,"Date":"2023-11-01","Value":0,"Color":"#00f","Name":""},{"Type":1,"Date":"","Value":0,"Color":"#f00","Name":""}]}`
+		chartInfo.ChartName = "雷达图"
 	default:
 		br.Msg = "暂不支持该类型"
 		br.IsSendEmail = false

+ 166 - 88
controllers/data_manage/edb_info.go

@@ -6,11 +6,13 @@ import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/company"
 	"eta/eta_api/models/data_manage"
+	request2 "eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/models/data_manage/request"
 	"eta/eta_api/models/data_manage/response"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
+	excel2 "eta/eta_api/services/data/excel"
 	"eta/eta_api/services/data_stat"
 	"eta/eta_api/services/elastic"
 	etaTrialService "eta/eta_api/services/eta_trial"
@@ -1623,6 +1625,100 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				}
 				isAdd = true
 			}
+		} else if source == utils.DATA_SOURCE_GFEX { //广州期货交易所
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取上期所已存在信息失败,Err:" + err.Error()
+				return
+			}
+
+			if len(dataItems) > 0 {
+				searchItem.EdbCode = edbCode
+				minDate, maxDate, err := data_manage.GetEdbDataGzMaxOrMinDate(edbCode)
+				if err != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取上期所日期信息失败,Err:" + err.Error()
+					return
+				}
+				searchItem.DataList = dataItems
+				searchItem.StartDate = minDate
+				searchItem.EndDate = maxDate
+			} else {
+				respItem, err := data.AddEdbData(source, edbCode)
+				if err != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取失败,Err:" + err.Error()
+					return
+				}
+				if respItem.Ret != 200 {
+					br.Msg = "未搜索到该指标"
+					br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
+					return
+				}
+				isAdd = true
+			}
+
+			//获取指标信息
+			indexInfo, err := data_manage.GetBaseInfoFromGzByIndexCode(edbCode)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取上期所指标详情失败,Err:" + err.Error()
+				return
+			}
+
+			if indexInfo != nil {
+				searchItem.Frequency = indexInfo.Frequency
+				searchItem.Unit = indexInfo.Unit
+				searchItem.EdbName = indexInfo.IndexName
+			}
+		} else if source == utils.DATA_SOURCE_ICPI { //消费者指数
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取上期所已存在信息失败,Err:" + err.Error()
+				return
+			}
+
+			if len(dataItems) > 0 {
+				searchItem.EdbCode = edbCode
+				minDate, maxDate, err := data_manage.GetEdbDataIcpiMaxOrMinDate(edbCode)
+				if err != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取上期所日期信息失败,Err:" + err.Error()
+					return
+				}
+				searchItem.DataList = dataItems
+				searchItem.StartDate = minDate
+				searchItem.EndDate = maxDate
+			} else {
+				respItem, err := data.AddEdbData(source, edbCode)
+				if err != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取失败,Err:" + err.Error()
+					return
+				}
+				if respItem.Ret != 200 {
+					br.Msg = "未搜索到该指标"
+					br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
+					return
+				}
+				isAdd = true
+			}
+
+			//获取指标信息
+			indexInfo, err := data_manage.GetBaseInfoFromIcpiByIndexCode(edbCode)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取上期所指标详情失败,Err:" + err.Error()
+				return
+			}
+
+			if indexInfo != nil {
+				searchItem.Frequency = "日度"
+				searchItem.Unit = "%"
+				searchItem.EdbName = indexInfo.IndexName
+			}
 		} else {
 			// 代码中没有的来源那么从edb_source中找是否有对应的
 			sourceItem := data_manage.EdbSourceIdMap[source]
@@ -4229,7 +4325,7 @@ func (this *EdbInfoController) SetEdbDataInsertConfig() {
 // TraceEdbInfo
 // @Title 指标溯源接口
 // @Description 指标溯源接口
-// @Param   EdbInfoId   query   int  true       "指标id"
+// @Param   UniqueCode   query   int  true       "指标唯一编码,如果是管理后台访问,传固定字符串:7c69b590249049942070ae9dcd5bf6dc"
 // @Success 200 {object} data_manage.ChartListResp
 // @router /edb_info/trace [get]
 func (this *EdbInfoController) TraceEdbInfo() {
@@ -4245,14 +4341,32 @@ func (this *EdbInfoController) TraceEdbInfo() {
 		br.Ret = 408
 		return
 	}
-	edbInfoId, _ := this.GetInt("EdbInfoId")
-	if edbInfoId <= 0 {
+	//edbInfoId, _ := this.GetInt("EdbInfoId")
+	//if edbInfoId <= 0 {
+	//	br.Msg = "参数错误"
+	//	br.ErrMsg = "参数错误"
+	//	return
+	//}
+
+	uniqueCode := this.GetString("UniqueCode")
+	if uniqueCode == `` {
 		br.Msg = "参数错误"
 		br.ErrMsg = "参数错误"
 		return
 	}
 
-	resp, err := data.TraceEdbInfoByEdbInfoId(edbInfoId)
+	//  根据UniqueCode获取指标信息
+	edbInfo, err := data_manage.GetEdbInfoByUniqueCode(uniqueCode)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.Msg = "获取失败,Err:" + err.Error()
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "指标不存在"
+		}
+		return
+	}
+
+	resp, err := data.TraceEdbInfoByEdbInfoId(edbInfo.EdbInfoId)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.Msg = "获取失败,Err:" + err.Error()
@@ -4335,7 +4449,7 @@ func (this *EdbInfoController) AllEdbInfoByEs() {
 		keyWordArr = append(keyWordArr, newKeyWord...)
 
 		// 普通的搜索
-		total, edbInfoList, err = elastic.SearchEdbInfoData(utils.DATA_INDEX_NAME, keyWord, startSize, pageSize, filterSource, source, -1, ``, noPermissionEdbInfoIdList)
+		total, edbInfoList, err = elastic.SearchEdbInfoData(utils.DATA_INDEX_NAME, keyWord, startSize, pageSize, filterSource, source, -1, frequency, noPermissionEdbInfoIdList)
 	} else {
 		var condition string
 		var pars []interface{}
@@ -4490,7 +4604,7 @@ func (this *EdbInfoController) GetEdbDateData() {
 // @Param   Date   query   string  false       "日期"
 // @Param   Num   query   int  false       "前后几期数据"
 // @Success 200 {object} data_manage.EdbInfoList
-// @router /edb_info/date_data/before_after [get]
+// @router /edb_info/date_data/before_after [post]
 func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -4498,9 +4612,17 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		this.ServeJSON()
 	}()
 
-	edbInfoId, _ := this.GetInt("EdbInfoId")
-	date := this.GetString("Date")
-	num, _ := this.GetInt("Num")
+	requestBody := string(this.Ctx.Input.RequestBody)
+	var req request2.DateDataBeforeAfterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	edbInfoId := req.EdbInfoId
+	currDate := req.Date
+	num := req.Num
 
 	// 默认2期数据
 	if num <= 0 {
@@ -4519,100 +4641,56 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		return
 	}
 
-	// 当前日期
-	var currDate string
-	// 是否查找之后的数据
-	isFindAfter := true
-	if date == `` {
-		currDate = edbInfo.EndDate
-		isFindAfter = false
-		if num <= 0 {
-			num = 4 //默认获取前面的几期数据
-		}
-	}
-
 	dataList := make([]*data_manage.EdbDataList, 0)
-
-	startDate := date
-	// 指定日期的类型
-	dateType := "day"
-	//如果填写的是月度日期
-	if strings.Count(date, "-") == 1 {
-		startDate = date + "-01"
-		dateType = "month"
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, _ = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
+	case 1:
+		_, dataList, _, _, _, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+	default:
+		br.Msg = "指标类型异常!"
+		br.ErrMsg = "指标类型异常,Err:" + strconv.Itoa(edbInfo.EdbInfoType)
+		return
 	}
 
-	resp := data_manage.BeforeAndAfterDateDataResp{
-		List: dataList,
-		Date: "",
-	}
-	// 后面的数据
-	afterList := make([]*data_manage.EdbDataList, 0)
-	if isFindAfter {
-		afterList, err = data.GetEdbBeforeAndAfterDateData(edbInfo, startDate, "", 2, num)
+	if currDate == `` {
+		currDate, err = excel2.GetEdbDateByMoveForward(requestBody, dataList)
 		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
+			br.Msg = "日期前移失败"
+			br.ErrMsg = "日期前移失败,Err:" + err.Error()
 			return
 		}
-
-		lenBeforeList := len(afterList)
-		if lenBeforeList <= 0 {
-			br.Ret = 200
-			br.Success = true
-			br.Msg = "所选指标所选日期无值"
-			br.Data = resp
-			return
-		} else {
-			var dateTimeStr string
-			switch dateType {
-			case "month":
-				dateTime, _ := time.ParseInLocation(utils.FormatDate, afterList[0].DataTime, time.Local)
-				dateTimeStr = dateTime.Format(utils.FormatYearMonthDate)
-			case "day":
-				dateTimeStr = afterList[0].DataTime
-			}
-			currDate = afterList[0].DataTime
-			// 如果对应日期找不到,那么就直接返回吧
-			if dateTimeStr != date {
-				br.Ret = 200
-				br.Success = true
-				br.Msg = "所选指标所选日期无值"
-				br.Data = resp
-				return
+	} else {
+		if strings.Count(currDate, "-") == 1 {
+			currDate = currDate + "-01"
+			// 查找这个月早的时间作为起始时间
+			for _, v := range dataList {
+				if v.DataTime >= currDate {
+					currDate = v.DataTime
+					break
+				}
 			}
 		}
 	}
-
-	// 前面的数据
-	beforeList, err := data.GetEdbBeforeAndAfterDateData(edbInfo, "", currDate, 1, num)
+	currDate, err = excel2.HandleMixTableDateChange(currDate, requestBody)
 	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = fmt.Sprint("获取前面的指数据失败,Err:", err.Error())
+		br.Msg = "日期变换失败"
+		br.ErrMsg = "日期变换失败,Err:" + err.Error()
 		return
 	}
+	list := make([]*data_manage.EdbDataList, 5)
 
-	dataList = append(dataList, beforeList...)
-	// 后面的数据
-	if len(afterList) > 0 {
-		if len(beforeList) > 0 {
-			dataList = append(dataList, afterList[1:]...)
-		} else {
-			dataList = append(dataList, afterList...)
-		}
-	}
-
-	// 数据翻转
-	for i, j := 0, len(dataList)-1; i < j; i, j = i+1, j-1 {
-		dataList[i], dataList[j] = dataList[j], dataList[i]
+	list, err = data.GetEdbBeforeAndAfterDateData(currDate, dataList)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
+		return
 	}
-
-	resp.List = dataList
-	// 前端不传入日期的时候,这个J皮不让返回这个字段,要不然他会颜色标记
-	if date != `` {
-		resp.Date = currDate
+	// 这个日期不存在的话直接返回空数组
+	resp := data_manage.BeforeAndAfterDateDataResp{
+		List: list,
+		Date: currDate,
 	}
-
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 634 - 0
controllers/data_manage/edb_info_refresh.go

@@ -0,0 +1,634 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/edb_refresh"
+	"eta/eta_api/models/data_manage/edb_refresh/request"
+	"eta/eta_api/services/data"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+// RefreshSourceList
+// @Title 获取指标刷新配置的来源接口
+// @Description 获取指标刷新配置的来源接口
+// @Success Ret=200 获取成功
+// @router /edb_info/refresh/source_list [get]
+func (c *EdbInfoController) RefreshSourceList() {
+	br := new(models.BaseResponse).Init()
+
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	item := edb_refresh.EdbRefreshSource{}
+	tmpList, err := item.GetAllList()
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取刷新数据源失败, Err: " + err.Error()
+		return
+	}
+
+	list := make([]edb_refresh.EdbRefreshSourceList, 0)
+	tmpMap := make(map[int]edb_refresh.EdbRefreshSourceList, 0)
+
+	for _, v := range tmpList {
+		tmp, ok := tmpMap[v.Source]
+		if ok {
+			continue
+		}
+		tmp = edb_refresh.EdbRefreshSourceList{
+			Source:     v.Source,
+			SourceName: v.SourceName,
+			//SubSource:     v.SubSource,
+			//SubSourceName: v.SubSourceName,
+			Child:    make([]edb_refresh.EdbRefreshSourceList, 0),
+			HasChild: v.HasChild,
+		}
+
+		if v.HasChild == 1 {
+			for _, v2 := range tmpList {
+				if v2.Source == v.Source {
+					tmp.Child = append(tmp.Child, edb_refresh.EdbRefreshSourceList{
+						Source:        v2.Source,
+						SourceName:    v2.SourceName,
+						SubSource:     v2.SubSource,
+						SubSourceName: v2.SubSourceName,
+						HasChild:      0,
+					})
+				}
+			}
+		}
+
+		tmpMap[v.Source] = tmp
+		list = append(list, tmp)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// RefreshClassifyList
+// @Title 获取指标分类列表接口
+// @Description 获取指标分类列表接口
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
+// @Success Ret=200 获取成功
+// @router /edb_info/refresh/classify_list [get]
+func (c *EdbInfoController) RefreshClassifyList() {
+	br := new(models.BaseResponse).Init()
+
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	source, _ := c.GetInt("Source", utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+
+	list := make([]*edb_refresh.BaseClassifyItems, 0)
+	switch source {
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联
+		rootList, err := data_manage.GetBaseFromMysteelChemicalClassifyByParentId(0)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		classifyAll, err := data_manage.GetAllBaseFromMysteelChemicalClassify()
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		rootChildMap := make(map[int][]*edb_refresh.BaseClassifyItems)
+
+		for _, v := range classifyAll {
+			//tmpList, ok := rootChildMap[v.ParentId]
+			//if !ok {
+			//	tmpList = make([]data_manage.BaseClassifyItems, 0)
+			//}
+			//tmpList = append(tmpList, data_manage.BaseClassifyItems{
+			//	ClassifyId:   v.BaseFromMysteelChemicalClassifyId,
+			//	ClassifyName: v.ClassifyName,
+			//	ParentId:     v.ParentId,
+			//	UniqueCode:   fmt.Sprint(v.BaseFromMysteelChemicalClassifyId),
+			//	Children:     nil,
+			//})
+			//rootChildMap[v.ParentId] = tmpList
+
+			rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], &edb_refresh.BaseClassifyItems{
+				ClassifyId:   v.BaseFromMysteelChemicalClassifyId,
+				ClassifyName: v.ClassifyName,
+				ParentId:     v.ParentId,
+				UniqueCode:   fmt.Sprint(v.BaseFromMysteelChemicalClassifyId),
+				Children:     nil,
+			})
+		}
+		for _, v := range rootList {
+			tmp := &edb_refresh.BaseClassifyItems{
+				ClassifyId:   v.BaseFromMysteelChemicalClassifyId,
+				ClassifyName: v.ClassifyName,
+				ParentId:     v.ParentId,
+				UniqueCode:   fmt.Sprint(v.BaseFromMysteelChemicalClassifyId),
+				Children:     nil,
+			}
+			if existItems, ok := rootChildMap[v.BaseFromMysteelChemicalClassifyId]; ok {
+				tmp.Children = existItems
+			} else {
+				items := make([]*edb_refresh.BaseClassifyItems, 0)
+				tmp.Children = items
+			}
+			list = append(list, tmp)
+		}
+
+	case utils.DATA_SOURCE_YS: // 有色
+
+		list = append(list, &edb_refresh.BaseClassifyItems{
+			ClassifyId:   0,
+			ClassifyName: "未分类",
+			ParentId:     0,
+			UniqueCode:   fmt.Sprint(0),
+			Children:     nil,
+		})
+		rootList, err := data_manage.GetBaseFromSmmClassifyByParentId(0)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		classifyAll, err := data_manage.GetAllBaseFromSmmClassify()
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		rootChildMap := make(map[int][]*edb_refresh.BaseClassifyItems)
+		for _, v := range classifyAll {
+			rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], &edb_refresh.BaseClassifyItems{
+				ClassifyId:   v.ClassifyId,
+				ClassifyName: v.ClassifyName,
+				ParentId:     v.ParentId,
+				UniqueCode:   fmt.Sprint(v.ClassifyId),
+				Children:     nil,
+			})
+		}
+		for _, v := range rootList {
+			tmp := &edb_refresh.BaseClassifyItems{
+				ClassifyId:   v.ClassifyId,
+				ClassifyName: v.ClassifyName,
+				ParentId:     v.ParentId,
+				UniqueCode:   fmt.Sprint(v.ClassifyId),
+				Children:     nil,
+			}
+			if existItems, ok := rootChildMap[v.ClassifyId]; ok {
+				tmp.Children = existItems
+			} else {
+				items := make([]*edb_refresh.BaseClassifyItems, 0)
+				tmp.Children = items
+			}
+			list = append(list, tmp)
+
+		}
+
+	default:
+		tmpList, err := data_manage.GetAllEdbClassify()
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range tmpList {
+			list = append(list, &edb_refresh.BaseClassifyItems{
+				ClassifyId:   v.ClassifyId,
+				ClassifyName: v.ClassifyName,
+				ParentId:     v.ParentId,
+				UniqueCode:   fmt.Sprint(v.ClassifyId),
+				Children:     nil,
+			})
+		}
+		list = buildTree(list, 0)
+		//fmt.Println(result)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// 生成多层级列表的递归函数
+func buildTree(items []*edb_refresh.BaseClassifyItems, parentId int) []*edb_refresh.BaseClassifyItems {
+	var result []*edb_refresh.BaseClassifyItems
+
+	// 遍历所有分类项
+	for i := range items {
+		// 找到当前节点的子节点
+		if items[i].ParentId == parentId {
+			// 递归构建子节点的子节点
+			items[i].Children = buildTree(items, items[i].ClassifyId)
+			// 将当前节点添加到结果中
+			result = append(result, items[i])
+		}
+	}
+
+	return result
+}
+
+// RefreshEdbList
+// @Title 获取待配置的指标列表接口
+// @Description 获取待配置的指标列表接口
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
+// @Param   SubSource   query   int  true       "来源:0:经济数据库,1:日期序列"
+// @Param   ClassifyId   query   string  false             "分类ID,支持多选,用英文,隔开"
+// @Param   TerminalCode   query   string  false       "终端编码"
+// @Param   SysUserId   query   string  false       "创建人,支持多选,用英文,隔开"
+// @Param   Frequency   query   string  false       "频度,支持多选,用英文,隔开"
+// @Param   Keyword   query   string  false       "关键词"
+// @Param   SortParam   query   string  false       "排序字段参数,用来排序的字段, 枚举值:'data_time':日期"
+// @Param   SortType   query   string  true       "如何排序,是正序还是倒序,枚举值:`asc 正序`,`desc 倒叙`"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/refresh/edb_list [get]
+func (c *EdbInfoController) RefreshEdbList() {
+	br := new(models.BaseResponse).Init()
+
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	source, _ := c.GetInt("Source")
+	subSource, _ := c.GetInt("SubSource")
+	classifyId := c.GetString("ClassifyId")
+	terminalCode := c.GetString("TerminalCode")
+	sysUserId := c.GetString("SysUserId")
+	frequency := c.GetString("Frequency")
+	keyword := c.GetString("Keyword")
+	status := c.GetString("Status")
+
+	sortParam := c.GetString("SortParam")
+	sortType := c.GetString("SortType")
+
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	total, list, err := data.GetList(source, subSource, classifyId, terminalCode, sysUserId, frequency, keyword, status, startSize, pageSize, sortParam, sortType)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+
+	resp := data_manage.RefreshBaseEdbInfoResp{
+		Paging: page,
+		List:   list,
+	}
+
+	// 刷新时间格式化
+	list, err, errMsg, isSendEmail := data.HandleRefreshTime(source, subSource, list)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// GetEdbRefreshDefaultConfig
+// @Title 获取待配置的指标列表接口
+// @Description 获取待配置的指标列表接口
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
+// @Param   SubSource   query   int  true       "来源:0:经济数据库,1:日期序列"
+// @Param   Frequency   query   string  false       "频度"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/refresh/default_config [get]
+func (c *EdbInfoController) GetEdbRefreshDefaultConfig() {
+	br := new(models.BaseResponse).Init()
+
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	source, _ := c.GetInt("Source")
+	subSource, _ := c.GetInt("SubSource")
+	frequency := c.GetString("Frequency")
+
+	if source <= 0 {
+		br.Msg = "来源不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 非有色的来源,频度不能为空
+	if source != utils.DATA_SOURCE_YS && frequency == `` {
+		br.Msg = "频度不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	list, err := edb_refresh.GetListBySourceAndFrequency(source, subSource, frequency)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// SaveEdbRefreshDefaultConfig
+// @Title 设置默认的指标刷新配置接口
+// @Description 设置默认的指标刷新配置接口
+// @Param	request	body data_manage.SaveEdbRefreshDefaultConfigReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /edb_info/refresh/default_config/save [post]
+func (c *EdbInfoController) SaveEdbRefreshDefaultConfig() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	var req request.SaveEdbRefreshDefaultConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 保存
+	err, errMsg, isSendEmail := data.SaveEdbRefreshDefaultConfig(req.Source, req.SubSource, req.Frequency, req.List)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// SaveEdbRefreshConfig
+// @Title 设置指标刷新配置接口
+// @Description 设置指标刷新配置接口
+// @Param	request	body data_manage.SaveEdbRefreshConfigReq true "type json string"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/refresh/config/save [post]
+func (c *EdbInfoController) SaveEdbRefreshConfig() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	var req request.SaveEdbRefreshConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 保存
+	err, errMsg, isSendEmail := data.SaveEdbRefreshConfig(req.Source, req.SubSource, req.ClassifyId, req.TerminalCode, req.Frequency, req.Keyword, req.Status, req.SysUserId, req.IsSelectAll, req.List, req.EdbSelectIdList, c.SysUser.AdminId, c.SysUser.RealName)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// SaveEdbRefreshStatus
+// @Title 设置指标刷新状态接口
+// @Description 设置指标刷新状态接口
+// @Param	request	body data_manage.SaveEdbRefreshStatusReq true "type json string"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/refresh/status/save [post]
+func (c *EdbInfoController) SaveEdbRefreshStatus() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	var req request.SaveEdbRefreshStatusReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.Source <= 0 {
+		br.Msg = "来源不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	edbIdList := make([]int, 0)
+	edbCodeList := make([]string, 0)
+	// 指标id列表
+	if req.IsSelectAll {
+		// 如果是列表全选
+		_, edbList, err := data.GetList(req.Source, req.SubSource, req.ClassifyId, req.TerminalCode, req.SysUserId, req.Frequency, req.Keyword, req.Status, 0, 100000, "", "")
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+		// 不配置的指标id
+		notIdMap := make(map[int]int, 0)
+		for _, v := range req.EdbSelectIdList {
+			notIdMap[v] = v
+		}
+
+		for _, v := range edbList {
+			_, ok := notIdMap[v.EdbInfoId]
+			// 在不配置的指标id列表内的话,那就过滤
+			if ok {
+				continue
+			}
+
+			// 加入到待配置的指标列表id
+			edbIdList = append(edbIdList, v.EdbInfoId)
+			edbCodeList = append(edbCodeList, v.IndexCode)
+		}
+	} else {
+		edbIdList = req.EdbSelectIdList
+	}
+
+	if len(edbIdList) <= 0 {
+		br.Msg = "指标不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	isStop := 0
+	if req.ModifyStatus == `暂停` {
+		isStop = 1
+	}
+
+	switch req.Source {
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联
+		err = data_manage.ModifyMysteelChemicalUpdateStatus(edbIdList, edbCodeList, isStop)
+	case utils.DATA_SOURCE_YS: // 有色
+		err = data_manage.ModifySmmUpdateStatus(edbIdList, edbCodeList, isStop)
+	default:
+		err = data_manage.ModifyEdbInfoUpdateStatus(edbIdList, isStop)
+	}
+	if err != nil {
+		br.Msg = `保存失败`
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// GetEdbRefreshEdbConfig
+// @Title 获取单个指标的刷新配置列表接口
+// @Description 获取单个指标的刷新配置列表接口
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
+// @Param   SubSource   query   int  true       "来源:0:经济数据库,1:日期序列"
+// @Param   EdbInfoId   query   int  false       "指标id"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/refresh/edb_config [get]
+func (c *EdbInfoController) GetEdbRefreshEdbConfig() {
+	br := new(models.BaseResponse).Init()
+
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	source, _ := c.GetInt("Source")
+	subSource, _ := c.GetInt("SubSource")
+	edbInfoId, _ := c.GetInt("EdbInfoId")
+
+	if source <= 0 {
+		br.Msg = "来源不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	if edbInfoId <= 0 {
+		br.Msg = "指标不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取指标的刷新配置列表
+	list, err := edb_refresh.GetEdbRefreshConfigListBySourceAndeEdbInfoId(source, subSource, edbInfoId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	if len(list) > 0 {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = list
+		return
+	}
+
+	// 如果没有找到该指标的配置,那么就查询默认配置
+
+	var frequency string
+
+	// 根据类型查找指标的频度信息
+	switch source {
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联
+		item, err := data_manage.GetBaseFromMysteelChemicalIndexByIndexId(edbInfoId)
+		if err != nil {
+			br.Msg = "获取指标信息失败"
+			br.ErrMsg = err.Error()
+			return
+		}
+		frequency = item.Frequency
+	case utils.DATA_SOURCE_YS: // 有色
+		item, err := data_manage.GetSmmIndexById(edbInfoId)
+		if err != nil {
+			br.Msg = "获取指标信息失败"
+			br.ErrMsg = err.Error()
+			return
+		}
+		frequency = item.Frequency
+	default:
+		item, err := data_manage.GetEdbInfoById(edbInfoId)
+		if err != nil {
+			br.Msg = "获取指标信息失败"
+			br.ErrMsg = err.Error()
+			return
+		}
+		frequency = item.Frequency
+	}
+
+	if frequency == `` {
+		br.Msg = "获取的指标频度信息异常"
+		br.IsSendEmail = false
+		return
+	}
+
+	tmpList, err := edb_refresh.GetListBySourceAndFrequency(source, subSource, frequency)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	list = make([]*edb_refresh.EdbRefreshConfigItem, 0)
+	for _, v := range tmpList {
+		list = append(list, &edb_refresh.EdbRefreshConfigItem{
+			RefreshFrequency:    v.RefreshFrequency,
+			RefreshFrequencyDay: v.RefreshFrequencyDay,
+			RefreshTime:         v.RefreshTime,
+			RefreshAllData:      v.RefreshAllData,
+			RefreshDataNum:      v.RefreshDataNum,
+		})
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}

+ 8 - 1
controllers/data_manage/excel/custom_analysis_edb.go

@@ -9,6 +9,7 @@ import (
 	"eta/eta_api/services/data"
 	"eta/eta_api/services/data/excel"
 	"eta/eta_api/utils"
+	"fmt"
 	"strconv"
 	"strings"
 	"time"
@@ -18,6 +19,7 @@ import (
 // @Title 指标列表
 // @Description 指标列表
 // @Param   ExcelInfoId   query   int  true       "excel的id"
+// @Param   Keyword   query   string  false	"指标关键词"
 // @Success 200 {object} []excel.ExcelEdbMappingItem
 // @router /edb/list [get]
 func (c *CustomAnalysisController) EdbList() {
@@ -33,6 +35,11 @@ func (c *CustomAnalysisController) EdbList() {
 		br.IsSendEmail = false
 		return
 	}
+	keyword := c.GetString("Keyword")
+	keyword = strings.TrimSpace(keyword)
+	if keyword != "" {
+		keyword = fmt.Sprint("%", keyword, "%")
+	}
 
 	// 获取excel表详情
 	excelInfo, err := excelModel.GetExcelInfoById(excelInfoId)
@@ -48,7 +55,7 @@ func (c *CustomAnalysisController) EdbList() {
 		return
 	}
 
-	list, err := excelModel.GetAllExcelEdbMappingItemByExcelInfoId(excelInfo.ExcelInfoId)
+	list, err := excelModel.GetExcelEdbMappingItemByExcelInfoIdOrKeyword(excelInfo.ExcelInfoId, keyword)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()

+ 169 - 113
controllers/data_manage/excel/excel_classify.go

@@ -9,6 +9,8 @@ import (
 	response2 "eta/eta_api/models/data_manage/excel/response"
 	excel2 "eta/eta_api/services/data/excel"
 	"eta/eta_api/utils"
+	"fmt"
+	"sort"
 	"strconv"
 	"time"
 )
@@ -43,14 +45,15 @@ func (this *ExcelClassifyController) List() {
 		showUserId = this.SysUser.AdminId
 	}
 
-	// 获取一级分类
-	rootList, err := excel.GetExcelClassifyByParentId(0, source)
-	if err != nil && err.Error() != utils.ErrNoRow() {
+	classifyList, err := excel.GetExcelClassifyBySource(source)
+	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()
 		return
 	}
 
+	// 获取二级分类
+	// 获取三级分类
 	// 根据来源获取所有excel表格(无内容)
 	allExcelInfo, err := excel.GetNoContentExcelInfoAll(source, showUserId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
@@ -63,26 +66,49 @@ func (this *ExcelClassifyController) List() {
 	for _, v := range allExcelInfo {
 		ExcelInfoMap[v.ExcelClassifyId] = append(ExcelInfoMap[v.ExcelClassifyId], v)
 	}
-	//rootChildMap := make(map[int][]*data_manage.ExcelClassifyItems)
-	//for _, v := range classifyAll {
-	//	rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
-	//	if existItems, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
-	//		v.Children = existItems
-	//	} else {
-	//		items := make([]*data_manage.ExcelClassifyItems, 0)
-	//		v.Children = items
-	//	}
-	//}
+	classifyMap := make(map[int][]*excel.ExcelClassifyItems)
+	for _, v := range classifyList {
+		if existItems, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
+			v.Children = existItems
+		}
+	}
+
+	for _, v := range classifyList {
+		if v.ParentId > 0 {
+			classifyMap[v.ParentId] = append(classifyMap[v.ParentId], v)
+		}
+	}
+	// todo 整理第三层
+	//组装三级分类
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 3 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第二层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		// 调用sort.Slice函数,传入切片、比较函数作为参数
+		sort.Slice(subList, func(i, j int) bool { return excel.ExcelClassifyItemBySort(subList[i], subList[j]) })
+		if ok && classify.Level == 2 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第一层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		sort.Slice(subList, func(i, j int) bool { return excel.ExcelClassifyItemBySort(subList[i], subList[j]) })
+		if ok && classify.Level == 1 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
 	nodeAll := make([]*excel.ExcelClassifyItems, 0)
-	for _, v := range rootList {
-		var items []*excel.ExcelClassifyItems
-		if tmpItem, ok := ExcelInfoMap[v.ExcelClassifyId]; ok {
-			items = tmpItem
-		} else {
-			items = make([]*excel.ExcelClassifyItems, 0)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			sort.Slice(v.Children, func(i, j int) bool { return excel.ExcelClassifyItemBySort(v.Children[i], v.Children[j]) })
+			nodeAll = append(nodeAll, v)
 		}
-		v.Children = items
-		nodeAll = append(nodeAll, v)
 	}
 	resp := response2.ExcelClassifyListResp{
 		AllNodes: nodeAll,
@@ -110,14 +136,51 @@ func (this *ExcelClassifyController) ExcelClassifyItems() {
 	if source <= 0 {
 		source = utils.EXCEL_DEFAULT
 	}
-	rootList, err := excel.GetExcelClassifyByParentId(0, source)
+	classifyList, err := excel.GetExcelClassifyBySource(source)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取数据失败,Err:" + err.Error()
 		return
 	}
+
+	// 获取二级分类
+	// 获取三级分类
+	classifyMap := make(map[int][]*excel.ExcelClassifyItems)
+	for _, v := range classifyList {
+		if v.ParentId > 0 {
+			classifyMap[v.ParentId] = append(classifyMap[v.ParentId], v)
+		}
+	}
+	// todo 整理第三层
+	//组装三级分类
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 3 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第二层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 2 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	// todo 整理第一层
+	for key, classify := range classifyList {
+		subList, ok := classifyMap[classify.ExcelClassifyId]
+		if ok && classify.Level == 1 {
+			classifyList[key].Children = append(classifyList[key].Children, subList...)
+		}
+	}
+	nodeAll := make([]*excel.ExcelClassifyItems, 0)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			nodeAll = append(nodeAll, v)
+		}
+	}
 	resp := response2.ExcelClassifyListResp{
-		AllNodes: rootList,
+		AllNodes: nodeAll,
 	}
 	br.Ret = 200
 	br.Success = true
@@ -173,8 +236,29 @@ func (this *ExcelClassifyController) AddExcelClassify() {
 		return
 	}
 	//获取该层级下最大的排序数
-	maxSort, err := excel.GetExcelClassifyMaxSort(req.ParentId)
+	maxSort, err := excel2.GetExcelClassifyMaxSort(req.ParentId, req.Source)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "查询排序信息失败,Err:" + err.Error()
+		return
+	}
 
+	// 查询父级分类是否存在
+
+	if req.ParentId > 0 {
+		var parent *excel.ExcelClassify
+		parent, err = excel.GetExcelClassifyById(req.ParentId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "父级分类不存在"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "查询父级分类信息失败,Err:" + err.Error()
+			return
+		}
+		req.Level = parent.Level + 1
+	}
 	// 入库
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	classify := &excel.ExcelClassify{
@@ -184,7 +268,7 @@ func (this *ExcelClassifyController) AddExcelClassify() {
 		Source:            source,
 		SysUserId:         this.SysUser.AdminId,
 		SysUserRealName:   this.SysUser.RealName,
-		Level:             req.Level + 1,
+		Level:             req.Level,
 		UniqueCode:        utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
 		Sort:              maxSort + 1,
 		CreateTime:        time.Now(),
@@ -334,6 +418,33 @@ func (this *ExcelClassifyController) DeleteExcelClassifyCheck() {
 		if count > 0 {
 			deleteStatus = 1
 			tipsMsg = "该分类下关联表格不可删除"
+		} else {
+			childClassify, e := excel.GetChildClassifyById(req.ExcelClassifyId)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+				return
+			}
+			if len(childClassify) > 0 {
+				var classifyIds []int
+				for _, v := range childClassify {
+					classifyIds = append(classifyIds, v.ExcelClassifyId)
+				}
+				condition := fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+				var pars []interface{}
+				pars = append(pars, classifyIds)
+				childCount, err := excel.GetExcelInfoCountByCondition(condition, pars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "删除失败"
+					br.ErrMsg = "查询分类下表格数量失败,Err:" + err.Error()
+					return
+				}
+
+				if childCount > 0 {
+					deleteStatus = 1
+					tipsMsg = "该分类下关联表格不可删除"
+				}
+			}
 		}
 	}
 
@@ -413,8 +524,35 @@ func (this *ExcelClassifyController) DeleteExcelClassify() {
 			br.Msg = "该目录下存在关联ETA表格,不可删除"
 			br.IsSendEmail = false
 			return
-		}
+		} else {
+			childClassify, e := excel.GetChildClassifyById(req.ExcelClassifyId)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+				return
+			}
+			if len(childClassify) > 0 {
+				var classifyIds []int
+				for _, v := range childClassify {
+					classifyIds = append(classifyIds, v.ExcelClassifyId)
+				}
+				condition := fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+				var pars []interface{}
+				pars = append(pars, classifyIds)
+				childCount, err := excel.GetExcelInfoCountByCondition(condition, pars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "删除失败"
+					br.ErrMsg = "查询分类下表格数量失败,Err:" + err.Error()
+					return
+				}
 
+				if childCount > 0 {
+					br.Msg = "该目录下存在关联ETA表格,不可删除"
+					br.IsSendEmail = false
+					return
+				}
+			}
+		}
 		classifyItem, err := excel.GetExcelClassifyById(req.ExcelClassifyId)
 		if err != nil {
 			br.Msg = "删除失败"
@@ -561,101 +699,19 @@ func (this *ExcelClassifyController) ExcelClassifyMove() {
 		return
 	}
 
-	if req.ClassifyId <= 0 {
+	if req.ClassifyId <= 0 && req.ExcelInfoId <= 0 {
 		br.Msg = "参数错误"
-		br.ErrMsg = "分类id小于等于0"
-		br.IsSendEmail = false
+		br.ErrMsg = "请选择拖动目标,分类目录或者指标"
 		return
 	}
 	//判断分类是否存在
-	ExcelClassifyInfo, err := excel.GetExcelClassifyById(req.ClassifyId)
+	err, errMsg := excel2.MoveExcelClassify(req)
 	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
 		return
 	}
-	updateCol := make([]string, 0)
 
-	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
-	if ExcelClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
-		parentExcelClassifyInfo, err := excel.GetExcelClassifyById(req.ParentClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
-			return
-		}
-		ExcelClassifyInfo.ParentId = parentExcelClassifyInfo.ExcelClassifyId
-		ExcelClassifyInfo.Level = parentExcelClassifyInfo.Level + 1
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
-	}
-
-	//如果有传入 上一个兄弟节点分类id
-	if req.PrevClassifyId > 0 {
-		//上一个兄弟节点
-		prevClassify, err := excel.GetExcelClassifyById(req.PrevClassifyId)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果是移动在两个兄弟节点之间
-		if req.NextClassifyId > 0 {
-			//下一个兄弟节点
-			nextClassify, err := excel.GetExcelClassifyById(req.NextClassifyId)
-			if err != nil {
-				br.Msg = "移动失败"
-				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
-				return
-			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == ExcelClassifyInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = excel.UpdateExcelClassifySortByParentId(prevClassify.ParentId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
-				if nextClassify.Sort-prevClassify.Sort == 1 {
-					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
-					_ = excel.UpdateExcelClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
-				}
-			}
-		}
-
-		ExcelClassifyInfo.Sort = prevClassify.Sort + 1
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-
-	} else {
-		firstClassify, err := excel.GetFirstExcelClassifyByParentId(ExcelClassifyInfo.ParentId)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
-			return
-		}
-
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = excel.UpdateExcelClassifySortByParentId(firstClassify.ParentId, firstClassify.ExcelClassifyId-1, 0, updateSortStr)
-		}
-
-		ExcelClassifyInfo.Sort = 0 //那就是排在第一位
-		ExcelClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
-
-	//更新
-	if len(updateCol) > 0 {
-		err = ExcelClassifyInfo.Update(updateCol)
-		if err != nil {
-			br.Msg = "移动失败"
-			br.ErrMsg = "修改失败,Err:" + err.Error()
-			return
-		}
-	}
 	br.Ret = 200
 	br.Success = true
 	br.IsAddLog = true

+ 171 - 137
controllers/data_manage/excel/excel_info.go

@@ -203,6 +203,14 @@ func (c *ExcelInfoController) Add() {
 		}
 	}
 
+	//获取该层级下最大的排序数
+	maxSort, err := excel2.GetExcelClassifyMaxSort(req.ExcelClassifyId, req.Source)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "查询排序信息失败,Err:" + err.Error()
+		return
+	}
+
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	excelInfo := &excel3.ExcelInfo{
 		//ExcelInfoId:     0,
@@ -215,7 +223,7 @@ func (c *ExcelInfoController) Add() {
 		SysUserRealName: sysUser.RealName,
 		Content:         content,
 		ExcelImage:      req.ExcelImage,
-		Sort:            0,
+		Sort:            maxSort + 1,
 		IsDelete:        0,
 		ModifyTime:      time.Now(),
 		CreateTime:      time.Now(),
@@ -346,8 +354,24 @@ func (c *ExcelInfoController) List() {
 			br.ErrMsg = "获取信息失败,GetExcelClassify,Err:" + err.Error()
 			return
 		}
-		condition += " AND excel_classify_id = ? "
-		pars = append(pars, excelClassifyId)
+
+		childClassify, e := excel3.GetChildClassifyById(excelClassifyId)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
+			return
+		}
+		if len(childClassify) == 0 {
+			condition += " AND excel_classify_id = ? "
+			pars = append(pars, excelClassifyId)
+		} else {
+			classifyIds := []int{excelClassifyId}
+			for _, v := range childClassify {
+				classifyIds = append(classifyIds, v.ExcelClassifyId)
+			}
+			condition += fmt.Sprintf(` AND excel_classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+			pars = append(pars, classifyIds)
+		}
 	}
 	if keyword != "" {
 		condition += ` AND  ( excel_name LIKE ? )`
@@ -511,13 +535,18 @@ func (c *ExcelInfoController) Edit() {
 	}
 
 	// 标记编辑状态
-	_, err = services.UpdateExcelEditMark(req.ExcelInfoId, sysUser.AdminId, 1, sysUser.RealName)
+	markRet, err := services.UpdateExcelEditMark(req.ExcelInfoId, sysUser.AdminId, 1, sysUser.RealName)
 	if err != nil {
 		br.Msg = "查询标记状态失败"
 		br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
 		return
 	}
-
+	if markRet.Status == 1 {
+		br.Ret = 200
+		br.Success = true
+		br.Data = markRet
+		return
+	}
 	excelClassify, err := excel3.GetExcelClassifyById(req.ExcelClassifyId)
 	if err != nil {
 		if err.Error() == utils.ErrNoRow() {
@@ -733,176 +762,176 @@ func (c *ExcelInfoController) Move() {
 		c.Data["json"] = br
 		c.ServeJSON()
 	}()
-
-	sysUser := c.SysUser
-	if sysUser == nil {
-		br.Msg = "请登录"
-		br.ErrMsg = "请登录,SysUser Is Empty"
-		br.Ret = 408
-		return
-	}
-
-	var req request.MoveExcelInfoReq
-	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
-	if err != nil {
-		br.Msg = "参数解析异常!"
-		br.ErrMsg = "参数解析失败,Err:" + err.Error()
-		return
-	}
-
-	if req.ExcelInfoId <= 0 {
-		br.Msg = "参数错误"
-		br.ErrMsg = "表格id小于等于0"
-		br.IsSendEmail = false
-		return
-	}
-
-	if req.ExcelClassifyId <= 0 {
-		br.Msg = "请选择分类"
-		br.IsSendEmail = false
-		return
-	}
-
-	//判断分类是否存在
-	_, err = excel3.GetExcelClassifyById(req.ExcelClassifyId)
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取分类信息失败" + err.Error()
-
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "分类已被删除,不可移动,请刷新页面"
-			br.ErrMsg = "分类已被删除,不可移动,请刷新页面"
-			br.IsSendEmail = false
+	/*
+		sysUser := c.SysUser
+		if sysUser == nil {
+			br.Msg = "请登录"
+			br.ErrMsg = "请登录,SysUser Is Empty"
+			br.Ret = 408
+			return
 		}
-		return
-	}
 
-	// 获取表格信息
-	excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "获取表格信息失败,Err:" + err.Error()
-		return
-	}
+		var req request.MoveExcelInfoReq
+		err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+		if err != nil {
+			br.Msg = "参数解析异常!"
+			br.ErrMsg = "参数解析失败,Err:" + err.Error()
+			return
+		}
 
-	//如果改变了分类,那么移动该表格数据
-	if excelInfo.ExcelClassifyId != req.ExcelClassifyId {
-		//查询需要修改的分类下是否存在同一个表格名称
-		tmpExcelInfo, tmpErr := excel3.GetExcelInfoByClassifyIdAndName(req.ExcelClassifyId, excelInfo.ExcelName)
-		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
+		if req.ExcelInfoId <= 0 {
+			br.Msg = "参数错误"
+			br.ErrMsg = "表格id小于等于0"
+			br.IsSendEmail = false
 			return
 		}
-		if tmpExcelInfo != nil {
-			br.Msg = "移动失败,同一个分类下表格名称不允许重复"
-			br.ErrMsg = "移动失败,同一个分类下表格名称不允许重复"
+
+		if req.ExcelClassifyId <= 0 {
+			br.Msg = "请选择分类"
 			br.IsSendEmail = false
 			return
 		}
 
-		// 变更表格的所属分类
-		excelInfo.ExcelClassifyId = req.ExcelClassifyId
-		err = excelInfo.Update([]string{"ExcelClassifyId"})
+		//判断分类是否存在
+		_, err = excel3.GetExcelClassifyById(req.ExcelClassifyId)
 		if err != nil {
 			br.Msg = "移动失败"
-			br.ErrMsg = "移动失败,Err:" + err.Error()
+			br.ErrMsg = "获取分类信息失败" + err.Error()
+
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "分类已被删除,不可移动,请刷新页面"
+				br.ErrMsg = "分类已被删除,不可移动,请刷新页面"
+				br.IsSendEmail = false
+			}
 			return
 		}
-	}
 
-	//移动排序
-	updateCol := make([]string, 0)
-	//如果有传入 上一个兄弟节点分类id
-	if req.PrevExcelInfoId > 0 {
-		prevExcelInfo, err := excel3.GetExcelInfoById(req.PrevExcelInfoId)
+		// 获取表格信息
+		excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
 		if err != nil {
 			br.Msg = "移动失败"
-			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+			br.ErrMsg = "获取表格信息失败,Err:" + err.Error()
 			return
 		}
 
-		//如果是移动在两个兄弟节点之间
-		if req.NextExcelInfoId > 0 {
-			//下一个兄弟节点
-			nextExcelInfo, err := excel3.GetExcelInfoById(req.NextExcelInfoId)
+		//如果改变了分类,那么移动该表格数据
+		if excelInfo.ExcelClassifyId != req.ExcelClassifyId {
+			//查询需要修改的分类下是否存在同一个表格名称
+			tmpExcelInfo, tmpErr := excel3.GetExcelInfoByClassifyIdAndName(req.ExcelClassifyId, excelInfo.ExcelName)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				br.Msg = "移动失败"
+				br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
+				return
+			}
+			if tmpExcelInfo != nil {
+				br.Msg = "移动失败,同一个分类下表格名称不允许重复"
+				br.ErrMsg = "移动失败,同一个分类下表格名称不允许重复"
+				br.IsSendEmail = false
+				return
+			}
+
+			// 变更表格的所属分类
+			excelInfo.ExcelClassifyId = req.ExcelClassifyId
+			err = excelInfo.Update([]string{"ExcelClassifyId"})
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "移动失败,Err:" + err.Error()
+				return
+			}
+		}
+
+		//移动排序
+		updateCol := make([]string, 0)
+		//如果有传入 上一个兄弟节点分类id
+		if req.PrevExcelInfoId > 0 {
+			prevExcelInfo, err := excel3.GetExcelInfoById(req.PrevExcelInfoId)
 			if err != nil {
 				br.Msg = "移动失败"
-				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+				br.ErrMsg = "获取一个兄弟节点分类信息失败,Err:" + err.Error()
 				return
 			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevExcelInfo.Sort == nextExcelInfo.Sort || prevExcelInfo.Sort == excelInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点下一层,那么需要再加一层了
-				if nextExcelInfo.Sort-prevExcelInfo.Sort == 1 {
+
+			//如果是移动在两个兄弟节点之间
+			if req.NextExcelInfoId > 0 {
+				//下一个兄弟节点
+				nextExcelInfo, err := excel3.GetExcelInfoById(req.NextExcelInfoId)
+				if err != nil {
+					br.Msg = "移动失败"
+					br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+					return
+				}
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevExcelInfo.Sort == nextExcelInfo.Sort || prevExcelInfo.Sort == excelInfo.Sort {
 					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
+					updateSortStr := `sort + 2`
 					_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr)
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点下一层,那么需要再加一层了
+					if nextExcelInfo.Sort-prevExcelInfo.Sort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						_ = excel3.UpdateExcelInfoSortByClassifyId(prevExcelInfo.ExcelClassifyId, prevExcelInfo.Sort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					}
 				}
 			}
-		}
 
-		// 变更表格在当前分类下的排序
-		excelInfo.Sort = prevExcelInfo.Sort + 1
-		excelInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
+			// 变更表格在当前分类下的排序
+			excelInfo.Sort = prevExcelInfo.Sort + 1
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
 
-	} else {
-		firstClassify, err := excel3.GetFirstExcelInfoByClassifyId(req.ExcelClassifyId)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			br.Msg = "移动失败"
-			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
-			return
-		}
+		} else {
+			firstClassify, err := excel3.GetFirstExcelInfoByClassifyId(req.ExcelClassifyId)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId+1, updateSortStr)
+			}
 
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId+1, updateSortStr)
+			// 变更表格在当前分类下的排序
+			excelInfo.Sort = 0 //那就是排在第一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
 		}
 
-		// 变更表格在当前分类下的排序
-		excelInfo.Sort = 0 //那就是排在第一位
-		excelInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
+		//更新
+		if len(updateCol) > 0 {
+			err = excelInfo.Update(updateCol)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "修改失败,Err:" + err.Error()
+				return
+			}
+		}
 
-	//更新
-	if len(updateCol) > 0 {
-		err = excelInfo.Update(updateCol)
 		if err != nil {
 			br.Msg = "移动失败"
 			br.ErrMsg = "修改失败,Err:" + err.Error()
 			return
 		}
-	}
-
-	if err != nil {
-		br.Msg = "移动失败"
-		br.ErrMsg = "修改失败,Err:" + err.Error()
-		return
-	}
-
-	//新增操作日志
-	//{
-	//	ExcelLog := new(data_manage.ExcelInfoLog)
-	//	ExcelLog.ExcelName = ExcelInfo.ExcelName
-	//	ExcelLog.ExcelInfoId = req.ExcelInfoId
-	//	ExcelLog.ExcelClassifyId = ExcelInfo.ExcelClassifyId
-	//	ExcelLog.SysUserId = sysUser.AdminId
-	//	ExcelLog.SysUserRealName = sysUser.RealName
-	//	ExcelLog.UniqueCode = ExcelInfo.UniqueCode
-	//	ExcelLog.CreateTime = time.Now()
-	//	ExcelLog.Content = string(c.Ctx.Input.RequestBody)
-	//	ExcelLog.Status = "移动表格"
-	//	ExcelLog.Method = c.Ctx.Input.URL()
-	//	go data_manage.AddExcelInfoLog(ExcelLog)
-	//}
 
+		//新增操作日志
+		//{
+		//	ExcelLog := new(data_manage.ExcelInfoLog)
+		//	ExcelLog.ExcelName = ExcelInfo.ExcelName
+		//	ExcelLog.ExcelInfoId = req.ExcelInfoId
+		//	ExcelLog.ExcelClassifyId = ExcelInfo.ExcelClassifyId
+		//	ExcelLog.SysUserId = sysUser.AdminId
+		//	ExcelLog.SysUserRealName = sysUser.RealName
+		//	ExcelLog.UniqueCode = ExcelInfo.UniqueCode
+		//	ExcelLog.CreateTime = time.Now()
+		//	ExcelLog.Content = string(c.Ctx.Input.RequestBody)
+		//	ExcelLog.Status = "移动表格"
+		//	ExcelLog.Method = c.Ctx.Input.URL()
+		//	go data_manage.AddExcelInfoLog(ExcelLog)
+		//}
+	*/
 	br.Ret = 200
 	br.Success = true
 	br.IsAddLog = true
@@ -2276,8 +2305,13 @@ func (this *ExcelInfoController) MarkEditStatus() {
 		br.Msg = "标记状态异常"
 		return
 	}
+
+	status := 1
+	if req.Status == 2 {
+		status = 0
+	}
 	//更新标记key
-	data, err := services.UpdateExcelEditMark(req.ExcelInfoId, sysUser.AdminId, req.Status, sysUser.RealName)
+	data, err := services.UpdateExcelEditMark(req.ExcelInfoId, sysUser.AdminId, status, sysUser.RealName)
 	if err != nil {
 		br.Msg = err.Error()
 		return

+ 227 - 16
controllers/data_manage/excel/mixed_table.go

@@ -7,7 +7,11 @@ import (
 	"eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/services/data"
 	excel2 "eta/eta_api/services/data/excel"
+	"eta/eta_api/utils"
+	"fmt"
 	"strconv"
+	"strings"
+	"time"
 )
 
 // GetSystemDate
@@ -29,7 +33,6 @@ func (c *ExcelInfoController) GetSystemDate() {
 		br.Ret = 408
 		return
 	}
-
 	var req request.MixedTableCellDataReq
 	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -38,7 +41,14 @@ func (c *ExcelInfoController) GetSystemDate() {
 		return
 	}
 
-	date, err, errMsg := excel2.HandleDate(req.DataTimeType, req.Value)
+	var config request.EdbDateConf
+	err = json.Unmarshal([]byte(req.Value), &config)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	date, _, err, errMsg := excel2.HandleDate(req.DataTimeType, req.Value)
 	if err != nil {
 		br.Msg = "获取系统日期失败"
 		if errMsg != `` {
@@ -47,6 +57,46 @@ func (c *ExcelInfoController) GetSystemDate() {
 		br.ErrMsg = "获取系统日期失败,Err:" + err.Error()
 		return
 	}
+	if req.DataTimeType == request.EdbDateDT {
+		edbInfo, err := data_manage.GetEdbInfoById(config.EdbInfoId)
+		if err != nil {
+			br.Msg = "获取指标信息失败!"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+
+		dataList := make([]*data_manage.EdbDataList, 0)
+		switch edbInfo.EdbInfoType {
+		case 0:
+			dataList, _ = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
+		case 1:
+			_, dataList, _, _, _, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+		default:
+			br.Msg = "指标类型异常!"
+			br.ErrMsg = "指标类型异常,Err:" + strconv.Itoa(edbInfo.EdbInfoType)
+			return
+		}
+
+		if req.DataTime == `` { //选择前移几期数
+			date, err = excel2.GetEdbDateByMoveForward(req.Value, dataList)
+			if err != nil {
+				br.Msg = "查询指标前移日期失败!"
+				br.ErrMsg = "查询指标前移日期失败,Err:" + err.Error()
+				return
+			}
+		} else {
+			date = req.DataTime //选择表格中的日期
+		}
+		if date != "" {
+			// 开始做日期变换
+			date, err = excel2.HandleMixTableDateChange(date, req.Value)
+			if err != nil {
+				br.Msg = "日期变换失败!"
+				br.ErrMsg = "日期变换失败,Err:" + err.Error()
+				return
+			}
+		}
+	}
 
 	type resp struct {
 		Date string
@@ -78,7 +128,7 @@ func (c *ExcelInfoController) CalculateData() {
 		br.Ret = 408
 		return
 	}
-
+	requestBody := string(c.Ctx.Input.RequestBody)
 	var req request.CalculateConf
 	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -139,7 +189,8 @@ func (c *ExcelInfoController) CalculateData() {
 	}
 	respItem, tmpErr := data.BaseCalculate(string(reqJson))
 	if tmpErr != nil {
-		err = tmpErr
+		br.Msg = "计算指标失败"
+		br.ErrMsg = tmpErr.Error()
 		return
 	}
 	if respItem.Ret != 200 {
@@ -155,26 +206,57 @@ func (c *ExcelInfoController) CalculateData() {
 		num = lenDate
 	}
 
-	var currDate string // 当前日期
 	dataListResp := make([]*data_manage.EdbDataList, 0)
 
+	var newDate string
+	var showValue string
+	if req.DataTime == `` { //选择前移几期数
+		newDate, err = excel2.GetEdbDateByMoveForwardByDateList(requestBody, respItem.Data.DateList)
+		if err != nil {
+			return
+		}
+	} else {
+		newDate = req.DataTime //选择表格中的日期
+		if strings.Count(newDate, "-") == 1 {
+			newDate = newDate + "-01"
+			// 查找这个月早的时间作为起始时间
+			for _, v := range respItem.Data.DateList {
+				if v >= newDate {
+					newDate = v
+				}
+			}
+		}
+	}
+	// 开始做日期变换
+	newDate, err = excel2.HandleMixTableDateChange(newDate, requestBody)
+	if err != nil {
+		return
+	}
 	if req.DataTime == `` {
-		for i := 1; i <= num; i++ {
+		canAdd := false
+		for i := 1; i <= lenDate; i++ {
 			date := respItem.Data.DateList[lenDate-i]
 			val, ok := respItem.Data.DataMap[date]
 			if !ok {
 				continue
 			}
-
-			dataListResp = append(dataListResp, &data_manage.EdbDataList{
-				Value:    val,
-				DataTime: date,
-			})
+			if date == newDate {
+				showValue = utils.FormatMixTableDataShowValue(val)
+				canAdd = true
+			}
+			if canAdd && len(dataListResp) <= num {
+				dataListResp = append(dataListResp, &data_manage.EdbDataList{
+					Value:    val,
+					DataTime: date,
+				})
+			}
 		}
 	} else {
-		if val, ok := respItem.Data.DataMap[req.DataTime]; ok {
+		// todo 如果选择了表格中的日期应该如何处理
+		if val, ok := respItem.Data.DataMap[newDate]; ok {
+			showValue = utils.FormatMixTableDataShowValue(val)
 			for i, tmpDate := range respItem.Data.DateList {
-				if tmpDate == req.DataTime {
+				if tmpDate == newDate {
 					if i+3 <= lenDate {
 						t1Date := respItem.Data.DateList[i+2]
 						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
@@ -200,7 +282,7 @@ func (c *ExcelInfoController) CalculateData() {
 					// 当前日期
 					dataListResp = append(dataListResp, &data_manage.EdbDataList{
 						Value:    val,
-						DataTime: req.DataTime,
+						DataTime: newDate,
 					})
 					if i >= 1 {
 						t1Date := respItem.Data.DateList[i-1]
@@ -227,11 +309,140 @@ func (c *ExcelInfoController) CalculateData() {
 		}
 	}
 	resp := data_manage.BeforeAndAfterDateDataResp{
-		List: dataListResp,
-		Date: currDate,
+		List:      dataListResp,
+		Date:      newDate,
+		ShowValue: showValue,
 	}
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "计算成功"
 	br.Data = resp
 }
+
+// GetMixDateCalculate
+// @Title 获取混合表格日期计算
+// @Description 获取混合表格日期计算
+// @Param	request	body request.MixedTableCellDataReq true "type json string"
+// @router /excel_info/mixed/date_calculate [post]
+func (c *ExcelInfoController) GetMixDateCalculate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.MixedDateCalculateReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	valMap := make(map[string]int)
+	for _, v := range req.DateList {
+		// 查找单元格数据
+		// 如果不是基础计算单元格,直接返回
+		_, err = time.ParseInLocation(utils.FormatDate, v.Date, time.Local)
+		if err != nil {
+			br.Msg = "日期计算失败!"
+			br.ErrMsg = fmt.Sprintf("%s 的单元格非日期类型, Err: %s", v.Date, err.Error())
+			return
+		}
+		// todo 把日期转换成excel里的天数
+		realDiffDay := utils.GetDaysDiff1900(v.Date)
+
+		valMap[strings.ToUpper(v.Tag)] = realDiffDay
+	}
+
+	// 计算
+	val, errMsg, err := excel2.DateCalculateFormula(valMap, strings.ToUpper(req.Formula))
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	showValue := utils.FormatMixTableDataShowValue(val)
+
+	type resp struct {
+		ShowValue string
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.Data = resp{
+		ShowValue: showValue,
+	}
+}
+
+// GetBaseEdbInfo
+// @Title 获取指标的基本信息
+// @Description 获取指标的基本信息
+// @Param	EdbInfoIds	string  "指标ID用英文逗号分割"
+// @router /excel_info/base_edb_info [get]
+func (c *ExcelInfoController) GetBaseEdbInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	edbInfoIds := c.GetString("EdbInfoIds")
+	if edbInfoIds == "" {
+		br.Msg = "请输入指标ID"
+		return
+	}
+	ids := strings.Split(edbInfoIds, ",")
+	edbIds := make([]int, 0)
+	for _, v := range ids {
+		id, err := strconv.Atoi(v)
+		if err != nil {
+			br.Msg = "指标ID格式错误"
+			return
+		}
+		edbIds = append(edbIds, id)
+	}
+	edbInfoList, err := data_manage.GetEdbInfoByIdList(edbIds)
+	if err != nil {
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	list := make([]*data_manage.BaseEdbNameItem, 0)
+	for _, v := range edbInfoList {
+		tmp := new(data_manage.BaseEdbNameItem)
+
+		tmp.EdbInfoId = v.EdbInfoId
+		tmp.EdbInfoType = v.EdbInfoType
+		tmp.EdbCode = v.EdbCode
+		tmp.EdbName = v.EdbName
+		tmp.Source = v.Source
+		tmp.SourceName = v.SourceName
+		tmp.Frequency = v.Frequency
+		tmp.Unit = v.Unit
+		list = append(list, tmp)
+	}
+	resp := data_manage.BaseEdbInfoResp{
+		List: list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = resp
+}

+ 492 - 0
controllers/data_manage/fenwei_data.go

@@ -0,0 +1,492 @@
+package data_manage
+
+import (
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/tealeg/xlsx"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+// FenweiClassify
+// @Title 汾渭数据分类
+// @Description 汾渭数据分类接口
+// @Success 200 {object} data_manage.BaseFromFenweiClassifyItem
+// @router /fenwei/classify [get]
+func (this *EdbInfoController) FenweiClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	classifies, e := data_manage.GetBaseFromFenweiClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取汾渭数据分类失败, Err: " + e.Error()
+		return
+	}
+
+	classifyOb := new(data_manage.BaseFromFenweiClassify)
+	resp := make([]*data_manage.BaseFromFenweiClassifyItem, 0)
+	parentMap := make(map[int][]*data_manage.BaseFromFenweiClassifyItem)
+	for _, v := range classifies {
+		t := classifyOb.Format2Item(v)
+		if v.ParentId == 0 {
+			resp = append(resp, t)
+		}
+		if v.ParentId > 0 {
+			if parentMap[v.ParentId] == nil {
+				parentMap[v.ParentId] = make([]*data_manage.BaseFromFenweiClassifyItem, 0)
+			}
+			parentMap[v.ParentId] = append(parentMap[v.ParentId], t)
+		}
+	}
+	for _, v := range resp {
+		v.Child = parentMap[v.ClassifyId]
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// FenweiIndexData
+// @Title 获取汾渭数据
+// @Description 获取汾渭数据接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ClassifyId   query   string  true       "分类id"
+// @Success 200 {object} data_manage.LzFrequency
+// @router /fenwei/index/data [get]
+func (this *EdbInfoController) FenweiIndexData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	classifyId, _ := this.GetInt("ClassifyId")
+	if classifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	// 获取指标
+	var condition string
+	var pars []interface{}
+	if classifyId >= 0 {
+		condition += ` AND classify_id=? `
+		pars = append(pars, classifyId)
+	}
+
+	indexes, err := data_manage.GetFenweiIndex(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	indexCodes := make([]string, 0)
+	for _, v := range indexes {
+		indexCodes = append(indexCodes, v.IndexCode)
+	}
+	indexCounts, e := data_manage.GetFenweiIndexDataCountGroup(indexCodes)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取指标数据总量失败, Err:" + err.Error()
+		return
+	}
+	countMap := make(map[string]int)
+	for _, v := range indexCounts {
+		countMap[v.IndexCode] = v.Count
+	}
+
+	resultList := make([]*data_manage.BaseFromFenweiIndexList, 0)
+	for _, v := range indexes {
+		product := new(data_manage.BaseFromFenweiIndexList)
+		product.FenweiIndexId = v.FenweiIndexId
+		product.ClassifyId = v.ClassifyId
+		product.Unit = v.Unit
+		product.IndexCode = v.IndexCode
+		product.IndexName = v.IndexName
+		product.Frequency = v.Frequency
+		product.CreateTime = v.CreateTime
+		product.ModifyTime = v.ModifyTime
+
+		total := countMap[v.IndexCode]
+		page := paging.GetPaging(currentIndex, pageSize, total)
+		dataList, e := data_manage.GetFenweiIndexData(v.IndexCode, startSize, pageSize)
+		if e != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + e.Error()
+			return
+		}
+		if dataList == nil {
+			dataList = make([]*data_manage.BaseFromFenweiData, 0)
+		}
+		product.DataList = dataList
+		product.Paging = page
+		resultList = append(resultList, product)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resultList
+}
+
+// FenweiSearchList
+// @Title Fenwei模糊搜索
+// @Description Fenwei模糊搜索
+// @Param   Keyword   query   string  ture       "关键字搜索"
+// @Success 200 {object} data_manage.BaseFromFenweiIndexSearchItem
+// @router /fenwei/search_list [get]
+func (this *EdbInfoController) FenweiSearchList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	list := make([]*data_manage.BaseFromFenweiIndexSearchItem, 0)
+	var err error
+	// 关键字
+	keyword := this.GetString("Keyword")
+	if keyword != "" {
+		keyWordArr := strings.Split(keyword, " ")
+
+		if len(keyWordArr) > 0 {
+			condition := ""
+			for _, v := range keyWordArr {
+				condition += ` AND CONCAT(index_name,index_code) LIKE '%` + v + `%'`
+			}
+			list, err = data_manage.GetFenweiItemList(condition)
+			if err != nil {
+				br.ErrMsg = "获取失败,Err:" + err.Error()
+				br.Msg = "获取失败"
+				return
+			}
+		}
+	} else {
+		list, err = data_manage.GetFenweiItemList("")
+		if err != nil {
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			br.Msg = "获取失败"
+			return
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// FenweiSingleData
+// @Title 获取Fenwei数据
+// @Description 获取Fenwei单条数据接口
+// @Param   IndexCode   query   string  true       "指标唯一编码"
+// @Success 200 {object} models.BaseResponse
+// @router /fenwei/single_data [get]
+func (this *EdbInfoController) FenweiSingleData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	indexCode := this.GetString("IndexCode")
+	indexInfo, err := data_manage.GetBaseFromFenweiIndexByIndexCode(indexCode)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	dataTmpList, err := data_manage.GetFenweiIndexDataByCode(indexCode)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	var ret data_manage.FenweiSingleDataResp
+	var dataList []*data_manage.FenweiSingleData
+
+	ret.ClassifyId = indexInfo.ClassifyId
+	ret.FenweiIndexId = indexInfo.FenweiIndexId
+	ret.IndexCode = indexInfo.IndexCode
+	ret.IndexName = indexInfo.IndexName
+	ret.Frequency = indexInfo.Frequency
+	ret.CreateTime = indexInfo.CreateTime.Format(utils.FormatDateTime)
+	ret.ModifyTime = indexInfo.ModifyTime.Format(utils.FormatDateTime)
+	ret.Unit = indexInfo.Unit
+	for _, v := range dataTmpList {
+		tmp := &data_manage.FenweiSingleData{
+			Value:    v.Value,
+			DataTime: v.DataTime,
+		}
+		dataList = append(dataList, tmp)
+	}
+	ret.Data = dataList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
+// ExportFenweiList
+// @Title 导出Fenwei数据
+// @Description 导出Fenwei数据
+// @Param   IndexName   query   string  false       "名称关键词"
+// @Param   IndexCode   query   string  false       "指标唯一编码"
+// @Param   ClassifyId   query   string  true       "分类"
+// @Success 200  导出成功
+// @router /fenwei/export [get]
+func (this *EdbInfoController) ExportFenweiList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	indexCode := this.GetString("IndexCode") //指标唯一编码
+	classifyId, _ := this.GetInt("ClassifyId")
+	//secNameList := make([]*models.EdbdataExportList, 0)
+
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+
+	var pars []interface{}
+	condition := ""
+	if classifyId > 0 {
+		//获取指标
+		condition += " AND classify_id=?"
+		pars = append(pars, classifyId)
+	}
+	if indexCode != "" {
+		//获取指标
+		condition += " AND index_code=?"
+		pars = append(pars, indexCode)
+	}
+	indexList, err := data_manage.GetFenweiIndex(condition, pars)
+	if err != nil {
+		fmt.Println("获取数据失败,Err:" + err.Error())
+		return
+	}
+	if len(indexList) <= 0 {
+		fmt.Println("indexList 为空")
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "success"
+		return
+	}
+	sheetNew := new(xlsx.Sheet)
+	// todo 分类名称
+	sheetNew, err = xlsxFile.AddSheet("汾渭数据")
+	//sheetNew.SetColWidth()
+	//获取指标数据
+	windRow := sheetNew.AddRow()
+	secNameRow := sheetNew.AddRow()
+	indexCodeRow := sheetNew.AddRow()
+	frequencyRow := sheetNew.AddRow()
+	unitRow := sheetNew.AddRow()
+	lastModifyDateRow := sheetNew.AddRow()
+	//获取分类下指标最大数据量
+	var dataMax int
+	setRowIndex := 6
+	indexCodeList := make([]string, 0)
+	for _, v := range indexList {
+		indexCodeList = append(indexCodeList, v.IndexCode)
+	}
+	dataListMap := make(map[string][]*data_manage.BaseFromFenweiData)
+	if len(indexList) > 0 {
+		allDataList, e := data_manage.GetFenweiIndexDataByCodes(indexCodeList)
+		if e != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取数据失败,Err:" + e.Error()
+			return
+		}
+		for _, v := range allDataList {
+			dataListMap[v.IndexCode] = append(dataListMap[v.IndexCode], v)
+		}
+		for _, v := range dataListMap {
+			if len(v) > dataMax {
+				dataMax = len(v)
+			}
+		}
+	}
+
+	for k, sv := range indexList {
+		//获取数据
+		dataList, ok := dataListMap[sv.IndexCode]
+		if !ok {
+			continue
+		}
+		if len(dataList) > 0 {
+			windRow.AddCell().SetValue("汾渭数据")
+			secNameRow.AddCell().SetValue("指标名称")
+			indexCodeRow.AddCell().SetValue("指标ID")
+			frequencyRow.AddCell().SetValue("频率")
+			unitRow.AddCell().SetValue("单位")
+			lastModifyDateRow.AddCell().SetValue("更新时间")
+
+			secNameRow.AddCell().SetValue(sv.IndexName)
+			indexCodeRow.AddCell().SetValue(sv.IndexCode)
+			frequencyRow.AddCell().SetValue(sv.Frequency)
+
+			unitRow.AddCell().SetValue(sv.Unit)
+			lastModifyDateRow.AddCell().SetValue(sv.ModifyTime)
+
+			windRow.AddCell()
+			windRow.AddCell()
+			secNameRow.AddCell()
+			indexCodeRow.AddCell()
+			frequencyRow.AddCell()
+			unitRow.AddCell()
+			lastModifyDateRow.AddCell()
+			min := k * 3
+			sheetNew.SetColWidth(min, min, 15)
+
+			if len(dataList) <= 0 {
+				for n := 0; n < dataMax; n++ {
+					rowIndex := setRowIndex + n
+					row := sheetNew.Row(rowIndex)
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+				}
+			} else {
+				endRowIndex := 0
+				for rk, dv := range dataList {
+					rowIndex := setRowIndex + rk
+					row := sheetNew.Row(rowIndex)
+					displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
+					displayDateCell := row.AddCell()
+					style := new(xlsx.Style)
+					style.ApplyAlignment = true
+					style.Alignment.WrapText = true
+					displayDateCell.SetStyle(style)
+					displayDateCell.SetDate(displayDate)
+
+					row.AddCell().SetValue(dv.Value)
+					row.AddCell()
+					endRowIndex = rowIndex
+				}
+				if len(dataList) < dataMax {
+					dataLen := dataMax - len(dataList)
+					for n := 0; n < dataLen; n++ {
+						rowIndex := (endRowIndex + 1) + n
+						row := sheetNew.Row(rowIndex)
+						row.AddCell()
+						row.AddCell()
+						row.AddCell()
+					}
+				}
+			}
+		}
+	}
+
+	err = xlsxFile.Save(downLoadnFilePath)
+	if err != nil {
+		//有指标无数据时先导出一遍空表
+		sheet, err := xlsxFile.AddSheet("无数据")
+		if err != nil {
+			br.Msg = "新增Sheet失败"
+			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
+			return
+		}
+		rowSecName := sheet.AddRow()
+		celSecName := rowSecName.AddCell()
+		celSecName.SetValue("")
+		err = xlsxFile.Save(downLoadnFilePath)
+		if err != nil {
+			br.Msg = "保存文件失败"
+			br.ErrMsg = "保存文件失败"
+			return
+		}
+	}
+	fileName := `汾渭数据`
+	if len(indexList) > 0 {
+		fileName = indexList[0].IndexName
+	}
+	fileName += time.Now().Format("06.01.02") + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+
+}

+ 33 - 19
controllers/data_manage/future_good/future_good_chart_info.go

@@ -2388,7 +2388,7 @@ func (this *FutureGoodChartInfoController) ChartInfoBase64Upload() {
 		}
 	}
 
-	var saveToOssPath string
+	//var saveToOssPath string
 	randStr := utils.GetRandStringNoSpecialChar(28)
 	var fileName, outFileName string
 	fileName = randStr + ".txt"
@@ -2432,29 +2432,43 @@ func (this *FutureGoodChartInfoController) ChartInfoBase64Upload() {
 
 	defer func() {
 		os.Remove(fileName)
+		os.Remove(outFileName)
 	}()
 
-	saveToOssPath = uploadDir + time.Now().Format("200601/20060102/")
-	saveToOssPath += outFileName
+	//saveToOssPath = uploadDir + time.Now().Format("200601/20060102/")
+	//saveToOssPath += outFileName
 	//上传到阿里云 和 minio
 	resourceUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadFileToMinIo("", outFileName, saveToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.MinIoImghost + saveToOssPath
-	} else {
-		err = services.UploadFileToAliyun("", outFileName, saveToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.Imghost + saveToOssPath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadFileToMinIo("", outFileName, saveToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + saveToOssPath
+	//} else {
+	//	err = services.UploadFileToAliyun("", outFileName, saveToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + saveToOssPath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
 	}
+	resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
 	resp.ResourceUrl = resourceUrl
 	resp.Source = "convert"
 	//resp.CacheKey = imgDataKey

+ 416 - 0
controllers/data_source/guagnzhouqihuo.go

@@ -0,0 +1,416 @@
+package data_source
+
+import (
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_source"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/tealeg/xlsx"
+	"os"
+	"path/filepath"
+	"strconv"
+	"time"
+)
+
+// 广州期货交易所
+type DataSourceController struct {
+	controllers.BaseAuthController
+}
+
+// ComTradeCountryList
+// @Title 获取广州期货交易所分类
+// @Description 获取广州期货交易所分类
+// @Success 200 {object} []data_manage.ComTradeCountryItem
+// @router /gfex/classify/list [get]
+func (this *DataSourceController) GfexClassifyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	classifyList, err := gzqhObj.GetBaseFromTradeGuangzhouClassifyAll()
+	if err != nil {
+		br.Msg = "获取分类失败"
+		br.ErrMsg = "获取分类失败,Err:" + err.Error()
+		return
+	}
+
+	classifyMap := make(map[int][]*data_source.BaseFromTradeGuangzhouClassifyView)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			continue
+		}
+		if items, ok := classifyMap[v.ParentId]; !ok {
+			list := make([]*data_source.BaseFromTradeGuangzhouClassifyView, 0)
+			list = append(list, v)
+			classifyMap[v.ParentId] = list
+		} else {
+			items = append(items, v)
+			classifyMap[v.ParentId] = items
+		}
+	}
+
+	classifyItems := make([]*data_source.BaseFromTradeGuangzhouClassifyView, 0)
+	for _, v := range classifyList {
+		if v.ParentId == 0 {
+			v.Children = classifyMap[v.BaseFromTradeGuangzhouClassifyId]
+			classifyItems = append(classifyItems, v)
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = classifyItems
+}
+
+// ComTradeCountryList
+// @Title 获取广州期货交易所数据最大日期
+// @Description 获取广州期货交易所数据最大日期
+// @Success 200 {object} []data_source.ComTradeCountryItem
+// @router /gfex/max/date [get]
+func (this *DataSourceController) GfexMaxDate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	maxDate, err := gzqhObj.GetBaseFromTradeGuangzhouMaxDate()
+	if err != nil {
+		br.ErrMsg = "获取最新日期失败,Err:" + err.Error()
+		br.Msg = "获取最新日期失败"
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = maxDate
+}
+
+// ComTradeCountryList
+// @Title 获取广州期货交易所-分类下合约
+// @Description 获取广州期货交易所-分类下合约
+// @Param   BaseFromTradeGuangzhouClassifyId   query   int  true       "分类id"
+// @Param   TradeDate   query   string  true       "日期"
+// @Success 200 {object} []data_source.BaseFromTradeGuangzhouContract
+// @router /gfex/contract [get]
+func (this *DataSourceController) GfexContract() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	baseFromTradeGuangzhouClassifyId, _ := this.GetInt("BaseFromTradeGuangzhouClassifyId", 0)
+	if baseFromTradeGuangzhouClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.Msg = "分类id错误"
+		return
+	}
+	tradeDate := this.GetString("TradeDate")
+	if tradeDate == "" {
+		br.Msg = "参数错误"
+		br.Msg = "交易日期不能为空"
+		return
+	}
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	list, err := gzqhObj.GetBaseFromTradeGuangzhouContract(baseFromTradeGuangzhouClassifyId, tradeDate)
+	if err != nil {
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		br.Msg = "获取数据失败"
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// ComTradeCountryList
+// @Title 获取广州期货交易所-分类下指标信息
+// @Description 获取广州期货交易所-分类下指标信息
+// @Param   BaseFromTradeGuangzhouClassifyId   query   int  true       "分类id"
+// @Param   BaseFromTradeGuangzhouContractId   query   int  true       "合约id"
+// @Param   TradeDate   query   string  true       "日期"
+// @Success 200 {object} []data_source.BaseFromTradeGuangzhouIndexView
+// @router /gfex/index_data [get]
+func (this *DataSourceController) GfexIndexData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	baseFromTradeGuangzhouClassifyId, _ := this.GetInt("BaseFromTradeGuangzhouClassifyId", 0)
+	if baseFromTradeGuangzhouClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "分类id错误"
+		return
+	}
+	tradeDate := this.GetString("TradeDate")
+	if tradeDate == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "交易日期不能为空"
+		return
+	}
+	baseFromTradeGuangzhouContractId, err := this.GetInt("BaseFromTradeGuangzhouContractId", 0)
+	fmt.Println(err)
+	fmt.Println(baseFromTradeGuangzhouContractId)
+
+	var condition string
+	var pars []interface{}
+
+	if baseFromTradeGuangzhouContractId > 0 {
+		condition += `  b.data_time=? `
+		pars = append(pars, tradeDate)
+		condition += ` AND a.base_from_trade_guangzhou_classify_id=? `
+		pars = append(pars, baseFromTradeGuangzhouClassifyId)
+	} else {
+		if baseFromTradeGuangzhouClassifyId == 11 || baseFromTradeGuangzhouClassifyId == 12 { //月度数据处理
+			td, err := time.Parse(utils.FormatDate, tradeDate)
+			if err != nil {
+				br.Msg = "日期格式错误"
+				br.ErrMsg = "日期格式错误,Err:" + err.Error()
+				return
+			}
+			_, monthEndDay := utils.GetMonthStartAndEnd(strconv.Itoa(td.Year()), strconv.Itoa(int(td.Month())))
+			condition += `  a.data_time=? `
+			pars = append(pars, monthEndDay)
+		} else {
+			condition += `  a.data_time=? `
+			pars = append(pars, tradeDate)
+		}
+
+		condition += ` AND b.base_from_trade_guangzhou_classify_id=? `
+		pars = append(pars, baseFromTradeGuangzhouClassifyId)
+	}
+
+	//if baseFromTradeGuangzhouContractId > 0 {
+	//	condition += ` AND c.base_from_trade_guangzhou_contract_id=? `
+	//	pars = append(pars, baseFromTradeGuangzhouContractId)
+	//}
+
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	list, err := gzqhObj.GetBaseFromTradeGuangzhouIndex(condition, pars, baseFromTradeGuangzhouContractId)
+	if err != nil {
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		br.Msg = "获取数据失败"
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// @Title 获取广州期货交易所-一次性交割卖方仓单明细
+// @Description 获取广州期货交易所-一次性交割卖方仓单明细
+// @Param   BaseFromTradeGuangzhouIndexId   query   int  true       "指标id"
+// @Param   TradeDate   query   string  true       "日期"
+// @Success 200 {object} []data_source.BaseFromTradeGuangzhouIndexView
+// @router /gfex/index/detail [get]
+func (this *DataSourceController) GfexIndexDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	baseFromTradeGuangzhouIndexId, _ := this.GetInt("BaseFromTradeGuangzhouIndexId", 0)
+	if baseFromTradeGuangzhouIndexId < 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	tradeDate := this.GetString("TradeDate")
+	if tradeDate == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "交易日期不能为空"
+		return
+	}
+
+	var condition string
+	var pars []interface{}
+
+	condition += ` a.base_from_trade_guangzhou_classify_id = ? `
+	pars = append(pars, baseFromTradeGuangzhouIndexId)
+
+	td, err := time.Parse(utils.FormatDate, tradeDate)
+	if err != nil {
+		br.Msg = "日期格式错误"
+		br.ErrMsg = "日期格式错误,Err:" + err.Error()
+		return
+	}
+	_, monthEndDay := utils.GetMonthStartAndEnd(strconv.Itoa(td.Year()), strconv.Itoa(int(td.Month())))
+	condition += ` AND a.end_date = ? `
+	pars = append(pars, monthEndDay)
+
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	list, err := gzqhObj.GetBaseFromTradeGuangzhouIndexDetail(condition, pars)
+	if err != nil {
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		br.Msg = "获取数据失败"
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// @Title 导出广州期货交易所-一次性交割卖方仓单明细
+// @Description 导出广州期货交易所-一次性交割卖方仓单明细
+// @Param   BaseFromTradeGuangzhouIndexId   query   int  true       "指标id"
+// @Param   TradeDate   query   string  true       "日期"
+// @Success 200  导出成功
+// @router /gfex/index/detail/export [get]
+func (this *DataSourceController) ExportGfexIndexDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	baseFromTradeGuangzhouIndexId, _ := this.GetInt("BaseFromTradeGuangzhouIndexId", 0)
+	if baseFromTradeGuangzhouIndexId < 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	tradeDate := this.GetString("TradeDate")
+	if tradeDate == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "交易日期不能为空"
+		return
+	}
+
+	var condition string
+	var pars []interface{}
+
+	condition += ` a.base_from_trade_guangzhou_classify_id = ? `
+	pars = append(pars, baseFromTradeGuangzhouIndexId)
+
+	td, err := time.Parse(utils.FormatDate, tradeDate)
+	if err != nil {
+		br.Msg = "日期格式错误"
+		br.ErrMsg = "日期格式错误,Err:" + err.Error()
+		return
+	}
+	_, monthEndDay := utils.GetMonthStartAndEnd(strconv.Itoa(td.Year()), strconv.Itoa(int(td.Month())))
+	condition += ` AND a.end_date = ? `
+	pars = append(pars, monthEndDay)
+
+	gzqhObj := new(data_source.BaseFromTradeGuangzhouIndex)
+	list, err := gzqhObj.GetBaseFromTradeGuangzhouIndexDetail(condition, pars)
+	if err != nil {
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		br.Msg = "获取数据失败"
+		return
+	}
+
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+	sheetNew, err := xlsxFile.AddSheet("详情")
+	if err != nil {
+		br.ErrMsg = "导出失败,Err:" + err.Error()
+		br.Msg = "导出失败"
+		return
+	}
+	titleRow := sheetNew.AddRow()
+	titleRow.AddCell().SetValue("指标ID")
+	titleRow.AddCell().SetValue("指标名称")
+	titleRow.AddCell().SetValue("数值")
+	titleRow.AddCell().SetValue("单位")
+	titleRow.AddCell().SetValue("频度")
+	titleRow.AddCell().SetValue("起始日期")
+	titleRow.AddCell().SetValue("最新日期")
+
+	var indexCode string
+	for _, sv := range list {
+		dataRow := sheetNew.AddRow()
+		dataRow.AddCell().SetValue(sv.IndexCode)
+		dataRow.AddCell().SetValue(sv.IndexName)
+		dataRow.AddCell().SetValue(sv.Value)
+		dataRow.AddCell().SetValue(sv.Unit)
+		dataRow.AddCell().SetValue(sv.Frequency)
+		dataRow.AddCell().SetValue(sv.StartDate)
+		dataRow.AddCell().SetValue(sv.EndDate)
+
+		indexCode = sv.IndexCode
+	}
+	err = xlsxFile.Save(downLoadnFilePath)
+	if err != nil {
+		//有指标无数据时先导出一遍空表
+		sheet, err := xlsxFile.AddSheet("无数据")
+		if err != nil {
+			br.Msg = "新增Sheet失败"
+			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
+			return
+		}
+		rowSecName := sheet.AddRow()
+		celSecName := rowSecName.AddCell()
+		celSecName.SetValue("")
+		err = xlsxFile.Save(downLoadnFilePath)
+		if err != nil {
+			br.Msg = "保存文件失败"
+			br.ErrMsg = "保存文件失败"
+			return
+		}
+	}
+	fileName := `一次性交割卖方仓单详情`
+	fileName = indexCode[:6] + fileName + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+
+}

+ 329 - 0
controllers/data_source/icpi.go

@@ -0,0 +1,329 @@
+package data_source
+
+import (
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_source"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/tealeg/xlsx"
+	"os"
+	"path/filepath"
+	"time"
+)
+
+// 消费者价格指数
+
+// ComTradeCountryList
+// @Title 获取居民消费价格指数分类
+// @Description 获取居民消费价格指数分类
+// @Success 200 {object} []data_manage.ComTradeCountryItem
+// @router /icpi/classify/list [get]
+func (this *DataSourceController) IcpiClassifyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	icpiObj := new(data_source.BaseFromIcpiIndex)
+	classifyList, err := icpiObj.GetBaseFromIcpiClassifyAll()
+	if err != nil {
+		br.Msg = "获取分类失败"
+		br.ErrMsg = "获取分类失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = classifyList
+}
+
+// @Title 获取消费者价格指数数据
+// @Description 获取消费者价格指数数据接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   BaseFromIcpiClassifyId   query   int  true       "分类id"
+// @Param   KeyWord   query   string  true       "关键词"
+// @Success 200 {object} data_source.BaseFromIcpiIndexView
+// @router /icpi/index/data [get]
+func (this *DataSourceController) IcpiData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	baseFromIcpiClassifyId, _ := this.GetInt("BaseFromIcpiClassifyId")
+	if baseFromIcpiClassifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	keyword := this.GetString("KeyWord")
+
+	//获取指标
+	var condition string
+	var pars []interface{}
+
+	if baseFromIcpiClassifyId > 0 {
+		condition += ` AND base_from_icpi_classify_id=? `
+		pars = append(pars, baseFromIcpiClassifyId)
+	}
+
+	if keyword != "" {
+		condition += ` AND (index_code =? OR index_name LIKE ?)  `
+		pars = append(pars, keyword)
+		pars = append(pars, "%"+keyword+"%")
+	}
+
+	icpiObj := new(data_source.BaseFromIcpiIndex)
+
+	icpiList, err := icpiObj.GetIcpiIndex(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	resultList := make([]*data_source.BaseFromIcpiIndexView, 0)
+	for _, v := range icpiList {
+		product := new(data_source.BaseFromIcpiIndexView)
+		product.BaseFromIcpiIndexId = v.BaseFromIcpiIndexId
+		product.BaseFromIcpiClassifyId = v.BaseFromIcpiClassifyId
+		product.IndexCode = v.IndexCode
+		product.IndexName = v.IndexName
+		product.Frequency = v.Frequency
+		product.Unit = v.Unit
+		product.ModifyTime = v.ModifyTime
+
+		total, err := icpiObj.GetIcpiIndexDataCount(v.IndexCode)
+		page := paging.GetPaging(currentIndex, pageSize, total)
+		dataList, err := icpiObj.GetIcpiIndexData(v.IndexCode, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		if dataList == nil {
+			dataList = make([]*data_source.BaseFromIcpiDataView, 0)
+		}
+		product.DataList = dataList
+		product.Paging = page
+		resultList = append(resultList, product)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resultList
+}
+
+// ExportBaiinfoList
+// @Title 导出ICPI数据
+// @Description 导出ICPI数据
+// @Param   BaseFromIcpiClassifyId   query   int  true       "分类id"
+// @Param   KeyWord   query   string  true       "关键词"
+// @Success 200  导出成功
+// @router /icpi/export/icpiDataList [get]
+func (this *DataSourceController) ExportIcpiDataList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	baseFromIcpiClassifyId, _ := this.GetInt("BaseFromIcpiClassifyId")
+	if baseFromIcpiClassifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	keyword := this.GetString("KeyWord")
+
+	//获取指标
+	var condition string
+	var pars []interface{}
+
+	if baseFromIcpiClassifyId >= 0 {
+		condition += ` AND base_from_icpi_classify_id=? `
+		pars = append(pars, baseFromIcpiClassifyId)
+	}
+
+	if keyword != "" {
+		condition += ` AND (index_code =? OR index_name LIKE ?)  `
+		pars = append(pars, keyword)
+		pars = append(pars, "%"+keyword+"%")
+	}
+
+	icpiObj := new(data_source.BaseFromIcpiIndex)
+
+	icpiList, err := icpiObj.GetIcpiIndex(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+
+	if err != nil {
+		fmt.Println("新增Sheet失败", err.Error())
+		return
+	}
+	//sheetNew.SetColWidth()
+	//获取指标数据
+	sheetNew, _ := xlsxFile.AddSheet("ICPI消费价格指数")
+	windRow := sheetNew.AddRow()
+	secNameRow := sheetNew.AddRow()
+	indexCodeRow := sheetNew.AddRow()
+	frequencyRow := sheetNew.AddRow()
+	unitRow := sheetNew.AddRow()
+	lastModifyDateRow := sheetNew.AddRow()
+	//获取分类下指标最大数据量
+	dataMax, err := icpiObj.GetIcpiDataMaxCount(baseFromIcpiClassifyId)
+	if err != nil {
+		fmt.Println("获取指标最大数据量失败", err.Error())
+		return
+	}
+	fmt.Println("dataMax:", dataMax)
+	setRowIndex := 6
+	for k, sv := range icpiList {
+		//获取数据
+		dataList, err := icpiObj.GetIcpiIndexDataByCode(sv.IndexCode)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if len(dataList) > 0 {
+			windRow.AddCell().SetValue("ICPI消费价格指数")
+			secNameRow.AddCell().SetValue("指标名称")
+			indexCodeRow.AddCell().SetValue("指标ID")
+			frequencyRow.AddCell().SetValue("频率")
+			unitRow.AddCell().SetValue("单位")
+			lastModifyDateRow.AddCell().SetValue("更新时间")
+
+			secNameRow.AddCell().SetValue(sv.IndexName)
+			indexCodeRow.AddCell().SetValue(sv.IndexCode)
+			frequencyRow.AddCell().SetValue(sv.Frequency)
+			unitRow.AddCell().SetValue(sv.Unit)
+			lastModifyDateRow.AddCell().SetValue(sv.ModifyTime)
+
+			windRow.AddCell()
+			windRow.AddCell()
+			secNameRow.AddCell()
+			indexCodeRow.AddCell()
+			frequencyRow.AddCell()
+			unitRow.AddCell()
+			lastModifyDateRow.AddCell()
+			min := k * 3
+			sheetNew.SetColWidth(min, min, 15)
+
+			if len(dataList) <= 0 {
+				for n := 0; n < dataMax; n++ {
+					rowIndex := setRowIndex + n
+					row := sheetNew.Row(rowIndex)
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+				}
+			} else {
+				endRowIndex := 0
+				for rk, dv := range dataList {
+					rowIndex := setRowIndex + rk
+					row := sheetNew.Row(rowIndex)
+					displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
+					displayDateCell := row.AddCell()
+					style := new(xlsx.Style)
+					style.ApplyAlignment = true
+					style.Alignment.WrapText = true
+					displayDateCell.SetStyle(style)
+					displayDateCell.SetDate(displayDate)
+
+					row.AddCell().SetValue(dv.Value)
+					row.AddCell()
+					endRowIndex = rowIndex
+				}
+				if len(dataList) < dataMax {
+					dataLen := dataMax - len(dataList)
+					for n := 0; n < dataLen; n++ {
+						rowIndex := (endRowIndex + 1) + n
+						row := sheetNew.Row(rowIndex)
+						row.AddCell()
+						row.AddCell()
+						row.AddCell()
+						row.AddCell()
+					}
+				}
+			}
+		}
+	}
+
+	err = xlsxFile.Save(downLoadnFilePath)
+	if err != nil {
+		//有指标无数据时先导出一遍空表
+		sheet, err := xlsxFile.AddSheet("无数据")
+		if err != nil {
+			br.Msg = "新增Sheet失败"
+			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
+			return
+		}
+		rowSecName := sheet.AddRow()
+		celSecName := rowSecName.AddCell()
+		celSecName.SetValue("")
+		err = xlsxFile.Save(downLoadnFilePath)
+		if err != nil {
+			br.Msg = "保存文件失败"
+			br.ErrMsg = "保存文件失败"
+			return
+		}
+	}
+	fileName := `ICPI消费价格指数`
+	fileName += time.Now().Format(utils.FormatDateUnSpace) + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+
+}

+ 2 - 18
controllers/english_report/english_auth.go

@@ -204,12 +204,6 @@ func (this *EnglishAuthController) BatchAdd() {
 		br.Ret = 408
 		return
 	}
-	if utils.BusinessCode != utils.BusinessCodeRelease {
-		br.Ret = 200
-		br.Success = true
-		br.Msg = "操作成功"
-		return
-	}
 
 	var req request.AddEnglishAuthRoleAdminReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -452,12 +446,7 @@ func (this *EnglishAuthController) Edit() {
 		br.Ret = 408
 		return
 	}
-	if utils.BusinessCode != utils.BusinessCodeRelease {
-		br.Ret = 200
-		br.Success = true
-		br.Msg = "操作成功"
-		return
-	}
+
 	var req request.EditEnglishAuthRoleAdminReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -595,12 +584,7 @@ func (this *EnglishAuthController) Del() {
 		br.Ret = 408
 		return
 	}
-	if utils.BusinessCode != utils.BusinessCodeRelease {
-		br.Ret = 200
-		br.Success = true
-		br.Msg = "操作成功"
-		return
-	}
+
 	var req request.DelEnglishAuthRoleAdminReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {

+ 1 - 4
controllers/english_report/report.go

@@ -956,10 +956,7 @@ func (this *EnglishReportController) Delete() {
 	go func() {
 		_ = services.ResetPPTReport(req.ReportIds, true)
 	}()
-
-	go func() {
-		_ = services.EnglishPolicyReportSyncCancel(reportInfo)
-	}()
+	
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "删除成功"

+ 32 - 20
controllers/ppt_english.go

@@ -541,30 +541,42 @@ func (this *PptEnglishController) PptUpload() {
 	pptName := utils.GetRandStringNoSpecialChar(28)
 	savePptxToOssPath += pptName + ".pptx"
 
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+
 	//上传到阿里云 和 minio
 	pptxUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadFileToMinIo("", fpath, savePptxToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		pptxUrl = utils.MinIoImghost + savePptxToOssPath
-	} else {
-		err = services.UploadFileToAliyun("", fpath, savePptxToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		pptxUrl = utils.Imghost + savePptxToOssPath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadFileToMinIo("", fpath, savePptxToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	pptxUrl = utils.MinIoImghost + savePptxToOssPath
+	//} else {
+	//	err = services.UploadFileToAliyun("", fpath, savePptxToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	pptxUrl = utils.Imghost + savePptxToOssPath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	pptxUrl, err = ossClient.UploadFile("", fpath, savePptxToOssPath)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
-	defer func() {
-		os.Remove(fpath)
-	}()
-
 	item := &models.Resource{
 		//Id:           0,
 		ResourceUrl:  pptxUrl,

+ 32 - 20
controllers/ppt_v2.go

@@ -542,30 +542,42 @@ func (this *PptV2Controller) PptUpload() {
 	pptName := utils.GetRandStringNoSpecialChar(28)
 	savePptxToOssPath += pptName + ".pptx"
 
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+
 	//上传到阿里云 和 minio
 	pptxUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadFileToMinIo("", fpath, savePptxToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		pptxUrl = utils.MinIoImghost + savePptxToOssPath
-	} else {
-		err = services.UploadFileToAliyun("", fpath, savePptxToOssPath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		pptxUrl = utils.Imghost + savePptxToOssPath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadFileToMinIo("", fpath, savePptxToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	pptxUrl = utils.MinIoImghost + savePptxToOssPath
+	//} else {
+	//	err = services.UploadFileToAliyun("", fpath, savePptxToOssPath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	pptxUrl = utils.Imghost + savePptxToOssPath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	pptxUrl, err = ossClient.UploadFile("", fpath, savePptxToOssPath)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
-	defer func() {
-		os.Remove(fpath)
-	}()
-
 	item := &models.Resource{
 		//Id:           0,
 		ResourceUrl:  pptxUrl,

+ 46 - 24
controllers/report.go

@@ -929,20 +929,32 @@ func (this *ReportController) Upload() {
 
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
 	defer func() {
@@ -1243,16 +1255,26 @@ func (this *ReportUploadCommonController) UploadImg() {
 	}
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
-		if err != nil {
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
-		if err != nil {
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
+	//	if err != nil {
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
 
 	defer func() {

+ 191 - 104
controllers/resource.go

@@ -60,20 +60,32 @@ func (this *ResourceController) Upload() {
 	}
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
 	defer func() {
@@ -237,28 +249,45 @@ func (this *ResourceController) VideoUpload() {
 	utils.FileLog.Info("start update oss ")
 	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
 
-	savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	savePath += fileName
+	//savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+	//savePath += fileName
+
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
 
 	//上传到阿里云 和 minio
 	resourceUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadVideoToMinIo(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.MinIoImghost + savePath
-	} else {
-		err = services.UploadVideoAliyun(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.Imghost + savePath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadVideoToMinIo(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + savePath
+	//} else {
+	//	err = services.UploadVideoAliyun(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + savePath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
+
 	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
 	utils.FileLog.Info("end update oss ")
 
@@ -414,26 +443,42 @@ func (this *ResourceController) VoiceUpload() {
 	utils.FileLog.Info("start update oss ")
 	utils.FileLog.Info(fmt.Sprintf("%s:", time.Now().Format(utils.FormatDateTime)))
 
-	savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	savePath += fileName
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+
+	//savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+	//savePath += fileName
 	//上传到阿里云 和 minio
 	resourceUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadVideoToMinIo(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.MinIoImghost + savePath
-	} else {
-		err = services.UploadVideoAliyun(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.Imghost + savePath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadVideoToMinIo(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + savePath
+	//} else {
+	//	err = services.UploadVideoAliyun(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + savePath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 	utils.FileLog.Info(fmt.Sprintf("%s:", time.Now().Format(utils.FormatDateTime)))
 	utils.FileLog.Info("end update oss ")
@@ -582,22 +627,34 @@ func (this *ResourceController) UploadImageBase64() {
 
 	//上传到阿里云 和 minio
 	resourceUrl := ``
-	if utils.ObjectStorageClient == "minio" {
-		err = services.UploadFileToMinIo(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.MinIoImghost + savePath
-	} else {
-		err = services.UploadFileToAliyun(fileName, fpath, savePath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-		resourceUrl = utils.Imghost + savePath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = services.UploadFileToMinIo(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + savePath
+	//} else {
+	//	err = services.UploadFileToAliyun(fileName, fpath, savePath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + savePath
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, savePath)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
 	utils.FileLog.Info("end update oss ")
@@ -723,20 +780,32 @@ func (this *ResourceController) UploadV2() {
 	}
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
 	defer func() {
@@ -775,29 +844,47 @@ func (this *ResourceController) OssSTSToken() {
 		this.ServeJSON()
 	}()
 
-	source, _ := this.GetInt("StorageSource")
-
-	if source == utils.STORAGESOURCE_OSS {
-		resp, err := services.GetOssSTSToken()
-		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取STSToken失败, Err: " + err.Error()
-			return
-		}
-		br.Data = resp
-		br.Msg = "获取成功"
-		br.Ret = 200
-		br.Success = true
-	} else if source == utils.STORAGESOURCE_MINIO {
-		resp, err := services.GetMinIOSTSToken()
-		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取STSToken失败, Err: " + err.Error()
-			return
-		}
-		br.Data = resp
-		br.Msg = "获取成功"
-		br.Ret = 200
-		br.Success = true
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
 	}
+	resp, e := ossClient.GetUploadToken()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取OSS上传Token失败, Err: " + e.Error()
+		return
+	}
+
+	br.Data = resp
+	br.Msg = "获取成功"
+	br.Ret = 200
+	br.Success = true
+
+	//source, _ := this.GetInt("StorageSource")
+	//
+	//if source == utils.STORAGESOURCE_OSS {
+	//	resp, err := services.GetOssSTSToken()
+	//	if err != nil {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取STSToken失败, Err: " + err.Error()
+	//		return
+	//	}
+	//	br.Data = resp
+	//	br.Msg = "获取成功"
+	//	br.Ret = 200
+	//	br.Success = true
+	//} else if source == utils.STORAGESOURCE_MINIO {
+	//	resp, err := services.GetMinIOSTSToken()
+	//	if err != nil {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取STSToken失败, Err: " + err.Error()
+	//		return
+	//	}
+	//	br.Data = resp
+	//	br.Msg = "获取成功"
+	//	br.Ret = 200
+	//	br.Success = true
+	//}
 }

+ 27 - 15
controllers/smart_report/smart_report.go

@@ -1235,24 +1235,36 @@ func (this *SmartReportController) VoiceUpload() {
 	defer func() {
 		_ = os.Remove(filePath)
 	}()
-	ossDir := "static/audio/"
+	//ossDir := "static/audio/"
 
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, e = services.UploadMinIoToDir(ossFileName, filePath, ossDir, "")
-		if e != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败, Err:" + e.Error()
-			return
-		}
-	} else {
-		resourceUrl, e = services.UploadAliyunToDir(ossFileName, filePath, ossDir, "")
-		if e != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败, Err:" + e.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, e = services.UploadMinIoToDir(ossFileName, filePath, ossDir, "")
+	//	if e != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败, Err:" + e.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, e = services.UploadAliyunToDir(ossFileName, filePath, ossDir, "")
+	//	if e != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败, Err:" + e.Error()
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, e = ossClient.UploadFile(ossFileName, filePath, "")
+	if e != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + e.Error()
+		return
 	}
 
 	resource := new(models.Resource)

+ 44 - 0
controllers/user_login.go

@@ -919,3 +919,47 @@ func (this *UserLoginController) AreaCodeList() {
 	br.Success = true
 	br.Msg = "获取成功"
 }
+
+// ICPLicense
+// @Title icp备案信息
+// @Description icp备案信息
+// @Success 200 Ret=200 获取成功
+// @router /base_info [get]
+func (this *UserLoginController) BaseInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	icp, e := models.GetBusinessConfByKey("ICPLicense")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+
+	title, e := models.GetBusinessConfByKey("ETATitle")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+	type BaseInfoResp struct {
+		Icp      *models.BusinessConf `description:"手机号"`
+		ETATitle *models.BusinessConf `description:"邮箱"`
+	}
+
+	resp := BaseInfoResp{
+		Icp:      icp,
+		ETATitle: title,
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 26 - 14
controllers/voice.go

@@ -76,20 +76,32 @@ func (this *VoiceController) Upload() {
 
 	resourceUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadAudioToMinIo(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
-	} else {
-		resourceUrl, err = services.UploadAudioAliyun(fileName, fpath)
-		if err != nil {
-			br.Msg = "文件上传失败"
-			br.ErrMsg = "文件上传失败,Err:" + err.Error()
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadAudioToMinIo(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = services.UploadAudioAliyun(fileName, fpath)
+	//	if err != nil {
+	//		br.Msg = "文件上传失败"
+	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+	//		return
+	//	}
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
 	}
 
 	defer func() {

+ 3 - 0
go.mod

@@ -13,6 +13,7 @@ require (
 	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1656
 	github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible
 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
+	github.com/aws/aws-sdk-go v1.42.23
 	github.com/beego/bee/v2 v2.0.4
 	github.com/beego/beego/v2 v2.0.7
 	github.com/beevik/etree v1.2.0
@@ -61,6 +62,7 @@ require (
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/fsnotify/fsnotify v1.6.0 // indirect
 	github.com/garyburd/redigo v1.6.3 // indirect
+	github.com/go-ego/gse v0.80.2 // indirect
 	github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc // indirect
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -102,6 +104,7 @@ require (
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
 	github.com/tjfoc/gmsm v1.3.2 // indirect
+	github.com/vcaesar/cedar v0.20.1 // 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.12.0 // indirect

+ 13 - 0
go.sum

@@ -15,6 +15,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
 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-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
 github.com/alibabacloud-go/alimt-20181012/v2 v2.0.0 h1:RZF3WXYiPB/m1FiZS51udLbpAvg0urYi1wAfB18kiUQ=
@@ -73,6 +74,7 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
 github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
+github.com/aws/aws-sdk-go v1.42.23 h1:V0V5hqMEyVelgpu1e4gMPVCJ+KhmscdNxP/NWP1iCOA=
 github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
 github.com/beego/bee/v2 v2.0.4 h1:nEjPwxJ8D+cr54eWChJGoGRH7bJ7OQwbhx8rU0OQf7E=
 github.com/beego/bee/v2 v2.0.4/go.mod h1:wq0YrEmPcdNfDNpaUgiTkaW9zso7M8n0HCCShEBOzM0=
@@ -142,10 +144,13 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
 github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
 github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-ego/gse v0.80.2 h1:3LRfkaBuwlsHsmkOZvnhTcsYPXUAhiP06Sqcid7mO1M=
+github.com/go-ego/gse v0.80.2/go.mod h1:kesekpZfcFQ/kwd9b27VZHUOH5dQUjaaQUZ4OGt4Hj4=
 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-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.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc h1:jZY+lpZB92nvBo2f31oPC/ivGll6NcsnEOORm8Fkr4M=
 github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc/go.mod h1:25mL1NKxbJhB63ihiK8MnNeTRd+xAizd6bOdydrTLUQ=
@@ -243,6 +248,7 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 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=
@@ -251,6 +257,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 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/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53 h1:+8X3HMX8A2QhvNg3dImiQTCiVUt6BQXz1mW+/DrWI+k=
 github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53/go.mod h1:E61jD6q4yJ6Cu9uDGRAfiENM1G5TVZhOog0Y3+GgTpQ=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -260,6 +267,7 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
 github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
 github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 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.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
@@ -300,6 +308,7 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwd
 github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4PfoagaA0=
 github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
 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/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19 h1:LhWT2dBuNkYexwRSsPpYh67e0ikmH1ebBDaVkGHoMts=
@@ -430,6 +439,8 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
 github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
 github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
 github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/vcaesar/cedar v0.20.1 h1:cDOmYWdprO7ZW8cngJrDi8Zivnscj9dA/y8Y+2SB1P0=
+github.com/vcaesar/cedar v0.20.1/go.mod h1:iMDweyuW76RvSrCkQeZeQk4iCbshiPzcCvcGCtpM7iI=
 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=
@@ -437,6 +448,8 @@ github.com/xuri/excelize/v2 v2.7.1 h1:gm8q0UCAyaTt3MEF5wWMjVdmthm2EHAWesGSKS9tdV
 github.com/xuri/excelize/v2 v2.7.1/go.mod h1:qc0+2j4TvAUrBw36ATtcTeC1VCM0fFdAXZOmcF4nTpY=
 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/yanyiwu/gojieba v1.3.0 h1:6VeaPOR+MawnImdeSvWNr7rP4tvUfnGlEKaoBnR33Ds=
+github.com/yanyiwu/gojieba v1.3.0/go.mod h1:54wkP7sMJ6bklf7yPl6F+JG71dzVUU1WigZbR47nGdY=
 github.com/yidane/formula v0.0.0-20210902154546-0782e1736717 h1:9CTJJpdISGxMAELfVlprj5kZEsJEaNAWiobv8ZAd72U=
 github.com/yidane/formula v0.0.0-20210902154546-0782e1736717/go.mod h1:9/dQiKiN04yPMdgsuFmKGuI2Hdp6OmFV9gSWS1col6g=
 github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=

+ 3 - 3
models/business_conf.go

@@ -17,9 +17,9 @@ const (
 	BusinessConfEnPptCoverImgs    = "EnPptCoverImgs"
 	BusinessConfIsReportApprove   = "IsReportApprove"
 	BusinessConfReportApproveType = "ReportApproveType"
-	BusinessConfCompanyName      = "CompanyName"
-	BusinessConfCompanyWatermark = "CompanyWatermark"
-	BusinessConfWatermarkChart   = "WatermarkChart"
+	BusinessConfCompanyName       = "CompanyName"
+	BusinessConfCompanyWatermark  = "CompanyWatermark"
+	BusinessConfWatermarkChart    = "WatermarkChart"
 )
 
 const (

+ 144 - 0
models/data_manage/base_from_fenwei.go

@@ -0,0 +1,144 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type BaseFromFenweiIndex struct {
+	FenweiIndexId int `orm:"column(fenwei_index_id);pk"`
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	Sort          int
+	CreateTime    time.Time
+	ModifyTime    time.Time
+}
+
+type BaseFromFenweiIndexList struct {
+	FenweiIndexId int `orm:"column(fenwei_index_id);pk"`
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	Sort          int
+	CreateTime    string
+	ModifyTime    string
+	DataList      []*BaseFromFenweiData
+	Paging        *paging.PagingItem `description:"分页数据"`
+}
+
+type FenweiSingleDataResp struct {
+	FenweiIndexId int
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	CreateTime    string
+	ModifyTime    string
+	Data          []*FenweiSingleData
+}
+
+type FenweiSingleData struct {
+	Value    string `orm:"column(value)" description:"日期"`
+	DataTime string `orm:"column(data_time)" description:"值"`
+}
+
+func GetFenweiIndex(condition string, pars interface{}) (items []*BaseFromFenweiIndexList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_fenwei_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC, fenwei_index_id asc`
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func GetFenweiIndexDataCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count FROM base_from_fenwei_data WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+type FenweiIndexDataCountGroup struct {
+	IndexCode string
+	Count     int
+}
+
+func GetFenweiIndexDataCountGroup(indexCodes []string) (items []*FenweiIndexDataCountGroup, err error) {
+	if len(indexCodes) <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count, index_code FROM base_from_fenwei_data WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodes)) + `) GROUP BY index_code`
+	_, err = o.Raw(sql, indexCodes).QueryRows(&items)
+	return
+}
+
+func GetFenweiIndexData(indexCode string, startSize, pageSize int) (items []*BaseFromFenweiData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_fenwei_data WHERE index_code=? ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetFenweiIndexDataByCodes(indexCode []string) (items []*BaseFromFenweiData, err error) {
+	if len(indexCode) <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_fenwei_data WHERE index_code in (` + utils.GetOrmInReplace(len(indexCode)) + `) ORDER BY data_time DESC  `
+	_, err = o.Raw(sql, indexCode).QueryRows(&items)
+	return
+}
+
+type BaseFromFenweiData struct {
+	FenweiDataId  int `orm:"column(fenwei_data_id);pk"`
+	FenweiIndexId int
+	IndexCode     string
+	DataTime      string
+	Value         string
+	CreateTime    string
+	ModifyTime    string
+	DataTimestamp int64
+}
+
+type BaseFromFenweiIndexSearchItem struct {
+	FenweiIndexId int `orm:"column(fenwei_index_id);pk"`
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+}
+
+// GetFenweiItemList 模糊查询汾渭数据库指标列表
+func GetFenweiItemList(condition string) (items []*BaseFromFenweiIndexSearchItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM base_from_fenwei_index WHERE 1=1"
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+func GetFenweiIndexDataByCode(indexCode string) (list []*BaseFromFenweiData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_fenwei_data WHERE index_code=? `
+	_, err = o.Raw(sql, indexCode).QueryRows(&list)
+	return
+}
+
+func GetBaseFromFenweiIndexByIndexCode(indexCode string) (list *BaseFromFenweiIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_fenwei_index WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&list)
+	return
+}

+ 55 - 0
models/data_manage/base_from_fenwei_classify.go

@@ -0,0 +1,55 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// BaseFromFenweiClassify 汾渭原始数据分类表
+type BaseFromFenweiClassify struct {
+	ClassifyId      int       `orm:"column(classify_id);pk"`
+	ClassifyName    string    `description:"分类名称"`
+	ParentId        int       `description:"父级id"`
+	SysUserId       int       `description:"创建人id"`
+	SysUserRealName string    `description:"创建人姓名"`
+	Level           int       `description:"层级"`
+	Sort            int       `description:"排序字段,越小越靠前,默认值:10"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+}
+
+// GetBaseFromFenweiClassify 获取所有分类
+func GetBaseFromFenweiClassify() (items []*BaseFromFenweiClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_fenwei_classify ORDER BY parent_id ASC, sort ASC, classify_id ASC`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+// BaseFromFenweiClassifyItem 汾渭数据分类信息
+type BaseFromFenweiClassifyItem struct {
+	ClassifyId   int                           `description:"分类ID"`
+	ClassifyName string                        `description:"分类名称"`
+	ParentId     int                           `description:"父级id"`
+	Level        int                           `description:"层级"`
+	Sort         int                           `description:"排序字段"`
+	CreateTime   string                        `description:"创建时间"`
+	ModifyTime   string                        `description:"修改时间"`
+	Child        []*BaseFromFenweiClassifyItem `description:"子分类"`
+}
+
+func (y *BaseFromFenweiClassify) Format2Item(origin *BaseFromFenweiClassify) (item *BaseFromFenweiClassifyItem) {
+	if origin == nil {
+		return
+	}
+	item = new(BaseFromFenweiClassifyItem)
+	item.ClassifyId = origin.ClassifyId
+	item.ClassifyName = origin.ClassifyName
+	item.ParentId = origin.ParentId
+	item.Level = origin.Level
+	item.Sort = origin.Sort
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	return
+}

+ 236 - 0
models/data_manage/base_from_mtjh.go

@@ -0,0 +1,236 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type BaseFromMtjhMapping struct {
+	BaseFromMtjhMappingId int       `orm:"column(base_from_mtjh_mapping_id);pk"`
+	IndexName             string    `description:"持买单量指标名称"`
+	IndexCode             string    `description:"持买单量指标编码"`
+	CreateTime            time.Time `description:"时间"`
+	Area                  string    `description:"区域"`
+	Port                  string    `description:"港口或码头"`
+	Variety               string    `description:"品种"`
+	Unit                  string    `description:"单位"`
+	Frequency             string    `description:"频率"`
+}
+
+type BaseFromMtjhIndex struct {
+	BaseFromMtjhIndexId int       `orm:"column(base_from_mtjh_index_id);pk"`
+	IndexName           string    `description:"持买单量指标名称"`
+	IndexCode           string    `description:"持买单量指标编码"`
+	DealValue           string    `description:"成交量"`
+	DataTime            string    `description:"数据日期"`
+	Area                string    `description:"区域"`
+	Port                string    `description:"港口或码头"`
+	Unit                string    `description:"单位"`
+	Frequency           string    `description:"频率"`
+	Variety             string    `description:"品种"`
+	CreateTime          time.Time `description:"插入时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+}
+
+type BaseFromMtjhIndexItem struct {
+	BaseFromMtjhIndexId int       `orm:"column(base_from_mtjh_index_id);pk"`
+	IndexName           string    `description:"持买单量指标名称"`
+	IndexCode           string    `description:"持买单量指标编码"`
+	DealValue           string    `description:"成交量"`
+	DataTime            string    `description:"数据日期"`
+	Area                string    `description:"区域"`
+	Port                string    `description:"港口或码头"`
+	Unit                string    `description:"单位"`
+	Frequency           string    `description:"频率"`
+	Variety             string    `description:"品种"`
+	CreateTime          string `description:"插入时间"`
+	ModifyTime          string `description:"修改时间"`
+}
+
+// 查询指标
+func GetBaseFromMtjhMapping() (items []*BaseFromMtjhMapping, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM base_from_mtjh_mapping`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+// 查询指标
+func GetBaseFromMtjhIndex() (items []*BaseFromMtjhIndex, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM base_from_mtjh_index`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+// 添加数据
+func AddBaseFromMtjhIndex(item *BaseFromMtjhIndex) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+func AddBaseFromMtjhIndexMuti(items []*BaseFromMtjhIndex) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.InsertMulti(500, items)
+	return
+}
+
+// 添加指标
+func AddBaseFromMtjhMapping(item *BaseFromMtjhMapping) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+func AddBaseFromMtjhMappingMuti(items []*BaseFromMtjhMapping) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.InsertMulti(500, items)
+	return
+}
+
+func UpdateBaseFromMtjhIndex(item *BaseFromMtjhIndex) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE base_from_mtjh_index SET deal_value=?  WHERE index_name=?  AND  data_time = ?`
+	_, err = o.Raw(sql, item.DealValue, item.IndexName, item.DataTime).Exec()
+	return
+}
+
+func GetMtjhClassifyList() (list []*BaseFromMtjhMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM base_from_mtjh_mapping group by area"
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
+type BaseFromMtjhMappingItem struct {
+	BaseFromMtjhMappingId int    `orm:"column(base_from_mtjh_mapping_id);pk"`
+	IndexName             string `description:"持买单量指标名称"`
+	IndexCode             string `description:"持买单量指标编码"`
+	CreateTime            string `description:"时间"`
+	Area                  string `description:"区域"`
+	Port                  string `description:"港口或码头"`
+	Variety               string `description:"品种"`
+	Unit                  string `description:"单位"`
+	Frequency             string `description:"频率"`
+}
+
+func GetMtjhMapping(condition string, pars interface{}) (items []*BaseFromMtjhMappingItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_mtjh_mapping WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY base_from_mtjh_mapping_id asc`
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+type BaseFromMtjhIndexList struct {
+	BaseFromMtjhMappingId int    `orm:"column(base_from_mtjh_mapping_id);pk"`
+	IndexName             string `description:"持买单量指标名称"`
+	IndexCode             string `description:"持买单量指标编码"`
+	Area                  string `description:"区域"`
+	Port                  string `description:"港口或码头"`
+	Unit                  string `description:"单位"`
+	Frequency             string `description:"频率"`
+	CreateTime            string `description:"插入时间"`
+	ModifyTime            string `description:"修改时间"`
+	Variety               string `description:"品种"`
+	DataList              []*BaseFromMtjhIndexItem
+	Paging                *paging.PagingItem `description:"分页数据"`
+}
+
+
+func GetMtjhIndexDataCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count  FROM base_from_mtjh_index WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+
+func GetMtjhIndexData(indexCode string, startSize, pageSize int) (items []*BaseFromMtjhIndexItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_mtjh_index WHERE index_code=? ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetMtjhItemList 模糊查询煤炭江湖数据库指标列表
+func GetMtjhItemList(keyword string) (items []*BaseFromMtjhMappingItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM base_from_mtjh_mapping WHERE CONCAT(index_name,index_code) LIKE ? "
+	_, err = o.Raw(sql, utils.GetLikeKeyword(keyword)).QueryRows(&items)
+	return
+}
+
+// 查询数据
+func GetBaseFromMtjhIndexByCode(indexCode string) (items []*BaseFromMtjhIndexItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_mtjh_index WHERE index_code=? ORDER BY data_time DESC `
+	_, err = o.Raw(sql, indexCode).QueryRows(&items)
+	return
+}
+
+// GetMtjhMappingItemByCode
+func GetMtjhMappingItemByCode(indexCode string) (item *BaseFromMtjhMappingItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM base_from_mtjh_mapping WHERE index_code=? "
+	err = o.Raw(sql, indexCode).QueryRow(&item)
+	return
+}
+
+// GetMtjhFrequencyByArea
+func GetMtjhFrequencyByArea(area string) (items []*string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT frequency FROM base_from_mtjh_index WHERE area=?  group by area "
+	_,err = o.Raw(sql, area).QueryRows(&items)
+	return
+}
+
+func GetClassifyMtjhByArea(area string) (items []*string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT DISTINCT index_code FROM base_from_mtjh_index WHERE area=? `
+	_, err = o.Raw(sql, area).QueryRows(&items)
+	return
+}
+
+func GetCoalMtjhMaxCount(area string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT
+	MAX( t.num ) AS count 
+FROM
+	(
+	SELECT
+		COUNT( 1 ) AS num 
+	FROM
+		base_from_mtjh_index 
+	WHERE
+		area =? 
+GROUP BY
+	index_name ) AS t `
+	err = o.Raw(sql, area).QueryRow(&count)
+	return
+}
+
+func GetMtjhCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT
+		COUNT( 1 ) AS num 
+	FROM
+		base_from_mtjh_index
+	WHERE
+		index_code =? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+func GetMtjhIndexLatestDate(indexCode string) (ModifyTime string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT modify_time FROM base_from_mtjh_index WHERE index_code=? ORDER BY modify_time DESC limit 1 `
+	err = o.Raw(sql, indexCode).QueryRow(&ModifyTime)
+	return
+}

+ 8 - 1
models/data_manage/chart_edb_mapping.go

@@ -30,6 +30,11 @@ type ChartEdbMapping struct {
 	ChartWidth        float64   `description:"线条大小"`
 	Source            int       `description:"1:ETA图库;2:商品价格曲线"`
 	EdbAliasName      string    `description:"中文别名"`
+	IsConvert         int       `description:"是否数据转换 0不转 1转"`
+	ConvertType       int       `description:"数据转换类型 1乘 2除 3对数"`
+	ConvertValue      float64   `description:"数据转换值"`
+	ConvertUnit       string    `description:"数据转换单位"`
+	ConvertEnUnit     string    `description:"数据转换单位"`
 }
 
 func AddChartEdbMapping(items []*ChartEdbMapping) (err error) {
@@ -40,7 +45,9 @@ func AddChartEdbMapping(items []*ChartEdbMapping) (err error) {
 
 func GetChartEdbMappingList(chartInfoId int) (list []*ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.*,b.source_name,b.source,b.sub_source,b.classify_id,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
+	sql := ` SELECT a.*,b.source_name,b.source,b.sub_source,b.classify_id,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,
+b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type,
+a.is_convert, a.convert_type, a.convert_value, a.convert_unit, a.convert_en_unit 
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE chart_info_id=? 

+ 89 - 11
models/data_manage/chart_info.go

@@ -26,7 +26,7 @@ type ChartInfo struct {
 	EndDate           string `description:"自定义结束日期"`
 	IsSetName         int    `description:"设置名称"`
 	EdbInfoIds        string `description:"指标id"`
-	ChartType         int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图,8:商品价格曲线图,9:相关性图"`
+	ChartType         int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图,8:商品价格曲线图,9:相关性图,10:截面散点图, 11:雷达图"`
 	Calendar          string `description:"公历/农历"`
 	SeasonStartDate   string `description:"季节性图开始日期"`
 	SeasonEndDate     string `description:"季节性图开始日期"`
@@ -47,6 +47,8 @@ type ChartInfo struct {
 	Instructions      string `description:"图表说明"`
 	MarkersLines      string `description:"标识线"`
 	MarkersAreas      string `description:"标识区"`
+	Unit              string `description:"中文单位名称"`
+	UnitEn            string `description:"英文单位名称"`
 }
 
 type ChartInfoMore struct {
@@ -175,6 +177,11 @@ type ChartSaveItem struct {
 	ChartWidth        float64 `description:"线条大小"`
 	Source            int     `description:"1:ETA图库;2:商品价格曲线"`
 	EdbAliasName      string  `description:"中文别名"`
+	IsConvert         int     `description:"是否数据转换 0不转 1转"`
+	ConvertType       int     `description:"数据转换类型 1乘 2除 3对数"`
+	ConvertValue      float64 `description:"数据转换值"`
+	ConvertUnit       string  `description:"数据转换单位"`
+	ConvertEnUnit     string  `description:"数据转换单位"`
 }
 
 func DeleteChartInfoAndData(chartInfoId int) (err error) {
@@ -235,6 +242,8 @@ type EditChartInfoReq struct {
 	Instructions         string                  `description:"图表说明"`
 	MarkersLines         string                  `description:"标识线"`
 	MarkersAreas         string                  `description:"标识区"`
+	Unit                 string                  `description:"中文单位名称"`
+	UnitEn               string                  `description:"英文单位名称"`
 }
 
 type EditChartEnInfoReq struct {
@@ -468,10 +477,15 @@ type ChartEdbInfoMapping struct {
 	MinValue            float64 `json:"-" description:"最小值"`
 	MaxValue            float64 `json:"-" description:"最大值"`
 	DataList            interface{}
-	IsNullData          bool   `json:"-" description:"是否空数据"`
-	MappingSource       int    `description:"1:ETA图库;2:商品价格曲线"`
-	RegionType          string `description:"交易所来源,海外还是国内" json:"-"`
-	ClassifyId          int    `description:"分类id"`
+	IsNullData          bool    `json:"-" description:"是否空数据"`
+	MappingSource       int     `description:"1:ETA图库;2:商品价格曲线"`
+	RegionType          string  `description:"交易所来源,海外还是国内" json:"-"`
+	ClassifyId          int     `description:"分类id"`
+	IsConvert           int     `description:"是否数据转换 0不转 1转"`
+	ConvertType         int     `description:"数据转换类型 1乘 2除 3对数"`
+	ConvertValue        float64 `description:"数据转换值"`
+	ConvertUnit         string  `description:"数据转换单位"`
+	ConvertEnUnit       string  `description:"数据转换单位"`
 }
 
 type QuarterData struct {
@@ -701,6 +715,8 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 	pars = append(pars, req.Instructions)
 	pars = append(pars, req.MarkersLines)
 	pars = append(pars, req.MarkersAreas)
+	pars = append(pars, req.Unit)
+	pars = append(pars, req.UnitEn)
 
 	sql := ` UPDATE  chart_info
 			SET
@@ -718,7 +734,9 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
  			  sources_from = ?,
  			  instructions = ?,
  			  markers_lines = ?,
- 			  markers_areas = ?
+ 			  markers_areas = ?,
+ 			  unit = ?,
+ 			  unit_en = ?
 			`
 	if calendar != "" {
 		sql += `,calendar = ? `
@@ -787,7 +805,13 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 			tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
 			tmpChartEdbMapping.ChartWidth = v.ChartWidth
 			tmpChartEdbMapping.EdbAliasName = v.EdbAliasName
-			_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName")
+			tmpChartEdbMapping.IsConvert = v.IsConvert
+			tmpChartEdbMapping.ConvertType = v.ConvertType
+			tmpChartEdbMapping.ConvertValue = v.ConvertValue
+			tmpChartEdbMapping.ConvertUnit = v.ConvertUnit
+			tmpChartEdbMapping.ConvertEnUnit = v.ConvertEnUnit
+			_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName",
+				"IsConvert", "ConvertType", "ConvertValue", "ConvertUnit", "ConvertEnUnit")
 			if err != nil {
 				fmt.Println("chart_edb_mapping Err:" + err.Error())
 				return err
@@ -813,6 +837,11 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 			mapItem.ChartWidth = v.ChartWidth
 			mapItem.Source = utils.CHART_SOURCE_DEFAULT
 			mapItem.EdbAliasName = v.EdbAliasName
+			mapItem.IsConvert = v.IsConvert
+			mapItem.ConvertType = v.ConvertType
+			mapItem.ConvertValue = v.ConvertValue
+			mapItem.ConvertUnit = v.ConvertUnit
+			mapItem.ConvertEnUnit = v.ConvertEnUnit
 			tmpId, err := to.Insert(mapItem)
 			if err != nil {
 				fmt.Println("AddChartEdbMapping Err:" + err.Error())
@@ -1069,6 +1098,8 @@ type AddChartInfoReq struct {
 	Instructions         string                  `description:"图表说明"`
 	MarkersLines         string                  `description:"标识线"`
 	MarkersAreas         string                  `description:"标识区"`
+	Unit                 string                  `description:"中文单位名称"`
+	UnitEn               string                  `description:"英文单位名称"`
 }
 
 type PreviewChartInfoReq struct {
@@ -1526,10 +1557,15 @@ type BarChartInfoReq struct {
 
 // BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
 type BarChartInfoEdbItemReq struct {
-	EdbInfoId int    `description:"指标ID"`
-	Name      string `description:"别名"`
-	NameEn    string `description:"英文别名"`
-	Source    int    `description:"1:ETA图库;2:商品价格"`
+	EdbInfoId     int     `description:"指标ID"`
+	Name          string  `description:"别名"`
+	NameEn        string  `description:"英文别名"`
+	Source        int     `description:"1:ETA图库;2:商品价格"`
+	IsConvert     int     `description:"是否数据转换 0不转 1转"`
+	ConvertType   int     `description:"数据转换类型 1乘 2除 3对数"`
+	ConvertValue  float64 `description:"数据转换值"`
+	ConvertUnit   string  `description:"数据转换单位"`
+	ConvertEnUnit string  `description:"数据转换单位"`
 }
 
 // BarChartInfoDateReq 柱方图预览请求数据(日期相关)
@@ -1900,3 +1936,45 @@ func EditChartInfoExtraConfig(chartId int, extraConfig string) (err error) {
 
 	return
 }
+
+// PreviewRadarChartReq 预览雷达图的请求入参
+type PreviewRadarChartReq struct {
+	ChartEdbInfoList []*ChartSaveItem `description:"指标及配置信息"`
+	ExtraConfig      string           `description:"图表额外配置信息,json字符串"`
+}
+
+// RadarChartInfoReq 雷达图预览请求数据
+type RadarChartInfoReq struct {
+	DateList []RadarChartInfoDateReq `description:"日期配置"`
+}
+
+// RadarChartInfoEdbItemReq 雷达图预览请求数据(指标相关)
+type RadarChartInfoEdbItemReq struct {
+	EdbInfoId int    `description:"指标ID"`
+	Name      string `description:"别名"`
+	//NameEn    string `description:"英文别名"`
+	//Source    int    `description:"1:ETA图库;2:商品价格"`
+}
+
+// RadarChartInfoDateReq 雷达图预览请求数据(日期相关)
+type RadarChartInfoDateReq struct {
+	Type  int    `description:"配置类型"`
+	Date  string `description:"固定日期"`
+	Value int    `description:"N天的值"`
+	Color string `description:"颜色"`
+	Name  string `description:"别名"`
+}
+
+// RadarChartInfoResp 雷达图数据
+type RadarChartInfoResp struct {
+	YDataList   []RadarYData `description:"数据列"`
+	XEdbIdValue []int
+}
+
+// RadarYData 雷达图的y轴数据
+type RadarYData struct {
+	Date  string    `description:"数据日期"`
+	Color string    `description:"数据颜色"`
+	Name  string    `description:"别名"`
+	Value []float64 `description:"每个指标的值"`
+}

+ 8 - 0
models/data_manage/edb_classify.go

@@ -146,6 +146,14 @@ func GetEdbClassifyAll() (items []*EdbClassifyItems, err error) {
 	return
 }
 
+// GetAllEdbClassify 获取所有的普通指标的分类列表(包含第一级)
+func GetAllEdbClassify() (items []*EdbClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_classify WHERE  classify_type = 0  order by sort asc,classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
 // GetNormalEdbClassifyAll 获取普通指标的分类列表
 func GetNormalEdbClassifyAll() (items []*EdbClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")

+ 6 - 2
models/data_manage/edb_data_base.go

@@ -165,6 +165,10 @@ func GetEdbDataTableName(source, subSource int) (tableName string) {
 		tableName = "edb_data_calculate_zdyfx" // 自定义分析->74
 	case utils.DATA_SOURCE_CALCULATE_RJZ: //日均值->75
 		tableName = "edb_data_calculate_rjz"
+	case utils.DATA_SOURCE_GFEX: //广州期货交易所->78
+		tableName = "edb_data_gz"
+	case utils.DATA_SOURCE_ICPI: //ICPI消费价格指数->79
+		tableName = "edb_data_icpi"
 	default:
 		edbSource := EdbSourceIdMap[source]
 		if edbSource != nil {
@@ -307,11 +311,11 @@ func GetEdbDataAllByEdbCodes(edbCodes []string, limit int) (items []*EdbInfoSear
 	pars = append(pars, edbCodes)
 	o := orm.NewOrmUsingDB("data")
 
-	sql := ` SELECT * FROM edb_data_ys WHERE edb_code IN (`+ utils.GetOrmInReplace(len(edbCodes)) +`) ORDER BY data_time DESC`
+	sql := ` SELECT * FROM edb_data_ys WHERE edb_code IN (` + utils.GetOrmInReplace(len(edbCodes)) + `) ORDER BY data_time DESC`
 	if limit > 0 {
 		sql += `  LIMIT ?  `
 		pars = append(pars, limit)
 	}
 	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
-}
+}

+ 39 - 0
models/data_manage/edb_data_gz.go

@@ -0,0 +1,39 @@
+package data_manage
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type GzData struct {
+	InputValue string `orm:"column(DATA_VALUE)" description:"日期"`
+	DataTime   string `orm:"column(DATA_DATE)" description:"值"`
+}
+
+func GetEdbDataGzMaxOrMinDate(edbCode string) (minDate, maxDate string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT MIN(data_time) AS minDate,MAX(data_time) AS maxDate FROM edb_data_gz WHERE edb_code=? `
+	err = o.Raw(sql, edbCode).QueryRow(&minDate, &maxDate)
+	return
+}
+
+type GzIndexView struct {
+	BaseFromTradeGuangzhouIndexId    int     `description:"指标id"`
+	BaseFromTradeGuangzhouClassifyId int     `description:"分类id"`
+	IndexCode                        string  `description:"指标编码"`
+	IndexName                        string  `description:"指标名称"`
+	Frequency                        string  `description:"频率"`
+	Unit                             string  `description:"单位"`
+	StartDate                        string  `description:"开始日期"`
+	EndDate                          string  `description:"结束日期"`
+	Value                            float64 `description:"数据"`
+}
+
+// GetBaseInfoFromShByIndexCode 获取指标信息
+func GetBaseInfoFromGzByIndexCode(indexCode string) (item *GzIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_trade_guangzhou_index WHERE index_code=? `
+	sql = fmt.Sprintf(sql)
+	err = o.Raw(sql, indexCode).QueryRow(&item)
+	return
+}

+ 39 - 0
models/data_manage/edb_data_icpi.go

@@ -0,0 +1,39 @@
+package data_manage
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type IcpiData struct {
+	InputValue string `orm:"column(DATA_VALUE)" description:"日期"`
+	DataTime   string `orm:"column(DATA_DATE)" description:"值"`
+}
+
+func GetEdbDataIcpiMaxOrMinDate(edbCode string) (minDate, maxDate string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT MIN(data_time) AS minDate,MAX(data_time) AS maxDate FROM edb_data_icpi WHERE edb_code=? `
+	err = o.Raw(sql, edbCode).QueryRow(&minDate, &maxDate)
+	return
+}
+
+type IcpiIndexView struct {
+	BaseFromTradeGuangzhouIndexId    int     `description:"指标id"`
+	BaseFromTradeGuangzhouClassifyId int     `description:"分类id"`
+	IndexCode                        string  `description:"指标编码"`
+	IndexName                        string  `description:"指标名称"`
+	Frequency                        string  `description:"频率"`
+	Unit                             string  `description:"单位"`
+	StartDate                        string  `description:"开始日期"`
+	EndDate                          string  `description:"结束日期"`
+	Value                            float64 `description:"数据"`
+}
+
+// GetBaseInfoFromShByIndexCode 获取指标信息
+func GetBaseInfoFromIcpiByIndexCode(indexCode string) (item *IcpiIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_icpi_index WHERE index_code=? `
+	sql = fmt.Sprintf(sql)
+	err = o.Raw(sql, indexCode).QueryRow(&item)
+	return
+}

+ 108 - 6
models/data_manage/edb_info.go

@@ -72,10 +72,19 @@ func AddEdbInfo(item *EdbInfo) (lastId int64, err error) {
 	return
 }
 
-type EdbInfoItem struct {
-	EdbInfoId  int    `description:"指标id"`
-	EdbName    string `description:"指标名称"`
-	ClassifyId int    `description:"指标分类"`
+type BaseEdbNameItem struct {
+	EdbInfoId   int    `description:"指标id"`
+	EdbInfoType int    `description:"指标类型,0:普通指标,1:预测指标"`
+	SourceName  string `description:"来源名称"`
+	Source      int    `description:"来源id"`
+	EdbCode     string `description:"指标编码"`
+	EdbName     string `description:"指标名称"`
+	Frequency   string `description:"频率"`
+	Unit        string `description:"单位"`
+}
+
+type BaseEdbInfoResp struct {
+	List []*BaseEdbNameItem
 }
 
 // GetEdbInfoAll 用于分类展示
@@ -152,6 +161,20 @@ func GetEdbInfoById(edbInfoId int) (item *EdbInfo, err error) {
 	return
 }
 
+// GetEdbInfoByUniqueCode
+// @Description: 根据uniqueCode获取指标详情
+// @author: Roc
+// @datetime 2024-01-18 13:40:01
+// @param uniqueCode string
+// @return item *EdbInfo
+// @return err error
+func GetEdbInfoByUniqueCode(uniqueCode string) (item *EdbInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_info WHERE unique_code=? `
+	err = o.Raw(sql, uniqueCode).QueryRow(&item)
+	return
+}
+
 // GetEdbInfoByIdList 根据指标id集合 获取 指标列表
 func GetEdbInfoByIdList(edbInfoIdList []int) (items []*EdbInfo, err error) {
 	num := len(edbInfoIdList)
@@ -328,6 +351,7 @@ type EdbInfoList struct {
 	SubSourceName    string                  `description:"子数据来源名称"`
 	IndicatorCode    string                  `description:"指标代码"`
 	StockCode        string                  `description:"证券代码"`
+	NoUpdate         int8                    `description:"是否停止更新,0:继续更新;1:停止更新"`
 }
 
 type EdbDataInsertConfigItem struct {
@@ -1647,13 +1671,15 @@ type TraceEdbInfoResp struct {
 	UniqueCode  string             `description:"唯一编码"`
 	ClassifyId  int                `description:"分类ID"`
 	Child       []TraceEdbInfoResp `description:"下级来源"`
+	IsStop      int8               `description:"是否终止"`
 	EdbInfo     *EdbInfo           `description:"指标信息" json:"-"`
 }
 
 // BeforeAndAfterDateDataResp 前后几期数据
 type BeforeAndAfterDateDataResp struct {
-	List []*EdbDataList `description:"list"`
-	Date string         `description:"实际日期"`
+	List      []*EdbDataList `description:"list"`
+	Date      string         `description:"实际日期"`
+	ShowValue string         `description:"展示值"`
 }
 
 // GetEdbInfoAdminList
@@ -1736,3 +1762,79 @@ type EdbInfoSmmExistCheckResp struct {
 	EdbInfoExistCheckResp
 	ExistAll bool `description:"是否全部重复"`
 }
+
+// GetEdbBaseInfoList
+// @Description: 获取指标库数据列表
+// @author: Roc
+// @datetime 2024-01-10 14:28:22
+// @param condition string
+// @param pars []interface{}
+// @param orderBy string
+// @param startSize int
+// @param pageSize int
+// @return total int
+// @return items []*BaseRefreshEdbInfo
+// @return err error
+func GetEdbBaseInfoList(condition string, pars []interface{}, orderBy string, startSize, pageSize int) (total int, items []*BaseRefreshEdbInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	// 数量汇总
+	totalSql := ` SELECT count(1) FROM edb_info WHERE 1=1 `
+	if condition != "" {
+		totalSql += condition
+	}
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil {
+		return
+	}
+
+	// 列表数据
+	sql := ` SELECT edb_info_id as edb_info_id, classify_id as classify_id,edb_code as index_code,edb_name as index_name,end_date,end_value,sys_user_id,sys_user_real_name,frequency,no_update as is_stop,terminal_code FROM edb_info WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+
+	if orderBy != "" {
+		sql += ` ORDER BY ` + orderBy
+	} else {
+		sql += ` ORDER BY edb_info_id ASC `
+	}
+	sql += `  LIMIT ?,? `
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+
+	return
+}
+
+// ModifyEdbInfoUpdateStatus
+// @Description:  修改指标库停更状态
+// @author: Roc
+// @datetime 2024-01-08 16:23:31
+// @param edbIdList []int
+// @param indexCodeList []string
+// @param isStop int
+// @return err error
+func ModifyEdbInfoUpdateStatus(edbIdList []int, isStop int) (err error) {
+	idNum := len(edbIdList)
+	if idNum <= 0 {
+		return
+	}
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 更改指标的更新状态
+	sql := ` UPDATE edb_info SET no_update = ? WHERE  edb_info_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+	_, err = o.Raw(sql, isStop, edbIdList).Exec()
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 3 - 1
models/data_manage/edb_info_calculate_mapping.go

@@ -68,6 +68,7 @@ func GetEdbInfoCalculateMappingDetail(edbInfoId int) (item *EdbInfoCalculateMapp
 }
 
 // EdbInfoCalculateMappingInfo
+// @Description: 计算指标与基础指标关系表
 type EdbInfoCalculateMappingInfo struct {
 	EdbInfoCalculateMappingId int       `orm:"column(edb_info_calculate_mapping_id);pk"`
 	EdbInfoId                 int       `description:"计算指标id"`
@@ -88,12 +89,13 @@ type EdbInfoCalculateMappingInfo struct {
 	FromEdbInfoType           int       `description:"来源指标类型: 0-基础指标; 1-预测指标"`
 	FromClassifyId            int       `description:"来源指标分类ID"`
 	FromUniqueCode            string    `description:"来源指标唯一编码"`
+	NoUpdate                  int8      `description:"是否停止更新,0:继续更新;1:停止更新"`
 }
 
 // GetEdbInfoCalculateMappingListByEdbInfoId 根据生成的指标id获取来源的指标id列表
 func GetEdbInfoCalculateMappingListByEdbInfoId(edbInfoId int) (items []*EdbInfoCalculateMappingInfo, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.*,b.edb_type as from_edb_type,b.edb_info_type as from_edb_info_type, b.unique_code AS from_unique_code, b.classify_id AS from_classify_id FROM edb_info_calculate_mapping AS a
+	sql := ` SELECT a.*,b.edb_type as from_edb_type,b.edb_info_type as from_edb_info_type, b.unique_code AS from_unique_code, b.classify_id AS from_classify_id,b.no_update FROM edb_info_calculate_mapping AS a
 			INNER JOIN edb_info AS b ON a.from_edb_info_id=b.edb_info_id
 			WHERE a.edb_info_id=? `
 	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)

+ 239 - 0
models/data_manage/edb_refresh/edb_refresh_config.go

@@ -0,0 +1,239 @@
+package edb_refresh
+
+import (
+	"errors"
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EdbRefreshConfig
+// @Description: 指标的刷新时间配置表
+type EdbRefreshConfig struct {
+	EdbRefreshConfigId  int       `orm:"column(edb_refresh_config_id);pk"`
+	RefreshFrequency    string    `description:"刷新频率"`
+	RefreshFrequencyDay int       `description:"具体刷新的日期"`
+	RefreshTime         string    `description:"刷新时间"`
+	RefreshAllData      int       `description:"是否刷新所有数据,0:否,1:刷新所有数据"`
+	RefreshDataNum      int       `description:"刷新单元格数"`
+	ModifyTime          time.Time `description:"最晚一次的更新时间"`
+	CreateTime          time.Time `description:"添加时间"`
+}
+
+// Add
+// @Description: 添加
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshConfig) Add() (err error) {
+	if m.EdbRefreshConfigId > 0 {
+		err = errors.New("该配置已存在")
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	lastId, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.EdbRefreshConfigId = int(lastId)
+
+	return
+}
+
+// Update
+// @Description: 更新
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshConfig) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+// Delete
+// @Description: 删除
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @return err error
+func (m *EdbRefreshConfig) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(m)
+	return
+}
+
+// GetEdbRefreshConfigListByCondition
+// @Description: 根据条件获取刷新配置列表
+// @author: Roc
+// @datetime 2024-01-08 14:07:10
+// @param refreshFrequency string
+// @param refreshTime string
+// @param refreshFrequencyDay int
+// @param refreshAllData int
+// @param refreshDataNum int
+// @return item *EdbRefreshConfig
+// @return err error
+func GetEdbRefreshConfigListByCondition(refreshFrequency, refreshTime string, refreshFrequencyDay, refreshAllData, refreshDataNum int) (item *EdbRefreshConfig, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_refresh_config
+         WHERE refresh_frequency = ? AND refresh_frequency_day = ? AND refresh_time = ? AND refresh_all_data = ? AND refresh_data_num = ? ORDER BY edb_refresh_config_id ASC `
+	err = o.Raw(sql, refreshFrequency, refreshFrequencyDay, refreshTime, refreshAllData, refreshDataNum).QueryRow(&item)
+
+	return
+}
+
+// SaveEdbRefreshConfig
+// @Description:  保存刷新配置
+// @author: Roc
+// @datetime 2024-01-08 15:13:23
+// @param source int
+// @param subSource int
+// @param sysUserId int
+// @param sysUserRealName string
+// @param newConfigList []*EdbRefreshConfig
+// @param addMapping []*EdbRefreshMapping
+// @param edbIdList []int
+// @return err error
+func SaveEdbRefreshConfig(source, subSource, sysUserId int, sysUserRealName string, newConfigList []*EdbRefreshConfig, addMapping []*EdbRefreshMapping, edbIdList []int) (err error) {
+	num := len(edbIdList)
+	if num <= 0 {
+		return
+	}
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	for _, v := range newConfigList {
+		lastId, tmpErr := o.Insert(v)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		v.EdbRefreshConfigId = int(lastId)
+
+		for _, edbId := range edbIdList {
+			addMapping = append(addMapping, &EdbRefreshMapping{
+				EdbRefreshMappingId: 0,
+				Source:              source,
+				SubSource:           subSource,
+				EdbInfoId:           edbId,
+				EdbRefreshConfigId:  v.EdbRefreshConfigId,
+				SysUserId:           sysUserId,
+				SysUserRealName:     sysUserRealName,
+				ModifyTime:          time.Now(),
+				CreateTime:          time.Now(),
+			})
+		}
+	}
+
+	// 先删除
+	sql := `DELETE FROM edb_refresh_mapping WHERE source =? AND sub_source =? AND edb_info_id in (` + utils.GetOrmInReplace(num) + `)`
+	_, err = o.Raw(sql, source, subSource, edbIdList).Exec()
+
+	// 再写入
+	if len(addMapping) > 0 {
+		tmpAddDataList := make([]*EdbRefreshMapping, 0)
+		i := 0
+		for _, v := range addMapping {
+			tmpAddDataList = append(tmpAddDataList, v)
+			i++
+			if i >= 500 {
+				_, err = o.InsertMulti(len(tmpAddDataList), tmpAddDataList)
+				if err != nil {
+					return
+				}
+				i = 0
+				tmpAddDataList = make([]*EdbRefreshMapping, 0)
+			}
+		}
+
+		if len(tmpAddDataList) > 0 {
+			_, err = o.InsertMulti(len(tmpAddDataList), tmpAddDataList)
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	return
+
+}
+
+// EdbRefreshConfigItem
+// @Description: 指标的刷新时间配置项
+type EdbRefreshConfigItem struct {
+	RefreshFrequency    string `description:"刷新频率"`
+	RefreshFrequencyDay int    `description:"具体刷新的日期"`
+	RefreshTime         string `description:"刷新时间"`
+	RefreshAllData      int    `description:"是否刷新所有数据,0:否,1:刷新所有数据"`
+	RefreshDataNum      int    `description:"刷新单元格数"`
+}
+
+// GetEdbRefreshConfigListBySourceAndeEdbInfoId
+// @Description: 根据来源和指标获取其配置列表
+// @author: Roc
+// @datetime 2024-01-10 14:18:21
+// @param source int
+// @param subSource int
+// @param edbInfoId int
+// @return list []*EdbRefreshDefaultConfig
+// @return err error
+func GetEdbRefreshConfigListBySourceAndeEdbInfoId(source, subSource, edbInfoId int) (list []*EdbRefreshConfigItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.* FROM edb_refresh_config a 
+         JOIN  edb_refresh_mapping b ON a.edb_refresh_config_id = b.edb_refresh_config_id
+         WHERE b.source = ? AND b.sub_source = ? AND b.edb_info_id = ? ORDER BY a.edb_refresh_config_id ASC `
+	_, err = o.Raw(sql, source, subSource, edbInfoId).QueryRows(&list)
+
+	return
+}
+
+// EdbRefreshConfigAndEdbItem
+// @Description: 指标的刷新时间配置项
+type EdbRefreshConfigAndEdbItem struct {
+	RefreshFrequency    string `description:"刷新频率"`
+	RefreshFrequencyDay int    `description:"具体刷新的日期"`
+	RefreshTime         string `description:"刷新时间"`
+	RefreshAllData      int    `description:"是否刷新所有数据,0:否,1:刷新所有数据"`
+	RefreshDataNum      int    `description:"刷新单元格数"`
+	EdbInfoId           int    `description:"指标id,如果是数据源(钢联、有色金属)的,那么就是数据源里面的id"`
+	Source              int    `description:"来源"`
+	SubSource           int    `description:"子来源"`
+}
+
+// GetEdbRefreshConfigAndEdbListBySourceAndeEdbInfoId
+// @Description: 根据来源和指标获取其配置列表
+// @author: Roc
+// @datetime 2024-01-10 14:18:21
+// @param source int
+// @param subSource int
+// @param edbInfoId int
+// @return list []*EdbRefreshDefaultConfig
+// @return err error
+func GetEdbRefreshConfigAndEdbListBySourceAndeEdbInfoId(source, subSource int, edbInfoIdList []int) (list []*EdbRefreshConfigAndEdbItem, err error) {
+	num := len(edbInfoIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.*,b.source,b.sub_source,b.edb_info_id FROM edb_refresh_config a 
+         JOIN  edb_refresh_mapping b ON a.edb_refresh_config_id = b.edb_refresh_config_id
+         WHERE b.source = ? AND b.sub_source = ? AND b.edb_info_id in (` + utils.GetOrmInReplace(num) + `)  ORDER BY a.edb_refresh_config_id ASC `
+	_, err = o.Raw(sql, source, subSource, edbInfoIdList).QueryRows(&list)
+
+	return
+}

+ 138 - 0
models/data_manage/edb_refresh/edb_refresh_default_config.go

@@ -0,0 +1,138 @@
+package edb_refresh
+
+import (
+	"errors"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EdbRefreshDefaultConfig
+// @Description: 指标的默认刷新时间配置表
+type EdbRefreshDefaultConfig struct {
+	Id                  int       `orm:"column(id);pk"`
+	Source              int       `description:"来源"`
+	SubSource           int       `description:"来源名称"`
+	Frequency           string    `description:"频度"`
+	RefreshFrequency    string    `description:"刷新频率"`
+	RefreshFrequencyDay int       `description:"具体刷新的日期"`
+	RefreshTime         string    `description:"刷新时间"`
+	RefreshAllData      int       `description:"是否刷新所有数据,0:否,1:刷新所有数据"`
+	RefreshDataNum      int       `description:"刷新单元格数"`
+	ModifyTime          time.Time `description:"最晚一次的更新时间"`
+	CreateTime          time.Time `description:"添加时间"`
+}
+
+// Add
+// @Description: 添加
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshDefaultConfig) Add() (err error) {
+	if m.Id > 0 {
+		err = errors.New("该配置已存在")
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	lastId, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.Id = int(lastId)
+
+	return
+}
+
+// Update
+// @Description: 更新
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshDefaultConfig) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+// Delete
+// @Description: 删除
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @return err error
+func (m *EdbRefreshDefaultConfig) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(m)
+	return
+}
+
+// GetListBySourceAndFrequency
+// @Description: 根据来源和频度获取列表
+// @author: Roc
+// @datetime 2024-01-04 17:39:47
+// @param source int
+// @param subSource int
+// @param frequency string
+// @return list []*EdbRefreshDefaultConfig
+// @return err error
+func GetListBySourceAndFrequency(source, subSource int, frequency string) (list []*EdbRefreshDefaultConfig, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_refresh_default_config
+         WHERE source = ? AND sub_source = ? AND frequency = ? ORDER BY id ASC `
+	_, err = o.Raw(sql, source, subSource, frequency).QueryRows(&list)
+
+	return
+}
+
+// GetAllListBySourceList
+// @Description: 根据来源列表获取所有默认刷新配置列表
+// @author: Roc
+// @datetime 2024-01-10 14:54:54
+// @param source int
+// @param subSource int
+// @return list []*EdbRefreshDefaultConfig
+// @return err error
+func GetAllListBySourceList(source, subSource int) (list []*EdbRefreshDefaultConfig, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_refresh_default_config
+         WHERE source = ? AND sub_source = ? ORDER BY id ASC `
+	_, err = o.Raw(sql, source, subSource).QueryRows(&list)
+
+	return
+}
+
+// SaveEdbRefreshDefaultConfig
+// @Description: 保存配置项
+// @author: Roc
+// @datetime 2024-01-08 10:20:00
+// @param source int
+// @param subSource int
+// @param frequency string
+// @param newList []*EdbRefreshDefaultConfig
+// @return err error
+func SaveEdbRefreshDefaultConfig(source, subSource int, frequency string, newList []*EdbRefreshDefaultConfig) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 先删除
+	sql := `DELETE FROM edb_refresh_default_config WHERE source =? AND sub_source =? AND frequency =?`
+	_, err = o.Raw(sql, source, subSource, frequency).Exec()
+
+	// 再写入
+	_, err = o.InsertMulti(len(newList), newList)
+
+	return
+
+}

+ 68 - 0
models/data_manage/edb_refresh/edb_refresh_mapping.go

@@ -0,0 +1,68 @@
+package edb_refresh
+
+import (
+	"errors"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EdbRefreshMapping
+// @Description: 指标刷新时间配置关系表
+type EdbRefreshMapping struct {
+	EdbRefreshMappingId int       `orm:"column(edb_refresh_mapping_id);pk"`
+	Source              int       `description:"来源"`
+	SubSource           int       `description:"来源名称"`
+	EdbInfoId           int       `description:"指标id,如果是数据源(钢联、有色)的,那么就是数据源里面的id"`
+	EdbRefreshConfigId  int       `description:"刷新配置id"`
+	SysUserId           int       `description:"操作人id"`
+	SysUserRealName     string    `description:"操作人真实姓名"`
+	ModifyTime          time.Time `description:"最晚一次的更新时间"`
+	CreateTime          time.Time `description:"添加时间"`
+}
+
+// Add
+// @Description: 添加
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshMapping) Add() (err error) {
+	if m.EdbRefreshMappingId > 0 {
+		err = errors.New("该配置已存在")
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	lastId, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.EdbRefreshMappingId = int(lastId)
+
+	return
+}
+
+// Update
+// @Description: 更新
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @param cols []string
+// @return err error
+func (m *EdbRefreshMapping) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+// Delete
+// @Description: 删除
+// @author: Roc
+// @receiver m
+// @datetime 2023-12-14 16:11:10
+// @return err error
+func (m *EdbRefreshMapping) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(m)
+	return
+}

+ 51 - 0
models/data_manage/edb_refresh/edb_refresh_source.go

@@ -0,0 +1,51 @@
+package edb_refresh
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EdbRefreshSource
+// @Description: 刷新的数据源表
+type EdbRefreshSource struct {
+	Id            int       `orm:"column(id);pk"`
+	Source        int       `orm:"column(source)" description:"来源"`
+	SourceName    string    `description:"来源名称"`
+	SubSource     int       `description:"子数据来源:0:经济数据库,1:日期序列"`
+	SubSourceName string    `description:"子来源名称"`
+	HasChild      int       `description:"是否有子来源,0:否,1:是"`
+	ModifyTime    time.Time `description:"修改时间"`
+	CreateTime    time.Time `description:"创建时间"`
+}
+
+// EdbRefreshSourceList
+// @Description: 获取刷新的数据源列表
+type EdbRefreshSourceList struct {
+	Source        int                    `orm:"column(source)" description:"来源"`
+	SourceName    string                 `description:"来源名称"`
+	SubSource     int                    `description:"子数据来源:0:经济数据库,1:日期序列"`
+	SubSourceName string                 `description:"子来源名称"`
+	Child         []EdbRefreshSourceList `description:"子来源"`
+	HasChild      int                    `description:"是否有子来源,0:否,1:是"`
+}
+
+// GetAllList
+// @Description: 获取刷新数据源列表
+// @author: Roc
+// @datetime 2024-01-03 15:03:24
+// @return items []*EdbRefreshSource
+// @return err error
+func (m EdbRefreshSource) GetAllList() (items []*EdbRefreshSource, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM edb_refresh_source ORDER BY id ASC `
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+type BaseClassifyItems struct {
+	ClassifyId   int                  `description:"分类id"`
+	ClassifyName string               `description:"分类名称"`
+	ParentId     int                  `description:"父级id"`
+	UniqueCode   string               `description:"唯一编码"`
+	Children     []*BaseClassifyItems `description:"下级"`
+}

+ 52 - 0
models/data_manage/edb_refresh/request/edb_info_refresh.go

@@ -0,0 +1,52 @@
+package request
+
+// SaveEdbRefreshDefaultConfigReq
+// @Description: 设置默认刷新时间配置
+type SaveEdbRefreshDefaultConfigReq struct {
+	Source    int                `description:"来源"`
+	SubSource int                `description:"子来源"`
+	Frequency string             `description:"频度"`
+	List      []RefreshConfigReq `description:"刷新配置项"`
+}
+
+// RefreshConfigReq
+// @Description: 刷新时间配置项
+type RefreshConfigReq struct {
+	RefreshFrequency    string `description:"刷新频率"`
+	RefreshFrequencyDay int    `description:"具体刷新的日期"`
+	RefreshTime         string `description:"刷新时间"`
+	RefreshAllData      int    `description:"是否刷新所有数据,0:否,1:刷新所有数据"`
+	RefreshDataNum      int    `description:"刷新单元格数"`
+}
+
+// SaveEdbRefreshConfigReq
+// @Description: 设置指标的刷新时间配置
+type SaveEdbRefreshConfigReq struct {
+	Source          int                `description:"来源"`
+	SubSource       int                `description:"子来源"`
+	ClassifyId      string             `description:"分类id,支持多选,用英文,隔开"`
+	TerminalCode    string             `description:"终端编码"`
+	SysUserId       string             `description:"操作人id,支持多选,用英文,隔开"`
+	Frequency       string             `description:"频度,支持多选,用英文,隔开"`
+	Keyword         string             `description:"关键字"`
+	Status          string             `description:"状态,枚举值:启用、暂停"`
+	IsSelectAll     bool               `description:"是否选择所有指标"`
+	EdbSelectIdList []int              `description:"选择的指标id列表"`
+	List            []RefreshConfigReq `description:"刷新配置项"`
+}
+
+// SaveEdbRefreshStatusReq
+// @Description: 设置指标的刷新状态
+type SaveEdbRefreshStatusReq struct {
+	Source          int    `description:"来源"`
+	SubSource       int    `description:"子来源"`
+	ClassifyId      string `description:"分类id,支持多选,用英文,隔开"`
+	TerminalCode    string `description:"终端编码"`
+	SysUserId       string `description:"操作人id,支持多选,用英文,隔开"`
+	Frequency       string `description:"频度,支持多选,用英文,隔开"`
+	Keyword         string `description:"关键字"`
+	Status          string `description:"状态,枚举值:启用、暂停"`
+	IsSelectAll     bool   `description:"是否选择所有指标"`
+	EdbSelectIdList []int  `description:"选择的指标id列表"`
+	ModifyStatus    string `description:"需要更改的状态,枚举值:启用、暂停"`
+}

+ 25 - 6
models/data_manage/excel/excel_classify.go

@@ -49,6 +49,13 @@ func GetExcelClassifyById(classifyId int) (item *ExcelClassify, err error) {
 	return
 }
 
+func GetChildClassifyById(classifyId int) (items []*ExcelClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM excel_classify WHERE parent_id=? AND is_delete=0 `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
 func GetExcelClassifyByParentId(parentId, source int) (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM excel_classify WHERE parent_id=? AND source = ? AND is_delete=0 order by sort asc,excel_classify_id asc`
@@ -56,6 +63,13 @@ func GetExcelClassifyByParentId(parentId, source int) (items []*ExcelClassifyIte
 	return
 }
 
+func GetExcelClassifyBySource(source int) (items []*ExcelClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM excel_classify WHERE  source = ? AND is_delete=0 order by sort asc,excel_classify_id asc`
+	_, err = o.Raw(sql, source).QueryRows(&items)
+	return
+}
+
 func GetExcelClassifyAll() (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM excel_classify WHERE parent_id<>0 AND is_delete=0 order by sort asc,excel_classify_id asc`
@@ -108,13 +122,13 @@ func GetFirstExcelClassifyByParentId(parentId int) (item *ExcelClassify, err err
 }
 
 // UpdateExcelClassifySortByParentId 根据图表父类id更新排序
-func UpdateExcelClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+func UpdateExcelClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string, source int) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` update excel_classify set sort = ` + updateSort + ` WHERE parent_id=? and sort > ? AND is_delete=0 `
+	sql := ` update excel_classify set sort = ` + updateSort + ` WHERE parent_id=? and source=? and sort > ? AND is_delete=0 `
 	if classifyId > 0 {
 		sql += ` or ( excel_classify_id > ` + fmt.Sprint(classifyId) + ` and sort= ` + fmt.Sprint(nowSort) + `)`
 	}
-	_, err = o.Raw(sql, parentId, nowSort).Exec()
+	_, err = o.Raw(sql, parentId, source, nowSort).Exec()
 	return
 }
 
@@ -126,10 +140,10 @@ func (ExcelClassify *ExcelClassify) Update(cols []string) (err error) {
 }
 
 // GetExcelClassifyMaxSort 获取图表分类下最大的排序数
-func GetExcelClassifyMaxSort(parentId int) (sort int, err error) {
+func GetExcelClassifyMaxSort(parentId int, source int) (sort int, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT Max(sort) AS sort FROM excel_classify WHERE parent_id=? AND is_delete=0 `
-	err = o.Raw(sql, parentId).QueryRow(&sort)
+	sql := `SELECT Max(sort) AS sort FROM excel_classify WHERE parent_id=? AND source = ? AND is_delete=0 `
+	err = o.Raw(sql, parentId, source).QueryRow(&sort)
 	return
 }
 
@@ -145,3 +159,8 @@ func GetExcelClassifyViewById(classifyId int) (item *ExcelClassifyView, err erro
 	err = o.Raw(sql, classifyId).QueryRow(&item)
 	return
 }
+
+// ExcelClassifyItemBySort 自定义比较函数,按年龄从小到大排序
+func ExcelClassifyItemBySort(p1, p2 *ExcelClassifyItems) bool {
+	return p1.Sort < p2.Sort
+}

+ 30 - 0
models/data_manage/excel/excel_edb_mapping.go

@@ -2,6 +2,7 @@ package excel
 
 import (
 	"eta/eta_api/utils"
+	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -110,3 +111,32 @@ func DeleteCustomAnalysisExcelEdbMappingByEdbInfoId(excelInfoId int) (err error)
 
 	return
 }
+
+// GetExcelEdbMappingItemByExcelInfoIdOrKeyword 根据表格ID或关键词获取指标
+func GetExcelEdbMappingItemByExcelInfoIdOrKeyword(excelInfoId int, keyword string) (items []*ExcelEdbMappingItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	cond := `b.excel_info_id = ?`
+	pars := make([]interface{}, 0)
+	pars = append(pars, excelInfoId)
+	if keyword != "" {
+		cond += ` AND (a.edb_code LIKE ? OR a.edb_name LIKE ?)`
+		pars = append(pars, keyword, keyword)
+	}
+	sql := fmt.Sprintf(`SELECT
+			a.edb_info_id,
+			a.unique_code,
+			a.edb_name,
+			a.classify_id,
+			a.frequency,
+			a.unit,
+			calculate_formula
+		FROM
+			edb_info AS a
+		JOIN excel_edb_mapping AS b ON a.edb_info_id = b.edb_info_id
+		WHERE
+			%s
+		ORDER BY
+			b.excel_edb_mapping_id ASC`, cond)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}

+ 13 - 4
models/data_manage/excel/excel_info.go

@@ -132,7 +132,7 @@ func GetExcelInfoAll() (items []*ExcelClassifyItems, err error) {
 func GetNoContentExcelInfoAll(source, userId int) (items []*ExcelClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT excel_info_id,excel_classify_id,excel_name AS excel_classify_name,
-             unique_code,sys_user_id,sys_user_real_name
+             unique_code,sys_user_id,sys_user_real_name,sort
             FROM excel_info where is_delete=0 AND source = ?  `
 
 	pars := []interface{}{source}
@@ -253,14 +253,15 @@ func GetFirstExcelInfoByClassifyId(classifyId int) (item *ExcelInfo, err error)
 }
 
 // UpdateExcelInfoSortByClassifyId 根据表格id更新排序
-func UpdateExcelInfoSortByClassifyId(classifyId, nowSort, prevExcelInfoId int, updateSort string) (err error) {
+func UpdateExcelInfoSortByClassifyId(classifyId, nowSort, prevExcelInfoId int, updateSort string, source int) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` update excel_info set sort = ` + updateSort + ` WHERE excel_classify_id=? AND is_delete=0 AND ( sort > ? `
+	sql := ` update excel_info set sort = ` + updateSort + ` WHERE excel_classify_id=? AND source=? AND is_delete=0 AND ( sort > ? `
+	// todo 前一个兄弟节点后移
 	if prevExcelInfoId > 0 {
 		sql += ` or (excel_info_id < ` + fmt.Sprint(prevExcelInfoId) + ` and sort = ` + fmt.Sprint(nowSort) + `)`
 	}
 	sql += `)`
-	_, err = o.Raw(sql, classifyId, nowSort).Exec()
+	_, err = o.Raw(sql, classifyId, source, nowSort).Exec()
 	return
 }
 
@@ -516,3 +517,11 @@ type BatchRefreshExcelReq struct {
 	ReportChapterId int      `description:"报告章节ID"`
 	Source          string   `description:"来源,枚举值:report、english_report、smart_report"`
 }
+
+// GetExcelMaxSortByClassifyId 获取当前分类下,且排序数最大的excel
+func GetExcelMaxSortByClassifyId(classifyId int, source int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT Max(sort) AS sort FROM excel_info WHERE excel_classify_id=? AND source = ? AND is_delete=0 order by sort desc,excel_info_id desc limit 1`
+	err = o.Raw(sql, classifyId, source).QueryRow(&sort)
+	return
+}

+ 7 - 2
models/data_manage/excel/request/excel_classify.go

@@ -3,7 +3,7 @@ package request
 // AddExcelClassifyReq 添加excel分类请求
 type AddExcelClassifyReq struct {
 	ExcelClassifyName string `description:"分类名称"`
-	ParentId          int    `description:"父级id,第一级传0" json:"-"`
+	ParentId          int    `description:"父级id,第一级传0"`
 	Level             int    `description:"层级,第一级传0,其余传上一级的层级" json:"-"`
 	Source            int    `description:"1:excel插件的表格,2:自定义表格,3:混合表格,默认:1"`
 }
@@ -17,9 +17,14 @@ type EditExcelClassifyReq struct {
 // MoveExcelClassifyReq 移动图表分类请求参数
 type MoveExcelClassifyReq struct {
 	ClassifyId       int `description:"分类id"`
-	ParentClassifyId int `description:"父级分类id" json:"-"`
+	ParentClassifyId int `description:"父级分类id"`
 	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
 	NextClassifyId   int `description:"下一个兄弟节点分类id"`
+
+	ExcelInfoId     int `description:"excel表格ID"`
+	PrevExcelInfoId int `description:"上一个excel表格ID"`
+	NextExcelInfoId int `description:"下一个excel表格ID"`
+	Source          int
 }
 
 type DeleteExcelClassifyReq struct {

+ 69 - 8
models/data_manage/excel/request/mixed_table.go

@@ -9,6 +9,7 @@ const (
 	PopInsertDataDT                     // 5 弹框插值(在表格上选择日期,然后空白单元格选择弹框并选择指标,插入该指标与该日期的值)
 	FormulateCalculateDataDT            // 6 公式计算(A+B这种)
 	InsertEdbCalculateDataDT            // 7 插入指标系统计算公式生成的值
+	DateCalculateDataDT                 // 8 日期计算
 )
 
 // 单元格的日期类型类型
@@ -16,6 +17,7 @@ const (
 	CustomDateT = iota //手动输入日期
 	SystemDateT        // 系统日期
 	EdbDateDT          // 导入指标日期(指标库的最新日期)
+
 )
 
 // 单元格的日期类型类型
@@ -33,14 +35,16 @@ type MixedTableReq struct {
 
 // MixedTableCellDataReq 混合表格单元格参数
 type MixedTableCellDataReq struct {
-	Uid          string `description:"单元格唯一标识"`
-	DataType     int    `description:"数据类型,1:日期,2:指标,3:自定义文本,4:插值"`
-	DataTime     string `description:"所属日期"`
-	DataTimeType int    `description:"日期类型:0:手动输入日期;1:导入系统日期;;3:导入指标日期(指标库的最新日期);"`
-	EdbInfoId    int    `description:"指标id"`
-	ShowValue    string `description:"展示值"`
-	Value        string `description:"实际值"`
-	Extra        string `description:"额外参数"`
+	Uid             string      `description:"单元格唯一标识"`
+	DataType        int         `description:"数据类型,1:日期,2:指标,3:自定义文本,4:插值"`
+	DataTime        string      `description:"所属日期"`
+	DataTimeType    int         `description:"日期类型:0:手动输入日期(固定日期);1:导入系统日期;;3:导入指标日期(指标库的最新日期);"`
+	EdbInfoId       int         `description:"指标id"`
+	ShowValue       string      `description:"展示值"`
+	Value           string      `description:"实际值和配置"`
+	Extra           string      `description:"额外参数"`
+	ShowStyle       string      `description:"展示的样式配置"`
+	ShowFormatValue interface{} `description:"样式处理后的值"`
 }
 
 // CellRelationConf
@@ -74,6 +78,61 @@ type SystemDateConf struct {
 // @Description: 导入指标日期配置
 type EdbDateConf struct {
 	EdbInfoId int `description:"指标id"`
+	EdbDateChangeConf
+}
+
+// EdbDateExtraConf
+// @Description: 导入指标日期前移和日期变换
+type EdbDateChangeConf struct {
+	MoveForward int `description:"前移的期数"`
+	DateChange  []*EdbDateConfDateChange
+}
+
+type EdbDateConfDateChange struct {
+	Year         int
+	Month        int
+	Day          int
+	Frequency    string `description:"频度变换"`
+	FrequencyDay string `description:"频度的固定日期"`
+	ChangeType   int    `description:"日期变换类型1日期位移,2指定频率"`
+}
+
+// MixedDateCalculateReq 混合表格日期计算
+type MixedDateCalculateReq struct {
+	Formula  string                   `description:"计算公式"`
+	DateList []MixDateCalculateTagReq `description:"表格中的单元格"`
+}
+
+// MixDateCalculateConf 混合表格中的日期计算
+type MixDateCalculateConf struct {
+	Formula          string                `description:"计算公式"`
+	RelationCellList []MixDateCalculateTag `description:"表格中的单元格"`
+}
+
+// MixDateCalculateTag 混合表格中的日期计算的关联单元格
+type MixDateCalculateTag struct {
+	Uid string `description:"单元格唯一值"`
+	Tag string `description:"单元格对应标签"`
+}
+
+// MixDateCalculateTagReq 混合表格中的日期计算的关联单元格
+type MixDateCalculateTagReq struct {
+	Date string `description:"日期"`
+	Tag  string `description:"指标对应标签"`
+}
+
+// MixCellShowStyle 混合表格 单元格样式展示计算
+type MixCellShowStyle struct {
+	Pn int    `description:"小数点位数增加或减少,正数表述增加,负数表示减少" json:"pn"`
+	Nt string `description:"变换类型:number 小数点位数改变,percent百分比," json:"nt"`
+}
+
+type DateDataBeforeAfterReq struct {
+	EdbInfoId   int
+	Date        string
+	Num         int
+	MoveForward int `description:"前移的期数"`
+	DateChange  []*EdbDateConfDateChange
 }
 
 // CalculateConf
@@ -87,6 +146,8 @@ type CalculateConf struct {
 	MoveType      int         `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency string      `description:"移动频度"`
 	Source        int         `description:"1:累计值转月;2:累计值转季;3:同比值;4:同差值;5:N数值移动平均数计算;6:环比值;7:环差值;8:升频;9:降频;10:时间移位;11:超季节性;12:年化;13:累计值;14:累计值年初至今;15:指数修匀;16:日均值"`
+
+	EdbDateChangeConf
 }
 
 // BaseCalculateConf

+ 126 - 0
models/data_manage/mysteel_chemical_index.go

@@ -30,6 +30,8 @@ type BaseFromMysteelChemicalIndex struct {
 	Sort                              int       `description:"排序字段"`
 	MergeFilePath                     string    `description:"合并文件"`
 	TerminalCode                      string    `description:"终端编码"`
+	IsStop                            int       `description:"是否停更:1:停更,0:未停更"`
+	EndValue                          float64   `description:"指标的最新值"`
 }
 
 // Update 更新钢联化工指标基础信息
@@ -337,3 +339,127 @@ func GetMysteelChemicalGroupTerminalNum() (items []*TerminalNum, err error) {
 	_, err = o.Raw(sql).QueryRows(&items)
 	return
 }
+
+// BaseRefreshEdbInfo
+// @Description: 刷新配置的基础指标信息结构体
+type BaseRefreshEdbInfo struct {
+	EdbInfoId       int
+	ClassifyId      int    `description:"钢联化工指标分类id"`
+	IndexCode       string `description:"指标编码"`
+	IndexName       string `description:"指标名称"`
+	EndDate         string `description:"最新日期"`
+	EndValue        string `description:"最新值"`
+	SysUserId       int    `description:"创建人id"`
+	SysUserRealName string `description:"创建人姓名"`
+	Frequency       string `description:"频度"`
+	IsStop          int    `description:"是否停更:1:停更,0:未停更"`
+	TerminalCode    string `description:"终端编码"`
+	RefreshTime     string `description:"刷新时间"`
+}
+
+// RefreshBaseEdbInfoResp
+// @Description: 刷新数据源的数据返回
+type RefreshBaseEdbInfoResp struct {
+	Paging *paging.PagingItem
+	List   []*BaseRefreshEdbInfo
+}
+
+// GetMysteelChemicalBaseInfoList
+// @Description: 获取钢联化工数据列表
+// @author: Roc
+// @datetime 2024-01-10 14:28:35
+// @param condition string
+// @param pars []interface{}
+// @param orderBy string
+// @param startSize int
+// @param pageSize int
+// @return total int
+// @return items []*BaseRefreshEdbInfo
+// @return err error
+func GetMysteelChemicalBaseInfoList(condition string, pars []interface{}, orderBy string, startSize, pageSize int) (total int, items []*BaseRefreshEdbInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+
+	// 数量汇总
+	totalSql := ` SELECT count(1) FROM base_from_mysteel_chemical_index WHERE 1=1 `
+	if condition != "" {
+		totalSql += condition
+	}
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil {
+		return
+	}
+
+	// 列表数据
+	sql := ` SELECT base_from_mysteel_chemical_index_id as edb_info_id, base_from_mysteel_chemical_classify_id as classify_id,index_code,index_name,end_date,end_value,sys_user_id,sys_user_real_name,frequency,is_stop,terminal_code FROM base_from_mysteel_chemical_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+
+	if orderBy != "" {
+		sql += ` ORDER BY ` + orderBy
+	} else {
+		sql += ` ORDER BY base_from_mysteel_chemical_index_id ASC `
+	}
+	sql += `  LIMIT ?,? `
+
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ModifyMysteelChemicalUpdateStatus
+// @Description:  修改钢联化工数据停更状态
+// @author: Roc
+// @datetime 2024-01-08 16:23:31
+// @param edbIdList []int
+// @param indexCodeList []string
+// @param isStop int
+// @return err error
+func ModifyMysteelChemicalUpdateStatus(edbIdList []int, indexCodeList []string, isStop int) (err error) {
+	idNum := len(edbIdList)
+	if idNum <= 0 {
+		return
+	}
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 更改数据源的更新状态
+	sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = ? WHERE base_from_mysteel_chemical_index_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+	_, err = o.Raw(sql, isStop, edbIdList).Exec()
+	if err != nil {
+		return
+	}
+
+	codeNum := len(indexCodeList)
+	if codeNum <= 0 {
+		// 需要通过指标id列表查找code列表
+		sql := ` SELECT index_code FROM base_from_mysteel_chemical_index WHERE base_from_mysteel_chemical_index_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+		_, err = o.Raw(sql, edbIdList).QueryRows(&indexCodeList)
+		if err != nil {
+			return
+		}
+	}
+
+	codeNum = len(indexCodeList)
+	// 查出来的编码是空的话,那么就直接返回了
+	if codeNum <= 0 {
+		return
+	}
+
+	// 更改指标的更新状态
+	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
+	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, indexCodeList).Exec()
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 119 - 0
models/data_manage/smm_data.go

@@ -47,6 +47,8 @@ type SmmIndex struct {
 	FinishTime         string
 	CreateTime         string
 	ModifyTime         string
+	IsStop             int     `description:"是否停更:1:停更,0:未停更"`
+	EndValue           float64 `description:"指标的最新值"`
 }
 
 type SmmIndexItem struct {
@@ -68,6 +70,8 @@ type SmmIndexItem struct {
 	FinishTime         string
 	CreateTime         string
 	ModifyTime         string
+	IsStop             int     `description:"是否停更:1:停更,0:未停更"`
+	EndValue           float64 `description:"指标的最新值"`
 }
 
 func GetSmmIndex(condition string, pars interface{}) (items []*SmmIndex, err error) {
@@ -81,6 +85,21 @@ func GetSmmIndex(condition string, pars interface{}) (items []*SmmIndex, err err
 	return
 }
 
+// GetSmmIndexById
+// @Description: 根据id获取指标信息
+// @author: Roc
+// @datetime 2024-01-10 14:25:26
+// @param basFromSmmIndexId int
+// @return item *SmmIndex
+// @return err error
+func GetSmmIndexById(basFromSmmIndexId int) (item *SmmIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_smm_index WHERE base_from_smm_index_id = ?  `
+	err = o.Raw(sql, basFromSmmIndexId).QueryRow(&item)
+
+	return
+}
+
 type SmmExportIndex struct {
 	TypeName   string
 	IndexCode  string
@@ -230,3 +249,103 @@ func GetExportSmmIndexDataByCodes(indexCodes []string) (items []*ExportSmmIndexD
 	_, err = o.Raw(sql, indexCodes).QueryRows(&items)
 	return
 }
+
+// GetSmmBaseInfoList
+// @Description: 获取有色数据列表
+// @author: Roc
+// @datetime 2024-01-10 14:28:29
+// @param condition string
+// @param pars []interface{}
+// @param orderBy string
+// @param startSize int
+// @param pageSize int
+// @return total int
+// @return items []*BaseRefreshEdbInfo
+// @return err error
+func GetSmmBaseInfoList(condition string, pars []interface{}, orderBy string, startSize, pageSize int) (total int, items []*BaseRefreshEdbInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+
+	// 数量汇总
+	totalSql := ` SELECT count(1) FROM base_from_smm_index WHERE 1=1 `
+	if condition != "" {
+		totalSql += condition
+	}
+	err = o.Raw(totalSql, pars).QueryRow(&total)
+	if err != nil {
+		return
+	}
+
+	// 列表数据
+	sql := ` SELECT base_from_smm_index_id as edb_info_id, classify_id,index_code,index_name,end_date,end_value,frequency,is_stop,terminal_code FROM base_from_smm_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+
+	if orderBy != "" {
+		sql += ` ORDER BY ` + orderBy
+	} else {
+		sql += ` ORDER BY base_from_smm_index_id ASC `
+	}
+	sql += `  LIMIT ?,? `
+
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// ModifySmmUpdateStatus
+// @Description:  修改有色数据停更状态
+// @author: Roc
+// @datetime 2024-01-08 16:23:31
+// @param edbIdList []int
+// @param indexCodeList []string
+// @param isStop int
+// @return err error
+func ModifySmmUpdateStatus(edbIdList []int, indexCodeList []string, isStop int) (err error) {
+	idNum := len(edbIdList)
+	if idNum <= 0 {
+		return
+	}
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 更改数据源的更新状态
+	sql := ` UPDATE base_from_smm_index SET is_stop = ? WHERE base_from_smm_index_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+	_, err = o.Raw(sql, isStop, edbIdList).Exec()
+	if err != nil {
+		return
+	}
+
+	codeNum := len(indexCodeList)
+	if codeNum <= 0 {
+		// 需要通过指标id列表查找code列表
+		sql := ` SELECT index_code FROM base_from_smm_index WHERE base_from_smm_index_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+		_, err = o.Raw(sql, edbIdList).QueryRows(&indexCodeList)
+		if err != nil {
+			return
+		}
+	}
+
+	codeNum = len(indexCodeList)
+	// 查出来的编码是空的话,那么就直接返回了
+	if codeNum <= 0 {
+		return
+	}
+
+	// 更改指标的更新状态
+	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
+	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_YS, 0, indexCodeList).Exec()
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 134 - 0
models/data_source/guagnzhouqihuo.go

@@ -0,0 +1,134 @@
+package data_source
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BaseFromTradeGuangzhouClassify struct {
+	BaseFromTradeGuangzhouClassifyId int       `orm:"column(base_from_trade_guangzhou_classify_id);pk"`
+	ClassifyName                     string    `description:"分类名称"`
+	ClassifyCode                     string    `description:"分类编码"`
+	ParentId                         int       `description:"分类父级id"`
+	ModifyTime                       time.Time `description:"修改时间"`
+	CreateTime                       time.Time `description:"创建时间"`
+}
+
+type BaseFromTradeGuangzhouIndex struct {
+	BaseFromTradeGuangzhouIndexId    int       `orm:"column(base_from_trade_guangzhou_index_id);pk"`
+	BaseFromTradeGuangzhouClassifyId int       `description:"分类id"`
+	IndexCode                        string    `description:"指标编码"`
+	IndexName                        string    `description:"指标名称"`
+	Frequency                        string    `description:"频率"`
+	Unit                             string    `description:"单位"`
+	StartDate                        string    `description:"开始日期"`
+	EndDate                          string    `description:"结束日期"`
+	CreateTime                       time.Time `description:"创建日期"`
+	ModifyTime                       time.Time `description:"修改日期"`
+}
+
+type BaseFromTradeGuangzhouData struct {
+	BaseFromTradeGuangzhouDataId  int       `orm:"column(base_from_trade_guangzhou_data_id);pk"`
+	BaseFromTradeGuangzhouIndexId int       `description:"指标id"`
+	IndexCode                     string    `description:"指标编码"`
+	DataTime                      string    `description:"数据日期"`
+	Value                         float64   `description:"数据值"`
+	QtySub                        float64   `description:"增减"`
+	CreateTime                    time.Time `description:"创建日期"`
+	ModifyTime                    time.Time `description:"修改日期"`
+}
+
+type BaseFromTradeGuangzhouClassifyView struct {
+	BaseFromTradeGuangzhouClassifyId int    `orm:"column(base_from_trade_guangzhou_classify_id);pk"`
+	ClassifyName                     string `description:"分类名称"`
+	ClassifyCode                     string `description:"分类编码"`
+	ParentId                         int    `description:"分类父级id"`
+	Children                         []*BaseFromTradeGuangzhouClassifyView
+}
+
+type BaseFromTradeGuangzhouContract struct {
+	BaseFromTradeGuangzhouContractId int    `orm:"column(base_from_trade_guangzhou_contract_id);pk"`
+	BaseFromTradeGuangzhouClassifyId int    `description:"分类id"`
+	ClassifyCode                     string `description:"分类编码"`
+	Contract                         string `description:"合约编码"`
+	TradeDate                        string `description:"合约日期"`
+}
+
+func (obj *BaseFromTradeGuangzhouIndex) GetBaseFromTradeGuangzhouClassifyAll() (list []*BaseFromTradeGuangzhouClassifyView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_trade_guangzhou_classify`
+	_, err = o.Raw(sql).QueryRows(&list)
+	return list, err
+}
+
+func (obj *BaseFromTradeGuangzhouIndex) GetBaseFromTradeGuangzhouMaxDate() (max_date string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT MAX(a.end_date) AS max_date FROM base_from_trade_guangzhou_index AS a `
+	err = o.Raw(sql).QueryRow(&max_date)
+	return max_date, err
+}
+
+func (obj *BaseFromTradeGuangzhouIndex) GetBaseFromTradeGuangzhouContract(classifyId int, tradeDate string) (list []*BaseFromTradeGuangzhouContract, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_trade_guangzhou_contract AS a WHERE base_from_trade_guangzhou_classify_id=? AND trade_date=? `
+	_, err = o.Raw(sql, classifyId, tradeDate).QueryRows(&list)
+	return
+}
+
+type BaseFromTradeGuangzhouIndexView struct {
+	BaseFromTradeGuangzhouIndexId    int     `description:"指标id"`
+	BaseFromTradeGuangzhouClassifyId int     `description:"分类id"`
+	IndexCode                        string  `description:"指标编码"`
+	IndexName                        string  `description:"指标名称"`
+	Frequency                        string  `description:"频率"`
+	Unit                             string  `description:"单位"`
+	StartDate                        string  `description:"开始日期"`
+	EndDate                          string  `description:"结束日期"`
+	Value                            float64 `description:"数据"`
+}
+
+func (obj *BaseFromTradeGuangzhouIndex) GetBaseFromTradeGuangzhouIndex(condition string, pars []interface{}, baseFromTradeGuangzhouContractId int) (list []*BaseFromTradeGuangzhouIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	if baseFromTradeGuangzhouContractId <= 0 {
+		sql := ` SELECT b.base_from_trade_guangzhou_index_id,b.index_code,b.index_name,b.unit,b.frequency,b.start_date,b.end_date,a.value,c.base_from_trade_guangzhou_contract_id 
+ FROM base_from_trade_guangzhou_data AS a
+INNER JOIN base_from_trade_guangzhou_index AS b ON a.base_from_trade_guangzhou_index_id=b.base_from_trade_guangzhou_index_id
+LEFT JOIN base_from_trade_guangzhou_contract AS c ON b.base_from_trade_guangzhou_classify_id=c.base_from_trade_guangzhou_classify_id
+WHERE `
+		if condition != "" {
+			sql += condition
+		}
+		sql += ` ORDER BY a.index_code ASC `
+		_, err = o.Raw(sql, pars).QueryRows(&list)
+		return
+	} else {
+		condition += ` AND a.base_from_trade_guangzhou_contract_id=? `
+		pars = append(pars, baseFromTradeGuangzhouContractId)
+
+		sql := ` SELECT a.*,b.value 
+ FROM base_from_trade_guangzhou_index AS a
+INNER JOIN base_from_trade_guangzhou_data AS b ON a.base_from_trade_guangzhou_index_id=b.base_from_trade_guangzhou_index_id
+WHERE `
+
+		if condition != "" {
+			sql += condition
+		}
+		sql += ` ORDER BY a.index_code ASC `
+		_, err = o.Raw(sql, pars).QueryRows(&list)
+		return
+	}
+}
+
+func (obj *BaseFromTradeGuangzhouIndex) GetBaseFromTradeGuangzhouIndexDetail(condition string, pars []interface{}) (list []*BaseFromTradeGuangzhouIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT a.*
+ FROM base_from_trade_guangzhou_index AS a
+WHERE `
+
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY a.index_code ASC `
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}

+ 114 - 0
models/data_source/icpi.go

@@ -0,0 +1,114 @@
+package data_source
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type BaseFromIcpiIndex struct {
+	BaseFromIcpiIndexId    int       `orm:"column(base_from_icpi_index_id);pk"`
+	BaseFromIcpiClassifyId int       `description:"分类id"`
+	IndexCode              string    `description:"指标编码"`
+	IndexName              string    `description:"指标名称"`
+	Frequency              string    `description:"频度"`
+	StartDate              time.Time `description:"开始日期"`
+	EndDate                time.Time `description:"结束日期"`
+	CreateTime             time.Time `description:"创建时间"`
+	ModifyTime             time.Time `description:"修改时间"`
+}
+
+type BaseFromIcpiData struct {
+	BaseFromIcpiDataId  int       `orm:"column(base_from_icpi_data_id);pk"`
+	BaseFromIcpiIndexId int       `description:"指标id"`
+	IndexCode           string    `description:"指标编码"`
+	DataTime            string    `description:"日期"`
+	Value               string    `description:"值"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+}
+
+type BaseFromIcpiClassify struct {
+	BaseFromIcpiClassifyId int    `orm:"column(base_from_icpi_classify_id);pk"`
+	ClassifyName           string `description:"分类名称"`
+	ClassifyNameEn         string `description:"英文名称"`
+	ParentId               int    `description:"上级id"`
+	CreateTime             string `description:"创建时间"`
+	ModifyTime             string `description:"修改时间"`
+}
+
+func (obj *BaseFromIcpiIndex) GetBaseFromIcpiClassifyAll() (list []*BaseFromIcpiClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_icpi_classify `
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
+type BaseFromIcpiDataView struct {
+	BaseFromIcpiDataId  int       `orm:"column(base_from_icpi_data_id);pk"`
+	BaseFromIcpiIndexId int       `description:"指标id"`
+	IndexCode           string    `description:"指标编码"`
+	DataTime            string    `description:"日期"`
+	Value               string    `description:"值"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+}
+
+type BaseFromIcpiIndexView struct {
+	BaseFromIcpiIndexId    int    `description:"指标id"`
+	BaseFromIcpiClassifyId int    `description:"分类id"`
+	IndexCode              string `description:"指标编码"`
+	IndexName              string `description:"指标名称"`
+	Frequency              string `description:"频度"`
+	Unit                   string `description:"单位"`
+	StartDate              string `description:"开始日期"`
+	EndDate                string `description:"结束日期"`
+	CreateTime             string `description:"创建时间"`
+	ModifyTime             string `description:"修改时间"`
+	DataList               []*BaseFromIcpiDataView
+	Paging                 *paging.PagingItem `description:"分页数据"`
+}
+
+func (obj *BaseFromIcpiIndex) GetIcpiIndex(condition string, pars interface{}) (items []*BaseFromIcpiIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_icpi_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += `ORDER BY base_from_icpi_index_id ASC `
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (obj *BaseFromIcpiIndex) GetIcpiIndexDataCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count  FROM base_from_icpi_data WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+func (obj *BaseFromIcpiIndex) GetIcpiIndexData(indexCode string, startSize, pageSize int) (items []*BaseFromIcpiDataView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_icpi_data WHERE index_code=? ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func (obj *BaseFromIcpiIndex) GetIcpiDataMaxCount(classifyId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT MAX(t.num) AS count FROM (
+				SELECT COUNT(1) AS num  FROM base_from_icpi_index AS a
+				INNER JOIN base_from_icpi_data AS b ON a.base_from_icpi_index_id=b.base_from_icpi_index_id
+				WHERE a.base_from_icpi_classify_id=?
+				GROUP BY a.base_from_icpi_index_id
+			)AS t `
+	err = o.Raw(sql, classifyId).QueryRow(&count)
+	return
+}
+
+func (obj *BaseFromIcpiIndex) GetIcpiIndexDataByCode(indexCode string) (items []*BaseFromIcpiDataView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_icpi_data WHERE index_code=? ORDER BY data_time DESC  `
+	_, err = o.Raw(sql, indexCode).QueryRows(&items)
+	return
+}

+ 14 - 0
models/db.go

@@ -6,6 +6,7 @@ import (
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/data_manage/chart_theme"
 	"eta/eta_api/models/data_manage/cross_variety"
+	"eta/eta_api/models/data_manage/edb_refresh"
 	"eta/eta_api/models/data_manage/excel"
 	future_good2 "eta/eta_api/models/data_manage/future_good"
 	"eta/eta_api/models/data_manage/supply_analysis"
@@ -182,6 +183,9 @@ func init() {
 	// 初始化图表主题
 	initChartTheme()
 
+	// 初始化指标刷新
+	initEdbRefresh()
+
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	data_manage.InitEdbSourceVar()
 }
@@ -534,3 +538,13 @@ func initChartTheme() {
 		new(chart_theme.ChartThemeDefaultData), //默认数据
 	)
 }
+
+// initEdbRefresh 初始化指标刷新
+func initEdbRefresh() {
+	orm.RegisterModel(
+		new(edb_refresh.EdbRefreshSource),        // 刷新的数据源表
+		new(edb_refresh.EdbRefreshDefaultConfig), // 指标的默认刷新时间配置表
+		new(edb_refresh.EdbRefreshConfig),        // 指标的刷新时间配置表
+		new(edb_refresh.EdbRefreshMapping),       // 指标刷新时间配置关系表
+	)
+}

+ 1 - 1
models/english_report_email.go

@@ -141,7 +141,7 @@ WHERE a.is_deleted = 0 `
 // GetEnglishReportEmailList 获取邮箱列表
 func GetEnglishReportEmailList(condition string, pars []interface{}, order string) (list []*EnglishReportEmail, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT * FROM english_report_email WHERE is_deleted = 0 `
+	sql := `SELECT * FROM english_report_email WHERE is_deleted = 0`
 	sql += condition
 	if order != "" {
 		sql += order

+ 4 - 3
models/roadshow/calendar.go

@@ -33,9 +33,10 @@ func GetResearcherGroup() (list []*ResearcherGroup, err error) {
 
 func GetResearcher() (list []*Researcher, err error) {
 	o := orm.NewOrm()
-	sql := ` SELECT * FROM admin AS a
-			WHERE a.role_type_code IN('researcher','rai_researcher','ficc_researcher','ficc_admin')
-			AND a.enabled=1 AND a.real_name<>'于菲' `
+	//sql := ` SELECT * FROM admin AS a
+	//		WHERE a.role_type_code IN('researcher','rai_researcher','ficc_researcher','ficc_admin')
+	//		AND a.enabled=1 AND a.real_name<>'于菲' `
+	sql := ` SELECT * FROM admin AS a WHERE a.enabled=1 `
 	_, err = o.Raw(sql).QueryRows(&list)
 	return
 }

+ 1 - 1
models/system/sys_role_admin.go

@@ -245,7 +245,7 @@ func EditEnglishAuthRoleAdmin(adminId int, englishRoleIds []int, roleAdmins []*S
 	}
 
 	// 新增绑定关系
-	_, err = o.InsertMulti(len(roleAdmins), roleAdmins)
+	_, err = tx.InsertMulti(len(roleAdmins), roleAdmins)
 	return
 }
 

+ 1 - 1
models/target.go

@@ -244,7 +244,7 @@ type EdbinfoAddReq struct {
 
 // GetMaxTradeCode 获取指标最大trade_code
 func GetMaxTradeCode() (max_trade_code string, err error) {
-	sql := " SELECT MAX(TRADE_CODE) AS max_trade_code FROM edbinfo WHERE LEFT(TRADE_CODE,1)='W' AND TRADE_CODE not like '%index%'"
+	sql := " SELECT MAX(TRADE_CODE) AS max_trade_code FROM edbinfo WHERE LEFT(TRADE_CODE,1)='W' AND TRADE_CODE not like '%index%' and TRADE_CODE NOT LIKE 'WDC%'"
 	o := orm.NewOrmUsingDB("edb")
 	err = o.Raw(sql).QueryRow(&max_trade_code)
 	if (err != nil && err.Error() == utils.ErrNoRow()) || max_trade_code == `` {

+ 298 - 1
routers/commentsRouter.go

@@ -637,6 +637,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetBaseEdbInfo",
+            Router: `/excel_info/base_edb_info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "Copy",
@@ -718,6 +727,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetMixDateCalculate",
+            Router: `/excel_info/mixed/date_calculate`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "Move",
@@ -1897,6 +1915,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoConvertDetail",
+            Router: `/chart_info/convert/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "CopyChartInfo",
@@ -2005,6 +2032,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "PreviewRadarChartInfo",
+            Router: `/chart_info/preview/radar`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "PreviewSectionScatterChartInfo",
@@ -2828,7 +2864,7 @@ func init() {
         beego.ControllerComments{
             Method: "GetEdbBeforeAndAfterDateData",
             Router: `/edb_info/date_data/before_after`,
-            AllowHTTPMethods: []string{"get"},
+            AllowHTTPMethods: []string{"post"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
@@ -2968,6 +3004,78 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "RefreshClassifyList",
+            Router: `/edb_info/refresh/classify_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "SaveEdbRefreshConfig",
+            Router: `/edb_info/refresh/config/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "GetEdbRefreshDefaultConfig",
+            Router: `/edb_info/refresh/default_config`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "SaveEdbRefreshDefaultConfig",
+            Router: `/edb_info/refresh/default_config/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "GetEdbRefreshEdbConfig",
+            Router: `/edb_info/refresh/edb_config`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "RefreshEdbList",
+            Router: `/edb_info/refresh/edb_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "RefreshSourceList",
+            Router: `/edb_info/refresh/source_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "SaveEdbRefreshStatus",
+            Router: `/edb_info/refresh/status/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
         beego.ControllerComments{
             Method: "RelationChartList",
@@ -3211,6 +3319,51 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "FenweiClassify",
+            Router: `/fenwei/classify`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "ExportFenweiList",
+            Router: `/fenwei/export`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "FenweiIndexData",
+            Router: `/fenwei/index/data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "FenweiSearchList",
+            Router: `/fenwei/search_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "FenweiSingleData",
+            Router: `/fenwei/single_data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
         beego.ControllerComments{
             Method: "GlClassify",
@@ -4228,6 +4381,87 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "GfexClassifyList",
+            Router: `/gfex/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "GfexContract",
+            Router: `/gfex/contract`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "GfexIndexDetail",
+            Router: `/gfex/index/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "ExportGfexIndexDetail",
+            Router: `/gfex/index/detail/export`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "GfexIndexData",
+            Router: `/gfex/index_data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "GfexMaxDate",
+            Router: `/gfex/max/date`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "IcpiClassifyList",
+            Router: `/icpi/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "ExportIcpiDataList",
+            Router: `/icpi/export/icpiDataList`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+        beego.ControllerComments{
+            Method: "IcpiData",
+            Router: `/icpi/index/data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbSourceStatController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbSourceStatController"],
         beego.ControllerComments{
             Method: "EdbDeleteLog",
@@ -8089,6 +8323,51 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "MtjhClassify",
+            Router: `/data/mtjh/classify`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "MtjhData",
+            Router: `/data/mtjh/data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "MtjhFrequency",
+            Router: `/data/mtjh/frequency`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "MtjhSearchList",
+            Router: `/data/mtjh/search`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "MtjhSingleData",
+            Router: `/data/mtjh/single_data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
         beego.ControllerComments{
             Method: "ShfeDataList",
@@ -8116,6 +8395,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:TradeCommonController"],
+        beego.ControllerComments{
+            Method: "ExportMtjhList",
+            Router: `/export/mtjh`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
         beego.ControllerComments{
             Method: "AreaCodeList",
@@ -8125,6 +8413,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
+        beego.ControllerComments{
+            Method: "BaseInfo",
+            Router: `/base_info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
         beego.ControllerComments{
             Method: "ForgetAccountGet",

+ 6 - 0
routers/router.go

@@ -18,6 +18,7 @@ import (
 	"eta/eta_api/controllers/data_manage/line_equation"
 	"eta/eta_api/controllers/data_manage/line_feature"
 	"eta/eta_api/controllers/data_manage/supply_analysis"
+	"eta/eta_api/controllers/data_source"
 	"eta/eta_api/controllers/data_stat"
 	"eta/eta_api/controllers/english_report"
 	"eta/eta_api/controllers/eta_trial"
@@ -336,6 +337,11 @@ func init() {
 				&report_approve.ReportApproveFlowController{},
 			),
 		),
+		web.NSNamespace("/data_source",
+			web.NSInclude(
+				&data_source.DataSourceController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 130 - 0
services/aws_s3.go

@@ -0,0 +1,130 @@
+package services
+
+import (
+	"bytes"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/s3"
+	"io/ioutil"
+	"time"
+)
+
+type OssClient interface {
+	UploadFile(string, string, string) (string, error)
+	GetUploadToken() (OssToken, error)
+}
+
+func NewOssClient() OssClient {
+	switch utils.ObjectStorageClient {
+	case utils.STORAGESOURCE_MINIO_NAME:
+		return new(MinioOss)
+	case utils.STORAGESOURCE_S3_NAME:
+		return new(S3Oss)
+	default:
+		// 默认使用阿里云OSS
+		return new(AliOss)
+	}
+}
+
+// OssToken 此处为了兼容前端那边所以有重复的
+type OssToken struct {
+	AccessKeyId string
+	SecretKeyId string
+	RegionId    string
+	Bucketname  string
+	Endpoint    string
+	ImgHost     string
+	UseSSL      string
+	Port        string
+	//AccessKeyId     string
+	AccessKeySecret string
+	SecurityToken   string
+	ExpiredTime     string
+	//RegionId        string
+	//Bucketname      string
+	//Endpoint        string
+	Imghost      string
+	S3ForceStyle bool
+	S3Protocol   string
+}
+
+type S3Oss struct{}
+
+func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl string, err error) {
+	defer func() {
+		if err != nil {
+			fmt.Println(err.Error())
+		}
+	}()
+
+	endpoint := utils.S3Endpoint
+	accessKey := utils.S3AccessKeyId
+	secretKey := utils.S3AccessKeySecret
+	region := utils.S3Region
+	bucketName := utils.S3BucketName
+	uploadDir := utils.S3UploadDir
+	resourceHost := utils.S3Host
+	forceStyle := utils.S3ForceStyle
+	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
+	if forceStyle == "false" {
+		hostStyle = false
+	}
+
+	// 创建AWS会话
+	sess, e := session.NewSession(&aws.Config{
+		Region:           aws.String(region),
+		Credentials:      credentials.NewStaticCredentials(accessKey, secretKey, ""),
+		Endpoint:         aws.String(endpoint),
+		S3ForcePathStyle: aws.Bool(hostStyle),
+	})
+	if e != nil {
+		err = fmt.Errorf("new session err: %s", e.Error())
+		return
+	}
+
+	// 创建S3服务客户端
+	client := s3.New(sess)
+
+	// 读取文件内容
+	fileContent, e := ioutil.ReadFile(localFile)
+	if e != nil {
+		err = fmt.Errorf("read file err: %s", e.Error())
+		return
+	}
+
+	path := savePath
+	if savePath == "" {
+		path = uploadDir + time.Now().Format("200601/20060102/") + fileName
+	}
+	_, e = client.PutObject(&s3.PutObjectInput{
+		Bucket: aws.String(bucketName),
+		Key:    aws.String(path),
+		Body:   bytes.NewReader(fileContent),
+	})
+	if e != nil {
+		err = fmt.Errorf("put object err: %s", e.Error())
+		return
+	}
+	resourceUrl = resourceHost + path
+	return
+}
+
+func (m *S3Oss) GetUploadToken() (token OssToken, err error) {
+	token.Endpoint = utils.S3Endpoint
+	token.AccessKeyId = utils.S3AccessKeyId
+	token.AccessKeySecret = utils.S3AccessKeySecret
+	token.RegionId = utils.S3Region
+	token.Bucketname = utils.S3BucketName
+	token.ImgHost = utils.S3Host
+	token.Port = utils.S3EndpointPort
+	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
+	if utils.S3ForceStyle == "false" {
+		hostStyle = false
+	}
+	token.S3ForceStyle = hostStyle
+	token.S3Protocol = utils.S3Protocol
+	return
+}

+ 8 - 0
services/data/base_edb_lib.go

@@ -67,6 +67,10 @@ func AddEdbData(source int, edbCode string) (resp *models.BaseResponse, err erro
 		urlStr = "national_statistics/add"
 	case utils.DATA_SOURCE_FUBAO:
 		urlStr = "fubao/add"
+	case utils.DATA_SOURCE_GFEX:
+		urlStr = "gz/add"
+	case utils.DATA_SOURCE_ICPI:
+		urlStr = "icpi/add"
 	default:
 		edbSource := data_manage.EdbSourceIdMap[source]
 		if edbSource != nil {
@@ -258,6 +262,10 @@ func RefreshEdbData(edbInfoId, source, subSource int, edbCode, startDate string)
 		urlStr = "national_statistics/refresh"
 	case utils.DATA_SOURCE_FUBAO:
 		urlStr = "fubao/refresh"
+	case utils.DATA_SOURCE_GFEX:
+		urlStr = "gz/refresh"
+	case utils.DATA_SOURCE_ICPI:
+		urlStr = "icpi/refresh"
 	default:
 		edbSource := data_manage.EdbSourceIdMap[source]
 		if edbSource != nil {

+ 531 - 21
services/data/chart_info.go

@@ -325,7 +325,20 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 		}
 
 		extraConfig = tmpExtraConfig
-
+	case utils.CHART_TYPE_RADAR:
+		var barConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
 	default:
 		xEdbIdValue = make([]int, 0)
 		yDataList = make([]data_manage.YData, 0)
@@ -379,8 +392,10 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 		for _, v := range edbList {
 			v.DataList = nil
 		}
+	case utils.CHART_TYPE_RADAR: //雷达图
+		radarConf := extraConfig.(data_manage.RadarChartInfoReq)
+		xEdbIdValue, dataResp, err = RadarChartData(mappingList, edbDataListMap, radarConf)
 	}
-
 	return
 }
 
@@ -450,6 +465,11 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 		item.UniqueCode = v.UniqueCode
 		item.MoveLatestDate = v.LatestDate
 		item.EdbAliasName = v.EdbAliasName
+		item.IsConvert = v.IsConvert
+		item.ConvertType = v.ConvertType
+		item.ConvertValue = v.ConvertValue
+		item.ConvertUnit = v.ConvertUnit
+		item.ConvertEnUnit = v.ConvertEnUnit
 
 		var startDateReal string
 		var diffSeconds int64
@@ -523,6 +543,34 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 		if err != nil {
 			return
 		}
+
+		if v.IsConvert == 1 {
+			switch v.ConvertType {
+			case 1:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value * v.ConvertValue
+				}
+				//item.MaxData = item.MaxData * v.ConvertValue
+				//item.MinData = item.MinData * v.ConvertValue
+			case 2:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value / v.ConvertValue
+				}
+				//item.MaxData = item.MaxData / v.ConvertValue
+				//item.MinData = item.MinData / v.ConvertValue
+			case 3:
+				for i, data := range dataList {
+					if data.Value <= 0 {
+						err = errors.New("数据中含有负数或0,无法对数运算")
+						return
+					}
+					dataList[i].Value = math.Log(data.Value) / math.Log(v.ConvertValue)
+				}
+				//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+				//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+			}
+		}
+
 		edbDataListMap[v.EdbInfoId] = dataList
 
 		if diffSeconds != 0 && v.EdbInfoType == 0 {
@@ -569,7 +617,8 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 				}
 				item.DataList = quarterDataList
 			}
-		} else if chartType == 7 { //柱方图
+
+		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
 			//item.DataList = dataList
 		} else {
 			item.DataList = dataList
@@ -1476,8 +1525,20 @@ func CheckChartExtraConfig(chartType int, extraConfigStr string) (edbIdList []in
 				edbIdList = append(edbIdList, v.YEdbInfoId)
 			}
 		}
+	case utils.CHART_TYPE_RADAR:
+		var extraConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &extraConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
 	}
-
 	return
 }
 
@@ -1860,7 +1921,12 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 
 	chartType := req.ChartType
 	extraConfig := req.ExtraConfig
-
+	var extraConfigEdbInfoIdArr []int
+	extraConfigEdbInfoIdArr, err, errMsg = CheckChartExtraConfig(chartType, extraConfig)
+	if err != nil {
+		err = errors.New("添加失败:" + err.Error())
+		return
+	}
 	// 季节性图表额外配置信息
 	var seasonExtraConfig string
 	// 关联指标
@@ -1936,14 +2002,7 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 			err = errors.New(errMsg)
 			return
 		}
-
-		tmpEdbInfoIdArr, tmpErr, tmpErrMsg := CheckChartExtraConfig(chartType, extraConfig)
-		if err != nil {
-			errMsg = tmpErrMsg
-			err = errors.New("添加失败:" + tmpErr.Error())
-			return
-		}
-		edbInfoIdArr = tmpEdbInfoIdArr
+		edbInfoIdArr = extraConfigEdbInfoIdArr
 		lenEdbInfoIdArr := len(edbInfoIdArr)
 		if lenEdbInfoIdArr > 0 {
 			tmpEdbList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdArr)
@@ -2108,6 +2167,8 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 	chartInfo.Instructions = req.Instructions
 	chartInfo.MarkersLines = req.MarkersLines
 	chartInfo.MarkersAreas = req.MarkersAreas
+	chartInfo.Unit = req.Unit
+	chartInfo.UnitEn = req.UnitEn
 	newId, err := data_manage.AddChartInfo(chartInfo)
 	if err != nil {
 		errMsg = `保存失败`
@@ -2138,6 +2199,11 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 		mapItem.ChartWidth = v.ChartWidth
 		mapItem.Source = utils.CHART_SOURCE_DEFAULT
 		mapItem.EdbAliasName = v.EdbAliasName
+		mapItem.IsConvert = v.IsConvert
+		mapItem.ConvertType = v.ConvertType
+		mapItem.ConvertValue = v.ConvertValue
+		mapItem.ConvertUnit = v.ConvertUnit
+		mapItem.ConvertEnUnit = v.ConvertEnUnit
 		mapList = append(mapList, mapItem)
 	}
 	err = data_manage.AddChartEdbMapping(mapList)
@@ -2218,6 +2284,13 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin) (cha
 		return
 	}
 
+	var extraConfigEdbInfoIdArr []int
+	extraConfigEdbInfoIdArr, err, errMsg = CheckChartExtraConfig(req.ChartType, req.ExtraConfig)
+	if err != nil {
+		err = errors.New("添加失败:" + err.Error())
+		return
+	}
+
 	// 季节性图表额外配置信息
 	var seasonExtraConfig string
 	// 图表关联指标id
@@ -2299,14 +2372,7 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin) (cha
 			return
 		}
 
-		// 校验配置的指标列表
-		tmpEdbInfoIdArr, tmpErr, tmpErrMsg := CheckChartExtraConfig(req.ChartType, req.ExtraConfig)
-		if tmpErr != nil {
-			errMsg = tmpErrMsg
-			err = errors.New("添加失败:" + tmpErr.Error())
-			return
-		}
-		edbInfoIdArr = tmpEdbInfoIdArr
+		edbInfoIdArr = extraConfigEdbInfoIdArr
 		lenEdbInfoIdArr := len(edbInfoIdArr)
 		if lenEdbInfoIdArr > 0 {
 			tmpEdbList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdArr)
@@ -2514,3 +2580,447 @@ func GetEdbSourceByEdbInfoIdList(chartEdbInfoMappingList []*data_manage.ChartEdb
 	}
 	return
 }
+
+// RadarChartData 雷达图的数据处理
+func RadarChartData(mappingList []*data_manage.ChartEdbInfoMapping, edbDataListMap map[int][]*data_manage.EdbDataList, extraConfig data_manage.RadarChartInfoReq) (edbIdList []int, chartDataResp data_manage.RadarChartInfoResp, err error) {
+	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
+	edbDataMap := make(map[int]map[string]float64)
+	for edbInfoId, edbDataList := range edbDataListMap {
+		edbDateData := make(map[string]float64)
+		for _, edbData := range edbDataList {
+			edbDateData[edbData.DataTime] = edbData.Value
+		}
+		edbDataMap[edbInfoId] = edbDateData
+	}
+	// edbIdList 指标展示顺序;x轴的指标顺序
+	edbIdList = make([]int, 0)
+	for _, v := range mappingList {
+		edbIdList = append(edbIdList, v.EdbInfoId)
+	}
+	chartDateList := extraConfig.DateList
+
+	yDataList := make([]data_manage.RadarYData, 0) //y轴的数据列表
+
+	for _, chartDate := range chartDateList {
+		var maxDate time.Time
+
+		findDataList := make([]float64, 0) // 当前日期的数据值
+		for _, edbInfoId := range edbIdList {
+			findDate := chartDate.Date            //需要的日期值
+			dataList := edbDataListMap[edbInfoId] //指标的所有数据值
+			if len(dataList) <= 0 {
+				// 没有数据的指标id
+				findDataList = append(findDataList, 0)
+				continue
+			}
+			switch chartDate.Type {
+			case 1: //最新值
+				findDate = dataList[len(dataList)-1].DataTime
+			case 2: //近期几天
+				findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[len(dataList)-1].DataTime, time.Local)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				findDateTime = findDateTime.AddDate(0, 0, -chartDate.Value)
+
+				lenData := len(dataList) - 1
+				for i := lenData; i >= 0; i-- {
+					currDateTime, e := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
+					if e != nil {
+						err = e
+						return
+					}
+					if currDateTime.Equal(findDateTime) || currDateTime.Before(findDateTime) {
+						findDate = dataList[i].DataTime
+						break
+					}
+				}
+			case 3: // 固定日期
+				//最早的日期
+				minDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				//寻找固定日期的数据
+				findDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, chartDate.Date, time.Local)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				for tmpDateTime := findDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
+					tmpDate := tmpDateTime.Format(utils.FormatDate)
+					if _, ok := edbDataMap[edbInfoId][tmpDate]; ok { //如果能找到数据,那么就返回
+						findDate = tmpDate
+						break
+					}
+				}
+			default:
+				err = errors.New(fmt.Sprint("日期类型异常,Type:", chartDate.Type))
+				return
+			}
+			findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
+			if maxDate.IsZero() {
+				maxDate = findDateTime
+			} else {
+				if findDateTime.After(maxDate) {
+					maxDate = findDateTime
+				}
+			}
+			if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
+				tmpValue, _ = decimal.NewFromFloat(tmpValue).Round(4).Float64()
+				findDataList = append(findDataList, tmpValue)
+			} else {
+				findDataList = append(findDataList, 0)
+			}
+		}
+
+		yDate := "0000-00-00"
+		if !maxDate.IsZero() {
+			yDate = maxDate.Format(utils.FormatDate)
+		}
+		yDataList = append(yDataList, data_manage.RadarYData{
+			Date:  yDate,
+			Value: findDataList,
+			Color: chartDate.Color,
+			Name:  chartDate.Name,
+		})
+	}
+
+	chartDataResp = data_manage.RadarChartInfoResp{
+		YDataList:   yDataList,
+		XEdbIdValue: edbIdList,
+	}
+	return
+}
+
+// GetChartConvertEdbData 获取图表数据转换的指标数据
+func GetChartConvertEdbData(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, extraConfigStr string, seasonExtraConfig string) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, yDataList []data_manage.YData, dataResp interface{}, err error, errMsg string) {
+	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
+	xEdbIdValue = make([]int, 0)
+	yDataList = make([]data_manage.YData, 0)
+
+	var extraConfig interface{}
+	switch chartType {
+	case 7: // 柱形图
+		var barConfig data_manage.BarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "柱方图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "柱方图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	case 10: // 截面散点图
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		extraConfig = tmpExtraConfig
+	case utils.CHART_TYPE_RADAR:
+		var barConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	default:
+		xEdbIdValue = make([]int, 0)
+		yDataList = make([]data_manage.YData, 0)
+	}
+
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err := getEdbConvertDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig)
+	if err != nil {
+		return
+	}
+
+	// 特殊图形数据处理
+	switch chartType {
+	case 7: // 柱形图
+		barChartConf := extraConfig.(data_manage.BarChartInfoReq)
+		xEdbIdValue, yDataList, err = BarChartData(mappingList, edbDataListMap, barChartConf.DateList, barChartConf.Sort)
+
+		for k := range yDataList {
+			yDataList[k].Unit = barChartConf.Unit
+			yDataList[k].UnitEn = barChartConf.UnitEn
+		}
+
+		for _, v := range edbList {
+			// 指标别名
+			if barChartConf.EdbInfoIdList != nil && len(barChartConf.EdbInfoIdList) > 0 {
+				for _, reqEdb := range barChartConf.EdbInfoIdList {
+					if v.EdbInfoId == reqEdb.EdbInfoId {
+						v.EdbAliasName = reqEdb.Name
+					}
+				}
+			}
+		}
+	case 10: // 截面散点图
+		sectionScatterConf := extraConfig.(data_manage.SectionScatterReq)
+		xEdbIdValue, dataResp, err = GetSectionScatterChartData(chartInfoId, mappingList, edbDataListMap, sectionScatterConf)
+
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 这个数据没有必要返回给前端
+		for _, v := range edbList {
+			v.DataList = nil
+		}
+	case utils.CHART_TYPE_RADAR: //雷达图
+		radarConf := extraConfig.(data_manage.RadarChartInfoReq)
+		xEdbIdValue, dataResp, err = RadarChartData(mappingList, edbDataListMap, radarConf)
+	}
+	return
+}
+
+func getEdbConvertDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
+
+	for _, v := range mappingList {
+		//fmt.Println("v:", v.EdbInfoId)
+		item := new(data_manage.ChartEdbInfoMapping)
+		item.EdbInfoId = v.EdbInfoId
+		item.SourceName = v.SourceName
+		item.Source = v.Source
+		item.EdbCode = v.EdbCode
+		item.EdbName = v.EdbName
+		item.EdbNameEn = v.EdbNameEn
+		item.Frequency = v.Frequency
+		item.EdbType = v.EdbType
+		item.FrequencyEn = GetFrequencyEn(v.Frequency)
+		if v.Unit != `无` {
+			item.Unit = v.Unit
+		}
+		item.UnitEn = v.UnitEn
+		item.StartDate = v.StartDate
+		item.EndDate = v.EndDate
+		item.ModifyTime = v.ModifyTime
+		item.EdbInfoCategoryType = v.EdbInfoCategoryType
+		item.PredictChartColor = v.PredictChartColor
+		item.ClassifyId = v.ClassifyId
+		if chartInfoId <= 0 {
+			item.IsAxis = 1
+			item.LeadValue = 0
+			item.LeadUnit = ""
+			item.ChartEdbMappingId = 0
+			item.ChartInfoId = 0
+			item.IsOrder = false
+			item.EdbInfoType = 1
+			item.ChartStyle = ""
+			item.ChartColor = ""
+			item.ChartWidth = 0
+			item.MaxData = v.MaxValue
+			item.MinData = v.MinValue
+		} else {
+			item.IsAxis = v.IsAxis
+			item.EdbInfoType = v.EdbInfoType
+			item.LeadValue = v.LeadValue
+			item.LeadUnit = v.LeadUnit
+			item.LeadUnitEn = GetLeadUnitEn(v.LeadUnit)
+			item.ChartEdbMappingId = v.ChartEdbMappingId
+			item.ChartInfoId = v.ChartInfoId
+			item.ChartStyle = v.ChartStyle
+			item.ChartColor = v.ChartColor
+			item.ChartWidth = v.ChartWidth
+			item.IsOrder = v.IsOrder
+			item.MaxData = v.MaxData
+			item.MinData = v.MinData
+		}
+		item.LatestValue = v.LatestValue
+		item.LatestDate = v.LatestDate
+		item.UniqueCode = v.UniqueCode
+		item.MoveLatestDate = v.LatestDate
+		item.EdbAliasName = v.EdbAliasName
+		item.IsConvert = v.IsConvert
+		item.ConvertType = v.ConvertType
+		item.ConvertValue = v.ConvertValue
+		item.ConvertUnit = v.ConvertUnit
+		item.ConvertEnUnit = v.ConvertEnUnit
+
+		var startDateReal string
+		var diffSeconds int64
+		if chartType == 2 { //季节性图
+			startDateReal = startDate
+		} else {
+			if v.EdbInfoType == 0 && v.LeadUnit != "" && v.LeadValue > 0 { //领先指标
+				var startTimeRealTemp time.Time
+				startDateParse, _ := time.Parse(utils.FormatDate, startDate)
+				switch v.LeadUnit {
+				case "天":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -v.LeadValue)
+				case "月":
+					startTimeRealTemp = startDateParse.AddDate(0, -v.LeadValue, 0)
+				case "季":
+					startTimeRealTemp = startDateParse.AddDate(0, -3*v.LeadValue, 0)
+				case "周":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -7*v.LeadValue)
+				case "年":
+					startTimeRealTemp = startDateParse.AddDate(-v.LeadValue, 0, 0)
+				}
+				if startTimeRealTemp.Before(startDateParse) {
+					startDateReal = startTimeRealTemp.Format(utils.FormatDate)
+					diffSeconds = (int64(startTimeRealTemp.UnixNano()) - int64(startDateParse.UnixNano())) / 1e6
+				} else {
+					startDateReal = startDate
+					diffSeconds = 0
+				}
+
+				// 预测指标的开始日期也要偏移
+				{
+					day, tmpErr := utils.GetDaysBetween2Date(utils.FormatDate, startDate, startDateReal)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					moveLatestDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, item.MoveLatestDate, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					item.MoveLatestDate = moveLatestDateTime.AddDate(0, 0, day).Format(utils.FormatDate)
+				}
+			} else {
+				startDateReal = startDate
+			}
+		}
+		//fmt.Println("line 1011 chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
+		calendarPreYear := 0
+		if calendar == "农历" {
+			newStartDateReal, err := time.Parse(utils.FormatDate, startDateReal)
+			if err != nil {
+				fmt.Println("time.Parse:" + err.Error())
+			}
+			calendarPreYear = newStartDateReal.Year() - 1
+			newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
+			startDateReal = newStartDateReal.Format(utils.FormatDate)
+		}
+		dataList := make([]*data_manage.EdbDataList, 0)
+		//fmt.Println("chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
+		//fmt.Println("calendarPreYear:", calendarPreYear)
+		//var newEdbInfo *data_manage.EdbInfo
+		switch v.EdbInfoCategoryType {
+		case 0:
+			dataList, err = data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, startDateReal, endDate)
+		case 1:
+			_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(v.EdbInfoId, startDateReal, endDate, true)
+		default:
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.EdbInfoCategoryType))
+		}
+		if err != nil {
+			return
+		}
+
+		if v.IsConvert == 1 {
+			switch v.ConvertType {
+			case 1:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value * v.ConvertValue
+				}
+				item.MaxData = item.MaxData * v.ConvertValue
+				item.MinData = item.MinData * v.ConvertValue
+			case 2:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value / v.ConvertValue
+				}
+				item.MaxData = item.MaxData / v.ConvertValue
+				item.MinData = item.MinData / v.ConvertValue
+			case 3:
+				for i, data := range dataList {
+					dataList[i].Value = math.Log(data.Value) / math.Log(v.ConvertValue)
+				}
+				item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+				item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+			}
+		}
+
+		edbDataListMap[v.EdbInfoId] = dataList
+
+		if diffSeconds != 0 && v.EdbInfoType == 0 {
+			dataListLen := len(dataList)
+			for i := 0; i < dataListLen; i++ {
+				dataList[i].DataTimestamp = dataList[i].DataTimestamp - diffSeconds
+			}
+		}
+
+		if chartType == 2 {
+			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
+			if tmpErr != nil {
+				//item.DataList = dataList
+				item.IsNullData = true
+				edbList = append(edbList, item)
+				continue
+				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
+				return
+			}
+
+			if calendar == "农历" {
+				if len(dataList) <= 0 {
+					result := new(data_manage.EdbDataResult)
+					item.DataList = result
+				} else {
+					result, tmpErr := data_manage.AddCalculateQuarterV6(dataList)
+					if tmpErr != nil {
+						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
+						return
+					}
+					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					if tErr != nil {
+						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+						return
+					}
+					item.DataList = quarterDataList
+				}
+
+			} else {
+				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				if tErr != nil {
+					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+					return
+				}
+				item.DataList = quarterDataList
+			}
+
+		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
+			//item.DataList = dataList
+		} else {
+			item.DataList = dataList
+		}
+		edbList = append(edbList, item)
+	}
+
+	return
+}

+ 19 - 3
services/data/chart_theme.go

@@ -49,7 +49,20 @@ func GetThemePreviewChartEdbData(chartType int, calendar, startDate, endDate str
 		}
 
 		extraConfig = tmpExtraConfig
-
+	case utils.CHART_TYPE_RADAR:
+		var barConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
 	default:
 		xEdbIdValue = make([]int, 0)
 		yDataList = make([]data_manage.YData, 0)
@@ -103,8 +116,11 @@ func GetThemePreviewChartEdbData(chartType int, calendar, startDate, endDate str
 		for _, v := range edbList {
 			v.DataList = nil
 		}
-	}
 
+	case utils.CHART_TYPE_RADAR: //雷达图
+		radarConf := extraConfig.(data_manage.RadarChartInfoReq)
+		xEdbIdValue, dataResp, err = RadarChartData(mappingList, edbDataListMap, radarConf)
+	}
 	return
 }
 
@@ -228,7 +244,7 @@ func getThemePreviewEdbDataMapList(chartType int, calendar, startDate, endDate s
 				return
 			}
 			item.DataList = quarterDataList
-		} else if chartType == 7 { //柱方图
+		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
 			//item.DataList = dataList
 		} else {
 			item.DataList = dataList

+ 24 - 38
services/data/edb_data.go

@@ -358,49 +358,35 @@ func GetDateData(edbInfo *data_manage.EdbInfo, startDate, endDate string) (item
 }
 
 // GetEdbBeforeAndAfterDateData 获取指标的单个日期的值
-func GetEdbBeforeAndAfterDateData(edbInfo *data_manage.EdbInfo, startDate, endDate string, dataType, num int) (list []*data_manage.EdbDataList, err error) {
-	var dataList []*data_manage.EdbDataList
-	switch edbInfo.EdbInfoType {
-	case 0:
-		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, startDate, endDate)
-	case 1:
-		_, dataList, _, _, err, _ = GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, startDate, endDate, true)
-	default:
-		err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType))
-
-	}
-	if err != nil {
-		return
-	}
-
+func GetEdbBeforeAndAfterDateData(targetDate string, dataList []*data_manage.EdbDataList) (list []*data_manage.EdbDataList, err error) {
 	lenDataList := len(dataList)
 	if lenDataList <= 0 {
 		return
 	}
-
-	switch dataType {
-	case 1: // 取前面的数据
-		if lenDataList <= 1 { // 如果只有一个,那么也返回,因为自己不算
-			return
-		}
-		if lenDataList <= num {
-			num = lenDataList - 1
-		}
-
-		for i := num; i >= 0; i-- {
-			list = append(list, dataList[lenDataList-1-i])
-		}
-
-	case 2: // 取后面的数据
-		num = num + 1
-		if lenDataList < num {
-			num = lenDataList
-		}
-
-		for i := 0; i < num; i++ {
-			list = append(list, dataList[i])
+	// 数组按照日期从小到大排序
+	maxIndex := lenDataList - 1
+	startIndex := 0
+	endIndex := 0
+	for index, v := range dataList {
+		if v.DataTime == targetDate {
+			if index+2 > maxIndex {
+				endIndex = maxIndex
+			} else if index+1 > maxIndex {
+				endIndex = maxIndex
+			} else {
+				endIndex = index + 2
+			}
+			startIndex = endIndex - 4
+			if startIndex < 0 {
+				startIndex = 0
+			}
+			if endIndex == maxIndex {
+				list = dataList[startIndex:]
+			} else {
+				list = dataList[startIndex : endIndex+1]
+			}
+			break
 		}
 	}
-
 	return
 }

+ 8 - 1
services/data/edb_info.go

@@ -155,6 +155,9 @@ func getEdbInfoIdList(edbInfoIdList []int) (newBaseEdbInfoArr, newBasePredictEdb
 		for _, edbInfo := range tmpBaseEdbInfoArr {
 			if _, ok := newBaseMap[edbInfo.EdbInfoId]; !ok {
 				newBaseMap[edbInfo.EdbInfoId] = edbInfo
+				if edbInfo.NoUpdate == 1 {
+					continue
+				}
 				newBaseEdbInfoArr = append(newBaseEdbInfoArr, edbInfo)
 			}
 		}
@@ -2307,6 +2310,7 @@ func EdbInfoAdd(source, subSource, classifyId int, edbCode, edbName, frequency,
 		utils.DATA_SOURCE_STOCK_PLANT:         "存量装置",
 		utils.DATA_SOURCE_NATIONAL_STATISTICS: "国家统计局",
 		utils.DATA_SOURCE_FUBAO:               "富宝数据",
+		utils.DATA_SOURCE_GFEX:                "广期所",
 	}
 
 	sourceName, ok := sourceNameMap[source]
@@ -2423,6 +2427,7 @@ func TraceEdbInfoByEdbInfoId(edbInfoId int) (traceEdbInfo data_manage.TraceEdbIn
 		//Source:      edbInfo.Source,
 		UniqueCode: edbInfo.UniqueCode,
 		ClassifyId: edbInfo.ClassifyId,
+		IsStop:     edbInfo.NoUpdate,
 		EdbInfo:    edbInfo,
 	}
 	findIdMap := make(map[int]int)
@@ -2471,6 +2476,7 @@ func TraceEdbInfoByEdbInfoIdList(edbInfoIdList []int) (traceEdbInfoList []data_m
 			//Source:      edbInfo.Source,
 			UniqueCode: edbInfo.UniqueCode,
 			ClassifyId: edbInfo.ClassifyId,
+			IsStop:     edbInfo.NoUpdate,
 			EdbInfo:    edbInfo,
 		}
 		traceEdbInfo.Child, err = traceEdbInfoByEdbInfoId(edbInfo.EdbInfoId, traceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)
@@ -2536,11 +2542,12 @@ func traceEdbInfoByEdbInfoId(edbInfoId int, traceEdbInfo data_manage.TraceEdbInf
 			EdbType:     v.FromEdbType,
 			UniqueCode:  v.FromUniqueCode,
 			ClassifyId:  v.FromClassifyId,
+			IsStop:      v.NoUpdate,
 			EdbInfo:     edbInfoMap[v.FromEdbInfoId],
 		}
 
 		// 计算指标/预测指标继续溯源
-		if v.FromEdbType == 2 || v.FromEdbInfoType == 1 {
+		if edbInfoId != v.FromEdbInfoId && (v.FromEdbType == 2 || v.FromEdbInfoType == 1) {
 			// 查过了就不查了
 			if _, ok2 := findIdMap[tmpEdbInfoId]; !ok2 {
 				tmpTraceEdbInfo.Child, e = traceEdbInfoByEdbInfoId(tmpEdbInfoId, tmpTraceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)

+ 638 - 0
services/data/edb_info_refresh.go

@@ -0,0 +1,638 @@
+package data
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/edb_refresh"
+	"eta/eta_api/models/data_manage/edb_refresh/request"
+	"eta/eta_api/utils"
+	"fmt"
+	"strings"
+	"time"
+)
+
+// 所有刷新配置key
+var allDefaultEdbRefreshConfigKey = `edb_refresh_config:default:all:`
+
+// GetAllDefaultEdbRefreshConfigListBySourceList
+// @Description: 获取默认的所有刷新配置列表
+// @author: Roc
+// @datetime 2024-01-10 15:03:36
+// @param source int
+// @param subSource int
+// @return list []*edb_refresh.EdbRefreshDefaultConfig
+// @return err error
+func GetAllDefaultEdbRefreshConfigListBySourceList(source, subSource int) (list []*edb_refresh.EdbRefreshDefaultConfig, err error) {
+	key := getAllDefaultEdbRefreshConfigKey(source, subSource)
+	if utils.Re == nil {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if data, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err = json.Unmarshal(data, &list)
+				return
+			}
+		}
+	}
+
+	list, err = edb_refresh.GetAllListBySourceList(source, subSource)
+	if err != nil {
+		return
+	}
+
+	// 将数据加入缓存
+	if utils.Re == nil {
+		data, _ := json.Marshal(list)
+		utils.Rc.Put(key, data, 2*time.Hour)
+	}
+
+	return
+}
+
+// SaveEdbRefreshDefaultConfig
+// @Description: 设置默认的指标刷新配置接口
+// @author: Roc
+// @datetime 2024-01-10 15:11:19
+// @param source int
+// @param subSource int
+// @param frequency string
+// @param list []request.RefreshConfigReq
+// @return err error
+// @return errMsg string
+// @return isSendEmail bool
+func SaveEdbRefreshDefaultConfig(source, subSource int, frequency string, list []request.RefreshConfigReq) (err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+	errMsg = `保存失败`
+
+	if source <= 0 {
+		errMsg = "来源不能为空"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	// 非有色的来源,频度不能为空
+	if source != utils.DATA_SOURCE_YS && frequency == `` {
+		errMsg = "频度不能为空"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	lenConf := len(list)
+	if lenConf == 0 {
+		errMsg = "至少需要一个刷新配置"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+	if lenConf > 5 {
+		errMsg = "刷新时间设置最多不超过5个"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	tmpArr := []string{"每周", "每旬", "每月", "每季", "每半年", "每年"}
+	// 配置的map,避免同一种类型配置同一个时间
+	configMap := make(map[string]string)
+	for _, v := range list {
+		if utils.InArrayByStr(tmpArr, v.RefreshFrequency) && v.RefreshFrequencyDay < 0 {
+			errMsg = "请选择具体日期"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+
+		if v.RefreshTime == "" {
+			errMsg = "请选择具体时间"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+
+		// 配置的map,避免同一种类型配置同一个时间
+		key := fmt.Sprint(v.RefreshFrequency, "_", v.RefreshFrequencyDay, "_", v.RefreshTime)
+		if _, ok := configMap[key]; ok {
+			errMsg = "刷新频率和日期不能重复"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		configMap[key] = key
+	}
+
+	addList := make([]*edb_refresh.EdbRefreshDefaultConfig, 0)
+	for _, v := range list {
+		addList = append(addList, &edb_refresh.EdbRefreshDefaultConfig{
+			Source:              source,
+			SubSource:           subSource,
+			Frequency:           frequency,
+			RefreshFrequency:    v.RefreshFrequency,
+			RefreshFrequencyDay: v.RefreshFrequencyDay,
+			RefreshAllData:      v.RefreshAllData,
+			RefreshTime:         v.RefreshTime,
+			RefreshDataNum:      v.RefreshDataNum,
+			ModifyTime:          time.Now(),
+			CreateTime:          time.Now(),
+		})
+	}
+
+	// 保存
+	err = edb_refresh.SaveEdbRefreshDefaultConfig(source, subSource, frequency, addList)
+
+	// 清除缓存
+	{
+		key := getAllDefaultEdbRefreshConfigKey(source, subSource)
+		if utils.Re == nil {
+			_ = utils.Rc.Delete(key)
+		}
+	}
+
+	return
+}
+
+// SaveEdbRefreshConfig
+// @Description: 设置指标刷新配置接口
+// @author: Roc
+// @datetime 2024-01-10 15:41:45
+// @param source int
+// @param subSource int
+// @param classifyId string
+// @param terminalCode string
+// @param frequency string
+// @param keyword string
+// @param status string
+// @param sysUserIdStr string
+// @param isSelectAll bool
+// @param list []request.RefreshConfigReq
+// @param edbSelectIdList []int
+// @param sysUserId int
+// @param sysUserRealName string
+// @return err error
+// @return errMsg string
+// @return isSendEmail bool
+func SaveEdbRefreshConfig(source, subSource int, classifyId, terminalCode, frequency, keyword, status, sysUserIdStr string, isSelectAll bool, list []request.RefreshConfigReq, edbSelectIdList []int, sysUserId int, sysUserRealName string) (err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+	errMsg = `保存失败`
+
+	if source <= 0 {
+		errMsg = "来源不能为空"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	lenConf := len(list)
+	if lenConf == 0 {
+		errMsg = "至少需要一个刷新配置"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+	if lenConf > 5 {
+		errMsg = "刷新时间设置最多不超过5个"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	tmpArr := []string{"每周", "每旬", "每月", "每季", "每半年", "每年"}
+
+	// 配置的map,避免同一种类型配置同一个时间
+	configMap := make(map[string]string)
+	for _, v := range list {
+		if utils.InArrayByStr(tmpArr, v.RefreshFrequency) && v.RefreshFrequencyDay < 0 {
+			errMsg = "请选择具体日期"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+
+		if v.RefreshTime == "" {
+			errMsg = "请选择具体时间"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+
+		// 配置的map,避免同一种类型配置同一个时间
+		key := fmt.Sprint(v.RefreshFrequency, "_", v.RefreshFrequencyDay, "_", v.RefreshTime)
+		if _, ok := configMap[key]; ok {
+			errMsg = "刷新频率和日期不能重复"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		configMap[key] = key
+	}
+
+	edbIdList := make([]int, 0)
+	// 指标id列表
+	if isSelectAll {
+		// 如果是列表全选
+		_, edbList, tmpErr := GetList(source, subSource, classifyId, terminalCode, sysUserIdStr, frequency, keyword, status, 0, 100000, "", "")
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			err = tmpErr
+			return
+		}
+
+		// 不配置的指标id
+		notIdMap := make(map[int]int, 0)
+		for _, v := range edbSelectIdList {
+			notIdMap[v] = v
+		}
+
+		for _, v := range edbList {
+			_, ok := notIdMap[v.EdbInfoId]
+			// 在不配置的指标id列表内的话,那就过滤
+			if ok {
+				continue
+			}
+
+			// 加入到待配置的指标列表id
+			edbIdList = append(edbIdList, v.EdbInfoId)
+		}
+	} else {
+		edbIdList = edbSelectIdList
+	}
+
+	if len(edbIdList) <= 0 {
+		errMsg = "指标不能为空"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	// 待添加的配置关系数据
+	addMappingList := make([]*edb_refresh.EdbRefreshMapping, 0)
+
+	// 待添加的日期配置项
+	addConfigList := make([]*edb_refresh.EdbRefreshConfig, 0)
+	for _, v := range list {
+		item, tmpErr := edb_refresh.GetEdbRefreshConfigListByCondition(v.RefreshFrequency, v.RefreshTime, v.RefreshFrequencyDay, v.RefreshAllData, v.RefreshDataNum)
+		if tmpErr != nil {
+			if tmpErr.Error() != utils.ErrNoRow() {
+				err = tmpErr
+				return
+			}
+
+			addConfigList = append(addConfigList, &edb_refresh.EdbRefreshConfig{
+				RefreshFrequency:    v.RefreshFrequency,
+				RefreshFrequencyDay: v.RefreshFrequencyDay,
+				RefreshTime:         v.RefreshTime,
+				RefreshAllData:      v.RefreshAllData,
+				RefreshDataNum:      v.RefreshDataNum,
+				ModifyTime:          time.Now(),
+				CreateTime:          time.Now(),
+			})
+			continue
+		}
+
+		for _, edbId := range edbIdList {
+			addMappingList = append(addMappingList, &edb_refresh.EdbRefreshMapping{
+				EdbRefreshMappingId: 0,
+				Source:              source,
+				SubSource:           subSource,
+				EdbInfoId:           edbId,
+				EdbRefreshConfigId:  item.EdbRefreshConfigId,
+				SysUserId:           sysUserId,
+				SysUserRealName:     sysUserRealName,
+				ModifyTime:          time.Now(),
+				CreateTime:          time.Now(),
+			})
+		}
+	}
+
+	// 保存
+	err = edb_refresh.SaveEdbRefreshConfig(source, subSource, sysUserId, sysUserRealName, addConfigList, addMappingList, edbIdList)
+
+	return
+}
+
+// HandleRefreshTime
+// @Description: 处理刷新时间的显示
+// @author: Roc
+// @datetime 2024-01-10 17:00:03
+// @param source int
+// @param subSource int
+// @param list []*data_manage.BaseRefreshEdbInfo
+// @return newList []*data_manage.BaseRefreshEdbInfo
+// @return err error
+// @return errMsg string
+// @return isSendEmail bool
+func HandleRefreshTime(source, subSource int, list []*data_manage.BaseRefreshEdbInfo) (newList []*data_manage.BaseRefreshEdbInfo, err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+	errMsg = "获取失败"
+	newList = list
+
+	// 默认刷新配置
+	defaultEdbRefreshConfigMap := make(map[string]string)
+	{
+		// 获取默认配置
+		allDefaultEdbRefreshConfigList, tmpErr := GetAllDefaultEdbRefreshConfigListBySourceList(source, subSource)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		defaultEdbRefreshConfigListMap := make(map[string][]string)
+		for _, v := range allDefaultEdbRefreshConfigList {
+			tmp, ok := defaultEdbRefreshConfigListMap[v.Frequency]
+			if !ok {
+				tmp = make([]string, 0)
+			}
+			defaultEdbRefreshConfigListMap[v.Frequency] = append(tmp, GetRefreshStr(v.RefreshFrequency, v.RefreshFrequencyDay, v.RefreshTime))
+		}
+		for k, v := range defaultEdbRefreshConfigListMap {
+			defaultEdbRefreshConfigMap[k] = strings.Join(v, ",")
+		}
+
+	}
+
+	edbInfoIdList := make([]int, 0)
+	for _, v := range newList {
+		edbInfoIdList = append(edbInfoIdList, v.EdbInfoId)
+	}
+
+	// 指标的刷新时间配置
+	edbRefreshConfigMap := make(map[int]string)
+	{
+		// 获取指标的单独配置
+		configList, tmpErr := edb_refresh.GetEdbRefreshConfigAndEdbListBySourceAndeEdbInfoId(source, subSource, edbInfoIdList)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		edbRefreshConfigListMap := make(map[int][]string)
+		for _, v := range configList {
+			tmp, ok := edbRefreshConfigListMap[v.EdbInfoId]
+			if !ok {
+				tmp = make([]string, 0)
+			}
+			edbRefreshConfigListMap[v.EdbInfoId] = append(tmp, GetRefreshStr(v.RefreshFrequency, v.RefreshFrequencyDay, v.RefreshTime))
+		}
+		for k, v := range edbRefreshConfigListMap {
+			edbRefreshConfigMap[k] = strings.Join(v, ",")
+		}
+	}
+
+	// 处理刷新时间
+	for _, v := range newList {
+		refreshTime, ok := edbRefreshConfigMap[v.EdbInfoId]
+		if ok {
+			v.RefreshTime = refreshTime
+			continue
+		}
+		if source == utils.DATA_SOURCE_YS {
+			v.RefreshTime = defaultEdbRefreshConfigMap[``]
+		} else {
+			v.RefreshTime = defaultEdbRefreshConfigMap[v.Frequency]
+		}
+	}
+
+	return
+}
+
+// GetList
+// @Description: 获取指标列表
+// @author: Roc
+// @datetime 2024-01-08 15:14:16
+// @param source int
+// @param subSource int
+// @param classifyId string
+// @param terminalCode string
+// @param sysUserId string
+// @param frequency string
+// @param keyword string
+// @param startSize int
+// @param pageSize int
+// @return total int
+// @return list []*data_manage.BaseRefreshEdbInfo
+// @return err error
+func GetList(source, subSource int, classifyId, terminalCode, sysUserId, frequency, keyword, status string, startSize, pageSize int, sortParam, sortType string) (total int, list []*data_manage.BaseRefreshEdbInfo, err error) {
+	var pars []interface{}
+	var condition string
+
+	list = make([]*data_manage.BaseRefreshEdbInfo, 0)
+
+	isStop := -1
+	if status == `暂停` {
+		isStop = 1
+	} else if status == "启用" {
+		isStop = 0
+	}
+
+	switch source {
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联
+		if classifyId != `` {
+			classifyIdSlice := strings.Split(classifyId, ",")
+			condition += ` AND base_from_mysteel_chemical_classify_id IN (` + utils.GetOrmInReplace(len(classifyIdSlice)) + `)`
+			pars = append(pars, classifyIdSlice)
+		}
+		if terminalCode != `` {
+			condition += " AND terminal_code = ? "
+			pars = append(pars, terminalCode)
+		}
+		if sysUserId != `` {
+			sysUserIdSlice := strings.Split(sysUserId, ",")
+			condition += ` AND sys_user_id IN (` + utils.GetOrmInReplace(len(sysUserIdSlice)) + `)`
+			pars = append(pars, sysUserIdSlice)
+		}
+		if frequency != `` {
+			frequencySlice := strings.Split(frequency, ",")
+			condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencySlice)) + `)`
+			pars = append(pars, frequencySlice)
+		}
+		if keyword != `` {
+			keywordSlice := strings.Split(keyword, " ")
+			if len(keywordSlice) > 0 {
+				tmpConditionSlice := make([]string, 0)
+				tmpConditionSlice = append(tmpConditionSlice, ` index_name like ? or index_code like ? `)
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+
+				for _, v := range keywordSlice {
+					if v == ` ` || v == `` {
+						continue
+					}
+					tmpConditionSlice = append(tmpConditionSlice, ` index_name like ? or index_code like ? `)
+					pars = utils.GetLikeKeywordPars(pars, v, 2)
+				}
+				condition += ` AND (` + strings.Join(tmpConditionSlice, " or ") + `)`
+
+			} else {
+				condition += ` index_name like ? or index_code like ? `
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+			}
+		}
+
+		if isStop >= 0 {
+			condition += " AND is_stop = ? "
+			pars = append(pars, isStop)
+		}
+		sortStr := ``
+		if sortParam != `` {
+			sortStr = fmt.Sprintf("%s %s,base_from_mysteel_chemical_index_id desc ", sortParam, sortType)
+		}
+		total, list, err = data_manage.GetMysteelChemicalBaseInfoList(condition, pars, sortStr, startSize, pageSize)
+	case utils.DATA_SOURCE_YS: // 有色
+		if classifyId != `` {
+			classifyIdSlice := strings.Split(classifyId, ",")
+			condition += ` AND classify_id IN (` + utils.GetOrmInReplace(len(classifyIdSlice)) + `)`
+			pars = append(pars, classifyIdSlice)
+		}
+		if terminalCode != `` {
+			condition += " AND terminal_code = ? "
+			pars = append(pars, terminalCode)
+		}
+		if frequency != `` {
+			frequencySlice := strings.Split(frequency, ",")
+			condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencySlice)) + `)`
+			pars = append(pars, frequencySlice)
+		}
+		if keyword != `` {
+			keywordSlice := strings.Split(keyword, " ")
+			if len(keywordSlice) > 0 {
+				tmpConditionSlice := make([]string, 0)
+				tmpConditionSlice = append(tmpConditionSlice, ` index_name like ? or index_code like ? `)
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+
+				for _, v := range keywordSlice {
+					if v == ` ` || v == `` {
+						continue
+					}
+					tmpConditionSlice = append(tmpConditionSlice, ` index_name like ? or index_code like ? `)
+					pars = utils.GetLikeKeywordPars(pars, v, 2)
+				}
+				condition += ` AND (` + strings.Join(tmpConditionSlice, " or ") + `)`
+
+			} else {
+				condition += ` index_name like ? or index_code like ? `
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+			}
+		}
+
+		if isStop >= 0 {
+			condition += " AND is_stop = ? "
+			pars = append(pars, isStop)
+		}
+
+		sortStr := ``
+		if sortParam != `` {
+			sortStr = fmt.Sprintf("%s %s,base_from_smm_index_id desc ", sortParam, sortType)
+		}
+
+		total, list, err = data_manage.GetSmmBaseInfoList(condition, pars, sortStr, startSize, pageSize)
+	default:
+		condition += ` AND source = ? AND sub_source = ? `
+		pars = append(pars, source, subSource)
+
+		if isStop >= 0 {
+			condition += " AND no_update = ? "
+			pars = append(pars, isStop)
+		}
+
+		if classifyId != `` {
+			classifyIdSlice := strings.Split(classifyId, ",")
+			condition += ` AND classify_id IN (` + utils.GetOrmInReplace(len(classifyIdSlice)) + `)`
+			pars = append(pars, classifyIdSlice)
+		}
+		if terminalCode != `` {
+			condition += " AND terminal_code = ? "
+			pars = append(pars, terminalCode)
+		}
+		if sysUserId != `` {
+			sysUserIdSlice := strings.Split(sysUserId, ",")
+			condition += ` AND sys_user_id IN (` + utils.GetOrmInReplace(len(sysUserIdSlice)) + `)`
+			pars = append(pars, sysUserIdSlice)
+		}
+		if frequency != `` {
+			frequencySlice := strings.Split(frequency, ",")
+			condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencySlice)) + `)`
+			pars = append(pars, frequencySlice)
+		}
+		if keyword != `` {
+			keywordSlice := strings.Split(keyword, " ")
+			if len(keywordSlice) > 0 {
+				tmpConditionSlice := make([]string, 0)
+				tmpConditionSlice = append(tmpConditionSlice, ` edb_name like ? or edb_code like ? `)
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+
+				for _, v := range keywordSlice {
+					if v == ` ` || v == `` {
+						continue
+					}
+					tmpConditionSlice = append(tmpConditionSlice, ` edb_name like ? or edb_code like ? `)
+					pars = utils.GetLikeKeywordPars(pars, v, 2)
+				}
+				condition += ` AND (` + strings.Join(tmpConditionSlice, " or ") + `)`
+
+			} else {
+				condition += ` edb_name like ? or edb_code like ? `
+				pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+			}
+		}
+
+		sortStr := ``
+		if sortParam != `` {
+			sortStr = fmt.Sprintf("%s %s,edb_info_id desc ", sortParam, sortType)
+		}
+
+		total, list, err = data_manage.GetEdbBaseInfoList(condition, pars, sortStr, startSize, pageSize)
+	}
+
+	return
+}
+
+// getAllDefaultEdbRefreshConfigKey
+// @Description: 获取默认的所有刷新配置key
+// @author: Roc
+// @datetime 2024-01-10 15:02:49
+// @param source int
+// @param subSource int
+// @return string
+func getAllDefaultEdbRefreshConfigKey(source, subSource int) string {
+	return allDefaultEdbRefreshConfigKey + fmt.Sprintf("%d_%d", source, subSource)
+}
+
+// GetRefreshStr
+// @Description: 获取刷新配置的中文字符串
+// @author: Roc
+// @datetime 2024-01-10 16:05:10
+// @param refreshFrequency string
+// @param refreshFrequencyDay int
+// @param refreshTime string
+// @return string
+func GetRefreshStr(refreshFrequency string, refreshFrequencyDay int, refreshTime string) string {
+	refreshDayStr := ``
+	//if refreshFrequency != "每自然日" && refreshFrequency != "每交易日"
+	switch refreshFrequency {
+	case "每自然日", "每交易日":
+	case "每周":
+		switch refreshFrequencyDay {
+		case 0:
+			refreshDayStr = "日"
+		case 1:
+			refreshDayStr = "一"
+		case 2:
+			refreshDayStr = "二"
+		case 3:
+			refreshDayStr = "三"
+		case 4:
+			refreshDayStr = "四"
+		case 5:
+			refreshDayStr = "五"
+		case 6:
+			refreshDayStr = "六"
+		case 7:
+			refreshDayStr = "日"
+		}
+	default:
+		if refreshFrequencyDay > 0 {
+			refreshDayStr = fmt.Sprintf("第%d天", refreshFrequencyDay)
+		} else {
+			refreshDayStr = `最后一天`
+		}
+	}
+	return refreshFrequency + refreshDayStr + " " + refreshTime
+}

+ 429 - 0
services/data/excel/excel_classify.go

@@ -0,0 +1,429 @@
+package excel
+
+import (
+	"errors"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/excel"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/utils"
+	"time"
+)
+
+func GetExcelClassifyMaxSort(parentId int, source int) (maxSort int, err error) {
+	//获取该层级下最大的排序数
+	maxSort, err = excel.GetExcelClassifyMaxSort(parentId, source)
+	if err != nil {
+		return
+	}
+	edbMaxSort, err := excel.GetExcelMaxSortByClassifyId(parentId, source)
+	if err != nil {
+		return
+	}
+	if maxSort < edbMaxSort {
+		maxSort = edbMaxSort
+	}
+	return
+}
+
+// MoveExcelClassify 移动指标分类
+func MoveExcelClassify(req request.MoveExcelClassifyReq) (err error, errMsg string) {
+	classifyId := req.ClassifyId
+	parentClassifyId := req.ParentClassifyId
+	prevClassifyId := req.PrevClassifyId
+	nextClassifyId := req.NextClassifyId
+
+	excelInfoId := req.ExcelInfoId
+	prevExcelInfoId := req.PrevExcelInfoId
+	nextExcelInfoId := req.NextExcelInfoId
+	source := req.Source
+	//首先确定移动的对象是分类还是指标
+	//判断上一个节点是分类还是指标
+	//判断下一个节点是分类还是指标
+	//同时更新分类目录下的分类sort和指标sort
+	//更新当前移动的分类或者指标sort
+
+	var parentExcelClassifyInfo *excel.ExcelClassify
+	if parentClassifyId > 0 {
+		parentExcelClassifyInfo, err = excel.GetExcelClassifyById(parentClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上级分类信息失败,Err:" + err.Error())
+			return
+		}
+	}
+
+	//如果有传入 上一个兄弟节点分类id
+	var (
+		excelClassifyInfo *excel.ExcelClassify
+		prevClassify      *excel.ExcelClassify
+		nextClassify      *excel.ExcelClassify
+
+		excelInfo     *excel.ExcelInfo
+		prevExcelInfo *excel.ExcelInfo
+		nextExcelInfo *excel.ExcelInfo
+		prevSort      int
+		nextSort      int
+	)
+
+	// 移动对象为分类, 判断权限
+	if excelInfoId == 0 {
+		excelClassifyInfo, err = excel.GetExcelClassifyById(classifyId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前分类不存在"
+				err = errors.New("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+
+	} else {
+		excelInfo, err = excel.GetExcelInfoById(excelInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前表格不存在"
+				err = errors.New("获取分类信息失败,Err:" + err.Error())
+				return
+			}
+			errMsg = "移动失败"
+			err = errors.New("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+		if parentClassifyId == 0 {
+			errMsg = "移动失败,表格必须挂在分类下"
+			err = errors.New(errMsg)
+			return
+		}
+	}
+
+	if prevClassifyId > 0 {
+		prevClassify, err = excel.GetExcelClassifyById(prevClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevClassify.Sort
+	} else if prevExcelInfoId > 0 {
+		prevExcelInfo, err = excel.GetExcelInfoById(prevExcelInfoId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevExcelInfo.Sort
+	}
+
+	if nextClassifyId > 0 {
+		//下一个兄弟节点
+		nextClassify, err = excel.GetExcelClassifyById(nextClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextClassify.Sort
+	} else if nextExcelInfoId > 0 {
+		//下一个兄弟节点
+		nextExcelInfo, err = excel.GetExcelInfoById(nextExcelInfoId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextExcelInfo.Sort
+	}
+
+	err, errMsg = moveExcelClassify(parentExcelClassifyInfo, excelClassifyInfo, prevClassify, nextClassify, excelInfo, prevExcelInfo, nextExcelInfo, parentClassifyId, prevSort, nextSort, source)
+	return
+}
+
+// moveExcelClassify 移动表格分类
+func moveExcelClassify(parentExcelClassifyInfo, excelClassifyInfo, prevClassify, nextClassify *excel.ExcelClassify, excelInfo, prevExcelInfo, nextExcelInfo *excel.ExcelInfo, parentClassifyId int, prevSort, nextSort int, source int) (err error, errMsg string) {
+	updateCol := make([]string, 0)
+
+	// 移动对象为分类, 判断分类是否存在
+	if excelClassifyInfo != nil {
+		oldParentId := excelClassifyInfo.ParentId
+		/*oldLevel := excelClassifyInfo.Level
+		var classifyIds []int*/
+		if oldParentId != parentClassifyId {
+			//todo 更新子分类对应的level
+			/*childList, e, m := GetChildClassifyByClassifyId(excelClassifyInfo.ClassifyId)
+			if e != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询子分类失败,Err:" + e.Error() + m)
+				return
+			}
+
+			if len(childList) > 0 {
+				for _, v := range childList {
+					if v.ClassifyId == excelClassifyInfo.ClassifyId {
+						continue
+					}
+					classifyIds = append(classifyIds, v.ClassifyId)
+				}
+			}*/
+		}
+		//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+		if excelClassifyInfo.ParentId != parentClassifyId && parentClassifyId != 0 {
+			if excelClassifyInfo.Level != parentExcelClassifyInfo.Level+1 { //禁止层级调整
+				errMsg = "移动失败"
+				err = errors.New("不支持目录层级变更")
+				return
+			}
+			excelClassifyInfo.ParentId = parentExcelClassifyInfo.ExcelClassifyId
+			excelClassifyInfo.Level = parentExcelClassifyInfo.Level + 1
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+		} else if excelClassifyInfo.ParentId != parentClassifyId && parentClassifyId == 0 {
+			errMsg = "移动失败"
+			err = errors.New("不支持目录层级变更")
+			return
+		}
+
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == excelClassifyInfo.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+					}
+
+					//变更表格
+					if prevExcelInfo != nil {
+						//变更兄弟节点的排序
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+
+						//变更分类
+						if prevClassify != nil {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevSort, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+						}
+
+						//变更表格
+						if prevExcelInfo != nil {
+							//变更兄弟节点的排序
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+						}
+
+					}
+				}
+			}
+
+			excelClassifyInfo.Sort = prevSort + 1
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevExcelInfo == nil && nextExcelInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetExcelClassifyMaxSort(parentClassifyId, source)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			excelClassifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级分类的第一位
+			firstClassify, tmpErr := data_manage.GetFirstEdbClassifyByParentId(parentClassifyId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, firstClassify.ClassifyId-1, 0, updateSortStr, source)
+				//该分类下的所有表格也需要+1
+				_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr, source)
+			} else {
+				//如果该分类下存在表格,且第一个表格的排序等于0,那么需要调整排序
+				firstExcel, tErr := excel.GetFirstExcelInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstExcel != nil && firstExcel.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, firstExcel.ExcelInfoId-1, updateSortStr, source)
+					_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, source)
+				}
+			}
+
+			excelClassifyInfo.Sort = 0 //那就是排在第一位
+			excelClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = excelClassifyInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+			//更新对应分类的root_id和层级
+			if oldParentId != parentClassifyId {
+				/*if len(classifyIds) > 0 {
+					levelStep := excelClassifyInfo.Level - oldLevel
+					err = data_manage.UpdateEdbClassifyChildByParentClassifyId(classifyIds, excelClassifyInfo.RootId, levelStep)
+					if err != nil {
+						errMsg = "移动失败"
+						err = errors.New("更新子分类失败,Err:" + err.Error())
+						return
+					}
+				}*/
+			}
+		}
+	} else {
+		if excelInfo == nil {
+			errMsg = "当前表格不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		//如果改变了分类,那么移动该表格数据
+		if excelInfo.ExcelClassifyId != parentClassifyId {
+			excelInfo.ExcelClassifyId = parentClassifyId
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ExcelClassifyId", "ModifyTime")
+		}
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == excelInfo.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevClassify.Sort, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+					}
+
+					//变更表格
+					if prevExcelInfo != nil {
+						//变更兄弟节点的排序
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+					} else {
+						_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						//变更分类
+						if prevClassify != nil {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, prevClassify.ExcelClassifyId, prevSort, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, source)
+						}
+
+						//变更表格
+						if prevExcelInfo != nil {
+							//变更兄弟节点的排序
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, prevExcelInfo.ExcelInfoId, updateSortStr, source)
+						} else {
+							_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr, source)
+						}
+					}
+				}
+			}
+
+			excelInfo.Sort = prevSort + 1
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevExcelInfo == nil && nextExcelInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetExcelClassifyMaxSort(parentClassifyId, source)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			excelInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else {
+			// 拖动到父级分类的第一位
+			firstClassify, tmpErr := excel.GetFirstExcelClassifyByParentId(parentClassifyId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "移动失败"
+				err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+				return
+			}
+
+			//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+			if firstClassify != nil && firstClassify.Sort == 0 {
+				updateSortStr := ` sort + 1 `
+				_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, firstClassify.ExcelClassifyId-1, 0, updateSortStr, source)
+				//该分类下的所有表格也需要+1
+				_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr, source)
+			} else {
+				//如果该分类下存在表格,且第一个表格的排序等于0,那么需要调整排序
+				firstExcel, tErr := excel.GetFirstExcelInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstExcel != nil && firstExcel.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = excel.UpdateExcelInfoSortByClassifyId(parentClassifyId, 0, firstExcel.ExcelInfoId-1, updateSortStr, source)
+					_ = excel.UpdateExcelClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, source)
+				}
+			}
+
+			excelInfo.Sort = 0 //那就是排在第一位
+			excelInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = excelInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+	return
+}

+ 15 - 4
services/data/excel/excel_op.go

@@ -262,14 +262,25 @@ func UpdateExcelInfoFileUrl(excelInfo *excelModel.ExcelInfo) {
 
 	var resourceUrl string
 	//上传到阿里云
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = services.UploadImgToMinIo(fileName, downloadFilePath)
-	} else {
-		resourceUrl, err = services.UploadAliyunV2(fileName, downloadFilePath)
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = services.UploadImgToMinIo(fileName, downloadFilePath)
+	//} else {
+	//	resourceUrl, err = services.UploadAliyunV2(fileName, downloadFilePath)
+	//}
+	//if err != nil {
+	//	return
+	//}
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
 	}
+	resourceUrl, err = ossClient.UploadFile(fileName, downloadFilePath, "")
 	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
 		return
 	}
+
 	excelInfo.FileUrl = resourceUrl
 	err = excelInfo.Update([]string{"FileUrl"})
 }

+ 519 - 67
services/data/excel/mixed_table.go

@@ -73,7 +73,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	// 日度指标数据map
 	edbDayDataListMap := make(map[int]map[string]float64)
 	// 月度指标数据map
-	edbMonthDataListMap := make(map[int]map[string]float64)
+	edbMonthDataListMap := make(map[int]map[string]string)
 	// 日度指标数据map
 	edbDataListMap := make(map[int][]*data_manage.EdbDataList)
 	for _, edbInfo := range edbInfoList {
@@ -90,18 +90,19 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 		}
 
 		dateValMap := make(map[string]float64)
-		monthValMap := make(map[string]float64)
+		monthDateMap := make(map[string]string)
 		for _, tmpData := range dataList {
 			// 日度数据
 			dateValMap[tmpData.DataTime] = tmpData.Value
 			// 月度数据(取该月份的第一个数据)
 			yearMonth := strings.Join(strings.Split(tmpData.DataTime, "-")[0:2], "-")
-			if _, ok := monthValMap[yearMonth]; !ok {
-				monthValMap[yearMonth] = tmpData.Value
+			if _, ok := monthDateMap[yearMonth]; !ok {
+				// 存最早的时间
+				monthDateMap[yearMonth] = tmpData.DataTime
 			}
 		}
 		edbDayDataListMap[edbInfo.EdbInfoId] = dateValMap
-		edbMonthDataListMap[edbInfo.EdbInfoId] = monthValMap
+		edbMonthDataListMap[edbInfo.EdbInfoId] = monthDateMap
 		edbDataListMap[edbInfo.EdbInfoId] = dataList
 	}
 
@@ -119,9 +120,19 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				if err != nil {
 					return
 				}
-				if edbInfo, ok := edbInfoMap[edbDateConfig.EdbInfoId]; ok {
-					cell.ShowValue = edbInfo.EndDate
-					cell.DataTime = edbInfo.EndDate
+				if dataList, ok := edbDataListMap[edbDateConfig.EdbInfoId]; ok {
+					// todo 获取配置信息,根据配置信息进行日期变换, 是否需要更新当前记录,将历史记录逐渐转换成新的记录
+					var newDate string
+					newDate, err = GetEdbDateByMoveForward(config[k][i].Value, dataList)
+					if err != nil {
+						return
+					}
+					newDate, err = HandleMixTableDateChange(newDate, config[k][i].Value)
+					if err != nil {
+						return
+					}
+					cell.ShowValue = newDate
+					cell.DataTime = newDate
 					config[k][i] = cell
 				}
 			}
@@ -133,7 +144,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	}
 
 	// 指标计算的结果map
-	edbSourceDataMap := make(map[string]map[string]float64)
+	edbSourceDataMap := make(map[string]data.BaseCalculateDataResp)
 
 	// 单元格对应的key与他的值(只处理数据类型)
 	cellKeyVal := make(map[string]float64)
@@ -141,6 +152,8 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 	// 基础计算单元格的位置信息
 	calculateCellMap := make(map[string]Cell)
 	calculateChainList := make([]string, 0)
+	dateCalculateList := make([]string, 0)
+	showStyleList := make([]string, 0)
 
 	// 处理单元格中的数据类型(除去基础计算,因为这个是依赖于其他)
 	for k, row := range config {
@@ -160,7 +173,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				//cell.Value = ``
 
 				// 日期关系配置不存在,则默认最新数据
-				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok {
+				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok { //表示表格日期
 					if relationConf.RelationDate.Key == `` {
 						// 日期关系配置未绑定
 						continue
@@ -178,11 +191,21 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 					if dateValMap, ok := edbDayDataListMap[cell.EdbInfoId]; ok {
 						tmpDateValMap = dateValMap
 					}
+					// todo 根据配置进行日期变换
+					relationDate := relationCell.DataTime
+					if strings.Contains(cell.Value, "{") {
+						relationDate, err = HandleMixTableDateChange(relationDate, cell.Value)
+						if err != nil {
+							return
+						}
+					} else {
+						cell.Value = ""
+					}
 
-					if val, ok2 := tmpDateValMap[relationCell.DataTime]; ok2 {
+					if val, ok2 := tmpDateValMap[relationDate]; ok2 {
 						//cell.ShowValue = fmt.Sprint(val)
 						cellKeyVal[cell.Uid] = val
-						cell.ShowValue = utils.FormatTableDataShowValue(val)
+						cell.ShowValue = utils.FormatMixTableDataShowValue(val)
 					}
 				} else {
 					// 如果不是取得一个关联的日期,那么就是指定日期
@@ -192,38 +215,67 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 						if dateValList, ok := edbDataListMap[cell.EdbInfoId]; ok {
 							tmpLenData := len(dateValList)
 							if tmpLenData > 0 {
-								cellKeyVal[cell.Uid] = dateValList[tmpLenData-1].Value
-								cell.ShowValue = utils.FormatTableDataShowValue(dateValList[tmpLenData-1].Value)
+								//做期数前移动和日期变换
+								if !strings.Contains(cell.Value, "{") {
+									cell.Value = ""
+								}
+								var newDate string
+								newDate, err = GetEdbDateByMoveForward(cell.Value, dateValList)
+								if err != nil {
+									return
+								}
+								newDate, err = HandleMixTableDateChange(newDate, cell.Value)
+								if err != nil {
+									return
+								}
+								var finalVal string
+								for _, v := range dateValList {
+									if v.DataTime == newDate {
+										finalVal = utils.FormatMixTableDataShowValue(v.Value)
+										cellKeyVal[cell.Uid] = v.Value
+										break
+									}
+								}
+
+								cell.ShowValue = finalVal
 							}
 						}
 					} else {
 						tmpDateList := strings.Split(cell.DataTime, "-")
 						tmpDateValMap := make(map[string]float64)
+						var newDate string
 						if len(tmpDateList) == 2 {
 							//月度数据
-							if dateValMap, ok := edbMonthDataListMap[cell.EdbInfoId]; ok {
-								tmpDateValMap = dateValMap
+							if dateMap, ok1 := edbMonthDataListMap[cell.EdbInfoId]; ok1 {
+								if d, ok2 := dateMap[cell.DataTime]; ok2 {
+									newDate = d
+								}
 							}
 						} else {
 							// 日度数据
-							if dateValMap, ok := edbDayDataListMap[cell.EdbInfoId]; ok {
-								tmpDateValMap = dateValMap
-							}
+							newDate = cell.DataTime
+						}
+						// 日期变换后才能确定最后的时间
+						//做期数前移动和日期变换
+						if !strings.Contains(cell.Value, "{") {
+							cell.Value = ""
+						}
 
+						newDate, err = HandleMixTableDateChange(newDate, cell.Value)
+						if err != nil {
+							return
 						}
-						if val, ok2 := tmpDateValMap[cell.DataTime]; ok2 {
-							//cell.ShowValue = fmt.Sprint(val)
-							cellKeyVal[cell.Uid] = val
-							cell.ShowValue = utils.FormatTableDataShowValue(val)
+
+						if dateValMap, ok3 := edbDayDataListMap[cell.EdbInfoId]; ok3 {
+							tmpDateValMap = dateValMap
+							if val, ok2 := tmpDateValMap[cell.DataTime]; ok2 {
+								//cell.ShowValue = fmt.Sprint(val)
+								cellKeyVal[cell.Uid] = val
+								cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+							}
 						}
 					}
 				}
-
-				calculateCellMap[cell.Uid] = Cell{
-					Column:   k,
-					Row:      i,
-					CellInfo: cell,
-				}
 			case request.CustomTextDT: //自定义文本
 				if cell.Value == `` {
 					continue
@@ -233,27 +285,21 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				if tmpErr == nil {
 					tmpVal, _ := tmpDeci.Float64()
 					cellKeyVal[cell.Uid] = tmpVal
-
-					calculateCellMap[cell.Uid] = Cell{
-						Column:   k,
-						Row:      i,
-						CellInfo: cell,
-					}
 				}
 
 			case request.FormulateCalculateDataDT: // 公式计算(A+B这种)
-				calculateCellMap[cell.Uid] = Cell{
-					Column:   k,
-					Row:      i,
-					CellInfo: cell,
-				}
-
 				calculateChainList = append(calculateChainList, cell.Uid)
 
 			case request.InsertEdbCalculateDataDT: // 插入指标系统计算公式生成的值
+				// 处理value的值
+				if !strings.Contains(cell.Value, "EdbInfoId") && cell.EdbInfoId > 0 {
+					cell.Value, _ = fixCalculateValueConfig(cell.Value, cell.EdbInfoId)
+					row[i] = cell
+				}
 				// 日期
 				var cellDateTime string
 				// 日期关系配置不存在,则默认最新数据
+				// 从绑定的单元格中获取数据的日期
 				if relationConf, ok := cellRelationConfMap[cell.Uid]; ok {
 					if relationConf.RelationDate.Key == `` {
 						// 日期关系配置未绑定
@@ -271,7 +317,7 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 				var tmpDataMap map[string]float64
 
 				key := utils.MD5(cell.Value)
-				tmpDataMap, ok := edbSourceDataMap[key]
+				respItemData, ok := edbSourceDataMap[key]
 				if !ok {
 					// 对应的配置值
 					var tmpConfig request.CalculateConf
@@ -318,22 +364,59 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 						continue
 					}
 
-					tmpDataMap = respItem.Data.DataMap
+					//tmpDataMap = respItem.Data.DataMap
 					// 计算结果存一份,万一存在重复的计算方式,那么省的重新计算一下
-					edbSourceDataMap[key] = tmpDataMap
-
-					lenDataList := len(respItem.Data.DateList)
-					if cellDateTime == `` && lenDataList > 0 {
-						cellDateTime = respItem.Data.DateList[lenDataList-1]
+					edbSourceDataMap[key] = respItem.Data
+					respItemData = respItem.Data
+				}
+				lenDataList := len(respItemData.DateList)
+				tmpDataMap = respItemData.DataMap
+				if cellDateTime == `` && lenDataList > 0 {
+					//判断是否需要做期数前移动
+					cellDateTime = respItemData.DateList[lenDataList-1]
+					cellDateTime, err = GetEdbDateByMoveForwardByDateList(cell.Value, respItemData.DateList)
+					if err != nil {
+						utils.FileLog.Error(fmt.Sprintf("日期前移失败,配置信息;%s", cell.Value))
+						continue
 					}
 				}
+				// 进行日期变换
+				cellDateTime, err = HandleMixTableDateChange(cellDateTime, cell.Value)
+				if err != nil {
+					utils.FileLog.Error(fmt.Sprintf("日期变换失败,配置信息;%s, 日期:%s", cell.Value, cellDateTime))
+					continue
+				}
+				val, ok := tmpDataMap[cellDateTime]
+				if ok {
+					cellKeyVal[cell.Uid] = val
+					cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+				} else {
+					cell.ShowValue = ""
+				}
 
-				val := tmpDataMap[cellDateTime]
-				cellKeyVal[cell.Uid] = val
-				cell.ShowValue = utils.FormatTableDataShowValue(val)
+			case request.DateCalculateDataDT: //日期计算
+				dateCalculateList = append(dateCalculateList, cell.Uid)
+				// 遍历数组,根据公式进行计算,并将得到的结果放到对应的单元格中
 			}
+			row[i] = cell
+		}
+		config[k] = row
+	}
 
+	// 处理指定指标的日期
+	for k, row := range config {
+		for i, cell := range row {
+			calculateCellMap[cell.Uid] = Cell{
+				Column:   k,
+				Row:      i,
+				CellInfo: cell,
+			}
+			cell.ShowFormatValue = cell.ShowValue
+			if cell.ShowStyle != `` {
+				showStyleList = append(showStyleList, cell.Uid)
+			}
 			row[i] = cell
+			cellDataRelationMap[cell.Uid] = cell
 		}
 		config[k] = row
 	}
@@ -364,12 +447,24 @@ func GetMixedTableCellData(mixedTableReq request.MixedTableReq) (newMixedTableCe
 			}
 
 			cellKeyVal[cell.Uid] = val
-			cell.ShowValue = utils.FormatTableDataShowValue(val)
+			cell.ShowValue = utils.FormatMixTableDataShowValue(val)
 			config[cellPosition.Column][cellPosition.Row] = cell
 
 		}
 	}
 
+	// 日期计算
+	config, err, errMsg = handlerDateCalculate(dateCalculateList, calculateCellMap, config)
+	if err != nil {
+		return
+	}
+
+	// 格式化展示
+	config, err, errMsg = handleMixCellShowStyle(showStyleList, calculateCellMap, config)
+	if err != nil {
+		return
+	}
+
 	newMixedTableCellDataList = config
 
 	return
@@ -475,11 +570,15 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 				if err != nil {
 					return
 				}
-				edbInfoIdList = append(edbInfoIdList, config.EdbInfoId)
+				if config.EdbInfoId == 0 && cell.EdbInfoId > 0 {
+					edbInfoIdList = append(edbInfoIdList, cell.EdbInfoId)
+				} else {
+					edbInfoIdList = append(edbInfoIdList, config.EdbInfoId)
+				}
 				dataEdbInfoIdList = append(dataEdbInfoIdList, cell.EdbInfoId)
 
 			case request.DateDT: // 日期类型
-				date, tmpErr, tmpErrMsg := handleDate(cell.DataTimeType, cell.Value)
+				date, newVal, tmpErr, tmpErrMsg := handleDate(cell.DataTimeType, cell.Value)
 				if tmpErr != nil {
 					err = tmpErr
 					errMsg = tmpErrMsg
@@ -487,6 +586,7 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 				}
 				rowList[rk].DataTime = date
 				rowList[rk].ShowValue = date
+				rowList[rk].Value = newVal //兼容原有的历史数据中系统导入日期
 
 				// 指标日期类型的单元格需要额外将指标id取出来
 				if cell.DataTimeType == request.EdbDateDT {
@@ -516,7 +616,7 @@ func handleConfig(configList [][]request.MixedTableCellDataReq) (newConfig [][]r
 // @return date string
 // @return err error
 // @return errMsg string
-func HandleDate(dataTimeType int, val string) (date string, err error, errMsg string) {
+func HandleDate(dataTimeType int, val string) (date string, newVal string, err error, errMsg string) {
 	return handleDate(dataTimeType, val)
 }
 
@@ -529,17 +629,39 @@ func HandleDate(dataTimeType int, val string) (date string, err error, errMsg st
 // @return date string
 // @return err error
 // @return errMsg string
-func handleDate(dataTimeType int, val string) (date string, err error, errMsg string) {
+func handleDate(dataTimeType int, val string) (date string, newVal string, err error, errMsg string) {
+	newVal = val
 	if val == `` {
 		errMsg = "错误的日期数据"
 		err = errors.New(errMsg)
 		return
 	}
+
 	switch dataTimeType {
 	case request.CustomDateT: //手动输入日期
+		/*if !strings.Contains(val, "{") {
+			newVal, err, errMsg = handleOldCustomerDateT(val)
+			if err != nil {
+				return
+			}
+		}
+		date, err = HandleMixTableDateChange("", newVal)
+		if err != nil {
+			return
+		}*/
 		date = val
+		return
 	case request.SystemDateT: // 系统日期
-		date, err, errMsg = handleSystemDateT(val)
+		date = time.Now().Format(utils.FormatDate)
+		newVal, err, errMsg = handleOldSystemDateT(val)
+		if err != nil {
+			return
+		}
+		date, err = HandleMixTableDateChange(date, newVal)
+		if err != nil {
+			return
+		}
+
 	case request.EdbDateDT: // 导入指标日期(指标库的最新日期)
 	default:
 		errMsg = "错误的日期类型"
@@ -550,30 +672,134 @@ func handleDate(dataTimeType int, val string) (date string, err error, errMsg st
 	return
 }
 
-// handleSystemDateT
-// @Description: 处理导入系统日期
+func GetEdbDateByMoveForward(conf string, edbDataList []*data_manage.EdbDataList) (date string, err error) {
+	dateList := make([]string, 0)
+	for _, v := range edbDataList {
+		dateList = append(dateList, v.DataTime)
+	}
+
+	date, err = GetEdbDateByMoveForwardByDateList(conf, dateList)
+	return
+}
+
+func GetEdbDateByMoveForwardByDateList(conf string, dateList []string) (date string, err error) {
+	moveForward := 0
+	if conf != "" {
+		var edbDateConf request.EdbDateChangeConf
+		err = json.Unmarshal([]byte(conf), &edbDateConf)
+		if err != nil {
+			err = fmt.Errorf("日期变换配置json解析失败失败: %s", err.Error())
+			return
+		}
+		moveForward = edbDateConf.MoveForward
+	}
+	// 根据日期进行排序
+	index := len(dateList) - 1 - moveForward
+	for k, v := range dateList {
+		if k == index {
+			date = v
+			return
+		}
+	}
+	return
+}
+
+// HandleMixTableDateChange 处理表格中的日期变换
+func HandleMixTableDateChange(date, conf string) (newDate string, err error) {
+	newDate = date
+	if conf == "" {
+		return
+	}
+	var edbDateConf request.EdbDateConf
+	err = json.Unmarshal([]byte(conf), &edbDateConf)
+	if err != nil {
+		err = fmt.Errorf("日期变换配置json解析失败失败: %s, Err:%s", conf, err.Error())
+		return
+	}
+
+	if newDate != "" {
+		if len(edbDateConf.DateChange) > 0 {
+			var dateTime time.Time
+			dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+			if err != nil {
+				err = fmt.Errorf("日期解析失败: %s", err.Error())
+				return
+			}
+			for _, v := range edbDateConf.DateChange {
+				if v.ChangeType == 1 {
+					dateTime = dateTime.AddDate(v.Year, v.Month, v.Day)
+					newDate = dateTime.Format(utils.FormatDate)
+				} else if v.ChangeType == 2 {
+					newDate, err, _ = handleSystemAppointDateT(dateTime, v.FrequencyDay, v.Frequency)
+					if err != nil {
+						return
+					}
+					dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+					if err != nil {
+						err = fmt.Errorf("日期解析失败: %s", err.Error())
+						return
+					}
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// handleOldSystemDateT
+// @Description: 历史数据中的导入系统日期
 // @author: Roc
 // @datetime2023-10-27 09:36:21
 // @param confStr string
 // @return date string
 // @return err error
 // @return errMsg string
-func handleSystemDateT(confStr string) (date string, err error, errMsg string) {
+func handleOldSystemDateT(confStr string) (newConf string, err error, errMsg string) {
+	newConf = confStr
 	var config request.SystemDateConf
 	err = json.Unmarshal([]byte(confStr), &config)
 	if err != nil {
 		return
 	}
+
+	newConfig := new(request.EdbDateConf)
+	dateChange := new(request.EdbDateConfDateChange)
+
+	dateChangeList := make([]*request.EdbDateConfDateChange, 0)
+
 	switch config.Source {
 	case request.SystemCurrDateT:
-		date = time.Now().Format(utils.FormatDate)
+		return
 	case request.SystemCalculateDateT:
-		date, err, errMsg = handleSystemCalculateDateT(config.CalculateNum, config.CalculateFrequency)
+		// todo 是否直接更新该excel记录,
+		dateChange.Day = config.CalculateNum
+		dateChange.ChangeType = 1
+		dateChangeList = append(dateChangeList, dateChange)
+		newConfig.DateChange = dateChangeList
+		newConfByte, e := json.Marshal(newConfig)
+		if e != nil {
+			err = fmt.Errorf("日期计算额外配置,json序列化失败: %s", e.Error())
+			return
+		}
+		newConf = string(newConfByte)
+		return
 	case request.SystemFrequencyDateT: // 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
-		date, err, errMsg = handleSystemAppointDateT(config.Day, config.Frequency)
+		dateChange.FrequencyDay = config.Day
+		dateChange.Frequency = config.Frequency
+		dateChange.ChangeType = 1
+		dateChangeList = append(dateChangeList, dateChange)
+		newConfig.DateChange = dateChangeList
+		newConfByte, e := json.Marshal(newConfig)
+		if e != nil {
+			err = fmt.Errorf("日期计算额外配置,json序列化失败: %s", e.Error())
+			return
+		}
+		newConf = string(newConfByte)
+		return
 	default:
-		errMsg = "错误的日期日期导入方式"
-		err = errors.New(fmt.Sprint("错误的日期日期导入方式:", config.Source))
+		//errMsg = "错误的日期日期导入方式"
+		//err = errors.New(fmt.Sprint("错误的日期日期导入方式:", config.Source))
 		return
 	}
 
@@ -615,8 +841,8 @@ func handleSystemCalculateDateT(num int, frequency string) (date string, err err
 // @return date string
 // @return err error
 // @return errMsg string
-func handleSystemAppointDateT(appointDay, frequency string) (date string, err error, errMsg string) {
-	currDate := time.Now()
+func handleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) {
+	//currDate := time.Now()
 	switch frequency {
 	case "本周":
 		day := int(currDate.Weekday())
@@ -813,3 +1039,229 @@ func calculateByCellList(calculateFormula string, tagList []utils.CellPosition)
 
 	return
 }
+
+// handlerDateCalculate 处理日期计算
+func handlerDateCalculate(dateCalculateList []string, calculateCellMap map[string]Cell, oldConfig [][]request.MixedTableCellDataReq) (config [][]request.MixedTableCellDataReq, err error, errMsg string) {
+	config = oldConfig
+	if len(dateCalculateList) == 0 {
+		return
+	}
+	if len(dateCalculateList) > 0 {
+		for _, cellKey := range dateCalculateList {
+			// 查找这个单元格的位置,直接map找了,而不是遍历整个单元格
+			cellPosition, ok := calculateCellMap[cellKey]
+			if !ok {
+				utils.FileLog.Error("找不到单元格位置:", cellKey)
+				continue
+			}
+
+			cell := config[cellPosition.Column][cellPosition.Row]
+			if cell.DataType != request.DateCalculateDataDT { // 判断公式计算(A+B这种)类型,不是的话也过滤了
+				continue
+			}
+
+			val, tmpErr, tmpErrMsg := DateCalculatePrepare(calculateCellMap, cell.Value)
+			if tmpErr != nil {
+				errMsg = tmpErrMsg
+				err = tmpErr
+				return
+			}
+
+			cell.ShowValue = utils.FormatMixTableDataShowValue(val)
+			config[cellPosition.Column][cellPosition.Row] = cell
+		}
+	}
+	return
+}
+
+// DateCalculatePrepare 单个单元格的日期计算
+func DateCalculatePrepare(calculateCellMap map[string]Cell, config string) (val float64, err error, errMsg string) {
+	var edbDateConf request.MixDateCalculateConf
+	err = json.Unmarshal([]byte(config), &edbDateConf)
+	if err != nil {
+		err = fmt.Errorf("日期计算配置json解析失败失败: %s, Err:%s", config, err.Error())
+		return
+	}
+	if len(edbDateConf.RelationCellList) == 0 {
+		err = fmt.Errorf("日期计算 未配置日期单元格失败: %s", config)
+		return
+	}
+	valMap := make(map[string]int)
+	for _, v := range edbDateConf.RelationCellList {
+		// 查找单元格数据
+		cell, ok := calculateCellMap[v.Uid]
+		if !ok {
+			err = fmt.Errorf("查找单元格:%s 的数据失败", v.Uid)
+			return
+		}
+		colData := cell.CellInfo
+
+		// 如果不是基础计算单元格,直接返回
+		_, err = time.ParseInLocation(utils.FormatDate, colData.ShowValue, time.Local)
+		if err != nil {
+			err = fmt.Errorf("%s 的单元格非日期类型, Err: %s", colData.ShowValue, err.Error())
+			return
+		}
+		// todo 把日期转换成excel里的天数
+		realDiffDay := utils.GetDaysDiff1900(colData.ShowValue)
+
+		valMap[strings.ToUpper(v.Tag)] = realDiffDay
+	}
+
+	// 计算
+	val, errMsg, err = DateCalculateFormula(valMap, strings.ToUpper(edbDateConf.Formula))
+	if err != nil {
+		return
+	}
+	return
+}
+
+func DateCalculateFormula(valTagMap map[string]int, calculateFormula string) (calVal float64, errMsg string, err error) {
+	if calculateFormula == "" {
+		errMsg = "公式异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	calculateFormula = strings.TrimPrefix(calculateFormula, "=")
+	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
+	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
+	calculateFormula = strings.Replace(calculateFormula, ",", ",", -1)
+	calculateFormula = strings.Replace(calculateFormula, "。", ".", -1)
+	calculateFormula = strings.Replace(calculateFormula, "%", "*0.01", -1)
+
+	formulaFormStr := utils.ReplaceFormulaByTagMap(valTagMap, calculateFormula)
+
+	if formulaFormStr == `` {
+		errMsg = "公式异常"
+		err = errors.New(errMsg)
+		return
+	}
+	fmt.Println("公式:" + formulaFormStr)
+	expression := formula.NewExpression(formulaFormStr)
+	calResult, err := expression.Evaluate()
+	if err != nil {
+		errMsg = "公式错误,请重新填写"
+		err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
+		// 分母为0的报错
+		if strings.Contains(err.Error(), "divide by zero") {
+			errMsg = "分母不能为0"
+			err = errors.New("分母不能为空,计算公式:" + formulaFormStr)
+		}
+		return
+	}
+	// 如果计算结果是NAN,那么就提示报错
+	if calResult.IsNan() {
+		errMsg = "公式错误,请重新填写"
+		err = errors.New("计算失败:计算结果是:NAN;formulaStr:" + formulaFormStr)
+		return
+	}
+	calVal, err = calResult.Float64()
+	if err != nil {
+		return
+	}
+
+	// 转Decimal然后四舍五入
+	calVal, _ = decimal.NewFromFloat(calVal).Round(4).Float64()
+
+	return
+}
+
+// handleMixCellShowStyle 处理混合表格中,显示计算的逻辑
+func handleMixCellShowStyle(showStyleList []string, calculateCellMap map[string]Cell, oldConfig [][]request.MixedTableCellDataReq) (config [][]request.MixedTableCellDataReq, err error, errMsg string) {
+	config = oldConfig
+	if len(showStyleList) == 0 {
+		return
+	}
+	if len(showStyleList) > 0 {
+		for _, cellKey := range showStyleList {
+			// 查找这个单元格的位置,直接map找了,而不是遍历整个单元格
+			cellPosition, ok := calculateCellMap[cellKey]
+			if !ok {
+				utils.FileLog.Error("找不到单元格位置:", cellKey)
+				continue
+			}
+
+			cell := config[cellPosition.Column][cellPosition.Row]
+			val := cell.ShowValue
+			isPercent := false
+			if strings.Contains(val, "%") {
+				isPercent = true
+				val = strings.Trim(val, "%")
+			}
+			_, e := strconv.ParseFloat(val, 64) // 将字符串转换成float类型
+			if e != nil {                       // 如果没有错误发生则返回true,说明该字符串是一个合法的数字
+				continue
+			}
+			var styleConf request.MixCellShowStyle
+			err = json.Unmarshal([]byte(cell.ShowStyle), &styleConf)
+			if err != nil {
+				err = fmt.Errorf("日期计算配置json解析失败失败: %s, Err:%s", config, err.Error())
+				return
+			}
+			if styleConf.Pn != 0 || styleConf.Nt != "" {
+				val = changePointDecimalPlaces(val, styleConf.Pn, styleConf.Nt, isPercent)
+				cell.ShowFormatValue = val
+			} else {
+				cell.ShowFormatValue = cell.ShowValue
+			}
+			config[cellPosition.Column][cellPosition.Row] = cell
+		}
+	}
+	return
+}
+
+// changePointDecimalPlaces 小数点位数加减和百分比格式
+func changePointDecimalPlaces(str string, changeNum int, numberType string, isPercent bool) (newStr string) {
+	newStr = str
+	// 把字符串转成浮点数
+	val, _ := strconv.ParseFloat(str, 64)
+	if isPercent {
+		if numberType == "number" { //百分数转成小数
+			val = val / 100
+			isPercent = false
+		}
+	} else {
+		if numberType == "percent" {
+			val = val * 100
+		}
+	}
+	newStr = fmt.Sprintf("%v", val)
+	var decimalPlaces int                  // 计算小数位数
+	dotIndex := strings.Index(newStr, ".") // 查找小数点的位置
+	if dotIndex == -1 {
+		decimalPlaces = 0
+	} else {
+		decimalPlaces = len(newStr) - dotIndex - 1
+	}
+	decimalPlaces += changeNum
+
+	if decimalPlaces < 0 {
+		decimalPlaces = 0
+	}
+	val, _ = decimal.NewFromFloat(val).Round(int32(decimalPlaces)).Float64()
+	newStr = strconv.FormatFloat(val, 'f', decimalPlaces, 64)
+	if numberType == "percent" || isPercent {
+		newStr += "%"
+	}
+	return
+}
+
+func fixCalculateValueConfig(conf string, edbInfoId int) (newConf string, err error) {
+	newConf = conf
+	if edbInfoId == 0 {
+		return
+	}
+	var tmpConfig request.CalculateConf
+	err = json.Unmarshal([]byte(conf), &tmpConfig)
+	if err != nil {
+		return
+	}
+	if tmpConfig.EdbInfoId == 0 {
+		tmpConfig.EdbInfoId = edbInfoId
+		newConfByte, _ := json.Marshal(tmpConfig)
+		newConf = string(newConfByte)
+		return
+	}
+	return
+}

+ 4 - 3
services/data/future_good/chart_info.go

@@ -480,8 +480,9 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 			//	err = tmpErr
 			//	return
 			//}
-			tmpRealDateTime := findDateTime
-			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][findDateTime.Format(utils.FormatDate)]
+			//tmpRealDateTime := findDateTime	// 按照配置找到的日期
+			tmpRealDateTime := realDateTime // 实际现货的日期
+			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
 			yDataMap[futureGoodMapping.FutureGoodEdbInfoId] = tmpFindDataValue
 
 			findDataList = append(findDataList, tmpFindDataValue)
@@ -547,7 +548,7 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 
 		yDataList = append(yDataList, data_manage.YData{
 			Date:           yDate,
-			ConfigDate:     findDateTime,
+			ConfigDate:     realDateTime,
 			Value:          findDataList,
 			NoDataEdbList:  noDataIdList,
 			XEdbInfoIdList: xEdbInfoIdList,

+ 1 - 1
services/data/future_good/profit_chart_info.go

@@ -384,7 +384,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 
 		yDataList = append(yDataList, data_manage.YData{
 			Date:           yDate,
-			ConfigDate:     findDateTime,
+			ConfigDate:     realDateTime,
 			Value:          findDataList,
 			NoDataEdbList:  noDataIdList,
 			XEdbInfoIdList: xEdbInfoIdList,

+ 225 - 0
services/email.go

@@ -0,0 +1,225 @@
+package services
+
+import (
+	"eta/eta_api/models"
+	"eta/eta_api/utils"
+	"fmt"
+	"strings"
+)
+
+func SendEmailToCompany() {
+	// 获取收件人列表
+	//emailCond := " AND enabled = 1 "
+	emailCond := ""
+	emailPars := make([]interface{}, 0)
+	emails, e := models.GetEnglishReportEmailList(emailCond, emailPars, "")
+	if e != nil {
+		fmt.Println("获取收件人列表失败, Err: " + e.Error())
+		return
+	}
+	if len(emails) == 0 {
+		fmt.Println("收件人列表为空")
+		return
+	}
+
+	// TODO:这是HTML模板内容
+	template := `<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,viewport-fit=cover">
+    <title>Horizon Insights x Fastmarkets x FGE: 2024 Macro & Commodities Outlook - Registration Open!</title>
+</head>
+
+<body style="padding:0;margin:0;background-color:#fff">
+<div id="app" style="max-width:1280px;margin:0 auto;font-size:14px;min-height:100vh;">
+    <div class="main-box" style="padding:25px 20px;">
+        <div style="line-height:1.7;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;"
+            class=" __aliyun_node_has_color">
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:center;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="font-size:18.0px;font-weight:bold;font-style:normal;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;color:#000000;text-decoration:underline;"
+                    class=" __aliyun_node_has_color">2024 Macro &amp; Commodities Outlook Invite</span></div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;"
+                    class=" __aliyun_node_has_color"><br></span></div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;"
+                    class=" __aliyun_node_has_color">Dear Client,</span></div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;"
+                    class=" __aliyun_node_has_color"><br></span></div>
+            <div style="clear:both;">
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;"
+                        class=" __aliyun_node_has_color">Happy Year-End Holidays!</span></div>
+            </div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;"
+                    class=" __aliyun_node_has_color"><br></span></div>
+            <div style="clear:both;">
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;border:.0px;font-family:arial;margin:.0px;padding:.0px;outline:.0px;font-size:13.0px;"
+                        class=" __aliyun_node_has_color">As we usher in the new year, Horizon Insights, in collaboration
+                        with Fastmarkets and FGE, is proud to announce</span><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;font-family:arial;font-size:13.0px;"
+                        class=" __aliyun_node_has_color">&nbsp;our 2024 Macro &amp; Commodities Outlook which will be
+                        held&nbsp;</span><span
+                        style="font-weight:bold;color:#000000;font-style:normal;text-transform:none;font-family:arial;font-size:13.0px;text-decoration:none;"
+                        class=" __aliyun_node_has_color">virtually</span><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;font-family:arial;font-size:13.0px;text-decoration:none;"
+                        class=" __aliyun_node_has_color">&nbsp;on&nbsp;</span><span
+                        style="font-weight:bold;color:#000000;font-style:normal;text-transform:none;font-family:arial;font-size:13.0px;text-decoration:none;"
+                        class=" __aliyun_node_has_color">10 &amp; 11 Jan 2024</span><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;font-family:arial;font-size:13.0px;"
+                        class=" __aliyun_node_has_color">,&nbsp;</span><span
+                        style="color:#000000;font-family:arial;font-size:13.0px;font-style:normal;font-weight:bold;text-transform:none;"
+                        class=" __aliyun_node_has_color">5pm - 8pm SGT</span><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;font-family:arial;font-size:13.0px;"
+                        class=" __aliyun_node_has_color">&nbsp;(i.e.&nbsp;</span><span
+                        style="color:#000000;font-family:arial;font-size:13.0px;font-style:normal;font-weight:bold;text-transform:none;"
+                        class=" __aliyun_node_has_color">9am - 12pm BST</span><span
+                        style="color:#000000;font-style:normal;font-weight:400;text-transform:none;font-family:arial;font-size:13.0px;"
+                        class=" __aliyun_node_has_color">). Our experienced analysts from Horizon Insights together with
+                        guest speakers from our valued partners will present our views in the fields of Macro, Ferrous
+                        Metals, Base Metals, Energy, as well as Petrochemicals.</span></div>
+            </div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-size:13.0px;font-family:arial;"><br></span>
+            </div>
+            <div style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-size:13.0px;font-family:arial;">Please
+                    see below for our event schedule:</span></div>
+            <div
+                style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;">
+                <br></div>
+            <div
+                style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;">
+                <span
+                    style="color:#000000;font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-size:13.0px;font-family:arial;"
+                    class=" __aliyun_node_has_color">&nbsp;&nbsp;<img style="vertical-align: bottom; margin: 0px;"
+                        height="3301"
+                        src="https://hzstatic.hzinsights.com/static/images/202312/20231228/KeDTAxIZ3UrZR5DZKKIQLdoIaOVB.png"
+                        width="890"></span></div>
+            <div
+                style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;">
+                <span
+                    style="color:#000000;font-style:normal;font-weight:400;text-transform:none;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-size:13.0px;font-family:arial;"
+                    class=" __aliyun_node_has_color">&nbsp; &nbsp;</span></div>
+            <div
+                style="clear:both;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-variant-ligatures:normal;font-variant-caps:normal;text-align:start;text-indent:.0px;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;">
+                <br></div>
+            <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;"><br></span>
+            </div>
+            <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;">To
+                    register, simply scan the QR code in the posters above to indicate your interest. Alternatively, you
+                    may also&nbsp;</span><span
+                    style="font-weight:bold;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;"><a
+                        href="https://forms.gle/yhPRDcri43P2QyPt8" target="_blank">register here</a></span><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;">.</span>
+            </div>
+            <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                class=" __aliyun_node_has_color"><span
+                    style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;color:#000000;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline;"
+                    class=" __aliyun_node_has_color">Should you encounter any difficulties registering, please contact
+                    Stephanie (stephanie@hzinsights.com).</span></div>
+            <div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="font-weight:bold;margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;">The
+                        virtual meeting details will be disseminated to you a few days prior to the event.</span></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><br></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;">Lastly,
+                        our firm would like to wish all of you a prosperous Happy New Year! We look forward to seeing
+                        everyone on the 10th &amp; 11th.</span></div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;"><br></span>
+                </div>
+                <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;color:#000000;font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;text-align:start;text-indent:.0px;text-transform:none;text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;clear:both;"
+                    class=" __aliyun_node_has_color"><span
+                        style="margin:.0px;padding:.0px;border:.0px;outline:.0px;font-family:arial;font-size:13.0px;">Cheers!</span>
+                </div>
+            </div>
+            <div><br></div>
+            <div>
+                <div style="clear:both;"><span style="font-family:arial;font-size:13.0px;color:#000000;"
+                        class=" __aliyun_node_has_color"><br></span></div>
+                <div style="clear:both;">
+                    <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;clear:both;font-variant-caps:normal;text-align:start;text-indent:.0px;"
+                        class="x___aliyun_node_has_color"><br></div>
+                    <div style="margin:.0px;padding:.0px;border:.0px;outline:.0px;clear:both;font-variant-caps:normal;text-align:start;text-indent:.0px;"
+                        class="x___aliyun_node_has_color"></div>
+                </div>
+            </div>
+            <div><br></div>
+            <div><br></div>
+            <div><br></div>
+            <div style="line-height:20.0px;clear:both;"><br></div>
+        </div>
+    </div>
+</div>
+</body>
+
+</html>`
+
+	// 推送信息
+	sendData := make([]*EnglishReportSendEmailRequest, 0)
+	for i := range emails {
+		r := new(EnglishReportSendEmailRequest)
+		r.EmailId = emails[i].Id
+		r.Email = strings.Replace(emails[i].Email, " ", "", -1)
+		r.Subject = "Horizon Insights x Fastmarkets x FGE: 2024 Macro & Commodities Outlook - Registration Open!" // TODO:这是主题
+		r.FromAlias = "Horizon FICC"                                                                              // TODO:这是推送人(中文)
+
+		r.HtmlBody = template
+		sendData = append(sendData, r)
+	}
+	if len(sendData) == 0 {
+		fmt.Println("无邮件可推送")
+		return
+	}
+
+	// 请求阿里云接口批量推送
+	aliEmail := new(AliyunEmail)
+	resultList, e := aliEmail.BatchSendEmail(sendData)
+	if e != nil {
+		fmt.Println("批量推送失败, Err: " + e.Error())
+		return
+	}
+	for _, r := range resultList {
+		utils.FileLog.Info("email: %s, ok: %v, res: %s", r.Email, r.Ok, r.ResultData)
+		if r.Ok {
+			fmt.Println("发送成功")
+		} else {
+			fmt.Println("发送失败:" + r.ResultData)
+		}
+	}
+}

+ 3 - 3
services/english_policy_report.go

@@ -2,11 +2,11 @@ package services
 
 import (
 	"encoding/json"
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/http"
 	"eta/eta_api/models"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/http"
 	"time"
 )
 
@@ -165,7 +165,7 @@ func getOriginPolicyReportList() (list []EnPolicyReportDataListItem, err error)
 	mode := "all"
 	startDt := ""
 	// 获取当天的报告
-	startDt = time.Now().Format(utils.FormatDate)
+	startDt = time.Now().AddDate(0, 0, -7).Format(utils.FormatDate)
 	//设置接口地址
 	//处理返回值
 	url := utils.EnPolicyReportUrl + `articles/index?type_id=%d&field_id=%d&take=%d&skip=%d&publish_status=%s&mode=%s&start_dt=%s`

+ 1 - 1
services/excel_info.go

@@ -52,7 +52,7 @@ func UpdateExcelEditMark(excelInfoId, nowUserId, status int, nowUserName string)
 		if opUserId > 0 {
 			utils.Rc.Do("SETEX", key, int64(300), string(bt)) //3分钟缓存
 		} else {
-			utils.Rc.SetNX(key, string(bt), time.Second*60*5) //3分钟缓存
+			utils.Rc.SetNX(key, string(bt), time.Second*60*3) //3分钟缓存
 		}
 	} else if status == 0 {
 		//清除编辑缓存

+ 23 - 12
services/file.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"eta/eta_api/models"
 	"eta/eta_api/utils"
+	"fmt"
 	"io"
 	"mime/multipart"
 	"os"
@@ -29,18 +30,28 @@ func UploadToOssAndFileName(fileMulti multipart.File, newFileName string) (resou
 	}
 
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		resourceUrl, err = UploadImgToMinIo(newFileName, fpath)
-		if err != nil {
-			err = errors.New("文件上传失败,Err:" + err.Error())
-			return
-		}
-	} else {
-		resourceUrl, err = UploadAliyunV2(newFileName, fpath)
-		if err != nil {
-			err = errors.New("文件上传失败,Err:" + err.Error())
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	resourceUrl, err = UploadImgToMinIo(newFileName, fpath)
+	//	if err != nil {
+	//		err = errors.New("文件上传失败,Err:" + err.Error())
+	//		return
+	//	}
+	//} else {
+	//	resourceUrl, err = UploadAliyunV2(newFileName, fpath)
+	//	if err != nil {
+	//		err = errors.New("文件上传失败,Err:" + err.Error())
+	//		return
+	//	}
+	//}
+	ossClient := NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(newFileName, fpath, "")
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
 
 	defer func() {

+ 399 - 290
services/minio.go

@@ -7,163 +7,402 @@ import (
 	"github.com/minio/minio-go/v7"
 	"github.com/minio/minio-go/v7/pkg/credentials"
 	"log"
-	"os"
 	"time"
 )
 
-func GetMinIOSTSToken() (item *Token, err error) {
-	// MinIO服务的访问信息
-	item = new(Token)
-	//useSSL := false
-	//if utils.MinIoUseSSL == "true" {
-	//	useSSL = true
-	//}
-	// 创建MinIO客户端
-	//minioClient, err := minio.New(utils.MinIoEndpoint, &minio.Options{
-	//	Creds:  credentials.NewStaticV4(utils.MinIoAccessKeyId, utils.MinIoAccessKeySecret, ""),
-	//	Secure: useSSL,
-	//})
-	//if err != nil {
-	//	return nil, err
-	//}
-	// 设置STS凭证请求参数
-	//policy := `{
-	//    "Version": "2012-10-17",
-	//    "Statement": [
-	//        {
-	//            "Sid": "",
-	//            "Effect": "Allow",
-	//            "Principal": {"AWS": "arn:aws:iam::1234567890:root"},
-	//            "Action": "s3:GetObject",
-	//            "Resource": "arn:aws:s3:::<YourBucketName>/*"
-	//        }
-	//    ]
-	//}`
-	//expiry := time.Hour * 24 // STS凭证的过期时间
-	//获取STS凭证
-	//stsCredentials, err := minioClient.PresignedPutObject(context.Background(), "etastatic", "myobject", expiry)
-	//if err != nil {
-	//	return
-	//}
-	item.AccessKeyId = utils.MinIoAccessKeyId
-	item.SecretKeyId = utils.MinIoAccessKeySecret
-	item.Endpoint = utils.MinIoEndpoint
-	item.ImgHost = utils.MinIoImghost
-	item.Bucketname = utils.MinIoBucketname
-	item.UseSSL = utils.MinIoUseSSL
-	item.RegionId = utils.MinIoRegion
-	item.Port = utils.MinIoPort
-	return
-}
+//func GetMinIOSTSToken() (item *Token, err error) {
+//	// MinIO服务的访问信息
+//	item = new(Token)
+//	//useSSL := false
+//	//if utils.MinIoUseSSL == "true" {
+//	//	useSSL = true
+//	//}
+//	// 创建MinIO客户端
+//	//minioClient, err := minio.New(utils.MinIoEndpoint, &minio.Options{
+//	//	Creds:  credentials.NewStaticV4(utils.MinIoAccessKeyId, utils.MinIoAccessKeySecret, ""),
+//	//	Secure: useSSL,
+//	//})
+//	//if err != nil {
+//	//	return nil, err
+//	//}
+//	// 设置STS凭证请求参数
+//	//policy := `{
+//	//    "Version": "2012-10-17",
+//	//    "Statement": [
+//	//        {
+//	//            "Sid": "",
+//	//            "Effect": "Allow",
+//	//            "Principal": {"AWS": "arn:aws:iam::1234567890:root"},
+//	//            "Action": "s3:GetObject",
+//	//            "Resource": "arn:aws:s3:::<YourBucketName>/*"
+//	//        }
+//	//    ]
+//	//}`
+//	//expiry := time.Hour * 24 // STS凭证的过期时间
+//	//获取STS凭证
+//	//stsCredentials, err := minioClient.PresignedPutObject(context.Background(), "etastatic", "myobject", expiry)
+//	//if err != nil {
+//	//	return
+//	//}
+//	item.AccessKeyId = utils.MinIoAccessKeyId
+//	item.SecretKeyId = utils.MinIoAccessKeySecret
+//	item.Endpoint = utils.MinIoEndpoint
+//	item.ImgHost = utils.MinIoImghost
+//	item.Bucketname = utils.MinIoBucketname
+//	item.UseSSL = utils.MinIoUseSSL
+//	item.RegionId = utils.MinIoRegion
+//	item.Port = utils.MinIoPort
+//	return
+//}
 
-type Token struct {
-	AccessKeyId string
-	SecretKeyId string
-	RegionId    string
-	Bucketname  string
-	Endpoint    string
-	ImgHost     string
-	UseSSL      string
-	Port        string
-}
+//type Token struct {
+//	AccessKeyId string
+//	SecretKeyId string
+//	RegionId    string
+//	Bucketname  string
+//	Endpoint    string
+//	ImgHost     string
+//	UseSSL      string
+//	Port        string
+//}
 
-func UploadMinIo() {
-	ctx := context.Background()
-	endpoint := "8.136.199.33:9000/"
-	accessKeyID := "LfQ8uiJiLP7vLxjRrmNW"
-	secretAccessKey := "IszGVHsNicJMQxHC46cYFtbrOiapo0ynwOIJ6c2R"
-	useSSL := false
+//func UploadMinIo() {
+//	ctx := context.Background()
+//	endpoint := "8.136.199.33:9000/"
+//	accessKeyID := "LfQ8uiJiLP7vLxjRrmNW"
+//	secretAccessKey := "IszGVHsNicJMQxHC46cYFtbrOiapo0ynwOIJ6c2R"
+//	useSSL := false
+//
+//	// Initialize minio client object.
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//	}
+//
+//	// Make a new bucket called mymusic.
+//	bucketName := "etastatic"
+//	location := "/"
+//
+//	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
+//	if err != nil {
+//		// Check to see if we already own this bucket (which happens if you run this twice)
+//		exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//		if errBucketExists == nil && exists {
+//			log.Printf("We already own %s\n", bucketName)
+//		} else {
+//			log.Fatalln(err)
+//		}
+//	} else {
+//		log.Printf("Successfully created %s\n", bucketName)
+//	}
+//	//buckets, err := minioClient.ListBuckets(ctx)
+//	//for _, bucket := range buckets {
+//	//	fmt.Println(bucket)
+//	//}
+//	// Upload the zip file
+//	objectName := "1111.xlsx"
+//	filePath := "/Users/xi/Desktop/1111.xlsx"
+//	contentType := "application/xlsx"
+//
+//	// Upload the zip file with FPutObject
+//	info, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})
+//	if err != nil {
+//		log.Fatalln(err)
+//	}
+//
+//	log.Printf("Successfully uploaded %s of size %d\n", objectName, info.Size)
+//}
 
-	// Initialize minio client object.
-	minioClient, err := minio.New(endpoint, &minio.Options{
-		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
-		Secure: useSSL,
-	})
-	if err != nil {
-		log.Fatalln(err)
-	}
+// UploadImgToMinIo 图片上传
+//func UploadImgToMinIo(fileName, filePath string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	path := utils.MinIoUploadDir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
 
-	// Make a new bucket called mymusic.
-	bucketName := "etastatic"
-	location := "/"
+// UploadAudioToMinIo 音频上传
+//func UploadAudioToMinIo(fileName, filePath string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//
+//	path := utils.MinIoUpload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
 
-	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
-	if err != nil {
-		// Check to see if we already own this bucket (which happens if you run this twice)
-		exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-		if errBucketExists == nil && exists {
-			log.Printf("We already own %s\n", bucketName)
-		} else {
-			log.Fatalln(err)
-		}
-	} else {
-		log.Printf("Successfully created %s\n", bucketName)
-	}
-	//buckets, err := minioClient.ListBuckets(ctx)
-	//for _, bucket := range buckets {
-	//	fmt.Println(bucket)
-	//}
-	// Upload the zip file
-	objectName := "1111.xlsx"
-	filePath := "/Users/xi/Desktop/1111.xlsx"
-	contentType := "application/xlsx"
+// UploadVideoToMinIo 视频上传
+//func UploadVideoToMinIo(filename, filePath, savePath string) error {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return errors.New("MinIo信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filePath)
+//	}()
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return err
+//	}
+//
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
 
-	// Upload the zip file with FPutObject
-	info, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})
-	if err != nil {
-		log.Fatalln(err)
-	}
+// UploadFileToMinIo 上传文件
+//func UploadFileToMinIo(filename, filePath, savePath string) error {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return errors.New("MinIo信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filePath)
+//	}()
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
 
-	log.Printf("Successfully uploaded %s of size %d\n", objectName, info.Size)
-}
+// UploadMinIoToDir 上传至hzchart
+//func UploadMinIoToDir(filename, filePath, uploadDir, fileDir string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	if uploadDir == "" {
+//		uploadDir = utils.MinIoUploadDir
+//	}
+//	if fileDir == "" {
+//		fileDir = time.Now().Format("200601/20060102/")
+//	}
+//	path := uploadDir + fileDir
+//	path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
 
-// UploadImgToMinIo 图片上传
-func UploadImgToMinIo(fileName, filePath string) (string, error) {
-	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
-		return "0", errors.New("MinIo信息未配置")
-	}
+//func UploadImgToMinIoTest(fileName, filePath string) (string, error) {
+//	ctx := context.Background()
+//	endpoint := utils.Endpoint
+//	accessKeyID := utils.AccessKeyId
+//	secretAccessKey := utils.AccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.Bucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//
+//	buckets, e := minioClient.ListBuckets(ctx)
+//	if e != nil {
+//		fmt.Println("ListBuckets: ", e.Error())
+//		return "", e
+//	}
+//	for k := range buckets {
+//		fmt.Println(k)
+//	}
+//
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	fmt.Println("exists: ", exists)
+//	fmt.Println("errBucketExists: ", errBucketExists)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	path := utils.UploadDir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.Imghost + path
+//	return path, err
+//}
 
-	ctx := context.Background()
-	endpoint := utils.MinIoEndpoint
-	accessKeyID := utils.MinIoAccessKeyId
-	secretAccessKey := utils.MinIoAccessKeySecret
-	useSSL := false
-	if utils.MinIoUseSSL == "true" {
-		useSSL = true
-	}
-	minioClient, err := minio.New(endpoint, &minio.Options{
-		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
-		Secure: useSSL,
-	})
-	if err != nil {
-		log.Fatalln(err)
-		return "1", err
-	}
-	bucketName := utils.MinIoBucketname
-	// Check to see if we already own this bucket (which happens if you run this twice)
-	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-	if errBucketExists == nil && exists {
-		log.Printf("We already own %s\n", bucketName)
-	} else {
-		log.Fatalln(err)
-		return "2", err
-	}
-	path := utils.MinIoUploadDir + time.Now().Format("200601/20060102/")
-	path += fileName
-	// Upload the zip file with FPutObject
-	//contentType := "application/xlsx"
-	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
-	if err != nil {
-		log.Fatalln(err)
-		return "3", err
-	}
-
-	path = utils.MinIoImghost + path
-	return path, err
-}
+type MinioOss struct{}
 
-// UploadAudioToMinIo 音频上传
-func UploadAudioToMinIo(fileName, filePath string) (string, error) {
+// UploadFile 上传文件
+func (m *MinioOss) UploadFile(fileName, filePath, savePath string) (string, error) {
 	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
 		return "0", errors.New("MinIo信息未配置")
 	}
@@ -185,7 +424,6 @@ func UploadAudioToMinIo(fileName, filePath string) (string, error) {
 		return "1", err
 	}
 	bucketName := utils.MinIoBucketname
-	// Check to see if we already own this bucket (which happens if you run this twice)
 	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
 	if errBucketExists == nil && exists {
 		log.Printf("We already own %s\n", bucketName)
@@ -194,156 +432,27 @@ func UploadAudioToMinIo(fileName, filePath string) (string, error) {
 		return "2", err
 	}
 
-	path := utils.MinIoUpload_Audio_Dir + time.Now().Format("200601/20060102/")
-	path += fileName
-
-	// Upload the zip file with FPutObject
-	//contentType := "application/xlsx"
+	path := savePath
+	if savePath == "" {
+		path = utils.MinIoUploadDir + time.Now().Format("200601/20060102/") + fileName
+	}
 	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
 	if err != nil {
 		log.Fatalln(err)
 		return "3", err
 	}
-
-	path = utils.MinIoImghost + path
-	return path, err
+	resourceUrl := utils.MinIoImghost + path
+	return resourceUrl, err
 }
 
-// UploadVideoToMinIo 视频上传
-func UploadVideoToMinIo(filename, filePath, savePath string) error {
-	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
-		return errors.New("MinIo信息未配置")
-	}
-	defer func() {
-		os.Remove(filePath)
-	}()
-
-	ctx := context.Background()
-	endpoint := utils.MinIoEndpoint
-	accessKeyID := utils.MinIoAccessKeyId
-	secretAccessKey := utils.MinIoAccessKeySecret
-	useSSL := false
-	if utils.MinIoUseSSL == "true" {
-		useSSL = true
-	}
-	minioClient, err := minio.New(endpoint, &minio.Options{
-		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
-		Secure: useSSL,
-	})
-	if err != nil {
-		log.Fatalln(err)
-		return err
-	}
-	bucketName := utils.MinIoBucketname
-	// Check to see if we already own this bucket (which happens if you run this twice)
-	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-	if errBucketExists == nil && exists {
-		log.Printf("We already own %s\n", bucketName)
-	} else {
-		log.Fatalln(err)
-		return err
-	}
-
-	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	//path += filename
-	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
-	if err != nil {
-		log.Fatalln(err)
-		return err
-	}
-	//path = utils.Imghost + path
-	//return path,err
-	return err
-}
-
-// UploadFileToMinIo 上传文件
-func UploadFileToMinIo(filename, filePath, savePath string) error {
-	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
-		return errors.New("MinIo信息未配置")
-	}
-	defer func() {
-		os.Remove(filePath)
-	}()
-	ctx := context.Background()
-	endpoint := utils.MinIoEndpoint
-	accessKeyID := utils.MinIoAccessKeyId
-	secretAccessKey := utils.MinIoAccessKeySecret
-	useSSL := false
-	if utils.MinIoUseSSL == "true" {
-		useSSL = true
-	}
-	minioClient, err := minio.New(endpoint, &minio.Options{
-		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
-		Secure: useSSL,
-	})
-	if err != nil {
-		log.Fatalln(err)
-		return err
-	}
-	bucketName := utils.MinIoBucketname
-	// Check to see if we already own this bucket (which happens if you run this twice)
-	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-	if errBucketExists == nil && exists {
-		log.Printf("We already own %s\n", bucketName)
-	} else {
-		log.Fatalln(err)
-		return err
-	}
-	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	//path += filename
-	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
-	if err != nil {
-		log.Fatalln(err)
-		return err
-	}
-	//path = utils.Imghost + path
-	//return path,err
-	return err
-}
-
-// UploadMinIoToDir 上传至hzchart
-func UploadMinIoToDir(filename, filePath, uploadDir, fileDir string) (string, error) {
-	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
-		return "0", errors.New("MinIo信息未配置")
-	}
-	ctx := context.Background()
-	endpoint := utils.MinIoEndpoint
-	accessKeyID := utils.MinIoAccessKeyId
-	secretAccessKey := utils.MinIoAccessKeySecret
-	useSSL := false
-	if utils.MinIoUseSSL == "true" {
-		useSSL = true
-	}
-	minioClient, err := minio.New(endpoint, &minio.Options{
-		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
-		Secure: useSSL,
-	})
-	if err != nil {
-		log.Fatalln(err)
-		return "1", err
-	}
-	bucketName := utils.MinIoBucketname
-	// Check to see if we already own this bucket (which happens if you run this twice)
-	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-	if errBucketExists == nil && exists {
-		log.Printf("We already own %s\n", bucketName)
-	} else {
-		log.Fatalln(err)
-		return "2", err
-	}
-	if uploadDir == "" {
-		uploadDir = utils.MinIoUploadDir
-	}
-	if fileDir == "" {
-		fileDir = time.Now().Format("200601/20060102/")
-	}
-	path := uploadDir + fileDir
-	path += filename
-	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
-	if err != nil {
-		log.Fatalln(err)
-		return "3", err
-	}
-	path = utils.MinIoImghost + path
-	return path, err
+func (m *MinioOss) GetUploadToken() (token OssToken, err error) {
+	token.AccessKeyId = utils.MinIoAccessKeyId
+	token.SecretKeyId = utils.MinIoAccessKeySecret
+	token.Endpoint = utils.MinIoEndpoint
+	token.ImgHost = utils.MinIoImghost
+	token.Bucketname = utils.MinIoBucketname
+	token.UseSSL = utils.MinIoUseSSL
+	token.RegionId = utils.MinIoRegion
+	token.Port = utils.MinIoPort
+	return
 }

+ 149 - 104
services/oss.go

@@ -4,8 +4,8 @@ import (
 	"encoding/json"
 	"errors"
 	"eta/eta_api/services/alarm_msg"
+	"fmt"
 	"github.com/aliyun/aliyun-oss-go-sdk/oss"
-	"os"
 	"time"
 
 	"eta/eta_api/utils"
@@ -13,104 +13,104 @@ import (
 )
 
 // UploadAliyunV2 图片上传到阿里云
-func UploadAliyunV2(filename, filepath string) (string, error) {
-	if utils.AccessKeyId == `` {
-		return "0", errors.New("阿里云信息未配置")
-	}
-	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
-	if err != nil {
-		return "1", err
-	}
-	bucket, err := client.Bucket(utils.Bucketname)
-	if err != nil {
-		return "2", err
-	}
-	path := utils.UploadDir + time.Now().Format("200601/20060102/")
-	path += filename
-	err = bucket.PutObjectFromFile(path, filepath)
-	if err != nil {
-		return "3", err
-	}
-	path = utils.Imghost + path
-	return path, err
-}
+//func UploadAliyunV2(filename, filepath string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	path := utils.UploadDir + time.Now().Format("200601/20060102/")
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
 
 // UploadAudioAliyun 音频上传到阿里云
-func UploadAudioAliyun(filename, filepath string) (string, error) {
-	if utils.AccessKeyId == `` {
-		return "0", errors.New("阿里云信息未配置")
-	}
-	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
-	if err != nil {
-		return "1", err
-	}
-	bucket, err := client.Bucket(utils.Bucketname)
-	if err != nil {
-		return "2", err
-	}
-	path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	path += filename
-	err = bucket.PutObjectFromFile(path, filepath)
-	if err != nil {
-		return "3", err
-	}
-	path = utils.Imghost + path
-	return path, err
-}
+//func UploadAudioAliyun(filename, filepath string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
 
 // UploadVideoAliyun 视频上传到阿里云
-func UploadVideoAliyun(filename, filepath, savePath string) error {
-	if utils.AccessKeyId == `` {
-		return errors.New("阿里云信息未配置")
-	}
-	defer func() {
-		os.Remove(filepath)
-	}()
-	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
-	if err != nil {
-		return err
-	}
-	bucket, err := client.Bucket(utils.Bucketname)
-	if err != nil {
-		return err
-	}
-	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	//path += filename
-	err = bucket.PutObjectFromFile(savePath, filepath)
-	if err != nil {
-		return err
-	}
-	//path = utils.Imghost + path
-	//return path,err
-	return err
-}
+//func UploadVideoAliyun(filename, filepath, savePath string) error {
+//	if utils.AccessKeyId == `` {
+//		return errors.New("阿里云信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filepath)
+//	}()
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	err = bucket.PutObjectFromFile(savePath, filepath)
+//	if err != nil {
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
 
 // UploadFileToAliyun 上传文件到阿里云
-func UploadFileToAliyun(filename, filepath, savePath string) error {
-	if utils.AccessKeyId == `` {
-		return errors.New("阿里云信息未配置")
-	}
-	defer func() {
-		os.Remove(filepath)
-	}()
-	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
-	if err != nil {
-		return err
-	}
-	bucket, err := client.Bucket(utils.Bucketname)
-	if err != nil {
-		return err
-	}
-	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
-	//path += filename
-	err = bucket.PutObjectFromFile(savePath, filepath)
-	if err != nil {
-		return err
-	}
-	//path = utils.Imghost + path
-	//return path,err
-	return err
-}
+//func UploadFileToAliyun(filename, filepath, savePath string) error {
+//	if utils.AccessKeyId == `` {
+//		return errors.New("阿里云信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filepath)
+//	}()
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	err = bucket.PutObjectFromFile(savePath, filepath)
+//	if err != nil {
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
 
 type STSToken struct {
 	AccessKeyId     string
@@ -223,7 +223,38 @@ func NewSTSToken() (item *STSToken, err error) {
 }
 
 // UploadAliyunToDir 上传至hzchart
-func UploadAliyunToDir(filename, filepath, uploadDir, fileDir string) (string, error) {
+//func UploadAliyunToDir(filename, filepath, uploadDir, fileDir string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	if uploadDir == "" {
+//		uploadDir = utils.UploadDir
+//	}
+//	if fileDir == "" {
+//		fileDir = time.Now().Format("200601/20060102/")
+//	}
+//	path := uploadDir + fileDir
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
+
+type AliOss struct{}
+
+// UploadFile 上传文件
+func (m *AliOss) UploadFile(fileName, filePath, savePath string) (string, error) {
 	if utils.AccessKeyId == `` {
 		return "0", errors.New("阿里云信息未配置")
 	}
@@ -235,18 +266,32 @@ func UploadAliyunToDir(filename, filepath, uploadDir, fileDir string) (string, e
 	if err != nil {
 		return "2", err
 	}
-	if uploadDir == "" {
-		uploadDir = utils.UploadDir
-	}
-	if fileDir == "" {
-		fileDir = time.Now().Format("200601/20060102/")
+
+	path := savePath
+	if savePath == "" {
+		path = utils.UploadDir + time.Now().Format("200601/20060102/") + fileName
 	}
-	path := uploadDir + fileDir
-	path += filename
-	err = bucket.PutObjectFromFile(path, filepath)
+	err = bucket.PutObjectFromFile(path, filePath)
 	if err != nil {
 		return "3", err
 	}
-	path = utils.Imghost + path
-	return path, err
+	resourceUrl := utils.Imghost + path
+	return resourceUrl, err
+}
+
+func (m *AliOss) GetUploadToken() (token OssToken, err error) {
+	stsToken, e := GetOssSTSToken()
+	if e != nil {
+		err = fmt.Errorf("GetOssSTSToken err: %s", e.Error())
+		return
+	}
+	token.AccessKeyId = stsToken.AccessKeyId
+	token.AccessKeySecret = stsToken.AccessKeySecret
+	token.SecurityToken = stsToken.SecurityToken
+	token.ExpiredTime = stsToken.ExpiredTime
+	token.RegionId = stsToken.RegionId
+	token.Bucketname = stsToken.Bucketname
+	token.Endpoint = stsToken.Endpoint
+	token.Imghost = stsToken.Imghost
+	return
 }

+ 45 - 26
services/report.go

@@ -638,23 +638,31 @@ func reportBase64ToImg(imageBase64 string) (resourceUrl string, err error) {
 	savePath += fileName
 
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		err = UploadFileToMinIo(fileName, fpath, savePath)
-		if err != nil {
-			err = errors.New("文件上传失败" + err.Error())
-			return
-		}
-		resourceUrl = utils.MinIoImghost + savePath
-	} else {
-		err = UploadFileToAliyun(fileName, fpath, savePath)
-		if err != nil {
-			err = errors.New("文件上传失败" + err.Error())
-			return
-		}
-		resourceUrl = utils.Imghost + savePath
+	//if utils.ObjectStorageClient == "minio" {
+	//	err = UploadFileToMinIo(fileName, fpath, savePath)
+	//	if err != nil {
+	//		err = errors.New("文件上传失败" + err.Error())
+	//		return
+	//	}
+	//	resourceUrl = utils.MinIoImghost + savePath
+	//} else {
+	//	err = UploadFileToAliyun(fileName, fpath, savePath)
+	//	if err != nil {
+	//		err = errors.New("文件上传失败" + err.Error())
+	//		return
+	//	}
+	//	resourceUrl = utils.Imghost + savePath
+	//}
+	ossClient := NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, savePath)
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
-
-
 
 	item := new(models.Resource)
 	item.ResourceUrl = resourceUrl
@@ -876,16 +884,27 @@ func PcCreateAndUploadSunCode(scene, page string) (imgUrl string, err error) {
 	fileDir := "yb/suncode/"
 
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		imgUrl, err = UploadMinIoToDir(fileName, fpath, "", fileDir)
-		if err != nil {
-			return
-		}
-	} else {
-		imgUrl, err = UploadAliyunToDir(fileName, fpath, "", fileDir)
-		if err != nil {
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	imgUrl, err = UploadMinIoToDir(fileName, fpath, "", fileDir)
+	//	if err != nil {
+	//		return
+	//	}
+	//} else {
+	//	imgUrl, err = UploadAliyunToDir(fileName, fpath, "", fileDir)
+	//	if err != nil {
+	//		return
+	//	}
+	//}
+	savePath := fileDir + time.Now().Format("200601/20060102/") + fileName
+	ossClient := NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	imgUrl, err = ossClient.UploadFile(fileName, fpath, savePath)
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
 
 	if err != nil {

+ 44 - 25
services/video.go

@@ -100,18 +100,28 @@ func CreateVideo(report *models.ReportDetail) (err error) {
 
 	uploadUrl := ``
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		uploadUrl, err = UploadAudioToMinIo(saveName, savePath)
-		if err != nil {
-			err = errors.New("UploadAudioAliyun Err:" + err.Error())
-			return
-		}
-	} else {
-		uploadUrl, err = UploadAudioAliyun(saveName, savePath)
-		if err != nil {
-			err = errors.New("UploadAudioAliyun Err:" + err.Error())
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	uploadUrl, err = UploadAudioToMinIo(saveName, savePath)
+	//	if err != nil {
+	//		err = errors.New("UploadAudioAliyun Err:" + err.Error())
+	//		return
+	//	}
+	//} else {
+	//	uploadUrl, err = UploadAudioAliyun(saveName, savePath)
+	//	if err != nil {
+	//		err = errors.New("UploadAudioAliyun Err:" + err.Error())
+	//		return
+	//	}
+	//}
+	ossClient := NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	uploadUrl, err = ossClient.UploadFile(saveName, savePath, "")
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
 
 	fileBody, err := ioutil.ReadFile(savePath)
@@ -300,20 +310,29 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 		time.Sleep(5 * time.Second)
 	}
 
-
 	//上传到阿里云 和 minio
-	if utils.ObjectStorageClient == "minio" {
-		uploadUrl, err = UploadAudioToMinIo(saveName, savePath)
-		if err != nil {
-			err = errors.New("UploadAudioAliyun Err:" + err.Error())
-			return
-		}
-	} else {
-		uploadUrl, err = UploadAudioAliyun(saveName, savePath)
-		if err != nil {
-			err = errors.New("UploadAudioAliyun Err:" + err.Error())
-			return
-		}
+	//if utils.ObjectStorageClient == "minio" {
+	//	uploadUrl, err = UploadAudioToMinIo(saveName, savePath)
+	//	if err != nil {
+	//		err = errors.New("UploadAudioAliyun Err:" + err.Error())
+	//		return
+	//	}
+	//} else {
+	//	uploadUrl, err = UploadAudioAliyun(saveName, savePath)
+	//	if err != nil {
+	//		err = errors.New("UploadAudioAliyun Err:" + err.Error())
+	//		return
+	//	}
+	//}
+	ossClient := NewOssClient()
+	if ossClient == nil {
+		err = fmt.Errorf("初始化OSS服务失败")
+		return
+	}
+	uploadUrl, err = ossClient.UploadFile(saveName, savePath, "")
+	if err != nil {
+		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
+		return
 	}
 
 	fileBody, err := ioutil.ReadFile(savePath)

+ 18 - 0
utils/calculate.go

@@ -221,6 +221,24 @@ func ReplaceFormulaByCellList(cellList []CellPosition, formulaStr string) string
 	return formulaStr
 }
 
+func ReplaceFormulaByTagMap(valTagMap map[string]int, formulaStr string) string {
+	funMap := getFormulaMap()
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, k, v, -1)
+	}
+
+	replaceCount := 0
+	for tag, val := range valTagMap {
+		dvStr := fmt.Sprintf("%v", val)
+		formulaStr = strings.Replace(formulaStr, tag, dvStr, -1)
+		replaceCount++
+	}
+	for k, v := range funMap {
+		formulaStr = strings.Replace(formulaStr, v, k, -1)
+	}
+	return formulaStr
+}
+
 func getFormulaMap() map[string]string {
 	funMap := make(map[string]string)
 	funMap["MAX"] = "[@@]"

+ 27 - 0
utils/common.go

@@ -637,6 +637,27 @@ func ConvertToFormatDay(excelDaysString string) string {
 	return resultTime
 }
 
+// GetDaysDiff1900 计算日期距离1900-01-01的天数
+func GetDaysDiff1900(date string) int {
+	// 将字符串转换为时间类型
+	//从1899年12月30日开始是因为Excel的日期计算是基于1900年1月1日的,而1900年并不是闰年,因此Excel日期计算存在一个错误。为了修正这个错误,
+	//我们将时间回溯到1899年12月30日,这样在进行日期计算时可以正确地处理Excel日期。
+	tStart, err := time.ParseInLocation(FormatDate, "1899-12-30", time.Local)
+	if err != nil {
+		return 0
+	}
+	tEnd, err := time.ParseInLocation(FormatDate, date, time.Local)
+	if err != nil {
+		return 0
+	}
+
+	// 计算两个日期之间的天数差值
+	duration := tEnd.Sub(tStart).Hours() / 24
+	days := int(duration)
+
+	return days
+}
+
 func CheckPwd(pwd string) bool {
 	compile := `([0-9a-z]+){6,12}|(a-z0-9]+){6,12}`
 	reg := regexp.MustCompile(compile)
@@ -2072,6 +2093,12 @@ func GetPredictEdbDayListByNum(startDate time.Time, num int, frequency string) (
 	return
 }
 
+// FormatMixTableDataShowValue 格式化自定表格显示数据
+func FormatMixTableDataShowValue(x float64) (res string) {
+	res = fmt.Sprint(x)
+	return
+}
+
 // FormatTableDataShowValue 格式化自定表格显示数据
 func FormatTableDataShowValue(x float64) (res string) {
 	if x > 1 || x < -1 {

+ 28 - 0
utils/config.go

@@ -213,6 +213,20 @@ var (
 	EtaSecret string
 )
 
+// S3配置
+var (
+	S3Endpoint        string
+	S3BucketName      string
+	S3UploadDir       string
+	S3AccessKeyId     string
+	S3AccessKeySecret string
+	S3Host            string
+	S3Region          string
+	S3ForceStyle      string
+	S3EndpointPort    string
+	S3Protocol        string
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -471,6 +485,20 @@ func init() {
 		MinIoRegion = config["minio_region"]
 	}
 
+	// S3-OSS相关
+	{
+		S3Endpoint = config["s3_endpoint"]
+		S3BucketName = config["s3_bucket_name"]
+		S3Host = config["s3_host"]
+		S3AccessKeyId = config["s3_access_key_id"]
+		S3AccessKeySecret = config["s3_access_key_secret"]
+		S3UploadDir = config["s3_upload_dir"]
+		S3Region = config["s3_region"]
+		S3ForceStyle = config["s3_force_style"]
+		S3EndpointPort = config["s3_endpoint_port"]
+		S3Protocol = config["s3_protocol"]
+	}
+
 	// 生成长图服务地址
 	PythonUrlReport2Img = config["python_url_report2img"]
 

+ 9 - 0
utils/constants.go

@@ -168,6 +168,8 @@ const (
 	DATA_SOURCE_PREDICT_CALCULATE_ZSXY                          // 预测指数修匀->73
 	DATA_SOURCE_CALCULATE_ZDYFX                                 // 自定义分析->74
 	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
+	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->78
+	DATA_SOURCE_ICPI                                 = 79       // ICPI消费价格指数->79
 )
 
 // 数据刷新频率
@@ -302,6 +304,7 @@ const (
 	CHART_TYPE_CURVE           = 1  //曲线图
 	CHART_TYPE_BAR             = 7  //柱形图
 	CHART_TYPE_SECTION_SCATTER = 10 //截面散点图样式
+	CHART_TYPE_RADAR           = 11 //雷达图
 )
 
 // 指标类型
@@ -351,6 +354,12 @@ const (
 	STORAGESOURCE_MINIO = 2 //MinIo
 )
 
+const (
+	STORAGESOURCE_OSS_NAME   = "oss"
+	STORAGESOURCE_MINIO_NAME = "minio"
+	STORAGESOURCE_S3_NAME    = "s3"
+)
+
 // DIR_MOD 目录创建权限
 const DIR_MOD fs.FileMode = 0766 // Unix permission bits