kobe6258 1 kuukausi sitten
vanhempi
commit
d500ec46c5

+ 63 - 8
controllers/chart.go

@@ -3,10 +3,12 @@ package controllers
 import (
 	"encoding/json"
 	"errors"
+	"eta/eta_chart_lib/facade"
 	"eta/eta_chart_lib/models"
 	"eta/eta_chart_lib/models/data_manage"
 	"eta/eta_chart_lib/models/data_manage/cross_variety/request"
 	"eta/eta_chart_lib/models/data_manage/excel"
+	requestDTO "eta/eta_chart_lib/models/request"
 	"eta/eta_chart_lib/services/data"
 	"eta/eta_chart_lib/services/data/area_graph"
 	"eta/eta_chart_lib/services/data/cross_variety"
@@ -39,6 +41,7 @@ func (this *ChartController) ChartInfoDetail() {
 	uniqueCode := this.GetString("UniqueCode")
 	token := this.GetString("Token")
 	source, _ := this.GetInt("Source")
+	miniSource := this.GetString("MiniSource")
 	if uniqueCode == "" {
 		br.Msg = "参数错误"
 		br.ErrMsg = "参数错误,uniqueCode is empty"
@@ -55,16 +58,24 @@ func (this *ChartController) ChartInfoDetail() {
 		return
 	}
 	var isCollect bool
-	if source == utils.CHART_SOURCE_DW && token != "" {
-		tmpIsCollect, err := dwmini.GetMyChartIsCollect(token, uniqueCode)
-		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取收藏状态失败,Err:" + err.Error()
-			return
+	if miniSource != "" {
+		auth := this.Ctx.Request.Header.Get("Authorization")
+		param := facade.BaseRequest{
+			Auth:       auth,
+			UniqueCode: uniqueCode,
+		}
+		isCollect = facade.FacadeClient.Deal(param).IsCollect(facade.GetInstance(miniSource))
+	} else {
+		if source == utils.CHART_SOURCE_DW && token != "" {
+			tmpIsCollect, err := dwmini.GetMyChartIsCollect(token, uniqueCode)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取收藏状态失败,Err:" + err.Error()
+				return
+			}
+			isCollect = tmpIsCollect
 		}
-		isCollect = tmpIsCollect
 	}
-
 	//判断是否有缓存
 	if utils.Re == nil {
 		if utils.Re == nil && utils.Rc.IsExist(key) {
@@ -258,6 +269,50 @@ func (this *ChartController) ChartInfoRefresh() {
 	br.Msg = "刷新成功"
 }
 
+// MiniBookMark
+// @Title 小程序收藏/取消收藏通用接口
+// @Description 小程序收藏/取消收藏通用接口
+// @Param	request	body models.ChartCollectReq true "type json string"
+// @Success Ret=200 取消收藏成功
+// @router /mini/bookMark [post]
+func (this *ChartController) MiniBookMark() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req requestDTO.ChartCollectReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,Err:" + err.Error()
+		return
+	}
+	if req.UniqueCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,UniqueCode is empty"
+		return
+	}
+	if req.Source == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,Source is empty"
+		return
+	}
+	auth := this.Ctx.Request.Header.Get("Authorization")
+	param := facade.BaseRequest{
+		Auth:       auth,
+		UniqueCode: req.UniqueCode,
+	}
+	action, err := facade.FacadeClient.Deal(param).HandleAction(req.Action, facade.GetInstance(req.Source))
+	if err != nil {
+		br.Msg = action + "失败"
+		br.ErrMsg = action + "失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = action + "成功"
+}
+
 // CollectCancel
 // @Title 东吴小程序图表取消收藏接口
 // @Description 东吴小程序图表取消收藏接口

+ 54 - 0
controllers/eta_forum_chart.go

@@ -0,0 +1,54 @@
+package controllers
+
+import (
+	"eta/eta_chart_lib/models"
+	"eta/eta_chart_lib/services/eta_forum"
+)
+
+type EtaForumChartController struct {
+	BaseCommonController
+}
+
+// CommonChartInfoDetailFromUniqueCode
+// @Title 根据编码获取图表详情
+// @Description 根据编码获取图表详情接口
+// @Param   UniqueCode   query   int  true       "图表唯一编码,如果是管理后台访问,传固定字符串:7c69b590249049942070ae9dcd5bf6dc"
+// @Param   IsCache   query   bool  true       "是否走缓存,默认false"
+// @Success 200 {object} data_manage.ChartInfoDetailFromUniqueCodeResp
+// @router /chart/common/detail [get]
+func (this *EtaForumChartController) CommonChartInfoDetailFromUniqueCode() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	uniqueCode := this.GetString("UniqueCode")
+	if uniqueCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,uniqueCode is empty"
+		return
+	}
+
+	resp := new(models.ChartInfoDetailResp)
+	//是否走缓存
+	isCache, _ := this.GetBool("IsCache")
+	forumResp, err, _ := eta_forum.GeChartFromUniqueCode(uniqueCode, isCache)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表信息失败, Err: " + err.Error()
+		return
+	}
+	chartInfo := forumResp.ChartInfo
+	resp.ChartInfo = chartInfo
+	resp.DataResp = forumResp.DataResp
+	resp.EdbInfoList = forumResp.EdbInfoList
+	resp.XDataList = forumResp.XDataList
+	resp.YDataList = forumResp.YDataList
+	resp.WaterMark = forumResp.WaterMark
+	resp.IsAuth = true
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 55 - 0
controllers/excel_info.go

