Эх сурвалжийг харах

Merge branch 'master' into feature/change_log

xyxie 1 жил өмнө
parent
commit
950f1bec73
69 өөрчлөгдсөн 5418 нэмэгдсэн , 2114 устгасан
  1. 1 0
      .gitignore
  2. 227 0
      controllers/business_conf.go
  3. 290 0
      controllers/data_manage/chart_info.go
  4. 170 3
      controllers/data_manage/edb_classify.go
  5. 94 19
      controllers/data_manage/edb_info.go
  6. 12 1
      controllers/data_manage/edb_info_calculate.go
  7. 92 0
      controllers/data_manage/future_good/future_good_chart_info.go
  8. 8 4
      controllers/data_manage/predict_edb_info.go
  9. 206 0
      controllers/english_report/english_company.go
  10. 217 57
      controllers/english_report/report.go
  11. 162 66
      controllers/report.go
  12. 117 47
      controllers/resource.go
  13. 2 2
      controllers/semantic_analysis/sa_compare.go
  14. 127 0
      controllers/sys_role.go
  15. 14 6
      go.mod
  16. 29 6
      go.sum
  17. 3 0
      log/api/apilog.log
  18. 167 0
      models/business_conf.go
  19. 108 0
      models/business_conf_operation_record.go
  20. 124 0
      models/company/company_permission.go
  21. 72 0
      models/data_manage/edb_classify.go
  22. 8 1
      models/data_manage/edb_data_base.go
  23. 0 321
      models/data_manage/edb_data_gl.go
  24. 0 528
      models/data_manage/edb_data_quarter.go
  25. 16 3
      models/data_manage/edb_info.go
  26. 1 1
      models/data_manage/edb_info_calculate.go
  27. 39 4
      models/data_manage/edb_source.go
  28. 0 135
      models/data_manage/gl_data.go
  29. 147 0
      models/data_manage/jiayue_index.go
  30. 35 6
      models/db.go
  31. 231 0
      models/english_company.go
  32. 258 0
      models/english_company_todo.go
  33. 95 53
      models/english_report.go
  34. 4 4
      models/permission.go
  35. 4 264
      models/report.go
  36. 7 4
      models/report_chapter.go
  37. 1 1
      models/report_chapter_ticker.go
  38. 7 7
      models/report_chapter_type.go
  39. 1 1
      models/report_chapter_type_permission.go
  40. 2 2
      models/sandbox/sandbox.go
  41. 2 2
      models/search_key_word.go
  42. 8 8
      models/semantic_analysis/sa_compare.go
  43. 52 1
      models/system/sys_menu.go
  44. 1 0
      models/system/sys_role_admin.go
  45. 6 6
      models/system/sys_session.go
  46. 8 4
      models/user_view_history.go
  47. 2 2
      models/wechat_send_msg.go
  48. 108 0
      routers/commentsRouter.go
  49. 16 0
      routers/router.go
  50. 52 0
      services/data/base_bridge.go
  51. 11 0
      services/data/base_edb_lib.go
  52. 570 78
      services/data/edb_classify.go
  53. 255 284
      services/data/edb_info.go
  54. 331 0
      services/data/jiayue_index.go
  55. 119 0
      services/english_company_todo.go
  56. 8 8
      services/excel/lucky_sheet.go
  57. 349 0
      services/minio.go
  58. 12 2
      services/oss.go
  59. 0 49
      services/ppt2img/ppt2img.go
  60. 93 0
      services/public_api/base_public_api.go
  61. 47 18
      services/report.go
  62. 56 0
      services/system.go
  63. 29 8
      services/user_login.go
  64. 73 14
      services/video.go
  65. 4 0
      services/wechat_send_msg.go
  66. 11 5
      services/xfyun.go
  67. 72 77
      utils/config.go
  68. 23 0
      utils/constants.go
  69. 2 2
      utils/des3.go

+ 1 - 0
.gitignore

@@ -6,3 +6,4 @@
 /.idea
 /.idea/
 /.DS_Store
+*.tar.gz

+ 227 - 0
controllers/business_conf.go

@@ -0,0 +1,227 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"html"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// BusinessConfController 商家配置
+type BusinessConfController struct {
+	BaseAuthController
+}
+
+type BusinessConfOpenController struct {
+	BaseCommonController
+}
+
+// Save
+// @Title 保存配置
+// @Description 保存配置
+// @Param	request	body map[string]interface{} true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /save [post]
+func (this *BusinessConfController) Save() {
+	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
+	}
+	var req map[string]interface{}
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+
+	// 获取配置信息
+	confOb := new(models.BusinessConf)
+	list, e := confOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "获取配置列表失败, Err: " + e.Error()
+		return
+	}
+	confMap := make(map[string]*models.BusinessConf)
+	for _, c := range list {
+		confMap[c.ConfKey] = c
+	}
+
+	// 根据配置类型取值
+	updates := make([]models.BusinessConfUpdate, 0)
+	for k, v := range req {
+		// 过滤掉表中没有的key
+		conf := confMap[k]
+		if conf == nil {
+			continue
+		}
+
+		switch conf.ValType {
+		case 1: // 字符串
+			str, ok := v.(string)
+			if !ok {
+				continue
+			}
+			str = strings.TrimSpace(str)
+			if conf.Necessary == 1 && str == "" {
+				br.Msg = conf.Remark + "不可为空"
+				return
+			}
+			updates = append(updates, models.BusinessConfUpdate{
+				ConfKey: k,
+				ConfVal: str,
+			})
+		case 2: // 数值
+			num, ok := v.(float64)
+			if !ok {
+				continue
+			}
+			if conf.Necessary == 1 && num <= 0 {
+				br.Msg = conf.Remark + "不可为空"
+				return
+			}
+			val := strconv.FormatFloat(num, 'f', 0, 64)
+			updates = append(updates, models.BusinessConfUpdate{
+				ConfKey: k,
+				ConfVal: val,
+			})
+		case 3: // 字符串数组
+			arr, ok := v.([]interface{})
+			if !ok {
+				continue
+			}
+			if conf.Necessary == 1 && len(arr) == 0 {
+				br.Msg = conf.Remark + "不可为空"
+				return
+			}
+			strArr := make([]string, 0)
+			for _, a := range arr {
+				if s, ok2 := a.(string); ok2 {
+					strArr = append(strArr, s)
+				}
+			}
+			val := strings.Join(strArr, ",")
+			updates = append(updates, models.BusinessConfUpdate{
+				ConfKey: k,
+				ConfVal: val,
+			})
+		case 4: // 富文本
+			content, ok := v.(string)
+			if !ok {
+				continue
+			}
+			content = strings.TrimSpace(content)
+			if conf.Necessary == 1 && content == "" {
+				br.Msg = conf.Remark + "不可为空"
+				return
+			}
+			content = html.EscapeString(content)
+			updates = append(updates, models.BusinessConfUpdate{
+				ConfKey: k,
+				ConfVal: content,
+			})
+		}
+	}
+
+	if len(updates) > 0 {
+		if e = models.UpdateBusinessConfMulti(updates); e != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存商家配置失败, Err: " + e.Error()
+			return
+		}
+	}
+
+	// 操作日志
+	go func() {
+		b, e := json.Marshal(req)
+		if e != nil {
+			return
+		}
+		recordOb := new(models.BusinessConfOperationRecord)
+		recordOb.SysUserId = sysUser.AdminId
+		recordOb.SysRealName = sysUser.RealName
+		recordOb.Content = string(b)
+		recordOb.CreateTime = time.Now().Local()
+		_ = recordOb.Create()
+	}()
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Fetch
+// @Title 获取配置
+// @Description 获取配置
+// @Success 200 Ret=200 获取成功
+// @router /fetch [get]
+func (this *BusinessConfController) Fetch() {
+	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, e := models.GetBusinessConf()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+
+	br.Data = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// CodeEncrypt
+// @Title 商家编码加密
+// @Description 商家编码加密
+// @Success 200 Ret=200 获取成功
+// @router /code_encrypt [get]
+func (this *BusinessConfOpenController) CodeEncrypt() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	res := ""
+	if utils.BusinessCode != "" {
+		res = utils.MD5(fmt.Sprintf("%s%s", utils.BusinessCode, utils.BusinessCodeSalt))
+	}
+
+	br.Data = res
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 290 - 0
controllers/data_manage/chart_info.go

@@ -6,10 +6,14 @@ import (
 	"eta/eta_mobile/models"
 	"eta/eta_mobile/models/data_manage"
 	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/services"
 	"eta/eta_mobile/services/data"
 	"eta/eta_mobile/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"os"
+	"os/exec"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -1505,3 +1509,289 @@ func (this *ChartInfoController) BatchChartInfoRefresh() {
 	br.Success = true
 	br.Msg = "刷新成功"
 }
+
+// @Title 保存图表接口
+// @Description 保存图表接口
+// @Param	request	body data_manage.SaveChartInfoReq true "type json string"
+// @Success Ret=200 返回图表id
+// @router /chart_info/save [post]
+func (this *ChartInfoController) ChartInfoSave() {
+	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
+	}
+
+	var req data_manage.SaveChartInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId > 0 && len(req.ChartEdbInfoList) <= 0 {
+		br.Msg = "参数错误!"
+		return
+	}
+
+	chartItem, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除,请刷新页面!"
+			br.ErrMsg = "图表已被删除,请刷新页面,ChartInfoId:" + strconv.Itoa(req.ChartInfoId)
+			return
+		}
+		br.Msg = "获取图表信息失败!"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	//图表操作权限
+	//ok := data.CheckOpChartPermission(sysUser, chartItem.SysUserId)
+	//if !ok {
+	//	br.Msg = "没有该图表的操作权限"
+	//	br.ErrMsg = "没有该图表的操作权限"
+	//	return
+	//}
+
+	if chartItem.ChartType == 2 && len(req.ChartEdbInfoList) > 1 {
+		br.Msg = "您选择的图表样式为季节性图表,只支持单指标画图!"
+		br.ErrMsg = "您选择的图表样式为季节性图表,只支持单指标画图,Data:" + string(this.Ctx.Input.RequestBody)
+		return
+	}
+
+	if req.Calendar == "" {
+		req.Calendar = "公历"
+	}
+
+	var edbInfoIdArr []int
+	edbList := make([]*data_manage.EdbInfo, 0)
+
+	for _, v := range req.ChartEdbInfoList {
+		edbInfo, err := data_manage.GetEdbInfoById(v.EdbInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "图表不存在!"
+				br.ErrMsg = "图表不存在,ChartInfoId:" + strconv.Itoa(v.EdbInfoId)
+				return
+			} else {
+				br.Msg = "获取图表信息失败!"
+				br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
+				return
+			}
+		}
+
+		if edbInfo == nil {
+			br.Msg = "指标不存在!"
+			br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(v.EdbInfoId)
+			return
+		}
+
+		edbInfoIdArr = append(edbInfoIdArr, v.EdbInfoId)
+		edbInfo.EdbNameSource = edbInfo.EdbName
+		edbList = append(edbList, edbInfo)
+	}
+	sort.Ints(edbInfoIdArr)
+	var edbInfoIdArrStr []string
+	for _, v := range edbInfoIdArr {
+		edbInfoIdArrStr = append(edbInfoIdArrStr, strconv.Itoa(v))
+	}
+	edbInfoIdStr := strings.Join(edbInfoIdArrStr, ",")
+	err = data_manage.ModifyChartInfoAndMapping(edbInfoIdStr, &req, chartItem.ChartType)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	key := utils.HZ_CHART_LIB_DETAIL + chartItem.UniqueCode
+	if utils.Re == nil && utils.Rc != nil {
+		utils.Rc.Delete(key)
+	}
+
+	//修改es数据
+	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
+	//修改my eta es数据
+	go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "修改配置项"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.IsAddLog = true
+}
+
+// @Param   Img   query   string  true       "图片"
+// @Success 200 {object} models.ResourceResp
+// @router /chart_info/base64Upload [post]
+func (this *ChartInfoController) ChartInfoBase64Upload() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	imgData := this.GetString("Img")
+	if imgData == "" {
+		br.Msg = "图片参数错误"
+		br.ErrMsg = "图片参数错误,Img Is Empty"
+		return
+	}
+	resp := new(models.ResourceResp)
+
+	uploadDir := "static/images/"
+	if !utils.FileIsExist(uploadDir) {
+		err := os.MkdirAll(uploadDir, 777)
+		if err != nil {
+			br.Msg = "图表保存失败"
+			br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	var saveToOssPath string
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	var fileName, outFileName string
+	fileName = randStr + ".txt"
+	fileName = uploadDir + fileName
+	err := utils.SaveToFile(imgData, fileName)
+	if err != nil {
+		br.Msg = "图片保存失败"
+		br.ErrMsg = "图片保存失败,Err:" + err.Error()
+		return
+	}
+	outFileName = randStr + ".png"
+
+	doneChannel := make(chan bool, 1)
+	errorChannel := make(chan error, 1)
+
+	cmd := exec.Command("highcharts-export-server", "--infile", fileName, "--constr", "Chart", "--scale", "2", "--workers", "10", "--workLimit", "3", "--outfile", outFileName)
+
+	go func() {
+		output, err := cmd.CombinedOutput()
+		if err != nil {
+			utils.FileLog.Info("execute command failed, output: , error: \n" + string(output) + err.Error())
+			errorChannel <- err
+			return
+		}
+		doneChannel <- true
+	}()
+
+	select {
+	case <-time.After(30 * time.Second):
+		utils.FileLog.Info("执行超过30秒 杀死超时进程")
+		cmd.Process.Kill()
+		fmt.Println("timeout kill process")
+	case <-doneChannel:
+		fmt.Println("done")
+	case err := <-errorChannel:
+		br.Msg = "文件上传失败"
+		br.ErrMsg = fmt.Sprintf("execute command failure err: %s", err.Error())
+		fmt.Println("execute command failure err:" + err.Error())
+		return
+	}
+
+	defer func() {
+		os.Remove(fileName)
+	}()
+
+	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
+	}
+
+	resp.ResourceUrl = resourceUrl
+	resp.Source = "convert"
+	//resp.CacheKey = imgDataKey
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+	return
+}
+
+// @Title 设置图表图片
+// @Description 设置图表图片接口
+// @Param	request	body data_manage.SetChartInfoImageReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /chart_info/image/set [post]
+func (this *ChartInfoController) ChartInfoImageSet() {
+	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
+	}
+
+	var req data_manage.SetChartInfoImageReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId > 0 && req.ImageUrl != "" {
+		err = data_manage.EditChartInfoImage(&req)
+		if err != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存失败,Err:" + err.Error()
+			return
+		}
+
+		//修改es数据
+		go data.EsAddOrEditChartInfo(req.ChartInfoId)
+		//修改my eta es数据
+		go data.EsAddOrEditMyChartInfoByChartInfoId(req.ChartInfoId)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}

+ 170 - 3
controllers/data_manage/edb_classify.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_mobile/models/system"
 	"eta/eta_mobile/services/data"
 	"eta/eta_mobile/utils"
+	"sort"
 )
 
 // EdbClassifyController 数据管理-分类模块
@@ -486,13 +487,13 @@ func (this *EdbClassifyController) EdbClassifyMove() {
 		return
 	}
 
