فهرست منبع

完成布局判断以及部分交互

jwyu 1 سال پیش
والد
کامیت
25820dcd72

+ 1 - 1
index.html

@@ -2,7 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
+    <link rel="icon" type="image/x-icon" href="/fa.ico" id="icon"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>ETA社区</title>
   </head>

+ 4 - 0
package.json

@@ -12,7 +12,11 @@
   "dependencies": {
     "@vueuse/core": "^10.9.0",
     "axios": "^1.6.8",
+    "highcharts": "^11.4.1",
+    "lodash": "^4.17.21",
+    "moment": "^2.30.1",
     "normalize.css": "^8.0.1",
+    "tdesign-icons-vue-next": "^0.2.2",
     "tdesign-vue-next": "^1.9.3",
     "vue": "^3.4.21",
     "vue-router": "4"

+ 20 - 0
pnpm-lock.yaml

@@ -7,9 +7,21 @@ dependencies:
   axios:
     specifier: ^1.6.8
     version: 1.6.8
+  highcharts:
+    specifier: ^11.4.1
+    version: 11.4.1
+  lodash:
+    specifier: ^4.17.21
+    version: 4.17.21
+  moment:
+    specifier: ^2.30.1
+    version: 2.30.1
   normalize.css:
     specifier: ^8.0.1
     version: 8.0.1
+  tdesign-icons-vue-next:
+    specifier: ^0.2.2
+    version: 0.2.2(vue@3.4.21)
   tdesign-vue-next:
     specifier: ^1.9.3
     version: 1.9.3(vue@3.4.21)
@@ -1492,6 +1504,10 @@ packages:
     hasBin: true
     dev: true
 
+  /highcharts@11.4.1:
+    resolution: {integrity: sha512-t+BjB4hba5rNheczCrpyDz8BJrqGdgECHaaXQrgbf1mRdPMPemlOfo08/kTMgZ/Kp/Xfj015atdXpUFdwUU12Q==}
+    dev: false
+
   /htmlparser2@3.10.1:
     resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
     dependencies:
@@ -1921,6 +1937,10 @@ packages:
       ufo: 1.5.3
     dev: true
 
+  /moment@2.30.1:
+    resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
+    dev: false
+
   /ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
     dev: true

BIN
public/fa.ico


+ 0 - 0
public/vite.svg


BIN
src/assets/imgs/404.png


+ 4 - 0
src/assets/svg/tree_close.svg

@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5.23642 8.48046H7.51642V10.7605C7.51642 10.8265 7.57042 10.8805 7.63642 10.8805H8.35642C8.42242 10.8805 8.47642 10.8265 8.47642 10.7605V8.48046H10.7564C10.8224 8.48046 10.8764 8.42646 10.8764 8.36046V7.64046C10.8764 7.57446 10.8224 7.52046 10.7564 7.52046H8.47642V5.24046C8.47642 5.17446 8.42242 5.12046 8.35642 5.12046H7.63642C7.57042 5.12046 7.51642 5.17446 7.51642 5.24046V7.52046H5.23642C5.17042 7.52046 5.11642 7.57446 5.11642 7.64046V8.36046C5.11642 8.42646 5.17042 8.48046 5.23642 8.48046Z" fill="#333333"/>
+<path d="M13.5168 2H2.47677C2.21127 2 1.99677 2.2145 1.99677 2.48V13.52C1.99677 13.7855 2.21127 14 2.47677 14H13.5168C13.7823 14 13.9968 13.7855 13.9968 13.52V2.48C13.9968 2.2145 13.7823 2 13.5168 2ZM12.9168 12.92H3.07677V3.08H12.9168V12.92Z" fill="#333333"/>
+</svg>

+ 4 - 0
src/assets/svg/tree_opend.svg

@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M5 8.5H11V7.5H5V8.5Z" fill="#333333"/>
+<path d="M3 14C2.44772 14 2 13.5523 2 13V3C2 2.44771 2.44772 2 3 2H13C13.5523 2 14 2.44772 14 3L14 13C14 13.5523 13.5523 14 13 14L3 14ZM3 13L13 13L13 3L3 3L3 13Z" fill="#333333"/>
+</svg>

+ 13 - 0
src/hooks/chart/commonFun.js

@@ -0,0 +1,13 @@
+
+
+export function setExtremumDate(dataList){
+  let startDateList = dataList.map(it => it.StartDate)
+                                  .filter(Boolean)
+                                  .sort((a,b)=> new Date(a).getTime() - new Date(b).getTime())
+  //过滤、排序 拿到最新日期
+  let endDateList = dataList.map(it => it.LatestDate)
+                                .filter(Boolean)
+                                .sort((a,b)=> new Date(b).getTime() - new Date(a).getTime())
+
+  return {earliestDate:startDateList[0],latestDate:endDateList[0]}
+}

+ 242 - 0
src/hooks/chart/config.js

@@ -0,0 +1,242 @@
+
+//图模块公共配置
+
+// 图默认配置
+export const chartDefaultOpts={
+    //图表配置
+	chart: {
+		spacingTop: 30,
+		backgroundColor: "rgba(0,0,0,0)",
+	},
+	title: {
+		enabled: false
+	},
+	exporting: {
+		enabled: false,
+	},
+	boost: {
+        useGPUTranslations: true,
+    },
+	//默认颜色配置
+	colors:['#00f','#f00','#999','#000','#7cb5ec', '#90ed7d', '#f7a35c', '#8085e9', 
+	'#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1'],
+	//版权信息
+	credits: {enabled:false},
+	//数据列通用配置
+	plotOptions: {
+		series: {
+			turboThreshold: 0, //不限制数据点个数 
+			boostThreshold:0,
+			animation: {
+				duration: 1000
+			}
+		},
+		areaspline: {
+			lineWidth: 1,
+			stacking: 'normal',
+			marker: {
+					enabled: false,
+			},
+			// fillOpacity: 0.5,
+		},
+		column:{
+			pointPadding: 0.05,
+			stacking: 'normal',
+		},
+		scatter: {
+			turboThreshold: 0,
+			marker: {
+					symbol: 'circle',
+					radius: 5,
+					states: {
+							hover: {
+									enabled: true,
+							}
+					}
+			},
+			states: {
+				hover: {
+					marker: {
+						enabled: true
+					}
+				}
+			}
+		}
+	},
+	//范围选择器
+	rangeSelector: {
+		enabled: false,
+		selected: 2,
+	},
+	//悬浮提示框
+	tooltip: {
+		split: false,
+		shared: true,
+		dateTimeLabelFormats: {
+			// 时间格式化字符
+			day: '%Y/%m/%d',
+			week: "%Y/%m",
+			month: '%Y/%m',
+			year: '%Y/%m',
+		},
+		xDateFormat:'%Y/%m/%d',
+		className:'chart-tooltips-box'
+		// formatter:function(e){
+		// 	return `<p>${this.x}</p><p>aaa</p>`
+		// 	// return e
+		// }
+		// outside: true,
+		// valueDecimals: 4,
+	},
+	//图例
+	legend: {
+		enabled: true,
+		verticalAlign: 'top',
+		margin:3,
+		// layout: 'vertical'
+	},
+	//滚动条
+	scrollbar: {
+		enabled: false,
+	},
+	//导航器
+	navigator: {
+		enabled: false,
+	},
+	//范围选择器
+	rangeSelector: {
+		enabled: false,
+	},
+	xAxis: {
+		tickPosition: 'inside',
+		lineColor: '#bfbfbf',
+    	tickColor: '#bfbfbf',
+		tickLength:5,
+		type: 'datetime',
+		ordinal: false,
+		dateTimeLabelFormats: {
+			day: '%y/%m',
+			week: '%y/%m',
+			month: '%y/%m',
+			year: '%y/%m',
+		}
+		// gridLineWidth:0
+	}
+}
+
+/* 季节性图配置 */
+export const seasonOptions = {
+	//默认颜色配置
+	colors:['#4B0082','#7FFFAA','#FF4500','#808000','#EEE8AA','#849EC1','#8A4294','#578B5A','#FDA8C7','#53B3FF','#999999','#000000','#FFDF0C','#FF0000','#0033FF'],
+	yAxis: {
+		lineWidth: 1,
+		lineColor: '#bfbfbf',
+		tickColor: '#bfbfbf',
+		offset: 0,
+		opposite: false,
+		reversed: false,
+		visible: true,
+		gridLineWidth: 0,
+		tickWidth: 1,
+		tickLength:5,
+		tickPosition: 'inside',
+		endOnTick: false,
+		startOnTick: false,
+		showLastLabel: true, //显示最后刻度值
+		tickPixelInterval: 50
+	}
+}
+
+// 散点x轴
+export const scatterXAxis = {
+    tickPosition: 'inside',
+    lineColor: '#bfbfbf',
+    tickColor: '#bfbfbf',
+    tickLength:5,
+    ordinal: false,
+    type: 'linear',
+}
+
+// 基础y轴配置
+export const basicYAxis = {
+    tickWidth: 1,
+    tickLength: 5,
+    lineWidth: 1,
+    lineColor: '#bfbfbf',
+    tickColor: '#bfbfbf',
+    // offset: 0,
+    visible: true,
+    gridLineWidth: 0,
+    tickPosition: 'inside',
+    endOnTick: false,
+    startOnTick: false,
+    showLastLabel: true,
+    tickPixelInterval: 50,
+}
+
+//基础x轴配置
+export const basicXAxis={
+    tickPosition: 'inside',
+    lineColor: '#bfbfbf',
+    tickColor: '#bfbfbf',
+    tickLength:5,
+    type: 'datetime',
+    ordinal: false,
+    dateTimeLabelFormats: {
+        day: '%y/%m',
+        week: '%y/%m',
+        month: '%y/%m',
+        year: '%y/%m',
+    },
+    xDateFormat:'%Y-%m-%d'
+}
+
+//领先频度对应英文
+export const leadUnitEnMap={
+	'年': 'Y',
+    '季': 'Q',
+    '月': 'M',
+    '周': 'W',
+    '天': 'D',
+}
+
+//相关性图表单位英文Map
+export const relevanceUnitEnMap={
+	'年': 'Year',
+    '季': 'Season',
+    '月': 'Month',
+    '周': 'Week',
+    '天': 'Day',
+}
+
+//图表年份筛选项
+export const yearSelectOpt = [
+	{
+		name: '15年至今',
+		value: 3,
+	},
+	// {
+	// 	name: '18年至今',
+	// 	value: 7,
+	// },
+	// {
+	// 	name: '19年至今',
+	// 	value: 8,
+	// },
+	{
+		name: '20年至今',
+		value: 9,
+	},
+	{
+		name: '21年至今',
+		value: 4,
+	},
+	{
+		name: '22年至今',
+		value: 11
+	},
+]
+
+// 拥有相同配置的图表类型集合
+export const sameOptionType=[1,3,4,5,6]
+

+ 240 - 0
src/hooks/chart/highcahrts-zh_CN.js

@@ -0,0 +1,240 @@
+/**
+ * Highcharts-zh_CN ES6 版本 plugins v1.2.1 (2020-07-29)
+ *
+ * (c) 2020 Jianshu Technology Co.,LTD (https://jianshukeji.com)
+ *
+ * Author : john@jianshukeji.com, Blue Monkey
+ *
+ * License: Creative Commons Attribution (CC)
+ */
+
+export default (H) => {
+  let protocol = window.location.protocol;
+
+  if (!/^http(s)?:&/.test(protocol)) {
+    protocol = 'http:';
+  }
+
+  let defaultOptionsZhCn = {
+    lang: {
+      // Highcharts
+      contextButtonTitle: '图表导出菜单',
+      decimalPoint: '.',
+      downloadJPEG: '下载 JPEG 图片',
+      downloadPDF: '下载 PDF 文件',
+      downloadPNG: '下载 PNG 文件',
+      downloadSVG: '下载 SVG 文件',
+      downloadXLS: '下载 XLS 文件',
+      drillUpText: '◁ 返回 {series.name}',
+      exitFullscreen: '退出全屏',
+      exportData: {
+        categoryDatetimeHeader: '时间',
+        categoryHeader: '类别',
+      },
+      openInCloud: '在 Highcharts Cloud 中打开',
+      invalidDate: '无效的时间',
+      loading: '加载中...',
+      months: [
+        '一月',
+        '二月',
+        '三月',
+        '四月',
+        '五月',
+        '六月',
+        '七月',
+        '八月',
+        '九月',
+        '十月',
+        '十一月',
+        '十二月',
+      ],
+      navigation: {
+        popup: {
+          addButton: '新增',
+          arrowLine: '直线',
+          arrowRay: '射线',
+          arrowSegment: '线段',
+          background: '背景',
+          backgroundColor: '背景颜色',
+          backgroundColors: '背景颜色',
+          borderColor: '边框颜色',
+          borderRadius: '圆角',
+          borderWidth: '边框大小',
+          circle: '圆',
+          color: '颜色',
+          connector: '连接',
+          crooked3: 'Crooked 3 line',
+          crooked5: 'Crooked 5 line',
+          crosshairX: '竖直准星线',
+          crosshairY: '水平准星线',
+          editButton: '编辑',
+          elliott3: 'Elliott 3 line',
+          elliott5: 'Elliott 5 line',
+          fibonacci: '斐波纳契',
+          fill: '填充颜色',
+          flags: '标志',
+          fontSize: '字体大小',
+          format: '文本',
+          height: '高度',
+          horizontalLine: '水平线',
+          infinityLine: '无限线',
+          innerBackground: '内背景',
+          label: '文字标签',
+          labelOptions: '文字标签配置',
+          labels: '文字标签',
+          line: '线',
+          lines: '线条',
+          measure: 'Measure',
+          measureX: 'Measure X',
+          measureXY: 'Measure XY',
+          measureY: 'Measure Y',
+          name: '名字',
+          outerBackground: '外背景',
+          padding: '内间距',
+          parallelChannel: '并行通道',
+          pitchfork: '杈子',
+          ray: '射线',
+          rectangle: '矩形',
+          removeButton: '删除',
+          saveButton: '保存',
+          segment: '段落',
+          series: '数据列',
+          shapeOptions: '图形配置',
+          shapes: '图形',
+          simpleShapes: '简单图形',
+          stroke: '线条颜色',
+          strokeWidth: '线条粗细',
+          style: '样式',
+          title: '标题',
+          tunnel: '通道',
+          typeOptions: '详情',
+          verticalArrow: '竖直箭头',
+          verticalCounter: '竖直计数器',
+          verticalLabel: '竖直标签',
+          verticalLine: '竖直线',
+          volume: '成交量',
+        },
+      },
+      noData: '暂无数据',
+      numericSymbols: null,
+      printChart: '打印图表',
+      resetZoom: '重置缩放比例',
+      resetZoomTitle: '重置为原始大小',
+      shortMonths: [
+        '一月',
+        '二月',
+        '三月',
+        '四月',
+        '五月',
+        '六月',
+        '七月',
+        '八月',
+        '九月',
+        '十月',
+        '十一月',
+        '十二月',
+      ],
+      thousandsSep: ',',
+      viewData: '查看数据表格',
+      viewFullscreen: '全屏查看',
+      weekdays: [
+        '星期天',
+        '星期一',
+        '星期二',
+        '星期三',
+        '星期四',
+        '星期五',
+        '星期六',
+      ],
+      viewData: '查看数据表格',
+      // Highstock
+      rangeSelectorFrom: '开始时间',
+      rangeSelectorTo: '结束时间',
+      rangeSelectorZoom: '范围',
+
+      // Highmaps
+      zoomIn: '缩小',
+      zoomOut: '放大',
+    },
+
+    global: {
+      // 不使用 UTC时间
+      useUTC: false,
+      timezoneOffset: -8 * 60,
+      canvasToolsURL:
+        protocol + '//cdn.hcharts.cn/highcharts/modules/canvas-tools.js',
+      VMLRadialGradientURL:
+        protocol + +'//cdn.hcharts.cn/highcharts/gfx/vml-radial-gradient.png',
+    },
+
+    exporting: {
+      url: protocol + '//export.highcharts.com.cn',
+    },
+
+    credits: {
+      text: 'Highcharts.com.cn',
+      href: 'https://www.highcharts.com.cn',
+    },
+
+    /**
+     * Highstock
+     */
+
+    rangeSelector: {
+      inputDateFormat: '%Y-%m-%d',
+      buttons: [
+        {
+          type: 'month',
+          count: 1,
+          text: '月',
+        },
+        {
+          type: 'month',
+          count: 3,
+          text: '季度',
+        },
+        {
+          type: 'month',
+          count: 6,
+          text: '半年',
+        },
+        {
+          type: 'ytd',
+          text: 'YTD',
+        },
+        {
+          type: 'year',
+          count: 1,
+          text: '年',
+        },
+        {
+          type: 'all',
+          text: '所有',
+        },
+      ],
+    },
+
+    plotOptions: {
+      series: {
+        dataGrouping: {
+          dateTimeLabelFormats: {
+            /* millisecond: [
+              '%Y-%m-%d %H:%M:%S.%L',
+              '%Y-%m-%d %H:%M:%S.%L',
+              ' ~ %H:%M:%S.%L',
+            ],
+            second: ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S', ' ~ %H:%M:%S'],
+            minute: ['%Y-%m-%d %H:%M', '%Y-%m-%d %H:%M', ' ~ %H:%M'],
+            hour: ['%Y-%m-%d %H:%M', '%Y-%m-%d %H:%M', ' ~ %H:%M'], */
+            day: ['%Y/%m/%d', '%Y/%m/%d', ' ~ %Y/%m/%d'],
+            week: ['%Y/%m/%d', '%Y/%m/%d', ' ~ %Y/%m/%d'],
+            month: ['%Y/%m', '%Y/%m', ' ~ %Y/%m'],
+            year: ['%Y', '%Y', ' ~ %Y'],
+          },
+        },
+      },
+    },
+  };
+
+  H.setOptions(defaultOptionsZhCn);
+};

+ 2414 - 0
src/hooks/chart/render.js

@@ -0,0 +1,2414 @@
+// 图渲染逻辑模块
+
+import {ref,nextTick,reactive} from 'vue'
+import {chartDefaultOpts,scatterXAxis,basicYAxis,basicXAxis,leadUnitEnMap,relevanceUnitEnMap} from './config'
+import Highcharts from 'highcharts/highstock';
+import HighchartsFormat from 'highcharts';
+import HighchartsMore from 'highcharts/highcharts-more';
+import HightchartsExport from 'highcharts/modules/exporting';
+import Boost from 'highcharts/modules/boost'
+import HighchartszhCN  from './highcahrts-zh_CN.js'
+import moment from 'moment'
+import _ from 'lodash';
+HighchartszhCN(Highcharts)
+HightchartsExport(Highcharts)
+HighchartsMore(Highcharts)
+Boost(Highcharts)
+
+
+/**
+ * 渲染图方法
+ * @param data 图详情数据
+ * @param renderId 图表在dom中的id
+ * @param lang 图表显示为中文/英文 默认 zh中文 en英文
+ * @param changeLangIsCheck 切换中英文时 是否要校验
+ * @param showChartTitle 是否显示图表标题 默认true
+ */
+let ChartIns=null//图表实例
+let chartData=ref(null)//图的所有数据
+let LangType=ref('zh')//当前图表显示的语言版本
+let RenderDomId=ref('')//图表渲染的domid
+let options=ref(null)//渲染图的数据
+const axisLimitState = reactive({//极值数据
+    leftIndex:-1,//左侧上下限对应下标
+    rightIndex: -1, //右侧上下限对应下标
+    rightTwoIndex: -1,//右2上下限对应下标
+
+    hasLeftAxis:false,
+    hasRightAxis:false,
+    hasRightTwoAxis:false,
+    hasXAxis:false,
+    leftMin:0,
+    leftMax:0,
+    rightMin:0,
+    rightMax:0,
+    rightTwoMin:0,
+    rightTwoMax:0,
+    xMin:0,
+    xMax:0,
+})
+//仅ETA图库内图表需要使用自定义上下限
+let useSalfLimit = false
+let isUseSelfLimit = ref(false)
+
+export function useChartRender(){
+    return {
+        options,
+        axisLimitState,
+        chartRender,
+        setLimitData,
+        isUseSelfLimit
+    }
+}
+
+/**备注一下 越多越乱 
+ * @params
+ * Source 1 ; chartType只在source:1用到 1曲线 2季节 3面积 4堆积柱 5散点 6组合 7柱形 10截面散点 11雷达图
+ * 2 商品价格
+ * 3 相关性
+ * 4 滚动相关性
+ * 5 商品利润
+ * 6 拟合方程
+ * 7 统计特征/标准差
+ * 8 统计特征/百分位
+ * 9 统计特征/频率
+ * 10 跨品种分析
+ */
+export function chartRender({data,renderId,lang='zh',changeLangIsCheck,showChartTitle=true}){
+    // 初始化掉极值数据
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    axisLimitState.hasLeftAxis=false
+    axisLimitState.hasRightAxis=false
+    axisLimitState.hasRightTwoAxis=false
+    axisLimitState.hasXAxis=false
+
+    //使用自定义上下限时,不需要初始化极值
+    if(!isUseSelfLimit.value){
+        axisLimitState.leftMin=0
+        axisLimitState.leftMax=0
+        axisLimitState.rightMin=0
+        axisLimitState.rightMax=0
+        axisLimitState.rightTwoMin=0
+        axisLimitState.rightTwoMax=0
+        axisLimitState.xMin=0
+        axisLimitState.xMax=0
+    }
+    
+
+
+    let chartOpt={}
+    LangType.value=lang
+    RenderDomId.value=renderId
+    chartData.value=data
+    useSalfLimit = ['/myETA/chartdetail','/chartETA/chartdetail'].includes(window.location.pathname)
+    if(data.ChartInfo.Source===1){
+        const chartSetMap = {
+            1: setSplineOpt,
+            2: setSeasonOpt,
+            3: setStackOrCombinChart,
+            4: setStackOrCombinChart,
+            5: setScatterOptions,
+            6: setStackOrCombinChart,
+            7: initBarData,
+            10: setSectionScatterChart,
+            11: setRadarChart
+        };
+        chartOpt=chartSetMap[data.ChartInfo.ChartType](data)
+    }else if([2,5].includes(data.ChartInfo.Source)){//商品价格曲线
+        chartOpt=initCommodityData(data);
+    }else if([3].includes(data.ChartInfo.Source)){//相关性 滚动相关性
+        chartOpt=initRelevanceChart(data);
+    }else if([4,6,7,8].includes(data.ChartInfo.Source)){//滚动相关性 拟合方程 标准差 百分比
+        chartOpt=setSplineOpt(data);
+    }else if([9].includes(data.ChartInfo.Source)){//统计频率
+        chartOpt=setStatisticFrequency(data);
+    }else if(data.ChartInfo.Source===10) {
+
+        /* 历史数据chartInfo里上下限全是空 兼容下历史数据不崩 */
+        axisLimitState.hasLeftAxis=true
+        axisLimitState.leftMin=data.ChartInfo.LeftMin?Number(data.ChartInfo.LeftMin):Number(data.DataResp.YMinValue)
+        axisLimitState.leftMax=data.ChartInfo.LeftMax?Number(data.ChartInfo.LeftMax):Number(data.DataResp.YMaxValue)
+        
+        axisLimitState.hasXAxis=true
+        axisLimitState.xMin= data.ChartInfo.XMin?Number(data.ChartInfo.XMin):Number(data.DataResp.XMinValue)
+        axisLimitState.xMax=data.ChartInfo.XMax?Number(data.ChartInfo.XMax):Number(data.DataResp.XMaxValue),
+
+        chartOpt = setCrossVarietyChart(data)
+    }
+
+    /* 
+        eta1.4.1增加了主题色
+		仍然以defaultOpts为最底层配置 外层配置在这里统一设置了如legend chart背景色
+			x轴y轴系列等样式还是需要在具体的options中单独设置
+    */
+
+    let themeOptions = setThemeOptions();
+
+    options.value={...chartDefaultOpts,...themeOptions, ...chartOpt}
+    // 设置图标题
+    setChartTitle(showChartTitle)
+    // 设置语言
+    setChartLang(changeLangIsCheck)
+    
+    //stock不支持线形图只支持时间图 某些用chart
+    let is_linear = chartOpt.series 
+    ? chartOpt.series.some(_ => _.chartType === 'linear')
+    : false ;
+
+    is_linear ?ChartIns=Highcharts.chart(RenderDomId.value,options.value) : ChartIns=Highcharts.stockChart(RenderDomId.value,options.value);
+
+    return ChartIns
+}
+
+//主题色一些外层公用配置  目前只有绘图区和legend和colors
+function setThemeOptions() {
+    if(!chartData.value.ChartInfo.ChartThemeStyle) return {}
+
+    let chartTheme = JSON.parse(chartData.value.ChartInfo.ChartThemeStyle)		
+    return {
+        legend: {
+            ...chartDefaultOpts.legend,
+            ...chartTheme.legendOptions
+        },
+        chart: {
+            ...chartDefaultOpts.chart,
+            ...chartTheme.drawOption
+        },
+        colors: chartTheme.colorsOptions
+    }
+}
+
+ /* 处理轴的标识线结构 在指定轴位置上拼接标识线 
+    0:右轴 1:左轴 2:右2轴 x轴固定3
+    axisType表示x轴类型 处理时间轴的值 datetime/null 
+*/
+function setAxisPlotLines(axis,axisType) {
+    const { MarkersLines,ChartType } = chartData.value.ChartInfo;
+    const { EdbInfoList } = chartData.value;
+    if(!MarkersLines) return []
+
+    let markerLines = JSON.parse(MarkersLines);
+
+    let arr = markerLines.filter(_ => _.isShow&&_.axis===axis)
+    let plotLines = arr.map(_ => {
+        //是否是x时间轴
+        let isXDateAxis = axis===3&&axisType==='datetime';
+        let markerValue;
+        if(isXDateAxis) {
+            //季节图x轴额外拼个年份
+            let nowYear = ChartType===2 ? new Date(EdbInfoList[0].DataList[1].DataList
+                [0].DataTimestamp).getFullYear() : '';
+            markerValue = ChartType===2 
+                ? new Date(`${nowYear}-${_.value}`).getTime()
+                : new Date(_.value).getTime()
+        }else {
+            markerValue = Number(_.value)
+        }
+
+        return { 
+        value: markerValue,
+        dashStyle: _.dashStyle,
+        width: Number(_.lineWidth),
+        color: _.color,
+        label: {
+            text: _.text||'',
+            verticalAlign: _.textPosition,
+            style: {
+            color: _.textColor,
+            fontSize: _.textFontSize
+            }
+        }
+        }
+    })
+    return plotLines
+}
+
+/* 处理标识区拼接 axisType表示x轴类型处理时间轴的值 datetime/null */
+function setAxisPlotAreas(axis,axisType) {
+    const { MarkersAreas,ChartType } = chartData.value.ChartInfo;
+    const { EdbInfoList } = chartData.value;
+    if(!MarkersAreas) return []
+
+    let markerAreas = JSON.parse(MarkersAreas);
+
+    let arr = markerAreas.filter(_ => _.isShow&&_.axis===axis)
+    let plotBands = arr.map(_ => {
+        //是否是x时间轴
+        let isXDateAxis = axis===3&&axisType==='datetime';
+        let fromMarkerValue,toMarkerValue;
+        if(isXDateAxis) {
+            //季节图x轴额外拼个年份
+            let nowYear = ChartType===2 ? new Date(EdbInfoList[0].DataList[1].DataList
+                [0].DataTimestamp).getFullYear() : '';
+            fromMarkerValue = ChartType===2 
+                ? new Date(`${nowYear}-${_.fromValue}`).getTime()
+                : new Date(_.fromValue).getTime()
+
+            toMarkerValue = ChartType===2 
+                ? new Date(`${nowYear}-${_.toValue}`).getTime()
+                : new Date(_.toValue).getTime()
+        }else {
+            fromMarkerValue = Number(_.fromValue);
+            toMarkerValue = Number(_.toValue);
+        }
+
+        //默认label有些偏移 重新归正下
+        let positionMapValue = {
+            'top': 12,
+            'middle': 0,
+            'bottom': -10
+        }
+
+        return { 
+            from: fromMarkerValue,
+            to: toMarkerValue,
+            color: _.color,
+            label: {
+                text: _.text||'',
+                verticalAlign: _.textPosition,
+                y: positionMapValue[_.textPosition],
+                style: {
+                    color: _.textColor,
+                    fontSize: _.textFontSize
+                }
+            }
+        }
+    })
+
+    return plotBands
+}
+
+
+/* 预测配置 分区 */
+function getPredictParams ({LatestDate,PredictChartColor}) {
+    return {
+    zoneAxis: 'x',
+    zones: [{
+        value: new Date(LatestDate).getTime()+1
+    }, {
+        dashStyle: 'ShortDot',
+        color: PredictChartColor
+    }]
+    }
+}
+
+/* 季节图预测数据 年份=分割点年份做分割 年份>分割点年份全为预测 */
+function getSeasonPredictParams (timestamp){
+    return timestamp
+    ? {
+        zoneAxis: 'x',
+        zones: [{
+            value: new Date(timestamp).getTime()+1
+        }, {
+            dashStyle: 'ShortDot',
+        }]
+        }
+    : {}
+}
+
+// 查询范围为1年内 x轴显示为月/日 否则默认年/月
+function xTimeDiffer(minTime,maxTime){
+    //年限差
+    let year_differ=moment(maxTime).diff(moment(minTime),'years',true)
+    // console.log('年限差',year_differ)
+    if (year_differ<=1) {
+        // console.log('true');
+        return true;
+    } else {
+        // console.log('false');
+        return false;
+    }
+}
+
+/* 拼接动态的指标名称小标签 */
+function concatDynamicTag(item,lang){
+    const { IsAxis,IsOrder,EdbInfoType,LeadValue,LeadUnit }  = item;
+    // IsAxis左轴1 右轴0 2右2轴 
+    //IsOrder正序false 逆序true 
+      //IsOrder正序false 逆序true 
+    //IsOrder正序false 逆序true 
+    //EdbInfoType是否是领先指标
+    const axisLabelMap =lang=='zh'? {
+        0: '右轴',
+        2: '右2轴'
+    }:{
+        0: 'RHS',
+        2: '2-RHS'
+    }
+    const orderLabelMap =lang=='zh'? {
+        1: '逆序'
+    }:{
+        1: 'REV'
+    }
+    const edbInfoMap =lang=='zh'? {
+        0: '领先'
+    }:{
+        0: 'Lead'
+    }
+
+    //英文领先单位转换
+    const leadUnit = lang==='zh' ? LeadUnit : leadUnitEnMap[LeadUnit];
+
+    let axis_tag = axisLabelMap[IsAxis] || '';
+      //逆序拼接
+    let order_tag = orderLabelMap[Number(IsOrder)] ? `${axis_tag ? ',': ''}${orderLabelMap[Number(IsOrder)]}` : ''
+      //领先拼接
+    let edb_tag = edbInfoMap[EdbInfoType] ? `${(axis_tag||order_tag) ? ',' : '' }${edbInfoMap[EdbInfoType]}${LeadValue}${leadUnit}` : '';
+
+    let dynamic_tag = (axis_tag || order_tag || edb_tag) ? `(${axis_tag}${order_tag}${edb_tag})` : '';
+
+    return dynamic_tag
+}
+/* 拼接数据列动态name */
+function setDyncmicSerieName (item,dynamic_arr,lang='zh') {
+    let temName =''
+    /* if(lang=='zh'){
+        temName= dynamic_arr.length > 1
+            ? `${item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}`
+            : `${item.EdbName}${concatDynamicTag(item,'zh')}`
+    }else{
+        temName=item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:''
+    } */
+    const temNameEn = item.EdbNameEn?`${item.EdbNameEn}${concatDynamicTag(item,'en')}`:''
+    const temNameZh = dynamic_arr.length > 1
+    ? `${item.EdbAliasName||item.EdbName}(${item.SourceName})${concatDynamicTag(item,'zh')}`
+    : `${item.EdbAliasName||item.EdbName}${concatDynamicTag(item,'zh')}`
+    temName = lang=='zh'?temNameZh:temNameEn?temNameEn:temNameZh
+
+    if(temName.length>20){
+        let temArr=[]
+        for(let i=0;i<temName.length/20;i++){
+            temArr.push(temName.slice(i*20,i*20+20))
+        }
+        temName=temArr.join('<br>')
+    }
+
+    return temName
+}
+
+/* 指标顺序调整  IsAxis: 0右轴 1左轴 2右2*/
+function changeEdbOrder (data){
+    // 左轴指标
+    let left_edbs = data.filter(_ => _.IsAxis===1);
+    //右轴指标
+    let right_edbs = data.filter(_ => !_.IsAxis);
+    // 右2轴指标
+    let right_two_edbs = data.filter(_ => _.IsAxis === 2);
+    // 按 左 右 右2顺序排列
+    return [left_edbs,right_edbs,right_two_edbs].flat(Infinity);
+}
+
+//检查图表英文配置是否完整
+function checkChartEnData(){
+    let result = true
+    //图表名称:this.chartInfo.ChartNameEn
+    if(!chartData.value.ChartInfo.ChartNameEn){
+      result = false
+    }
+    //指标名称:this.dataList[].EdbNameEn
+    //指标单位:this.dataList[].UnitEn
+    chartData.value.EdbInfoList.forEach(item=>{
+      if(!item.EdbNameEn){
+        result = false
+      }
+      if(chartData.value.ChartInfo.ChartType!==10&&item.Unit&&!item.UnitEn){
+        result = false
+      }
+    })
+    return result   
+}
+
+// 设置图表显示的语言
+function setChartLang(changeLangIsCheck){
+    if(changeLangIsCheck&&!checkChartEnData()) return
+    const {ChartType,Source} = chartData.value.ChartInfo
+    if(Source==1){
+        // 散点图
+        if(ChartType == 5){
+            options.value.yAxis.title.text = LangType.value == 'zh' ? options.value.yAxis.title.textZh : options.value.yAxis.title.textEn;
+            options.value.yAxis.title.style = LangType.value == 'zh' ? {} : options.value.yAxis.title.styleEn;
+            options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn
+            options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn;
+            options.value.series.forEach(item => {
+                item.name = LangType.value == 'zh' ? item.nameZh : item.nameEn;
+            });
+            options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterZh : options.value.tooltip.formatterEn;
+        }else{
+            // 单位
+            options.value.yAxis.forEach(item => {
+                item.title.text = LangType.value == 'zh' ? item.title.textZh : item.title.textEn;
+                item.title.style = LangType.value == 'zh' ? {} : (item.title.styleEn || {})
+            });
+            // 图例  名称
+            if(ChartType != 2){
+                // 季节图 不更改图例名称
+                options.value.series.forEach(item => {
+                    item.name = LangType.value == 'zh' 
+                        ? item.nameZh 
+                        : (item.nameEn!='无英文名称'?item.nameEn:`<span style="color:#999">${item.nameEn}</span>`)
+                });
+            }
+            //截面散点 x轴标题
+            if(ChartType === 10){
+                options.value.xAxis.title.text = LangType.value == 'zh' ? options.value.xAxis.title.textZh : options.value.xAxis.title.textEn;
+                options.value.xAxis.title.style = LangType.value == 'zh' ? {} : options.value.xAxis.title.styleEn;
+                options.value.tooltip.formatter = LangType.value == 'zh' ? options.value.tooltip.formatterCh : options.value.tooltip.formatterEn;
+                options.value.series.forEach(item => {
+                    if(!item.linkedTo) {
+                        item.data.forEach(point => {
+                            point.dataLabels.format = LangType.value == 'zh' ? point.dataLabels.formatZh : (point.dataLabels.formatEn||'无英文标签');
+                            point.dataLabels.color = (LangType.value==='en' && !point.dataLabels.formatEn) ? '#999' : '#333'
+                        })
+                    }
+                });
+            } 
+
+            //柱形图额外设置x轴中英文
+            if([7,11].includes(ChartType)){
+                //x轴
+                options.value.xAxis.categories = chartData.value.XEdbIdValue.map(_ => LangType.value == 'zh' 
+                ? chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName
+                : chartData.value.EdbInfoList.find(edb => edb.EdbInfoId===_).EdbNameEn)
+            }
+        }
+    }
+    if([2,3,4].includes(Source)){
+        options.value.yAxis.forEach(item => {
+            item.title.text =  LangType.value == 'zh' ? item.title.textZh: item.title.textEn
+        });
+        //图例
+        options.value.series.forEach(item => {
+            item.name = LangType.value == 'en' ?item.nameEn : item.nameZh 
+        });
+        //tooltip
+        options.value.tooltip.formatter = LangType.value == 'en'?options.value.tooltip.formatterEn:options.value.tooltip.formatterZh
+        //x轴
+        if(Source==2){
+            options.value.xAxis.categories = commodityXData.value.map(_ => {
+                LangType.value == 'en'?_.NameEn:_.Name
+            });
+        }
+        if([3].includes(Source)){
+            options.value.xAxis.title.text=LangType.value == 'en'?options.value.xAxis.title.textEn:options.value.xAxis.title.textZh
+        }
+    }
+}
+
+// 设置图标题
+function setChartTitle(showChartTitle){
+    if(showChartTitle){
+        const ChartInfo=chartData.value.ChartInfo
+        options.value.title.textZh=ChartInfo.ChartName
+        options.value.title.textEn=ChartInfo.ChartNameEn
+        options.value.title.text=LangType.value == 'zh' ?options.value.title.textZh:options.value.title.textEn||options.value.title.textZh
+    }else{
+        options.value.title.text=''
+    }
+}
+
+//统计频率图
+function setStatisticFrequency(e){
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+     /* 主题样式*/
+    const chartTheme =  e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
+
+    const { DataList,LeftMaxValue,LeftMinValue,RightMaxValue,RightMinValue } = e.DataResp;
+
+    const xAxis = {
+        ...scatterXAxis,
+        tickWidth: 1,
+        labels: {
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        }
+    }
+
+    //y和系列
+    let yAxis = [],series = [];
+    DataList.forEach((item,index) => {
+      let y_item = {
+        ...basicYAxis,
+        title: {
+            text: item.Unit,
+            textCh:item.Unit,// 中文
+            textEn:item.UnitEn||item.Unit,
+            align: 'high',
+            rotation: 0,
+            y: -15,
+            reserveSpace: false,
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        labels: {
+            style:{
+              ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        opposite: item.IsAxis===1?false:true,
+        min: index===0? Number(LeftMinValue):Number(RightMinValue),
+        max: index===0? Number(LeftMaxValue):Number(RightMaxValue),
+        tickWidth: 1,
+      }
+
+      let series_item = {
+        data: item.Value.map(_ =>[_.X,_.Y]),
+        dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+        type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+        yAxis: index,
+        name: item.Name,
+        nameZh: item.Name,
+        nameEn: item.NameEn||item.Name,
+        color: item.Color,
+        lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth)||3,
+        chartType: 'linear',
+        zIndex:1
+      }
+
+      series.push(series_item);
+      yAxis.push(y_item)
+    })
+
+    let tooltip = {
+        formatter: function() {
+          let xList = DataList[0].Value.map(_ =>_.X);
+          let step = xList[1]-xList[0];
+          let data_interval = `[${this.x},${this.x+step}]`;
+
+          let str=`<b>${ data_interval }</b>`;
+          this.points.forEach(item => {
+            str += `<br><span style="color:${item.color}">\u25CF</span>${item.series.name}: ${item.y}%<br>`
+          })
+          return str
+        },
+        shared: true
+    }
+
+    return {
+        title: {
+            text:''
+          },
+        tooltip,
+        series,
+        yAxis,
+        xAxis
+    }
+}
+
+//曲线图
+function setSplineOpt(e){
+    //其他Source也会用到曲线图,这里需要兼容
+    const isETASource = e.ChartInfo.Source===1
+    const data=[4,6,7,8].includes(e.ChartInfo.Source)?[e.DataResp]:e.EdbInfoList
+    let series=[]
+    let yAxis=[]
+    let xAxis = {}
+
+    let temYLeftArr=[]
+    let temYRightArr=[]
+    let temYRightTwoArr = []
+    let temYLeftIndex=data.findIndex((item) => item.IsAxis===1)
+    let temYRightIndex=data.findIndex((item) => !item.IsAxis)
+    let temYRightTwoIndex = data.findIndex((item) => item.IsAxis===2)
+    axisLimitState.leftIndex=temYLeftIndex
+    axisLimitState.rightIndex=temYRightIndex
+    axisLimitState.rightTwoIndex=temYRightTwoIndex
+
+     /* 主题样式*/
+    const chartTheme =  e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
+
+
+    let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间
+
+    //有右二轴时排个序 按照左 右 右2的顺序
+    let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data;
+
+    newData.forEach((item,index)=>{
+
+         //轴位置值相同的下标
+        let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis);
+
+        let dynamic_title = item.EdbName;
+        let dynamic_arr = newData.filter(
+          (item) => dynamic_title === item.EdbName
+        );
+        //处理数据列name
+        let temName= setDyncmicSerieName(item,dynamic_arr,'zh')  
+        let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en')  
+        //预测指标配置
+        let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {};
+
+        let seriesItemObj={
+            data:[],
+            dataGrouping:{
+                enabled:false
+            },
+            type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+            dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+            yAxis:index,
+            name:temName,
+            nameZh:temName,
+            nameEn:temNameEN,
+            color: item.ChartColor,
+            lineWidth: Number(item.ChartWidth),
+            visible:true,
+            LatestDate:item.LatestDate,
+            LatestValue:item.LatestValue,
+            ...predict_params
+        }
+        item.DataList = item.DataList || [];
+        for (let i of item.DataList) {
+          seriesItemObj.data.push([i.DataTimestamp, i.Value]);
+        }
+        series.push(seriesItemObj)
+        
+
+        // 设置y轴
+        if(item.IsAxis){
+            temYLeftArr.push(item)
+        }else{
+            temYRightArr.push(item)
+        }
+
+        //获取上下限
+        let minLimit = 0,maxLimit = 0
+        if(!useSalfLimit||!isETASource){
+            minLimit = item.MinData
+            maxLimit = item.MaxData
+        }
+        if(useSalfLimit&&isETASource){
+            const limitMap = {
+                0:['rightMin','rightMax'],
+                1:['leftMin','leftMax'],
+                2:['rightTwoMin','rightTwoMax']
+            }
+            if(limitMap[item.IsAxis]){
+                minLimit = axisLimitState[`${limitMap[item.IsAxis][0]}`]||0
+                maxLimit = axisLimitState[`${limitMap[item.IsAxis][1]}`]||0
+            }
+        }
+        const textZh = item.ConvertUnit||item.Unit
+        const textEn = item.ConvertEnUnit||item.UnitEn||item.ConvertUnit||item.Unit
+        let yItem={
+            ...basicYAxis,
+            IsAxis:item.IsAxis,
+            labels: {
+                formatter: function (ctx) {
+                    return sameSideIndex !== index ? '' : ctx.value;
+                },
+                align: 'center',
+                x: [0,2].includes(item.IsAxis) ? 5 : -5,
+                style:{
+                    ...chartTheme&&chartTheme.yAxisOptions.style
+                },
+            },
+            tickWidth: sameSideIndex !== index ? 0 : 1,
+            title: {
+                text:  sameSideIndex !== index ? '' : `${textZh}`,
+                textZh:textZh,//中文单位
+                textEn:textZh?textEn:'',//英文单位,但如果无中文单位则不显示
+                align: 'high',
+                rotation: 0,
+                y: -15,
+                x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0,
+                textAlign: item.IsAxis===1 ? 'left' : 'right',
+                reserveSpace: false,
+                style:{
+                    ...chartTheme&&chartTheme.yAxisOptions.style
+                },
+            },
+            opposite: [0,2].includes(item.IsAxis),
+            reversed: item.IsOrder,
+            min: Number(minLimit),
+            max: Number(maxLimit),
+            visible: sameSideIndex === index,
+            chartEdbInfo:item,//指标数据用于在保存时读取指标数据
+            plotBands: setAxisPlotAreas(item.IsAxis),
+            plotLines: setAxisPlotLines(item.IsAxis)
+        }
+        yAxis.push(yItem)
+        
+        if(item.DataList.length>0){
+            minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp)
+            minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
+        }
+        
+    })
+    
+    
+    // 设置x轴
+    // 找出所有指标的最大和最小时间 分成6段
+    let minTime=Math.min.apply(null,minAndMaxTimeTemArr)
+    let maxTime=Math.max.apply(null,minAndMaxTimeTemArr)
+
+
+    const isLessThanOneYear = xTimeDiffer(minTime,maxTime)
+    xAxis={
+        ...basicXAxis,
+        labels: {
+            formatter: function (ctx) {
+                return isLessThanOneYear
+                ? HighchartsFormat.dateFormat('%m/%d', ctx.value)
+                : HighchartsFormat.dateFormat('%y/%m', ctx.value);
+            },
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        tickInterval:((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30,
+        plotBands: setAxisPlotAreas(3,'datetime'),
+        plotLines: setAxisPlotLines(3,'datetime')
+    }
+    
+
+    yAxis.forEach(item=>{
+        if(item.IsAxis===1){//左轴
+            axisLimitState.hasLeftAxis=true
+            if(!useSalfLimit||!isETASource){
+                axisLimitState.leftMin=data[temYLeftIndex].MinData
+                axisLimitState.leftMax=data[temYLeftIndex].MaxData
+
+                item.min=data[temYLeftIndex].MinData
+                item.max=data[temYLeftIndex].MaxData
+            }
+        }else if (item.IsAxis===2){ // 右2轴
+            axisLimitState.hasRightTwoAxis=true
+            if(!useSalfLimit||!isETASource){
+                axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData
+                axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData
+
+                item.min=data[temYRightTwoIndex].MinData
+                item.max=data[temYRightTwoIndex].MaxData
+            }
+        }else{
+            axisLimitState.hasRightAxis=true
+            if(!useSalfLimit||!isETASource){
+                axisLimitState.rightMin=data[temYRightIndex].MinData
+                axisLimitState.rightMax=data[temYRightIndex].MaxData
+
+                item.min=data[temYRightIndex].MinData
+                item.max=data[temYRightIndex].MaxData
+            }
+        }
+    })
+
+    return {
+        series,
+        xAxis:[xAxis],
+        yAxis,
+        rangeSelector:{ enabled: false}
+    }
+}
+
+
+//季节图
+function setSeasonOpt(e){
+    axisLimitState.leftIndex=0
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+     /* 主题样式*/
+    const chartTheme =  e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
+
+    let chartData={}
+    const data=e.EdbInfoList[0]
+    const calendarType=e.ChartInfo.Calendar||'公历'
+
+    const colorsArr=chartTheme&&chartTheme.colorsOptions.reverse();
+    let series=[],yAxis=[]
+    //农历默认选中一年数据并隐藏按钮  公历显示全部数据
+    // let rangeSelector={}
+    // 农历数据需要去除第一项  农历和公历处理逻辑一样
+    const chartDataHandle=calendarType === '农历'?
+                        data.DataList.filter((item, index) => index > 0):
+                        data.DataList
+    // if(calendarType==='公历'){
+        chartDataHandle.forEach((item,index)=>{
+             //预测指标配置
+            let predict_params =  data.EdbInfoCategoryType === 1 ? getSeasonPredictParams(item.CuttingDataTimestamp) : {};
+
+            let seriesItem={
+                data:[],
+                dataGrouping:{
+                    enabled:false
+                },
+                type: (chartTheme&&chartTheme.lineOptions.lineType) || data.ChartStyle,
+                dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+                yAxis:0,
+                name:item.ChartLegend,
+                lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+                color:colorsArr.slice(-chartDataHandle.length)[index],                
+                visible:true,
+                ...predict_params
+            }
+            item.DataList=item.DataList||[]
+            for(let i of item.DataList){
+                seriesItem.data.push([i.DataTimestamp, i.Value])
+            }
+            series.push(seriesItem)
+        })
+    
+    //获取上下限
+    let minLimit = 0,maxLimit = 0
+    //非ETA图库不使用自定义上下限
+    if(!useSalfLimit){
+        minLimit = data.MinData
+        maxLimit = data.MaxData
+    }else{
+        minLimit = axisLimitState.leftMin||0
+        maxLimit = axisLimitState.leftMax||0
+    }
+    const textZh = data.ConvertUnit||data.Unit
+    const textEn = data.ConvertEnUnit||data.UnitEn||data.ConvertUnit||data.Unit
+    yAxis=[{
+        IsAxis:data.IsAxis,
+        labels: {
+            align: 'center',
+            y:5,
+            style: {
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            }
+        },
+        title: {
+            text:  `${textZh}`,
+            textZh:textZh, // 中文
+            // 中文不存在,无论英文有无都显示空
+            textEn:textZh?textEn||'英文单位':'', // 英文
+            align: 'high',
+            rotation: 0,
+            y: -5,
+            x: 0,
+            textAlign: 'left',
+            reserveSpace: false,
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        max: Number(maxLimit),
+        min: Number(minLimit),
+        plotBands: setAxisPlotAreas(1),
+        plotLines: setAxisPlotLines(1),
+        lineWidth: 1,
+        lineColor: '#bfbfbf',
+        tickColor: '#bfbfbf',
+        offset: 0,
+        opposite: false,
+        reversed: false,
+        visible: true,
+        gridLineWidth: 0,
+        tickWidth: 1,
+        tickLength:5,
+        tickPosition: 'inside',
+        endOnTick: false,
+        startOnTick: false,
+        showLastLabel: true, //显示最后刻度值
+        tickPixelInterval: 50,
+        // chartEdbInfo:item//指标数据
+    }]
+
+    chartData.series=series
+    chartData.yAxis=yAxis
+    // chartData.rangeSelector=rangeSelector
+    // 设置坐标轴极值
+    axisLimitState.hasLeftAxis=true
+    if(!useSalfLimit){
+        axisLimitState.leftMin=Number(data.MinData)
+        axisLimitState.leftMax=Number(data.MaxData)
+    }
+    
+
+    // 季节图x轴显示月/日
+    let xAxis={
+        tickPosition: 'inside',
+		lineColor: '#bfbfbf',
+    	tickColor: '#bfbfbf',
+		tickLength:5,
+		type: 'datetime',
+		ordinal: false,
+		dateTimeLabelFormats: {
+			day: '%y/%m',
+			week: '%y/%m',
+			month: '%y/%m',
+			year: '%y/%m',
+		},
+        labels: {
+            formatter: (ctx)=> {
+                return HighchartsFormat.dateFormat('%m/%d', ctx.value)
+            },
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        tickInterval:24*3600*1000*60,//季节图
+        plotBands: setAxisPlotAreas(3,'datetime'),
+        plotLines: setAxisPlotLines(3,'datetime')
+    }
+    
+
+    chartData.xAxis=[xAxis]
+
+    // 季节图提示框显示 月/日
+    chartData.tooltip={
+        split: false,
+        shared: true,
+        dateTimeLabelFormats: {
+          // 时间格式化字符
+          day: '%m/%d',
+          week: '%m/%d',
+          month: '%m/%d',
+          year: '%m/%d',
+        },
+        xDateFormat: '%m/%d',
+    }
+
+    return {
+        ...chartData,
+        // title: {
+		//     enabled: true,
+        //     text:e.ChartInfo.ChartName
+        // },
+        // legend:{
+        //     enabled:true,
+        //     verticalAlign: 'top',
+        //     y:-10,
+        //     x:(10 * data.Unit.length)/2
+        // }
+    }
+}
+
+
+//堆叠图/组合图设置
+//本来和曲线图逻辑基本一致兼容下即可 为了以后便于维护和阅读还是拆开写吧
+function setStackOrCombinChart(e){
+    const data=e.EdbInfoList
+    //图表类型
+    const chartTypeMap = {
+        3: 'areaspline',
+        4: 'column',
+        6: ''
+    };
+    let chartStyle = chartTypeMap[e.ChartInfo.ChartType];
+
+    /* 主题样式*/
+    const chartTheme =  e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
+
+    let series=[]
+    let yAxis=[]
+    let xAxis = {}
+
+    let temYLeftArr=[]
+    let temYRightArr=[]
+    let temYRightTwoArr = []
+    let temYLeftIndex,temYRightIndex,temYRightTwoIndex;
+
+    let minAndMaxTimeTemArr=[]//存放所有指标的最大最小时间
+
+    //有右二轴时排个序 按照左 右 右2的顺序
+    let newData = data.some(_ =>_.IsAxis===2) ? changeEdbOrder(data) : data;
+
+
+    newData.forEach((item,index)=>{
+
+        //轴位置值相同的下标
+        let sameSideIndex = newData.findIndex(i => i.IsAxis === item.IsAxis);
+
+        //堆叠图的yAxis必须一致 数据列所对应的y轴
+        let serie_yIndex = index;
+        if([3,4].includes(e.ChartInfo.ChartType)) {
+            // 类型为堆叠图时公用第一个指标y轴 
+            serie_yIndex =  0;
+        } else if(e.ChartInfo.ChartType ===6 && ['areaspline','column'].includes(item.ChartStyle)) {
+            // 组合图找第一个堆叠柱状或面积的作为公用
+            serie_yIndex = newData.findIndex(i => i.ChartStyle === item.ChartStyle);
+        }
+        //数据对应的y轴是公用轴则配置也共享
+        item.IsAxis = serie_yIndex === index ? item.IsAxis : newData[serie_yIndex].IsAxis;
+        item.IsOrder = serie_yIndex === index ? item.IsOrder : newData[serie_yIndex].IsOrder;
+
+        temYLeftIndex = [3,4].includes(e.ChartInfo.ChartType) 
+            ? (newData[serie_yIndex].IsAxis ? serie_yIndex : -1)
+            : data.findIndex((item) => item.IsAxis===1);
+        temYRightIndex = [3,4].includes(e.ChartInfo.ChartType) 
+            ? (newData[serie_yIndex].IsAxis ? -1 : serie_yIndex)
+            : data.findIndex((item) => !item.IsAxis);
+        temYRightTwoIndex = [3,4].includes(e.ChartInfo.ChartType) 
+            ? -1
+            : data.findIndex((item) => item.IsAxis===2);
+        
+        axisLimitState.leftIndex=temYLeftIndex
+        axisLimitState.rightIndex=temYRightIndex
+        axisLimitState.rightTwoIndex=temYRightTwoIndex
+
+        let dynamic_title = item.EdbName;
+        let dynamic_arr = newData.filter(
+          (item) => dynamic_title === item.EdbName
+        );
+        //处理数据列name
+        let temName= setDyncmicSerieName(item,dynamic_arr,'zh')
+        let temNameEN=setDyncmicSerieName(item,dynamic_arr,'en')  
+
+        //预测指标配置
+        let predict_params = item.EdbInfoCategoryType === 1 ? getPredictParams(item) : {};
+
+        let seriesItemObj={
+            data:[],
+            dataGrouping:{
+                enabled:false
+            },
+            type: chartStyle || item.ChartStyle,
+            yAxis:serie_yIndex,
+            name:temName,
+            nameZh:temName,
+            nameEn:temNameEN,
+            color: item.ChartColor,
+            lineWidth:  Number(item.ChartWidth),
+            fillColor: (e.ChartInfo.ChartType === 3 || (e.ChartInfo.ChartType === 6 && item.ChartStyle === 'areaspline')) ? item.ChartColor : undefined,
+            visible:true,
+            LatestDate:item.LatestDate,
+            LatestValue:item.LatestValue,
+            ...predict_params
+        }
+        item.DataList = item.DataList || [];
+        for (let i of item.DataList) {
+          seriesItemObj.data.push([i.DataTimestamp, i.Value]);
+        }
+        series.push(seriesItemObj)
+        
+        //获取上下限
+        let minLimit = 0,maxLimit = 0
+        //非ETA图库不使用自定义上下限
+        if(!useSalfLimit){
+            minLimit = newData[sameSideIndex].MinData
+            maxLimit = newData[sameSideIndex].MaxData
+        }else{
+            const limitMap = {
+                0:['rightMin','rightMax'],
+                1:['leftMin','leftMax'],
+                2:['rightTwoMin','rightTwoMax']
+            }
+            if(limitMap[item.IsAxis]){
+                minLimit = axisLimitState[`${limitMap[item.IsAxis][0]}`]||0
+                maxLimit = axisLimitState[`${limitMap[item.IsAxis][1]}`]||0
+            }
+        }
+
+        // 设置y轴
+        if(item.IsAxis){
+            temYLeftArr.push(item)
+        }else{
+            temYRightArr.push(item)
+        }
+
+        const textZh = item.ConvertUnit||item.Unit
+        const textEn = item.ConvertEnUnit||item.UnitEn||item.ConvertUnit||item.Unit
+        let yItem={
+            ...basicYAxis,
+            IsAxis:item.IsAxis,
+            labels: {
+                formatter: function (ctx) {
+                    return sameSideIndex !== index ? '' : ctx.value;
+                },
+                align: 'center',
+                x: [0,2].includes(item.IsAxis) ? 5 : -5,
+                style:{
+                    ...chartTheme&&chartTheme.yAxisOptions.style
+                },
+            },
+            title: {
+                // text:  sameSideIndex !== index ? '' : `${item.Unit}`,
+                text: textZh,
+                textZh:textZh, // 中文
+                // 中文不存在,无论英文有无都显示空
+                textEn:textZh?textEn||'英文单位':'', // 英文
+                align: 'high',
+                rotation: 0,
+                y: -15,
+                x: (item.IsAxis===0 && temYRightTwoIndex>-1) ? -newData[temYRightTwoIndex].Unit.length*12 : 0,
+                textAlign: item.IsAxis===1 ? 'left' : 'right',
+                reserveSpace: false,
+                style:{
+                    ...chartTheme&&chartTheme.yAxisOptions.style
+                },
+            },
+            opposite: [0,2].includes(item.IsAxis),
+            reversed: item.IsOrder,
+            min: Number(minLimit),
+            max: Number(maxLimit),
+            tickWidth: sameSideIndex !== index ? 0 : 1,
+            visible: serie_yIndex === index && sameSideIndex ===index,
+            plotBands: setAxisPlotAreas(item.IsAxis),
+            plotLines: setAxisPlotLines(item.IsAxis),
+            chartEdbInfo:item//指标数据用于在保存时读取指标数据
+        }
+        yAxis.push(yItem)
+        
+        if(item.DataList.length>0){
+            minAndMaxTimeTemArr.push(item.DataList[0].DataTimestamp)
+            minAndMaxTimeTemArr.push(item.DataList[item.DataList.length-1].DataTimestamp)
+        }
+        
+    })
+    
+    
+    // 设置x轴
+    // 找出所有指标的最大和最小时间 分成6段
+    let minTime=Math.min.apply(null,minAndMaxTimeTemArr)
+    let maxTime=Math.max.apply(null,minAndMaxTimeTemArr)
+
+    const isLessThanOneYear = xTimeDiffer(minTime,maxTime)
+    xAxis={
+        ...basicXAxis,
+        labels: {
+            formatter: function (ctx) {
+                return isLessThanOneYear
+                ? HighchartsFormat.dateFormat('%m/%d', ctx.value)
+                : HighchartsFormat.dateFormat('%y/%m', ctx.value);
+            },
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        tickInterval:((maxTime-minTime)/6)/(24*3600*1000)>30?(maxTime-minTime)/6:24*3600*1000*30,
+        plotBands: setAxisPlotAreas(3,'datetime'),
+        plotLines: setAxisPlotLines(3,'datetime')
+    }
+    
+    yAxis.forEach(item=>{
+        if(item.IsAxis === 1){//左轴
+            axisLimitState.hasLeftAxis=true
+            if(!useSalfLimit){
+                axisLimitState.leftMin=data[temYLeftIndex].MinData
+                axisLimitState.leftMax=data[temYLeftIndex].MaxData
+
+                item.min=data[temYLeftIndex].MinData
+                item.max=data[temYLeftIndex].MaxData
+            }
+        }else if (item.IsAxis===2){ // 右2轴
+            axisLimitState.hasRightTwoAxis=true
+            if(!useSalfLimit){
+                axisLimitState.rightTwoMin=data[temYRightTwoIndex].MinData
+                axisLimitState.rightTwoMax=data[temYRightTwoIndex].MaxData
+
+                item.min=data[temYRightTwoIndex].MinData
+                item.max=data[temYRightTwoIndex].MaxData
+            }
+            
+        }else{
+            axisLimitState.hasRightAxis=true
+            if(!useSalfLimit){
+                axisLimitState.rightMin=data[temYRightIndex].MinData
+                axisLimitState.rightMax=data[temYRightIndex].MaxData
+
+                item.min=data[temYRightIndex].MinData
+                item.max=data[temYRightIndex].MaxData
+            }
+            
+        }
+    })
+    
+   
+
+    return {
+        series,
+        xAxis:xAxis,
+        yAxis,
+        rangeSelector:{ enabled: false}
+    }
+}
+
+
+/* 散点图 第一个指标值为x轴 第二个指标为y轴*/
+function setScatterOptions(data){
+    axisLimitState.leftIndex=1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    const dataList=data.EdbInfoList
+    const { ChartInfo } = data;
+
+     /* 主题样式*/
+    const chartTheme = ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
+
+    //上下限设置的是y轴,也就是第二个指标的值,改回来
+    axisLimitState.hasLeftAxis=true
+    /* axisLimitState.leftMin=Number(dataList[1].MinData)
+    axisLimitState.leftMax=Number(dataList[1].MaxData)
+
+    axisLimitData.leftMin=Number(dataList[1].MinData)
+    axisLimitData.leftMax=Number(dataList[1].MaxData) */
+
+    // 取2个指标中日期相同的数据
+    const real_data = [];
+    let tmpData_date = {};//用来取点对应的日期
+    let data1 =  _.cloneDeep(dataList)[0].DataList || [];
+    let data2 =  _.cloneDeep(dataList)[1].DataList || [];
+    data1.forEach((_item) => {
+        data2.forEach((_item2) => {
+            if(_item.DataTimestamp === _item2.DataTimestamp) {
+                //日期
+                let itemIndex =_item.Value + "_" +_item2.Value
+                if(tmpData_date[itemIndex]) {
+                    tmpData_date[itemIndex].push( moment(_item.DataTimestamp).format('YYYY/MM/DD'))
+                } else {
+                    tmpData_date[itemIndex] = [moment(_item.DataTimestamp).format('YYYY/MM/DD')]
+                }
+            
+                //值
+                real_data.push({
+                    x: _item.Value,
+                    y: _item2.Value
+                })
+            }
+        })
+    })
+    real_data.sort((x,y) => x-y);
+
+    //悬浮窗 拼接日期 原始指标名称
+    let tooltip = {
+        formatter: function() {
+            return `<strong>${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }</strong><br>
+            ${dataList[0].EdbName}: <span style="font-weight: 600">	${this.x}</span><br>
+            ${dataList[1].EdbName}: <span style="font-weight: 600">	${this.y}</span>
+            `
+        },
+        // 中文
+        formatterCh: function() {
+            return `<strong>${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }</strong><br>
+            ${dataList[0].EdbName}: <span style="font-weight: 600">	${this.x}</span><br>
+            ${dataList[1].EdbName}: <span style="font-weight: 600">	${this.y}</span>
+            `
+        },
+        // 英文
+        formatterEn: function() {
+            let str1 = `${dataList[0].EdbNameEn}`
+            let str2 = `${dataList[1].EdbNameEn}`
+            return `<strong>${ tmpData_date[this.x+'_'+this.y].length > 4 ? tmpData_date[this.x+'_'+this.y].slice(0,4).join()+'...' : tmpData_date[this.x+'_'+this.y].join() }</strong><br>
+            ${str1}: <span style="font-weight: 600">	${this.x}</span><br>
+            ${str2}: <span style="font-weight: 600">	${this.y}</span>
+            `
+        }
+    }
+
+    const { IsOrder,ChartColor } = dataList[0];
+
+    //获取上下限
+    let minLimit = 0,maxLimit = 0
+    if(!useSalfLimit){
+        minLimit = data.ChartInfo.LeftMin||0;
+        maxLimit = data.ChartInfo.LeftMax||0;
+    }else{
+        minLimit = axisLimitState.leftMin||0
+        maxLimit = axisLimitState.leftMax||0
+    }
+    console.log('check limit',minLimit,maxLimit)
+    const textYZh = dataList[1].ConvertUnit||dataList[1].Unit
+    const textYEn = dataList[1].ConvertEnUnit||dataList[1].UnitEn||dataList[1].ConvertUnit||dataList[1].Unit
+    //y轴
+    let yAxis = {
+        title: {
+            text:  `${textYZh}`,
+            textZh:textYZh,
+            textEn:textYZh?textYEn:'',
+            align: 'high',
+            rotation: 0,
+            y: -15,
+            x:0,
+            textAlign: 'left',
+            reserveSpace: false,
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        labels: {
+            formatter: function (ctx) {
+            return ctx.value;
+            },
+            align: 'center',
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        opposite: false,
+        reversed: IsOrder,
+        min: Number(minLimit),
+        max: Number(maxLimit),
+        tickWidth: 1,
+        tickLength: 5,
+        lineWidth: 1,
+        lineColor: '#bfbfbf',
+        tickColor: '#bfbfbf',
+        offset: 0,
+        visible: true,
+        gridLineWidth: 0,
+        tickPosition: 'inside',
+        endOnTick: false,
+        startOnTick: false,
+        showLastLabel: true,
+        tickPixelInterval: 50,
+        plotBands: setAxisPlotAreas(1),
+        plotLines: setAxisPlotLines(1)
+    }
+
+    //数据列
+    let series = {
+        data: [],
+        type: 'scatter',
+        name: `${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`,
+        nameZh:`${ChartInfo.ChartName}${IsOrder ? '(逆序)' : ''}`,
+        nameEn:ChartInfo.ChartNameEn?`${ChartInfo.ChartNameEn}${IsOrder ? '(reverse)' : ''}`:'',
+        color: ChartColor,
+        visible:true,
+        chartType: 'linear',
+        marker: {
+          radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+        },
+    }
+    real_data.forEach(_ => {
+        series.data.push([_.x,_.y])
+    })
+    const textXZh = dataList[0].ConvertUnit||dataList[0].Unit
+    const textXEn = dataList[0].ConvertEnUnit||dataList[0].UnitEn||dataList[0].ConvertUnit||dataList[0].Unit
+    return {
+        title: {
+            text:''
+        },
+        series: [ series ],
+        yAxis,
+        xAxis: {
+            ...scatterXAxis,
+            title: {
+                text:  `${textXZh}`,
+                textZh:textXZh,
+                textEn:textXZh?textXEn:'',
+                align: 'high',
+                rotation: 0,
+                x: 0,
+                offset: 20,
+                style: {
+                    ...chartTheme&&chartTheme.xAxisOptions.style
+                },
+            },
+            labels: {
+                style: {
+                  ...chartTheme&&chartTheme.xAxisOptions.style
+                }
+            },
+        },
+        tooltip
+    }
+}
+
+
+/* 奇怪柱形图 */
+const barDateList = ref([]);//柱形图的绘图数据
+const barXData = ref([]);//柱形图的x轴
+const barEdbData = ref([]);//柱形图的表格数据 只用于取值
+let axisLimitData={}
+/* 奇怪柱状图 和其他逻辑无公用点 依赖数据为单独的数据
+    x轴为指标名称的柱形图 以日期作为series
+*/
+function setBarChart (e){
+    let seriesData = [];
+    const data = _.cloneDeep(barDateList.value);
+
+    /* 主题样式*/
+    const chartTheme =  e.ChartInfo.ChartThemeStyle ? JSON.parse(e.ChartInfo.ChartThemeStyle) : null;
+
+    //x轴
+    let xAxis = {
+        ...scatterXAxis,
+        categories: barXData.value,
+        tickWidth: 1,
+        labels: {
+            style: {
+              ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        }
+    }
+
+    const { leftMin,leftMax } = axisLimitState;
+    // console.log(leftMin,leftMax)
+    //y轴
+    let yAxis = {
+        ...basicYAxis,
+        title: {
+            text:  ``,
+            textZh: '',
+            textEn: '',
+            align: 'high',
+            rotation: 0,
+            y: -15,
+            x:0,
+            textAlign: 'left',
+            reserveSpace: false,
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        labels: {
+            formatter: function (ctx) {
+            let val = ctx.value;
+            return val;
+            },
+            align: 'center',
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        min: Number(leftMin),
+        max: Number(leftMax),
+        opposite: false,
+        tickWidth: 1,
+        plotBands: setAxisPlotAreas(1),
+        plotLines: setAxisPlotLines(1)
+    }
+
+    //数据列
+    data.forEach(item => {
+        let serie_item = {
+            data: item.Value,
+            type: 'column',
+            yAxis: 0,
+            name: item.Name || item.Date,
+            nameZh: item.Name || item.Date,
+            nameEn: item.Date,
+            color: item.Color,
+            chartType: 'linear',              
+            visible:true,
+        };
+        seriesData.push(serie_item)
+    })
+    
+    return {
+        title: {
+            text:''
+        },
+        plotOptions: {
+            column:{
+            stacking: null,
+            },
+        },
+        series: seriesData,
+        yAxis: [ yAxis ],
+        xAxis
+    }
+}
+/* 获取图表详情后赋值柱状图数据 */
+function initBarData(data){
+    const { XEdbIdValue,YDataList,EdbInfoList,ChartInfo } = data;
+
+    let xData = XEdbIdValue.map(_ => EdbInfoList.find(edb => edb.EdbInfoId===_).EdbAliasName)
+    // console.log(xData)
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    barDateList.value = YDataList;
+    barXData.value = xData;
+    barEdbData.value = EdbInfoList;
+
+    axisLimitState.hasLeftAxis=true
+    axisLimitState.leftMin=Number(ChartInfo.LeftMin)
+    axisLimitState.leftMax=Number(ChartInfo.LeftMax)
+
+    return setBarChart(data);
+}
+
+
+/* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/
+const commodityChartData = ref([]);//商品价格图的绘图数据
+const commodityXData = ref([]);//商品价格图的x轴
+const commodityEdbList = ref([]);//商品价格图的表格数据 只用于取值
+/* 商品价格曲线设置 绘图逻辑同奇怪柱形图*/
+const setCommodityChart = (leftMin,leftMax) => {
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    /* 主题样式*/
+    const chartTheme =  chartData.value.ChartInfo.ChartThemeStyle ? JSON.parse(chartData.value.ChartInfo.ChartThemeStyle) : null;
+
+    let seriesData = [];
+    const data = _.cloneDeep(commodityChartData.value);
+    console.log(data);
+
+    //x轴
+    let xAxis = {
+        ...scatterXAxis,
+        categories: commodityXData.value.map(_ => _.Name),
+        tickWidth: 1,
+        labels: {
+            style: {
+              ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        }
+    }
+
+    //y轴
+    let yAxis = {
+        ...basicYAxis,
+        title: {
+            text: commodityEdbList.value[0].Unit,
+            textZh: commodityEdbList.value[0].Unit,
+            textEn: commodityEdbList.value[0].Unit?(commodityEdbList.value[0].UnitEn||'英文单位'):'',
+            align: 'high',
+            rotation: 0,
+            y: -15,
+            textAlign: 'left',
+            reserveSpace: false,
+            style:{
+              ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        labels: {
+            formatter: function (ctx) {
+            let val = ctx.value;
+            return val;
+            },
+            align: 'center',
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        min: Number(leftMin),
+        max: Number(leftMax),
+        opposite: false,
+        tickWidth: 1,
+    }
+
+    //数据列
+    data.forEach(item => {
+        //处理首或/尾全是无效数据的以null填充
+        let filterData = filterInvalidData(item)
+
+        let serie_item = {
+            data: filterData,
+            type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+            dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+            yAxis: 0,
+            name: item.Name,
+            nameZh: item.Name,
+            nameEn: item.NameEn,
+            color: item.Color,
+            chartType: 'linear',
+            lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+            visible: true,
+            marker: {
+                enabled: false
+            }
+        };
+        seriesData.push(serie_item)
+    })
+
+    //tooltip
+    let tooltip = {
+        formatter: function() {
+            const ctx = this;
+            let str = '';
+            ctx.points.forEach(item => {
+                let obj_item = data.find(_ => _.Name === item.series.name);
+                let index = commodityXData.value.findIndex(_ => _.Name === ctx.x);
+                
+                // 合约显示
+                const haveContract=obj_item.XEdbInfoIdList[index]
+                if(haveContract){
+                    // 利润曲线指标名
+                    let edb_name = chartData.value.ChartInfo.Source === 5 
+                        ? (index === 0 ? obj_item.NameList[index] : `${chartData.value.DataResp.ProfitName}(${obj_item.NameList[index]})`)
+                        : commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName;
+                    str+=`<b>${ edb_name }</b>`
+
+                    if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
+                        str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
+                    }else {
+                        str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
+                    }
+
+                }
+            })
+            return str||'无合约'
+        },
+        formatterCh: function() {
+            let str = ''; 
+            this.points.forEach(item => {
+              let obj_item = data.find(_ => _.Name === item.series.name);
+              let index = commodityXData.value.findIndex(_ => _.Name === this.x);
+  
+              str+=`<b>${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbName }</b>`
+  
+              if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
+                str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
+              }else {
+                str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
+              }
+            })
+            return str
+          },
+          formatterEn: function() {
+            let str = ''; 
+            this.points.forEach(item => {
+              let obj_item = data.find(_ => _.NameEn === item.series.name);
+              let index = commodityXData.value.findIndex(_ => _.NameEn === this.x);
+  
+              str+=`<b>${ commodityEdbList.value.find(_ => _.EdbInfoId === obj_item.XEdbInfoIdList[index]).EdbNameEn }</b>`
+  
+              if(!obj_item.NoDataEdbList.includes(obj_item.XEdbInfoIdList[index])) {
+                str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: ${item.y}<br>`
+              }else {
+                str += `<br><span style="color:${item.color}">\u25CF</span>${obj_item.Date}: 无<br>`
+              }
+            })
+            return str
+          },
+        shared: true
+    }
+    // console.log(seriesData);
+    return {
+        title: {
+            text:''
+        },
+        series: seriesData,
+        yAxis: [ yAxis ],
+        xAxis,
+        tooltip
+    }
+};
+/* 处理无效数据为null */
+function filterInvalidData(item){
+    let validateArr = item.XEdbInfoIdList.filter(_ =>!item.NoDataEdbList.includes(_));
+
+    let first_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[0]);
+    let last_index = item.XEdbInfoIdList.findIndex(_ => _ === validateArr[validateArr.length-1]);
+    // console.log('first_index',first_index)
+    // console.log('last_index',last_index)
+
+    let arr = item.Value.map((item,index) => {
+    if(index < first_index || index > last_index) {
+        return null
+    }else {
+        return item
+    }
+    })
+
+    return arr;
+}
+function initCommodityData(data){
+    const { XDataList,YDataList,EdbInfoList,ChartInfo,DataResp } = data;
+
+    commodityEdbList.value = EdbInfoList;
+    commodityChartData.value = ChartInfo.Source===5?DataResp.YDataList:YDataList
+    commodityXData.value = ChartInfo.Source===5?DataResp.XDataList:XDataList
+
+    axisLimitState.hasLeftAxis=true
+    axisLimitState.leftMin=Number(ChartInfo.LeftMin)
+    axisLimitState.leftMax=Number(ChartInfo.LeftMax)
+
+    return setCommodityChart(ChartInfo.LeftMin,ChartInfo.LeftMax);
+}
+
+
+//相关性图表
+function initRelevanceChart(data){
+
+    /* 主题样式*/
+    const chartTheme =  data.ChartInfo.ChartThemeStyle ? JSON.parse(data.ChartInfo.ChartThemeStyle) : null;
+
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+    // 处理X轴
+    let xAxis={
+        categories: data.ChartInfo.Source===3?data.XEdbIdValue:data.DataResp.XDateTimeValue,
+        tickWidth: 1,
+        title: {
+          text: data.ChartInfo.Source===3 ?`期数(${data.CorrelationChartInfo.LeadUnit})` : null,
+          textZh:data.ChartInfo.Source===3 ? `期数(${data.CorrelationChartInfo.LeadUnit})`:null,
+          textEn:data.ChartInfo.Source===3 ? `stage(${relevanceUnitEnMap[data.CorrelationChartInfo.LeadUnit]})`:null,
+          align: 'high',
+          rotation: 0,
+          x: 0,
+          y:10,
+          offset: 20,
+          style: {
+            ...chartTheme&&chartTheme.xAxisOptions.style
+          }
+        },
+        labels: {
+            style: {
+              ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        tickInterval: 1,
+        offset:0,
+        tickmarkPlacement:'on'
+    }
+
+    // 处理Y轴
+    let yAxis={
+        ...basicYAxis,
+        title: {
+          text: '相关性系数',
+          textZh: '相关性系数',
+          textEn: 'Correlation coefficient',
+          align: 'high',
+          rotation: 0,
+          y: -15,
+          textAlign: 'left',
+          reserveSpace: false,
+          style:{
+            ...chartTheme&&chartTheme.yAxisOptions.style
+          },
+        },
+        labels: {
+          formatter: function (ctx) {
+            let val = ctx.value;
+            return val;
+          },
+          align: 'center',
+          style:{
+            ...chartTheme&&chartTheme.yAxisOptions.style
+          },
+        },
+        opposite: false,
+        tickWidth: 1,
+    }
+
+    //处理series
+    let seriesData=[]
+    data.YDataList.forEach(item=>{
+        let serie_item = {
+          data: item.Value,
+          type: (chartTheme&&chartTheme.lineOptions.lineType) || 'spline',
+          dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+          yAxis: 0,
+          name: data.ChartInfo.ChartName,
+          nameZh: data.ChartInfo.ChartName,
+          nameEn: data.ChartInfo.ChartNameEn,
+          color: '#00f',
+          chartType: 'linear',
+          lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 3,
+          visible:true,
+          marker: {
+            enabled: false
+          }
+        };
+        seriesData.push(serie_item)
+    })
+    const { LeadValue,LeadUnit } = data.CorrelationChartInfo;
+    const { Source } = data.ChartInfo;
+
+    let tooltip = {
+        formatter: function() {
+            let str = `<p>相关性系数:${this.y.toFixed(4)}</p><br><p>领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}</p>`
+            return str
+        },
+        formatterCh: function() {
+            let str = `<p>相关性系数:${this.y.toFixed(4)}</p><br><p>领先${ Source===3 ?this.x+'期' : LeadValue+LeadUnit}</p>`
+            return str
+        },
+        formatterEn: function() {
+            let str = `<p>Correlation coefficient:${this.y.toFixed(4)}</p><br><p>lead${ Source===3 ? this.x+'stage' : LeadValue+relevanceUnitEnMap[LeadUnit]}</p>`
+            return str
+        }
+    }
+    
+    nextTick(()=>{
+        // if(data.ChartInfo.Source===3){
+        //     const hEl=document.getElementById(RenderDomId.value)
+        //     // console.log(hEl.offsetHeight);
+        //     xAxis.offset=-(hEl.offsetHeight-98)/2
+        // }
+        
+        options.value = {
+            isRelevanceChart:data.ChartInfo.Source===3,
+            title: {
+                text:''
+            },
+            series: seriesData,
+            yAxis: [yAxis] ,
+            xAxis:xAxis,
+            tooltip
+        }
+        ChartIns.update(options.value,true)
+    })
+
+    return {
+        isRelevanceChart:true,
+        title: {
+            text:''
+        },
+        series: seriesData,
+        yAxis: [yAxis] ,
+        xAxis:xAxis,
+        tooltip
+    }
+}
+
+
+/* 截面散点图设置 sectionScatterData */
+function setSectionScatterChart({DataResp,ChartInfo}) {
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+     /* 主题样式*/
+    const chartTheme =  ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
+
+    const { DataList,XName,XNameEn,XUnitName,XUnitNameEn,YName,YNameEn,YUnitName,YUnitNameEn } = DataResp;
+    const leftMin=Number(DataResp.YMinValue)
+    const leftMax=Number(DataResp.YMaxValue)
+    const xMin=Number(DataResp.XMinValue)
+    const xMax=Number(DataResp.XMaxValue)
+
+    axisLimitState.hasLeftAxis=true
+    axisLimitState.hasXAxis=true
+    axisLimitState.leftMin=leftMin
+    axisLimitState.leftMax=leftMax
+    axisLimitState.xMin=xMin
+    axisLimitState.xMax=xMax
+
+    //y轴
+    let yAxis = {
+        ...basicYAxis,
+        title: {
+            text: YName,
+            textZh:YName,// 中文
+            textEn:YNameEn|| '',
+            style:{
+                ...chartTheme&&chartTheme.yAxisOptions.style
+                },
+            align: 'middle',
+        },
+        labels: {
+            style:{
+              ...chartTheme&&chartTheme.yAxisOptions.style
+            },
+        },
+        opposite: false,
+        reversed: false,
+        min: Number(leftMin),
+        max: Number(leftMax),
+        tickWidth: 1,
+        plotBands: setAxisPlotAreas(1),
+        plotLines: setAxisPlotLines(1)
+    }
+
+    //x轴
+    let xAxis = {
+        ...scatterXAxis,
+        title: {
+            text: XName,
+            textZh:XName,// 中文
+            textEn:XNameEn || '',
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            },
+            align: 'middle',
+        },
+        labels: {
+            style:{
+              ...chartTheme&&chartTheme.xAxisOptions.style
+            },
+        },
+        min: Number(xMin),
+        max: Number(xMax),
+        plotBands: setAxisPlotAreas(3),
+        plotLines: setAxisPlotLines(3)
+    }
+
+    //数据列
+    let series = [];
+    DataList.forEach(item => {
+        //数据列
+        let series_item = {
+            data: [],
+            type: 'scatter',
+            name: item.Name,
+            nameZh: item.Name,
+            nameEn: item.NameEn,
+            color: item.Color,
+            lineWidth: 0,
+            chartType: 'linear',
+            zIndex:1,
+            visible: true,
+            marker: {
+                radius: (chartTheme&&chartTheme.lineOptions.radius)||5,
+            },
+        }
+        item.EdbInfoList.forEach(_ => {
+            series_item.data.push({
+            x: _.XValue,
+            y: _.YValue,
+            dataLabels: {
+                enabled: _.IsShow,
+                allowOverlap: true,
+                align: 'left',
+                format: _.Name,
+                formatZh: _.Name,
+                formatEn: _.NameEn
+            }
+            })
+        })
+        series.push(series_item);
+
+        //趋势线
+        if(item.ShowTrendLine)  {
+            
+            let trend_data = item.TrendLimitData.map((_,_index) => (
+                _index === item.TrendLimitData.length-1 ? {
+                    x: _.X,
+                    y: _.Y,
+                    dataLabels: {
+                    enabled: item.ShowRSquare || item.ShowFitEquation,
+                    align: 'left',
+                    color: '#666',
+                    x: 20,
+                    y: 30,
+                    zIndex: 9,
+                    allowOverlap: true,
+                    formatter: function(){
+                        let tag = '';
+                        item.ShowRSquare && item.ShowFitEquation
+                        ? tag =`<span>${item.TrendLine}</span><br><span>R²=${item.RSquare}</span>`
+                        : item.ShowRSquare && !item.ShowFitEquation
+                        ? tag =`<span>R²=${item.RSquare}</span>`
+                        : item.ShowFitEquation && !item.ShowRSquare
+                        ? tag =`<span>${item.TrendLine}</span>`
+                        : ''
+                        return tag
+                    }
+                    }
+                } : {
+                    x: _.X,
+                    y: _.Y,
+                }
+            ))
+
+            let trend_item = {
+                data: trend_data,
+                type: 'spline',
+                linkedTo: ':previous',
+                color: item.Color,
+                lineWidth: 1,
+                chartType: 'linear',
+                enableMouseTracking: false,
+                dashStyle:'Dash',
+                zIndex: 2,
+                visible: true,
+                marker: {
+                    enabled: false
+                }
+            }
+            series.push(trend_item)
+        }
+    })
+
+    let tooltip = {
+        formatter: function() {
+            let series_obj = DataList.find(_ => _.Name === this.series.name);
+            let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
+
+            let str=`<b>${ ponit_obj.Name }</b>`;
+            str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}<br>`;
+            str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`;
+
+            return str
+        },
+        formatterCh: function() {
+            let series_obj = DataList.find(_ => _.Name === this.series.name);
+            let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
+  
+            let str=`<b>${ ponit_obj.Name }</b>`;
+            str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XName}: ${this.x} ${ponit_obj.XDate}<br>`;
+            str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YName}: ${this.y} (${ponit_obj.YDate})`;
+  
+            return str
+            
+          },
+        formatterEn: function() {
+            let series_obj = DataList.find(_ => _.NameEn === this.series.name);
+            let ponit_obj = series_obj.EdbInfoList.find(_ => _.XValue ===this.x && _.YValue===this.y);
+  
+            let str=`<b>${ ponit_obj.NameEn }</b>`;
+            str += `<br><span style="color:${this.color}">\u25CF</span>${ponit_obj.XNameEn}: ${this.x} ${ponit_obj.XDate}<br>`;
+            str += `<span style="color:${this.color}">\u25CF</span>${ponit_obj.YNameEn}: ${this.y} ${ponit_obj.YDate}`;
+  
+            return str
+        }
+    }
+    
+    return {
+        title: {
+            text:''
+        },
+        series,
+        yAxis: [yAxis],
+        xAxis,
+        tooltip
+    }
+}
+
+/* 跨品种分析 */
+function setCrossVarietyChart({DataResp,EdbInfoList,ChartInfo}) {
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    /* 主题样式*/
+    const chartTheme =  ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
+
+    const { DataList,XName,YName,XNameEn,YNameEn,XMaxValue,XMinValue,YMaxValue,YMinValue } = DataResp;
+
+    const {leftMin,leftMax,xMin,xMax} = axisLimitState;
+
+     //y轴
+     let yAxis = {
+        ...basicYAxis,
+        title: {
+          text: YName,
+          textCh:YName,// 中文
+          textEn:YNameEn||YName,
+          align: 'middle',
+          style: {
+            ...chartTheme&&chartTheme.xAxisOptions.style
+          }
+        },
+        labels: {
+            style: {
+              ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        opposite: false,
+        reversed: false,
+        min: Number(leftMin),
+        max: Number(leftMax),
+        tickWidth: 1,
+      }
+
+      // x轴
+      let xAxis = {
+        ...scatterXAxis,
+        title: {
+            text: XName,
+            textCh:XName,// 中文
+            textEn:XNameEn || XName,
+            align: 'middle',
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        labels: {
+            style: {
+                ...chartTheme&&chartTheme.xAxisOptions.style
+            }
+        },
+        min: Number(xMin),
+        max: Number(xMax),
+      }
+
+       //数据列
+      let series = [];
+      const tagMap = { //标签对应文字
+        1: '最新',
+        3: 'Fix'
+      }
+      DataList.forEach(item => {
+        //数据列
+        let series_item = {
+          data: [],
+          type: 'scatter',
+          name: item.Name,
+          nameZh: item.Name,
+          nameEn: item.NameEn||item.Name,
+          color: item.Color,
+          lineWidth: 0,
+          chartType: 'linear',
+          zIndex:1
+        }
+        item.CoordinatePointData.forEach(_ => {
+          series_item.data.push({
+            x: _.X,
+            y: _.Y,
+            dataLabels: {
+              enabled: _.ShowTips===1,
+              allowOverlap: true,
+              align: 'left',
+              format: tagMap[_.DateType] || `-${_.DaysAgo}D`,
+            }
+          })
+        })
+        series.push(series_item);
+      })
+
+      let tooltip = {
+        formatter: function() {
+          let series_obj = DataList.find(_ => _.Name === this.series.name);
+          let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
+          
+          let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
+          let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
+
+          let str=`<b>${ this.series.name }</b>`;
+          str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}<br>`;
+          str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`;
+
+          return str
+        },
+        formatterCh: function() {
+          let series_obj = DataList.find(_ => _.Name === this.series.name);
+          let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
+          
+          let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
+          let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
+
+          let str=`<b>${ this.series.name }</b>`;
+          str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbName}: ${this.x} ${ponit_obj.XDate}<br>`;
+          str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbName}: ${this.y} ${ponit_obj.YDate}`;
+
+          return str
+          
+        },
+        formatterEn: function() {
+          let series_obj = DataList.find(_ => _.NameEn === this.series.name);
+          let ponit_obj = series_obj.CoordinatePointData.find(_ => _.X ===this.x && _.Y===this.y);
+          
+          let xEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.XEdbInfoId);
+          let yEdbInfo = EdbInfoList.find(_ => _.EdbInfoId===ponit_obj.YEdbInfoId);
+
+          let str=`<b>${ this.series.name }</b>`;
+          str += `<br><span style="color:${this.color}">\u25CF</span>${xEdbInfo.EdbNameEn}: ${this.x} ${ponit_obj.XDate}<br>`;
+          str += `<span style="color:${this.color}">\u25CF</span>${yEdbInfo.EdbNameEn}: ${this.y} ${ponit_obj.YDate}`;
+
+          return str
+        }
+      }
+
+      return {
+        title: {
+          text:''
+        },
+        series,
+        yAxis: [yAxis],
+        xAxis,
+        tooltip
+      }
+}
+
+/* 雷达图 */
+function setRadarChart({DataResp,EdbInfoList,ChartInfo}) {
+    axisLimitState.leftIndex=-1
+    axisLimitState.rightIndex=-1
+    axisLimitState.rightTwoIndex=-1
+
+    const { YDataList,XEdbIdValue } = DataResp;
+
+    let XDataList = EdbInfoList.filter(_ => XEdbIdValue.includes(_.EdbInfoId));
+
+    axisLimitState.hasLeftAxis=true
+    axisLimitState.leftMin=Number(ChartInfo.LeftMin)
+    axisLimitState.leftMax=Number(ChartInfo.LeftMax)
+
+    /* 主题样式*/
+    const chartTheme =  ChartInfo.ChartThemeStyle ? JSON.parse(ChartInfo.ChartThemeStyle) : null;
+
+    //x轴
+    let xAxis = {
+      lineWidth: 0,
+      tickLength: 0,
+      tickmarkPlacement: 'on',
+      categories:XDataList.map(_ => _.EdbAliasName||_.EdbName),
+      labels: {
+        allowOverlap: true,
+        autoRotationLimit: 40,
+        style: {
+          ...chartTheme&&chartTheme.xAxisOptions.style
+        }
+      }
+    }
+
+    //y轴
+    let yAxis = [{
+      gridLineInterpolation: 'polygon',
+      gridLineWidth: 1,
+      lineWidth: 0,
+      endOnTick: false,
+      startOnTick: false,
+      showLastLabel: true,
+      // tickAmount:4,
+      title: {
+        text:  ChartInfo.Unit,
+        textCh: ChartInfo.Unit,
+        textEn: ChartInfo.UnitEn,
+        align: 'high',
+        rotation: 0,
+        y: 5,
+        x:10,
+        textAlign: 'left',
+        reserveSpace: false,
+        style:{
+          ...chartTheme&&chartTheme.yAxisOptions.style
+        },
+      },
+      labels: {
+        allowOverlap: true,
+        style:{
+          ...chartTheme&&chartTheme.yAxisOptions.style
+        }
+      },
+      min: Number(ChartInfo.LeftMin),
+      max: Number(ChartInfo.LeftMax),
+    }]
+
+    //系列
+    let series = [];
+    YDataList.forEach(item => {
+      let serie_item = {
+        name: item.Name || item.Date,
+        nameZh: item.Name || item.Date,
+        nameEn: item.Date,
+        data: item.Value,
+        pointPlacement: 'on',
+        type: (chartTheme&&chartTheme.lineOptions.lineType) || 'line',
+        dashStyle: (chartTheme&&chartTheme.lineOptions.dashStyle)||'Solid',
+        yAxis: 0,
+        color: item.Color,
+        lineWidth: (chartTheme&&chartTheme.lineOptions.lineWidth) || 1,
+        chartType: 'linear'
+      };
+      series.push(serie_item)
+    })
+
+    return {
+      chart: {
+        ...chartDefaultOpts.chart,
+        ...chartTheme.drawOption,
+        spacing: [2,10,2,10],
+        polar:true,
+      },
+      title: {
+        text:''
+      },
+      pane: {
+        size: '85%'
+      },
+      series,
+      yAxis,
+      xAxis
+    }
+}
+
+/* ----自定义上下限相关--- */
+/* 计算y轴上下限 */
+function calcYAxislimit(tableData=[],ChartInfo){
+    //散点图单独处理
+    if(ChartInfo.ChartType===5){
+        if(tableData[1]){
+            axisLimitState.leftMin = tableData[1].MinData
+            axisLimitState.leftMax = tableData[1].MaxData
+        }
+        return 
+    }
+    //分组
+    const leftData = tableData.filter(i => i.IsAxis === 1).map(i => [Number(i.MinData), Number(i.MaxData)])
+    const rightData = tableData.filter(i => !i.IsAxis).map(i => [Number(i.MinData), Number(i.MaxData)])
+    const rightTwoData = tableData.filter(i => i.IsAxis === 2).map(i => [Number(i.MinData), Number(i.MaxData)])
+    //计算最大最小值
+    if (leftData.length) {
+        const {
+            Max,
+            Min
+        } = calcLimit(leftData.flat())
+        axisLimitState.leftMin = Min
+        axisLimitState.leftMax = Max
+    } 
+    if (rightData.length) {
+        const {
+            Max,
+            Min
+        } = calcLimit(rightData.flat())
+        axisLimitState.rightMin = Min
+        axisLimitState.rightMax = Max
+    }
+    if (rightTwoData.length) {
+        const {
+            Max,
+            Min
+        } = calcLimit(rightTwoData.flat())
+        axisLimitState.rightTwoMin = Min
+        axisLimitState.rightTwoMax = Max
+    }
+}
+function calcLimit(arr) {
+    return {
+        Max: Math.max(...arr),
+        Min: Math.min(...arr)
+    }
+}
+//图表详情-设置图表上下限
+function setLimitData({EdbInfoList,ChartInfo}){
+    const {
+        //左右轴极值字段 
+        LeftMin=0,LeftMax=0,
+        RightMin=0,RightMax=0,
+        Right2Min=0,Right2Max=0,
+        MinMaxSave
+    } = ChartInfo
+    if(MinMaxSave){
+        axisLimitState.leftMin = Number(LeftMin)
+        axisLimitState.leftMax = Number(LeftMax)
+        axisLimitState.rightMin = Number(RightMin)
+        axisLimitState.rightMax = Number(RightMax)
+        axisLimitState.rightTwoMin = Number(Right2Min)
+        axisLimitState.rightTwoMax = Number(Right2Max)
+        //若用户修改过,则检测轴的上下限是否为空,若为空,则需要计算对应轴的上下限
+        checkLimit(EdbInfoList,ChartInfo)
+        console.log('check',axisLimitState.leftMin,axisLimitState.leftMax)
+    }else{
+        calcYAxislimit(EdbInfoList,ChartInfo)
+    }
+}
+function checkLimit(tableData=[],ChartInfo){
+    //散点图单独处理
+    if(ChartInfo.ChartType===5){
+        if(tableData[1]){
+            if(Number(axisLimitState.leftMin)===0&&Number(axisLimitState.leftMax)===0){
+                axisLimitState.leftMin = tableData[1].MinData
+                axisLimitState.leftMax = tableData[1].MaxData
+            }
+        }
+        return 
+    }
+    //若轴的上下限均为0,则不管用户有没有修改过,都重新赋值
+    if(Number(axisLimitState.leftMin)===0&&Number(axisLimitState.leftMax)===0){
+        const leftData = tableData.filter(i=>i.IsAxis===1).map(i=>[Number(i.MinData),Number(i.MaxData)])
+        if(leftData.length){
+            const {Max,Min} = calcLimit(leftData.flat())
+            axisLimitState.leftMin = Min
+            axisLimitState.leftMax = Max
+        }
+    }
+    if(Number(axisLimitState.rightMin)===0&&Number(axisLimitState.rightMax)===0){
+        const rightData = tableData.filter(i => !i.IsAxis).map(i=>[Number(i.MinData),Number(i.MaxData)])
+        if(rightData.length){
+            const {Max,Min} = calcLimit(rightData.flat())
+            axisLimitState.rightMin = Min
+            axisLimitState.rightMax = Max
+        }
+    }
+    if(Number(axisLimitState.rightTwoMin)===0&&Number(axisLimitState.rightTwoMax)===0){
+        const rightTwoData = tableData.filter(i=>i.IsAxis===2).map(i=>[Number(i.MinData),Number(i.MaxData)])
+        if(rightTwoData.length){
+            const {Max,Min} = calcLimit(rightTwoData.flat())
+            axisLimitState.rightTwoMin = Min
+            axisLimitState.rightTwoMax = Max
+        }
+    }
+}
+/*-------------------- */

+ 40 - 4
src/layout/Index.vue

@@ -4,9 +4,45 @@
 
 <template>
     <div class="layout-wrap">
-        <div class="header">
-            <t-button theme="primary">ETA社区</t-button>
+        <div class="bg-white header">
+            <span class="bread-item" v-for="item in $route.matched" :key="item.name">{{item.meta.title}}</span>
         </div>
-        <router-view />
+        <div class="layout-content">
+            <router-view />
+        </div>
+        
     </div>
-</template>
+</template>
+
+<style lang="scss" scoped>
+.layout-wrap{
+    height: 100%;
+    padding-top: 64px;
+    .header{
+        position: fixed;
+        left: 0;
+        right: 0;
+        top: 0;
+        z-index: 10;
+        height: 64px;
+        display: flex;
+        align-items: center;
+        padding-left: 24px;
+        .bread-item{
+            &::after{
+                content:'/'
+            }
+        }
+        .bread-item:last-child{
+            color: $primary-color;
+            &::after{
+                content:''
+            }
+        }
+    }
+    .layout-content{
+        padding: 20px;
+        min-height: calc(100% - 64px);
+    }
+}
+</style>

+ 6 - 0
src/router/index.js

@@ -7,11 +7,17 @@ const routes = [
     name:'LayoutIndex',
     redirect: '/etaChart/index',
     component:LayoutIndex,
+    meta:{
+      title:'ETA社区'
+    },
     children:[
       {
         path:'etaChart/index',
         name:'ETAChartIndex',
         component:()=>import('@/views/etaChart/Index.vue'),
+        meta:{
+          title:'ETA图库'
+        },
       }
     ]
   },

+ 6 - 0
src/styles/common.scss

@@ -1,6 +1,8 @@
 html,body,#app{
     font-size: 14px;
     color: #333;
+    background-color: #F2F6FA;
+    height: 100%;
 }
 
 div,ul,li{
@@ -23,4 +25,8 @@ img {
     image-rendering: -webkit-optimize-contrast;
     image-rendering: crisp-edges;
     -ms-interpolation-mode: nearest-neighbor;
+}
+
+.bg-white{
+    background-color: #fff;
 }

+ 1 - 0
src/styles/var.scss

@@ -0,0 +1 @@
+$primary-color:#0052D9;

+ 2 - 3
src/views/404.vue

@@ -11,8 +11,7 @@ function goHome(){
 
 <template>
     <div class="nofound-page">
-        <!-- <img src="@/assets/imgs/404.png" alt=""> -->
-        <svg-icon name='close'/>
+        <img src="@/assets/imgs/404.png" alt="">
         <p>404</p>
         <t-button @click="goHome">返回首页</t-button>
     </div>
@@ -29,6 +28,6 @@ function goHome(){
     }
 }
 img{
-    width: 80%;
+    width: 300px;
 }
 </style>

+ 89 - 35
src/views/etaChart/Index.vue

@@ -1,41 +1,46 @@
 <script setup>
 import { ref } from 'vue'
 import ClassifyWrapVue from "./components/ClassifyWrap.vue";
-import { useScroll } from '@vueuse/core'
 
 const tableColOpts = [
   {
-    align: 'center',
     colKey: 'ChartName',
-    title: '图表名称'
+    title: '图表名称',
+    width: '450px'
   },
   {
-    align: 'center',
     colKey: 'Company',
     title: '机构',
-    width: '200px'
+    width: '100px'
   },
   {
-    align: 'center',
     colKey: 'AdminName',
     title: '创建人',
-    width: '150px'
+    width: '80px'
   }
 ]
 const tableData = ref([])
-for (let i = 0; i < 30; i++) {
-  tableData.value.push({
-    index: i + 1,
-    ChartName: '图表名称很长的附近的拉进来放到手机里尽快费德勒就看撒就进口发动机啊',
-    Company: '弘则研究',
-    AdminName: '管理眼',
-  });
+const tableLoading = ref(false)
+function getTableData() {
+  tableLoading.value = true
+  setTimeout(() => {
+    for (let i = 0; i < 30; i++) {
+      tableData.value.push({
+        index: i + 1,
+        ChartName: '图表名称很长的附近的拉进来放到手机里尽快费德勒就看撒就进口法',
+        Company: '弘则研究研究',
+        AdminName: '管理眼研',
+      });
+    }
+    tableLoading.value = false
+  }, 1500);
 }
-const tableEl = ref(null)
-const { x, y, isScrolling, arrivedState, directions } = useScroll(tableEl)
-function tableScroll(evevt) {
-  //scrollTop
-
+getTableData()
+function tableScroll(opt) {
+  if (tableLoading.value) return
+  if (opt.scrollBottom < 100) {
+    getTableData()
+  }
 }
 
 </script>
@@ -43,32 +48,81 @@ function tableScroll(evevt) {
 <template>
   <div class="eta-chart-page">
     <ClassifyWrapVue />
-    <div class="table-wrap">
-      <t-table
-        row-key="index"
-        :data="tableData"
-        :columns="tableColOpts"
-        bordered
-        lazy-load
-        max-height="100%"
+    <div class="table-wrap" v-loading='tableLoading'>
+      <t-list
         style="height: 100%"
+        :onScroll="tableScroll"
       >
-        <!-- <template #operation="{ row }">
-          <t-link theme="primary" hover="color" @click="rehandleClickOp(row)">
-            {{ row.status === 0 ? "查看详情" : "再次申请" }}
-          </t-link>
-        </template> -->
-      </t-table>
+        <table class="table-box" cellpadding="0" cellspacing="0">
+          <thead class="table-head thead-sticky">
+            <tr>
+              <td
+                v-for="opt in tableColOpts"
+                :key="opt.colKey"
+                :style="{ width: opt.width }"
+              >
+                {{ opt.title }}
+              </td>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="row in tableData" :key="row.index">
+              <td
+                v-for="opt in tableColOpts"
+                :key="opt.colKey"
+                :style="{ width: opt.width }"
+              >
+                {{ row[opt.colKey] }}
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </t-list>
     </div>
-    <div class="chart-wrap"></div>
+    <div class="bg-white chart-wrap"></div>
   </div>
 </template>
 
 <style lang="scss" scoped>
 .eta-chart-page {
   display: flex;
+  gap: 0 20px;
   .table-wrap {
-    height: calc(100vh - 100px);
+    flex-shrink: 0;
+    height: calc(100vh - 120px);
+    .table-box {
+      width: 100%;
+      border-color: #dcdfe6;
+      td,
+      th {
+        word-break: break-all;
+        word-wrap: break-word;
+        border: 1px solid #dcdfe6;
+        height: 40px;
+        text-align: center;
+        border-left: none;
+        border-top: none;
+        &:first-child {
+          border-left: 1px solid #dcdfe6;
+        }
+      }
+      .thead-sticky {
+        position: sticky;
+        top: 0;
+      }
+      .table-head {
+        background-color: #EBEEF5;
+        font-weight: bold;
+      }
+      tbody{
+        color: #666;
+      }
+    }
+  }
+  .chart-wrap{
+    flex: 1;
+    min-width: 600px;
+    border: 1px solid #DCDFE6;
   }
 }
 </style>

+ 67 - 50
src/views/etaChart/components/ClassifyWrap.vue

@@ -1,5 +1,6 @@
 <script setup>
 import { ref } from 'vue'
+import { SearchIcon,Icon  } from 'tdesign-icons-vue-next';
 
 const companyOpts = [{ label: '弘则研究', value: 1 }]
 const companyVal = ref('')
@@ -7,59 +8,59 @@ const companyVal = ref('')
 const userOpts = [{ label: '弘则研究', value: 1 }]
 const userVal = ref('')
 
-const searchVal=ref('')
+const searchVal = ref('')
 
 
-const classifyList=ref([{
-    label: '第一段',
-    children: [
-      {
-        label: '第二段',
-      },
-      {
-        label: '第二段',
-      },
-    ],
-  },
-  {
-    label: '第一段',
-    children: [
-      {
-        label: '第二段',
-      },
-      {
-        label: '第二段',
-      },
-    ],
-  },
-  {
-    label: '第一段',
-    children: [
-      {
-        label: '第二段',
-      },
-      {
-        label: '第二段',
-      },
-    ],
-  },
-  {
-    label: '第一段',
-    children: [
-      {
-        label: '第二段',
-      },
-      {
-        label: '第二段',
-      },
-    ],
-  },])
+const classifyList = ref([{
+  label: '第一段',
+  children: [
+    {
+      label: '第二段',
+    },
+    {
+      label: '第二段',
+    },
+  ],
+},
+{
+  label: '第一段',
+  children: [
+    {
+      label: '第二段',
+    },
+    {
+      label: '第二段',
+    },
+  ],
+},
+{
+  label: '第一段',
+  children: [
+    {
+      label: '第二段',
+    },
+    {
+      label: '第二段',
+    },
+  ],
+},
+{
+  label: '第一段',
+  children: [
+    {
+      label: '第二段',
+    },
+    {
+      label: '第二段',
+    },
+  ],
+},])
 
 
 </script>
 
 <template>
-  <div class="classify-wrap">
+  <div class="bg-white classify-wrap">
     <div class="select-wrap">
       <t-select placeholder="机构" v-model="companyVal">
         <t-option
@@ -78,21 +79,37 @@ const classifyList=ref([{
         ></t-option>
       </t-select>
     </div>
-    <t-input v-model="searchVal" clearable placeholder="请输入图表名称"/>
+    <t-input v-model="searchVal" clearable placeholder="请输入图表名称">
+      <template #prefixIcon>
+        <search-icon />
+      </template>
+    </t-input>
     <div class="classify-list-box">
-        <t-tree :data="classifyList" activable transition />
+      <t-tree :data="classifyList" activable transition>
+        <template #icon="{ node }">
+          <svg-icon style="font-size:16px" v-if="node.getChildren() && node.expanded" name="tree_opend" />
+          <svg-icon style="font-size:16px" v-if="node.getChildren() && !node.expanded" name="tree_close" />
+        </template>
+      </t-tree>
     </div>
   </div>
 </template>
 
 <style lang="scss" scoped>
 .classify-wrap {
-    width: 300px;
-    flex-shrink: 0;
+  width: 300px;
+  flex-shrink: 0;
+  padding: 20px;
+  
   .select-wrap {
     display: flex;
     gap: 0 10px;
     margin-bottom: 10px;
   }
+  .classify-list-box {
+    padding-top: 10px;
+    height: calc(100vh - 240px);
+    overflow-y: auto;
+  }
 }
 </style>

+ 26 - 0
vite.config.js

@@ -26,7 +26,23 @@ export default defineConfig(({ mode }) => {
           TDesignResolver({
             library: "vue-next",
           }),
+          // 由于tdesign 官方未在unplugin-vue-components 处理自动导入指令的情况
+          // 所以手动导入下
+          {
+            type: 'directive',
+            resolve: (name) => {
+              if (name === 'Loading') {
+                return {
+                  name: 'vLoading',
+                  from: `tdesign-vue-next/esm/loading/directive`
+                };
+              } else {
+                return;
+              }
+            },
+          }
         ],
+        directives: true
       }),
       createSvgIconsPlugin({
         // 指定需要缓存的图标文件夹
@@ -46,6 +62,16 @@ export default defineConfig(({ mode }) => {
         // customDomId: '__svg__icons__dom__'
       }),
     ],
+    css: {
+      // css预处理器
+      preprocessorOptions: {
+        scss: {
+          // 定义全局的scss变量
+          // 给导入的路径最后加上 ;
+          additionalData: `@import '@/styles/var.scss';`,
+        },
+      },
+    },
     resolve: {
       alias: {
         "@": path.resolve(__dirname, "./src"),