@@ -43,6 +43,9 @@ func (this *ExcelInfoController) GetTableDetail() {
 		return
 	}
 	fromScene, _ := this.GetInt("FromScene", 0)
+	referencedId, _ := this.GetInt("ReferencedId", 0)
+	uuid := this.GetString("Uuid")
+
 	key := utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + uniqueCode
 	resp := new(response.ExcelTableDetailResp)
 	switch fromScene {
@@ -181,6 +184,49 @@ func (this *ExcelInfoController) GetTableDetail() {
 		}
 		resp.ExcelSource = strings.Join(sourceNameList, ",")
 		resp.ExcelSourceEn = strings.Join(sourceNameEnList, ",")
+	case utils.BALANCE_TABLE:
+		var result request.MixedTableReq
+		err = json.Unmarshal([]byte(excelInfo.Content), &result)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
+			return
+		}
+		newResult, tmpErr, tmpErrMsg := excel2.GetMixedTableCellData(result, this.Lang)
+		if tmpErr != nil {
+			br.Msg = "获取失败"
+			if tmpErrMsg != `` {
+				br.Msg = tmpErrMsg
+			}
+			br.ErrMsg = "获取最新的数据失败,Err:" + tmpErr.Error()
+			return
+		}
+		tableData, err = excel.GetTableDataByMixedTableData(newResult, true, excelInfo.ExcelInfoId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "转换成table失败,Err:" + err.Error()
+			return
+		}
+		edbInfoIds := make([]int, 0)
+		edbInfoIdExist := make(map[int]bool)
+		if len(newResult) > 0 {
+			for _, t := range newResult {
+				for _, v := range t {
+					if v.EdbInfoId > 0 && !edbInfoIdExist[v.EdbInfoId] {
+						edbInfoIdExist[v.EdbInfoId] = true
+						edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+					}
+				}
+			}
+		}
+		sourceNameList, sourceNameEnList, err := data.GetEdbSourceByEdbInfoIdListForExcel(edbInfoIds)
+		if err != nil {
+			br.Msg = "自定义表格数据获取失败"
+			br.ErrMsg = "自定义表格数据获取失败,Err:" + err.Error()
+			return
+		}
+		resp.ExcelSource = strings.Join(sourceNameList, ",")
+		resp.ExcelSourceEn = strings.Join(sourceNameEnList, ",")
 	}
 
 	tableData = excel.HandleTableCell(tableData)
@@ -214,6 +260,14 @@ func (this *ExcelInfoController) GetTableDetail() {
 		}
 	}
 
+	// 获取表格引用
+	reference, err := models.GetReferencedExcelConfig(referencedId, fromScene, uniqueCode, uuid)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取表格引用失败,Err:" + err.Error()
+		return
+	}
+
 	resp.TableInfo = tableData
 	resp.Source = excelInfo.Source
 	resp.ExcelType = excelInfo.ExcelType
@@ -222,6 +276,7 @@ func (this *ExcelInfoController) GetTableDetail() {
 	resp.UniqueCode = excelInfo.UniqueCode
 	resp.Config = config
 	resp.SourcesFrom = excelInfo.SourcesFrom
+	resp.ReferencedExcelConfig = reference
 
 	if utils.Re == nil {
 		data, _ := json.Marshal(resp)

+ 146 - 0
facade/instance/ht_mini_facade.go

@@ -0,0 +1,146 @@
+package instance
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_chart_lib/facade"
+	"eta/eta_chart_lib/models"
+	"eta/eta_chart_lib/utils"
+	"fmt"
+)
+
+const (
+	bookMarkUrl      = "user/bookMark"
+	unBookMarkUrl    = "user/unBookMark"
+	checkBookMarkUrl = "user/checkBookMark"
+	target           = "ht"
+)
+
+type HTCollectionReq struct {
+	UniqueCode string `json:"uniqueCode"`
+}
+type HTMiniFacade struct {
+	facade.BaseMiniFacade
+}
+type HTResponse struct {
+	Ret     int
+	Msg     string
+	Data    interface{} `json:"data"`
+	ErrMsg  string
+	ErrCode int
+	Success bool
+}
+type HTRequest struct {
+	facade.BaseRequest
+	ChartInfoId int
+	ChartName   string
+	ChartImage  string
+	SourceType  string
+	SourceId    int
+}
+
+func dealChartInfo(baseReq facade.BaseRequest) (request HTRequest, err error) {
+	chartInfo, err := models.GetChartInfoByUniqueCode(baseReq.UniqueCode)
+	if err != nil {
+		utils.FileLog.Error("收藏失败,获取图表信息失败:%v", err.Error())
+		return
+	}
+	request = HTRequest{
+		BaseRequest: baseReq,
+		ChartImage:  chartInfo.ChartImage,
+		ChartInfoId: chartInfo.ChartInfoId,
+		ChartName:   chartInfo.ChartName,
+		SourceType:  "chart",
+		SourceId:    chartInfo.ChartInfoId,
+	}
+	return
+}
+func parseResult(resp string) (response HTResponse, err error) {
+	err = json.Unmarshal([]byte(resp), &response)
+	if err != nil {
+		utils.FileLog.Error("收藏失败,解析应答失败:%v,应答结果:%s", err.Error(), resp)
+	}
+	if !response.Success {
+		utils.FileLog.Error("收藏失败,应答结果:%d[%s]", response.ErrCode, response.ErrMsg)
+		err = errors.New(response.ErrMsg)
+	}
+	return
+}
+func (ht *HTMiniFacade) Collect(req facade.BaseRequest) (err error) {
+	param, err := dealChartInfo(req)
+	if err != nil {
+		utils.FileLog.Error("收藏失败,获取图表信息失败:%v", err.Error())
+		return err
+	}
+	url, err := generateUrl(bookMarkUrl)
+	if err != nil {
+		return
+	}
+	resp, err := ht.Post(url, param, req.Auth)
+	if err != nil {
+		utils.FileLog.Error("收藏失败,err:%v,resp:%v", err, resp)
+		return
+	}
+	_, err = parseResult(resp)
+	return
+}
+func (ht *HTMiniFacade) UnCollect(req facade.BaseRequest) (err error) {
+	param, err := dealChartInfo(req)
+	if err != nil {
+		utils.FileLog.Error("收藏失败,获取图表信息失败:%v", err.Error())
+		return err
+	}
+	url, err := generateUrl(unBookMarkUrl)
+	if err != nil {
+		return
+	}
+	resp, err := ht.Post(url, param, req.Auth)
+	if err != nil {
+		utils.FileLog.Error("取消收藏失败,err:%v,resp:%v", err, resp)
+		return
+	}
+	_, err = parseResult(resp)
+	return
+}
+func generateUrl(path string) (url string, err error) {
+	configPath := utils.GetMiniUrl(target)
+	if configPath == "" {
+		utils.FileLog.Error("获取mini接口地址失败", err)
+		err = errors.New("获取mini接口地址失败")
+		return
+	}
+	url = fmt.Sprintf("%s%s", configPath, path)
+	return
+}
+func (ht *HTMiniFacade) IsCollect(req facade.BaseRequest) bool {
+	param, err := dealChartInfo(req)
+	if err != nil {
+		utils.FileLog.Error("获取是否收藏失败,获取图表信息失败:%v", err.Error())
+		return false
+	}
+	url, err := generateUrl(checkBookMarkUrl)
+	if err != nil {
+		return false
+	}
+	resp, err := ht.Post(url, param, req.Auth)
+	if err != nil {
+		utils.FileLog.Error("获取是否收藏失败,err:%v,resp:%v", err, resp)
+		return false
+	}
+	response, err := parseResult(resp)
+	if err != nil {
+		utils.FileLog.Error("获取是否收藏失败,解析应答失败:%v,应答结果:%s", err, resp)
+		return false
+	}
+	var resMap = response.Data.(map[string]interface{})
+	bookMarked := resMap["isBookMarked"]
+	if bookMarked == nil {
+		return false
+	}
+	return bookMarked.(bool)
+}
+func init() {
+	facade.RegisterMiniFacade(target, &HTMiniFacade{
+		BaseMiniFacade: facade.FacadeClient,
+	})
+}

+ 234 - 0
facade/mini_facde.go

@@ -0,0 +1,234 @@
+package facade
+
+import (
+	"context"
+	"encoding/json"
+	"errors"
+	"eta/eta_chart_lib/utils"
+	"fmt"
+	"io"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+)
+
+var (
+	once          sync.Once
+	miniFacadeMap = make(map[string]ChartCollect)
+
+	FacadeClient = BaseMiniFacade{
+		client: DefaultClient(),
+	}
+)
+
+const (
+	bookMark   = "bookMark"
+	unBookMark = "unBookMark"
+)
+
+func GetInstance(name string) ChartCollect {
+	return miniFacadeMap[name]
+}
+
+type ChartCollect interface {
+	Collect(data BaseRequest) (err error)
+	UnCollect(data BaseRequest) (err error)
+	IsCollect(data BaseRequest) bool
+}
+
+type BaseRequest struct {
+	Auth       string `json:"auth"`
+	UniqueCode string `json:"uniqueCode"`
+}
+
+func (bm *BaseMiniFacade) GetData() interface{} {
+	return bm.data
+}
+
+func (bm *BaseMiniFacade) Post(url string, data interface{}, auth string) (result string, err error) {
+	resp, err := bm.client.Post(url, data, auth)
+	if err != nil {
+		return
+	}
+	respBody, respErr := io.ReadAll(resp.Body)
+	if respErr != nil {
+		utils.FileLog.Error("读取body失败,err:%v", err)
+		return
+	}
+	result = string(respBody)
+	return
+}
+func (bm *BaseMiniFacade) Deal(data BaseRequest) *BaseMiniFacade {
+	bm.data = data
+	return bm
+}
+func (bm *BaseMiniFacade) HandleAction(action string, handler ChartCollect) (actionMsg string, err error) {
+	if handler == nil {
+		return "", errors.New("不支持的操作类型")
+	}
+	switch action {
+	case bookMark:
+		err = handler.Collect(bm.data)
+		actionMsg = "收藏"
+	case unBookMark:
+		err = handler.UnCollect(bm.data)
+		actionMsg = "取消收藏"
+	default:
+		err = errors.New("不支持的操作")
+	}
+	return
+}
+
+func (bm *BaseMiniFacade) IsCollect(handler ChartCollect) bool {
+	return handler.IsCollect(bm.data)
+}
+
+type BaseMiniFacade struct {
+	client *HttpClient
+	data   BaseRequest //返回参数
+}
+
+type HttpClient struct {
+	*http.Client
+	maxRetries     int
+	retryDelayFunc RetryDelayFunc
+}
+
+// NewClient 构造函数,其中 delayFunc 参数是可选的
+func NewClient(timeout time.Duration, maxRetries int, delayFunc ...RetryDelayFunc) *HttpClient {
+	var df RetryDelayFunc
+	if len(delayFunc) > 0 {
+		df = delayFunc[0]
+	} else {
+		df = defaultRetryDelayFunc
+	}
+	return &HttpClient{
+		Client:         &http.Client{Timeout: timeout},
+		maxRetries:     maxRetries,
+		retryDelayFunc: df,
+	}
+}
+
+func DefaultClient() *HttpClient {
+	return NewClient(time.Second*10, 3)
+}
+func defaultRetryDelayFunc(attempt int) time.Duration {
+	delay := time.Duration(attempt) * time.Second
+	if attempt > 0 {
+		delay *= 2
+	}
+	return delay
+}
+
+type RetryDelayFunc func(attempt int) time.Duration
+
+func retryErr(err error) bool {
+	return errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled)
+}
+
+// DoWithRetry 发送带有重试机制的HTTP请求,允许用户自定义重试延迟逻辑
+func (hc *HttpClient) DoWithRetry(ctx context.Context, req *http.Request) (resp *http.Response, err error) {
+	attempt := 0
+	for {
+		resp, err = hc.Do(req.WithContext(ctx))
+		if err != nil && retryErr(err) {
+			if attempt >= hc.maxRetries {
+
+				return nil, fmt.Errorf("请求失败: %w", err)
+			}
+			attempt++
+			delay := hc.retryDelayFunc(attempt)
+			time.Sleep(delay)
+			continue
+		}
+		return
+	}
+}
+
+func (hc *HttpClient) Post(url string, data interface{}, auth string) (resp *http.Response, err error) {
+	dataStr, err := json.Marshal(data)
+	if err != nil {
+		utils.FileLog.Error("请求data json序列化失败,err:" + err.Error())
+	}
+	body := io.NopCloser(strings.NewReader(string(dataStr)))
+	req, err := http.NewRequest(http.MethodPost, url, body)
+	req.Header.Set("Content-Type", "application/json")
+	req.Header.Set("Authorization", auth)
+	if err != nil {
+		utils.FileLog.Error("创建POST请求失败: %v", err.Error())
+	}
+	resp, err = hc.DoWithRetry(req.Context(), req)
+	if err == nil {
+		code := resp.StatusCode
+		if code != 200 {
+			utils.FileLog.Error("请求错误应答,状态码:%d", code)
+			errMsg := fmt.Sprintf("请求状态码异常,StatusCode:[%d]", code)
+			respBody, respErr := io.ReadAll(resp.Body)
+			if respErr != nil {
+				utils.FileLog.Error("读取body失败,err:%v", err)
+				err = errors.New(errMsg)
+				return
+			}
+			utils.FileLog.Error("请求错误应答,body:%s", string(respBody))
+			errMsg = fmt.Sprintf("%s,body:%s", errMsg, string(respBody))
+			err = errors.New(errMsg)
+			return
+		}
+	} else {
+		utils.FileLog.Error("未知的应答错误,获取第三方授权信息失败", err.Error())
+	}
+	return
+}
+func (hc *HttpClient) PostWithAuth(url string, data interface{}, token string) (resp *http.Response, err error) {
+	dataStr, err := json.Marshal(data)
+	if err != nil {
+		utils.FileLog.Error("请求data json序列化失败,err:" + err.Error())
+	}
+	body := io.NopCloser(strings.NewReader(string(dataStr)))
+	req, err := http.NewRequest(http.MethodPost, url, body)
+	req.Header.Set("Content-Type", "application/json")
+	req.Header.Set("Authorization", token)
+	if err != nil {
+		utils.FileLog.Error("创建POST请求失败: %v", err)
+	}
+	resp, err = hc.DoWithRetry(req.Context(), req)
+	code := resp.StatusCode
+	if code != 200 {
+		utils.FileLog.Error("请求错误应答,状态码:%d", code)
+		errMsg := fmt.Sprintf("请求状态码异常,StatusCode:[%d]", code)
+		respBody, respErr := io.ReadAll(resp.Body)
+		if respErr != nil {
+			utils.FileLog.Error("读取body失败,err:%v", err)
+			err = errors.New(errMsg)
+			return
+		}
+		utils.FileLog.Error("请求错误应答,body:%s", string(respBody))
+		errMsg = fmt.Sprintf("%s,body:%s", errMsg, string(respBody))
+		err = errors.New(errMsg)
+		return
+	}
+	return
+}
+func (hc *HttpClient) Get(url string) (resp *http.Response, err error) {
+	req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
+	if err != nil {
+		utils.FileLog.Error("创建请求失败: %v", err)
+	}
+	resp, err = hc.DoWithRetry(req.Context(), req)
+	return
+}
+
+func RegisterMiniFacade(name string, facade ChartCollect) {
+	if facade == nil {
+		panic("实例不存在,无法注册")
+	}
+	if _, ok := miniFacadeMap[name]; ok {
+		utils.FileLog.Error("请勿重复注册小程序插件:" + name)
+	}
+	miniFacadeMap[name] = facade
+}
+
+func init() {
+
+}

+ 3 - 3
main.go

@@ -2,16 +2,16 @@ package main
 
 import (
 	"eta/eta_chart_lib/controllers"
+	_ "eta/eta_chart_lib/facade/instance"
 	_ "eta/eta_chart_lib/routers"
 	"eta/eta_chart_lib/services/alarm_msg"
 	"eta/eta_chart_lib/utils"
 	"fmt"
-	"runtime"
-	"time"
-
 	"github.com/beego/beego/v2/adapter/logs"
 	beego "github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web/context"
+	"runtime"
+	"time"
 )
 
 func main() {

+ 1 - 0
models/chart.go

@@ -289,6 +289,7 @@ type ChartInfoDetailResp struct {
 	DataResp             interface{}      `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
 	WaterMark            string           `description:"水印"`
 	IsCollect            bool             `description:"是否收藏"`
+	IsAuth               bool             `description:"是否授权"`
 }
 
 // XData 商品价格曲线的的x轴数据

+ 29 - 0
models/referenced_excel_config.go

@@ -0,0 +1,29 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ReferencedExcelConfig struct {
+	ReferencedExcelConfigId int       `orm:"column(referenced_excel_config_id);pk;auto" ` // excel表格配置id
+	UniqueCode              string    // 表格唯一编码
+	ReferencedId            int       // 被引用的id,报告就是报告id,pptId
+	FromScene               int       // 引用类型 1智能研报 2研报列表 3英文研报 4PPT 5英文ppt
+	Uuid                    string    // 引用唯一标识
+	WidthList               string    // 宽度数组
+	HeightList              string    // 高度数组
+	OpUserId                int       // 当前编辑操作的用户id
+	OpUserName              string    // 当前编辑的用户名称(冗余字段,避免查表)
+	CreateTime              time.Time // 创建时间
+	Content                 string    // 内容
+	ModifyTime              time.Time // 修改时间
+}
+
+// getByCode
+func GetReferencedExcelConfig(referencedId, fromScene int, uniqueCode, uuid string) (item ReferencedExcelConfig, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM referenced_excel_config WHERE referenced_id = ? AND from_scene = ? AND unique_code = ? AND uuid = ? `
+	err = o.Raw(sql, referencedId, fromScene, uniqueCode, uuid).QueryRow(&item)
+	return
+}

+ 8 - 0
models/request/mini.go

@@ -0,0 +1,8 @@
+package request
+
+type ChartCollectReq struct {
+	UniqueCode string `json:"uniqueCode"`
+	Source     string `json:"source"`
+	Action     string `json:"action"`
+	ExtraInfo  string `json:"extraInfo"` //通用额外信息传输需要的扩展信息
+}

+ 1 - 0
models/request/mixed_table.go

@@ -169,6 +169,7 @@ type MixCellShowStyle struct {
 	BackgroundColor string      `description:"背景颜色值,#RRG" json:"background-color"`
 	Width           float64     `description:"单元格宽度" json:"width"`
 	Align           string      `description:"对齐方式:left|center|right" json:"align"`
+	FontSize        string      `description:"字体大小" json:"font-size"`
 }
 
 type DateDataBeforeAfterReq struct {

+ 11 - 10
models/response/excel_info.go

@@ -10,16 +10,17 @@ import (
 // ExcelTableDetailResp  excel表格详情
 type ExcelTableDetailResp struct {
 	//ChartInfo   *ChartInfo
-	UniqueCode    string `description:"表格唯一code"`
-	Source        int    `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
-	ExcelType     int    `description:"表格类型,1:指标列,2:日期列,默认:1"`
-	ExcelImage    string `description:"表格截图"`
-	ExcelName     string `description:"表格名称"`
-	SourcesFrom   string `description:"图表来源"`
-	ExcelSource   string `description:"表格来源str"`
-	ExcelSourceEn string `description:"表格来源(英文)"`
-	TableInfo     excel.TableData
-	Config        ExcelTableDetailConfigResp
+	UniqueCode            string `description:"表格唯一code"`
+	Source                int    `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType             int    `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelImage            string `description:"表格截图"`
+	ExcelName             string `description:"表格名称"`
+	SourcesFrom           string `description:"图表来源"`
+	ExcelSource           string `description:"表格来源str"`
+	ExcelSourceEn         string `description:"表格来源(英文)"`
+	TableInfo             excel.TableData
+	Config                ExcelTableDetailConfigResp
+	ReferencedExcelConfig models.ReferencedExcelConfig `description:"表格引用信息"`
 }
 
 // ExcelTableDetailConfigResp

+ 18 - 0
routers/commentsRouter.go

@@ -70,6 +70,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ChartController"],
+        beego.ControllerComments{
+            Method: "MiniBookMark",
+            Router: `/mini/bookMark`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ChartController"] = append(beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ChartController"],
         beego.ControllerComments{
             Method: "ChartInfoRefresh",
@@ -79,6 +88,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:EtaForumChartController"] = append(beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:EtaForumChartController"],
+        beego.ControllerComments{
+            Method: "CommonChartInfoDetailFromUniqueCode",
+            Router: `/chart/common/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_chart_lib/controllers:ExcelInfoController"],
         beego.ControllerComments{
             Method: "GetTableDetail",

+ 5 - 0
routers/router.go

@@ -34,6 +34,11 @@ func init() {
 				&controllers.ExcelInfoController{},
 			),
 		),
+		web.NSNamespace("/eta_forum",
+			web.NSInclude(
+				&controllers.EtaForumChartController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 14 - 0
services/data/chart_info.go

@@ -614,6 +614,7 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 				return
 			}
 
+			nowYear := time.Now().Year()
 			newDataList := make([]*models.EdbDataList, 0)
 			for _, v := range dataList {
 				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
@@ -621,6 +622,10 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
 					return
 				}
+				dataTimeT, _ := time.Parse(utils.FormatDate, v.DataTime)
+				year := dataTimeT.Year()
+				newItemDate := dataTimeT.AddDate(nowYear-year, 0, 0)
+				v.DataTimestamp = newItemDate.UnixNano() / 1e6
 				if dataTime.Equal(rightAxisDate) || dataTime.After(rightAxisDate) {
 					newDataList = append(newDataList, v)
 				}
@@ -1004,6 +1009,10 @@ func GetSeasonEdbInfoDataListByXDateNong(result *models.EdbDataResult, latestDat
 				Value:         item.Value,
 			}
 			dataTimeT, _ := time.Parse(utils.FormatDate, item.DataTime)
+			year := dataTimeT.Year()
+			newItemDate := dataTimeT.AddDate(nowYear-year, 0, 0)
+			timestamp := newItemDate.UnixNano() / 1e6
+			tmpVal.DataTimestamp = timestamp
 			if (startTmpT.Before(dataTimeT) && endTmpT.After(dataTimeT)) || startTmpT == dataTimeT || endTmpT == dataTimeT {
 				tmpV := &tmpVal
 				if findVal, ok := quarterMap[name]; !ok {
@@ -2798,6 +2807,7 @@ func getEdbDataMapListForSeason(chartInfoId, chartType int, calendar, startDate,
 				return
 			}
 
+			nowYear := time.Now().Year()
 			newList := make([]*models.EdbDataList, 0)
 			for _, v := range newDataList {
 				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
@@ -2805,6 +2815,10 @@ func getEdbDataMapListForSeason(chartInfoId, chartType int, calendar, startDate,
 					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
 					return
 				}
+				dataTimeT, _ := time.Parse(utils.FormatDate, v.DataTime)
+				year := dataTimeT.Year()
+				newItemDate := dataTimeT.AddDate(nowYear-year, 0, 0)
+				v.DataTimestamp = newItemDate.UnixNano() / 1e6
 				if dataTime.Equal(rightAxisDate) || dataTime.After(rightAxisDate) {
 					newList = append(newList, v)
 				}

+ 57 - 0
services/eta_forum/chart_collect.go

@@ -0,0 +1,57 @@
+package eta_forum
+
+import (
+	"eta/eta_chart_lib/models"
+	"eta/eta_chart_lib/services/alarm_msg"
+	"eta/eta_chart_lib/utils"
+	"fmt"
+)
+
+type ChartFromUniqueCodeResp struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        *ChartFromUniqueCodeRespItem
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
+type ChartFromUniqueCodeRespItem struct {
+	ChartInfo   *models.ChartInfo
+	EdbInfoList []*models.ChartEdbInfoMapping
+	XEdbIdValue []int          `description:"柱方图的x轴数据,指标id"`
+	YDataList   []models.YData `description:"柱方图的y轴数据"`
+	XDataList   []models.XData `description:"商品价格曲线的X轴数据"`
+	//BarChartInfo BarChartInfoReq `description:"柱方图的配置"`
+	//CorrelationChartInfo *CorrelationInfo `description:"相关性图表信息"`
+	DataResp  interface{} `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
+	WaterMark string      `description:"水印"`
+}
+
+// GeChartFromUniqueCode 社区中根据唯一编码查询图表
+func GeChartFromUniqueCode(uniqueCode string, isCache bool) (resp ChartFromUniqueCodeRespItem, err error, errMsg string) {
+	defer func() {
+		if err != nil {
+			msg := fmt.Sprintf("查询社区中对用户可见的图表列表 GeChartFromUniqueCode:Err:%v,ErrMsg:%s", err, errMsg)
+			utils.FileLog.Info(msg)
+			go alarm_msg.SendAlarmMsg(msg, 3)
+		}
+	}()
+	urlQuery := fmt.Sprintf("UniqueCode=%s&isCache=%v", uniqueCode, isCache)
+	result, err := getChartFromUniqueCodeLib(urlQuery)
+	if err != nil {
+		errMsg = "查询失败"
+		err = fmt.Errorf("查询失败,Err:" + err.Error())
+		return
+	}
+	if result.Ret != 200 {
+		errMsg = "查询失败"
+		err = fmt.Errorf(result.Msg + result.ErrMsg)
+		return
+	}
+	resp = *result.Data
+
+	return
+}

+ 58 - 0
services/eta_forum/eta_forum_hub_lib.go

@@ -0,0 +1,58 @@
+package eta_forum
+
+import (
+	"encoding/json"
+	"eta/eta_chart_lib/models"
+	"eta/eta_chart_lib/utils"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+)
+
+// getChartFromUniqueCodeLib 根据唯一编码查询图表
+func getChartFromUniqueCodeLib(req string) (resp ChartFromUniqueCodeResp, err error) {
+	_, resultByte, err := get(req, "/v1/chart/common/from_unique_code")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// get
+func get(paramStr string, urlStr string) (resp *models.BaseResponse, result []byte, err error) {
+	if utils.ETA_FORUM_HUB_URL == "" {
+		err = fmt.Errorf("ETA社区桥接服务地址为空")
+		return
+	}
+	urlStr = urlStr + "?" + paramStr
+	getUrl := utils.ETA_FORUM_HUB_URL + urlStr
+	result, err = HttpGet(getUrl)
+	if err != nil {
+		err = fmt.Errorf("调用ETA社区桥接服务接口失败 error:%s", err.Error())
+		return
+	}
+	err = json.Unmarshal(result, &resp)
+	if err != nil {
+		return
+	}
+
+	return
+}
+
+func HttpGet(url string) ([]byte, error) {
+	client := &http.Client{}
+	req, err := http.NewRequest("GET", url, nil)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("authorization", utils.MD5(utils.ETA_FORUM_HUB_NAME_EN+utils.ETA_FORUM_HUB_MD5_KEY))
+	resp, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	utils.FileLog.Debug("HttpPost:" + string(b))
+	return b, err
+}

+ 3 - 0
services/excel/lucky_sheet.go

@@ -1271,6 +1271,9 @@ func GetTableDataByMixedTableData(config [][]request.MixedTableCellDataReq, hide
 						tmp.HorizontalType = 2
 						tmp.Ht = 2
 					}
+					if styleConfig.FontSize != "" {
+						tmp.Fs = styleConfig.FontSize
+					}
 					tmp.Monitor = cell.ShowFormatValue
 					// 如果没有showValue, 则使用value
 					if cell.ShowValue == "" {

+ 23 - 0
utils/config.go

@@ -66,6 +66,13 @@ var (
 	UseMongo bool // 是否使用mongo
 )
 
+// eta_forum_hub ETA社区桥接服务地址
+var (
+	ETA_FORUM_HUB_URL     string
+	ETA_FORUM_HUB_NAME_EN string
+	ETA_FORUM_HUB_MD5_KEY string
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -155,6 +162,13 @@ func init() {
 		logMaxDaysStr := config["log_max_day"]
 		LogMaxDays, _ = strconv.Atoi(logMaxDaysStr)
 	}
+
+	// eta_forum_hub ETA社区桥接服务地址
+	{
+		ETA_FORUM_HUB_URL = config["eta_forum_hub_url"]
+		ETA_FORUM_HUB_NAME_EN = config["eta_forum_hub_name_en"]
+		ETA_FORUM_HUB_MD5_KEY = config["eta_forum_hub_md5_key"]
+	}
 }
 
 // FormatMixTableDataShowValue 格式化自定表格显示数据
@@ -231,3 +245,12 @@ func FormatTableDataShowValue(x float64) (res string) {
 	}
 	return
 }
+
+func GetMiniUrl(source string) string {
+	config, err := web.AppConfig.GetSection(RunMode)
+	if err != nil {
+		panic("配置文件读取错误 " + err.Error())
+	}
+	urlName := fmt.Sprintf("mini_url_%s", source)
+	return config[urlName]
+}

+ 1 - 0
utils/constants.go

@@ -156,6 +156,7 @@ const (
 	TIME_TABLE            = 2 // 时间序列表格
 	MIXED_TABLE           = 3 // 混合表格
 	CUSTOM_ANALYSIS_TABLE = 4 // 自定义分析表格
+	BALANCE_TABLE         = 5 // 平衡表
 )
 
 // 图表样式类型