-	if req.ClassifyId <= 0 {
+	if req.ClassifyId <= 0 && req.EdbInfoId <= 0 {
 		br.Msg = "参数错误"
-		br.ErrMsg = "分类id小于等于0"
+		br.ErrMsg = "请选择拖动目标,分类目录或者指标"
 		return
 	}
 
-	err, errMsg := data.MoveEdbClassify(req.ClassifyId, req.ParentClassifyId, req.PrevClassifyId, req.NextClassifyId, sysUser)
+	err, errMsg := data.MoveEdbClassify(req, sysUser, 0)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -906,3 +907,169 @@ func (this *EdbClassifyController) ItemsV3() {
 //	br.Success = true
 //	br.Msg = "移动成功"
 //}
+
+// SimpleList
+// @Title 单层分类列表
+// @Description 单层分类列表
+// @Success 200 {object} data_manage.EdbClassifyListResp
+// @router /classify/simple [get]
+func (this *EdbClassifyController) SimpleList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	// 默认查一级分类和一级分类下的指标信息,
+	// 如果是 子级分类,查询该子级分类的下一级分类和指标信息
+	// 增加标识判断是文件夹还是指标列表
+	parentId, _ := this.GetInt("ParentId")
+
+	rootList, err := data_manage.GetEdbClassifyByParentId(parentId, 0)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	nodeAll := make([]*data_manage.EdbClassifyItems, 0)
+
+	var sortList data_manage.EdbClassifyItemList
+	if parentId > 0 {
+		// 查询挂在当前分类上的指标列表
+		// 获取当前账号的不可见指标
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllListByAdminId(this.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		noPermissionEdbInfoIdMap := make(map[int]bool)
+		for _, v := range confList {
+			noPermissionEdbInfoIdMap[v.EdbInfoId] = true
+		}
+		allEdbInfo, err := data_manage.GetEdbInfoByClassifyId(parentId, 0)
+		if err != nil {
+			br.Msg = "获取指标数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+
+		for _, v := range allEdbInfo {
+			// 如果指标不可见,那么就不返回该指标
+			if _, ok := noPermissionEdbInfoIdMap[v.EdbInfoId]; ok {
+				continue
+			}
+			button := data.GetEdbOpButton(this.SysUser, v.SysUserId, v.EdbType, utils.EDB_INFO_TYPE)
+			button.AddButton = false //不管有没有权限,指标都是没有添加按钮的
+			v.Button = button
+			v.Children = make([]*data_manage.EdbClassifyItems, 0)
+			v.ParentId = parentId
+			nodeAll = append(nodeAll, v)
+		}
+	}
+	if len(rootList) > 0 {
+		for _, v := range rootList {
+			button := data.GetEdbClassifyOpButton(this.SysUser, v.SysUserId)
+			v.Button = button
+			v.Children = make([]*data_manage.EdbClassifyItems, 0)
+			nodeAll = append(nodeAll, v)
+		}
+	}
+	if len(nodeAll) > 0 {
+		//根据sort值排序
+		sortList = nodeAll
+		sort.Sort(sortList)
+	}
+
+	language := `CN`
+	// 指标显示的语言
+	{
+		configDetail, _ := system.GetConfigDetailByCode(this.SysUser.AdminId, system.EdbLanguageVar)
+		if configDetail != nil {
+			language = configDetail.ConfigValue
+		} else {
+			configDetail, _ = system.GetDefaultConfigDetailByCode(system.EdbLanguageVar)
+			if configDetail != nil {
+				language = configDetail.ConfigValue
+			}
+		}
+	}
+
+	// 是否允许添加一级分类
+	canOpClassify := true
+	button := data.GetEdbClassifyOpButton(this.SysUser, 0)
+	if !button.AddButton {
+		canOpClassify = false
+	}
+
+	resp := new(data_manage.EdbClassifyListResp)
+	resp.AllNodes = sortList
+	resp.Language = language
+	resp.CanOpClassify = canOpClassify
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ClassifyTree
+// @Title 多层分类列表树
+// @Description 多层分类列表树
+// @Success 200 {object} data_manage.EdbClassifyListResp
+// @router /classify/tree [get]
+func (this *EdbClassifyController) ClassifyTree() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	allList, err := data_manage.GetNormalEdbClassifyAll()
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	nodeAll := make([]*data_manage.EdbClassifyItems, 0)
+	var sortList data_manage.EdbClassifyItemList
+
+	if len(allList) > 0 {
+		for k, v := range allList {
+			button := data.GetEdbClassifyOpButton(this.SysUser, v.SysUserId)
+			allList[k].Button = button
+		}
+		nodeAll = data.GetClassifyTreeRecursive(allList, 0)
+		//根据sort值排序
+		sortList = nodeAll
+		sort.Sort(sortList)
+	}
+	language := `CN`
+	// 指标显示的语言
+	{
+		configDetail, _ := system.GetConfigDetailByCode(this.SysUser.AdminId, system.EdbLanguageVar)
+		if configDetail != nil {
+			language = configDetail.ConfigValue
+		} else {
+			configDetail, _ = system.GetDefaultConfigDetailByCode(system.EdbLanguageVar)
+			if configDetail != nil {
+				language = configDetail.ConfigValue
+			}
+		}
+	}
+
+	// 是否允许添加一级分类
+	canOpClassify := true
+	button := data.GetEdbClassifyOpButton(this.SysUser, 0)
+	if !button.AddButton {
+		canOpClassify = false
+	}
+
+	resp := new(data_manage.EdbClassifyListResp)
+	resp.AllNodes = sortList
+	resp.Language = language
+	resp.CanOpClassify = canOpClassify
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 94 - 19
controllers/data_manage/edb_info.go

@@ -1548,8 +1548,76 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				isAdd = true
 			}
 		} else {
-			br.Msg = "无效的数据来源"
-			return
+			// 代码中没有的来源那么从edb_source中找是否有对应的
+			sourceItem := data_manage.EdbSourceIdMap[source]
+			if sourceItem == nil {
+				br.Msg = "无效指标来源"
+				return
+			}
+
+			// 获取指标数据
+			dataList, e := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取指标数据失败, Err: " + e.Error()
+				return
+			}
+			if len(dataList) > 0 {
+				searchItem.EdbCode = edbCode
+				searchItem.DataList = dataList
+				// 获取最大最小值
+				edbInfoMaxAndMinInfo, e := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				if e != nil && e.Error() != utils.ErrNoRow() {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取数据失败, GetEdbInfoMaxAndMinInfo Err:" + e.Error()
+					return
+				}
+				if edbInfoMaxAndMinInfo != nil {
+					searchItem.StartDate = edbInfoMaxAndMinInfo.MinDate
+					searchItem.EndDate = edbInfoMaxAndMinInfo.MaxDate
+				}
+			} else {
+				// 新增指标数据
+				addRes, e := data.AddEdbData(source, edbCode)
+				if e != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取失败,Err:" + e.Error()
+					return
+				}
+				if addRes == nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "新增指标数据失败, addRes nil"
+					return
+				}
+				if addRes.Ret != 200 {
+					br.Msg = "未搜索到该指标, " + addRes.Msg
+					//br.ErrMsg = addRes.ErrMsg + ";EdbCode:" + edbCode
+					br.Success = true
+					return
+				}
+				isAdd = true
+			}
+
+			// 指标来源于桥接服务: 桥接服务获取指标取频度信息等
+			if sourceItem.BridgeFlag != "" {
+				bridgeOb := data.InitBridgeOB(sourceItem.BridgeFlag)
+				if bridgeOb != nil {
+					var r data.GetIndexFromBridgeReq
+					r.IndexCode = edbCode
+					r.Source = sourceItem.EdbSourceId
+					r.SourceExtend = sourceItem.SourceExtend
+					r.IndexCodeRequired = sourceItem.EdbCodeRequired
+					bridgeIndex, e := bridgeOb.GetIndex(r)
+					if e != nil {
+						br.Msg = "获取失败"
+						br.ErrMsg = "桥接服务获取指标信息失败, Err: " + e.Error()
+						return
+					}
+					searchItem.EdbName = bridgeIndex.IndexName
+					searchItem.Frequency = bridgeIndex.Frequency
+					searchItem.Unit = bridgeIndex.Unit
+				}
+			}
 		}
 		if isAdd {
 			dataList, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
@@ -1743,11 +1811,16 @@ func (this *EdbInfoController) EdbInfoList() {
 	//是否展示英文标识
 	edbInfoItem.IsEnEdb = data.CheckIsEnEdb(edbInfoItem.EdbNameEn, edbInfoItem.Unit, edbInfoItem.UnitEn)
 	//查询目录
-	resultList, _ := data_manage.GetClassifyAllByClassifyId(edbInfoItem.ClassifyId)
+	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfoItem.ClassifyId)
+	if err != nil {
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
+		return
+	}
 
 	resp.Paging = page
 	resp.Item = edbInfoItem
-	resp.ClassifyList = resultList
+	resp.ClassifyList = classifyList
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
@@ -2948,9 +3021,19 @@ func (this *ChartInfoController) EdbInfoData() {
 		br.Msg = "获取失败,Err:" + err.Error()
 		return
 	}
-	resp := new(data_manage.EdbInfoDataResp)
-	resp.EdbInfo = edbInfo
+	fullEdb := new(data_manage.EdbInfoFullClassify)
+	resp := new(data_manage.EdbInfoDataFullClassifyResp)
+	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfo.ClassifyId)
+	if err != nil {
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
+		return
+	}
+	fullEdb.EdbInfo = edbInfo
+	fullEdb.ClassifyList = classifyList
+	resp.EdbInfo = fullEdb
 	resp.DataList = dataList
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
@@ -4378,26 +4461,18 @@ func (this *EdbInfoController) EdbChartList() {
 	// 分类筛选
 	classifyId, _ := this.GetInt("ClassifyId")
 	if classifyId > 0 {
-		strClassifyIds, e := data_manage.GetEdbClassify(classifyId)
+		childClassify, e, _ := data.GetChildClassifyByClassifyId(classifyId)
 		if e != nil && e.Error() != utils.ErrNoRow() {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取分类信息失败, GetEdbClassify,Err:" + e.Error()
 			return
 		}
 		var classifyIds []int
-		classifyIdArr := strings.Split(strClassifyIds, ",")
-		for _, v := range classifyIdArr {
-			c, _ := strconv.Atoi(v)
-			if c > 0 {
-				classifyIds = append(classifyIds, c)
-			}
-		}
-		if len(classifyIds) > 0 {
-			condition += fmt.Sprintf(` AND classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
-			pars = append(pars, classifyIds)
-		} else {
-			condition += ` AND 1=2 `
+		for _, v := range childClassify {
+			classifyIds = append(classifyIds, v.ClassifyId)
 		}
+		condition += fmt.Sprintf(` AND classify_id IN (%s) `, utils.GetOrmInReplace(len(classifyIds)))
+		pars = append(pars, classifyIds)
 	}
 
 	// 创建人

+ 12 - 1
controllers/data_manage/edb_info_calculate.go

@@ -209,8 +209,19 @@ func (this *ChartInfoController) CalculateDetail() {
 		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
+
+	fullEdb := new(data_manage.EdbInfoFullClassify)
+	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfo.ClassifyId)
+	if err != nil {
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
+		return
+	}
+	fullEdb.EdbInfo = edbInfo
+	fullEdb.ClassifyList = classifyList
+
 	resp := new(data_manage.CalculateDetailResp)
-	resp.EdbInfoDetail = edbInfo
+	resp.EdbInfoDetail = fullEdb
 	resp.CalculateList = calculateList
 	br.Ret = 200
 	br.Success = true

+ 92 - 0
controllers/data_manage/future_good/future_good_chart_info.go

@@ -594,3 +594,95 @@ func (this *FutureGoodChartInfoController) CopyChartInfo() {
 	}
 	br.IsAddLog = true
 }
+
+// ChartInfoSave
+// @Title 保存图表接口
+// @Description 保存图表接口
+// @Param	request	body data_manage.SaveChartInfoReq true "type json string"
+// @Success Ret=200 返回图表id
+// @router /chart_info/save [post]
+func (this *FutureGoodChartInfoController) ChartInfoSave() {
+	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
+	}
+
+	var req data_manage.SaveChartInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数错误!"
+		return
+	}
+
+	chartItem, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除,请刷新页面!"
+			br.ErrMsg = "图表已被删除,请刷新页面,ChartInfoId:" + strconv.Itoa(req.ChartInfoId)
+			return
+		}
+		br.Msg = "获取图表信息失败!"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	if !utils.InArrayByInt([]int{utils.CHART_SOURCE_FUTURE_GOOD, utils.CHART_SOURCE_FUTURE_GOOD_PROFIT}, chartItem.Source) {
+		br.Msg = "该图不是商品价格/利润曲线图!"
+		br.IsSendEmail = false
+		return
+	}
+	//数据更新
+	chartItem.LeftMin = req.LeftMin
+	chartItem.LeftMax = req.LeftMax
+	err = chartItem.Update([]string{"LeftMin", "LeftMax"})
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	key := utils.HZ_CHART_LIB_DETAIL + chartItem.UniqueCode
+	if utils.Re == nil && utils.Rc != nil {
+		utils.Rc.Delete(key)
+	}
+
+	//修改es数据
+	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
+	//修改my eta es数据
+	go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "修改商品价格图表配置项"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.IsAddLog = true
+}

+ 8 - 4
controllers/data_manage/predict_edb_info.go

@@ -98,9 +98,6 @@ func (this *PredictEdbInfoController) List() {
 	//获取英文频度
 	edbInfoItem.FrequencyEn = data.GetFrequencyEn(edbInfoItem.Frequency)
 
-	//查询目录
-	resultList, _ := data_manage.GetClassifyAllByClassifyId(edbInfoItem.ClassifyId)
-
 	// 未来的指标预测数据
 	predictDataList := make([]*data_manage.EdbData, 0)
 
@@ -277,9 +274,16 @@ func (this *PredictEdbInfoController) List() {
 	if edbInfoItem.DataList == nil {
 		edbInfoItem.DataList = make([]*data_manage.EdbData, 0)
 	}
+	//查询目录
+	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfoItem.ClassifyId)
+	if err != nil {
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
+		return
+	}
 	resp.Paging = page
 	resp.Item = edbInfoItem
-	resp.ClassifyList = resultList
+	resp.ClassifyList = classifyList
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 206 - 0
controllers/english_report/english_company.go

@@ -0,0 +1,206 @@
+package english_report
+
+import (
+	"eta/eta_mobile/controllers"
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/services"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
+	"strings"
+)
+
+// EnglishCompanyController 英文客户
+type EnglishCompanyController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 英文客户列表
+// @Description 英文客户列表
+// @Param   Keywords	query	string	false	"关键词:客户名称/联系人邮箱/联系人手机号"
+// @Param   SortType	query	int		false	"点击量排序:1-降序; 2-升序"
+// @Param   EnPermissionIds		query	string		false	"品种权限IDs(字符串)"
+// @Success 200 {object} models.EnglishCompanyPageListResp
+// @router /company/list [get]
+func (this *EnglishCompanyController) List() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	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
+	}
+
+	var startSize int
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	keywords := this.GetString("Keywords", "")
+	sortType, _ := this.GetInt("SortType", 0)
+	sortParam := this.GetString("SortParam", "")
+	strPermissionIds := this.GetString("EnPermissionIds", "")
+
+	var cond, order string
+	var pars []interface{}
+	if keywords != "" {
+		k := "%" + keywords + "%"
+		companyIds, e := models.GetEnCompanyIdsByKeyword(k)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "关键词获取英文客户IDs失败, Err: " + e.Error()
+			return
+		}
+		if len(companyIds) == 0 {
+			page := paging.GetPaging(currentIndex, pageSize, 0)
+			resp := &models.EnglishCompanyPageListResp{
+				Paging: page,
+				List:   make([]*models.EnglishCompanyResp, 0),
+			}
+			br.Ret = 200
+			br.Success = true
+			br.Msg = "获取成功"
+			br.Data = resp
+			return
+		}
+		cond += fmt.Sprintf(` AND c.company_id IN (%s) `, utils.GetOrmInReplace(len(companyIds)))
+		pars = append(pars, companyIds)
+	}
+	// 品种权限
+	if strPermissionIds != "" {
+		permissionIdArr := strings.Split(strPermissionIds, ",")
+		permissionIds := make([]int, 0)
+		for _, s := range permissionIdArr {
+			p, e := strconv.Atoi(s)
+			if e != nil {
+				br.Msg = "品种权限有误"
+				br.ErrMsg = "品种权限筛选有误"
+				return
+			}
+			permissionIds = append(permissionIds, p)
+		}
+		if len(permissionIds) == 0 {
+			br.Msg = "品种权限有误"
+			br.ErrMsg = "品种权限筛选ID为空"
+			return
+		}
+		queryCond := fmt.Sprintf(` AND %s IN (%s)`, models.EnCompanyPermissionColumns.EnPermissionId, utils.GetOrmInReplace(len(permissionIds)))
+		queryPars := make([]interface{}, 0)
+		queryPars = append(queryPars, permissionIds)
+		queryOB := new(models.EnCompanyPermission)
+		queryList, e := queryOB.GetItemsByCondition(queryCond, queryPars, []string{"DISTINCT en_company_id"}, "")
+		if e != nil {
+			br.Msg = "品种筛选有误"
+			br.ErrMsg = "品种筛选失败, Err: " + e.Error()
+			return
+		}
+		companyIds := make([]int, 0)
+		for _, q := range queryList {
+			companyIds = append(companyIds, q.EnCompanyId)
+		}
+		if len(companyIds) == 0 {
+			page := paging.GetPaging(currentIndex, pageSize, 0)
+			resp := &models.EnglishCompanyPageListResp{
+				Paging: page,
+				List:   make([]*models.EnglishCompanyResp, 0),
+			}
+			br.Ret = 200
+			br.Success = true
+			br.Msg = "获取成功"
+			br.Data = resp
+			return
+		}
+		cond += fmt.Sprintf(` AND c.company_id IN (%s) `, utils.GetOrmInReplace(len(companyIds)))
+		pars = append(pars, companyIds)
+	}
+
+	if sortParam == "" {
+		if sortType == 1 {
+			order = ` ORDER BY c.view_total DESC`
+		}
+		if sortType == 2 {
+			order = ` ORDER BY c.view_total ASC`
+		}
+	} else if sortParam == "deadLine" {
+		order = ` ORDER BY todo_end_time asc, c.view_total desc, c.company_id desc`
+	} else if sortParam == "todoStatusStr" {
+		order = ` ORDER BY FIELD (todo_status_str,'进行中','已完成','无任务'), c.view_total desc, c.company_id desc`
+	}
+
+	total, list, e := models.GetEnglishCompanyPageList(cond, pars, order, startSize, pageSize)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文客户列表失败, Err: " + e.Error()
+		return
+	}
+	// 客户列表TODO信息
+	todoMap := services.GetEnglishCompanyListTodoMap(list, sysUser)
+
+	// 品种权限
+	permissionMap := make(map[int][]int)
+	{
+		companyIds := make([]int, 0)
+		for _, v := range list {
+			companyIds = append(companyIds, v.CompanyId)
+		}
+		if len(companyIds) > 0 {
+			cond := fmt.Sprintf(` AND %s IN (%s)`, models.EnCompanyPermissionColumns.EnCompanyId, utils.GetOrmInReplace(len(companyIds)))
+			pars := make([]interface{}, 0)
+			pars = append(pars, companyIds)
+			ob := new(models.EnCompanyPermission)
+			items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取客户权限列表失败, Err: " + e.Error()
+				return
+			}
+			for _, v := range items {
+				if permissionMap[v.EnCompanyId] == nil {
+					permissionMap[v.EnCompanyId] = make([]int, 0)
+				}
+				permissionMap[v.EnCompanyId] = append(permissionMap[v.EnCompanyId], v.EnPermissionId)
+			}
+		}
+	}
+
+	respList := make([]*models.EnglishCompanyResp, 0)
+	for i := range list {
+		respList = append(respList, &models.EnglishCompanyResp{
+			CompanyId:     list[i].CompanyId,
+			CompanyName:   list[i].CompanyName,
+			CountryCode:   list[i].CountryCode,
+			Country:       list[i].Country,
+			SellerId:      list[i].SellerId,
+			SellerName:    list[i].SellerName,
+			ViewTotal:     list[i].ViewTotal,
+			CreateTime:    list[i].CreateTime.Format(utils.FormatDateTime),
+			Enabled:       list[i].Enabled,
+			TodoInfo:      todoMap[list[i].CompanyId],
+			EnPermissions: permissionMap[list[i].CompanyId],
+		})
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := &models.EnglishCompanyPageListResp{
+		Paging: page,
+		List:   respList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 217 - 57
controllers/english_report/report.go

@@ -267,6 +267,23 @@ func (this *EnglishReportController) Detail() {
 	}
 	item.Content = html.UnescapeString(item.Content)
 	item.ContentSub = html.UnescapeString(item.ContentSub)
+	classifyNameMap := make(map[int]*models.EnglishClassifyFullName)
+	if item.ClassifyIdSecond > 0 {
+		nameList, tErr := models.GetEnglishClassifyFullNameByIds([]int{item.ClassifyIdSecond})
+		if tErr != nil {
+			br.Msg = "获取分类名称失败"
+			br.ErrMsg = "获取分类名称失败, ERR:" + tErr.Error()
+			return
+		}
+		for _, v := range nameList {
+			classifyNameMap[v.Id] = v
+		}
+		//处理分类名
+		if n, ok := classifyNameMap[item.ClassifyIdSecond]; ok {
+			item.ClassifyNameRoot = n.RootName
+			item.ClassifyIdRoot = n.RootId
+		}
+	}
 
 	// 获取邮件配置-是否有权限群发
 	conf := new(models.EnglishReportEmailConf)
@@ -351,8 +368,9 @@ func (this *EnglishReportController) ListReport() {
 	startDate := this.GetString("StartDate")
 	endDate := this.GetString("EndDate")
 	frequency := this.GetString("Frequency")
-	classifyNameFirst := this.GetString("ClassifyNameFirst")
-	classifyNameSecond := this.GetString("ClassifyNameSecond")
+	classifyIdFirst, _ := this.GetInt("ClassifyIdFirst")
+	classifyIdSecond, _ := this.GetInt("ClassifyIdSecond")
+	classifyIdRoot, _ := this.GetInt("ClassifyIdRoot")
 	state, _ := this.GetInt("State")
 	keyWord := this.GetString("KeyWord")
 	companyType := this.GetString("CompanyType")
@@ -395,19 +413,48 @@ func (this *EnglishReportController) ListReport() {
 		condition += ` AND frequency = ? `
 		pars = append(pars, frequency)
 	}
-	if classifyNameFirst != "" {
-		condition += ` AND classify_name_first = ? `
-		pars = append(pars, classifyNameFirst)
+	if classifyIdFirst != 0 {
+		condition += ` AND classify_id_first = ? `
+		pars = append(pars, classifyIdFirst)
 	}
 
-	if classifyNameSecond != "" {
-		condition += ` AND classify_name_second = ? `
-		pars = append(pars, classifyNameSecond)
+	if classifyIdSecond != 0 {
+		condition += ` AND classify_id_second = ? `
+		pars = append(pars, classifyIdSecond)
 	}
 	if state > 0 {
 		condition += ` AND state = ? `
 		pars = append(pars, state)
 	}
+
+	if classifyIdRoot > 0 && classifyIdFirst == 0 && classifyIdSecond == 0 {
+		//查询顶级分类下的所有二级分类ID
+		childClassify, err := models.GetEnglishSecondClassifyList([]int{classifyIdRoot})
+		if err != nil {
+			br.Msg = "查询子分类出错"
+			br.ErrMsg = "查询子分类出错, Err:" + err.Error()
+			return
+		}
+		var childClassifyIds []int
+		if len(childClassify) > 0 {
+			for _, v := range childClassify {
+				childClassifyIds = append(childClassifyIds, v.Id)
+			}
+			condition += ` AND classify_id_first IN (` + utils.GetOrmInReplace(len(childClassifyIds)) + `)`
+			pars = append(pars, childClassifyIds)
+		} else {
+			//一级分类下没有子分类,直接返回空列表
+			page := paging.GetPaging(currentIndex, pageSize, 0)
+			resp := new(models.EnglishReportListResp)
+			resp.Paging = page
+			resp.List = make([]*models.EnglishReportList, 0)
+			br.Ret = 200
+			br.Success = true
+			br.Msg = "获取成功"
+			br.Data = resp
+			return
+		}
+	}
 	// 未群发邮件(包含推送邮件失败的)
 	if emailState == 1 {
 		failIds, e := models.GetHasFailEmailLogReportIds()
@@ -486,7 +533,23 @@ func (this *EnglishReportController) ListReport() {
 	for i := range failList {
 		failMap[failList[i].ReportId] = true
 	}
-
+	// 查询分类信息
+	var classifyIdSecondSlice []int
+	for _, item := range list {
+		classifyIdSecondSlice = append(classifyIdSecondSlice, item.ClassifyIdSecond)
+	}
+	classifyNameMap := make(map[int]*models.EnglishClassifyFullName)
+	if len(classifyIdSecondSlice) > 0 {
+		nameList, err := models.GetEnglishClassifyFullNameByIds(classifyIdSecondSlice)
+		if err != nil {
+			br.Msg = "获取分类名称失败"
+			br.ErrMsg = "获取分类名称失败, ERR:" + err.Error()
+			return
+		}
+		for _, v := range nameList {
+			classifyNameMap[v.Id] = v
+		}
+	}
 	for _, item := range list {
 		if item.State == 2 {
 			item.ShareUrl = "https://share.hzinsights.com/reportEn?code=" + item.ReportCode
@@ -523,6 +586,16 @@ func (this *EnglishReportController) ListReport() {
 		} else {
 			item.Editor = markStatus.Editor
 		}
+		//处理分类名
+		if n, ok := classifyNameMap[item.ClassifyIdSecond]; ok {
+			if n.RootId == 0 {
+				item.FullClassifyName = strings.Join([]string{n.ParentName, n.ClassifyName}, "/")
+			} else {
+				item.FullClassifyName = strings.Join([]string{n.RootName, n.ParentName, n.ClassifyName}, "/")
+			}
+			item.ClassifyIdRoot = n.RootId
+			item.ClassifyNameRoot = n.RootName
+		}
 	}
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(models.EnglishReportListResp)
@@ -534,6 +607,7 @@ func (this *EnglishReportController) ListReport() {
 	br.Data = resp
 }
 
+// ListClassify
 // @Title 获取分类列表
 // @Description 获取分类列表
 // @Param   PageSize   query   int  true       "每页数据条数"
@@ -551,7 +625,6 @@ func (this *EnglishReportController) ListClassify() {
 	pageSize, _ := this.GetInt("PageSize")
 	currentIndex, _ := this.GetInt("CurrentIndex")
 	keyWord := this.GetString("KeyWord")
-	classifyType, _ := this.GetInt("ClassifyType", 0)
 
 	var startSize int
 	if pageSize <= 0 {
@@ -566,13 +639,21 @@ func (this *EnglishReportController) ListClassify() {
 	page := paging.GetPaging(currentIndex, pageSize, 0)
 	resp := new(models.EnglishClassifyListResp)
 
-	list, err := models.GetEnglishClassifyList(startSize, pageSize, keyWord, classifyType)
+	// 处理一级分类分页的情况
+	rootList, err := models.GetEnglishClassifyRootId(startSize, pageSize, keyWord)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
-	total, err := models.GetEnglishClassifyListCount(keyWord, classifyType)
+	var ids []int
+	var rootIds []int
+	rootMap := make(map[int]struct{}, 0)
+	for _, v := range rootList {
+		rootIds = append(rootIds, v.Id)
+		rootMap[v.Id] = struct{}{}
+	}
+	total, err := models.GetEnglishClassifyListCount(keyWord)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败,Err:" + err.Error()
@@ -588,37 +669,100 @@ func (this *EnglishReportController) ListClassify() {
 		br.Msg = "获取成功"
 		return
 	}
-	var parentIds []int
-	for _, v := range list {
-		parentIds = append(parentIds, v.Id)
-	}
+	page = paging.GetPaging(currentIndex, pageSize, total)
 
-	childMap := make(map[int][]*models.EnglishClassify)
-	tmpList, err := models.GetEnglishClassifyChildByParentIds(parentIds, keyWord, classifyType)
+	//获取相关的分类ID
+	idList, err := models.GetEnglishClassifyListByRootId(rootIds, keyWord)
 	if err != nil {
-		br.Msg = "获取二级分类失败"
-		br.ErrMsg = "获取二级分类失败,Err:" + err.Error()
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
+	secondListMap := make(map[int][]*models.EnglishClassifyList)
+	thirdListMap := make(map[int][]*models.EnglishClassifyList)
+	var thirdIds []int
+	var sortChildList models.RSChildClassifyList
+	// 三级分类-品种权限
+	permissionMap := make(map[int][]int)
 
-	for _, v := range tmpList {
-		childMap[v.ParentId] = append(childMap[v.ParentId], v)
-	}
-	for _, v := range list {
-		if child, ok := childMap[v.Id]; ok {
-			v.Child = child
+	if len(idList) > 0 {
+		childIdMap := make(map[int]struct{}, 0)
+		for _, v := range idList {
+			if _, ok := childIdMap[v.ParentId]; !ok {
+				ids = append(ids, v.ParentId)
+			}
+			if _, ok := childIdMap[v.Id]; !ok {
+				ids = append(ids, v.Id)
+			}
+		}
+		tmpList, err := models.GetEnglishClassifyChildByIds(ids)
+		if err != nil {
+			br.Msg = "获取二级分类失败"
+			br.ErrMsg = "获取二级分类失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range tmpList {
+			if _, ok := rootMap[v.ParentId]; !ok {
+				thirdIds = append(thirdIds, v.Id)
+			}
+		}
+		{
+			classifyIds := thirdIds
+			if len(classifyIds) > 0 {
+				cond := fmt.Sprintf(` AND %s IN (%s)`, models.EnClassifyPermissionColumns.EnClassifyId, utils.GetOrmInReplace(len(classifyIds)))
+				pars := make([]interface{}, 0)
+				pars = append(pars, classifyIds)
+				ob := new(models.EnClassifyPermission)
+				items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
+				if e != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取客户权限列表失败, Err: " + e.Error()
+					return
+				}
+				for _, v := range items {
+					if permissionMap[v.EnClassifyId] == nil {
+						permissionMap[v.EnClassifyId] = make([]int, 0)
+					}
+					permissionMap[v.EnClassifyId] = append(permissionMap[v.EnClassifyId], v.EnPermissionId)
+				}
+			}
+		}
+		// 处理三级分类
+		for _, v := range tmpList {
+			if _, ok := rootMap[v.ParentId]; !ok {
+				if p, ok1 := permissionMap[v.Id]; ok1 {
+					v.EnPermissions = p
+				}
+				thirdListMap[v.ParentId] = append(thirdListMap[v.ParentId], v)
+			}
+		}
+
+		//处理二级分类
+		for _, v := range tmpList {
+			if _, ok := rootMap[v.ParentId]; ok {
+				if child, ok1 := thirdListMap[v.Id]; ok1 {
+					sortChildList = child
+					sort.Sort(sortChildList)
+					v.Child = sortChildList
+				}
+				secondListMap[v.ParentId] = append(secondListMap[v.ParentId], v)
+			}
 		}
 	}
+
+	//处理一级分类
 	var sortList models.RSClassifyList
-	sortList = list
+	for _, v := range rootList {
+		if child, ok := secondListMap[v.Id]; ok {
+			sortChildList = child
+			sort.Sort(sortChildList)
+			v.Child = sortChildList
+		}
+		sortList = append(sortList, v)
+	}
+
 	sort.Sort(sortList)
 
-	for _, item := range sortList {
-		var sortChildList models.RSChildClassifyList
-		sortChildList = item.Child
-		sort.Sort(sortChildList)
-		item.Child = sortChildList
-	}
 	resp.List = sortList
 	resp.Paging = page
 
@@ -668,32 +812,30 @@ func (this *EnglishReportController) DelClassify() {
 		return
 	}
 
-	if classifyInfo.ClassifyType == 0 {
-		reportCount, e := models.GetEnglishReportCounts(classifyId, classifyInfo.ParentId)
-		if e != nil && e.Error() != utils.ErrNoRow() {
-			br.Msg = "获取信息失败"
-			br.ErrMsg = "获取失败,Err:" + e.Error()
-			return
-		}
+	reportCount, e := models.GetEnglishReportCounts(classifyId, classifyInfo.ParentId)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		br.Msg = "获取信息失败"
+		br.ErrMsg = "获取失败,Err:" + e.Error()
+		return
+	}
 
-		if reportCount > 0 {
-			br.Msg = "该分类有关联报告,不允许删除"
-			br.Ret = 403
-			return
-		}
-	} else {
-		videoCount, e := models.GetEnglishVideoCounts(classifyId, classifyInfo.ParentId)
-		if e != nil && e.Error() != utils.ErrNoRow() {
-			br.Msg = "获取信息失败"
-			br.ErrMsg = "获取失败,Err:" + e.Error()
-			return
-		}
+	if reportCount > 0 {
+		br.Msg = "该分类有关联报告,不允许删除"
+		br.Ret = 403
+		return
+	}
 
-		if videoCount > 0 {
-			br.Msg = "该分类有关联的路演视频,不允许删除"
-			br.Ret = 403
-			return
-		}
+	videoCount, e := models.GetEnglishVideoCounts(classifyId, classifyInfo.ParentId)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		br.Msg = "获取信息失败"
+		br.ErrMsg = "获取失败,Err:" + e.Error()
+		return
+	}
+
+	if videoCount > 0 {
+		br.Msg = "该分类有关联的路演视频,不允许删除"
+		br.Ret = 403
+		return
 	}
 
 	if err = models.DeleteEnglishClassify(classifyId); err != nil {
@@ -1070,7 +1212,25 @@ func (this *EnglishReportController) ClassifyIdDetail() {
 	if item != nil {
 		item.Content = html.UnescapeString(item.Content)
 		item.ContentSub = html.UnescapeString(item.ContentSub)
+		classifyNameMap := make(map[int]*models.EnglishClassifyFullName)
+		if item.ClassifyIdSecond > 0 {
+			nameList, tErr := models.GetEnglishClassifyFullNameByIds([]int{item.ClassifyIdSecond})
+			if tErr != nil {
+				br.Msg = "获取分类名称失败"
+				br.ErrMsg = "获取分类名称失败, ERR:" + tErr.Error()
+				return
+			}
+			for _, v := range nameList {
+				classifyNameMap[v.Id] = v
+			}
+			//处理分类名
+			if n, ok := classifyNameMap[item.ClassifyIdSecond]; ok {
+				item.ClassifyNameRoot = n.RootName
+				item.ClassifyIdRoot = n.RootId
+			}
+		}
 	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 162 - 66
controllers/report.go

@@ -142,27 +142,27 @@ func (this *ReportController) ListReport() {
 				syncReportIdArr = append(syncReportIdArr, strconv.Itoa(list[i].OldReportId))
 			}
 		}
-		reportIds := strings.Join(reportIdArr, ",")
-		syncReportIds := strings.Join(syncReportIdArr, ",")
 
 		// 查询同步过来的报告对应的老报告PV+UV
 		pvMap := make(map[int]int, 0)
 		uvMap := make(map[int]int, 0)
-		if syncReportIds != "" {
-			puvList, e := models.GetPUVByResearchReportIds(syncReportIds)
-			if e != nil {
-				br.Msg = "获取失败"
-				br.ErrMsg = "获取同步报告对应的PV、UV失败, Err: " + e.Error()
-				return
-			}
-			puvLen := len(puvList)
-			for i := 0; i < puvLen; i++ {
-				pvMap[puvList[i].ResearchReportId] = puvList[i].Pv
-				uvMap[puvList[i].ResearchReportId] = puvList[i].Uv
+		if len(syncReportIdArr) > 0 {
+			if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+				puvList, e := models.GetPUVByResearchReportIds(syncReportIdArr)
+				if e != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取同步报告对应的PV、UV失败, Err: " + e.Error()
+					return
+				}
+				puvLen := len(puvList)
+				for i := 0; i < puvLen; i++ {
+					pvMap[puvList[i].ResearchReportId] = puvList[i].Pv
+					uvMap[puvList[i].ResearchReportId] = puvList[i].Uv
+				}
 			}
 		}
 		// 晨周报音频列表
-		videoList, err := models.GetReportChapterVideoListByReportIds(reportIds)
+		videoList, err := models.GetReportChapterVideoListByReportIds(reportIdArr)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取报告音频文件失败,Err:" + err.Error()
@@ -481,21 +481,25 @@ func (this *ReportController) Add() {
 		br.ErrMsg = "保存失败,Err:" + err.Error()
 		return
 	}
-	//处理权限
-	{
-		permissionItems, err := models.GetPermission(req.ClassifyNameSecond)
-		if err != nil {
-			go alarm_msg.SendAlarmMsg("获取权限失败,Err:"+err.Error(), 3)
-			//utils.SendEmail(utils.APPNAME+"失败提醒", "获取权限失败,Err:"+err.Error(), utils.EmailSendToUsers)
-		}
-		for _, v := range permissionItems {
-			err = models.AddChartPermissionChapterMapping(v.ChartPermissionId, newReportId)
-			if err != nil {
-				go alarm_msg.SendAlarmMsg("新增权限失败,Err:"+err.Error(), 3)
-				//utils.SendEmail(utils.APPNAME+"失败提醒", "新增权限失败,Err:"+err.Error()+strconv.FormatInt(newReportId, 10), utils.EmailSendToUsers)
+
+	// 处理权限
+	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+		go func() {
+			permissionItems, e := models.GetPermission(req.ClassifyNameSecond)
+			if e != nil {
+				alarm_msg.SendAlarmMsg("获取权限失败,Err:"+e.Error(), 3)
+				return
 			}
-		}
+			for _, v := range permissionItems {
+				e = models.AddChartPermissionChapterMapping(v.ChartPermissionId, newReportId)
+				if e != nil {
+					alarm_msg.SendAlarmMsg("新增权限失败,Err:"+e.Error(), 3)
+					return
+				}
+			}
+		}()
 	}
+
 	reportCode := utils.MD5(strconv.Itoa(int(newReportId)))
 	//修改唯一编码
 	{
@@ -601,26 +605,30 @@ func (this *ReportController) Edit() {
 		br.ErrMsg = "保存失败,Err:" + err.Error()
 		return
 	}
+
 	//处理权限
-	{
-		err = models.RemoveChartPermissionChapterMapping(req.ReportId)
-		if err != nil {
-			go alarm_msg.SendAlarmMsg("修改删除报告权限失败,Err:"+err.Error(), 3)
-			//utils.SendEmail(utils.APPNAME+"失败提醒", "修改删除报告权限失败,Err:"+err.Error(), utils.EmailSendToUsers)
-		}
-		permissionItems, err := models.GetPermission(req.ClassifyNameSecond)
-		if err != nil {
-			go alarm_msg.SendAlarmMsg("获取权限失败,Err:"+err.Error(), 3)
-			//utils.SendEmail(utils.APPNAME+"失败提醒", "获取权限失败,Err:"+err.Error(), utils.EmailSendToUsers)
-		}
-		for _, v := range permissionItems {
-			err = models.AddChartPermissionChapterMapping(v.ChartPermissionId, req.ReportId)
-			if err != nil {
-				go alarm_msg.SendAlarmMsg("新增权限失败,Err:"+err.Error(), 3)
-				//utils.SendEmail(utils.APPNAME+"失败提醒", "新增权限失败,Err:"+err.Error()+strconv.FormatInt(req.ReportId, 10), utils.EmailSendToUsers)
+	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+		go func() {
+			e := models.RemoveChartPermissionChapterMapping(req.ReportId)
+			if e != nil {
+				alarm_msg.SendAlarmMsg("修改删除报告权限失败,Err:"+e.Error(), 3)
+				return
 			}
-		}
+			permissionItems, e := models.GetPermission(req.ClassifyNameSecond)
+			if e != nil {
+				alarm_msg.SendAlarmMsg("获取权限失败,Err:"+e.Error(), 3)
+				return
+			}
+			for _, v := range permissionItems {
+				e = models.AddChartPermissionChapterMapping(v.ChartPermissionId, req.ReportId)
+				if e != nil {
+					alarm_msg.SendAlarmMsg("新增权限失败,Err:"+e.Error(), 3)
+					return
+				}
+			}
+		}()
 	}
+
 	reportCode := utils.MD5(strconv.Itoa(int(req.ReportId)))
 	resp := new(models.EditResp)
 	resp.ReportId = req.ReportId
@@ -682,11 +690,14 @@ func (this *ReportController) Detail() {
 		if len(tmpChapterList) > 0 {
 			// 获取更新规则
 			researchType := tmpChapterList[0].ReportType
-			chapterTypeList, tmpErr := models.GetAllReportChapterTypeListByResearchType(researchType)
-			if tmpErr != nil {
-				br.Msg = "获取更新规则失败"
-				br.ErrMsg = "获取更新规则失败, Err: " + tmpErr.Error()
-				return
+			chapterTypeList := make([]*models.ReportChapterType, 0)
+			if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+				chapterTypeList, err = models.GetAllReportChapterTypeListByResearchType(researchType)
+				if err != nil {
+					br.Msg = "获取更新规则失败"
+					br.ErrMsg = "获取更新规则失败, Err: " + err.Error()
+					return
+				}
 			}
 			// 调整章节更新
 			nowTime := time.Now().Local()
@@ -762,7 +773,7 @@ func (this *ReportController) Upload() {
 	ext := path.Ext(h.Filename)
 	dateDir := time.Now().Format("20060102")
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
-	err = os.MkdirAll(uploadDir, 777)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
 		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
@@ -778,12 +789,23 @@ func (this *ReportController) Upload() {
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		return
 	}
-	//上传到阿里云
-	resourceUrl, err := services.UploadAliyun(fileName, fpath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		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
+		}
 	}
 
 	defer func() {
@@ -994,7 +1016,7 @@ func (this *ReportUploadCommonController) UploadImg() {
 	ext := path.Ext(h.Filename)
 	dateDir := time.Now().Format("20060102")
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
-	err = os.MkdirAll(uploadDir, 777)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		return
 	}
@@ -1006,10 +1028,18 @@ func (this *ReportUploadCommonController) UploadImg() {
 	if err != nil {
 		return
 	}
-	//上传到阿里云
-	resourceUrl, err := services.UploadAliyun(fileName, fpath)
-	if err != nil {
-		return
+	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
+		}
 	}
 
 	defer func() {
@@ -1351,11 +1381,14 @@ func (this *ReportController) GetReportChapterList() {
 	if len(chapterList) > 0 {
 		// 获取更新规则
 		researchType := chapterList[0].ReportType
-		chapterTypeList, tmpErr := models.GetAllReportChapterTypeListByResearchType(researchType)
-		if tmpErr != nil {
-			br.Msg = "获取更新规则失败"
-			br.ErrMsg = "获取更新规则失败, Err: " + tmpErr.Error()
-			return
+		chapterTypeList := make([]*models.ReportChapterType, 0)
+		if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+			chapterTypeList, err = models.GetAllReportChapterTypeListByResearchType(researchType)
+			if err != nil {
+				br.Msg = "获取更新规则失败"
+				br.ErrMsg = "获取更新规则失败, Err: " + err.Error()
+				return
+			}
 		}
 		// 调整章节更新
 		nowTime := time.Now().Local()
@@ -1637,6 +1670,12 @@ func (this *ReportController) GetChapterTrendTag() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	list, err := models.GetKeyWordListByFrom("trend")
 	if err != nil {
@@ -1670,6 +1709,12 @@ func (this *ReportController) EditChapterTrendTag() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	var req models.EditChapterTrendTagReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -1834,6 +1879,12 @@ func (this *ReportController) IsLastDayWeekReportChapter() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	reportChapterId, _ := this.GetInt("ReportChapterId")
 	if reportChapterId <= 0 {
@@ -1890,6 +1941,12 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	var req models.PublishReportChapterReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -1930,6 +1987,11 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 		br.ErrMsg = "查询报告信息失败, Err: " + err.Error()
 		return
 	}
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
 
 	// 获取规则配置
 	reportChapterTypeRule, err := models.GetReportChapterTypeById(chapterInfo.TypeId)
@@ -1948,6 +2010,7 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 	updateCols := make([]string, 0)
 	updateCols = append(updateCols, "Title", "AddType", "Author", "Content", "ContentSub", "IsEdit", "CreateTime", "PublishState", "PublishTime")
 
+	var needHandleVideo bool // 是否需要处理音频文件
 	nowTime := time.Now()
 	var publishTime time.Time
 	if reportInfo.MsgIsSend == 1 && reportInfo.PublishTime != "" { //如果报告曾经发布过,并且已经发送过模版消息,则章节的发布时间为报告的发布时间
@@ -1963,6 +2026,9 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 		chapterInfo.VideoKind = 1
 
 		updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds", "VideoKind")
+
+		// 手动上传的音频需要处理音频文件
+		needHandleVideo = true
 	} else {
 		if chapterInfo.VideoUrl == "" {
 			// 生成video
@@ -2041,6 +2107,11 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 		}
 	}
 
+	// 处理报告中的音频文件分贝
+	if needHandleVideo {
+		go services.HandleVideoDecibel(chapterInfo)
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"
@@ -2064,6 +2135,12 @@ func (this *ReportController) PublishDayWeekReport() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	var req models.PublishDayWeekReportReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -2123,6 +2200,13 @@ func (this *ReportController) GetSunCode() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
 	var req models.SunCodeReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -2177,6 +2261,12 @@ func (this *ReportController) GetStopDayWeekReportChapterTypeList() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	stopDay := make([]*models.ReportChapterType, 0)
 	stopWeek := make([]*models.ReportChapterType, 0)
@@ -2388,6 +2478,12 @@ func (this *ReportController) CheckDayWeekReportChapterVideo() {
 		br.Ret = 408
 		return
 	}
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
 
 	reqReportId := this.GetString("ReportId")
 	reportId, _ := strconv.Atoi(reqReportId)

+ 117 - 47
controllers/resource.go

@@ -44,7 +44,7 @@ func (this *ResourceController) Upload() {
 	ext := path.Ext(h.Filename)
 	dateDir := time.Now().Format("20060102")
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
-	err = os.MkdirAll(uploadDir, 766)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
 		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
@@ -60,12 +60,22 @@ func (this *ResourceController) Upload() {
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		return
 	}
-	//上传到阿里云
-	resourceUrl, err := services.UploadAliyun(fileName, fpath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		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
+		}
 	}
 
 	defer func() {
@@ -120,7 +130,7 @@ func (this *ResourceController) VideoUpload() {
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
 	//uploadDir := "./" + dateDir
 	fmt.Println(uploadDir)
-	err = os.MkdirAll(uploadDir, 777)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
 		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
@@ -231,16 +241,28 @@ func (this *ResourceController) VideoUpload() {
 
 	savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
 	savePath += fileName
-	//上传到阿里云
-	err = services.UploadVideoAliyun(fileName, fpath, savePath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		return
+
+	//上传到阿里云 和 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
 	}
 	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
 	utils.FileLog.Info("end update oss ")
-	resourceUrl := utils.Imghost + savePath
 
 	item := new(models.Resource)
 	item.ResourceUrl = resourceUrl
@@ -303,7 +325,7 @@ func (this *ResourceController) VoiceUpload() {
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
 	//uploadDir := "./" + dateDir
 	fmt.Println(uploadDir)
-	err = os.MkdirAll(uploadDir, 766)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
 		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
@@ -396,16 +418,27 @@ func (this *ResourceController) VoiceUpload() {
 
 	savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
 	savePath += fileName
-	//上传到阿里云
-	err = services.UploadVideoAliyun(fileName, fpath, savePath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		return
+	//上传到阿里云 和 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
 	}
 	utils.FileLog.Info(fmt.Sprintf("%s:", time.Now().Format(utils.FormatDateTime)))
 	utils.FileLog.Info("end update oss ")
-	resourceUrl := utils.Imghost + savePath
 
 	item := new(models.Resource)
 	item.ResourceUrl = resourceUrl
@@ -548,18 +581,29 @@ func (this *ResourceController) UploadImageBase64() {
 	hzUploadDir := "static/images/"
 	savePath := hzUploadDir + time.Now().Format("200601/20060102/")
 	savePath += fileName
-	//上传到阿里云
-	err = services.UploadFileToAliyun(fileName, fpath, savePath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		return
+
+	//上传到阿里云 和 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
 	}
 	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
 	utils.FileLog.Info("end update oss ")
 
-	resourceUrl := utils.Imghost + savePath
-
 	item := new(models.Resource)
 	item.ResourceUrl = resourceUrl
 	item.ResourceType = 1
@@ -663,7 +707,7 @@ func (this *ResourceController) UploadV2() {
 	ext := path.Ext(h.Filename)
 	dateDir := time.Now().Format("20060102")
 	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
-	err = os.MkdirAll(uploadDir, 766)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
 		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
@@ -679,12 +723,22 @@ func (this *ResourceController) UploadV2() {
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		return
 	}
-	//上传到阿里云
-	resourceUrl, err := services.UploadAliyun(fileName, fpath)
-	if err != nil {
-		br.Msg = "文件上传失败"
-		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-		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
+		}
 	}
 
 	defer func() {
@@ -722,16 +776,32 @@ func (this *ResourceController) OssSTSToken() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
-	resp, err := services.GetOssSTSToken()
-	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取STSToken失败, Err: " + err.Error()
-		return
+
+	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
 	}
-	br.Msg = "获取成功"
-	br.Ret = 200
-	br.Success = true
-	br.Data = resp
 }
 
 // WechatWarning 小程序前端预警提示

+ 2 - 2
controllers/semantic_analysis/sa_compare.go

@@ -1,12 +1,12 @@
 package semantic_analysis
 
 import (
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"eta/eta_mobile/controllers"
 	"eta/eta_mobile/models"
 	saModel "eta/eta_mobile/models/semantic_analysis"
 	"eta/eta_mobile/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // SaCompareController 语义分析-文档比对

+ 127 - 0
controllers/sys_role.go

@@ -0,0 +1,127 @@
+package controllers
+
+import (
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/models/company"
+	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/utils"
+)
+
+type SysRoleController struct {
+	BaseAuthController
+}
+
+// ButtonList
+// @Title 角色-按钮权限列表
+// @Description 角色-按钮权限列表
+// @Param   RoleId   query   int  true       "角色Id"
+// @Success 200 {object} system.SysRoleListResp
+// @router /role/menu/buttons [get]
+func (this *SysRoleController) ButtonList() {
+	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
+	}
+
+	roleId := sysUser.RoleId
+	list, e := system.GetMenuButtonsByRoleId(roleId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取角色按钮权限失败, Err: " + e.Error()
+		return
+	}
+
+	buttonList := make([]*system.SysMenuButtonResp, 0)
+	for _, v := range list {
+		tmp := new(system.SysMenuButtonResp)
+		tmp.MenuId = v.MenuId
+		tmp.ParentId = v.ParentId
+		tmp.MenuType = v.MenuType
+		tmp.Name = v.Name
+		tmp.ButtonCode = v.ButtonCode
+		buttonList = append(buttonList, tmp)
+	}
+
+	br.Data = buttonList
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// SystemConfig
+// @Title 系统配置列表
+// @Description 系统配置列表
+// @Success 200 {object} []system.BusinessConf
+// @router /config [get]
+func (this *SysRoleController) SystemConfig() {
+	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([]system.BusinessConf, 0)
+
+	// 获取基础配置, 若未配置则直接返回
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取基础配置失败, Err: " + e.Error()
+		return
+	}
+
+	list = append(list, system.BusinessConf{
+		ConfKey: "ReportViewUrl",
+		ConfVal: conf["ReportViewUrl"],
+	}, system.BusinessConf{
+		ConfKey: "ChartViewUrl",
+		ConfVal: conf["ChartViewUrl"],
+	})
+
+	osc := system.BusinessConf{
+		ConfKey: "ObjectStorageClient",
+		ConfVal: utils.ObjectStorageClient,
+	}
+	if osc.ConfVal == "" {
+		osc.ConfVal = "oss"
+	}
+	list = append(list, osc)
+
+	// 获取审批流设置
+	confKey := "approval_flow"
+	confTmp, e := company.GetConfigDetailByCode(confKey)
+	if e != nil {
+		br.Msg = "获取审批流配置失败"
+		br.ErrMsg = "获取审批流配置失败, Err: " + e.Error()
+		return
+	}
+	list = append(list, system.BusinessConf{
+		ConfKey: "ApprovalFlow",
+		ConfVal: confTmp.ConfigValue,
+	})
+
+	br.Data = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 14 - 6
go.mod

@@ -16,13 +16,14 @@ require (
 	github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b
 	github.com/gorilla/websocket v1.4.2
 	github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53
+	github.com/minio/minio-go/v7 v7.0.63
 	github.com/mojocn/base64Captcha v1.3.5
 	github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19
 	github.com/olivere/elastic/v7 v7.0.30
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/shopspring/decimal v1.3.1
 	github.com/silenceper/wechat/v2 v2.1.4
-	github.com/sirupsen/logrus v1.9.0
+	github.com/sirupsen/logrus v1.9.3
 	github.com/tealeg/xlsx v1.0.5
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.655
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.655
@@ -46,6 +47,7 @@ require (
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/clbanning/mxj/v2 v2.5.5 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/garyburd/redigo v1.6.3 // indirect
 	github.com/go-redis/redis/v8 v8.11.5 // indirect
@@ -57,13 +59,18 @@ require (
 	github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect
 	github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9 // indirect
 	github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 // indirect
+	github.com/google/uuid v1.3.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.16.7 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+	github.com/minio/md5-simd v1.1.2 // indirect
+	github.com/minio/sha256-simd v1.0.1 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -76,6 +83,7 @@ require (
 	github.com/prometheus/procfs v0.8.0 // indirect
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
+	github.com/rs/xid v1.5.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
 	github.com/spf13/cast v1.4.1 // indirect
 	github.com/tidwall/gjson v1.14.1 // indirect
@@ -84,15 +92,15 @@ require (
 	github.com/tjfoc/gmsm v1.3.2 // 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.8.0 // indirect
+	golang.org/x/crypto v0.12.0 // indirect
 	golang.org/x/image v0.5.0 // indirect
-	golang.org/x/net v0.9.0 // indirect
-	golang.org/x/sys v0.7.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
+	golang.org/x/net v0.14.0 // indirect
+	golang.org/x/sys v0.11.0 // indirect
+	golang.org/x/text v0.12.0 // indirect
 	golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
-	gopkg.in/ini.v1 v1.66.2 // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	xorm.io/builder v0.3.6 // indirect

+ 29 - 6
go.sum

@@ -128,6 +128,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
@@ -253,6 +255,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
 github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -294,6 +298,11 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
 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=
+github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
+github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+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=
@@ -313,6 +322,12 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
+github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
+github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ=
+github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4=
+github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
+github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -406,6 +421,8 @@ github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTK
 github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
 github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
@@ -420,8 +437,9 @@ github.com/silenceper/wechat/v2 v2.1.4/go.mod h1:F0PKqImb15THnwoqRNrZO1z3vpwyWui
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
-github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
@@ -504,8 +522,9 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
 golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
+golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
+golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -585,8 +604,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
 golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
+golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -656,8 +676,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
 golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -670,8 +691,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -824,8 +846,9 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp
 gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
 gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
 gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
 gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 3 - 0
log/api/apilog.log


+ 167 - 0
models/business_conf.go

@@ -0,0 +1,167 @@
+package models
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"html"
+	"strings"
+	"time"
+)
+
+const (
+	BusinessConfUseXf          = "UseXf"
+	BusinessConfXfAppid        = "XfAppid"
+	BusinessConfXfApiKey       = "XfApiKey"
+	BusinessConfXfApiSecret    = "XfApiSecret"
+	BusinessConfXfVcn          = "XfVcn"
+	BusinessConfEnPptCoverImgs = "EnPptCoverImgs"
+)
+
+// BusinessConf 商户配置表
+type BusinessConf struct {
+	Id         int    `orm:"column(id);pk"`
+	ConfKey    string `description:"配置Key"`
+	ConfVal    string `description:"配置值"`
+	ValType    int    `description:"1-字符串;2-数值;3-字符串数组;4-富文本;"`
+	Necessary  int    `description:"是否必填:0-否;1-是"`
+	Remark     string `description:"备注"`
+	CreateTime time.Time
+}
+
+func (m *BusinessConf) TableName() string {
+	return "business_conf"
+}
+
+func (m *BusinessConf) PrimaryId() string {
+	return "id"
+}
+
+func (m *BusinessConf) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.Id = int(id)
+	return
+}
+
+func (m *BusinessConf) CreateMulti(items []*BusinessConf) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *BusinessConf) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *BusinessConf) Del() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.Id).Exec()
+	return
+}
+
+func (m *BusinessConf) GetItemById(id int) (item *BusinessConf, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *BusinessConf) GetItemByCondition(condition string, pars []interface{}) (item *BusinessConf, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s LIMIT 1`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *BusinessConf) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *BusinessConf) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*BusinessConf, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *BusinessConf) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*BusinessConf, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetBusinessConf 获取商家配置
+func GetBusinessConf() (list map[string]string, err error) {
+	list = make(map[string]string)
+
+	var items []*BusinessConf
+	o := orm.NewOrm()
+	sql := `SELECT * FROM business_conf`
+	_, err = o.Raw(sql).QueryRows(&items)
+	if err != nil {
+		return
+	}
+
+	for _, v := range items {
+		if v.ValType == 4 {
+			list[v.ConfKey] = html.UnescapeString(v.ConfVal)
+			continue
+		}
+		list[v.ConfKey] = v.ConfVal
+	}
+	return
+}
+
+// BusinessConfUpdate 更新配置
+type BusinessConfUpdate struct {
+	ConfKey string
+	ConfVal string
+}
+
+// UpdateBusinessConfMulti 批量修改配置
+func UpdateBusinessConfMulti(items []BusinessConfUpdate) (err error) {
+	o := orm.NewOrm()
+	p, err := o.Raw("UPDATE business_conf SET conf_val = ? WHERE conf_key = ?").Prepare()
+	if err != nil {
+		return
+	}
+	defer func() {
+		_ = p.Close()
+	}()
+	for _, v := range items {
+		_, err = p.Exec(v.ConfVal, v.ConfKey)
+		if err != nil {
+			return
+		}
+	}
+	return
+}

+ 108 - 0
models/business_conf_operation_record.go

@@ -0,0 +1,108 @@
+package models
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// BusinessConfOperationRecord 商户配置操作记录表
+type BusinessConfOperationRecord struct {
+	Id          int       `orm:"column(id);pk"`
+	SysUserId   int       `description:"操作人ID"`
+	SysRealName string    `description:"操作人姓名"`
+	Content     string    `description:"操作数据"`
+	CreateTime  time.Time `description:"操作时间"`
+}
+
+func (m *BusinessConfOperationRecord) TableName() string {
+	return "business_conf_operation_record"
+}
+
+func (m *BusinessConfOperationRecord) PrimaryId() string {
+	return "id"
+}
+
+func (m *BusinessConfOperationRecord) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.Id = int(id)
+	return
+}
+
+func (m *BusinessConfOperationRecord) CreateMulti(items []*BusinessConfOperationRecord) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *BusinessConfOperationRecord) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *BusinessConfOperationRecord) Del() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.Id).Exec()
+	return
+}
+
+func (m *BusinessConfOperationRecord) GetItemById(id int) (item *BusinessConfOperationRecord, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *BusinessConfOperationRecord) GetItemByCondition(condition string, pars []interface{}) (item *BusinessConfOperationRecord, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s LIMIT 1`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *BusinessConfOperationRecord) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *BusinessConfOperationRecord) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*BusinessConfOperationRecord, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *BusinessConfOperationRecord) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*BusinessConfOperationRecord, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 124 - 0
models/company/company_permission.go

@@ -0,0 +1,124 @@
+package company
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ChartPermission struct {
+	ChartPermissionId   int       `description:"权限id"`
+	ChartPermissionName string    `description:"权限名称(旧)"`
+	PermissionName      string    `description:"权限名称"`
+	Sort                int       `description:"排序"`
+	Enabled             int       `description:"是否可用"`
+	CreatedTime         time.Time `description:"创建时间"`
+	LastUpdatedTime     time.Time `description:"最后更新时间"`
+	TeleconferenceSort  int       `description:"电话会排序"`
+	Remark              string    `description:"备注"`
+	ClassifyName        string    `description:"分类"`
+	PermissionType      int       `description:"1主观,2客观"`
+	Checked             bool      `description:"选中状态"`
+}
+
+type PermissionSetItem struct {
+	ChartPermissionId int                  `description:"权限id"`
+	PermissionName    string               `description:"权限名称"`
+	PermissionType    int                  `description:"1主观,2客观"`
+	Checked           bool                 `description:"选中状态"`
+	Child             []*PermissionSetItem `description:"具体的主客观-方便前端的排版用的"`
+}
+
+type PermissionSetItemType struct {
+	PermissionName string `description:"权限名称"`
+	Checked        bool   `description:"选中状态"`
+	CheckedMinate  bool   `description:"不确定状态"`
+	NoClicking     bool   `description:"是否禁止点击"`
+	Items          []*PermissionLookItem
+}
+
+type PermissionSetList struct {
+	ClassifyName string `description:"分类"`
+	Items        []*PermissionSetItem
+	CheckList    []int
+}
+
+type PermissionSetListType struct {
+	ClassifyName string `description:"分类"`
+	Items        []*PermissionSetItemType
+	CheckList    []int
+}
+
+type PermissionSetResp struct {
+	List []*PermissionSetList
+	//ListUpgrade []*PermissionSetList     `description:"升级权限列表"`
+	ListType []*PermissionSetListType `description:"主观客观列表"`
+}
+
+func GetPermissionSetItems(productId int, classifyName string) (items []*PermissionSetItem, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := ` SELECT * FROM chart_permission WHERE enabled=1 AND product_id=? AND classify_name=?  AND permission_type=0 ORDER BY sort ASC `
+	_, err = o.Raw(sql, productId, classifyName).QueryRows(&items)
+	return
+}
+
+type PermissionLookItem struct {
+	ChartPermissionId  int                   `description:"权限id"`
+	PermissionName     string                `description:"权限名称"`
+	StartDate          string                `description:"权限开始日期"`
+	EndDate            string                `description:"权限结束日期"`
+	Status             string                `description:"'正式','试用','关闭'"`
+	ExpireDay          string                `description:"到期天数"`
+	ClassifyName       string                `description:"分类"`
+	PermissionType     int                   `description:"1主观,2客观"`
+	PermissionTypeName string                `description:"主观、客观"`
+	Checked            bool                  `description:"选中状态"`
+	Remark             string                `description:"备注"`
+	IsMerge            bool                  `description:"是否合并行业, 给前端的标识, 暂时仅权益使用"`
+	RaiBothHas         bool                  `description:"权益-是否主客观都有"`
+	IsUpgrade          int                   `description:"是否升级,1是,0否"`
+	Child              []*PermissionLookItem `description:"子权限"`
+}
+
+type PermissionVarietyResp struct {
+	List []*PermissionVarietyList
+}
+
+type PermissionVarietyItem struct {
+	ChartPermissionId int    `description:"权限id"`
+	ClassifyName      string `orm:"column(permission_name)" description:"权限名称"`
+}
+
+type PermissionVarietyList struct {
+	ChartPermissionId int    `description:"父级id"`
+	ClassifyName      string `description:"分类"`
+	Items             []*PermissionVarietyItem
+}
+
+func GetPermissionVarietyItems(productId int, classifyName string) (items []*PermissionVarietyItem, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := ` SELECT * FROM chart_permission WHERE enabled=1 AND product_id=? AND classify_name=? GROUP BY permission_name ORDER BY sort ASC `
+	_, err = o.Raw(sql, productId, classifyName).QueryRows(&items)
+	return
+}
+
+// GetChartPermissionListById 根据权限id获取产品权限详情
+func GetChartPermissionListById(chartPermissionId int) (item *ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := `SELECT * FROM chart_permission WHERE chart_permission_id =? `
+	err = o.Raw(sql, chartPermissionId).QueryRow(&item)
+	return
+}
+
+func GetParentIdFromGroup(gid int) (items *int, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT parent_id FROM sys_group WHERE group_id=? `
+	err = o.Raw(sql, gid).QueryRow(&items)
+	return
+}
+
+func GetGroupNamesById(gid int) (items *string, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT group_name FROM sys_group WHERE group_id=? `
+	err = o.Raw(sql, gid).QueryRow(&items)
+	return
+}

+ 72 - 0
models/data_manage/edb_classify.go

@@ -13,6 +13,7 @@ type EdbClassify struct {
 	ClassifyType    uint8     `description:"分类类型,0:普通指标分类,1:预测指标分类"`
 	ClassifyName    string    `description:"分类名称"`
 	ParentId        int       `description:"父级id"`
+	RootId          int       `description:"顶级id"`
 	HasData         int       `description:"是否含有指标数据"`
 	CreateTime      time.Time `description:"创建时间"`
 	ModifyTime      time.Time `description:"修改时间"`
@@ -139,6 +140,7 @@ type EdbClassifyItems struct {
 	ClassifyName    string
 	ClassifyNameEn  string
 	ParentId        int
+	RootId          int    `description:"顶级id"`
 	Level           int    `description:"层级"`
 	Sort            int    `description:"排序字段,越小越靠前,默认值:10"`
 	UniqueCode      string `description:"唯一编码"`
@@ -229,6 +231,9 @@ type MoveEdbClassifyReq struct {
 	ParentClassifyId int `description:"父级分类id"`
 	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
 	NextClassifyId   int `description:"下一个兄弟节点分类id"`
+	EdbInfoId        int `description:"指标ID, 如果指标ID有值,则移动对象为指标,否则认为移动对象为分类"`
+	PrevEdbInfoId    int `description:"上一个指标ID"`
+	NextEdbInfoId    int `description:"下一个指标ID"`
 }
 
 // GetFirstEdbClassifyByParentId 获取当前父级分类下,且排序数相同 的排序第一条的数据
@@ -448,3 +453,70 @@ func FixPredictEdbClassifySysUser() {
 	}
 	fmt.Println("EditChartClassifySysUser end")
 }
+
+type EdbClassifyItemList []*EdbClassifyItems
+
+func (m EdbClassifyItemList) Len() int {
+	return len(m)
+}
+
+func (m EdbClassifyItemList) Less(i, j int) bool {
+	return m[i].Sort < m[j].Sort
+}
+
+func (m EdbClassifyItemList) Swap(i, j int) {
+	m[i], m[j] = m[j], m[i]
+}
+
+// GetNormalEdbClassifyAll 获取普通指标的分类列表
+func GetNormalEdbClassifyAll() (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
+}
+
+type EdbClassifyIdItems struct {
+	ClassifyId   int `description:"分类id"`
+	ClassifyName string
+	UniqueCode   string `description:"唯一编码"`
+	ParentId     int    `description:"父级分类id"`
+	Level        int    `description:"层级"`
+	RootId       int    `description:"顶级分类id"`
+}
+
+func GetEdbClassifyByRootIdLevel(rootId int, classifyType uint8, orderStr string) (items []*EdbClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_classify WHERE root_id=? AND classify_type = ? `
+	if orderStr != "" {
+		sql += orderStr
+	} else {
+		sql += ` order by level desc, sort asc, classify_id asc`
+	}
+
+	_, err = o.Raw(sql, rootId, classifyType).QueryRows(&items)
+	return
+}
+
+// GetEdbInfoMaxSortByClassifyId 获取分类下指标的最大的排序数
+func GetEdbInfoMaxSortByClassifyId(classifyId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT Max(sort) AS sort FROM edb_info WHERE classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&sort)
+	return
+}
+func UpdateEdbClassifyChildByParentClassifyId(classifyIds []int, rootId int, levelStep int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	var pars []interface{}
+	pars = append(pars, rootId, levelStep)
+	pars = append(pars, classifyIds)
+	// 更新相关联的二级分类的parentId,和classify_name_second
+	sql := `update edb_classify 
+SET root_id = ?, level = level+?
+where classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `)`
+	_, err = o.Raw(sql, pars).Exec()
+	if err != nil {
+		return
+	}
+	return
+}

+ 8 - 1
models/data_manage/edb_data_base.go

@@ -152,8 +152,15 @@ func GetEdbDataTableName(source int) (tableName string) {
 		tableName = "edb_data_calculate_zsxy" // 指数修匀->72
 	case utils.DATA_SOURCE_PREDICT_CALCULATE_ZSXY:
 		tableName = "edb_data_predict_calculate_zsxy" // 预测指数修匀->73
+	case utils.DATA_SOURCE_CALCULATE_ZDYFX:
+		tableName = "edb_data_calculate_zdyfx" // 自定义分析->74
+	case utils.DATA_SOURCE_CALCULATE_RJZ: //日均值->75
+		tableName = "edb_data_calculate_rjz"
 	default:
-		tableName = ""
+		edbSource := EdbSourceIdMap[source]
+		if edbSource != nil {
+			tableName = edbSource.TableName
+		}
 	}
 	return
 }

+ 0 - 321
models/data_manage/edb_data_gl.go

@@ -1,333 +1,12 @@
 package data_manage
 
 import (
-	"eta/eta_mobile/utils"
-	"fmt"
 	"github.com/beego/beego/v2/client/orm"
-	"strconv"
-	"strings"
-	"time"
 )
 
-func AddEdbDataGlBySql(sqlStr string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sqlStr).Exec()
-	return
-}
-
-func GetEdbDataGlByEdbCode(edbCode string) (items []*EdbInfoSearchData, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_data_gl WHERE edb_code=? ORDER BY data_time DESC LIMIT ? `
-	_, err = o.Raw(sql, edbCode, utils.EDB_DATA_LIMIT).QueryRows(&items)
-	return
-}
-
 func GetEdbDataGlMaxOrMinDate(edbCode string) (min_date, max_date string, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT MIN(data_time) AS min_date,MAX(data_time) AS max_date FROM edb_data_gl WHERE edb_code=? `
 	err = o.Raw(sql, edbCode).QueryRow(&min_date, &max_date)
 	return
 }
-
-type GlData struct {
-	InputValue string `orm:"column(DATA_VALUE)" description:"日期"`
-	DataTime   string `orm:"column(DATA_DATE)" description:"值"`
-}
-
-func GetGlDataByTradeCode(condition string, pars []interface{}) (item []*GlData, err error) {
-	condition += " AND IS_DELETE=0 "
-	sql := ` SELECT * FROM mb_index_main_data WHERE 1=1 `
-	o := orm.NewOrmUsingDB("gl")
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY PUBLISH_TIME DESC `
-	_, err = o.Raw(sql, pars).QueryRows(&item)
-	return
-}
-
-func GetEdbDataGlByCode(edbCode string) (items []*EdbInfoSearchData, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_data_gl WHERE edb_code=? ORDER BY data_time DESC LIMIT ? `
-	_, err = o.Raw(sql, edbCode, utils.EDB_DATA_LIMIT).QueryRows(&items)
-	return
-}
-
-func GetEdbDataByGl(edbCode, startDate, endDate string) (searchItem *EdbInfoSearch, err error) {
-
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND INDEX_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	glDataList, err := GetGlDataByTradeCode(condition, pars)
-	if err != nil {
-		return
-	}
-	searchItem = new(EdbInfoSearch)
-	searchItem.EdbCode = edbCode
-	dataLen := len(glDataList)
-
-	existMap := make(map[string]string)
-	if dataLen > 0 {
-		var isAdd bool
-		addSql := ` INSERT INTO edb_data_gl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-		dataList := make([]*EdbInfoSearchData, 0)
-		for i := 0; i < dataLen; i++ {
-			item := glDataList[i]
-			eDate := item.DataTime
-			sValue := item.InputValue
-			if sValue != "" {
-				if _, ok := existMap[eDate]; !ok {
-					dataTime, err := time.Parse(utils.FormatDate, eDate)
-					if err != nil {
-						return nil, err
-					}
-					timestamp := dataTime.UnixNano() / 1e6
-					timeStr := fmt.Sprintf("%d", timestamp)
-					addSql += GetAddSql("0", edbCode, eDate, timeStr, sValue)
-					isAdd = true
-				}
-			}
-			existMap[eDate] = eDate
-		}
-		fmt.Println("isAdd:", isAdd)
-		if isAdd {
-			//addSql = strings.TrimRight(addSql, ",")
-			//fmt.Println("addSql:exec start")
-			//_, err = o.Raw(addSql).Exec()
-			//if err != nil {
-			//	utils.FileLogData.Info("GetEdbDataByGl Err:%s", err.Error())
-			//	return
-			//}
-			//fmt.Println("addSql:exec end")
-			addSql = strings.TrimRight(addSql, ",")
-			utils.FileLog.Info(addSql)
-			err = AddEdbDataGlBySql(addSql)
-			if err != nil {
-				utils.FileLogData.Info("AddEdbDataGlBySql Err:%s", err.Error())
-				return
-			}
-		}
-		dataList, err := GetEdbDataGlByCode(edbCode)
-		if err != nil {
-			utils.FileLogData.Info("GetEdbDataGlByCode Err:%s", err.Error())
-			return searchItem, err
-		}
-		minDate, maxDate, err := GetEdbDataGlMaxOrMinDate(edbCode)
-		if err != nil {
-			return searchItem, err
-		}
-		searchItem.DataList = dataList
-		searchItem.StartDate = minDate
-		searchItem.EndDate = maxDate
-	}
-	if searchItem.DataList == nil {
-		searchItem.DataList = make([]*EdbInfoSearchData, 0)
-	}
-	return
-}
-
-func ModifyEdbDataGlStatus(edbInfoId int64, edbCode string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE edb_data_gl SET edb_info_id=?, status=1,modify_time=NOW() WHERE edb_code=? `
-	_, err = o.Raw(sql, edbInfoId, edbCode).Exec()
-	return
-}
-
-func GetEdbDataGlByCodeAndDate(edbCode string, startDate string) (count int, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT COUNT(1) AS count FROM edb_data_gl WHERE edb_code=? AND data_time=? `
-	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
-	return
-}
-
-func ModifyEdbDataGl(edbInfoId int64, dataTime, value string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE edb_data_gl SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-	_, err = o.Raw(sql, value, edbInfoId, dataTime).Exec()
-	return
-}
-
-// 刷新钢联指标数据
-func RefreshEdbDataByGl(edbInfoId int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	if err != nil {
-		return
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND INDEX_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	if startDate != "" {
-		condition += " AND DATA_DATE>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND DATA_DATE<=? "
-		pars = append(pars, endDate)
-	}
-
-	glDataList, err := GetGlDataByTradeCode(condition, pars)
-
-	addSql := ` INSERT INTO edb_data_gl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range glDataList {
-		item := v
-		if _, ok := existMap[v.DataTime]; !ok {
-			count, err := GetEdbDataGlByCodeAndDate(edbCode, v.DataTime)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				return err
-			}
-			if count <= 0 {
-				eDate := item.DataTime
-				sValue := item.InputValue
-				if sValue != "" {
-					dataTime, err := time.Parse(utils.FormatDate, eDate)
-					if err != nil {
-						return err
-					}
-					timestamp := dataTime.UnixNano() / 1e6
-					timeStr := fmt.Sprintf("%d", timestamp)
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, sValue)
-					isAdd = true
-				}
-			} else {
-				err = ModifyEdbDataGl(int64(edbInfoId), v.DataTime, v.InputValue)
-				if err != nil {
-					return err
-				}
-			}
-		}
-		existMap[v.DataTime] = v.InputValue
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// 全部刷新隆众数据
-func RefreshAllEdbDataByGl(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	if err != nil {
-		return
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND INDEX_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	if startDate != "" {
-		condition += " AND DATA_DATE>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND DATA_DATE<=? "
-		pars = append(pars, endDate)
-	}
-
-	glDataList, err := GetGlDataByTradeCode(condition, pars)
-
-	//获取指标所有数据
-	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
-	sql := `SELECT * FROM %s WHERE edb_info_id=? `
-	sql = fmt.Sprintf(sql, dataTableName)
-	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)
-	if err != nil {
-		return err
-	}
-	dataMap := make(map[string]string)
-	for _, v := range dataList {
-		dataMap[v.DataTime] = v.Value
-	}
-
-	addSql := ` INSERT INTO edb_data_gl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range glDataList {
-		item := v
-		if _, ok := existMap[v.DataTime]; !ok {
-			eDate := item.DataTime
-			sValue := item.InputValue
-			if sValue != "" {
-				dataTime, err := time.Parse(utils.FormatDate, eDate)
-				if err != nil {
-					return err
-				}
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				saveValue := sValue
-
-				if existVal, ok := dataMap[eDate]; !ok {
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, saveValue)
-					isAdd = true
-				} else {
-					if existVal != saveValue {
-						sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-						sql = fmt.Sprintf(sql, dataTableName)
-						_, err = to.Raw(sql, sValue, edbInfoId, eDate).Exec()
-						if err != nil {
-							return err
-						}
-					}
-				}
-			}
-		}
-		existMap[v.DataTime] = v.DataTime
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}

+ 0 - 528
models/data_manage/edb_data_quarter.go

@@ -1,216 +1,14 @@
 package data_manage
 
 import (
-	"encoding/json"
 	"eta/eta_mobile/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"sort"
 	"strconv"
-	"strings"
 	"time"
 
 	"github.com/nosixtools/solarlunar"
 )
 
-func GetEdbDataQuarterCount(edbInfoId int) (count int, err error) {
-	o := orm.NewOrmUsingDB("data")
-	hsql := `SELECT COUNT(1) AS count FROM edb_data_quarter WHERE edb_info_id=? `
-	err = o.Raw(hsql, edbInfoId).QueryRow(&count)
-	return
-}
-
-// 指标季度数据计算(公历转农历)
-func AddCalculateQuarterV2(edbInfoId, source int, edbCode string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			fmt.Println("Err:", err)
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	fmt.Println(edbInfoIdStr)
-	//计算数据
-	var condition string
-	var pars []interface{}
-	condition += " AND edb_info_id=? "
-	pars = append(pars, edbInfoId)
-	dataList, err := GetEdbDataListAll(condition, pars, source, 0)
-	if err != nil {
-		return err
-	}
-
-	var yearArr []int
-	yearMap := make(map[int]int)
-	dataMap := make(map[string]*EdbInfoSearchData)
-	for _, v := range dataList {
-		//日其中获取年
-		itemDate, err := time.Parse(utils.FormatDate, v.DataTime)
-		if err != nil {
-			return err
-		}
-		year := itemDate.Year()
-		if _, ok := yearMap[year]; !ok {
-			yearArr = append(yearArr, year)
-			yearMap[year] = year
-		}
-		dataMap[v.DataTime] = v
-	}
-	sort.Sort(sort.Reverse(sort.IntSlice(yearArr)))
-	addSql := ` INSERT INTO edb_data_quarter(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	//yearLen := len(yearArr)
-
-	fmt.Println(yearArr)
-
-	for _, yv := range yearArr {
-		fmt.Println(yv)
-	}
-	fmt.Println("isAdd", isAdd)
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		utils.FileLog.Info(addSql)
-		_, err = to.Raw(addSql).Exec()
-		fmt.Println("err:", err)
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// 指标季度数据计算(公历转农历)
-func AddCalculateQuarterV3(edbInfoId, source int, edbCode string, list []*EdbDataList) (err error) {
-	var errMsg string
-	defer func() {
-		if errMsg != "" {
-			fmt.Println("errMsg:", errMsg)
-		}
-	}()
-	lunarDate := "2017-01-01" //农历
-	fmt.Println(solarlunar.LunarToSolar(lunarDate, false))
-
-	dataList, err := GetHzTestEdbdata()
-	var yearArr []int
-	yearMap := make(map[int]int)
-	var cureentDate time.Time
-	for k, v := range dataList {
-		if k == 0 {
-			cureentDate = v.Dt
-		}
-		year := v.Dt.Year()
-		if _, ok := yearMap[year]; !ok {
-			yearArr = append(yearArr, year)
-		}
-		yearMap[year] = year
-	}
-	//排序
-	fmt.Println(yearArr)
-	thisYear := cureentDate.Year()
-	thisMonth := int(cureentDate.Month())
-
-	sort.Ints(yearArr)
-	fmt.Println("thisYear:", thisYear)
-
-	result := new(HzTestEdbdataResult)
-	for ky, vy := range yearArr {
-		if thisMonth < 11 {
-			currentYearCjnl := strconv.Itoa(thisYear) + "-01-01"               //当前年份春节农历
-			currentYearCjgl := solarlunar.LunarToSolar(currentYearCjnl, false) //当前年份春节公历
-			currentYearCjglDate, err := time.Parse(utils.FormatDate, currentYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return err
-			}
-
-			fmt.Println(ky, vy)
-			preYear := vy
-			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return err
-			}
-			day := currentYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-			fmt.Println("day:", day)
-			items := new(HzTestEdbdataItems)
-			dataLen := len(dataList)
-			for i := dataLen - 1; i >= 0; i-- {
-				v := dataList[i]
-				newDate := v.Dt.AddDate(0, 0, int(day))
-				selectDateStr := strconv.Itoa(thisYear) + "-11" + "-30"
-				selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-
-				if newDate.Before(selectDate) {
-					item := new(HzTestEdbdata)
-					item.TtradeCode = v.TtradeCode
-					item.Dt = newDate
-					item.Close = v.Close
-					timestamp := item.Dt.UnixNano() / 1e6
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-			}
-			result.List = append(result.List, items)
-		} else {
-			fmt.Println(ky, vy)
-			nextYear := thisYear + 1
-			nextYearCjnl := strconv.Itoa(nextYear) + "-01-01"            //当前年份春节农历
-			nextYearCjgl := solarlunar.LunarToSolar(nextYearCjnl, false) //当前年份春节公历
-
-			nextYearCjglDate, err := time.Parse(utils.FormatDate, nextYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return err
-			}
-
-			preYear := vy
-			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return err
-			}
-			day := nextYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-
-			fmt.Println("day:", day)
-			items := new(HzTestEdbdataItems)
-			dataLen := len(dataList)
-			for i := dataLen - 1; i >= 0; i-- {
-				v := dataList[i]
-				newDate := v.Dt.AddDate(0, 0, int(day))
-				selectDateStr := strconv.Itoa(nextYear) + "-05" + "-31"
-				selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-
-				if newDate.Before(selectDate) {
-					item := new(HzTestEdbdata)
-					item.TtradeCode = v.TtradeCode
-					item.Dt = newDate
-					item.Close = v.Close
-					timestamp := item.Dt.UnixNano() / 1e6
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-			}
-			result.List = append(result.List, items)
-		}
-
-	}
-	resultJson, err := json.Marshal(result)
-	utils.FileLog.Info(string(resultJson))
-	return
-}
-
 // 指标季度数据计算(公历转农历)
 func AddCalculateQuarterV4(dataList []*EdbDataList) (result *EdbDataResult, err error) {
 	var errMsg string
@@ -387,203 +185,6 @@ func AddCalculateQuarterV4(dataList []*EdbDataList) (result *EdbDataResult, err
 	return
 }
 
-// AddCalculateQuarterV4ByUniqueCode 指标季度数据计算(公历转农历)
-func AddCalculateQuarterV4ByUniqueCode(dataList []*EdbDataListByUniqueCode) (result *EdbDataResult, err error) {
-	var errMsg string
-	defer func() {
-		if errMsg != "" {
-			fmt.Println("errMsg:", errMsg)
-		}
-	}()
-
-	endDate := dataList[len(dataList)-1].DataTime
-	endDateForm, err := time.Parse(utils.FormatDate, endDate)
-	if err != nil {
-		return result, err
-	}
-	thisMonth := int(endDateForm.Month())
-
-	result = new(EdbDataResult)
-	var yearArr []int
-	yearMap := make(map[int]int)
-	var cureentDate time.Time
-	if thisMonth < 11 {
-		for k, v := range dataList {
-			dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
-			if err != nil {
-				errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
-				return result, err
-			}
-			if k == len(dataList)-1 {
-				cureentDate = dateTime
-			}
-			year := dateTime.Year()
-			if _, ok := yearMap[year]; !ok {
-				yearArr = append(yearArr, year)
-			}
-			yearMap[year] = year
-		}
-	} else {
-		for k, v := range dataList {
-			dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
-			if err != nil {
-				errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
-				return result, err
-			}
-			if k == len(dataList)-1 {
-				cureentDate = dateTime
-			}
-			year := dateTime.Year() + 1
-			if _, ok := yearMap[year]; !ok {
-				yearArr = append(yearArr, year)
-			}
-			yearMap[year] = year
-		}
-	}
-	//排序
-	fmt.Println("yearArr:", yearArr)
-	thisYear := cureentDate.Year()
-	//thisMonth := int(cureentDate.Month())
-
-	fmt.Println("thisMonth:", thisMonth)
-	for ky, vy := range yearArr {
-		fmt.Println("line 432:", ky, vy, thisYear, thisMonth)
-		if thisMonth < 11 {
-			currentYearCjnl := strconv.Itoa(thisYear) + "-01-01"               //当前年份春节农历
-			currentYearCjgl := solarlunar.LunarToSolar(currentYearCjnl, false) //当前年份春节公历
-			currentYearCjglDate, err := time.Parse(utils.FormatDate, currentYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return result, err
-			}
-
-			preYear := vy
-			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return result, err
-			}
-			day := currentYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-
-			items := new(EdbDataItems)
-			items.Year = preYear
-			for _, v := range dataList {
-				dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
-				if err != nil {
-					errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
-					return result, err
-				}
-				newDate := dateTime.AddDate(0, 0, int(day))
-				selectDateStr := strconv.Itoa(thisYear) + "-11" + "-30"
-				selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-				if newDate.Before(selectDate) || newDate == selectDate {
-					timestamp := newDate.UnixNano() / 1e6
-					item := new(EdbDataList)
-					item.DataTime = newDate.Format(utils.FormatDate)
-					item.EdbInfoId = v.EdbInfoId
-					item.Value = v.Value
-					item.EdbDataId = v.EdbDataId
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-			}
-			result.List = append(result.List, items)
-		} else {
-			nextYear := thisYear + 1
-			nextYearCjnl := strconv.Itoa(nextYear) + "-01-01"            //当前年份春节农历
-			nextYearCjgl := solarlunar.LunarToSolar(nextYearCjnl, false) //当前年份春节公历
-
-			nextYearCjglDate, err := time.Parse(utils.FormatDate, nextYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return result, err
-			}
-			preYear := vy
-			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return result, err
-			}
-			day := nextYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-
-			fmt.Println("day:", day, nextYearCjglDate, preYearCjglDate)
-
-			items := new(EdbDataItems)
-			items.Year = preYear - 1
-			fmt.Println("preYear:", preYear, "ky:", ky, "yearArrLen:", len(yearArr))
-			if ky+1 < len(yearArr) {
-				for _, v := range dataList {
-					dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
-					if err != nil {
-						errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
-						return result, err
-					}
-					newDate := dateTime.AddDate(0, 0, int(day))
-					selectDateStr := strconv.Itoa(nextYear) + "-05" + "-31"
-					selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-
-					if newDate.Before(selectDate) || newDate == selectDate {
-						timestamp := newDate.UnixNano() / 1e6
-						item := new(EdbDataList)
-						item.DataTime = newDate.Format(utils.FormatDate)
-						item.EdbInfoId = v.EdbInfoId
-						item.Value = v.Value
-						item.EdbDataId = v.EdbDataId
-						item.DataTimestamp = timestamp
-						items.Items = append(items.Items, item)
-					}
-				}
-				result.List = append(result.List, items)
-			} else {
-				for _, v := range dataList {
-					dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
-					if err != nil {
-						errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
-						return result, err
-					}
-					timestamp := dateTime.UnixNano() / 1e6
-					item := new(EdbDataList)
-					item.DataTime = dateTime.Format(utils.FormatDate)
-					item.EdbInfoId = v.EdbInfoId
-					item.Value = v.Value
-					item.EdbDataId = v.EdbDataId
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-				result.List = append(result.List, items)
-			}
-		}
-	}
-	return
-}
-
-type HzTestEdbdataResult struct {
-	List []*HzTestEdbdataItems
-}
-
-type HzTestEdbdataItems struct {
-	Items []*HzTestEdbdata
-}
-
-type HzTestEdbdata struct {
-	TtradeCode    string    `orm:"column(TRADE_CODE)"`
-	Dt            time.Time `orm:"column(DT)"`
-	Close         float64   `orm:"column(CLOSE)"`
-	ModifyTime    time.Time `orm:"column(modify_time)"`
-	DataTimestamp int64
-}
-
-func GetHzTestEdbdata() (list []*HzTestEdbdata, err error) {
-	o := orm.NewOrm()
-	sql := ` SELECT * FROM hz_test_edbdata WHERE TRADE_CODE=? ORDER BY DT DESC `
-	_, err = o.Raw(sql, "ST_0000577845").QueryRows(&list)
-	return
-}
-
 type EdbDataItems struct {
 	Items                []*EdbDataList
 	Year                 int
@@ -594,132 +195,3 @@ type EdbDataItems struct {
 type EdbDataResult struct {
 	List []*EdbDataItems
 }
-
-func AddCalculateQuarterV5(dataList []*EdbDataList) (result *EdbDataResult, err error) {
-	var errMsg string
-	defer func() {
-		if errMsg != "" {
-			fmt.Println("errMsg:", errMsg)
-		}
-	}()
-	result = new(EdbDataResult)
-	thisYear := time.Now().Year()
-
-	endDate := dataList[len(dataList)-1].DataTime
-	endDateForm, err := time.Parse(utils.FormatDate, endDate)
-	if err != nil {
-		return result, err
-	}
-	thisMonth := int(endDateForm.Month())
-
-	fmt.Println(thisMonth)
-	for i := 4; i > 0; i-- {
-		if thisMonth < 11 {
-			nextYear := thisYear
-			nextYearCjnl := strconv.Itoa(nextYear) + "-01-01"            //当前年份春节农历
-			nextYearCjgl := solarlunar.LunarToSolar(nextYearCjnl, false) //当前年份春节公历
-			nextYearCjglDate, err := time.Parse(utils.FormatDate, nextYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return result, err
-			}
-			preYearCjnl := strconv.Itoa(nextYear-i) + "-01-01"         //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return result, err
-			}
-			day := nextYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-			items := new(EdbDataItems)
-			for _, v := range dataList {
-				dataDate := v.DataTime
-				dataDateForm, err := time.Parse(utils.FormatDate, dataDate)
-				if err != nil {
-					return result, err
-				}
-				newDate := dataDateForm.AddDate(0, 0, int(day))
-				selectDateStr := strconv.Itoa(nextYear) + "-11" + "-30"
-				selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-				if newDate.Before(selectDate) {
-					timestamp := newDate.UnixNano() / 1e6
-					item := new(EdbDataList)
-					item.DataTime = newDate.Format(utils.FormatDate)
-					item.EdbInfoId = v.EdbInfoId
-					item.Value = v.Value
-					item.EdbDataId = v.EdbDataId
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-			}
-			fmt.Println(nextYear, "年春节阳历", nextYearCjgl)
-			fmt.Println(i, "年前春节", preYearCjnl)
-			fmt.Println(i, "年前春节阳历", preYearCjgl)
-			fmt.Println("与", nextYear, "年春节相差天数", day, "____________")
-			result.List = append(result.List, items)
-		} else {
-			nextYear := thisYear + 1
-			nextYearCjnl := strconv.Itoa(nextYear) + "-01-01"            //当前年份春节农历
-			nextYearCjgl := solarlunar.LunarToSolar(nextYearCjnl, false) //当前年份春节公历
-			nextYearCjglDate, err := time.Parse(utils.FormatDate, nextYearCjgl)
-			if err != nil {
-				errMsg = "生成当前春节失败,Err:" + err.Error()
-				return result, err
-			}
-			preYearCjnl := strconv.Itoa(nextYear-i) + "-01-01"         //之前年份春节农历
-			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
-			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
-			if err != nil {
-				errMsg = "生成历史年份春节失败,Err:" + err.Error()
-				return result, err
-			}
-			day := nextYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
-			items := new(EdbDataItems)
-			for _, v := range dataList {
-				dataDate := v.DataTime
-				dataDateForm, err := time.Parse(utils.FormatDate, dataDate)
-				if err != nil {
-					return result, err
-				}
-
-				newDate := dataDateForm.AddDate(0, 0, int(day))
-				selectDateStr := strconv.Itoa(nextYear) + "-05" + "-31"
-				selectDate, _ := time.Parse(utils.FormatDate, selectDateStr)
-				if newDate.Before(selectDate) {
-					timestamp := newDate.UnixNano() / 1e6
-					item := new(EdbDataList)
-					item.DataTime = newDate.Format(utils.FormatDate)
-					item.EdbInfoId = v.EdbInfoId
-					item.Value = v.Value
-					item.EdbDataId = v.EdbDataId
-					item.DataTimestamp = timestamp
-					items.Items = append(items.Items, item)
-				}
-			}
-			fmt.Println(nextYear, "年春节阳历", nextYearCjgl)
-			fmt.Println(i, "年前春节", preYearCjnl)
-			fmt.Println(i, "年前春节阳历", preYearCjgl)
-			fmt.Println("与", nextYear, "年春节相差天数", day, "____________")
-			result.List = append(result.List, items)
-		}
-	}
-	//合并第五组数据
-	items := new(EdbDataItems)
-	for _, v := range dataList {
-		dataDate := v.DataTime
-		dataDateForm, err := time.Parse(utils.FormatDate, dataDate)
-		if err != nil {
-			return result, err
-		}
-		timestamp := dataDateForm.UnixNano() / 1e6
-		item := new(EdbDataList)
-		item.DataTime = v.DataTime
-		item.EdbInfoId = v.EdbInfoId
-		item.Value = v.Value
-		item.EdbDataId = v.EdbDataId
-		item.DataTimestamp = timestamp
-		items.Items = append(items.Items, item)
-	}
-	result.List = append(result.List, items)
-	return
-}

+ 16 - 3
models/data_manage/edb_info.go

@@ -48,6 +48,16 @@ type EdbInfo struct {
 	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
 }
 
+type EdbInfoFullClassify struct {
+	*EdbInfo
+	ClassifyList []*EdbClassifyIdItems
+}
+
+type EdbInfoDataFullClassifyResp struct {
+	EdbInfo  *EdbInfoFullClassify
+	DataList []*EdbDataList
+}
+
 func AddEdbInfo(item *EdbInfo) (lastId int64, err error) {
 	o := orm.NewOrmUsingDB("data")
 	lastId, err = o.Insert(item)
@@ -297,7 +307,7 @@ type EdbData struct {
 type EdbInfoListResp struct {
 	Paging       *paging.PagingItem
 	Item         *EdbInfoList
-	ClassifyList []*EdbClassifySimplify
+	ClassifyList []*EdbClassifyIdItems
 }
 
 func GetEdbInfoByCondition(condition string, pars []interface{}) (item *EdbInfoList, err error) {
@@ -727,9 +737,11 @@ func GetFirstEdbInfoByClassifyId(classifyId int) (item *EdbInfo, err error) {
 // UpdateEdbInfoSortByClassifyId 根据分类id更新排序
 func UpdateEdbInfoSortByClassifyId(classifyId, nowSort int, prevEdbInfoId int, updateSort string) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` update edb_info set sort = ` + updateSort + ` WHERE classify_id=? AND `
+	sql := ` update edb_info set sort = ` + updateSort + ` WHERE classify_id=?`
 	if prevEdbInfoId > 0 {
-		sql += ` ( sort > ? or ( edb_info_id > ` + fmt.Sprint(prevEdbInfoId) + ` and sort=` + fmt.Sprint(nowSort) + ` )) `
+		sql += ` AND ( sort > ? or ( edb_info_id > ` + fmt.Sprint(prevEdbInfoId) + ` and sort=` + fmt.Sprint(nowSort) + ` )) `
+	} else {
+		sql += ` AND ( sort > ? )`
 	}
 	_, err = o.Raw(sql, classifyId, nowSort).Exec()
 	return
@@ -1524,6 +1536,7 @@ type TraceEdbInfoResp struct {
 	UniqueCode  string             `description:"唯一编码"`
 	ClassifyId  int                `description:"分类ID"`
 	Child       []TraceEdbInfoResp `description:"下级来源"`
+	EdbInfo     *EdbInfo           `description:"指标信息" json:"-"`
 }
 
 // BeforeAndAfterDateDataResp 前后几期数据

+ 1 - 1
models/data_manage/edb_info_calculate.go

@@ -93,7 +93,7 @@ func GetEdbInfoCalculateDetail(edbInfoId, source int) (list []*EdbInfoCalculateD
 }
 
 type CalculateDetailResp struct {
-	EdbInfoDetail *EdbInfo
+	EdbInfoDetail *EdbInfoFullClassify
 	CalculateList []*EdbInfoCalculateDetail
 }
 

+ 39 - 4
models/data_manage/edb_source.go

@@ -1,17 +1,29 @@
 package data_manage
 
 import (
+	"eta/eta_mobile/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"strings"
 )
 
+var (
+	EdbSourceIdMap       map[int]*EdbSource // 指标来源
+	EdbSourceExtendIdMap map[string]int     // 指标来源字符串对应来源ID
+)
+
 // EdbSource 指标来源表
 type EdbSource struct {
-	EdbSourceId int    `orm:"column(edb_source_id);pk"`
-	SourceName  string `description:"指标来源名称"`
-	TableName   string `description:"数据表名"`
-	IsBase      int    `description:"是否为基础指标: 0-否; 1-是"`
+	EdbSourceId      int    `orm:"column(edb_source_id);pk"`
+	SourceName       string `description:"指标来源名称"`
+	TableName        string `description:"数据表名"`
+	EdbAddMethod     string `description:"指标新增接口"`
+	EdbRefreshMethod string `description:"指标刷新接口"`
+	IsBase           int    `description:"是否为基础指标: 0-否; 1-是"`
+	FromBridge       int    `description:"是否来源于桥接服务: 0-否; 1-是"`
+	BridgeFlag       string `description:"桥接服务对象标识"`
+	SourceExtend     string `description:"扩展字段做查询用"`
+	EdbCodeRequired  int    `description:"指标编码是否必填: 0-否; 1-是"`
 }
 
 // GetEdbSourceItemsByCondition 获取指标来源
@@ -29,3 +41,26 @@ func GetEdbSourceItemsByCondition(condition string, pars []interface{}, fieldArr
 	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
+
+// InitEdbSource 初始化时加载指标来源对应信息, 避免循环中查库, 注意edb_source表修改table_name的话需要重启服务
+func InitEdbSource() {
+	EdbSourceIdMap = make(map[int]*EdbSource)
+	EdbSourceExtendIdMap = make(map[string]int)
+	sources, e := GetEdbSourceItemsByCondition(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		utils.FileLog.Info("init source table err: %s", e.Error())
+		return
+	}
+	for _, v := range sources {
+		EdbSourceIdMap[v.EdbSourceId] = v
+		if v.SourceExtend != "" {
+			arr := strings.Split(v.SourceExtend, ",")
+			if len(arr) == 0 {
+				continue
+			}
+			for _, s := range arr {
+				EdbSourceExtendIdMap[s] = v.EdbSourceId
+			}
+		}
+	}
+}

+ 0 - 135
models/data_manage/gl_data.go

@@ -2,37 +2,8 @@ package data_manage
 
 import (
 	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
-type GlClassify struct {
-	BreedShortName string `orm:"column(BREED_SHORT_NAME)" description:"分类名称"`
-}
-
-func GetGlSurveyClassify() (items []*GlClassify, err error) {
-	sql := ` SELECT CASE WHEN BREED_SHORT_NAME IS NULL THEN '无' ELSE BREED_SHORT_NAME END BREED_SHORT_NAME  FROM mb_index_main_info GROUP BY BREED_SHORT_NAME ORDER BY BREED_SHORT_NAME ASC `
-	o := orm.NewOrmUsingDB("gl")
-	o.Raw(sql).QueryRows(&items)
-	return
-}
-
-type GlFrequency struct {
-	Frequency string `description:"频度:1-日度 2-周度 3-月度 4-季度 5-年度 99-无固定频率"`
-}
-
-func GetGlFrequencyByClassifyId(breedShortName string) (items []*GlFrequency, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	if breedShortName == "无" {
-		sql := ` SELECT FREQUENCY_NAME AS frequency FROM mb_index_main_info WHERE BREED_SHORT_NAME IS NULL GROUP BY FREQUENCY_CODE ORDER BY FREQUENCY_CODE ASC `
-		_, err = o.Raw(sql).QueryRows(&items)
-		return
-	} else {
-		sql := ` SELECT FREQUENCY_NAME AS frequency FROM mb_index_main_info WHERE BREED_SHORT_NAME=? GROUP BY FREQUENCY_CODE ORDER BY FREQUENCY_CODE ASC `
-		_, err = o.Raw(sql, breedShortName).QueryRows(&items)
-		return
-	}
-}
-
 type GlIndex struct {
 	Id            int    `orm:"column(ID)"`
 	IndexCode     string `orm:"column(INDEX_CODE)"`
@@ -42,115 +13,9 @@ type GlIndex struct {
 	UpdateTime    string `orm:"column(UPDATE_TIME)"`
 }
 
-func GetGlIndex(breedShortName, frequency string) (items []*GlIndex, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	if breedShortName == "无" {
-		sql := ` SELECT * FROM mb_index_main_info WHERE BREED_SHORT_NAME IS NULL AND FREQUENCY_NAME=? ORDER BY INDEX_CODE ASC `
-		_, err = o.Raw(sql, frequency).QueryRows(&items)
-		return
-	} else {
-		sql := ` SELECT * FROM mb_index_main_info WHERE BREED_SHORT_NAME=? AND FREQUENCY_NAME=? ORDER BY INDEX_CODE ASC `
-		_, err = o.Raw(sql, breedShortName, frequency).QueryRows(&items)
-		return
-	}
-}
-
-func GetGlFrequency(productName string) (items []*string, err error) {
-	sql := `SELECT DISTINCT FREQUENCY_NAME FROM mb_index_main_info WHERE BREED_SHORT_NAME=? ORDER BY FIELD(FREQUENCY_NAME,'日度','周度','旬度','月度','季度','半年','年度') `
-	o := orm.NewOrmUsingDB("gl")
-	_, err = o.Raw(sql, productName).QueryRows(&items)
-	return
-}
-
-type GlIndexList struct {
-	Id            int                `orm:"column(ID)"`
-	IndexCode     string             `orm:"column(INDEX_CODE)"`
-	IndexName     string             `orm:"column(INDEX_NAME)"`
-	UnitName      string             `orm:"column(UNIT_NAME)"`
-	FrequencyName string             `orm:"column(FREQUENCY_NAME)"`
-	UpdateTime    string             `orm:"column(UPDATE_TIME)"`
-	Paging        *paging.PagingItem `description:"分页数据"`
-	DataList      []*GlIndexData
-}
-
-type GlIndexData struct {
-	InputValue string `orm:"column(DATA_VALUE)" description:"日期"`
-	DataTime   string `orm:"column(DATA_DATE)" description:"值"`
-}
-
-func GetGlIndexData(indexCode string, startSize, pageSize int) (items []*GlIndexData, err error) {
-	//sql := ` SELECT *  FROM mb_index_main_data WHERE INDEX_CODE=? ORDER BY DATA_DATE DESC,PUBLISH_TIME DESC LIMIT ?,?`
-	sql := ` SELECT * FROM (
-	SELECT DISTINCT a.INDEX_CODE,a.DATA_VALUE,a.DATA_DATE FROM mb_index_main_data AS a WHERE INDEX_CODE=? AND IS_DELETE=0
-	ORDER BY DATA_DATE DESC,PUBLISH_TIME DESC 
-	)AS t
-	GROUP BY t.DATA_DATE
-	ORDER BY t.DATA_DATE DESC LIMIT ?,? `
-	o := orm.NewOrmUsingDB("gl")
-	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
-	return
-}
-
 func GetGlIndexByCode(indexCode string) (items *GlIndex, err error) {
 	sql := ` SELECT *  FROM mb_index_main_info WHERE INDEX_CODE=? `
 	o := orm.NewOrmUsingDB("gl")
 	err = o.Raw(sql, indexCode).QueryRow(&items)
 	return
 }
-
-func GetGlIndexDataCount(indexCode string) (count int, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	sql := `SELECT COUNT(1) AS count FROM (
-			SELECT * FROM (
-				SELECT DISTINCT a.INDEX_CODE,a.DATA_VALUE,a.DATA_DATE FROM mb_index_main_data AS a WHERE INDEX_CODE=? AND IS_DELETE=0
-				ORDER BY DATA_DATE DESC,PUBLISH_TIME DESC 
-				)AS t
-				GROUP BY t.DATA_DATE
-				ORDER BY t.DATA_DATE DESC
-			)AS n `
-	err = o.Raw(sql, indexCode).QueryRow(&count)
-	return
-}
-
-type GlSearchIndex struct {
-	Id             int    `orm:"column(ID)"`
-	IndexCode      string `orm:"column(INDEX_CODE)"`
-	IndexName      string `orm:"column(INDEX_NAME)"`
-	UnitName       string `orm:"column(UNIT_NAME)"`
-	FrequencyName  string `orm:"column(FREQUENCY_NAME)"`
-	UpdateTime     string `orm:"column(UPDATE_TIME)"`
-	BreedShortName string `orm:"column(BREED_SHORT_NAME)"`
-}
-
-// GetGlItemList 模糊查询隆众数据库指标列表
-func GetGlItemList(keyword string) (items []*GlSearchIndex, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	sql := "SELECT * FROM mb_index_main_info WHERE CONCAT(INDEX_NAME,INDEX_CODE) LIKE '%" + keyword + "%'"
-	_, err = o.Raw(sql).QueryRows(&items)
-	return
-
-}
-
-func GetGlDataMaxCount(classifyName string) (count int, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	sql := `SELECT MAX(t.num) AS count FROM (
-				SELECT COUNT(1) AS num  FROM mb_index_main_info AS a
-				INNER JOIN mb_index_main_data AS b ON a.INDEX_CODE=b.INDEX_CODE
-				WHERE a.BREED_SHORT_NAME=?
-				GROUP BY a.INDEX_CODE
-			)AS t `
-	err = o.Raw(sql, classifyName).QueryRow(&count)
-	return
-}
-
-func GetGlDataByCode(indexCode string) (items []*GlIndexData, err error) {
-	o := orm.NewOrmUsingDB("gl")
-	sql := `SELECT
-	* 
-FROM
-	( SELECT * FROM mb_index_main_data WHERE INDEX_CODE = ? GROUP BY UPDATE_TIME DESC, DATA_DATE DESC ) a 
-GROUP BY
-	a.DATA_DATE DESC `
-	_, err = o.Raw(sql, indexCode).QueryRows(&items)
-	return
-}

+ 147 - 0
models/data_manage/jiayue_index.go

@@ -0,0 +1,147 @@
+package data_manage
+
+import (
+	"eta/eta_mobile/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+// DictIndex 嘉悦指标表
+type DictIndex struct {
+	Id                int       `description:"主键"`
+	Code              string    `description:"指标编码"`
+	Name              string    `description:"指标名称"`
+	Unit              string    `description:"单位"`
+	Frequency         string    `description:"更新频率"`
+	Description       string    `description:"描述"`
+	TableName         string    `description:"指标数据存储库表"`
+	SourceType        string    `description:"指标来源,如:wind:万德;manual:手工导入;formula:公式;webisite:网页爬取"`
+	SourceCode        string    `description:"来源编码"`
+	SourceDescription string    `description:"来源说明"`
+	Industry          string    `description:"品种板块"`
+	Type              string    `description:"指标类型"`
+	Commodity         string    `description:"商品名称"`
+	SjbId             int       `description:"SJB_ID"`
+	UserId            int       `description:"所属用户"`
+	RowsCount         int       `description:"指标数据数量"`
+	DateFirst         time.Time `description:"指标开始时间"`
+	DateLast          time.Time `description:"指标最新时间"`
+	TimeLastUpdate    time.Time `description:"最新更新时间"`
+	TimeLastRequest   time.Time `description:"下次更新时间"`
+	Priority          int       `description:"更新优先级"`
+	Status            int       `description:"指标状态"`
+	ShortName         string    `description:"指标简称"`
+	UpdateDescription string    `description:"更新说明"`
+	ForecastFlag      int       `description:"预测标识"`
+	ManualFlag        int       `description:"手动标识"`
+	VariableFlag      int       `description:"有效标识"`
+	MarketDataFlag    int       `description:"市场价标识"`
+	CreateUser        int       `description:"创建用户"`
+	CreateTime        time.Time `description:"创建时间"`
+	UpdateUser        int       `description:"更新用户"`
+	UpdateTime        time.Time `description:"更新时间"`
+}
+
+// BridgeJiaYueIndexParams 桥接服务-获取嘉悦指标入参
+type BridgeJiaYueIndexParams struct {
+	IndexCode         string `json:"index_code" form:"index_code" description:"指标编码"`
+	SourceExtend      string `json:"source_extend" form:"source_extend" description:"来源"`
+	IndexCodeRequired int    `json:"index_code_required" form:"index_code_required" description:"指标编码是否必填: 0-否; 1-是"`
+}
+
+// BridgeJiaYueIndexDataParams 桥接服务-获取嘉悦指标数据入参
+type BridgeJiaYueIndexDataParams struct {
+	BridgeJiaYueIndexParams
+	StartDate string `json:"start_date" form:"start_date" description:"开始日期"`
+	EndDate   string `json:"end_date" form:"end_date" description:"结束日期"`
+}
+
+// BridgeJiaYueResultIndexData 桥接服务-获取嘉悦指标数据响应体
+type BridgeJiaYueResultIndexData struct {
+	Code int                      `json:"code" description:"状态码"`
+	Msg  string                   `json:"msg" description:"提示信息"`
+	Data BridgeJiaYueIndexAndData `json:"data" description:"返回数据"`
+}
+
+// BridgeJiaYueIndexAndData 桥接服务-嘉悦指标和数据
+type BridgeJiaYueIndexAndData struct {
+	Id             int                     `description:"指标自增ID" json:"id"`
+	IndexCode      string                  `description:"指标编码" json:"index_code"`
+	IndexName      string                  `description:"指标名称" json:"index_name"`
+	Unit           string                  `description:"单位" json:"unit"`
+	Frequency      string                  `description:"频度" json:"frequency"`
+	LastDate       time.Time               `description:"指标最新时间" json:"last_date"`
+	LastUpdateTime time.Time               `description:"最新更新时间" json:"last_update_time"`
+	Status         int                     `description:"指标状态" json:"status"`
+	IndexData      []BridgeJiaYueIndexData `description:"指标数据" json:"index_data"`
+}
+
+// BridgeJiaYueIndexData 桥接服务-嘉悦指标数据
+type BridgeJiaYueIndexData struct {
+	Val        float64   `json:"val"`
+	DataTime   time.Time `json:"data_time"`
+	UpdateTime time.Time `json:"update_time"`
+}
+
+// BridgeJiaYueResultFrequencyList 桥接服务-频度列表响应体
+type BridgeJiaYueResultFrequencyList struct {
+	Code int      `json:"code" description:"状态码"`
+	Msg  string   `json:"msg" description:"提示信息"`
+	Data []string `json:"data" description:"返回数据"`
+}
+
+// BridgeJiaYueResultIndexPageList 桥接服务-指标分页列表响应体
+type BridgeJiaYueResultIndexPageList struct {
+	Code int                       `json:"code" description:"状态码"`
+	Msg  string                    `json:"msg" description:"提示信息"`
+	Data BridgeJiaYuePageIndexResp `json:"data" description:"返回数据"`
+}
+
+// BridgeJiaYuePageIndexReq 桥接服务-指标分页列表请求体
+type BridgeJiaYuePageIndexReq struct {
+	SourceExtend string `json:"source_extend" form:"source_extend" description:"来源"`
+	Keyword      string `json:"keyword" form:"keyword" description:"关键词"`
+	Frequency    string `json:"frequency" form:"frequency" description:"频度"`
+	PageIndex    int    `json:"page_index" form:"page_index" description:"当前页码"`
+	PageSize     int    `json:"page_size" form:"page_size" description:"每页数据量"`
+	SortField    int    `json:"sort_field" form:"sort_field" description:"排序字段: 1-指标开始时间; 2-指标最新时间; 3-更新时间"`
+	SortRule     int    `json:"sort_rule" form:"sort_rule" description:"排序方式: 1-正序; 2-倒序"`
+}
+
+// BridgeJiaYuePageIndexResp 桥接服务-指标分页列表响应体
+type BridgeJiaYuePageIndexResp struct {
+	Total int         `description:"数据总量"`
+	List  []DictIndex `description:"列表数据"`
+}
+
+// JiaYueIndexPageListResp 指标分页列表响应体
+type JiaYueIndexPageListResp struct {
+	List   []*DictIndexItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// DictIndexItem 指标信息
+type DictIndexItem struct {
+	Id             int    `description:"主键"`
+	Code           string `description:"指标编码"`
+	Name           string `description:"指标名称"`
+	Unit           string `description:"单位"`
+	Frequency      string `description:"频度"`
+	DateFirst      string `description:"指标开始时间"`
+	DateLast       string `description:"指标最新时间"`
+	TimeLastUpdate string `description:"最新更新时间"`
+}
+
+// FormatDictIndex2Item 格式化数据宝指标信息
+func FormatDictIndex2Item(origin DictIndex) (item *DictIndexItem) {
+	item = new(DictIndexItem)
+	item.Id = origin.Id
+	item.Code = origin.SourceCode
+	item.Name = origin.Name
+	item.Unit = origin.Unit
+	item.Frequency = origin.Frequency
+	item.DateFirst = utils.TimeTransferString(utils.FormatDate, origin.DateFirst)
+	item.DateLast = utils.TimeTransferString(utils.FormatDate, origin.DateLast)
+	item.TimeLastUpdate = utils.TimeTransferString(utils.FormatDateTime, origin.TimeLastUpdate)
+	return
+}

+ 35 - 6
models/db.go

@@ -43,12 +43,22 @@ func init() {
 	data_db, _ := orm.GetDB("data")
 	data_db.SetConnMaxLifetime(10 * time.Minute)
 
-	_ = orm.RegisterDataBase("eta", "mysql", utils.MYSQL_URL_ETA)
-	orm.SetMaxIdleConns("eta", 50)
-	orm.SetMaxOpenConns("eta", 100)
+	_ = orm.RegisterDataBase("gl", "mysql", utils.MYSQL_URL_GL)
+	orm.SetMaxIdleConns("gl", 50)
+	orm.SetMaxOpenConns("gl", 100)
 
-	etaDb, _ := orm.GetDB("eta")
-	etaDb.SetConnMaxLifetime(10 * time.Minute)
+	gl, _ := orm.GetDB("gl")
+	gl.SetConnMaxLifetime(10 * time.Minute)
+
+	// 用户主库
+	if utils.MYSQL_WEEKLY_URL != `` && (utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox) {
+		_ = orm.RegisterDataBase("weekly", "mysql", utils.MYSQL_WEEKLY_URL)
+		orm.SetMaxIdleConns("weekly", 50)
+		orm.SetMaxOpenConns("weekly", 100)
+
+		weeklyDb, _ := orm.GetDB("weekly")
+		weeklyDb.SetConnMaxLifetime(10 * time.Minute)
+	}
 
 	orm.Debug = true
 	orm.DebugLog = orm.NewLog(utils.Binlog)
@@ -92,6 +102,12 @@ func init() {
 
 	// 文档对比
 	initSaCompare()
+
+	// 商家配置
+	initBusinessConf()
+
+	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
+	data_manage.InitEdbSource()
 }
 
 // initSystem 系统表 数据表
@@ -203,7 +219,12 @@ func initEnglishReport() {
 		new(EnglishReportEmail),
 		new(EnglishReportEmailLog),
 		new(EnglishClassify),
-		new(EnglishVideo), // 英文研报线上路演
+		new(EnglishCompany),       // 英文客户
+		new(EnglishCompanyTodo),   // 英文客户TODO任务
+		new(EnglishVideo),         // 英文研报线上路演
+		new(EnPermission),         // 英文品种权限表
+		new(EnCompanyPermission),  // 英文客户品种权限关联表
+		new(EnClassifyPermission), // 英文分类品种权限关联表
 	)
 }
 
@@ -220,3 +241,11 @@ func initSaCompare() {
 		new(saModel.SaCompare), //文档对比
 	)
 }
+
+// initBusinessConf 商家配置
+func initBusinessConf() {
+	orm.RegisterModel(
+		new(BusinessConf),                // 商家配置表
+		new(BusinessConfOperationRecord), // 商家配置操作记录表
+	)
+}

+ 231 - 0
models/english_company.go

@@ -0,0 +1,231 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+const (
+	EnglishCompanyDisabled = iota
+	EnglishCompanyEnabled
+	EnglishCompanyHalfEnabled
+)
+
+// EnglishCompany 英文客户
+type EnglishCompany struct {
+	CompanyId   int       `orm:"column(company_id);pk" description:"英文客户ID"`
+	CompanyName string    `description:"客户名称"`
+	CountryCode string    `description:"国家Code"`
+	Country     string    `description:"国家"`
+	SellerId    int       `description:"销售ID"`
+	SellerName  string    `description:"销售姓名"`
+	ViewTotal   int       `description:"累计点击量/阅读量"`
+	IsDeleted   int       `description:"删除状态:0-正常;1-已删除"`
+	CreateTime  time.Time `description:"创建时间"`
+	ModifyTime  time.Time `description:"更新时间"`
+	Enabled     int       `description:"0-禁用; 1-启用; 2-部分禁用"`
+	Status      int       `description:"1:正式,2:临时,3:终止"`
+}
+
+type EnglishCompanyListItem struct {
+	EnglishCompany
+	TodoStatusStr string
+	TodoEndTime   time.Time
+	TodoSellerId  int
+}
+
+func (item *EnglishCompany) TableName() string {
+	return "english_company"
+}
+
+func (item *EnglishCompany) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+	item.CompanyId = int(id)
+	return
+}
+
+// EnglishCompanySaveReq 英文客户-保存请求体
+type EnglishCompanySaveReq struct {
+	CompanyId     int    `description:"客户ID"`
+	CompanyName   string `description:"客户名称"`
+	CountryCode   string `description:"国家代码"`
+	Country       string `description:"国家"`
+	SellerId      int    `description:"销售ID"`
+	EnPermissions []int  `description:"英文权限IDs"`
+}
+
+func (item *EnglishCompany) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// GetEnglishCompanyById 主键获取客户
+func GetEnglishCompanyById(id int) (item *EnglishCompany, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM english_company WHERE is_deleted = 0 AND company_id = ? LIMIT 1`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// GetEnglishCompanyByName 名称获取客户
+func GetEnglishCompanyByName(companyName string) (item *EnglishCompany, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM english_company WHERE is_deleted = 0 AND company_name = ? LIMIT 1`
+	err = o.Raw(sql, companyName).QueryRow(&item)
+	return
+}
+
+// EnglishCompanyDelReq 英文客户-删除请求体
+type EnglishCompanyDelReq struct {
+	CompanyId int `description:"客户ID"`
+}
+
+// DeleteEnglishCompanyAndEmails 删除英文客户及联系人
+func DeleteEnglishCompanyAndEmails(companyId int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+		} else {
+			_ = tx.Commit()
+		}
+	}()
+
+	// 删除客户
+	sql := `UPDATE english_company SET is_deleted = 1,modify_time = NOW() WHERE company_id = ? LIMIT 1`
+	_, err = tx.Raw(sql, companyId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 删除联系人
+	sql = `UPDATE english_report_email SET is_deleted = 1,modify_time = NOW() WHERE company_id = ?`
+	_, err = tx.Raw(sql, companyId).Exec()
+	return
+}
+
+// EnglishCompanyPageListResp 英文客户-分页列表响应体
+type EnglishCompanyPageListResp struct {
+	List   []*EnglishCompanyResp
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// EnglishCompanyResp 英文客户-列表响应体
+type EnglishCompanyResp struct {
+	CompanyId     int                     `description:"客户ID"`
+	CompanyName   string                  `description:"客户名称"`
+	CountryCode   string                  `description:"国家代码"`
+	Country       string                  `description:"国家"`
+	SellerId      int                     `description:"销售ID"`
+	SellerName    string                  `description:"销售姓名"`
+	ViewTotal     int                     `description:"累计点击量"`
+	CreateTime    string                  `description:"创建时间"`
+	Enabled       int                     `description:"0-禁用; 1-启用; 2-部分禁用"`
+	TodoInfo      *EnglishCompanyListTodo `description:"TODO任务信息"`
+	EnPermissions []int                   `description:"英文权限"`
+}
+
+// EnglishCompanyListTodo 英文客户列表-TODO任务信息
+type EnglishCompanyListTodo struct {
+	Deadline       string `description:"未完成的todo任务的截止日期,截止目前还剩余的天数"`
+	TodoEndTimeStr string `description:"未完成的todo任务的截止日期拼接格式"`
+	//TodoEndTime     time.Time `description:"未完成的todo任务的截止日期"`
+	TodoStatus      bool   `description:"是否存在进行中任务"`
+	CanConfirm      bool   `description:"是否允许完成任务"`
+	HiddenConfirm   bool   `description:"是否隐藏完成任务按钮"`
+	HiddenCreate    bool   `description:"是否隐藏新增/编辑按钮"`
+	TodoButtonColor string `description:"任务按钮颜色: red; green; gray"`
+}
+
+// GetEnglishCompanyPageList 获取客户列表-分页
+func GetEnglishCompanyPageList(condition string, pars []interface{}, order string, startSize, pageSize int) (total int, list []*EnglishCompanyListItem, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT
+	c.*,
+IF
+	( ct.status IS NULL, "无任务", ct.status ) AS todo_status_str,
+	ct.seller_id as todo_seller_id,
+IF
+	( ct.end_time IS NULL or ct.status !="进行中", "9999-01-01", ct.end_time) AS todo_end_time
+FROM
+	english_company AS c
+	LEFT JOIN (
+SELECT
+	b.* 
+FROM
+	(
+SELECT
+	company_id,
+	MAX( create_time ) AS ct 
+FROM
+	english_company_todo 
+WHERE
+	is_delete = 0 
+	AND STATUS != "已作废"
+GROUP BY
+	company_id 
+	) AS a
+	LEFT JOIN english_company_todo AS b ON b.company_id = a.company_id 
+	AND b.create_time = a.ct 
+	) AS ct ON c.company_id = ct.company_id 
+WHERE
+	c.is_deleted = 0 AND c.status = 1`
+	sql += condition
+	if order != "" {
+		sql += order
+	} else {
+		sql += ` ORDER BY c.create_time DESC, c.company_id DESC`
+	}
+	totalSQl := `SELECT COUNT(1) total FROM (` + sql + `) z`
+	if err = o.Raw(totalSQl, pars).QueryRow(&total); err != nil {
+		return
+	}
+	sql += ` LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&list)
+	return
+}
+
+// GetEnglishCompanyViewPageListResp 英文客户-点击量分页列表响应体
+type GetEnglishCompanyViewPageListResp struct {
+	List   []*EnglishCompanyViewResp
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// EnglishCompanyViewResp 英文客户-点击量响应体
+type EnglishCompanyViewResp struct {
+	EmailId      int    `description:"联系人ID"`
+	UserName     string `description:"联系人姓名"`
+	Email        string `description:"邮箱地址"`
+	ViewTotal    int    `description:"累计点击量"`
+	LastViewTime string `description:"创建时间"`
+}
+
+// GetEnglishCompanyList 获取英文客户列表
+func GetEnglishCompanyList(condition string, pars []interface{}, order string) (list []*EnglishCompany, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM english_company WHERE is_deleted = 0 `
+	sql += condition
+	if order != "" {
+		sql += order
+	} else {
+		sql += ` ORDER BY create_time DESC`
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}
+
+// EnglishCompanyEditEnabledReq 禁启用请求体
+type EnglishCompanyEditEnabledReq struct {
+	CompanyId int `description:"公司ID"`
+	Enabled   int `description:"1:有效,0:禁用"`
+}

+ 258 - 0
models/english_company_todo.go

@@ -0,0 +1,258 @@
+package models
+
+import (
+	"eta/eta_mobile/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+// 英文客户Todo状态枚举值
+const (
+	EnglishCompanyTodoStatusDoing     = "进行中"
+	EnglishCompanyTodoStatusCompleted = "已完成"
+	EnglishCompanyTodoStatusVoided    = "已作废"
+	EnglishCompanyTodoStatusNull      = "无任务"
+)
+
+// EnglishCompanyTodo 英文客户TODO任务
+type EnglishCompanyTodo struct {
+	Id                 int       `orm:"column(id);pk"`
+	CompanyId          int       `description:"客户id"`
+	Content            string    `description:"任务描述"`
+	SellerId           int       `description:"客户所属销售id"`
+	SellerName         string    `description:"客户所属销售名称"`
+	CreateUserId       int       `description:"创建人用户id"`
+	CreateUserName     string    `description:"创建人用户姓名"`
+	ApproveUserId      int       `description:"审批人用户id"`
+	ApproveUserName    string    `description:"审批人用户姓名"`
+	ApprovedSellerId   int       `description:"审批时,客户所属销售id"`
+	ApprovedSellerName string    `description:"审批时,客户所属销售名称"`
+	Status             string    `description:"任务状态: 枚举值:进行中,已完成,已作废"`
+	ModifyTime         time.Time `description:"修改时间"`
+	ApproveTime        time.Time `description:"审核时间"`
+	CreateTime         time.Time `description:"创建时间"`
+	EndTime            time.Time `description:"截止时间"`
+	IsDelete           int       `json:"-" description:"是否已经删除,0:未删除,1:已删除;默认:0"`
+	Remark             string    `description:"审批备注"`
+}
+
+// EnglishCompanyTodoResp 英文客户TODO响应体
+type EnglishCompanyTodoResp struct {
+	Id              int    `orm:"column(id);pk"`
+	CompanyId       int    `description:"客户id"`
+	Content         string `description:"任务描述"`
+	SellerId        int    `description:"客户所属销售id"`
+	SellerName      string `description:"客户所属销售名称"`
+	CreateUserId    int    `description:"创建人用户id"`
+	CreateUserName  string `description:"创建人用户姓名"`
+	ApproveUserId   int    `description:"审批人用户id"`
+	ApproveUserName string `description:"审批人用户姓名"`
+	Status          string `description:"任务状态: 枚举值:进行中,已完成,已作废"`
+	CreateTime      string `description:"创建时间"`
+	EndTime         string `description:"截止时间"`
+	ApproveTime     string `description:"审核时间"`
+	EndTimeStr      string `description:"格式化后的截止时间"`
+	Remark          string `description:"审批备注"`
+}
+
+func (item *EnglishCompanyTodo) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+	item.CompanyId = int(id)
+	return
+}
+
+func (item *EnglishCompanyTodo) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// EnglishCompanyTodoAddReq 新增任务请求
+type EnglishCompanyTodoAddReq struct {
+	CompanyId   int    `description:"客户id"`
+	Description string `description:"任务描述"`
+	EndTime     string `description:"截止时间"`
+}
+
+// EnglishCompanyTodoEditReq 编辑任务请求
+type EnglishCompanyTodoEditReq struct {
+	Id          int    `description:"客户任务记录id"`
+	CompanyId   int    `description:"客户id"`
+	Description string `description:"任务描述"`
+	EndTime     string `description:"截止时间"`
+}
+
+// EnglishCompanyTodoApproveReq 审批任务请求
+type EnglishCompanyTodoApproveReq struct {
+	Id     int    `description:"客户任务记录id"`
+	Remark string `description:"审批备注"`
+}
+
+// GetEnglishCompanyTodoById 根据任务ID获取客户任务
+func GetEnglishCompanyTodoById(id int) (item *EnglishCompanyTodo, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM english_company_todo WHERE id = ? LIMIT 1 `
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// GetCountDoingEnglishCompanyTodo 获取正在进行中的任务数量
+func GetCountDoingEnglishCompanyTodo(companyId int) (total int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT count(1) AS total FROM english_company_todo WHERE status = "进行中" AND company_id = ? AND is_delete = 0 `
+	err = o.Raw(sql, companyId).QueryRow(&total)
+	return
+}
+
+// GetEnglishCompanyTodoPageListResp 英文客户TODO-分页列表
+type GetEnglishCompanyTodoPageListResp struct {
+	List   []*EnglishCompanyTodoResp
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// GetEnglishCompanyTodoList 获取客户任务列表
+func GetEnglishCompanyTodoList(companyId, startSize, pageSize int, order string) (total int, items []*EnglishCompanyTodo, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT
+				a.*
+			FROM
+				english_company_todo a
+			JOIN english_company b ON a.company_id = b.company_id
+			WHERE
+				a.company_id = ? AND a.status != "已作废" AND a.is_delete = 0 `
+	totalSQl := `SELECT COUNT(1) total FROM (` + sql + `) z`
+	if err = o.Raw(totalSQl, companyId).QueryRow(&total); err != nil {
+		return
+	}
+	if order != `` {
+		sql += order
+	} else {
+		sql += ` ORDER BY a.create_time DESC`
+	}
+	sql += ` LIMIT ?,?`
+	_, err = o.Raw(sql, companyId, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetDoingEnglishCompanyTodoList 获取客户的进行中任务列表
+func GetDoingEnglishCompanyTodoList(companyId int) (items []*EnglishCompanyTodo, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT
+				a.*
+			FROM
+				english_company_todo a
+			JOIN english_company b ON a.company_id = b.company_id
+			WHERE
+				a.company_id = ? AND a.status = "进行中" AND a.is_delete = 0
+			ORDER BY
+				a.create_time ASC`
+	_, err = o.Raw(sql, companyId).QueryRows(&items)
+	return
+}
+
+// GetEnglishCompanyLatestTodoByCompanyIds 获取英文客户最新的一条TODO任务
+func GetEnglishCompanyLatestTodoByCompanyIds(companyIds []int) (items []*EnglishCompanyTodo, err error) {
+	itemsLen := len(companyIds)
+	if itemsLen == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT b.* FROM 
+			(
+				SELECT
+					company_id,
+					MAX(create_time) AS ct
+				FROM
+					english_company_todo
+				WHERE
+					is_delete = 0 AND status != "已作废" AND company_id IN (` + utils.GetOrmInReplace(itemsLen) + `)
+				GROUP BY
+					company_id
+			) AS a
+			LEFT JOIN english_company_todo AS b ON b.company_id = a.company_id AND b.create_time = a.ct `
+	_, err = o.Raw(sql, companyIds).QueryRows(&items)
+	return
+}
+
+type EnglishCompanyTodoDoing struct {
+	Id                 int       `description:"待办ID"`
+	CompanyId          int       `description:"客户id"`
+	CompanyName        string    `description:"客户名称"`
+	Content            string    `description:"任务描述"`
+	SellerId           int       `description:"客户所属销售id"`
+	SellerName         string    `description:"客户所属销售名称"`
+	CreateUserId       int       `description:"创建人用户id"`
+	CreateUserName     string    `description:"创建人用户姓名"`
+	ApproveUserId      int       `description:"审批人用户id"`
+	ApproveUserName    string    `description:"审批人用户姓名"`
+	ApprovedSellerId   int       `description:"审批时,客户所属销售id"`
+	ApprovedSellerName string    `description:"审批时,客户所属销售名称"`
+	Status             string    `description:"任务状态: 枚举值:进行中,已完成,已作废"`
+	ModifyTime         time.Time `description:"修改时间"`
+	ApproveTime        time.Time `description:"审核时间"`
+	CreateTime         time.Time `description:"创建时间"`
+	EndTime            time.Time `description:"截止时间"`
+	Remark             string    `description:"审批备注"`
+}
+
+type EnglishCompanyTodoDoingResp struct {
+	Id              int    `description:"待办ID"`
+	CompanyId       int    `description:"客户id"`
+	CompanyName     string `description:"客户名称"`
+	Content         string `description:"任务描述"`
+	SellerId        int    `description:"客户所属销售id"`
+	SellerName      string `description:"客户所属销售名称"`
+	CreateUserId    int    `description:"创建人用户id"`
+	CreateUserName  string `description:"创建人用户姓名"`
+	ApproveUserId   int    `description:"审批人用户id"`
+	ApproveUserName string `description:"审批人用户姓名"`
+	Status          string `description:"任务状态: 枚举值:进行中,已完成,已作废"`
+	CreateTime      string `description:"创建时间"`
+	EndTime         string `description:"截止时间"`
+	ApproveTime     string `description:"审核时间"`
+	Remark          string `description:"审批备注"`
+}
+
+// GetEnglishCompanyTodoDoingPageListResp 英文客户未完成TODO-分页列表
+type GetEnglishCompanyTodoDoingPageListResp struct {
+	List   []*EnglishCompanyTodoDoingResp
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// GetEnglishCompanyTodoDoingList 获取客户任务未完成列表
+func GetEnglishCompanyTodoDoingList(startSize, pageSize int, order string) (total int, items []*EnglishCompanyTodoDoing, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT
+				a.*,
+				b.company_name
+			FROM
+				english_company_todo a
+			JOIN english_company b ON a.company_id = b.company_id
+			WHERE
+				a.status = "进行中" AND a.is_delete = 0 `
+	totalSQl := `SELECT COUNT(1) total FROM (` + sql + `) z`
+	if err = o.Raw(totalSQl).QueryRow(&total); err != nil {
+		return
+	}
+	if order != `` {
+		sql += order
+	} else {
+		sql += ` ORDER BY a.end_time ASC`
+	}
+	sql += ` LIMIT ?,?`
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// DeleteEnglishCompanyTodoByCompanyId (软)删除英文客户TODO
+func DeleteEnglishCompanyTodoByCompanyId(companyId int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE english_company_todo SET is_delete = 1 WHERE company_id = ?`
+	_, err = o.Raw(sql, companyId).Exec()
+	return
+}

+ 95 - 53
models/english_report.go

@@ -211,6 +211,8 @@ type EnglishReportDetail struct {
 	EmailState         int    `description:"群发邮件状态: 0-未发送; 1-已发送"`
 	EmailAuth          bool   `description:"是否有权限群发邮件"`
 	EmailHasFail       bool   `description:"是否存在邮件发送失败的记录"`
+	ClassifyIdRoot     int    `description:"顶级分类id"`
+	ClassifyNameRoot   string `description:"顶级分类名称"`
 }
 
 func GetEnglishReportById(reportId int) (item *EnglishReportDetail, err error) {
@@ -261,6 +263,9 @@ type EnglishReportList struct {
 	FromReportId       int       `description:"继承的报告ID(英文策略报告ID)"`
 	AdminId            int       `description:"创建者账号"`
 	AdminRealName      string    `description:"创建者姓名"`
+	FullClassifyName   string    `description:"顶级分类名/父级分类名/当前分类名"`
+	ClassifyIdRoot     int       `description:"顶级分类id"`
+	ClassifyNameRoot   string    `description:"顶级分类名称"`
 }
 
 type EnglishReportListResp struct {
@@ -384,13 +389,15 @@ type EnglishClassifyList struct {
 	ClassifyName  string    `description:"分类名称"`
 	Sort          int       `description:"排序"`
 	ParentId      int       `description:"父级分类id"`
+	RootId        int       `description:"一级分类ID"`
 	CreateTime    time.Time `description:"创建时间"`
 	ModifyTime    time.Time `description:"修改时间"`
 	ClassifyLabel string    `description:"分类标签"`
 	ShowType      int       `description:"展示类型:1-列表 2-专栏"`
 	IsShow        int       `description:"是否在小程序显示:1-显示 0-隐藏"`
-	ClassifyType  int       `description:"分类类型:0英文报告,1英文线上路演"`
-	Child         []*EnglishClassify
+	//ClassifyType  int       `description:"分类类型:0英文报告,1英文线上路演"`
+	EnPermissions []int `description:"英文权限IDs"`
+	Child         []*EnglishClassifyList
 }
 
 type EnglishClassifyListResp struct {
@@ -398,75 +405,77 @@ type EnglishClassifyListResp struct {
 	Paging *paging.PagingItem `description:"分页数据"`
 }
 
-// 获取分类列表
-func GetEnglishClassifyList(startSize, pageSize int, keyWord string, classifyType int) (items []*EnglishClassifyList, err error) {
+// GetEnglishClassifyRootId 获取一级分类列表
+func GetEnglishClassifyRootId(startSize, pageSize int, keyWord string) (items []*EnglishClassifyList, err error) {
 	sql := ``
 	o := orm.NewOrmUsingDB("rddp")
 	if keyWord != "" {
 		sql = `SELECT * FROM (
-                   SELECT * FROM english_classify
-                   WHERE parent_id=0 AND classify_name LIKE '%` + keyWord + `%' AND classify_type = ?
+			                   SELECT * FROM english_classify
+                   WHERE parent_id=0 AND classify_name LIKE '%` + keyWord + `%'
                    UNION
                    SELECT * FROM english_classify
                    WHERE id IN(SELECT parent_id FROM english_classify
-                   WHERE parent_id>0 AND classify_name LIKE '%` + keyWord + `%') AND classify_type = ?
+                   WHERE parent_id>0 AND classify_name LIKE '%` + keyWord + `%')
                    )AS t
                    ORDER BY sort ASC,create_time ASC
                    LIMIT ?,? `
-		_, err = o.Raw(sql, classifyType, classifyType, startSize, pageSize).QueryRows(&items)
+		_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
 	} else {
-		sql = `SELECT * FROM english_classify WHERE parent_id=0 AND classify_type = ? ORDER BY sort ASC,create_time ASC LIMIT ?,? `
-		_, err = o.Raw(sql, classifyType, startSize, pageSize).QueryRows(&items)
+		sql = `SELECT * FROM english_classify WHERE parent_id=0 ORDER BY sort ASC,create_time ASC LIMIT ?,? `
+		_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
 	}
 	return
 }
 
-func GetEnglishClassifyListCount(keyWord string, classifyType int) (count int, err error) {
+func GetEnglishClassifyListCount(keyWord string) (count int, err error) {
 	sqlCount := ``
 	o := orm.NewOrmUsingDB("rddp")
 	if keyWord != "" {
 		sqlCount = `SELECT  COUNT(1) AS count FROM (
                SELECT * FROM english_classify
-               WHERE parent_id=0 AND classify_name LIKE '%` + keyWord + `%' AND classify_type = ?
+               WHERE parent_id=0 AND classify_name LIKE '%` + keyWord + `%'
                UNION
                SELECT * FROM english_classify
                WHERE id IN(SELECT parent_id FROM english_classify
-               WHERE parent_id>0 AND classify_name LIKE '%` + keyWord + `%' AND classify_type = ?)
+               WHERE parent_id>0 AND classify_name LIKE '%` + keyWord + `%')
                )AS t `
-		err = o.Raw(sqlCount, classifyType, classifyType).QueryRow(&count)
+		err = o.Raw(sqlCount).QueryRow(&count)
 	} else {
-		sqlCount = `SELECT COUNT(1) AS count FROM english_classify WHERE parent_id=0 AND classify_type = ?`
-		err = o.Raw(sqlCount, classifyType).QueryRow(&count)
+		sqlCount = `SELECT COUNT(1) AS count FROM english_classify WHERE parent_id=0`
+		err = o.Raw(sqlCount).QueryRow(&count)
 	}
 
 	return
 }
 
-func GetEnglishClassifyChild(parentId int, keyWord string, classifyType int) (items []*EnglishClassify, err error) {
-	o := orm.NewOrmUsingDB("rddp")
+func GetEnglishClassifyListByRootId(rootIds []int, keyWord string) (items []*EnglishClassifyList, err error) {
 	sql := ``
+	o := orm.NewOrmUsingDB("rddp")
 	if keyWord != "" {
-		sql = `SELECT * FROM english_classify WHERE parent_id=? AND classify_type = ? AND classify_name LIKE '%` + keyWord + `%' ORDER BY create_time ASC `
+		sql = `SELECT
+	a.*
+FROM
+	english_classify a
+	LEFT JOIN english_classify b ON a.root_id = b.id
+	LEFT JOIN english_classify c ON a.parent_id = c.id
+	WHERE a.parent_id >0 and a.classify_name LIKE '%` + keyWord + `%' and a.root_id IN (` + utils.GetOrmInReplace(len(rootIds)) + `)`
+		_, err = o.Raw(sql, rootIds).QueryRows(&items)
 	} else {
-		sql = `SELECT * FROM english_classify WHERE parent_id=? AND classify_type = ? ORDER BY create_time ASC `
+		sql = `SELECT * FROM english_classify WHERE parent_id >0 and root_id IN (` + utils.GetOrmInReplace(len(rootIds)) + `) `
+		_, err = o.Raw(sql, rootIds).QueryRows(&items)
 	}
-	_, err = o.Raw(sql, parentId, classifyType).QueryRows(&items)
 	return
 }
 
-func GetEnglishClassifyChildByParentIds(parentIds []int, keyWord string, classifyType int) (items []*EnglishClassify, err error) {
+func GetEnglishClassifyChildByIds(ids []int) (items []*EnglishClassifyList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ``
-	if keyWord != "" {
-		sql = `SELECT * FROM english_classify WHERE parent_id IN (` + utils.GetOrmInReplace(len(parentIds)) + `) AND classify_type = ? AND classify_name LIKE '%` + keyWord + `%' ORDER BY create_time ASC `
-	} else {
-		sql = `SELECT * FROM english_classify WHERE parent_id IN (` + utils.GetOrmInReplace(len(parentIds)) + `) AND classify_type = ? ORDER BY create_time ASC `
-	}
-	_, err = o.Raw(sql, parentIds, classifyType).QueryRows(&items)
+	sql := `SELECT * FROM english_classify WHERE id IN (` + utils.GetOrmInReplace(len(ids)) + `) ORDER BY create_time ASC `
+	_, err = o.Raw(sql, ids).QueryRows(&items)
 	return
 }
 
-func GetEnglishReportDetailByClassifyId(classifyIdFirst, classifyIdSecond int) (item *EnglishReport, err error) {
+func GetEnglishReportDetailByClassifyId(classifyIdFirst, classifyIdSecond int) (item *EnglishReportDetail, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := ` SELECT * FROM english_report WHERE 1=1 `
 	if classifyIdSecond > 0 {
@@ -503,12 +512,13 @@ type EnglishClassify struct {
 	ClassifyName  string    `description:"分类名称"`
 	Sort          int       `description:"排序"`
 	ParentId      int       `description:"父级分类id"`
+	RootId        int       `description:"一级分类ID"`
 	CreateTime    time.Time `description:"创建时间"`
 	ModifyTime    time.Time `description:"修改时间"`
 	ClassifyLabel string    `description:"分类标签"`
 	ShowType      int       `description:"展示类型:1-列表 2-专栏"`
 	IsShow        int       `description:"是否在小程序显示:1-显示 0-隐藏"`
-	ClassifyType  int       `description:"分类类型:0英文报告,1英文线上路演"`
+	//ClassifyType  int       `description:"分类类型:0英文报告,1英文线上路演"`
 }
 
 func AddEnglishClassify(item *EnglishClassify) (lastId int64, err error) {
@@ -524,9 +534,10 @@ func ModifyEnglishClassify(item *EnglishClassify) (err error) {
 	classify_name = ?,
 	sort = ?,
 	parent_id = ?,
+	root_id = ?,
 	modify_time = ? 
 	WHERE id = ? `
-	_, err = o.Raw(sql, item.ClassifyName, item.Sort, item.ParentId, item.ModifyTime, item.Id).Exec()
+	_, err = o.Raw(sql, item.ClassifyName, item.Sort, item.ParentId, item.RootId, item.ModifyTime, item.Id).Exec()
 	return
 }
 
@@ -565,30 +576,33 @@ func GetEnglishReportCounts(classifyId, parentId int) (count int, err error) {
 	return
 }
 
-func GetEnglishClassifyCountsByName(name string, parentId int, classifyType int) (count int, err error) {
+func GetEnglishClassifyCountsByName(name string, parentId int) (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT COUNT(1) AS count FROM english_classify WHERE classify_name=? AND parent_id = ? AND classify_type = ? `
-	err = o.Raw(sql, name, parentId, classifyType).QueryRow(&count)
+	sql := `SELECT COUNT(1) AS count FROM english_classify WHERE classify_name=? AND parent_id = ? `
+	err = o.Raw(sql, name, parentId).QueryRow(&count)
 	return
 }
 
-// 获取分类列表
-func GetEnglishFirstClassifyList(classifyType, startSize, pageSize int) (items []*EnglishClassifyList, err error) {
-	sql := ``
-
-	sql = `SELECT * FROM english_classify WHERE parent_id=0 AND classify_type = ?  ORDER BY sort ASC,create_time ASC LIMIT ?,? `
-
+// GetEnglishFirstClassifyList 获取一级、二级分类列表
+func GetEnglishFirstClassifyList(startSize, pageSize int) (items []*EnglishClassifyList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	_, err = o.Raw(sql, classifyType, startSize, pageSize).QueryRows(&items)
+	sql := `SELECT * FROM english_classify WHERE parent_id =0  ORDER BY sort ASC,create_time ASC LIMIT ?,? `
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
 	return
 }
 
-func GetEnglishFirstClassifyListCount(classifyType int) (count int, err error) {
-	sqlCount := ``
-	sqlCount = `SELECT COUNT(1) AS count FROM english_classify WHERE parent_id=0 AND classify_type = ? `
+// GetEnglishSecondClassifyList 获取一级、二级分类列表
+func GetEnglishSecondClassifyList(rootIds []int) (items []*EnglishClassifyList, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM english_classify WHERE root_id IN (` + utils.GetOrmInReplace(len(rootIds)) + `) and parent_id>0 and root_id=parent_id ORDER BY sort ASC,create_time ASC`
+	_, err = o.Raw(sql, rootIds).QueryRows(&items)
+	return
+}
 
+func GetEnglishFirstClassifyListCount() (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	err = o.Raw(sqlCount, classifyType).QueryRow(&count)
+	sqlCount := `SELECT COUNT(1) AS count FROM english_classify WHERE parent_id=0`
+	err = o.Raw(sqlCount).QueryRow(&count)
 	return
 }
 
@@ -647,10 +661,10 @@ func (reportInfo *EnglishReport) UpdateReport(cols []string) (err error) {
 }
 
 // GetAllEnglishClassify 获取所有英文分类
-func GetAllEnglishClassify(classifyType int) (list []*Classify, err error) {
+func GetAllEnglishClassify() (list []*Classify, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT * FROM english_classify where classify_type = ? `
-	_, err = o.Raw(sql, classifyType).QueryRows(&list)
+	sql := ` SELECT * FROM english_classify `
+	_, err = o.Raw(sql).QueryRows(&list)
 	return
 }
 
@@ -710,7 +724,7 @@ func (m RSClassifyList) Swap(i, j int) {
 	m[i], m[j] = m[j], m[i]
 }
 
-type RSChildClassifyList []*EnglishClassify
+type RSChildClassifyList []*EnglishClassifyList
 
 func (m RSChildClassifyList) Len() int {
 	return len(m)
@@ -725,9 +739,37 @@ func (m RSChildClassifyList) Swap(i, j int) {
 }
 
 // GetEnglishClassifyByClassifyNameParentId 获取英文分类
-func GetEnglishClassifyByClassifyNameParentId(classifyName string, parentId, classifyType int) (item *Classify, err error) {
+func GetEnglishClassifyByClassifyNameParentId(classifyName string, parentId int) (item *Classify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM english_classify where classify_name = ? and parent_id = ? `
+	err = o.Raw(sql, classifyName, parentId).QueryRow(&item)
+	return
+}
+
+type EnglishClassifyFullName struct {
+	Id           int    `description:"分类ID"`
+	ParentId     int    `description:"父级分类id"`
+	RootId       int    `description:"一级分类ID"`
+	RootName     string `description:"一级分类名"`
+	ParentName   string `description:"二级分类名"`
+	ClassifyName string `description:"分类名称"`
+}
+
+// GetEnglishClassifyFullNameByIds 获取英文分类名一级/二级/三级
+func GetEnglishClassifyFullNameByIds(classifyIds []int) (list []*EnglishClassifyFullName, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT * FROM english_classify where classify_name = ? and parent_id = ? and classify_type = ? `
-	err = o.Raw(sql, classifyName, parentId, classifyType).QueryRow(&item)
+	sql := ` SELECT
+	a.id,
+	a.parent_id,
+	a.root_id,
+	a.classify_name,
+	b.classify_name AS root_name,
+	c.classify_name AS parent_name 
+FROM
+	english_classify a
+	LEFT JOIN english_classify b ON a.root_id = b.id
+	LEFT JOIN english_classify c ON a.parent_id = c.id 
+where a.id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `)`
+	_, err = o.Raw(sql, classifyIds).QueryRows(&list)
 	return
 }

+ 4 - 4
models/permission.go

@@ -13,7 +13,7 @@ type ChartPermissionSearchKeyWordMapping struct {
 }
 
 func GetPermission(classifyNameSecond string) (items []*ChartPermissionSearchKeyWordMapping, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := `SELECT * FROM chart_permission_search_key_word_mapping AS a WHERE a.from='rddp' AND a.key_word=? `
 	_, err = o.Raw(sql, classifyNameSecond).QueryRows(&items)
 	return
@@ -22,14 +22,14 @@ func GetPermission(classifyNameSecond string) (items []*ChartPermissionSearchKey
 func AddChartPermissionChapterMapping(chartPermissionId int, reportId int64) (err error) {
 	sql := `INSERT INTO chart_permission_chapter_mapping (chart_permission_id, report_chapter_type_id,research_type)
            VALUES(?,?,?)`
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	_, err = o.Raw(sql, chartPermissionId, reportId, "rddp").Exec()
 	return
 }
 
 func RemoveChartPermissionChapterMapping(reportId int64) (err error) {
 	sql := ` DELETE FROM chart_permission_chapter_mapping WHERE research_type=? AND report_chapter_type_id=? `
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	_, err = o.Raw(sql, "rddp", reportId).Exec()
 	return
 }
@@ -40,7 +40,7 @@ type ChartPermissionMappingIdName struct {
 }
 
 func GetChartPermissionNameFromMappingByKeyword(keyword string, source string) (list []*ChartPermissionMappingIdName, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := " SELECT b.chart_permission_id AS permission_id,b.permission_name FROM chart_permission_search_key_word_mapping AS a INNER JOIN chart_permission AS b ON a.chart_permission_id = b.chart_permission_id WHERE a.`from` = ? AND a.key_word = ? "
 	_, err = o.Raw(sql, source, keyword).QueryRows(&list)
 

+ 4 - 264
models/report.go

@@ -121,7 +121,7 @@ func GetReportList(condition string, pars []interface{}, companyType string, sta
 	if condition != "" {
 		sql += condition
 	}
-	sql += `ORDER BY state ASC, modify_time DESC LIMIT ?,?`
+	sql += `ORDER BY FIELD(state,3,1,2,4), modify_time DESC LIMIT ?,?`
 	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
 	return
 }
@@ -191,21 +191,6 @@ func GetReportById(reportId int) (item *ReportDetail, err error) {
 	return
 }
 
-func GetReportByIds(reportIds string) (list []*ReportDetail, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT * FROM report WHERE id in ` + reportIds
-	_, err = o.Raw(sql).QueryRows(&list)
-	return
-}
-
-// GetSimpleReportByIds 根据报告ID查询报告基本信息
-func GetSimpleReportByIds(reportIds string) (list []*ReportDetail, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT id, title FROM report WHERE id IN (` + reportIds + `)`
-	_, err = o.Raw(sql).QueryRows(&list)
-	return
-}
-
 func GetReportStage(classifyIdFirst, classifyIdSecond int) (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := ``
@@ -522,14 +507,6 @@ func GetReportByReportId(reportId int) (item *Report, err error) {
 	return
 }
 
-// GetReportByOldReportId 根据老报告id主键获取报告
-func GetReportByOldReportId(reportId int) (item *Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT * FROM report WHERE old_report_id = ?`
-	err = o.Raw(sql, reportId).QueryRow(&item)
-	return
-}
-
 // DeleteDayWeekReportAndChapter 删除晨周报及章节
 func DeleteDayWeekReportAndChapter(reportId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -571,26 +548,6 @@ type ReportDetailView struct {
 	ChapterList []*ReportChapter
 }
 
-func GetUnPublishDayReport(startTime time.Time, endTime time.Time) (item *Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT
-				*
-			FROM
-				report AS a
-			WHERE
-				a.has_chapter = 1
-			AND a.chapter_type = "day"
-			AND a.state = 1
-			AND (
-				a.create_time BETWEEN ? AND ?
-			)
-			ORDER BY
-				a.create_time DESC
-			LIMIT 1 `
-	err = o.Raw(sql, startTime, endTime).QueryRow(&item)
-	return
-}
-
 type ElasticReportDetail struct {
 	ReportId           int    `description:"报告ID"`
 	ReportChapterId    int    `description:"报告章节ID"`
@@ -617,15 +574,6 @@ func GetLastPublishDayWeekReport(chapterType string) (item *Report, err error) {
 	return
 }
 
-// GetNewReportExist
-func GetNewReportExist(oldReportId int) (item *Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT id FROM report WHERE old_report_id = ? LIMIT 1 `
-	err = o.Raw(sql, oldReportId).QueryRow(&item)
-
-	return
-}
-
 // PublishReportAndChapter 发布报告及章节
 func PublishReportAndChapter(reportInfo *Report, publishIds string, unPublishIds string, isPublishReport bool, cols []string) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -658,15 +606,6 @@ func PublishReportAndChapter(reportInfo *Report, publishIds string, unPublishIds
 	return
 }
 
-func GetSyncEmptyVideoReport() (list []*Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT id FROM report WHERE old_report_id > 0 AND state = 2 AND chapter_type = "" AND (video_size = "" OR video_play_seconds = "")
-UNION ALL
-SELECT DISTINCT report_id FROM report_chapter WHERE publish_state = 2 AND (video_size = "" OR video_play_seconds = "") `
-	_, err = o.Raw(sql).QueryRows(&list)
-	return
-}
-
 // 发布报告
 func PublishReportById(reportId int, publishTime time.Time) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -675,181 +614,6 @@ func PublishReportById(reportId int, publishTime time.Time) (err error) {
 	return
 }
 
-// GetCommentReportByReportId 查询有留言的报告列表
-func GetCommentReportByReportId(condition string, pars []interface{}, startSize, pageSize int) (list []*Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT
-	id,
-	create_time,
-	title,
-	classify_name_first,
-	classify_id_first,
-	classify_name_second,
-	classify_id_second,
-	state,
-IF
-	( publish_time, publish_time, create_time ) AS publish_time 
-FROM
-	report 
-WHERE
-	1=1
-  `
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY  publish_time DESC , title ASC LIMIT ?,?`
-	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&list)
-	return
-}
-
-// GetCommentReportByReportIdOrderBy 查询有留言的报告列表(指定排序)
-func GetCommentReportByReportIdOrderBy(condition string, pars []interface{}, startSize, pageSize int, orderBy string) (list []*Report, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT
-	id,
-	create_time,
-	title,
-	classify_name_first,
-	classify_id_first,
-	classify_name_second,
-	classify_id_second,
-	state,
-IF
-	( publish_time, publish_time, create_time ) AS publish_time 
-FROM
-	report 
-WHERE
-	1=1
-  `
-	if condition != "" {
-		sql += condition
-	}
-	if orderBy == `` {
-		sql += ` ORDER BY  publish_time DESC , title ASC `
-	} else {
-		sql += orderBy
-	}
-	sql += ` LIMIT ?,? `
-	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&list)
-	return
-}
-
-// GetCommentReportTotalByReportId 查询有留言的报告列表总数
-func GetCommentReportTotalByReportId(condition string, pars []interface{}) (total int64, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT count(*)
-        FROM report WHERE 1=1`
-	if condition != "" {
-		sql += condition
-	}
-	err = o.Raw(sql, pars).QueryRow(&total)
-	return
-}
-
-// 点赞相关的报告列表
-type LikeReportItem struct {
-	ReportId              int       `description:"报告Id"`
-	ReportChapterId       int       `description:"报告章节Id"`
-	ClassifyIdFirst       int       `description:"一级分类id"`
-	ClassifyNameFirst     string    `description:"一级分类名称"`
-	ClassifyIdSecond      int       `description:"二级分类id"`
-	ClassifyNameSecond    string    `description:"二级分类名称"`
-	ReportChapterTypeId   int       `description:"章节类型"`
-	ReportChapterTypeName string    `description:"品种名称"`
-	PublishTime           time.Time `description:"发布时间" `
-	Title                 string    `description:"标题"`
-}
-
-// GetLikeReportByReportIdReportChapterId 获取有被点赞的报告列表
-func GetLikeReportByReportIdReportChapterId(reportIds string, chapterIds string, orderStr string, startSize, pageSize int) (list []*LikeReportItem, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `( SELECT
-id AS report_id,
-0 AS report_chapter_id,
-classify_id_first,
-classify_id_second,
-classify_name_first,
-classify_name_second,
-0 as report_chapter_type_id,
-"" as report_chapter_type_name,
-publish_time,
-title
-FROM
-	report
-WHERE
-	classify_name_first != "晨报" 
-	AND classify_name_first != "周报"
-	AND id in (` + reportIds + `)
-	)
-UNION
-	
-( SELECT
-report_id,
-report_chapter_id,
-classify_id_first,
-0 as classify_id_second,
-classify_name_first,
-null as classify_name_second,
-type_id as report_chapter_type_id,
-type_name as report_chapter_type_name,
-publish_time,
-title
-FROM
-	report_chapter
-WHERE
-	 report_chapter_id in (` + chapterIds + `)
-	)`
-	if orderStr != "" {
-		sql += ` ORDER BY FIELD(CONCAT(report_id, "-",report_chapter_id),` + orderStr + `)`
-	} else {
-		sql += ` ORDER BY  publish_time DESC, report_id Desc`
-	}
-	sql += ` LIMIT ?,?`
-	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&list)
-	return
-}
-
-// GetLikeReportTotalByReportIdReportChapterId 获取有被点赞的报告列表总数
-func GetLikeReportTotalByReportIdReportChapterId(reportIds string, chapterIds string) (total int64, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := `select count(*) from (( SELECT
-id AS report_id,
-0 AS report_chapter_id,
-classify_id_first,
-classify_id_second,
-classify_name_first,
-classify_name_second,
-0 as report_chapter_type_id,
-publish_time,
-title
-FROM
-	report
-WHERE
-	classify_name_first != "晨报" 
-	AND classify_name_first != "周报"
-	AND id in (` + reportIds + `)
-	)
-UNION
-	
-( SELECT
-report_id,
-report_chapter_id,
-classify_id_first,
-0 as classify_id_second,
-classify_name_first,
-null as classify_name_second,
-type_id as report_chapter_type_id,
-publish_time,
-title
-FROM
-	report_chapter
-WHERE
-report_chapter_id in (` + chapterIds + `)
-	)) r`
-	err = o.Raw(sql).QueryRow(&total)
-	return
-}
-
 // GetPageReportList 分页获取报告列表
 func GetPageReportList(condition string, pars []interface{}, startSize, pageSize int) (total int, items []*ReportList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -884,14 +648,14 @@ type YbPcSuncode struct {
 
 // GetYbPcSunCode 获取太阳码
 func GetYbPcSunCode(scene, page string) (item *YbPcSuncode, err error) {
-	o := orm.NewOrmUsingDB("default")
+	o := orm.NewOrmUsingDB("weekly")
 	sql := `SELECT * FROM yb_pc_suncode WHERE scene = ? AND code_page = ? `
 	err = o.Raw(sql, scene, page).QueryRow(&item)
 	return
 }
 
 func AddYbPcSunCode(item *YbPcSuncode) (err error) {
-	o := orm.NewOrmUsingDB("default")
+	o := orm.NewOrmUsingDB("weekly")
 	_, err = o.Insert(item)
 	return
 }
@@ -905,35 +669,11 @@ type YbSuncodePars struct {
 }
 
 func AddYbSuncodePars(item *YbSuncodePars) (err error) {
-	o := orm.NewOrmUsingDB("default")
+	o := orm.NewOrmUsingDB("weekly")
 	_, err = o.Insert(item)
 	return
 }
 
-// UpdateReportSecondClassifyNameByClassifyId 更新报告分类名称字段
-func UpdateReportSecondClassifyNameByClassifyId(classifyId int, classifyName string) (err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := " UPDATE report SET classify_name_second = ? WHERE classify_id_second = ? "
-	_, err = o.Raw(sql, classifyName, classifyId).Exec()
-	return
-}
-
-// UpdateReportFirstClassifyNameByClassifyId 更新报告分类一级名称字段
-func UpdateReportFirstClassifyNameByClassifyId(classifyId int, classifyName string) (err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := " UPDATE report SET classify_name_first = ? WHERE classify_id_first = ? "
-	_, err = o.Raw(sql, classifyName, classifyId).Exec()
-	return
-}
-
-// UpdateReportSecondClassifyFirstNameByClassifyId 更新报告二级分类的一级分类名称和id
-func UpdateReportSecondClassifyFirstNameByClassifyId(classifyId, newClassifyId int, classifyName string) (err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := " UPDATE report SET classify_name_first = ?, classify_id_first = ? WHERE classify_id_second = ? "
-	_, err = o.Raw(sql, classifyName, newClassifyId, classifyId).Exec()
-	return
-}
-
 // GetEmptyContentSubPPTReport 获取前两章为空的PPT报告
 func GetEmptyContentSubPPTReport() (list []*Report, err error) {
 	sql := `SELECT

+ 7 - 4
models/report_chapter.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"eta/eta_mobile/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -199,7 +200,10 @@ func GetReportChapterVideoList(reportId int) (list []*ReportChapterVideoList, er
 }
 
 // GetReportChapterVideoListByReportIds 根据报告ID集合获取报告章节音频列表
-func GetReportChapterVideoListByReportIds(reportIds string) (list []*ReportChapterVideoList, err error) {
+func GetReportChapterVideoListByReportIds(reportIds []string) (list []*ReportChapterVideoList, err error) {
+	if len(reportIds) == 0 {
+		return
+	}
 	o := orm.NewOrmUsingDB("rddp")
 	sql := ` SELECT
 				report_id,
@@ -210,11 +214,10 @@ func GetReportChapterVideoListByReportIds(reportIds string) (list []*ReportChapt
 			FROM
 				report_chapter
 			WHERE
-				report_id IN (` + reportIds + `) AND publish_state = 2 AND video_url != ""
+				report_id IN (` + utils.GetOrmInReplace(len(reportIds)) + `) AND publish_state = 2 AND video_url != ""
 			ORDER BY
 				report_chapter_id ASC `
-	_, err = o.Raw(sql).QueryRows(&list)
-
+	_, err = o.Raw(sql, reportIds).QueryRows(&list)
 	return
 }
 

+ 1 - 1
models/report_chapter_ticker.go

@@ -57,7 +57,7 @@ type DailyBaseColumn struct {
 
 // GetDailyBaseColumnList 获取基础列列表
 func GetDailyBaseColumnList(keyword string, typeId int) (list []*DailyBaseColumn, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM daily_base_column WHERE 1 = 1 `
 	pars := make([]interface{}, 0)
 	if keyword != "" {

+ 7 - 7
models/report_chapter_type.go

@@ -33,7 +33,7 @@ type ReportChapterType struct {
 
 // GetReportChapterTypeById 获取章节类型
 func GetReportChapterTypeById(reportChapterTypeId int) (item *ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE report_chapter_type_id = ? `
 	err = o.Raw(sql, reportChapterTypeId).QueryRow(&item)
 	return
@@ -41,7 +41,7 @@ func GetReportChapterTypeById(reportChapterTypeId int) (item *ReportChapterType,
 
 // GetReportChapterTypeList 获取章节类型列表
 func GetReportChapterTypeList() (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE enabled = 1 `
 	_, err = o.Raw(sql).QueryRows(&list)
 	return
@@ -49,7 +49,7 @@ func GetReportChapterTypeList() (list []*ReportChapterType, err error) {
 
 // GetReportChapterTypeListByResearchType 通过报告类型获取章节类型列表
 func GetReportChapterTypeListByResearchType(researchType string) (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE research_type = ? AND enabled = 1`
 	_, err = o.Raw(sql, researchType).QueryRows(&list)
 	return
@@ -57,7 +57,7 @@ func GetReportChapterTypeListByResearchType(researchType string) (list []*Report
 
 // GetAllReportChapterTypeListByResearchType 通过报告类型获取章节类型列表
 func GetAllReportChapterTypeListByResearchType(researchType string) (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE research_type = ?`
 	_, err = o.Raw(sql, researchType).QueryRows(&list)
 	return
@@ -65,7 +65,7 @@ func GetAllReportChapterTypeListByResearchType(researchType string) (list []*Rep
 
 // GetEnableReportChapterTypeList 获取未暂停的章节类型列表
 func GetEnableReportChapterTypeList(researchType string) (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT
 				*
 			FROM
@@ -95,7 +95,7 @@ type StopUpdateReportChapterTypeResp struct {
 
 // GetStopUpdateReportChapterTypeListByResearchType 获取暂停更新章节类型列表
 func GetStopUpdateReportChapterTypeListByResearchType() (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE is_set = 1 AND pause_end_time >= ? AND enabled = 1 `
 	_, err = o.Raw(sql, time.Now().Format(utils.FormatDate)).QueryRows(&list)
 	return
@@ -103,7 +103,7 @@ func GetStopUpdateReportChapterTypeListByResearchType() (list []*ReportChapterTy
 
 // GetDisableUpdateReportChapterTypeListByResearchType 获取停止更新的章节类型列表
 func GetDisableUpdateReportChapterTypeListByResearchType() (list []*ReportChapterType, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type WHERE enabled = 0`
 	_, err = o.Raw(sql).QueryRows(&list)
 	return

+ 1 - 1
models/report_chapter_type_permission.go

@@ -17,7 +17,7 @@ type ReportChapterTypePermission struct {
 
 // GetChapterTypePermissionByTypeIdAndResearchType 根据章节类型ID及研报类型获取章节类型权限列表
 func GetChapterTypePermissionByTypeIdAndResearchType(typeId int, researchType string) (list []*ReportChapterTypePermission, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := ` SELECT * FROM report_chapter_type_permission WHERE report_chapter_type_id = ? AND research_type = ? ORDER BY chart_permission_id ASC `
 	_, err = o.Raw(sql, typeId, researchType).QueryRows(&list)
 	return

+ 2 - 2
models/sandbox/sandbox.go

@@ -24,7 +24,7 @@ type Sandbox struct {
 
 // Update 沙盘字段变更
 func (sandbox *Sandbox) Update(cols []string) (err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("data")
 	_, err = o.Update(sandbox, cols...)
 	return
 }
@@ -52,7 +52,7 @@ type SandboxListItem struct {
 
 // GetList 获取沙盘列表页
 func GetList(condition string, pars []interface{}, startSize, pageSize int) (total int, list []*SandboxListItem, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("data")
 	sql := "select a.sandbox_id,a.name,a.chart_permission_id,a.chart_permission_name,a.curr_version,a.code,a.pic_url,a.op_user_id,a.op_user_name,a.modify_time,a.create_time,b.version_code from sandbox as a join sandbox_version b on a.sandbox_id=b.sandbox_id and a.curr_version=b.curr_version where 1=1 AND a.is_delete = 0 "
 	sql += condition
 	sql += ` order by a.modify_time desc,a.sandbox_id desc`

+ 2 - 2
models/search_key_word.go

@@ -18,7 +18,7 @@ type SearchKeyWord struct {
 
 // AddTrendTagKeyWord 新增趋势标签关键词
 func AddTrendTagKeyWord(trend string) (err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := " REPLACE INTO search_key_word (`key_word`,`from`) values (?,'trend') "
 	_, err = o.Raw(sql, trend).Exec()
 
@@ -27,7 +27,7 @@ func AddTrendTagKeyWord(trend string) (err error) {
 
 // GetKeyWordListByFrom 根据来源获取搜索关键词列表
 func GetKeyWordListByFrom(from string) (list []*SearchKeyWord, err error) {
-	o := orm.NewOrm()
+	o := orm.NewOrmUsingDB("weekly")
 	sql := " SELECT * FROM search_key_word WHERE `from` = ? ORDER BY created_time ASC "
 	_, err = o.Raw(sql, from).QueryRows(&list)
 

+ 8 - 8
models/semantic_analysis/sa_compare.go

@@ -50,7 +50,7 @@ func (m *SaCompare) TableName() string {
 }
 
 func (m *SaCompare) Create() (err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	id, err := o.Insert(m)
 	if err != nil {
 		return
@@ -60,27 +60,27 @@ func (m *SaCompare) Create() (err error) {
 }
 
 func (m *SaCompare) Update(cols []string) (err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	_, err = o.Update(m, cols...)
 	return
 }
 
 func (m *SaCompare) Del() (err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	sql := `DELETE FROM sa_compare WHERE sa_compare_id = ? LIMIT 1`
 	_, err = o.Raw(sql, m.SaCompareId).Exec()
 	return
 }
 
 func (m *SaCompare) GetItemById(id int) (err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	sql := `SELECT * FROM sa_compare WHERE sa_compare_id = ? LIMIT 1`
 	err = o.Raw(sql, id).QueryRow(&m)
 	return
 }
 
 func (m *SaCompare) GetItemByCondition(condition string, pars []interface{}) (err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	sql := `SELECT * FROM sa_compare WHERE 1=1 `
 	sql += condition
 	sql += ` LIMIT 1`
@@ -89,14 +89,14 @@ func (m *SaCompare) GetItemByCondition(condition string, pars []interface{}) (er
 }
 
 func (m *SaCompare) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
 	err = o.Raw(sql, pars).QueryRow(&count)
 	return
 }
 
 func (m *SaCompare) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*SaCompare, err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	fields := strings.Join(fieldArr, ",")
 	if len(fieldArr) == 0 {
 		fields = `*`
@@ -111,7 +111,7 @@ func (m *SaCompare) GetItemsByCondition(condition string, pars []interface{}, fi
 }
 
 func (m *SaCompare) GetPageItemsByCondition(startSize, pageSize int, condition string, pars []interface{}, fieldArr []string, orderRule string) (total int, items []*SaCompare, err error) {
-	o := orm.NewOrmUsingDB("eta")
+	o := orm.NewOrm()
 	fields := strings.Join(fieldArr, ",")
 	if len(fieldArr) == 0 {
 		fields = `*`

+ 52 - 1
models/system/sys_menu.go

@@ -1,6 +1,9 @@
 package system
 
-import "github.com/beego/beego/v2/client/orm"
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
 
 type MenuList struct {
 	MenuId    int          `description:"导航唯一标识"`
@@ -72,3 +75,51 @@ func GetMenuByParentIdRoleIds(roleIds string, parentId int) (items []*ChildMenu,
 	_, err = orm.NewOrm().Raw(sql, parentId).QueryRows(&items)
 	return
 }
+
+type SysMenu struct {
+	MenuId     int       `orm:"column(menu_id);pk"`
+	ParentId   int       `description:"父级菜单ID"`
+	Name       string    `description:"菜单名称或者按钮名称"`
+	Sort       string    `description:"排序"`
+	Path       string    `description:"路由地址"`
+	IconPath   string    `description:"菜单图标地址"`
+	Component  int       `description:"组件路径"`
+	Hidden     int       `description:"是否隐藏:1-隐藏 0-显示"`
+	IsLevel    int       `description:"是否为多级菜单:1,只有一级;2,有多级"`
+	LevelPath  string    `description:"兼容以前menu表的字段"`
+	MenuType   int       `description:"菜单类型: 0-菜单; 1-按钮; 2-字段(需要特殊处理)"`
+	ButtonCode string    `description:"按钮/菜单唯一标识"`
+	CreateTime time.Time `description:"创建时间"`
+	ModifyTime time.Time `description:"更新时间"`
+}
+
+// GetMenuButtonsByRoleId 获取角色按钮菜单
+func GetMenuButtonsByRoleId(roleId int) (items []*SysMenu, err error) {
+	sql := `SELECT
+				r.*
+			FROM
+				sys_menu AS r
+			JOIN sys_role_menu AS rm ON r.menu_id = rm.menu_id AND rm.type = 0
+			WHERE
+				rm.role_id = ? AND r.menu_type <> 0 AND r.hidden = 0
+			ORDER BY
+				r.sort ASC,
+				r.create_time DESC`
+	_, err = orm.NewOrm().Raw(sql, roleId).QueryRows(&items)
+	return
+}
+
+// SysMenuButtonResp 按钮菜单响应体
+type SysMenuButtonResp struct {
+	MenuId     int    `description:"菜单ID"`
+	ParentId   int    `description:"父级菜单ID"`
+	Name       string `description:"菜单名称或者按钮名称"`
+	MenuType   int    `description:"菜单类型: 0-菜单; 1-按钮"`
+	ButtonCode string `description:"按钮唯一标识"`
+}
+
+// BusinessConf 商户配置表
+type BusinessConf struct {
+	ConfKey string `description:"配置Key"`
+	ConfVal string `description:"配置值"`
+}

+ 1 - 0
models/system/sys_role_admin.go

@@ -22,3 +22,4 @@ func GetRoleIdsByAdminId(adminId int) (items []*SysRoleAdmin, err error) {
 	_, err = orm.NewOrm().Raw(sql, adminId).QueryRows(&items)
 	return
 }
+

+ 6 - 6
models/system/sys_session.go

@@ -16,9 +16,9 @@ type SysSession struct {
 	LastUpdatedTime time.Time
 }
 
-//新增用户登录session信息
+// 新增用户登录session信息
 func AddSysSession(item *SysSession) (err error) {
-	o := orm.NewOrmUsingDB("rddp")
+	o := orm.NewOrm()
 	lastId, err := o.Insert(item)
 	if err != nil {
 		return
@@ -29,22 +29,22 @@ func AddSysSession(item *SysSession) (err error) {
 
 func GetSysSessionBySysUserId(sysUserId int) (item *SysSession, err error) {
 	sql := `SELECT * FROM sys_session WHERE sys_user_id=? AND expired_time> NOW() ORDER BY expired_time DESC LIMIT 1 `
-	o := orm.NewOrmUsingDB("rddp")
+	o := orm.NewOrm()
 	err = o.Raw(sql, sysUserId).QueryRow(&item)
 	return
 }
 
 func GetSysSessionByToken(token string) (item *SysSession, err error) {
 	sql := `SELECT * FROM sys_session WHERE access_token=? AND expired_time> NOW() ORDER BY expired_time DESC LIMIT 1 `
-	o := orm.NewOrmUsingDB("rddp")
+	o := orm.NewOrm()
 	err = o.Raw(sql, token).QueryRow(&item)
 	return
 }
 
-//过期掉用户token
+// 过期掉用户token
 func ExpiredSysSessionByAdminId(adminId int) (err error) {
 	sql := `update sys_session set expired_time = NOW()  WHERE sys_user_id=? `
-	o := orm.NewOrmUsingDB("rddp")
+	o := orm.NewOrm()
 	_, err = o.Raw(sql, adminId).Exec()
 	return
 }

+ 8 - 4
models/user_view_history.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"eta/eta_mobile/utils"
 	"github.com/beego/beego/v2/client/orm"
 )
 
@@ -11,8 +12,11 @@ type ResearchReportViewPUV struct {
 }
 
 // GetPUVByResearchReportIds 通过报告IDs获取老报告PV、UV
-func GetPUVByResearchReportIds(reportIds string) (list []*ResearchReportViewPUV, err error) {
-	o := orm.NewOrm()
+func GetPUVByResearchReportIds(reportIds []string) (list []*ResearchReportViewPUV, err error) {
+	if len(reportIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("weekly")
 	sql := `SELECT
 				research_report_id,
 				COUNT(1) AS pv,
@@ -20,9 +24,9 @@ func GetPUVByResearchReportIds(reportIds string) (list []*ResearchReportViewPUV,
 			FROM
 				user_view_history
 			WHERE
-				research_report_id IN (` + reportIds + `)
+				research_report_id IN (` + utils.GetOrmInReplace(len(reportIds)) + `)
 			GROUP BY
 				research_report_id`
-	_, err = o.Raw(sql).QueryRows(&list)
+	_, err = o.Raw(sql, reportIds).QueryRows(&list)
 	return
 }

+ 2 - 2
models/wechat_send_msg.go

@@ -11,7 +11,7 @@ func GetOpenIdArr() (items []string, err error) {
 		INNER JOIN user_record  AS ur ON wu.user_id=ur.user_id
           WHERE ur.open_id != "" AND ur.subscribe=1 AND ur.create_platform=1 AND  d.status IN('正式','试用','永续')
          ORDER BY FIELD(c.company_id, 16) desc, ur.user_record_id asc`
-	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	_, err = orm.NewOrmUsingDB("weekly").Raw(sql).QueryRows(&items)
 	return
 }
 
@@ -27,6 +27,6 @@ func GetOpenIdArrByClassifyNameSecond(classifyNameSecond string) (items []string
 			AND g.from='rddp'
 			AND g.key_word=?
 			ORDER BY FIELD(c.company_id, 16) DESC, ur.user_record_id ASC  `
-	_, err = orm.NewOrm().Raw(sql, classifyNameSecond).QueryRows(&items)
+	_, err = orm.NewOrmUsingDB("weekly").Raw(sql, classifyNameSecond).QueryRows(&items)
 	return
 }

+ 108 - 0
routers/commentsRouter.go

@@ -88,6 +88,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoSave",
+            Router: `/chart_info/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoSearchByEs",
@@ -268,6 +277,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoBase64Upload",
+            Router: `/chart_info/base64Upload`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "BatchChartInfoRefresh",
@@ -322,6 +340,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoImageSet",
+            Router: `/chart_info/image/set`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoMove",
@@ -340,6 +367,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoSave",
+            Router: `/chart_info/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoSearchByEs",
@@ -502,6 +538,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"],
+        beego.ControllerComments{
+            Method: "SimpleList",
+            Router: `/classify/simple`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"],
+        beego.ControllerComments{
+            Method: "ClassifyTree",
+            Router: `/classify/tree`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:EdbClassifyController"],
         beego.ControllerComments{
             Method: "EdbClassifyMove",
@@ -925,6 +979,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/english_report:EnglishCompanyController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/english_report:EnglishCompanyController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/company/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/english_report:EnglishReportController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/english_report:EnglishReportController"],
         beego.ControllerComments{
             Method: "Add",
@@ -1114,6 +1177,33 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfController"],
+        beego.ControllerComments{
+            Method: "Fetch",
+            Router: `/fetch`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfController"],
+        beego.ControllerComments{
+            Method: "Save",
+            Router: `/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfOpenController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:BusinessConfOpenController"],
+        beego.ControllerComments{
+            Method: "CodeEncrypt",
+            Router: `/code_encrypt`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers:ClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:ClassifyController"],
         beego.ControllerComments{
             Method: "ListClassify",
@@ -2086,6 +2176,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysRoleController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysRoleController"],
+        beego.ControllerComments{
+            Method: "SystemConfig",
+            Router: `/config`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysRoleController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysRoleController"],
+        beego.ControllerComments{
+            Method: "ButtonList",
+            Router: `/role/menu/buttons`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysUserAuthController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:SysUserAuthController"],
         beego.ControllerComments{
             Method: "CheckPwd",

+ 16 - 0
routers/router.go

@@ -143,6 +143,9 @@ func init() {
 			web.NSInclude(
 				&controllers.SysAdminController{},
 			),
+			web.NSInclude(
+				&controllers.SysRoleController{},
+			),
 		),
 		web.NSNamespace("/en_permission",
 			web.NSInclude(
@@ -160,6 +163,19 @@ func init() {
 				&semantic_analysis.SaCompareController{},
 			),
 		),
+		web.NSNamespace("/business_conf",
+			web.NSInclude(
+				&controllers.BusinessConfController{},
+				&controllers.BusinessConfOpenController{},
+			),
+		),
+		web.NSNamespace("/english_report",
+			web.NSInclude(
+				&english_report.EnglishReportController{},
+				&english_report.EnglishReportEmailController{},
+				&english_report.EnglishCompanyController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 52 - 0
services/data/base_bridge.go

@@ -0,0 +1,52 @@
+package data
+
+import "time"
+
+// EdbBridge 桥接数据源接口(算了别用了难用的一批, 不如直接判断商户号来的方便快捷...)
+type EdbBridge interface {
+	GetIndex(GetIndexFromBridgeReq) (BridgeIndexItem, error)
+	//GetIndexAndData(GetIndexAndDataFromBridgeReq) (BridgeIndexItem, error)
+}
+
+// GetIndexFromBridgeReq 获取指标信息请求体
+type GetIndexFromBridgeReq struct {
+	IndexCode         string `description:"指标编码"`
+	Source            int    `description:"指标来源ID"`
+	SourceExtend      string `description:"指标来源(用作查询条件)"`
+	IndexCodeRequired int    `description:"指标编码是否必填: 0-否; 1-是"`
+}
+
+// GetIndexAndDataFromBridgeReq 获取指标数据请求体
+type GetIndexAndDataFromBridgeReq struct {
+	IndexCode    string `description:"指标编码"`
+	Source       int    `description:"指标来源ID"`
+	SourceExtend string `description:"指标来源(用作查询条件)"`
+	StartDate    string `description:"数据开始日期"`
+	EndDate      string `description:"数据结束日期"`
+}
+
+// BridgeIndexItem 桥接服务指标信息
+type BridgeIndexItem struct {
+	Id        int                   `description:"自增ID"`
+	IndexCode string                `description:"指标编码"`
+	IndexName string                `description:"指标名称"`
+	Unit      string                `description:"单位"`
+	Frequency string                `description:"频度"`
+	Data      []BridgeIndexDataItem `description:"数据值"`
+}
+
+// BridgeIndexDataItem 桥接服务指标数据信息
+type BridgeIndexDataItem struct {
+	Val        float64   `description:"数据值"`
+	DataTime   time.Time `description:"数据日期"`
+	UpdateTime time.Time `description:"更新时间"`
+}
+
+// InitBridgeOB 初始化桥接服务
+func InitBridgeOB(bridgeKey string) EdbBridge {
+	switch bridgeKey {
+	case "bridge_jiayue":
+		return new(EdbBridgeJiaYue) // 嘉悦物产
+	}
+	return nil
+}

+ 11 - 0
services/data/base_edb_lib.go

@@ -15,6 +15,7 @@ import (
 func AddEdbData(source int, edbCode string) (resp *models.BaseResponse, err error) {
 	param := make(map[string]interface{})
 	param["EdbCode"] = edbCode
+	param["Source"] = source
 	urlStr := ``
 	switch source {
 	case utils.DATA_SOURCE_THS:
@@ -66,6 +67,10 @@ func AddEdbData(source int, edbCode string) (resp *models.BaseResponse, err erro
 	case utils.DATA_SOURCE_FUBAO:
 		urlStr = "fubao/add"
 	default:
+		edbSource := data_manage.EdbSourceIdMap[source]
+		if edbSource != nil {
+			urlStr = edbSource.EdbAddMethod
+		}
 	}
 	if urlStr == "" {
 		err = fmt.Errorf("未实现该指标的刷新接口,请联系管理员")
@@ -92,6 +97,7 @@ func RefreshEdbData(edbInfoId, source int, edbCode, startDate string) (resp *mod
 	param["EdbCode"] = edbCode
 	param["EdbInfoId"] = edbInfoId
 	param["StartDate"] = startDate
+	param["Source"] = source
 	urlStr := ``
 	switch source {
 	case utils.DATA_SOURCE_THS:
@@ -146,6 +152,11 @@ func RefreshEdbData(edbInfoId, source int, edbCode, startDate string) (resp *mod
 		urlStr = "national_statistics/refresh"
 	case utils.DATA_SOURCE_FUBAO:
 		urlStr = "fubao/refresh"
+	default:
+		edbSource := data_manage.EdbSourceIdMap[source]
+		if edbSource != nil {
+			urlStr = edbSource.EdbRefreshMethod
+		}
 	}
 	if urlStr == "" {
 		err = fmt.Errorf(fmt.Sprint("source:", source, ";未实现该指标的刷新接口,请联系管理员"))

+ 570 - 78
services/data/edb_classify.go

@@ -132,8 +132,33 @@ func AddEdbClassify(classifyName string, parentId, level int, classifyType uint8
 		errMsg = `分类名称已存在,请重新输入`
 		return
 	}
+	if level > 6 {
+		errMsg = `最高只支持添加6级分类`
+		return
+	}
 	//获取该层级下最大的排序数
-	maxSort, err := data_manage.GetEdbClassifyMaxSort(parentId, classifyType)
+	maxSort, err := GetEdbClassifyMaxSort(parentId, classifyType)
+	if err != nil {
+		errMsg = "获取失败"
+		err = errors.New("查询排序信息失败,Err:" + err.Error())
+		return
+	}
+	//查询顶级rootId
+	rootId := 0
+	if parentId > 0 {
+		parentClassify, tErr := data_manage.GetEdbClassifyById(parentId)
+		if tErr != nil {
+			if tErr.Error() == utils.ErrNoRow() {
+				errMsg = "父级分类不存在"
+				err = errors.New(errMsg)
+				return
+			}
+			errMsg = "获取失败"
+			err = errors.New("获取分类信息失败,Err:" + tErr.Error())
+			return
+		}
+		rootId = parentClassify.RootId
+	}
 
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	classifyInfo = &data_manage.EdbClassify{
@@ -141,6 +166,7 @@ func AddEdbClassify(classifyName string, parentId, level int, classifyType uint8
 		ClassifyType:    classifyType,
 		ClassifyName:    classifyName,
 		ParentId:        parentId,
+		RootId:          rootId,
 		HasData:         0,
 		CreateTime:      time.Now(),
 		ModifyTime:      time.Now(),
@@ -148,11 +174,21 @@ func AddEdbClassify(classifyName string, parentId, level int, classifyType uint8
 		SysUserRealName: sysUserName,
 		Level:           level + 1,
 		UniqueCode:      utils.MD5(utils.DATA_PREFIX + "_" + timestamp),
-		Sort:            maxSort,
+		Sort:            maxSort + 1,
 	}
-	_, err = data_manage.AddEdbClassify(classifyInfo)
+	newId, err := data_manage.AddEdbClassify(classifyInfo)
 	if err != nil {
 		errMsg = "保存分类失败"
+		return
+	}
+	if parentId == 0 { //一级目录的rootId等于自己本身
+		classifyInfo.ClassifyId = int(newId)
+		classifyInfo.RootId = int(newId)
+		err = classifyInfo.Update([]string{"RootId"})
+		if err != nil {
+			errMsg = "更新分类失败"
+			return
+		}
 	}
 	return
 }
@@ -475,113 +511,432 @@ func Delete(classifyId, edbInfoId int, sysUser *system.Admin, requestBody, reque
 }
 
 // MoveEdbClassify 移动指标分类
-func MoveEdbClassify(classifyId, parentClassifyId, prevClassifyId, nextClassifyId int, sysUser *system.Admin) (err error, errMsg string) {
-	//判断分类是否存在
-	edbClassifyInfo, err := data_manage.GetEdbClassifyById(classifyId)
-	if err != nil {
-		errMsg = "移动失败"
-		err = errors.New("获取分类信息失败,Err:" + err.Error())
-		return
+func MoveEdbClassify(req data_manage.MoveEdbClassifyReq, sysUser *system.Admin, classifyType uint8) (err error, errMsg string) {
+	// req.ClassifyId, req.ParentClassifyId, req.PrevClassifyId, req.NextClassifyId
+	classifyId := req.ClassifyId
+	parentClassifyId := req.ParentClassifyId
+	prevClassifyId := req.PrevClassifyId
+	nextClassifyId := req.NextClassifyId
+
+	edbInfoId := req.EdbInfoId
+	prevEdbInfoId := req.PrevEdbInfoId
+	nextEdbInfoId := req.NextEdbInfoId
+
+	//首先确定移动的对象是分类还是指标
+	//判断上一个节点是分类还是指标
+	//判断下一个节点是分类还是指标
+	//同时更新分类目录下的分类sort和指标sort
+	//更新当前移动的分类或者指标sort
+
+	var parentEdbClassifyInfo *data_manage.EdbClassify
+	if parentClassifyId > 0 {
+		parentEdbClassifyInfo, err = data_manage.GetEdbClassifyById(parentClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上级分类信息失败,Err:" + err.Error())
+			return
+		}
 	}
 
-	// 权限校验
-	{
-		if edbClassifyInfo.ClassifyType == 0 { // 普通指标
-			button := GetEdbClassifyOpButton(sysUser, edbClassifyInfo.SysUserId)
-			if !button.MoveButton {
-				errMsg = "无操作权限"
-				err = errors.New(errMsg)
+	//如果有传入 上一个兄弟节点分类id
+	var (
+		edbClassifyInfo *data_manage.EdbClassify
+		prevClassify    *data_manage.EdbClassify
+		nextClassify    *data_manage.EdbClassify
+
+		edbInfo     *data_manage.EdbInfo
+		prevEdbInfo *data_manage.EdbInfo
+		nextEdbInfo *data_manage.EdbInfo
+		prevSort    int
+		nextSort    int
+	)
+
+	// 移动对象为分类, 判断权限
+	if edbInfoId == 0 {
+		edbClassifyInfo, err = data_manage.GetEdbClassifyById(classifyId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				errMsg = "当前分类不存在"
+				err = errors.New("获取分类信息失败,Err:" + err.Error())
 				return
 			}
-		} else if edbClassifyInfo.ClassifyType == 1 { // 预测指标
-			button := GetPredictEdbClassifyOpButton(sysUser, edbClassifyInfo.SysUserId)
-			if !button.MoveButton {
-				errMsg = "无操作权限"
-				err = errors.New(errMsg)
-				return
+			errMsg = "移动失败"
+			err = errors.New("获取分类信息失败,Err:" + err.Error())
+			return
+		}
+		if parentClassifyId > 0 && parentEdbClassifyInfo.Level == 6 {
+			errMsg = "最高只支持添加6级分类"
+			err = errors.New(errMsg)
+			return
+		}
+		// 权限校验
+		{
+			if edbClassifyInfo.ClassifyType == 0 { // 普通指标
+				button := GetEdbClassifyOpButton(sysUser, edbClassifyInfo.SysUserId)
+				if !button.MoveButton {
+					errMsg = "无操作权限"
+					err = errors.New(errMsg)
+					return
+				}
+			} else if edbClassifyInfo.ClassifyType == 1 { // 预测指标
+				button := GetPredictEdbClassifyOpButton(sysUser, edbClassifyInfo.SysUserId)
+				if !button.MoveButton {
+					errMsg = "无操作权限"
+					err = errors.New(errMsg)
+					return
+				}
 			}
 		}
 
+	} else {
+		edbInfo, err = data_manage.GetEdbInfoById(req.EdbInfoId)
+		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
+		}
+		// 移动权限校验
+		button := GetEdbOpButton(sysUser, edbInfo.SysUserId, edbInfo.EdbType, edbInfo.EdbInfoType)
+		if !button.MoveButton {
+			errMsg = "无操作权限"
+			err = errors.New(errMsg)
+			return
+		}
 	}
 
-	updateCol := make([]string, 0)
-
-	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
-	if edbClassifyInfo.ParentId != parentClassifyId && parentClassifyId != 0 {
-		parentEdbClassifyInfo, tmpErr := data_manage.GetEdbClassifyById(parentClassifyId)
-		if tmpErr != nil {
+	if prevClassifyId > 0 {
+		prevClassify, err = data_manage.GetEdbClassifyById(prevClassifyId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevClassify.Sort
+	} else if prevEdbInfoId > 0 {
+		prevEdbInfo, err = data_manage.GetEdbInfoById(prevEdbInfoId)
+		if err != nil {
 			errMsg = "移动失败"
-			err = errors.New("获取上级分类信息失败,Err:" + tmpErr.Error())
+			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
 			return
 		}
-		edbClassifyInfo.ParentId = parentEdbClassifyInfo.ClassifyId
-		edbClassifyInfo.Level = parentEdbClassifyInfo.Level + 1
-		edbClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+		prevSort = prevEdbInfo.Sort
 	}
 
-	//如果有传入 上一个兄弟节点分类id
-	if prevClassifyId > 0 {
-		prevClassify, tmpErr := data_manage.GetEdbClassifyById(prevClassifyId)
-		if tmpErr != nil {
+	if nextClassifyId > 0 {
+		//下一个兄弟节点
+		nextClassify, err = data_manage.GetEdbClassifyById(nextClassifyId)
+		if err != nil {
 			errMsg = "移动失败"
-			err = errors.New("获取上一个兄弟节点分类信息失败,Err:" + tmpErr.Error())
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
 			return
 		}
+		nextSort = nextClassify.Sort
+	} else if nextEdbInfoId > 0 {
+		//下一个兄弟节点
+		nextEdbInfo, err = data_manage.GetEdbInfoById(nextEdbInfoId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextEdbInfo.Sort
+	}
 
-		//如果是移动在两个兄弟节点之间
-		if nextClassifyId > 0 {
-			//下一个兄弟节点
-			nextClassify, tmpErr := data_manage.GetEdbClassifyById(nextClassifyId)
-			if tmpErr != nil {
+	err, errMsg = moveEdbClassify(parentEdbClassifyInfo, edbClassifyInfo, prevClassify, nextClassify, edbInfo, prevEdbInfo, nextEdbInfo, parentClassifyId, prevSort, nextSort, classifyType)
+	return
+}
+
+// moveEdbClassify 移动指标分类
+func moveEdbClassify(parentEdbClassifyInfo, edbClassifyInfo, prevClassify, nextClassify *data_manage.EdbClassify, edbInfo, prevEdbInfo, nextEdbInfo *data_manage.EdbInfo, parentClassifyId int, prevSort, nextSort int, classifyType uint8) (err error, errMsg string) {
+	updateCol := make([]string, 0)
+
+	// 移动对象为分类, 判断分类是否存在
+	if edbClassifyInfo != nil {
+		oldParentId := edbClassifyInfo.ParentId
+		oldLevel := edbClassifyInfo.Level
+		var classifyIds []int
+		if oldParentId != parentClassifyId {
+			//更新子分类对应的level
+			childList, e, m := GetChildClassifyByClassifyId(edbClassifyInfo.ClassifyId)
+			if e != nil {
 				errMsg = "移动失败"
-				err = errors.New("获取下一个兄弟节点分类信息失败,Err:" + tmpErr.Error())
+				err = errors.New("查询子分类失败,Err:" + e.Error() + m)
 				return
 			}
-			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
-			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == edbClassifyInfo.Sort {
-				//变更兄弟节点的排序
-				updateSortStr := `sort + 2`
-				_ = data_manage.UpdateEdbClassifySortByParentId(prevClassify.ParentId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr, edbClassifyInfo.ClassifyType)
-			} else {
-				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
-				if nextClassify.Sort-prevClassify.Sort == 1 {
+
+			if len(childList) > 0 {
+				for _, v := range childList {
+					if v.ClassifyId == edbClassifyInfo.ClassifyId {
+						continue
+					}
+					classifyIds = append(classifyIds, v.ClassifyId)
+				}
+			}
+		}
+		//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+		if edbClassifyInfo.ParentId != parentClassifyId && parentClassifyId != 0 {
+			edbClassifyInfo.ParentId = parentEdbClassifyInfo.ClassifyId
+			edbClassifyInfo.RootId = parentEdbClassifyInfo.RootId
+			edbClassifyInfo.Level = parentEdbClassifyInfo.Level + 1
+			edbClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "RootId", "Level", "ModifyTime")
+		} else if edbClassifyInfo.ParentId != parentClassifyId && parentClassifyId == 0 {
+			edbClassifyInfo.ParentId = 0
+			edbClassifyInfo.RootId = edbClassifyInfo.ClassifyId
+			edbClassifyInfo.Level = 1
+			edbClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ParentId", "RootId", "Level", "ModifyTime")
+		}
+
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == edbClassifyInfo.Sort {
 					//变更兄弟节点的排序
-					updateSortStr := `sort + 1`
-					_ = data_manage.UpdateEdbClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr, edbClassifyInfo.ClassifyType)
+					updateSortStr := `sort + 2`
+
+					//变更分类
+					if prevClassify != nil {
+						_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr, classifyType)
+					} else {
+						_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, classifyType)
+					}
+
+					//变更指标
+					if prevEdbInfo != nil {
+						//变更兄弟节点的排序
+						_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, prevEdbInfo.EdbInfoId, updateSortStr)
+					} else {
+						_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+
+						//变更分类
+						if prevClassify != nil {
+							_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevSort, updateSortStr, classifyType)
+						} else {
+							_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, classifyType)
+						}
+
+						//变更指标
+						if prevEdbInfo != nil {
+							//变更兄弟节点的排序
+							_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, prevEdbInfo.EdbInfoId, updateSortStr)
+						} else {
+							_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr)
+						}
+
+					}
+				}
+			}
+
+			edbClassifyInfo.Sort = prevSort + 1
+			edbClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevEdbInfo == nil && nextEdbInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetEdbClassifyMaxSort(parentClassifyId, classifyType)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			edbClassifyInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			edbClassifyInfo.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 `
+				_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, firstClassify.ClassifyId-1, 0, updateSortStr, classifyType)
+				//该分类下的所有指标也需要+1
+				_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr)
+			} else {
+				//如果该分类下存在指标,且第一个指标的排序等于0,那么需要调整排序
+				firstEdb, tErr := data_manage.GetFirstEdbInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstEdb != nil && firstEdb.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, 0, firstEdb.EdbInfoId-1, updateSortStr)
+					_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, classifyType)
 				}
 			}
+
+			edbClassifyInfo.Sort = 0 //那就是排在第一位
+			edbClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
 		}
 
-		edbClassifyInfo.Sort = prevClassify.Sort + 1
-		edbClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
+		//更新
+		if len(updateCol) > 0 {
+			err = edbClassifyInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
+			//更新对应分类的root_id和层级
+			if oldParentId != parentClassifyId {
+				if len(classifyIds) > 0 {
+					levelStep := edbClassifyInfo.Level - oldLevel
+					err = data_manage.UpdateEdbClassifyChildByParentClassifyId(classifyIds, edbClassifyInfo.RootId, levelStep)
+					if err != nil {
+						errMsg = "移动失败"
+						err = errors.New("更新子分类失败,Err:" + err.Error())
+						return
+					}
+				}
+			}
+		}
 	} else {
-		firstClassify, tmpErr := data_manage.GetFirstEdbClassifyByParentId(edbClassifyInfo.ParentId)
-		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
-			errMsg = "移动失败"
-			err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tmpErr.Error())
+		if edbInfo == nil {
+			errMsg = "当前指标不存在"
+			err = errors.New(errMsg)
 			return
 		}
-
-		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
-		if firstClassify != nil && firstClassify.Sort == 0 {
-			updateSortStr := ` sort + 1 `
-			_ = data_manage.UpdateEdbClassifySortByParentId(firstClassify.ParentId, firstClassify.ClassifyId-1, 0, updateSortStr, edbClassifyInfo.ClassifyType)
+		//如果改变了分类,那么移动该指标数据
+		if edbInfo.ClassifyId != parentClassifyId {
+			edbInfo.ClassifyId = parentClassifyId
+			edbInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "ClassifyId", "ModifyTime")
 		}
+		if prevSort > 0 {
+			//如果是移动在两个兄弟节点之间
+			if nextSort > 0 {
+				//下一个兄弟节点
+				//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+				if prevSort == nextSort || prevSort == edbInfo.Sort {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 2`
 
-		edbClassifyInfo.Sort = 0 //那就是排在第一位
-		edbClassifyInfo.ModifyTime = time.Now()
-		updateCol = append(updateCol, "Sort", "ModifyTime")
-	}
+					//变更分类
+					if prevClassify != nil {
+						_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr, classifyType)
+					} else {
+						_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, classifyType)
+					}
 
-	//更新
-	if len(updateCol) > 0 {
-		err = edbClassifyInfo.Update(updateCol)
-		if err != nil {
-			errMsg = "移动失败"
-			err = errors.New("修改失败,Err:" + err.Error())
-			return
+					//变更指标
+					if prevEdbInfo != nil {
+						//变更兄弟节点的排序
+						_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, prevEdbInfo.EdbInfoId, updateSortStr)
+					} else {
+						_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr)
+					}
+				} else {
+					//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+					if nextSort-prevSort == 1 {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 1`
+						//变更分类
+						if prevClassify != nil {
+							_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, prevClassify.ClassifyId, prevSort, updateSortStr, classifyType)
+						} else {
+							_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, prevSort, updateSortStr, classifyType)
+						}
+
+						//变更指标
+						if prevEdbInfo != nil {
+							//变更兄弟节点的排序
+							_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, prevEdbInfo.EdbInfoId, updateSortStr)
+						} else {
+							_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, prevSort, 0, updateSortStr)
+						}
+					}
+				}
+			}
+
+			edbInfo.Sort = prevSort + 1
+			edbInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		} else if prevClassify == nil && nextClassify == nil && prevEdbInfo == nil && nextEdbInfo == nil && parentClassifyId > 0 {
+			//处理只拖动到目录里,默认放到目录底部的情况
+			var maxSort int
+			maxSort, err = GetEdbClassifyMaxSort(parentClassifyId, classifyType)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("查询组内排序信息失败,Err:" + err.Error())
+				return
+			}
+			edbInfo.Sort = maxSort + 1 //那就是排在组内最后一位
+			edbInfo.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 `
+				_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, firstClassify.ClassifyId-1, 0, updateSortStr, classifyType)
+				//该分类下的所有指标也需要+1
+				_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, 0, 0, updateSortStr)
+			} else {
+				//如果该分类下存在指标,且第一个指标的排序等于0,那么需要调整排序
+				firstEdb, tErr := data_manage.GetFirstEdbInfoByClassifyId(parentClassifyId)
+				if tErr != nil && tErr.Error() != utils.ErrNoRow() {
+					errMsg = "移动失败"
+					err = errors.New("获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + tErr.Error())
+					return
+				}
+
+				//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+				if firstEdb != nil && firstEdb.Sort == 0 {
+					updateSortStr := ` sort + 1 `
+					_ = data_manage.UpdateEdbInfoSortByClassifyId(parentClassifyId, 0, firstEdb.EdbInfoId-1, updateSortStr)
+					_ = data_manage.UpdateEdbClassifySortByParentId(parentClassifyId, 0, 0, updateSortStr, classifyType)
+				}
+			}
+
+			edbInfo.Sort = 0 //那就是排在第一位
+			edbInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+		}
+
+		//更新
+		if len(updateCol) > 0 {
+			err = edbInfo.Update(updateCol)
+			if err != nil {
+				errMsg = "移动失败"
+				err = errors.New("修改失败,Err:" + err.Error())
+				return
+			}
 		}
 	}
 	return
@@ -648,3 +1003,140 @@ func GetPredictEdbClassifyOpButton(sysUser *system.Admin, belongUserId int) (but
 
 	return
 }
+
+// GetClassifyTreeRecursive 递归获取分类树形结构
+func GetClassifyTreeRecursive(list []*data_manage.EdbClassifyItems, parentId int) []*data_manage.EdbClassifyItems {
+	res := make([]*data_manage.EdbClassifyItems, 0)
+	for _, v := range list {
+		if v.ParentId == parentId {
+			v.Children = GetClassifyTreeRecursive(list, v.ClassifyId)
+			res = append(res, v)
+		}
+	}
+	return res
+}
+
+func GetFullClassifyByClassifyId(targetClassifyId int) (targetList []*data_manage.EdbClassifyIdItems, err error, errMsg string) {
+	//判断是否是挂在顶级目录下
+	targetClassify, err := data_manage.GetEdbClassifyById(targetClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前分类不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取失败"
+		err = errors.New("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+	if targetClassify.ParentId == 0 {
+		targetItem := new(data_manage.EdbClassifyIdItems)
+		targetItem.ClassifyId = targetClassify.ClassifyId
+		targetItem.ParentId = targetClassify.ParentId
+		targetItem.RootId = targetClassify.RootId
+		targetItem.UniqueCode = targetClassify.UniqueCode
+		targetItem.Level = targetClassify.Level
+		targetItem.ClassifyName = targetClassify.ClassifyName
+		targetList = append(targetList, targetItem)
+		return
+	}
+	tmpList, err := data_manage.GetEdbClassifyByRootIdLevel(targetClassify.RootId, targetClassify.ClassifyType, "")
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		errMsg = "获取失败"
+		err = errors.New("获取数据失败,Err:" + err.Error())
+		return
+	}
+	idMap := make(map[int]struct{})
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.ClassifyId == targetClassify.ClassifyId {
+				idMap[v.ClassifyId] = struct{}{}
+				idMap[v.ParentId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ClassifyId]; ok {
+				idMap[v.ParentId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ClassifyId]; ok {
+				targetItem := new(data_manage.EdbClassifyIdItems)
+				targetItem.ClassifyId = v.ClassifyId
+				targetItem.ParentId = v.ParentId
+				targetItem.RootId = v.RootId
+				targetItem.UniqueCode = v.UniqueCode
+				targetItem.Level = v.Level
+				targetItem.ClassifyName = v.ClassifyName
+				targetList = append(targetList, targetItem)
+			}
+		}
+	}
+	return
+}
+
+func GetChildClassifyByClassifyId(targetClassifyId int) (targetList []*data_manage.EdbClassifyIdItems, err error, errMsg string) {
+	//判断是否是挂在顶级目录下
+	targetClassify, err := data_manage.GetEdbClassifyById(targetClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前分类不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取失败"
+		err = errors.New("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+	orderStr := ` order by level asc, sort asc, classify_id asc`
+	tmpList, err := data_manage.GetEdbClassifyByRootIdLevel(targetClassify.RootId, targetClassify.ClassifyType, orderStr)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		errMsg = "获取失败"
+		err = errors.New("获取数据失败,Err:" + err.Error())
+		return
+	}
+	idMap := make(map[int]struct{})
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.ClassifyId == targetClassify.ClassifyId {
+				idMap[v.ClassifyId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ParentId]; ok {
+				idMap[v.ClassifyId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ClassifyId]; ok {
+				targetItem := new(data_manage.EdbClassifyIdItems)
+				targetItem.ClassifyId = v.ClassifyId
+				targetItem.ParentId = v.ParentId
+				targetItem.RootId = v.RootId
+				targetItem.UniqueCode = v.UniqueCode
+				targetItem.Level = v.Level
+				targetItem.ClassifyName = v.ClassifyName
+				targetList = append(targetList, targetItem)
+			}
+		}
+	}
+
+	return
+}
+
+func GetEdbClassifyMaxSort(parentId int, classifyType uint8) (maxSort int, err error) {
+	//获取该层级下最大的排序数
+	classifyMaxSort, err := data_manage.GetEdbClassifyMaxSort(parentId, classifyType)
+	if err != nil {
+		return
+	}
+	maxSort = classifyMaxSort
+	edbMaxSort, err := data_manage.GetEdbInfoMaxSortByClassifyId(parentId)
+	if err != nil {
+		return
+	}
+	if maxSort < edbMaxSort {
+		maxSort = edbMaxSort
+	}
+	return
+}

+ 255 - 284
services/data/edb_info.go

@@ -256,290 +256,13 @@ func GetLeadUnitEn(unit string) (unitEn string) {
 	return
 }
 
-// EdbInfoRefreshAllFromBaseV3 全部刷新指标(切换到edb_lib服务)
+// EdbInfoRefreshAllFromBaseV3Bak 全部刷新指标(切换到edb_lib服务)
 // @author Roc
 // @datetime 2022-09-16 11:04:44
 // @description 将原有的单个指标刷新,调整为批量多个指标刷新
-//func EdbInfoRefreshAllFromBaseV3(edbInfoIdList []int, refreshAll bool) (err error) {
-//	var errmsg string
-//	defer func() {
-//		if err != nil {
-//			fmt.Println("EdbInfoRefreshAllFromBaseV2 Err:" + err.Error() + ";errmsg:" + errmsg)
-//			go alarm_msg.SendAlarmMsg("EdbInfoRefreshFromBaseV2,Err"+err.Error()+";errMsg:"+errmsg, 3)
-//			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "EdbInfoRefreshFromBase:"+errmsg, utils.EmailSendToUsers)
-//		}
-//	}()
-//
-//	// 获取关联的基础指标
-//	newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr, err, errmsg := getRefreshEdbInfoListByIds(edbInfoIdList)
-//	if err != nil {
-//		return
-//	}
-//	var startDate string
-//	for _, bv := range newBaseEdbInfoArr {
-//		//source := bv.Source
-//		//edbInfoId := bv.EdbInfoId
-//		//edbCode := bv.EdbCode
-//		if bv.StartDate == "0000-00-00" {
-//			continue
-//		}
-//		//开始时间
-//		startDate = ``
-//		if refreshAll { //刷新所有数据,用开始时间作为起始日期去刷新
-//			sTime, err := time.Parse(utils.FormatDate, bv.StartDate)
-//			if err != nil {
-//				return err
-//			}
-//			startDate = sTime.Format(utils.FormatDate)
-//		} else {
-//			sTime, err := time.Parse(utils.FormatDate, bv.EndDate)
-//			if err != nil {
-//				return err
-//			}
-//			frequency := bv.Frequency
-//			var limitDay int
-//			switch frequency {
-//			case "日度":
-//				limitDay = utils.DATA_START_REFRESH_LIMIT
-//			case "周度":
-//				limitDay = utils.DATA_START_REFRESH_LIMIT * 7
-//			case "月度":
-//				limitDay = utils.DATA_START_REFRESH_LIMIT * 30
-//			case "季度":
-//				limitDay = utils.DATA_START_REFRESH_LIMIT * 90
-//			case "年度":
-//				limitDay = utils.DATA_START_REFRESH_LIMIT * 365
-//			default:
-//				limitDay = utils.DATA_START_REFRESH_LIMIT
-//			}
-//			startDate = sTime.AddDate(0, 0, -limitDay).Format(utils.FormatDate)
-//		}
-//		result, err := RefreshEdbData(bv.EdbInfoId, bv.Source, bv.EdbCode, startDate)
-//		if err != nil {
-//			fmt.Println(bv.EdbInfoId, "RefreshBaseEdbData err", time.Now())
-//			errmsg = "RefreshBaseEdbData Err:" + err.Error()
-//			return err
-//		}
-//		if result.Ret != 200 {
-//			fmt.Println(bv.EdbInfoId, "RefreshBaseEdbData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			errmsg = fmt.Sprint(bv.EdbInfoId, "RefreshBaseEdbData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			return fmt.Errorf("刷新失败, err:", errmsg)
-//		}
-//
-//		//maxAndMinItem, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
-//		//if err != nil {
-//		//	if err.Error() == utils.ErrNoRow() { //找不到数据,那么就进入到下一条数据做处理
-//		//		continue
-//		//	}
-//		//	return err
-//		//}
-//		//if maxAndMinItem != nil {
-//		//	err = data_manage.ModifyEdbInfoMaxAndMinInfo(edbInfoId, maxAndMinItem)
-//		//	if err != nil {
-//		//		return err
-//		//	}
-//		//}
-//		fmt.Println("end newBaseEdbInfoArr:", bv, time.Now())
-//	}
-//
-//	//刷新相关普通计算指标
-//	for _, v := range calculateArr {
-//		edbInfo := newCalculateMap[v]
-//		if edbInfo == nil {
-//			return err
-//		}
-//
-//		//计算指标就不用开始时间了吧,因为存在说开始时间变更的情况
-//		startDate = ``
-//		if !refreshAll { //如果不是全部更新,那么以指标的开始时间作为刷新
-//			startDate = edbInfo.StartDate
-//			source := edbInfo.Source
-//			if startDate == "" || startDate == "0000-00-00" { //如果没有开始日期,说明还没有计算出来数据,那么就往前面推40年吧(也意味着重新计算了)
-//				startDate = time.Now().AddDate(-40, 0, 0).Format(utils.FormatDate)
-//			} else {
-//				if source == utils.DATA_SOURCE_CALCULATE {
-//					sTime, err := time.Parse(utils.FormatDate, edbInfo.EndDate)
-//					if err != nil {
-//						return err
-//					}
-//					frequency := edbInfo.Frequency
-//					var limitDay int
-//					switch frequency {
-//					case "日度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					case "周度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 7
-//					case "月度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 30
-//					case "季度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 90
-//					case "年度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 365
-//					default:
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					}
-//					startDate = sTime.AddDate(0, 0, -limitDay).Format(utils.FormatDate)
-//				}
-//			}
-//		}
-//
-//		result, err := RefreshEdbCalculateData(edbInfo.EdbInfoId, edbInfo.EdbCode, startDate)
-//		if err != nil {
-//			fmt.Println(v, "RefreshEdbCalculateData err", time.Now())
-//			errmsg = "RefreshEdbCalculateData Err:" + err.Error()
-//			return err
-//		}
-//		if result.Ret != 200 {
-//			fmt.Println(v, "RefreshEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			errmsg = fmt.Sprint(v, "RefreshEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			return fmt.Errorf("刷新失败")
-//		}
-//	}
-//
-//	//刷新相关预测计算指标
-//	for _, v := range predictCalculateArr {
-//		edbInfo := newPredictCalculateMap[v]
-//		if edbInfo == nil {
-//			return err
-//		}
-//		startDate = edbInfo.StartDate
-//		source := edbInfo.Source
-//		if startDate == "" || startDate == "0000-00-00" { //如果没有开始日期,说明还没有计算出来数据,那么就往前面推40年吧(也意味着重新计算了)
-//			startDate = time.Now().AddDate(-40, 0, 0).Format(utils.FormatDate)
-//		} else {
-//			if source == utils.DATA_SOURCE_PREDICT_CALCULATE {
-//				startDate = ``
-//				if refreshAll { //刷新所有数据,用开始时间作为起始日期去刷新
-//					startDate = edbInfo.StartDate
-//				} else {
-//					sTime, err := time.Parse(utils.FormatDate, edbInfo.EndDate)
-//					if err != nil {
-//						return err
-//					}
-//					frequency := edbInfo.Frequency
-//					var limitDay int
-//					switch frequency {
-//					case "日度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					case "周度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 7
-//					case "月度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 30
-//					case "季度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 90
-//					case "年度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 365
-//					default:
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					}
-//					startDate = sTime.AddDate(0, 0, -limitDay).Format(utils.FormatDate)
-//				}
-//			}
-//		}
-//
-//		result, err := RefreshPredictEdbCalculateData(edbInfo.EdbInfoId, edbInfo.EdbCode, startDate)
-//		if err != nil {
-//			fmt.Println(v, "RefreshEdbCalculateData err", time.Now())
-//			errmsg = "RefreshEdbCalculateData Err:" + err.Error()
-//			return err
-//		}
-//		if result.Ret != 200 {
-//			fmt.Println(v, "RefreshPredictEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			errmsg = fmt.Sprint(v, "RefreshPredictEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			return fmt.Errorf("刷新失败")
-//		}
-//	}
-//
-//	// 4、更新动态环差值
-//	{
-//		predictEdbInfoIdList := make([]int, 0)
-//		for _, v := range newBasePredictEdbInfoArr {
-//			predictEdbInfoIdList = append(predictEdbInfoIdList, v.EdbInfoId)
-//		}
-//		fmt.Println("predictEdbConfCalculateMappingDetailList:", predictEdbInfoIdList)
-//		predictEdbConfCalculateMappingDetailList, err := data_manage.GetPredictEdbConfCalculateMappingDetailListByEdbInfoId(predictEdbInfoIdList)
-//		if err != nil {
-//			errmsg = fmt.Sprint("更新动态环差值时,获取数据失败:" + err.Error())
-//			return fmt.Errorf("刷新失败, err:", errmsg)
-//		}
-//		for _, bv := range predictEdbConfCalculateMappingDetailList {
-//			result, err := RefreshEdbData(bv.EdbInfoId, utils.DATA_SOURCE_PREDICT, bv.EdbCode, "")
-//			if err != nil {
-//				fmt.Println(bv.EdbInfoId, "RefreshBasePredictEdbData err", time.Now())
-//				errmsg = "RefreshBasePredictEdbData Err:" + err.Error()
-//				return err
-//			}
-//			if result.Ret != 200 {
-//				fmt.Println(bv.EdbInfoId, "RefreshBasePredictEdbData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//				errmsg = fmt.Sprint(bv.EdbInfoId, "RefreshBasePredictEdbData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//				return fmt.Errorf("刷新失败, err:%s", errmsg)
-//			}
-//			fmt.Println("end predictEdbConfCalculateMappingDetailList:", bv, time.Now())
-//		}
-//	}
-//
-//	//5、再次刷新相关预测计算指标
-//	for _, v := range predictCalculateArr {
-//		edbInfo := newPredictCalculateMap[v]
-//		if edbInfo == nil {
-//			return err
-//		}
-//		startDate = edbInfo.StartDate
-//		source := edbInfo.Source
-//		if startDate == "" || startDate == "0000-00-00" { //如果没有开始日期,说明还没有计算出来数据,那么就往前面推40年吧(也意味着重新计算了)
-//			startDate = time.Now().AddDate(-40, 0, 0).Format(utils.FormatDate)
-//		} else {
-//			if source == utils.DATA_SOURCE_PREDICT_CALCULATE {
-//				startDate = ``
-//				if refreshAll { //刷新所有数据,用开始时间作为起始日期去刷新
-//					startDate = edbInfo.StartDate
-//				} else {
-//					sTime, err := time.Parse(utils.FormatDate, edbInfo.EndDate)
-//					if err != nil {
-//						return err
-//					}
-//					frequency := edbInfo.Frequency
-//					var limitDay int
-//					switch frequency {
-//					case "日度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					case "周度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 7
-//					case "月度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 30
-//					case "季度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 90
-//					case "年度":
-//						limitDay = utils.DATA_START_REFRESH_LIMIT * 365
-//					default:
-//						limitDay = utils.DATA_START_REFRESH_LIMIT
-//					}
-//					startDate = sTime.AddDate(0, 0, -limitDay).Format(utils.FormatDate)
-//				}
-//			}
-//		}
-//
-//		result, err := RefreshPredictEdbCalculateData(edbInfo.EdbInfoId, edbInfo.EdbCode, startDate)
-//		if err != nil {
-//			fmt.Println(v, "RefreshEdbCalculateData err", time.Now())
-//			errmsg = "RefreshEdbCalculateData Err:" + err.Error()
-//			return err
-//		}
-//		if result.Ret != 200 {
-//			fmt.Println(v, "RefreshPredictEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			errmsg = fmt.Sprint(v, "RefreshPredictEdbCalculateData err;msg:", result.Msg, ";errMsg:", result.ErrMsg)
-//			return fmt.Errorf("刷新失败")
-//		}
-//	}
-//
-//	return err
-//}
-
-// EdbInfoRefreshAllFromBaseV3 全部刷新指标(切换到edb_lib服务)
-// @author Roc
-// @datetime 2022-09-16 11:04:44
-// @description 将原有的单个指标刷新,调整为批量多个指标刷新
-func EdbInfoRefreshAllFromBaseV3(edbInfoIdList []int, refreshAll, isSync bool) (err error, isAsync bool) {
+// DeprecatedTime 2023-10-23 09:38:19废弃
+// Deprecated
+func EdbInfoRefreshAllFromBaseV3Bak(edbInfoIdList []int, refreshAll, isSync bool) (err error, isAsync bool) {
 	var errmsg string
 	defer func() {
 		if err != nil {
@@ -568,6 +291,167 @@ func EdbInfoRefreshAllFromBaseV3(edbInfoIdList []int, refreshAll, isSync bool) (
 	return
 }
 
+// EdbInfoRefreshAllFromBaseV3
+//
+//	@Description: 全部刷新指标(切换到edb_lib服务)
+//	@author: Roc
+//	@datetime2023-10-23 09:57:55
+//	@param edbInfoIdList []int
+//	@param refreshAll bool
+//	@param isSync bool
+//	@return err error
+//	@return isAsync bool
+func EdbInfoRefreshAllFromBaseV3(edbInfoIdList []int, refreshAll bool, isSync bool) (err error, isAsync bool) {
+	var errmsg string
+	defer func() {
+		if err != nil {
+			fmt.Println("EdbInfoRefreshAllFromBaseV3 Err:" + err.Error() + ";errmsg:" + errmsg)
+			go alarm_msg.SendAlarmMsg("EdbInfoRefreshAllFromBaseV3,Err"+err.Error()+";errMsg:"+errmsg, 3)
+		}
+	}()
+	traceEdbInfoList, err := TraceEdbInfoByEdbInfoIdList(edbInfoIdList)
+	if err != nil {
+		return
+	}
+	// existEdbInfoIdMap 已经处理了的指标id map
+	existEdbInfoIdMap := make(map[int]int)
+
+	// 基础指标
+	newBaseEdbInfoArr := make([]*data_manage.EdbInfo, 0)
+	newBasePredictEdbInfoArr := make([]*data_manage.EdbInfo, 0)
+	newBaseMap := make(map[int]*data_manage.EdbInfo)
+	newPredictBaseMap := make(map[int]*data_manage.EdbInfo)
+
+	// 计算指标
+	newCalculateMap := make(map[int]*data_manage.EdbInfo)
+	newPredictCalculateMap := make(map[int]*data_manage.EdbInfo)
+	calculateArr := make([]int, 0)
+	predictCalculateArr := make([]int, 0)
+
+	// 获取关联指标
+	for _, traceEdbInfo := range traceEdbInfoList {
+		tmpBaseEdbInfoArr, tmpBasePredictEdbInfoArr, tmpCalculateMap, tmpPredictCalculateMap, _, _ := getRefreshEdbInfoListByTraceEdbInfo(traceEdbInfo, existEdbInfoIdMap)
+
+		// 普通基础指标
+		for _, edbInfo := range tmpBaseEdbInfoArr {
+			if _, ok := newBaseMap[edbInfo.EdbInfoId]; !ok {
+				newBaseMap[edbInfo.EdbInfoId] = edbInfo
+				newBaseEdbInfoArr = append(newBaseEdbInfoArr, edbInfo)
+			}
+		}
+
+		// 预测基础指标
+		for _, edbInfo := range tmpBasePredictEdbInfoArr {
+			if _, ok := newPredictBaseMap[edbInfo.EdbInfoId]; !ok {
+				newPredictBaseMap[edbInfo.EdbInfoId] = edbInfo
+				newBasePredictEdbInfoArr = append(newBasePredictEdbInfoArr, edbInfo)
+			}
+		}
+
+		// 普通计算指标
+		for _, edbInfo := range tmpCalculateMap {
+			if _, ok := newCalculateMap[edbInfo.EdbInfoId]; !ok {
+				newCalculateMap[edbInfo.EdbInfoId] = edbInfo
+				calculateArr = append(calculateArr, edbInfo.EdbInfoId)
+			}
+		}
+
+		// 预测计算指标
+		for _, edbInfo := range tmpPredictCalculateMap {
+			if _, ok := newPredictCalculateMap[edbInfo.EdbInfoId]; !ok {
+				newPredictCalculateMap[edbInfo.EdbInfoId] = edbInfo
+				predictCalculateArr = append(predictCalculateArr, edbInfo.EdbInfoId)
+			}
+		}
+	}
+
+	// 普通计算指标的id
+	sort.Ints(calculateArr)
+	// 预测计算指标的id
+	sort.Ints(predictCalculateArr)
+
+	// 需要刷新的指标数量
+	totalEdbInfo := len(newBaseEdbInfoArr) + len(calculateArr) + len(predictCalculateArr)
+
+	if totalEdbInfo <= 20 || isSync {
+		err = edbInfoRefreshAll(refreshAll, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
+	} else {
+		isAsync = true
+		go edbInfoRefreshAll(refreshAll, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
+	}
+
+	return
+}
+
+// getRefreshEdbInfoListByTraceEdbInfo
+//
+//	@Description: 根据溯源获取关联指标
+//	@author: Roc
+//	@datetime2023-10-23 10:55:01
+//	@param traceEdbInfo data_manage.TraceEdbInfoResp
+//	@param existEdbInfoIdMap map[int]int
+//	@return newBaseEdbInfoArr []*data_manage.EdbInfo
+//	@return newBasePredictEdbInfoArr []*data_manage.EdbInfo
+//	@return newCalculateMap map[int]*data_manage.EdbInfo
+//	@return newPredictCalculateMap map[int]*data_manage.EdbInfo
+//	@return calculateArr []int
+//	@return predictCalculateArr []int
+func getRefreshEdbInfoListByTraceEdbInfo(traceEdbInfo data_manage.TraceEdbInfoResp, existEdbInfoIdMap map[int]int) (newBaseEdbInfoArr, newBasePredictEdbInfoArr []*data_manage.EdbInfo, newCalculateMap, newPredictCalculateMap map[int]*data_manage.EdbInfo, calculateArr, predictCalculateArr []int) {
+	newBaseEdbInfoArr = make([]*data_manage.EdbInfo, 0)
+	newBasePredictEdbInfoArr = make([]*data_manage.EdbInfo, 0)
+	newCalculateMap = make(map[int]*data_manage.EdbInfo)
+	newPredictCalculateMap = make(map[int]*data_manage.EdbInfo)
+	calculateArr = make([]int, 0)
+	predictCalculateArr = make([]int, 0)
+
+	_, ok := existEdbInfoIdMap[traceEdbInfo.EdbInfoId]
+	if ok {
+		return
+	}
+
+	existEdbInfoIdMap[traceEdbInfo.EdbInfoId] = traceEdbInfo.EdbInfoId
+
+	switch traceEdbInfo.EdbInfoType {
+	//0-普通指标; 1-预测指标
+	case 0: // 0-普通指标
+		if traceEdbInfo.EdbType == 1 { //1-基础指标
+			newBaseEdbInfoArr = append(newBaseEdbInfoArr, traceEdbInfo.EdbInfo)
+		} else if traceEdbInfo.EdbType == 2 { //2-计算指标
+			newCalculateMap[traceEdbInfo.EdbInfoId] = traceEdbInfo.EdbInfo
+			calculateArr = append(calculateArr, traceEdbInfo.EdbInfoId)
+		}
+	case 1: // 1-预测指标
+		if traceEdbInfo.EdbType == 1 { //1-基础指标
+			newBasePredictEdbInfoArr = append(newBasePredictEdbInfoArr, traceEdbInfo.EdbInfo)
+		} else if traceEdbInfo.EdbType == 2 { //2-计算指标
+			newPredictCalculateMap[traceEdbInfo.EdbInfoId] = traceEdbInfo.EdbInfo
+			predictCalculateArr = append(predictCalculateArr, traceEdbInfo.EdbInfoId)
+		}
+	}
+
+	if traceEdbInfo.Child != nil && len(traceEdbInfo.Child) > 0 {
+		for _, v := range traceEdbInfo.Child {
+			tmpBaseEdbInfoArr, tmpPredictEdbInfoArr, tmpCalculateMap, tmpPredictCalculateMap, tmpCalculateArr, tmpPredictCalculateArr := getRefreshEdbInfoListByTraceEdbInfo(v, existEdbInfoIdMap)
+
+			newBaseEdbInfoArr = append(newBaseEdbInfoArr, tmpBaseEdbInfoArr...)
+			newBasePredictEdbInfoArr = append(newBasePredictEdbInfoArr, tmpPredictEdbInfoArr...)
+
+			for k, tmpEdbInfo := range tmpCalculateMap {
+				newCalculateMap[k] = tmpEdbInfo
+			}
+
+			for k, tmpEdbInfo := range tmpPredictCalculateMap {
+				newPredictCalculateMap[k] = tmpEdbInfo
+			}
+
+			calculateArr = append(calculateArr, tmpCalculateArr...)
+			predictCalculateArr = append(predictCalculateArr, tmpPredictCalculateArr...)
+		}
+	}
+
+	return
+}
+
 func edbInfoRefreshAll(refreshAll bool, newBaseEdbInfoArr, newBasePredictEdbInfoArr []*data_manage.EdbInfo, newCalculateMap, newPredictCalculateMap map[int]*data_manage.EdbInfo, calculateArr, predictCalculateArr []int) (err error) {
 	var errmsg string
 	defer func() {
@@ -1163,9 +1047,15 @@ func EdbInfoAdd(source, classifyId int, edbCode, edbName, frequency, unit, start
 
 	sourceName, ok := sourceNameMap[source]
 	if !ok {
-		errMsg = "指标来源异常"
-		err = errors.New(errMsg)
-		return
+		edbSource := data_manage.EdbSourceIdMap[source]
+		if edbSource != nil {
+			sourceName = edbSource.SourceName
+		}
+		if sourceName == "" {
+			errMsg = "指标来源异常"
+			err = errors.New(errMsg)
+			return
+		}
 	}
 	edbInfo.SourceName = sourceName
 
@@ -1184,6 +1074,13 @@ func EdbInfoAdd(source, classifyId int, edbCode, edbName, frequency, unit, start
 			}
 		}
 	}
+	//获取该层级下最大的排序数
+	maxSort, err := GetEdbClassifyMaxSort(classifyId, 0)
+	if err != nil {
+		errMsg = "获取失败"
+		err = errors.New("查询排序信息失败,Err:" + err.Error())
+		return
+	}
 	edbInfo.EdbCode = edbCode
 	edbInfo.EdbName = edbName
 	edbInfo.EdbNameSource = edbName
@@ -1197,6 +1094,7 @@ func EdbInfoAdd(source, classifyId int, edbCode, edbName, frequency, unit, start
 	edbInfo.CreateTime = time.Now()
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.ServerUrl = serverUrl
+	edbInfo.Sort = maxSort + 1
 	edbInfo.DataDateType = `交易日`
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	edbInfo.UniqueCode = utils.MD5(utils.DATA_PREFIX + "_" + timestamp)
@@ -1254,6 +1152,55 @@ func EdbInfoAdd(source, classifyId int, edbCode, edbName, frequency, unit, start
 	return
 }
 
+// TraceEdbInfoByEdbInfoIdList 指标追溯
+func TraceEdbInfoByEdbInfoIdList(edbInfoIdList []int) (traceEdbInfoList []data_manage.TraceEdbInfoResp, err error) {
+	traceEdbInfoList = make([]data_manage.TraceEdbInfoResp, 0)
+	edbInfoList, err := data_manage.GetEdbInfoByIdList(edbInfoIdList)
+	if err != nil {
+		return
+	}
+	edbInfoRuleMap := make(map[int]string, 0)
+	edbMappingMap := make(map[int][]*data_manage.EdbInfoCalculateMappingInfo)
+
+	findIdMap := make(map[int]int)
+	existMap := make(map[int]data_manage.TraceEdbInfoResp)
+
+	for _, edbInfo := range edbInfoList {
+		findIdMap[edbInfo.EdbInfoId] = edbInfo.EdbInfoId
+		//edbInfoRuleMap[edbInfoId] = getEdbRuleTitle(edbInfo)
+		traceEdbInfo := data_manage.TraceEdbInfoResp{
+			//EdbInfoId: edbInfo.EdbInfoId,
+			EdbInfoId:   edbInfo.EdbInfoId,
+			EdbInfoType: edbInfo.EdbInfoType,
+			EdbName:     edbInfo.EdbName,
+			EdbType:     edbInfo.EdbType,
+			//Source:      edbInfo.Source,
+			UniqueCode: edbInfo.UniqueCode,
+			ClassifyId: edbInfo.ClassifyId,
+			EdbInfo:    edbInfo,
+		}
+		traceEdbInfo.Child, err = traceEdbInfoByEdbInfoId(edbInfo.EdbInfoId, traceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)
+		traceEdbInfoList = append(traceEdbInfoList, traceEdbInfo)
+	}
+
+	//findEdbInfoIdList := make([]int, 0)
+	//for _, v := range findIdMap {
+	//	findEdbInfoIdList = append(findEdbInfoIdList, v)
+	//}
+	//findEdbInfoList, err := data_manage.GetEdbInfoByIdList(findEdbInfoIdList)
+	//if err != nil {
+	//	return
+	//}
+	//edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	//for _, tmpEdbInfo := range findEdbInfoList {
+	//	edbInfoMap[tmpEdbInfo.EdbInfoId] = tmpEdbInfo
+	//}
+	//for k, traceEdbInfo := range traceEdbInfoList {
+	//	traceEdbInfoList[k], err = handleTraceEdbInfo(traceEdbInfo, 0, edbInfoMap, edbMappingMap)
+	//}
+	return
+}
+
 // TraceEdbInfoByEdbInfoId 指标追溯
 func TraceEdbInfoByEdbInfoId(edbInfoId int) (traceEdbInfo data_manage.TraceEdbInfoResp, err error) {
 	edbInfo, err := data_manage.GetEdbInfoById(edbInfoId)
@@ -1267,6 +1214,7 @@ func TraceEdbInfoByEdbInfoId(edbInfoId int) (traceEdbInfo data_manage.TraceEdbIn
 		//EdbInfoId: edbInfo.EdbInfoId,
 		EdbInfoId: edbInfoId,
 		EdbName:   edbInfo.EdbName,
+		EdbInfo:   edbInfo,
 	}
 	findIdMap := make(map[int]int)
 	findIdMap[edbInfoId] = edbInfoId
@@ -1298,12 +1246,35 @@ func traceEdbInfoByEdbInfoId(edbInfoId int, traceEdbInfo data_manage.TraceEdbInf
 	child = make([]data_manage.TraceEdbInfoResp, 0)
 
 	edbInfoMappingList, err := data_manage.GetEdbInfoCalculateMappingListByEdbInfoId(edbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoCalculateMappingListByEdbInfoId err: %s", err.Error())
+		return
+	}
+
+	// 指标信息map
+	edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	if len(edbInfoMappingList) > 0 {
+		fromEdbInfoIdList := make([]int, 0)
+		for _, v := range edbInfoMappingList {
+			fromEdbInfoIdList = append(fromEdbInfoIdList, v.FromEdbInfoId)
+		}
+		edbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(fromEdbInfoIdList)
+		if tmpErr != nil {
+			err = fmt.Errorf("traceEdbInfoByEdbInfoId GetEdbInfoByIdList err: %s", tmpErr.Error())
+			return
+		}
+		for _, v := range edbInfoList {
+			edbInfoMap[v.EdbInfoId] = v
+		}
+
+	}
 	edbMappingMap[edbInfoId] = edbInfoMappingList
 
 	for _, v := range edbInfoMappingList {
 		tmpEdbInfoId := v.FromEdbInfoId
 		tmpTraceEdbInfo := data_manage.TraceEdbInfoResp{
 			EdbInfoId: tmpEdbInfoId,
+			EdbInfo:   edbInfoMap[v.FromEdbInfoId],
 			//EdbName:   v.EdbName,
 			//RuleTitle: edbInfoRuleMap[v.EdbInfoId],
 			//Child:     make([]data_manage.TraceEdbInfoResp, 0),

+ 331 - 0
services/data/jiayue_index.go

@@ -0,0 +1,331 @@
+package data
+
+import (
+	"encoding/json"
+	"eta/eta_mobile/models/data_manage"
+	"eta/eta_mobile/services/alarm_msg"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+)
+
+// 嘉悦桥接服务接口
+var (
+	BridgeApiJiaYueIndexUrl         = "/api/index_data/jiayue/index"          // 获取指标信息
+	BridgeApiJiaYueIndexDataUrl     = "/api/index_data/jiayue/index_data"     // 获取指标数据
+	BridgeApiJiaYuePageIndexUrl     = "/api/index_data/jiayue/page_index"     // 获取指标列表-分页
+	BridgeApiJiaYueFrequencyListUrl = "/api/index_data/jiayue/frequency_list" // 获取指标频度列表
+)
+
+type EdbBridgeJiaYue struct{}
+
+// GetIndex 获取指标信息
+func (brg *EdbBridgeJiaYue) GetIndex(req GetIndexFromBridgeReq) (item BridgeIndexItem, err error) {
+	var params data_manage.BridgeJiaYueIndexParams
+	params.IndexCode = req.IndexCode
+	params.SourceExtend = req.SourceExtend
+	params.IndexCodeRequired = req.IndexCodeRequired
+	indexData, e := GetJiaYueIndexFromBridge(params)
+	if e != nil {
+		err = fmt.Errorf("GetJiaYueIndexDataFromBridge err: %s", e.Error())
+		return
+	}
+	if indexData.Id <= 0 {
+		return
+	}
+	item.Id = indexData.Id
+	item.IndexCode = indexData.IndexCode
+	item.IndexName = indexData.IndexName
+	item.Unit = indexData.Unit
+	item.Frequency = brg.TransFrequency(indexData.Frequency)
+	return
+}
+
+// GetIndexAndData 获取指标和数据
+//func (brg *EdbBridgeJiaYue) GetIndexAndData(req GetIndexAndDataFromBridgeReq) (item BridgeIndexItem, err error) {
+//	var params data_manage.BridgeJiaYueIndexDataParams
+//	params.IndexCode = req.IndexCode
+//	params.SourceExtend = req.SourceExtend
+//	params.StartDate = req.StartDate
+//	params.EndDate = req.EndDate
+//	indexData, e := GetJiaYueIndexDataFromBridge(params)
+//	if e != nil {
+//		err = fmt.Errorf("GetJiaYueIndexDataFromBridge err: %s", e.Error())
+//		return
+//	}
+//	if indexData.Id <= 0 {
+//		return
+//	}
+//	item.Id = indexData.Id
+//	item.IndexCode = indexData.IndexCode
+//	item.IndexName = indexData.IndexName
+//	item.Unit = indexData.Unit
+//	item.Frequency = brg.TransFrequency(indexData.Frequency)
+//	var dataList []BridgeIndexDataItem
+//	for _, v := range indexData.IndexData {
+//		dataList = append(dataList, BridgeIndexDataItem{
+//			Val:        v.Val,
+//			DataTime:   v.DataTime,
+//			UpdateTime: v.UpdateTime,
+//		})
+//	}
+//	item.Data = dataList
+//	return
+//}
+
+// TransFrequency 嘉悦指标频度转换
+func (brg *EdbBridgeJiaYue) TransFrequency(origin string) string {
+	mapping := map[string]string{
+		"日":  "日度",
+		"周":  "周度",
+		"旬":  "旬度",
+		"半月": "旬度",
+		"月":  "月度",
+		"季":  "季度",
+		"半年": "半年度",
+		"年":  "年度",
+	}
+	return mapping[origin]
+}
+
+// GetJiaYueIndexFromBridge 从桥接服务获取指标信息
+func GetJiaYueIndexFromBridge(param data_manage.BridgeJiaYueIndexParams) (indexData data_manage.BridgeJiaYueIndexAndData, err error) {
+	defer func() {
+		if err != nil {
+			b, _ := json.Marshal(param)
+			tips := fmt.Sprintf("桥接服务-获取嘉悦指标信息, err: %s, params: %s", err.Error(), string(b))
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+	}()
+
+	url := fmt.Sprint(utils.EtaBridgeUrl, BridgeApiJiaYueIndexUrl)
+	data, e := json.Marshal(param)
+	if e != nil {
+		err = fmt.Errorf("data json marshal err: %s", e.Error())
+		return
+	}
+	body := ioutil.NopCloser(strings.NewReader(string(data)))
+	client := &http.Client{}
+	req, e := http.NewRequest("POST", url, body)
+	if e != nil {
+		err = fmt.Errorf("http create request err: %s", e.Error())
+		return
+	}
+
+	checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key)
+	contentType := "application/json;charset=utf-8"
+	req.Header.Set("Content-Type", contentType)
+	req.Header.Set("Authorization", checkToken)
+	resp, e := client.Do(req)
+	if e != nil {
+		err = fmt.Errorf("http client do err: %s", e.Error())
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	b, e := ioutil.ReadAll(resp.Body)
+	if e != nil {
+		err = fmt.Errorf("resp body read err: %s", e.Error())
+		return
+	}
+	if len(b) == 0 {
+		err = fmt.Errorf("resp body is empty")
+		return
+	}
+	// 生产环境解密
+	if utils.RunMode == "release" {
+		str := string(b)
+		str = strings.Trim(str, `"`)
+		b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey)
+	}
+
+	result := new(data_manage.BridgeJiaYueResultIndexData)
+	if e = json.Unmarshal(b, &result); e != nil {
+		err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b))
+		return
+	}
+	if result.Code != 200 {
+		err = fmt.Errorf("result: %s", string(b))
+		return
+	}
+	indexData = result.Data
+	return
+}
+
+// GetJiaYueIndexDataFromBridge 从桥接服务获取指标数据
+//func GetJiaYueIndexDataFromBridge(param data_manage.BridgeJiaYueIndexDataParams) (indexData data_manage.BridgeJiaYueIndexAndData, err error) {
+//	defer func() {
+//		if err != nil {
+//			b, _ := json.Marshal(param)
+//			tips := fmt.Sprintf("桥接服务-获取嘉悦指标数据, err: %s, params: %s", err.Error(), string(b))
+//			go alarm_msg.SendAlarmMsg(tips, 3)
+//		}
+//	}()
+//
+//	url := fmt.Sprint(utils.EtaBridgeUrl, BridgeApiJiaYueIndexDataUrl)
+//	data, e := json.Marshal(param)
+//	if e != nil {
+//		err = fmt.Errorf("data json marshal err: %s", e.Error())
+//		return
+//	}
+//	body := ioutil.NopCloser(strings.NewReader(string(data)))
+//	client := &http.Client{}
+//	req, e := http.NewRequest("POST", url, body)
+//	if e != nil {
+//		err = fmt.Errorf("http create request err: %s", e.Error())
+//		return
+//	}
+//
+//	checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key)
+//	contentType := "application/json;charset=utf-8"
+//	req.Header.Set("Content-Type", contentType)
+//	req.Header.Set("Authorization", checkToken)
+//	resp, e := client.Do(req)
+//	if e != nil {
+//		err = fmt.Errorf("http client do err: %s", e.Error())
+//		return
+//	}
+//	defer func() {
+//		_ = resp.Body.Close()
+//	}()
+//	b, e := ioutil.ReadAll(resp.Body)
+//	if e != nil {
+//		err = fmt.Errorf("resp body read err: %s", e.Error())
+//		return
+//	}
+//	if len(b) == 0 {
+//		err = fmt.Errorf("resp body is empty")
+//		return
+//	}
+//	// 生产环境解密
+//	if utils.RunMode == "release" {
+//		str := string(b)
+//		str = strings.Trim(str, `"`)
+//		b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey)
+//	}
+//
+//	result := new(data_manage.BridgeJiaYueResultIndexData)
+//	if e = json.Unmarshal(b, &result); e != nil {
+//		err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b))
+//		return
+//	}
+//	if result.Code != 200 {
+//		err = fmt.Errorf("result: %s", string(b))
+//		return
+//	}
+//	indexData = result.Data
+//	return
+//}
+
+// GetJiaYueFrequencyListFromBridge 获取指标频度列表
+func GetJiaYueFrequencyListFromBridge() (frequencies []string, err error) {
+	url := fmt.Sprint(utils.EtaBridgeUrl, BridgeApiJiaYueFrequencyListUrl)
+	body := ioutil.NopCloser(strings.NewReader(""))
+	client := &http.Client{}
+	req, e := http.NewRequest("POST", url, body)
+	if e != nil {
+		err = fmt.Errorf("http create request err: %s", e.Error())
+		return
+	}
+
+	checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key)
+	contentType := "application/json;charset=utf-8"
+	req.Header.Set("Content-Type", contentType)
+	req.Header.Set("Authorization", checkToken)
+	resp, e := client.Do(req)
+	if e != nil {
+		err = fmt.Errorf("http client do err: %s", e.Error())
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	b, e := ioutil.ReadAll(resp.Body)
+	if e != nil {
+		err = fmt.Errorf("resp body read err: %s", e.Error())
+		return
+	}
+	if len(b) == 0 {
+		err = fmt.Errorf("resp body is empty")
+		return
+	}
+	// 生产环境解密
+	if utils.RunMode == "release" {
+		str := string(b)
+		str = strings.Trim(str, `"`)
+		b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey)
+	}
+
+	result := new(data_manage.BridgeJiaYueResultFrequencyList)
+	if e = json.Unmarshal(b, &result); e != nil {
+		err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b))
+		return
+	}
+	if result.Code != 200 {
+		err = fmt.Errorf("result: %s", string(b))
+		return
+	}
+	frequencies = result.Data
+	return
+}
+
+// GetJiaYueIndexPageListFromBridge 获取指标分页列表
+func GetJiaYueIndexPageListFromBridge(param data_manage.BridgeJiaYuePageIndexReq) (total int, items []data_manage.DictIndex, err error) {
+	url := fmt.Sprint(utils.EtaBridgeUrl, BridgeApiJiaYuePageIndexUrl)
+	data, e := json.Marshal(param)
+	if e != nil {
+		err = fmt.Errorf("data json marshal err: %s", e.Error())
+		return
+	}
+	body := ioutil.NopCloser(strings.NewReader(string(data)))
+	client := &http.Client{}
+	req, e := http.NewRequest("POST", url, body)
+	if e != nil {
+		err = fmt.Errorf("http create request err: %s", e.Error())
+		return
+	}
+
+	checkToken := utils.MD5(utils.EtaBridgeAppNameEn + utils.EtaBridgeMd5Key)
+	contentType := "application/json;charset=utf-8"
+	req.Header.Set("Content-Type", contentType)
+	req.Header.Set("Authorization", checkToken)
+	resp, e := client.Do(req)
+	if e != nil {
+		err = fmt.Errorf("http client do err: %s", e.Error())
+		return
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+	b, e := ioutil.ReadAll(resp.Body)
+	if e != nil {
+		err = fmt.Errorf("resp body read err: %s", e.Error())
+		return
+	}
+	if len(b) == 0 {
+		err = fmt.Errorf("resp body is empty")
+		return
+	}
+	// 生产环境解密
+	if utils.RunMode == "release" {
+		str := string(b)
+		str = strings.Trim(str, `"`)
+		b = utils.DesBase64Decrypt([]byte(str), utils.EtaBridgeDesKey)
+	}
+
+	result := new(data_manage.BridgeJiaYueResultIndexPageList)
+	if e = json.Unmarshal(b, &result); e != nil {
+		err = fmt.Errorf("result unmarshal err: %s\nresult: %s", e.Error(), string(b))
+		return
+	}
+	if result.Code != 200 {
+		err = fmt.Errorf("result: %s", string(b))
+		return
+	}
+	total = result.Data.Total
+	items = result.Data.List
+	return
+}

+ 119 - 0
services/english_company_todo.go

@@ -0,0 +1,119 @@
+package services
+
+import (
+	"errors"
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/utils"
+	"strconv"
+	"time"
+)
+
+const (
+	TodoButtonColorDoing     = "red"
+	TodoButtonColorDefault   = "gray"
+	TodoButtonColorCompleted = "green"
+)
+
+// GetEnglishCompanyTodoAuthRole 获取可操作英文客户TODO的角色列表
+func GetEnglishCompanyTodoAuthRole() []string {
+	return []string{
+		utils.ROLE_TYPE_CODE_ADMIN,           // 管理员
+		utils.ROLE_TYPE_CODE_FICC_ADMIN,      // FICC管理员
+		utils.ROLE_TYPE_CODE_FICC_DEPARTMENT, // FICC部门经理
+		utils.ROLE_TYPE_CODE_FICC_GROUP,      // FICC销售主管
+		utils.ROLE_TYPE_CODE_FICC_TEAM,       // FICC销售组长
+		utils.ROLE_TYPE_CODE_FICC_SELLER,     // FICC销售
+		utils.ROLE_TYPE_CODE_FICC_RESEARCHR,  // ficc研究员
+	}
+}
+
+// CheckEnglishCompanyTodoAuth 校验当前用户对客户的操作(新增/编辑)权限
+func CheckEnglishCompanyTodoAuth(sysUser *system.Admin, sellerInfo *system.Admin) (ok bool, errMsg string, err error) {
+	// 是否有权限添加/编辑任务
+	roleCode := sysUser.RoleTypeCode
+	authList := GetEnglishCompanyTodoAuthRole()
+	if !utils.InArrayByStr(authList, roleCode) {
+		errMsg = "账号角色异常,不允许操作"
+		return
+	}
+
+	// 销售仅能操作自己的客户
+	if roleCode == utils.ROLE_TYPE_CODE_FICC_SELLER && sellerInfo.AdminId != sysUser.AdminId {
+		errMsg = "该客户不是当前账号所属,不允许操作"
+		return
+	}
+
+	// 判断销售主管、组长权限, 其余管理员角色不做限制
+	switch roleCode {
+	case utils.ROLE_TYPE_CODE_FICC_GROUP:
+		same, e := CheckAdminIsSameBigGroup(sysUser, sellerInfo)
+		if e != nil {
+			errMsg = "保存失败"
+			err = errors.New("判断主管与客户所属销售是否属于同一大组失败, Err: " + e.Error())
+			return
+		}
+		if !same {
+			errMsg = "该客户销售不是当前账号所属组员,不允许操作"
+			return
+		}
+	case utils.ROLE_TYPE_CODE_FICC_TEAM:
+		if sellerInfo.GroupId != sysUser.GroupId {
+			errMsg = "该客户销售不是当前账号所属组员,不允许操作"
+			return
+		}
+	}
+	ok = true
+	return
+}
+
+// GetEnglishCompanyListTodoMap 获取英文客户列表TODO相关信息
+func GetEnglishCompanyListTodoMap(companyList []*models.EnglishCompanyListItem, sysUser *system.Admin) (todoMap map[int]*models.EnglishCompanyListTodo) {
+	todoMap = make(map[int]*models.EnglishCompanyListTodo, 0)
+	if len(companyList) == 0 || sysUser == nil {
+		return
+	}
+	nowTime := time.Now().Local()
+	todayTime := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 0, 0, 0, 0, time.Local)
+	for i := range companyList {
+		c := companyList[i]
+		v := new(models.EnglishCompanyListTodo)
+		v.TodoButtonColor = TodoButtonColorDefault
+		v.HiddenConfirm = true // 默认隐藏完成按钮
+		if c.TodoStatusStr != models.EnglishCompanyTodoStatusNull {
+			// 已完成
+			if c.TodoStatusStr == models.EnglishCompanyTodoStatusCompleted {
+				v.TodoButtonColor = TodoButtonColorCompleted
+			}
+			// 进行中
+			if c.TodoStatusStr == models.EnglishCompanyTodoStatusDoing {
+				v.TodoStatus = true
+				v.TodoButtonColor = TodoButtonColorDoing
+				//v.TodoEndTime = td.EndTime
+				v.TodoEndTimeStr = c.TodoEndTime.Format(utils.FormatDate)
+				// 截止目前还剩余的天数
+				todoEndTime := time.Date(c.TodoEndTime.Year(), c.TodoEndTime.Month(), c.TodoEndTime.Day(), 0, 0, 0, 0, time.Local)
+				deadline := int(todoEndTime.Sub(todayTime).Hours() / 24)
+				v.Deadline = strconv.Itoa(deadline)
+			}
+			// 根据当前角色判断按钮权限
+			switch sysUser.RoleTypeCode {
+			case utils.ROLE_TYPE_CODE_ADMIN, utils.ROLE_TYPE_CODE_FICC_ADMIN, utils.ROLE_TYPE_CODE_FICC_DEPARTMENT, utils.ROLE_TYPE_CODE_FICC_GROUP, utils.ROLE_TYPE_CODE_FICC_RESEARCHR:
+				v.HiddenConfirm = false
+				if c.TodoStatusStr == models.EnglishCompanyTodoStatusDoing {
+					v.CanConfirm = true
+				}
+			case utils.ROLE_TYPE_CODE_FICC_TEAM:
+				// 组长不是自己的客户则展示完成按钮
+				if c.SellerId != sysUser.AdminId {
+					v.HiddenConfirm = false
+				}
+				if c.TodoStatusStr == models.EnglishCompanyTodoStatusDoing {
+					v.CanConfirm = true
+				}
+			}
+		}
+		todoMap[c.CompanyId] = v
+	}
+	return
+}

+ 8 - 8
services/excel/lucky_sheet.go

@@ -110,13 +110,13 @@ type LuckySheetData struct {
 	ChWidth  int64                `json:"ch_width" description:"工作表区域的宽度"`
 	Config   LuckySheetDataConfig `json:"config" description:""`
 	//Index             int                  `json:"index" description:"工作表索引"`
-	RhHeight          float64 `json:"rh_height" description:"工作表区域的高度"`
-	ScrollLeft        float64 `json:"scrollLeft" description:"左右滚动条位置"`
-	ScrollTop         float64 `json:"scrollTop" description:"上下滚动条位置"`
-	Status            int64   `json:"status" description:"激活状态"`
-	VisibleDataColumn []int64 `json:"visibledatacolumn" description:"所有列的位置信息,递增的列位置数据,初始化无需设置"`
-	VisibleDataRow    []int64 `json:"visibledatarow" description:"所有行的位置信息,递增的行位置数据,初始化无需设置"`
-	ZoomRatio         float64 `json:"zoomRatio" description:"sheet缩放比例"`
+	RhHeight          float64     `json:"rh_height" description:"工作表区域的高度"`
+	ScrollLeft        float64     `json:"scrollLeft" description:"左右滚动条位置"`
+	ScrollTop         float64     `json:"scrollTop" description:"上下滚动条位置"`
+	Status            interface{} `json:"status" description:"激活状态"`
+	VisibleDataColumn []int64     `json:"visibledatacolumn" description:"所有列的位置信息,递增的列位置数据,初始化无需设置"`
+	VisibleDataRow    []int64     `json:"visibledatarow" description:"所有行的位置信息,递增的行位置数据,初始化无需设置"`
+	ZoomRatio         float64     `json:"zoomRatio" description:"sheet缩放比例"`
 }
 
 // LuckySheetDataConfig sheet表单的配置
@@ -718,7 +718,7 @@ func (item *LuckySheetData) ToExcel() (downloadFilePath string, err error) {
 func getDownloadPath() (fpath string, err error) {
 	dateDir := time.Now().Format("20060102")
 	uploadDir := "static/xls/" + dateDir
-	err = os.MkdirAll(uploadDir, 0766)
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		return
 	}

+ 349 - 0
services/minio.go

@@ -0,0 +1,349 @@
+package services
+
+import (
+	"context"
+	"errors"
+	"eta/eta_mobile/utils"
+	"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
+}
+
+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
+
+	// 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)
+}
+
+// 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
+}
+
+// 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
+}
+
+// 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
+}

+ 12 - 2
services/oss.go

@@ -148,6 +148,10 @@ type STSToken struct {
 	AccessKeySecret string
 	SecurityToken   string
 	ExpiredTime     string
+	RegionId        string
+	Bucketname      string
+	Endpoint        string
+	Imghost         string
 }
 
 // GetOssSTSToken 获取STSToken
@@ -210,18 +214,20 @@ func NewSTSToken() (item *STSToken, err error) {
 		}
 	}()
 	item = new(STSToken)
-	client, e := sts.NewClientWithAccessKey(utils.RegionId, utils.RAMAccessKeyId, utils.RAMAccessKeySecret)
+	client, e := sts.NewClientWithAccessKey("cn-shanghai", utils.RAMAccessKeyId, utils.RAMAccessKeySecret)
 	if e != nil {
 		err = errors.New("NewSTSToken NewClient Err: " + e.Error())
 		return
 	}
 	request := sts.CreateAssumeRoleRequest()
-	request.Scheme = "https"
+	request.Scheme = utils.AliStsScheme
 	request.RegionId = utils.RegionId
 	request.RoleArn = utils.RoleArn
 	now := time.Now().Format(utils.FormatDateTimeUnSpace)
 	request.RoleSessionName = utils.RoleSessionName + now
 	request.DurationSeconds = "3600"
+	request.ConnectTimeout = 300 * time.Second
+	request.ReadTimeout = 300 * time.Second
 
 	response, e := client.AssumeRole(request)
 	if e != nil {
@@ -235,6 +241,10 @@ func NewSTSToken() (item *STSToken, err error) {
 		t, _ := time.Parse(time.RFC3339, response.Credentials.Expiration)
 		expiration := t.In(time.Local)
 		item.ExpiredTime = expiration.Format(utils.FormatDateTime)
+		item.RegionId = utils.RegionId
+		item.Bucketname = utils.Bucketname
+		item.Endpoint = utils.Imghost
+		item.Imghost = utils.Imghost
 	}
 	return
 }

+ 0 - 49
services/ppt2img/ppt2img.go

@@ -1,49 +0,0 @@
-package ppt2img
-
-import (
-	"encoding/json"
-	"errors"
-	"eta/eta_mobile/utils"
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/http"
-<<<<<<< HEAD
-	"eta/eta_mobile/utils"
-=======
->>>>>>> eta/1.4
-)
-
-type Ppt2ImgResponse struct {
-	Ret         int
-	Msg         string
-	ErrMsg      string
-	ErrCode     string
-	Data        []string
-	Success     bool `description:"true 执行成功,false 执行失败"`
-	IsSendEmail bool `description:"true 发送邮件,false 不发送邮件"`
-}
-
-// Ppt2Img ppt转图片
-// @params pptUrl ppt的在线url
-func Ppt2Img(pptUrl string) (resourceUrlList []string, err error) {
-	params := make(map[string]interface{})
-	params["PptUrl"] = pptUrl
-	param, err := json.Marshal(params)
-	if err != nil {
-		utils.FileLog.Info("Ppt2Img json.Marshal Err:" + err.Error())
-		return
-	}
-
-	body, err := http.Post(utils.Ppt2ImageUrl, string(param))
-	var result Ppt2ImgResponse
-	err = json.Unmarshal(body, &result)
-	if err != nil {
-		fmt.Println("err:" + err.Error())
-		return
-	}
-	if result.Ret != 200 {
-		err = errors.New("获取token失败,Err:" + result.Msg)
-		return
-	}
-	resourceUrlList = result.Data
-	return
-}

+ 93 - 0
services/public_api/base_public_api.go

@@ -0,0 +1,93 @@
+package public_api
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/services/alarm_msg"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+)
+
+// SendTemplateMsg 发送微信模板消息
+func SendTemplateMsg(postData string) (err error) {
+	_, err = post(utils.SendWxTemplateMsgUrl, postData)
+	if err != nil {
+		alarm_msg.SendAlarmMsg("SendTemplateMsg http.NewRequest Err:"+err.Error(), 1)
+		return
+	}
+	return
+}
+
+// ReportChapterReq 报告章节id
+type ReportChapterReq struct {
+	ReportChapterId int `description:"报告章节ID"`
+}
+
+// HandleVideoDecibel 处理音频
+func HandleVideoDecibel(reportChapterId int) (err error) {
+	if utils.HandleVideoDecibelUrl == `` {
+		// 处理音频的地址未配置的话,直接返回
+		return
+	}
+	postData := ReportChapterReq{
+		ReportChapterId: reportChapterId,
+	}
+	postDataByte, err := json.Marshal(postData)
+	if err != nil {
+		alarm_msg.SendAlarmMsg("HandleVideoDecibel json.Marshal Err:"+err.Error(), 1)
+		return err
+	}
+	_, err = post(utils.HandleVideoDecibelUrl, string(postDataByte))
+	if err != nil {
+		alarm_msg.SendAlarmMsg("HandleVideoDecibel json.Marshal Err:"+err.Error(), 1)
+		return err
+	}
+	return
+}
+
+type BaseResponse struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        interface{}
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
+func post(postUrl, postData string) (result *models.BaseResponse, err error) {
+	body := ioutil.NopCloser(strings.NewReader(postData))
+	client := &http.Client{}
+	req, err := http.NewRequest("POST", postUrl, body)
+	if err != nil {
+		alarm_msg.SendAlarmMsg("post public_api http.NewRequest Err:"+err.Error(), 1)
+		return
+	}
+	contentType := "application/json;charset=utf-8"
+	req.Header.Set("Content-Type", contentType)
+	req.Header.Set("Authorization", utils.SendTemplateMsgAuthorization)
+	resp, err := client.Do(req)
+	if err != nil {
+		fmt.Println("http client.Do Err:" + err.Error())
+		return
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return
+	}
+	result = new(models.BaseResponse)
+	err = json.Unmarshal(b, &result)
+	if err != nil {
+		return
+	}
+	if result.Ret != 200 {
+		err = errors.New(string(b))
+	}
+	return
+}

+ 47 - 18
services/report.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_mobile/models/company"
 	"eta/eta_mobile/models/system"
 	"eta/eta_mobile/services/alarm_msg"
+	"eta/eta_mobile/services/public_api"
 	"eta/eta_mobile/utils"
 	"fmt"
 	"github.com/PuerkitoBio/goquery"
@@ -45,6 +46,10 @@ func GetReportContentSub(content string) (contentSub string, err error) {
 
 // PublishDayWeekReport 发布晨周报
 func PublishDayWeekReport(reportId int) (tips string, err error) {
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		return
+	}
+
 	report, err := models.GetReportByReportId(reportId)
 	if err != nil {
 		return
@@ -186,9 +191,12 @@ func UpdateReportEs(reportId int, publishState int) (err error) {
 		if len(chapterList) > 0 {
 			for i := 0; i < len(chapterList); i++ {
 				// 章节对应的品种
-				permissionList, tmpErr := models.GetChapterTypePermissionByTypeIdAndResearchType(chapterList[i].TypeId, chapterList[i].ReportType)
-				if tmpErr != nil {
-					return
+				permissionList := make([]*models.ReportChapterTypePermission, 0)
+				if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+					permissionList, tmpErr = models.GetChapterTypePermissionByTypeIdAndResearchType(chapterList[i].TypeId, chapterList[i].ReportType)
+					if tmpErr != nil {
+						return
+					}
 				}
 				categoryArr := make([]string, 0)
 				if len(permissionList) > 0 {
@@ -222,16 +230,18 @@ func UpdateReportEs(reportId int, publishState int) (err error) {
 			}
 		}
 	} else {
-		permissionList, tmpErr := models.GetChartPermissionNameFromMappingByKeyword(reportInfo.ClassifyNameSecond, "rddp")
-		if tmpErr != nil {
-			return
-		}
-		categoryArr := make([]string, 0)
-		for i := 0; i < len(permissionList); i++ {
-			categoryArr = append(categoryArr, permissionList[i].PermissionName)
+		if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+			permissionList, tmpErr := models.GetChartPermissionNameFromMappingByKeyword(reportInfo.ClassifyNameSecond, "rddp")
+			if tmpErr != nil {
+				return
+			}
+			categoryArr := make([]string, 0)
+			for i := 0; i < len(permissionList); i++ {
+				categoryArr = append(categoryArr, permissionList[i].PermissionName)
+			}
+			aliasArr, _ := addCategoryAliasToArr(categoryArr)
+			categories = strings.Join(aliasArr, ",")
 		}
-		aliasArr, _ := addCategoryAliasToArr(categoryArr)
-		categories = strings.Join(aliasArr, ",")
 	}
 
 	// 新增报告ES
@@ -303,9 +313,12 @@ func UpdateReportChapterEs(reportChapterId int) (err error) {
 		return
 	}
 	// 章节对应的品种
-	permissionList, tmpErr := models.GetChapterTypePermissionByTypeIdAndResearchType(chapterInfo.TypeId, chapterInfo.ReportType)
-	if tmpErr != nil {
-		return
+	permissionList := make([]*models.ReportChapterTypePermission, 0)
+	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
+		permissionList, err = models.GetChapterTypePermissionByTypeIdAndResearchType(chapterInfo.TypeId, chapterInfo.ReportType)
+		if err != nil {
+			return
+		}
 	}
 	categoryArr := make([]string, 0)
 	if len(permissionList) > 0 {
@@ -502,9 +515,18 @@ func PcCreateAndUploadSunCode(scene, page string) (imgUrl string, err error) {
 	}()
 	// 上传OSS
 	fileDir := "yb/suncode/"
-	imgUrl, err = UploadAliyunToDir(fileName, fpath, "", fileDir)
-	if err != nil {
-		return
+
+	//上传到阿里云 和 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 err != nil {
@@ -732,3 +754,10 @@ func SaveReportLogs(item *models.Report, chapters []*models.ReportChapter, admin
 	}
 	return
 }
+
+// HandleVideoDecibel 处理报告中的音频文件
+func HandleVideoDecibel(chapterInfo *models.ReportChapter) {
+	public_api.HandleVideoDecibel(chapterInfo.ReportChapterId)
+
+	return
+}

+ 56 - 0
services/system.go

@@ -0,0 +1,56 @@
+package services
+
+import (
+	"eta/eta_mobile/models/company"
+	"eta/eta_mobile/models/system"
+)
+
+// CheckAdminIsSameBigGroup 判断是否两个系统用户是否同一个大组内
+func CheckAdminIsSameBigGroup(adminInfo1, adminInfo2 *system.Admin) (isSame bool, err error) {
+	// 如果销售和创建人是同一个小组
+	if adminInfo1.GroupId == adminInfo2.GroupId {
+		isSame = true
+		return
+	}
+	var admin1BigGroupId, admin2BigGroupId int
+
+	//获取第一个系统用户的大组id
+	{
+		//获取该账号的大组id
+		pid, tmpErr := company.GetParentIdFromGroup(adminInfo1.GroupId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if pid != nil && *pid > 0 {
+			//该账号放在了三级分组下
+			admin1BigGroupId = *pid
+		} else {
+			//该账号放在了二级分组下
+			admin1BigGroupId = adminInfo1.GroupId
+		}
+	}
+
+	//获取第二个系统用户的大组id
+	{
+		//获取该账号的大组id
+		pid, tmpErr := company.GetParentIdFromGroup(adminInfo2.GroupId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if pid != nil && *pid > 0 {
+			//该账号放在了三级分组下
+			admin2BigGroupId = *pid
+		} else {
+			//该账号放在了二级分组下
+			admin2BigGroupId = adminInfo2.GroupId
+		}
+	}
+
+	if admin1BigGroupId == admin2BigGroupId {
+		isSame = true
+		return
+	}
+	return
+}

+ 29 - 8
services/user_login.go

@@ -79,24 +79,45 @@ func SendAdminEmailVerifyCode(source int, email string) (ok bool, err error) {
 	}
 
 	// 获取邮箱模板
-	confKey := "admin_verify_code_email_tmp"
-	confTmp, e := company.GetConfigDetailByCode(confKey)
+	// 获取配置好的短信模版
+	cond := ` AND (conf_key = ? OR conf_key = ?)`
+	pars := make([]interface{}, 0)
+	pars = append(pars, "LoginEmailTemplateSubject", "LoginEmailTemplateContent")
+	busiConf := new(models.BusinessConf)
+	emailConfList, e := busiConf.GetItemsByCondition(cond, pars, []string{"conf_key, conf_val"}, "")
 	if e != nil {
-		err = fmt.Errorf("获取邮件模板失败, Err: %s", e.Error())
+		if e.Error() == utils.ErrNoRow() {
+			err = fmt.Errorf("请先配置邮件模版")
+			return
+		}
+		err = fmt.Errorf("获取邮件模版失败, Err: %s", e.Error())
 		return
 	}
-	if confTmp.ConfigValue == `` {
-		err = fmt.Errorf("邮件模板为空, 不可推送")
+	var emaiContent, emailSubject string
+	for _, v := range emailConfList {
+		if v.ConfKey == "LoginEmailTemplateContent" {
+			emaiContent = v.ConfVal
+		} else if v.ConfKey == "LoginEmailTemplateSubject" {
+			emailSubject = v.ConfVal
+		}
+	}
+	if emailSubject == "" {
+		err = fmt.Errorf("请先配置邮件模版主题")
+		return
+	}
+	if emaiContent == "" {
+		err = fmt.Errorf("请先配置邮件模版内容")
 		return
 	}
 
 	req := new(EnglishReportSendEmailRequest)
-	req.Subject = "弘则研究登录验证"
+	req.Subject = emailSubject
 	req.Email = email
+	// todo 发信人昵称
 	req.FromAlias = conf.FromAlias
 	// 填充模板
 	t := time.Now().Format("2006年01月02日")
-	ct := confTmp.ConfigValue
+	ct := emaiContent
 	ct = strings.Replace(ct, "{{VERIFY_CODE}}", verifyCode, 1)
 	ct = strings.Replace(ct, "{{EXPIRED_MINUTE}}", strconv.Itoa(utils.VerifyCodeExpireMinute), 1)
 	ct = strings.Replace(ct, "{{DATE_TIME}}", t, 1)
@@ -120,4 +141,4 @@ func SendAdminEmailVerifyCode(source int, email string) (ok bool, err error) {
 		err = fmt.Errorf("更新验证码记录失败, Err: %s", e.Error())
 	}
 	return
-}
+}

+ 73 - 14
services/video.go

@@ -9,6 +9,7 @@ import (
 	"eta/eta_mobile/models"
 	"eta/eta_mobile/services/alarm_msg"
 	"eta/eta_mobile/utils"
+	"fmt"
 	"github.com/PuerkitoBio/goquery"
 	"github.com/kgiannakakis/mp3duration/src/mp3duration"
 	"html"
@@ -28,6 +29,24 @@ func CreateVideo(report *models.ReportDetail) (err error) {
 			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "Err:"+err.Error(), utils.EmailSendToUsers)
 		}
 	}()
+
+	// 获取基础配置, 若未配置则直接返回
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("获取基础配置失败, Err: " + e.Error())
+		return
+	}
+	if conf[models.BusinessConfUseXf] != "true" {
+		return
+	}
+	if conf[models.BusinessConfXfAppid] == "" || conf[models.BusinessConfXfApiKey] == "" || conf[models.BusinessConfXfApiSecret] == "" || conf[models.BusinessConfXfVcn] == "" {
+		return
+	}
+	var xfReq XfParams
+	xfReq.XfAPPID = conf[models.BusinessConfXfAppid]
+	xfReq.XfAPIKey = conf[models.BusinessConfXfApiKey]
+	xfReq.XfAPISecret = conf[models.BusinessConfXfApiSecret]
+
 	ct, err := time.Parse(utils.FormatDateTime, report.CreateTime)
 	createTime := ct.Format("0102")
 	videoName := report.Title + "(" + createTime + ")"
@@ -42,11 +61,11 @@ func CreateVideo(report *models.ReportDetail) (err error) {
 	}
 
 	param := new(models.XfSendParam)
-	param.Common.AppId = utils.XfAPPID
+	param.Common.AppId = conf[models.BusinessConfXfAppid]
 	param.Business.Aue = "lame"
 	param.Business.Sfl = 1
 	param.Business.Auf = "audio/L16;rate=16000"
-	param.Business.Vcn = utils.XfVcn
+	param.Business.Vcn = conf[models.BusinessConfXfVcn]
 	param.Business.Speed = 50
 	param.Business.Volume = 100
 	param.Business.Pitch = 50
@@ -70,7 +89,7 @@ func CreateVideo(report *models.ReportDetail) (err error) {
 		if err != nil {
 			return err
 		}
-		err = GetXfVideo(result, savePath)
+		err = GetXfVideo(result, savePath, xfReq)
 		if err != nil {
 			err = errors.New("GetXfVideo Err:" + err.Error())
 			utils.FileLog.Error("GetXfVideo err", err.Error())
@@ -78,10 +97,21 @@ func CreateVideo(report *models.ReportDetail) (err error) {
 		}
 		time.Sleep(5 * time.Second)
 	}
-	uploadUrl, err := UploadAudioAliyun(saveName, savePath)
-	if err != nil {
-		err = errors.New("UploadAudioAliyun Err:" + err.Error())
-		return
+
+	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
+		}
 	}
 
 	fileBody, err := ioutil.ReadFile(savePath)
@@ -198,6 +228,24 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 	if reportContent == "" {
 		return
 	}
+
+	// 获取基础配置, 若未配置则直接返回
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("获取基础配置失败, Err: " + e.Error())
+		return
+	}
+	if conf[models.BusinessConfUseXf] != "true" {
+		return
+	}
+	if conf[models.BusinessConfXfAppid] == "" || conf[models.BusinessConfXfApiKey] == "" || conf[models.BusinessConfXfApiSecret] == "" || conf[models.BusinessConfXfVcn] == "" {
+		return
+	}
+	var xfReq XfParams
+	xfReq.XfAPPID = conf[models.BusinessConfXfAppid]
+	xfReq.XfAPIKey = conf[models.BusinessConfXfApiKey]
+	xfReq.XfAPISecret = conf[models.BusinessConfXfApiSecret]
+
 	ct, err := time.Parse(utils.FormatDateTime, reportTime)
 	if err != nil {
 		return
@@ -215,11 +263,11 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 	}
 
 	param := new(models.XfSendParam)
-	param.Common.AppId = utils.XfAPPID
+	param.Common.AppId = conf[models.BusinessConfXfAppid]
 	param.Business.Aue = "lame"
 	param.Business.Sfl = 1
 	param.Business.Auf = "audio/L16;rate=16000"
-	param.Business.Vcn = utils.XfVcn
+	param.Business.Vcn = conf[models.BusinessConfXfVcn]
 	param.Business.Speed = 50
 	param.Business.Volume = 100
 	param.Business.Pitch = 50
@@ -243,7 +291,7 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 		if tmpErr != nil {
 			return
 		}
-		err = GetXfVideo(result, savePath)
+		err = GetXfVideo(result, savePath, xfReq)
 		if err != nil {
 			err = errors.New("GetXfVideo Err:" + err.Error())
 			utils.FileLog.Error("GetXfVideo err", err.Error())
@@ -251,10 +299,21 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 		}
 		time.Sleep(5 * time.Second)
 	}
-	uploadUrl, err = UploadAudioAliyun(saveName, savePath)
-	if err != nil {
-		err = errors.New("UploadAudioAliyun Err:" + err.Error())
-		return
+
+
+	//上传到阿里云 和 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
+		}
 	}
 
 	fileBody, err := ioutil.ReadFile(savePath)

+ 4 - 0
services/wechat_send_msg.go

@@ -15,6 +15,10 @@ import (
 
 // SendMiniProgramReportWxMsg 推送报告微信模板消息-小程序链接
 func SendMiniProgramReportWxMsg(reportId int) (err error) {
+	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox {
+		return
+	}
+
 	var msg string
 	reportIdStr := strconv.Itoa(reportId)
 	defer func() {

+ 11 - 5
services/xfyun.go

@@ -14,9 +14,15 @@ import (
 	"github.com/gorilla/websocket"
 )
 
+type XfParams struct {
+	XfAPPID     string
+	XfAPIKey    string
+	XfAPISecret string
+}
+
 // 科大讯飞,语音合成
-func GetXfVideo(body []byte, savePath string) (err error) {
-	path, err := assembleAuthUrl()
+func GetXfVideo(body []byte, savePath string, req XfParams) (err error) {
+	path, err := assembleAuthUrl(req)
 	if err != nil {
 		return
 	}
@@ -79,7 +85,7 @@ webSocketClose:
 // @hosturl :  like  wss://iat-api.xfyun.cn/v2/iat
 // @apikey : apiKey
 // @apiSecret : apiSecret
-func assembleAuthUrl() (callUrl string, err error) {
+func assembleAuthUrl(req XfParams) (callUrl string, err error) {
 	ul, err := url.Parse(utils.XfHostUrl)
 	if err != nil {
 		return
@@ -92,9 +98,9 @@ func assembleAuthUrl() (callUrl string, err error) {
 	sign := strings.Join(signString, "\n")
 	fmt.Println("sign:", sign)
 	//签名结果
-	sha := crypt.HmacSha256EncryptToBase64([]byte(sign), []byte(utils.XfAPISecret))
+	sha := crypt.HmacSha256EncryptToBase64([]byte(sign), []byte(req.XfAPISecret))
 	//构建请求参数 此时不需要urlencoding
-	authUrl := fmt.Sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", utils.XfAPIKey,
+	authUrl := fmt.Sprintf("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", req.XfAPIKey,
 		"hmac-sha256", "host date request-line", sha)
 	//将请求参数使用base64编码
 	authorization := base64.StdEncoding.EncodeToString([]byte(authUrl))

+ 72 - 77
utils/config.go

@@ -9,32 +9,26 @@ import (
 )
 
 var (
-	RunMode               string //运行模式
-	MYSQL_URL             string //数据库连接
-	MYSQL_URL_RDDP        string //数据库连接
-	MYSQL_URL_EDB         string
-	MYSQL_URL_DATA        string
-	MYSQL_URL_GL          string
-	MYSQL_LOG_URL         string
-	MYSQL_URL_COMEIN_DATA string // 路演记录数据库
-	MYSQL_URL_ETA         string
+	RunMode          string //运行模式
+	MYSQL_URL        string //数据库连接
+	MYSQL_URL_RDDP   string //数据库连接
+	MYSQL_URL_EDB    string
+	MYSQL_URL_DATA   string
+	MYSQL_URL_GL     string
+	MYSQL_LOG_URL    string
+	MYSQL_WEEKLY_URL string //用户主库
 
 	REDIS_CACHE string       //缓存地址
 	Rc          *cache.Cache //redis缓存
 	Re          error        //redis错误
 )
 
-// SystemType 系统类型; hz:弘则;trial:试用平台;custom:客户
-var SystemType string
-
 // 基础配置
 var (
 	STATIC_DIR       string
 	DesKey           string // 接口返回加密KEY
 	APPNAME          string //项目中文名称
 	EmailSendToUsers string // 邮件提醒人员
-	// LibreOfficePath LibreOfficePath的地址
-	LibreOfficePath string
 )
 
 // 公共api内部服务调用
@@ -56,23 +50,23 @@ var (
 	// HandleVideoDecibelUrl 处理音频分贝的url
 	HandleVideoDecibelUrl string
 
-	// Ppt2ImageUrl ppt转图片服务的地址
-	Ppt2ImageUrl string
-
 	// EnglishShareUrl 英文研报群发邮件分享地址
 	EnglishShareUrl string
 
 	// AlarmMsgUrl 报警服务地址
 	AlarmMsgUrl string
+
+	EtaBridgeUrl       string // 桥接服务地址
+	EtaBridgeAppNameEn string // 桥接服务英文名称-鉴权用
+	EtaBridgeMd5Key    string // 桥接服务Md5密钥-鉴权用
+	EtaBridgeDesKey    string // 桥接服务Des密钥-解密数据用
 )
 
 // TemplateIdByProduct 微信配置信息
 var (
 	TemplateIdByProduct string //产品运行报告通知-模板ID
 	WxYbAppId           string // 研报小程序appid
-	WxYbId              string // 研报小程序微信原始ID
 	WxYbAppSecret       string // 研报小程序秘钥
-	WxYbPlatform        int    //弘则研报来源
 )
 
 // ES配置
@@ -91,6 +85,11 @@ var (
 	MY_CHART_INDEX_NAME      string //研究图库(MY ETA)索引
 )
 
+// 科大讯飞--语音合成
+var (
+	XfHostUrl string
+)
+
 // 阿里云配置
 var (
 	Bucketname       string
@@ -113,35 +112,17 @@ var (
 	STSTokenCacheKey   string
 )
 
-// 科大讯飞--语音合成
-var (
-	XfSTATUS_FIRST_FRAME    = 0 //第一帧标识
-	XfSTATUS_CONTINUE_FRAME = 1 //中间帧标识
-	XfSTATUS_LAST_FRAME     = 2 //最后一帧标识
-	XfHost                  = "tts-api.xfyun.cn"
-	XfMaxFontSize           = 8000
-	XfAPPID                 string
-	XfAPIKey                string
-	XfAPISecret             string
-	XfHostUrl               string
-	XfOrigin                string
-	XfVcn                   string //发言人
-)
-
 // 阿里云邮箱配置
 var (
-	AliyunEmailAccountName       string
-	AliyunEmailAccessKeyId       string
-	AliyunEmailAccessKeySecret   string
-	AliyunEmailReplyAddress      string
-	AliyunEmailReplyAddressAlias string
+	AliyunEmailAccountName     string
+	AliyunEmailAccessKeyId     string
+	AliyunEmailAccessKeySecret string
 )
 
 // 腾讯云邮箱配置
 var (
-	TencentSDKSecretId  string // 腾讯云主账号SecretId
-	TencentSDKSecretKey string // 腾讯云主账号SecretKey
-
+	TencentSDKSecretId           string // 腾讯云主账号SecretId
+	TencentSDKSecretKey          string // 腾讯云主账号SecretKey
 	TencentEmailFromEmailAddress string // 腾讯云邮件发信地址
 	TencentEmailTemplateID       uint64 // 云邮件模板ID
 )
@@ -159,6 +140,28 @@ var (
 	LogMaxDays  int //日志最大保留天数
 )
 
+// BusinessCode 商家编码
+var BusinessCode string
+
+// MinIo配置
+var (
+	MinIoBucketname       string
+	MinIoEndpoint         string
+	MinIoImghost          string
+	MinIoUploadDir        string
+	MinIoUpload_Audio_Dir string
+	MinIoAccessKeyId      string
+	MinIoAccessKeySecret  string
+	MinIoUseSSL           string
+	MinIoPort             string
+	MinIoRegion           string
+)
+
+// 对象存储客户端
+var (
+	ObjectStorageClient string // 目前有oss minio,默认oss
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -194,8 +197,7 @@ func init() {
 	MYSQL_URL_DATA = config["mysql_url_data"]
 	MYSQL_URL_GL = config["mysql_url_gl"]
 	MYSQL_LOG_URL = config["mysql_url_log"]
-	MYSQL_URL_COMEIN_DATA = config["mysql_url_comein_data"]
-	MYSQL_URL_ETA = config["mysql_url_eta"]
+	MYSQL_WEEKLY_URL = config["mysql_url_weekly"]
 
 	REDIS_CACHE = config["beego_cache"]
 	if len(REDIS_CACHE) <= 0 {
@@ -207,13 +209,6 @@ func init() {
 		panic(Re)
 	}
 
-	// 系统类型
-	systemType, err := web.AppConfig.String("system_type")
-	if err != nil {
-		panic(any("配置文件读取system_type错误 " + err.Error()))
-	}
-	SystemType = systemType
-
 	// 项目中文名称
 	appNameCn, err := web.AppConfig.String("app_name_cn")
 	if err != nil {
@@ -226,14 +221,11 @@ func init() {
 	// 接口返回加密KEY
 	DesKey = config["des_key"]
 
-	// 服务基本配置
-	{
-		// 邮件提醒人员
-		EmailSendToUsers = config["email_send_to_users"]
+	// 邮件提醒人员
+	EmailSendToUsers = config["email_send_to_users"]
 
-		// 静态文件目录
-		STATIC_DIR = config["static_dir"]
-	}
+	// 静态文件目录
+	STATIC_DIR = config["static_dir"]
 
 	// 系统内部服务地址
 	{
@@ -260,8 +252,10 @@ func init() {
 		// 报警服务地址
 		AlarmMsgUrl = config["alarm_msg_url"]
 
-		// ppt 转图片服务地址
-		Ppt2ImageUrl = config["ppt2_image_url"]
+		EtaBridgeUrl = config["eta_bridge_url"]               // 桥接服务地址
+		EtaBridgeAppNameEn = config["eta_bridge_app_name_en"] // 桥接服务英文名称-鉴权用
+		EtaBridgeMd5Key = config["eta_bridge_md5_key"]        // 桥接服务Md5密钥-鉴权用
+		EtaBridgeDesKey = config["eta_bridge_des_key"]        // 桥接服务Des密钥-解密数据用
 	}
 	//日志配置
 	{
@@ -298,17 +292,12 @@ func init() {
 		//模板消息
 		TemplateIdByProduct = config["template_id_by_product"]
 		WxYbAppId = config["wx_yb_appid"]          //弘则研报小程序
-		WxYbId = config["wx_yb_id"]                // 研报小程序微信原始ID
 		WxYbAppSecret = config["wx_yb_app_secret"] // 研报小程序秘钥
-		wxYbPlatformStr := config["wx_yb_platform"]
-		if wxYbPlatformStr != `` {
-			WxYbPlatform, err = strconv.Atoi(wxYbPlatformStr) //弘则研报来源
-			if err != nil {
-				panic(any("配置文件读取wx_yb_platform错误 " + err.Error()))
-			}
-		}
 	}
 
+	// 对象存储客户端
+	ObjectStorageClient = config["object_storage_client"]
+
 	// OSS相关
 	{
 		Endpoint = config["endpoint"]
@@ -336,8 +325,6 @@ func init() {
 		AliyunEmailAccountName = config["aliyun_email_account_name"]
 		AliyunEmailAccessKeyId = config["aliyun_email_access_key_id"]
 		AliyunEmailAccessKeySecret = config["aliyun_email_access_key_secret"]
-		AliyunEmailReplyAddress = config["aliyun_email_reply_address"]
-		AliyunEmailReplyAddressAlias = config["aliyun_email_reply_address_alias"]
 	}
 
 	// 腾讯云邮箱配置
@@ -358,16 +345,24 @@ func init() {
 
 	// 科大讯飞
 	{
-
-		XfAPPID = config["xf_appid"]
-		XfAPIKey = config["xf_api_key"]
-		XfAPISecret = config["xf_api_secret"]
 		XfHostUrl = config["xf_host_url"]
-		XfOrigin = config["xf_origin"]
-		XfVcn = config["xf_vcn"]
 	}
 
-	LibreOfficePath = config["libre_office_path"]
+	// MinIo相关
+	{
+		MinIoEndpoint = config["minio_endpoint"]
+		MinIoBucketname = config["minio_bucket_name"]
+		MinIoImghost = config["minio_img_host"]
+		MinIoUploadDir = config["minio_upload_dir"]
+		MinIoUpload_Audio_Dir = config["minio_upload_audio_dir"]
+		MinIoAccessKeyId = config["minio_access_key_id"]
+		MinIoAccessKeySecret = config["minio_access_key_secret"]
+		MinIoUseSSL = config["minio_use_ssl"]
+		MinIoPort = config["minio_port"]
+		MinIoRegion = config["minio_region"]
+	}
+	// 商家编码
+	BusinessCode = config["business_code"]
 
 	// 初始化ES
 	initEs()

+ 23 - 0
utils/constants.go

@@ -1,5 +1,7 @@
 package utils
 
+import "io/fs"
+
 const (
 	Md5Key = "Ks@h64WJ#tcVgG8$&WlNfqvLAtMgpxWN"
 )
@@ -156,6 +158,8 @@ const (
 	DATA_SOURCE_FUBAO                                           //富宝数据->71
 	DATA_SOURCE_CALCULATE_ZSXY                                  // 指数修匀->72
 	DATA_SOURCE_PREDICT_CALCULATE_ZSXY                          // 预测指数修匀->73
+	DATA_SOURCE_CALCULATE_ZDYFX                                 // 自定义分析->74
+	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
 )
 
 // 数据刷新频率
@@ -347,6 +351,7 @@ const (
 	SmsNewLoginTplId       = "254663"            // 【弘则研究】您的验证码是XXX,有效期15分钟
 )
 
+// TODO:2023-0915 聚合短信相关配置在ETA1.0.6版本中被改成了商家配置, 还未上线, 上线后这里也改成配置
 // 聚合短信
 var (
 	JhGnAppKey = "4c8504c49dd335e99cfd7b6a3a9e2415" //聚合国内AppKey
@@ -354,3 +359,21 @@ var (
 )
 
 const LoginCacheTime = 60 // 登录缓存时长, 分钟
+
+// DIR_MOD 目录创建权限
+const DIR_MOD fs.FileMode = 0766 // Unix permission bits
+
+// 自用商户号
+const (
+	BusinessCodeSandbox = "E2023080700" // 试用平台
+	BusinessCodeRelease = "E2023080900" // 生产环境
+)
+
+// BusinessCodeSalt 商家编码盐值
+const BusinessCodeSalt = "dr7WY0OZgGR7upw1"
+
+// 对象存储客户端
+const (
+	STORAGESOURCE_OSS   = 1 //阿里云OSS
+	STORAGESOURCE_MINIO = 2 //MinIo
+)

+ 2 - 2
utils/des3.go

@@ -20,7 +20,7 @@ func DesBase64Encrypt(origData []byte) []byte {
 	return []byte(base64.StdEncoding.EncodeToString(result))
 }
 
-func DesBase64Decrypt(crypted []byte) []byte {
+func DesBase64Decrypt(crypted []byte, desKey string) []byte {
 	result, _ := base64.StdEncoding.DecodeString(string(crypted))
 	remain := len(result) % 8
 	if remain > 0 {
@@ -29,7 +29,7 @@ func DesBase64Decrypt(crypted []byte) []byte {
 			result = append(result, 0)
 		}
 	}
-	origData, err := TripleDesDecrypt(result, []byte(DesKey))
+	origData, err := TripleDesDecrypt(result, []byte(desKey))
 	if err != nil {
 		panic(err)
 	}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно