Browse Source

发现版本内容有冲突,合并master,指标库成图逻辑修改

hbchen 1 year ago
parent
commit
563d11b225
96 changed files with 5373 additions and 914 deletions
  1. 12 1
      index.html
  2. 7 2
      src/api/api.js
  3. 36 0
      src/api/modules/chartApi.js
  4. 37 0
      src/api/modules/etaBaseConfigApi.js
  5. 9 1
      src/api/modules/oldApi.js
  6. 8 0
      src/api/modules/pptApi.js
  7. 8 0
      src/api/modules/pptEnApi.js
  8. 5 0
      src/api/modules/reportEnApi.js
  9. 4 0
      src/api/modules/semanticsApi.js
  10. 74 0
      src/api/modules/setApi.js
  11. BIN
      src/assets/img/eta_base_config/outlink.png
  12. BIN
      src/assets/img/home/email_icon.png
  13. BIN
      src/assets/img/home/phone_icon.png
  14. 0 12
      src/config/setting.js
  15. 25 35
      src/main.js
  16. 1 1
      src/mixins/index.js
  17. 1 1
      src/mixins/theme.js
  18. 19 7
      src/routes/modules/chartRoutes.js
  19. 5 1
      src/routes/modules/futuresRoutes.js
  20. 23 1
      src/routes/modules/oldRoutes.js
  21. 111 21
      src/utils/TimeOnPage.js
  22. 8 0
      src/utils/buttonConfig.js
  23. 47 0
      src/utils/commonOptions.js
  24. 34 27
      src/views/Home.vue
  25. 446 158
      src/views/Login.vue
  26. 8 0
      src/views/chartRelevance_manage/fittingEquationChartEditor.vue
  27. 2 2
      src/views/chartRelevance_manage/fittingEquationList.vue
  28. 2 2
      src/views/chartRelevance_manage/list.vue
  29. 8 0
      src/views/chartRelevance_manage/relevanceChartEditor.vue
  30. 8 0
      src/views/chartRelevance_manage/statisticFeatureChartEditor.vue
  31. 2 2
      src/views/chartRelevance_manage/statisticFeatureList.vue
  32. 1 1
      src/views/classify_manage/classifyEnlist.vue
  33. 2 2
      src/views/classify_manage/classifylist.vue
  34. 23 10
      src/views/dataEntry_manage/chartSetting.vue
  35. 25 12
      src/views/dataEntry_manage/codecount/index.vue
  36. 2 8
      src/views/dataEntry_manage/databaseComponents/addTargetDiaBase.vue
  37. 780 0
      src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue
  38. 1 1
      src/views/dataEntry_manage/databaseComponents/createChart.vue
  39. 150 0
      src/views/dataEntry_manage/databaseComponents/edbDetailData.vue
  40. 429 155
      src/views/dataEntry_manage/databaseList.vue
  41. 8 0
      src/views/dataEntry_manage/onlineExcelCopy.vue
  42. 1 1
      src/views/dataEntry_manage/targetList.vue
  43. 8 0
      src/views/datasheet_manage/customSheetEdit.vue
  44. 8 0
      src/views/datasheet_manage/mixedSheetEdit.vue
  45. 16 0
      src/views/futures_manage/chartEditor.vue
  46. 2 1
      src/views/futures_manage/commodityChartBase.vue
  47. 139 0
      src/views/login_manage/EmailModel.vue
  48. 339 0
      src/views/login_manage/ForgetPassModel.vue
  49. 156 0
      src/views/login_manage/MobileModel.vue
  50. 117 0
      src/views/login_manage/OrdinaryModel.vue
  51. 108 0
      src/views/login_manage/components/CaptchaInput.vue
  52. 99 0
      src/views/login_manage/components/ModelSteps.vue
  53. 79 0
      src/views/login_manage/components/VerificationBox.vue
  54. 111 0
      src/views/login_manage/css/formStyle.scss
  55. 34 0
      src/views/login_manage/modelMixins.js
  56. 8 4
      src/views/ppt_manage/mixins/pptMixins.js
  57. 120 0
      src/views/ppt_manage/newVersion/components/editor/InsertSemantics.vue
  58. 28 14
      src/views/ppt_manage/newVersion/pptCatalog.vue
  59. 6 2
      src/views/ppt_manage/newVersion/pptEditor.vue
  60. 32 18
      src/views/ppt_manage/newVersion/pptEnCatalog.vue
  61. 7 2
      src/views/ppt_manage/newVersion/pptEnEditor.vue
  62. 18 0
      src/views/ppt_manage/newVersion/utils/untils.js
  63. 2 2
      src/views/predictEdb_manage/addPredicEdb.vue
  64. 16 10
      src/views/predictEdb_manage/components/chartInfo.vue
  65. 104 41
      src/views/predictEdb_manage/components/childData.vue
  66. 2 2
      src/views/predictEdb_manage/components/classifyDia.vue
  67. 112 3
      src/views/predictEdb_manage/components/edbDetail.vue
  68. 101 31
      src/views/predictEdb_manage/predictEdb.vue
  69. 93 4
      src/views/report_manage/addreportNew.vue
  70. 121 0
      src/views/report_manage/components/importSemantics.vue
  71. 1 1
      src/views/report_manage/dayOrWeek.vue
  72. 100 90
      src/views/report_manage/editChapterReport.vue
  73. 109 2
      src/views/report_manage/editreportNew.vue
  74. 4 2
      src/views/report_manage/mixins/messagePush.js
  75. 28 0
      src/views/report_manage/mixins/reportMixin.js
  76. 103 2
      src/views/report_manage/reportEn/reportEditor.vue
  77. 46 9
      src/views/report_manage/reportEn/reportlist.vue
  78. 1 1
      src/views/report_manage/reportVariety.vue
  79. 53 11
      src/views/report_manage/reportlist.vue
  80. 18 2
      src/views/resetpassword.vue
  81. 15 13
      src/views/sandbox_manage/sandFlow/index.vue
  82. 2 2
      src/views/semantics_manage/components/canvasTable.vue
  83. 4 0
      src/views/semantics_manage/semantics/components/selectFileDialog.vue
  84. 38 4
      src/views/semantics_manage/semanticsPage.vue
  85. 54 8
      src/views/system_manage/components/addUserDialog.vue
  86. 10 5
      src/views/system_manage/dataAuthManage.vue
  87. 39 136
      src/views/system_manage/departManage.vue
  88. 5 5
      src/views/system_manage/enAuthManage.vue
  89. 21 6
      src/views/system_manage/mixin/departManageMixin.js
  90. 14 9
      src/views/system_manage/newAuthManage.vue
  91. 125 0
      src/views/system_manage/outlinkList.vue
  92. 194 0
      src/views/system_manage/outlinkListConfig.vue
  93. 11 6
      src/views/system_manage/roleManage.vue
  94. 4 2
      src/vuex/index.js
  95. 10 0
      src/vuex/modules/permissionButton.js
  96. 6 0
      src/vuex/mutations.js

+ 12 - 1
index.html

@@ -25,7 +25,18 @@
 	
 	<!-- dataTables -->
 	<link rel="stylesheet" type="text/css" href="./static/css/jquery.dataTables.css"/>
-
+    <!-- 隐藏Edge在密码输入框的icon -->
+    <style>
+        input[type="password"]::-ms-reveal{
+            display: none;
+        }
+        input[type="password"]::-ms-clear{
+            display: none;
+        }
+        input[type="password"]::-o-reveal{
+            display: none;
+        }
+    </style>
 	<script>
 		var _hmt = _hmt || [];
 		(function() {

+ 7 - 2
src/api/api.js

@@ -134,6 +134,7 @@ const {
   reportauthor,
   getDraft,
   autosave,
+  reportSetPrepublish,
   classifylist,
   classifyparent,
   classifyadd,
@@ -186,7 +187,9 @@ const {
   reportMessageSend,
   weekReportValidAudio,
   getUserUuid,
-  getBusinessCode
+  getBusinessCode,
+  recordActiveLogin
+
 } = oldApis;
 
 export {
@@ -208,6 +211,7 @@ export {
   reportauthor,
   getDraft,
   autosave,
+  reportSetPrepublish,
   classifylist,
   classifyparent,
   classifyadd,
@@ -260,6 +264,7 @@ export {
   reportMessageSend,
   weekReportValidAudio,
   getUserUuid,
-  getBusinessCode
+  getBusinessCode,
+  recordActiveLogin
 };
 

+ 36 - 0
src/api/modules/chartApi.js

@@ -374,6 +374,14 @@ const dataBaseInterface = {
 		return http.post('/datamanage/edb_info/calculate/compute_correlation',params)
 	},
 
+	/**
+	 * 代码运算的sourceList
+	 * @param {*} params 
+	 */
+	getCodecountEdbSources: params => {
+		return http.get('/datamanage/edb_source/list/python')
+	},
+
 
 	//========================================chart
 	// /**
@@ -862,6 +870,34 @@ const dataBaseInterface = {
 	getDataSource:(params)=>{
 		return http.get('datamanage/edb_source/list',params)
 	},
+	/**
+	 * 指标图表列表
+	 * @param {Number} PageSize 
+	 * @param {Number} CurrentIndex
+	 * @param {Number} ClassifyId
+	 * @param {Number} AdminId
+	 * @param {Boolean} IsOnlyMe
+	 */
+	getEdbChartList:(params)=>{
+		return http.get('/datamanage/edb_info/chart/list',params)
+	},
+	/**
+	 * 保存指标上下限
+	 * @param {*} params 
+	 * @returns 
+	 */
+	saveEdbChartLimit:(params)=>{
+		return http.post('/datamanage/edb_info/modify',params)
+	},
+	/**
+	 * 保存指标缩略图
+	 * @param {Number} EdbInfoId 
+	 * @param {String} ImageUrl 
+	 * @returns 
+	 */
+	saveEdbChartImg:(params)=>{
+		return http.post('/datamanage/edb_info/image/set',params)
+	}
 	
 }
 

+ 37 - 0
src/api/modules/etaBaseConfigApi.js

@@ -7,4 +7,41 @@ export const etaBaseConfigInterence = {
     saveBaseConfig:params=>{
         return http.post('/business_conf/save',params)
     }
+}
+
+// 外部链接配置 接口
+export const outlinkConfigInterence = {
+    /**
+     * 外部链接列表
+     * @param params.CurrentIndex 页码-number
+     * @param params.PageSize 每页数据量-number
+     * @param params.SortParam 排序字段-string
+     * @param params.SortType 排序类型-string desc/asc/""
+     * @returns 
+     */
+    getOutlinkList:params=>{
+        return http.get('/out_link/list',params)
+    },
+    // 外部链接列表全部
+    getOutlinkListAll:params=>{
+        return http.get('/out_link/all',params)
+    },
+    /** 
+     * 新增/编辑
+     * @param params.Id Id-number-不传ID表示新增,传了ID表示编辑
+     * @param params.Title 菜单名称-string
+     * @param params.Url 页面链接-string
+     * @returns 
+     */
+    outlinkSave:params=>{
+        return http.post('/out_link/save',params)
+    },
+    /** 
+     * 删除
+     * @param params.Id Id-number
+     * @returns 
+     */
+    outlinkDelete:params=>{
+        return http.post('/out_link/del',params)
+    }
 }

+ 9 - 1
src/api/modules/oldApi.js

@@ -22,6 +22,7 @@ import http from "@/api/http.js"
  const reportauthor = params => { return http.get('/report/author',params); };  //获取作者
  const getDraft = params => { return http.get('/report/getDraft',params); };  //获取草稿
  const autosave = params => { return http.post('/report/saveReportContent',params); };  //保存
+ const reportSetPrepublish=params=>{return http.post('/report/pre_publish',params);};//报告设置定时发布
 
  const classifylist = params => { return http.get('/classify/list',params); };  //获取分类列表
  const classifyparent = params => { return http.get('/classify/parent',params); };  //获取父级分类
@@ -298,6 +299,11 @@ const getBusinessCode=params=>{
 	return http.get('/business_conf/code_encrypt',params)
 }
 
+// 获取商家code "ActiveTime":99
+const recordActiveLogin=params=>{
+	return http.post('/eta_trial/user/login_duration',params)
+}
+
 /**
  * 获取动态配配置 系统内部动态链接
  * @param {*} params 
@@ -325,6 +331,7 @@ export {
 	reportauthor,
 	getDraft,
 	autosave,
+	reportSetPrepublish,
 	classifylist,
 	classifyparent,
 	classifyadd,
@@ -378,5 +385,6 @@ export {
 	weekReportValidAudio,
 	getUserUuid,
 	getBusinessCode,
-	getPublicSettingsApi
+	getPublicSettingsApi,
+	recordActiveLogin
 }

+ 8 - 0
src/api/modules/pptApi.js

@@ -146,6 +146,14 @@ export default{
     searchPPTByKeyWorld:params=>{
       return http.get('/pptv2/share/ppt/list',params)
     },
+    /**
+     * 搜索PPT,范围为 我的+公共
+     * @param {String} Keyword 
+     * @returns 
+     */
+    searchPPTByKeyWorldV2:params=>{
+        return http.get('/pptv2/ppt/search',params)
+    },
     /**
      * 移动目录里的ppt
      * GroupPptId

+ 8 - 0
src/api/modules/pptEnApi.js

@@ -131,6 +131,14 @@ export const pptEnInterface = {
     searchPPTByKeyWorld:params=>{
       return http.get('/ppt_english/share/ppt/list',params)
     },
+    /**
+     * 搜索PPT,范围为 我的+公共
+     * @param {String} Keyword 
+     * @returns 
+     */
+    searchPPTByKeyWorldV2:params=>{
+        return http.get('/ppt_english/ppt/search',params)
+      },
     /**
      * 移动目录里的ppt
      * GroupPptId

+ 5 - 0
src/api/modules/reportEnApi.js

@@ -162,6 +162,11 @@ export const markReport=params => {
   return http.post('/english_report/mark',params)
 }
 
+//定时发布报告
+export const enReportPrepblish=params=>{
+	return http.post('/english_report/pre_publish',params)
+}
+
 /* 发送日志 */
 export const logInterface = {
 	/**

+ 4 - 0
src/api/modules/semanticsApi.js

@@ -270,6 +270,10 @@ const semanticInterface = {
    */
   moveCompare:params => {
       return http.post('/semantic_analysis/compare/move',params)
+  },
+  //对比文档列表数据
+  compareSearch:params=>{
+    return http.get('/semantic_analysis/compare/search',params)
   }
 }
 

+ 74 - 0
src/api/modules/setApi.js

@@ -260,7 +260,81 @@ const departInterence = {
 	//获取用户所有的按钮权限
 	getRoleBtnAuth:params=>{
 		return http.get('/system/role/menu/buttons',params)
+	},
+	/**
+	 * 获取图形验证码 返回Base64格式数据
+	 * @returns 
+	 */
+	getCodePic:params=>{
+		return http.get('/user_login/get_captcha',params)
+	},
+	/**
+	 * 获取短信/邮箱验证码
+	 * @param {Number} VerifyType 验证方式: 1-手机号; 2-邮箱
+	 * @param {String} CaptchaId 图形验证码ID
+	 * @param {String} CaptchaCode 图形验证码的值
+	 * @param {String} Mobile 手机号 验证方式为1时必填
+	 * @param {String} Email 邮箱 验证方式为2时必填
+	 * @param {String} TelAreaCode 手机区号
+	 * @param {Number} Source 来源:1-登录;3-忘记密码
+	 * @returns 
+	 */
+	getCodeVerify:params=>{
+		return http.post('/user_login/verify_code',params)
+	},
+	/**
+	 * ETA1.4后,用户登录
+	 * @param {Number} LoginType 登录方式: 1-账号; 2-手机号; 3-邮箱
+	 * @param {String} Username 用户名
+	 * @param {String} Password 密码
+	 * @param {String} Mobile 手机号
+	 * @param {String} Email 邮箱
+	 * @param {String} VerifyCode 手机号/邮箱的验证码
+	 * @returns 
+	 */
+	userLogin:params=>{
+		return http.post('/user_login/login',params)
+	},
+	/**
+	 * 忘记密码账号校验,获取账号信息
+	 * @param {String} CaptchaId 图形验证码ID
+	 * @param {String} CaptchaCode 图形验证码
+	 * @param {String} UserName 账号
+	 * @returns 
+	 */
+	accountCheck:params=>{
+		return http.post('/user_login/forget/account_get',params)
+	},
+	/**
+	 * 忘记密码-手机/邮箱的验证码校验
+	 * @param {Number} FindType 密码找回方式:1-手机号;2-邮箱
+	 * @param {String} VerifyCode 验证码
+	 * @param {String} UserName 用户名
+	 * @param {String} Mobile 找回方式为手机号时必填
+	 * @param {String} Email 找回方式为邮箱时必填
+	 * @returns 
+	 */
+	checkCodeVerify:params=>{
+		return http.post('/user_login/forget/code_verify',params)
+	},
+	/**
+	 * 忘记密码-重置密码
+	 * @param {String} UserName 
+	 * @param {String} Password 
+	 * @param {String} RePassword 
+	 * @returns 
+	 */
+	resetPass:params=>{
+		return http.post('/user_login/forget/reset_pass',params)
+	},
+	/**
+	 * 获取手机号区号
+	 * @returns 
+	 */
+	getPhoneAreaCode:params=>{
+		return http.get('/user_login/area_code/list',params)
 	}
+
 }
 
 /* 视频管理 */

BIN
src/assets/img/eta_base_config/outlink.png


BIN
src/assets/img/home/email_icon.png


BIN
src/assets/img/home/phone_icon.png


+ 0 - 12
src/config/setting.js

@@ -1,12 +0,0 @@
-//全局配置
-export default {
-  name: '后台管理系统',
-  company_name: '**公司',
-  g_logo: require('@/assets/img/home/logo.png'), //主页菜单栏logo
-  g_mini_logo: require('@/assets/img/home/eta_mini.png'), //主页菜单栏mini-logo
-  theme_color: '',
-  menu_bg:'#FFFFFF',//菜单栏背景色
-  login_title: '',//登录页标题
-  login_logo: require('@/assets/img/home/login_logo.png'),//登录页logo
-  login_bg: require('@/assets/img/login_bg.png')
-}

+ 25 - 35
src/main.js

@@ -18,21 +18,8 @@ Vue.use(ElementUI);
 Vue.use(VueRouter);
 Vue.use(Vuex);
 
-import {
-  getBusinessCode
-} from "api/api.js";
-import global from '@/config/setting';
-import{endCalc,optionTimeCalc,doPageEventListener}from'@/utils/TimeOnPage.js';
-
-// 获取商家code
-getBusinessCode().then(res=>{
-  if(res.Ret!==200) return 
-  let bus_code = res.Data||''
-  if(stores.state.TRIAL_CODE == bus_code){
-    doPageEventListener()
-  }
-  stores.mutations.SET_BUSINESS_CODE(stores.state,bus_code) 
-})
+import{endCalc,optionTimeCalc,init}from'@/utils/TimeOnPage.js';
+
 
 import setting from '@/mixins/theme.js'
 Vue.prototype.$setting = setting;
@@ -157,7 +144,7 @@ router.beforeEach(async(to, from, next) => {
   } */
 
   let auth = localStorage.getItem("auth") || false;
-  if (to.path != "/login" && to.path!='/temppage' && !auth) {
+  if (to.path != "/login" && to.path!='/temppage' &&to.path!='/fogetpassword' && !auth) {
     window.location.href =  window.location.origin + '/login';
     return false;
   }
@@ -192,28 +179,31 @@ router.beforeEach(async(to, from, next) => {
 
 router.afterEach((to, from, next) => {
   // 改变页面标题
-  if(stores.state.TRIAL_CODE == stores.state.businessCode){
-    // 试用ETA
-    document.title = to.matched[to.matched.length-1].name ?
-    `${global.company_name}-${to.matched[to.matched.length-1].name}`: global.name
-  }else{
-    document.title = to.matched[to.matched.length - 1].name
-    ? `ETA-${to.matched[to.matched.length - 1].name}`
-    : "ETA";
-  }
+  document.title = to.matched[to.matched.length - 1].name
+  ? `${setting.name}-${to.matched[to.matched.length - 1].name}`
+  : setting.name;
 
   window.scrollTo(0, 0);
-  
-  sessionStorage.setItem('preTitle',from.name||'')
-  const routerChangeType = sessionStorage.getItem('routerChangeType')
-  if(routerChangeType==='popstate'){
-    const IsActive = sessionStorage.getItem('IsActive')
-    if(IsActive=='1'){
-      endCalc('popstate',Number(sessionStorage.getItem('popStayTime')||0))
+  if(stores.state.hasTrialUserPermisson){
+
+    sessionStorage.setItem('preTitle',from.name||'')
+
+    if(!stores.state.hasDoPageListening){
+      // 初始化需要放在 页面设置标题后,才能拿到正确的标题
+      init()
+      stores.mutations.SET_PAGE_EVENT_LISTENER(stores.state,true)
+    }
+
+    const routerChangeType = sessionStorage.getItem('routerChangeType')
+    if(routerChangeType==='popstate'){
+      const IsActive = sessionStorage.getItem('IsActive')
+      if(IsActive=='1'){
+        endCalc('popstate',Number(sessionStorage.getItem('popStayTime')||0))
+      }
+      optionTimeCalc()
+      sessionStorage.removeItem('routerChangeType')
+      sessionStorage.removeItem('popStayTime')
     }
-    optionTimeCalc()
-    sessionStorage.removeItem('routerChangeType')
-    sessionStorage.removeItem('popStayTime')
   }
 });
 

+ 1 - 1
src/mixins/index.js

@@ -9,7 +9,7 @@ const mixins = {
 			if(time==='0001-01-01 00:00:00'||time==='0000-00-00 00:00:00'){
 				return '--'
 			}else{
-				return time.replace(/-/g,'.')
+				return time?time.replace(/-/g,'.'):''
 			}
 			
 		},

+ 1 - 1
src/mixins/theme.js

@@ -2,7 +2,7 @@
 一些动态配置和一些全局自定义东西 
 */
 export default {
-	name: '后台管理系统',
+	name: 'ETA',
   theme_color: '#0052D9',
   menu_bg:'#fff',//菜单栏背景色
   //跳转外部系统

+ 19 - 7
src/routes/modules/chartRoutes.js

@@ -93,12 +93,12 @@ export default [
 			},
 			{
 				path:"addCustomSheet",
-				name:"表格编辑",
+				name:"添加表格",
 				component:()=>import('@/views/datasheet_manage/customSheetEdit.vue')
 			},
 			{
 				path:"addMixedSheet",
-				name:"表格编辑",
+				name:"添加表格",
 				component:()=>import('@/views/datasheet_manage/mixedSheetEdit.vue')
 			}
 		]
@@ -169,12 +169,20 @@ export default [
 			{
 				path: 'fittingEquationChartEditor',
 				name: '添加图表',
-				component: () => import('@/views/chartRelevance_manage/fittingEquationChartEditor.vue')
+				component: () => import('@/views/chartRelevance_manage/fittingEquationChartEditor.vue'),
+				meta: { 
+					pathFrom: "fittingEquationList",
+          			pathName: "拟合方程曲线",
+				}
 			},
 			{
 				path: 'relevancechartEditor',
-				name: '图表编辑',
-				component:()=>import('@/views/chartRelevance_manage/relevanceChartEditor.vue')
+				name: '编辑图表',
+				component:()=>import('@/views/chartRelevance_manage/relevanceChartEditor.vue'),
+				meta: { 
+					pathFrom: "chartrelevance",
+          			pathName: "相关性图表",
+				}
 			},
 			{
 				path: 'statisticFeatureList',
@@ -183,8 +191,12 @@ export default [
 			},
 			{
 				path: 'statisticFeatureChartEditor',
-				name: '图表编辑',
-				component:()=>import('@/views/chartRelevance_manage/statisticFeatureChartEditor.vue')
+				name: '编辑图表',
+				component:()=>import('@/views/chartRelevance_manage/statisticFeatureChartEditor.vue'),
+				meta: { 
+					pathFrom: "statisticFeatureList",
+          			pathName: "统计特征",
+				}
 			}
 		]
 	},

+ 5 - 1
src/routes/modules/futuresRoutes.js

@@ -20,7 +20,11 @@ export default [
       {
 				path: "addCommodityChart",
 				name: "编辑图表",
-				component: () => import('@/views/futures_manage/chartEditor.vue')
+				component: () => import('@/views/futures_manage/chartEditor.vue'),
+				meta: { 
+					pathFrom: "commordityChartBase",
+          			pathName: "商品价格曲线",
+				}
 			},
     ]
   }  

+ 23 - 1
src/routes/modules/oldRoutes.js

@@ -187,7 +187,7 @@ export default [
         path: "reportEnEditor",
         component: () =>
           import("@/views/report_manage/reportEn/reportEditor.vue"),
-        name: "英文研报编辑",
+        name: "添加英文研报",
         hidden: false,
       },
       {
@@ -300,6 +300,28 @@ export default [
         name: "基本配置",
         hidden: true,
       },
+      {
+        path: "outlinkListConfig",
+        component: () => import("@/views/system_manage/outlinkListConfig.vue"),
+        name: "外部链接配置",
+        hidden: true,
+      },
     ],
   },
+  // 外部链接
+  {    
+    path: "/",
+    component: home,
+    name: "外部链接",
+    hidden: false,
+    icon_path: require("@/assets/img/home/set_ico.png"),
+    children: [
+      {
+        path: "outlinkList",
+        component: () => import("@/views/system_manage/outlinkList.vue"),
+        name: "外部链接",
+        hidden: true,
+      },
+    ]
+  }
 ];

+ 111 - 21
src/utils/TimeOnPage.js

@@ -1,12 +1,49 @@
 //计算账号累计活跃时长
-import global from '@/config/setting';
-import {timeOnPage} from '@/api/api.js';
-
+import setting from '@/mixins/theme.js'
+import {timeOnPage , recordActiveLogin} from '@/api/api.js';
 //活跃时间间隔 (s)
 const TimeInterval = 60*10
 //页面停留时间 (s)
 let stayTime = 0
 
+
+//活跃时间记录计时器 1分钟记录一次
+let intervalTimer=null
+
+export const openLoginTimer=()=>{
+  // 登录时间
+  localStorage.setItem("loginTime",new Date())
+
+  clearInterval(intervalTimer)
+  intervalTimer = setInterval(()=>{
+    // let inactiveTime = time || new Date()
+    let ActiveTime=0
+    if(localStorage.getItem('loginTime')){
+      ActiveTime = (new Date()-new Date(localStorage.getItem('loginTime')))/1000
+      console.log("1分钟间隔记录时长",ActiveTime+'s');
+      recordActiveLogin({ActiveTime:Math.round(ActiveTime)}).then(res=>{
+        if(res.Ret!==200) return
+      })
+    }
+  },1000*60)
+}
+
+export const recordActiveLoginFun=(time)=>{
+  let inactiveTime = time || new Date()
+  let ActiveTime=0
+  if(localStorage.getItem('loginTime')){
+    ActiveTime = (inactiveTime-new Date(localStorage.getItem('loginTime')))/1000
+    console.log("结束计算时长",ActiveTime+'s');
+    recordActiveLogin({ActiveTime:Math.round(ActiveTime)}).then(res=>{
+      if(res.Ret!==200) return
+    }).finally(()=>{
+      // 清除工作
+      clearInterval(intervalTimer)
+      localStorage.removeItem('loginTime')
+    })
+  }
+}
+
 let timer = null
 
 //打开计时器
@@ -48,6 +85,15 @@ export const endCalc = (type,intervalT)=>{
   sessionStorage.setItem('IsActive',0)
 }
 
+// 退出登录时的结算
+export const loginEndCalc=()=>{
+  let t = new Date().getTime() - timeStr
+  //console.log('待了时长replacestate:'+ t)
+  const IsActive = sessionStorage.getItem('IsActive')
+  if(Number(IsActive)){
+    endCalc('logout',t)
+  }
+}
 
 //发送活跃时长数据
 export const sendTOPInfo = (type,intervalT)=>{
@@ -63,7 +109,7 @@ export const sendTOPInfo = (type,intervalT)=>{
   const Part = Title.split('-').length>1?Title.split('-')[1]:Title
   const ActiveTime = type==='timeup'?stayTime:Number(intervalT)/1000
   //发送数据
-  if(!Part.length||Part==global.name) return
+  if(!Part.length||Part==setting.name) return
   if(ActiveTime>TimeInterval*12) return
   console.log("ActiveTime:",ActiveTime,"Part:",Part)
   timeOnPage({
@@ -90,37 +136,80 @@ let rewriteHis = function(type){
   }
 }
 
+export function init(){
+  const unloadT = sessionStorage.getItem('unloadT')
+  const IsActive = sessionStorage.getItem('IsActive')
+  if(unloadT){
+    //console.log('刷新该页呆了时长',unloadT)
+    sessionStorage.removeItem('unloadT')
+    sessionStorage.setItem('preTitle',document.title)
+    if(Number(IsActive)){
+      endCalc('unload',unloadT)
+    }
+  }
+  timeStr = new Date().getTime()
+  optionTimeCalc()
+
+  if((!localStorage.getItem("loginTime")) && localStorage.getItem('auth')){
+    // 初始化的时候 先重置最近登录时长
+    recordActiveLogin({ActiveTime:0}).then(res=>{
+      if(res.Ret!==200) return
+    })
+    openLoginTimer()
+  }
+}
 
 export const doPageEventListener=function(){
+
+  // init() 放在router.afterEach中,不然一开始拿不到正确的页面标题
+
   window.history.pushState = rewriteHis('pushState')
 
   window.history.replaceState = rewriteHis('replaceState')
+
+  //刷新加载完成 
+  // 因为监听改位置了,每次路由刷新时,由于需要等待接口返回,需要先判断是否有 权限才能监听,这时候onload已经执行了,根本监听不到
+  // window.addEventListener('load',(e)=>{
+    // const unloadT = sessionStorage.getItem('unloadT')
+    // const IsActive = sessionStorage.getItem('IsActive')
+    // if(unloadT){
+    //   //console.log('刷新该页呆了时长',unloadT)
+    //   sessionStorage.removeItem('unloadT')
+    //   sessionStorage.setItem('preTitle',document.title)
+    //   if(Number(IsActive)){
+    //     endCalc('unload',unloadT)
+    //   }
+    // }
+    // timeStr = new Date().getTime()
+    // optionTimeCalc()
   
-  //刷新加载完成
-  window.addEventListener('load',(e)=>{
-    const unloadT = sessionStorage.getItem('unloadT')
-    const IsActive = sessionStorage.getItem('IsActive')
-    if(unloadT){
-      //console.log('刷新该页呆了时长',unloadT)
-      sessionStorage.removeItem('unloadT')
-      sessionStorage.setItem('preTitle',document.title)
-      if(Number(IsActive)){
-        endCalc('unload',unloadT)
-      }
-    }
-    console.log('onload')
-    timeStr = new Date().getTime()
-    optionTimeCalc()
-  })
+    // if((!localStorage.getItem("loginTime")) && localStorage.getItem('auth')){
+    //   // 初始化的时候 先重置最近登录时长
+    //   recordActiveLogin({ActiveTime:0}).then(res=>{
+    //     if(res.Ret!==200) return
+    //   })
+    //   openLoginTimer()
+    // }
+  // })
   //刷新离开页面
   window.addEventListener('beforeunload',(e)=>{
-    console.log('unload')
+    console.log('beforeunload')
     let t = new Date().getTime() - timeStr
     const IsActive = sessionStorage.getItem('IsActive')
     if(Number(IsActive)){
       sessionStorage.setItem('unloadT',t)
     }
   })
+
+  //刷新离开页面
+  window.addEventListener('unload',(e)=>{
+    console.log('unload')
+    recordActiveLoginFun()
+    // 猜测在unload这里 浏览器不会等待异步返回 清除工作在这进行
+    clearInterval(intervalTimer)
+    localStorage.removeItem('loginTime')
+  })
+
   //popstate会在router.before/afterEach 之前触发,所以这里不对计时操作,操作放到before/afterEach
   window.addEventListener('popstate',(e)=>{
     //console.log('popState',e)
@@ -177,6 +266,7 @@ export const doPageEventListener=function(){
     }
   }); */
   document.addEventListener('click',(e)=>{
+
     //console.log('click',e,e.composedPath())
     //只计算displayMain 的click
     const path = e.composedPath()

+ 8 - 0
src/utils/buttonConfig.js

@@ -454,4 +454,12 @@ export const baseConfigPermission = {
     etaBaseConfig_watermark:'etaBaseConfig:watermark',
     etaBaseConfig_watermark_ybChart:'etaBaseConfig:watermark:ybChart',//如果没权限,表单不显示也不校验
 
+}
+
+/*-----------外部链接配置-------- */
+export const outlinkConfigPermission = {
+    outlinkListConfig_list:'outlinkListConfig:list',//查看列表
+    outlinkListConfig_add:'outlinkListConfig:add',//添加
+    outlinkListConfig_edit:'outlinkListConfig:edit',//编辑
+    outlinkListConfig_del:'outlinkListConfig:del',//删除
 }

+ 47 - 0
src/utils/commonOptions.js

@@ -0,0 +1,47 @@
+
+//验证密码的正则 产品定的规则是:8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型
+export const patternPassWord = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/
+export function checkPassWord(pwd){
+    let num = 0
+    const patternArr = [
+        /^(?=.*[0-9])/,
+        /^(?=.*[a-z])/,
+        /^(?=.*[A-Z])/,
+        /^(?=.*[@#$%^&+=.])/,
+    ]
+    patternArr.forEach(pattern=>{
+        if(pattern.test(pwd)){
+            num++
+        }
+    })
+    if(pwd.length<8){
+        num = 0
+    }
+    return num>=3
+}
+//验证手机号的正则 仅支持国内大陆的
+export const patternPhone = /0?(13|14|15|18|17)[0-9]{9}/
+export function isMobileNo(account) {
+    // 手机号正则
+    var isChinaMobile = new RegExp(
+      "(^1(3[4-9]|4[78]|5[0-27-9]|7[28]|8[2-478]|98)\\d{8}$)"
+    ); // 中国移动
+    // 手机段:134,135,136,137,138,139,147,148[卫星通信],150,151,152,157,158,159,172,178,182,183,184,187,188,198
+    var isChinaUnicom = new RegExp(
+      "(^1(3[0-2]|4[56]|5[56]|66|7[156]|8[56])\\d{8}$)"
+    ); // 中国联通
+    // 手机段:130,131,132,145,146[卫星通信],155,156,166,171,175,176,185,186
+    var isChinaTelcom = new RegExp("(^1(33|49|53|7[347]|8[019]|99)\\d{8}$)"); // 中国电信
+    // 手机段:133,149,153,173,174,177,180,181,189,199
+    var isOtherTelphone = new RegExp("(^170\\d{8}$)");
+    // 虚拟运营商170号段
+    if (isChinaMobile.test(account)) {
+      return true;
+    } else if (isChinaUnicom.test(account)) {
+      return true;
+    } else if (isChinaTelcom.test(account)) {
+      return true;
+    } else return isOtherTelphone.test(account);
+  }
+//验证邮箱的正则
+export const patternEmail = /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/

+ 34 - 27
src/views/Home.vue

@@ -7,13 +7,13 @@
           <img
             class="logo"
             v-if="!isCollapse"
-            :src="isTrail?global.g_logo:$setting.g_logo"
+            :src="$setting.g_logo"
           />
           <!-- 折叠侧边栏logo尺寸 -->
           <img
             class="logo_coll"
             v-else
-            :src="isTrail?global.g_mini_logo:$setting.g_mini_logo"
+            :src="$setting.g_mini_logo"
           />
         </div>
         <div
@@ -23,7 +23,7 @@
           <aside class="menu-expanded">
             <!--导航菜单-->
             <el-menu
-              :background-color="isTrail?global.menu_bg:$setting.menu_bg"
+              :background-color="$setting.menu_bg"
               text-color="#333"
               :collapse-transition="false"
               :active-text-color="$setting.theme_color"
@@ -316,7 +316,8 @@ import PwdDlg from "@/components/pwdDlg.vue";
 import questionMsgDia from "@/components/questionMsgDia.vue";
 import questionnaireDia from "../components/questionnaireDia.vue";
 import EventBus from "@/api/bus.js";
-import global from '@/config/setting';
+
+import {recordActiveLoginFun,loginEndCalc} from "@/utils/TimeOnPage.js"
 
 export default {
   components: {
@@ -385,7 +386,7 @@ export default {
     },
 		// 是否是eta试用
     isTrail(){
-			return this.$store.state.businessCode == this.$store.state.TRIAL_CODE
+			return this.$store.state.hasTrialUserPermisson
 		}
   },
   data() {
@@ -464,7 +465,6 @@ export default {
       //链接系统
       linkSystems: this.$setting.linkSystems,
       bus_code:"",
-      global
     };
   },
   created() {
@@ -478,7 +478,7 @@ export default {
       this.isShowApprovalNotice = true;
     }
     this.resetLinkSys()
-    // this.getBusinessCodeFun()
+    this.getBusinessCodeFun()
     
     this.getQuestionStaus()
   },
@@ -493,13 +493,12 @@ export default {
   },
   methods: {
     // 获取商家Code
-    // getBusinessCodeFun(){
-      // getBusinessCode().then(res=>{
-      //   if(res.Ret!==200) return 
-      //   this.bus_code = res.Data||''
-      //   this.$store.commit("SET_BUSINESS_CODE", this.bus_code);
-      // })
-    // },
+    getBusinessCodeFun(){
+      getBusinessCode().then(res=>{
+        if(res.Ret!==200) return 
+        this.bus_code = res.Data||''
+      })
+    },
     //判断是否为初始密码
     async isInitialPwd() {
       const res = await checkPwd();
@@ -678,7 +677,6 @@ export default {
         this.questionList=[]
         return 
       }
-      // console.log(this.isTrail,'isTrail');
       homeInterface.getQuestionnaireDetail().then(res=>{
         // console.log(res);
         if(res.Ret == 200){
@@ -701,8 +699,7 @@ export default {
       // });
       // window.open(href, "_blank");
       //打开帮助文档
-      const href = `${process.env.VUE_APP_ETA_HELP_DOCS}?bus_code=${this.$store.state.businessCode}`
-      // console.log(href);
+      const href = `${process.env.VUE_APP_ETA_HELP_DOCS}?bus_code=${this.bus_code}`
       // const href = `http://192.168.77.13:3033/help/index?bus_code=${this.bus_code}`
       window.open(href, "_blank");
     },
@@ -785,21 +782,31 @@ export default {
         type: "warning",
       })
         .then(() => {
-          localStorage.setItem("auth", "");
-          localStorage.setItem("userName", "");
-          localStorage.setItem("Role", "");
-          localStorage.setItem("RoleType", "");
-          localStorage.setItem("AdminId", "");
-          localStorage.setItem("AdminName", "");
-          localStorage.setItem("ManageType", "");
-          localStorage.setItem("RoleIdentity", "");
-          that.$router.push("/login");
+          if(this.isTrail){
+            // 结算活跃计时
+            loginEndCalc()
+            // 结算登录计时
+            recordActiveLoginFun()
+          }
+          setTimeout(() => {
+            // 退出登录时可能有一些请求需要发送或者处理
+            localStorage.setItem("auth", "");
+            localStorage.setItem("userName", "");
+            localStorage.setItem("Role", "");
+            localStorage.setItem("RoleType", "");
+            localStorage.setItem("AdminId", "");
+            localStorage.setItem("AdminName", "");
+            localStorage.setItem("ManageType", "");
+            localStorage.setItem("RoleIdentity", "");
+
+            that.$router.push("/login");
+          }, 10);
         })
         .catch(() => {});
     },
     toDoc(){
       //打开更新日志项目
-      const href = `${process.env.VUE_APP_ETA_DOCS}?bus_code=${this.$store.state.businessCode}`
+      const href = `${process.env.VUE_APP_ETA_DOCS}?bus_code=${this.bus_code}`
       window.open(href, "_blank");
     },
     collapseHandle () {

+ 446 - 158
src/views/Login.vue

@@ -1,10 +1,10 @@
 <template>
-  <div id="login">
+	<div id="login">
 		<div id="login_wrapper">
       
-			<img class="login-bg" :src="isTrail?global.login_bg:$setting.login_bg" alt />
-      <img class="login-icon" :src="isTrail?global.login_logo:$setting.login_logo" v-if="isTrail?global.login_logo:$setting.login_logo">
-			<el-form
+            <img class="login-bg" :src="$setting.login_bg" alt />
+            <img class="login-icon" :src="$setting.login_logo" />
+			<!-- <el-form
 				:model="ruleForm"
 				:rules="rules"
 				ref="ruleForm"
@@ -63,176 +63,464 @@
 						>登录</el-button
 					>
 				</el-form-item>
-			</el-form>
+			</el-form>  -->
+			<div class="login-box" id="login-container" v-if="activeModel!=='forgetPassModel'">
+				<span class="login-title">ETA — 让投研领先市场半步</span>
+				<el-tabs v-model="activeModel" @tab-click="handleClick">
+					<el-tab-pane label="账号登录" name="ordinaryModel">
+						<OrdinaryModel ref="ordinaryModel"
+							:loginCheck="loginCheck"
+							:accountCheck="accountCheck"
+							@clearnHint="clearnHint"
+							@changeModel="changeModel('forgetPassModel')"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="手机号登录" name="mobileModel">
+						<MobileModel ref="mobileModel"
+							:areaCode="areaCode"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="邮箱登录" name="emailModel">
+						<EmailModel ref="emailModel"/>
+					</el-tab-pane>
+				</el-tabs>
+				<el-button
+					type="primary"
+					size="medium"
+					@click.native="handleLogin"
+					:loading="logining"
+					class="submit_btn"
+					>登录</el-button>
+			</div>
+			<div class="login-box" v-else>
+				<ForgetPassModel 
+					ref="forgetPassModel"
+					:autoAccount="$refs.ordinaryModel?$refs.ordinaryModel.form.account:''"
+					@changeModel="changeModel('ordinaryModel')"/>
+			</div>
 		</div>
+		<!-- 验证弹窗 -->
+		<el-dialog
+			class="check-dialog"
+			:visible.sync="isCheckDialogShow"
+			:close-on-click-modal="false"
+			:modal-append-to-body="false"
+			width="30%"
+			@close="isCheckDialogShow = false"
+			>
+			<el-tabs v-model="checkActiveModel" @tab-click="handleClick">
+				<el-tab-pane label="手机号验证" name="checkMobileModel">
+						<MobileModel ref="checkMobileModel"
+							:areaCode="areaCode"
+						/>
+					</el-tab-pane>
+					<el-tab-pane label="邮箱验证" name="checkEmailModel">
+						<EmailModel ref="checkEmailModel"/>
+					</el-tab-pane>
+			</el-tabs>
+			<span slot="footer" class="dialog-footer">
+				<el-button 
+					type="primary" 
+					:loading="checkLogining"
+					@click="submitCheck">提 交</el-button>
+			</span>
+		</el-dialog>
 	</div>
 </template>
 
 <script>
-import { userLogin, departInterence } from "@/api/api.js";
+import { userLogin, departInterence,recordActiveLogin } from "@/api/api.js";
 import http from "@/api/http.js";
 import md5 from "@/utils/md5.js";
-import global from '@/config/setting'
+
+import EmailModel from "./login_manage/EmailModel.vue";
+import ForgetPassModel from "./login_manage/ForgetPassModel.vue";
+import MobileModel from "./login_manage/MobileModel.vue";
+import OrdinaryModel from "./login_manage/OrdinaryModel.vue";
+
 export default {
+    components: { OrdinaryModel, MobileModel, EmailModel, ForgetPassModel },
   data() {
     return {
-			global,
-      b: new http.Base64(),
-      logining: false, //登录loadding
-      ruleForm: {
-        account: "",
-        checkPass: "",
-      },
-      rules: {
-        account: [
-          {
-            required: true,
-            message: "请输入用户名",
-            trigger: "blur",
-          },
-        ],
-        checkPass: [
-          {
-            required: true,
-            message: "请输入密码",
-            trigger: "blur",
-          },
-        ],
-      },
-      checked: false, //是否保持登录状态
-      visible: true, //密码输入类型
-    };
-  },
-	computed: {
-		// 是否是eta试用
-    isTrail(){
-			return this.$store.state.businessCode == this.$store.state.TRIAL_CODE
-		}
-  },
-  created() {
-    this.keyupSubmit(); //回车登录
-    let userAccount = localStorage.getItem("account") || null;
-    let userCheckPass = localStorage.getItem("checkPass") || null;
-    if (userAccount) {
-      this.ruleForm.account = this.b.decode(userAccount);
-      this.ruleForm.checkPass = this.b.decode(userCheckPass);
-      this.checked = true;
-    }
-  },
-  methods: {
-    keyupSubmit() {
-      //回车登录
-      document.onkeydown = (e) => {
-        let keyval = window.event.keyCode;
-        if (keyval === 13) {
-          this.handleSubmit2();
-        }
-      };
+        b: new http.Base64(),
+        logining: false, //登录loadding
+        ruleForm: {
+            account: "",
+            checkPass: "",
+        },
+        rules: {
+            account: [
+            {
+                required: true,
+                message: "请输入用户名",
+                trigger: "blur",
+            },
+            ],
+            checkPass: [
+            {
+                required: true,
+                message: "请输入密码",
+                trigger: "blur",
+            },
+            ],
+        },
+        checked: false, //是否保持登录状态
+        visible: true, //密码输入类型
+
+        activeModel: 'ordinaryModel',
+        /* form check 错误提示标识*/
+        loginCheck:false, //账号或密码错误
+        accountCheck:false,//账号异常:多次输错密码、长时间未登录
+        accountForbidden:false,//账号被禁用
+        mobileCheck:false,//手机号未绑定
+        emailCheck:false,//邮箱未绑定
+        areaCode:[],
+
+        isCheckDialogShow:false,
+        checkActiveModel:'checkMobileModel'
+        };
     },
-    handleSubmit2() {
-      //登录
-      let that = this;
-      this.$refs.ruleForm.validate((valid) => {
-        if (valid) {
-          that.logining = true;
-          var loginParams = {
-            Username: that.ruleForm.account,
-            Password: md5.hex_md5(that.ruleForm.checkPass),
-            IsRemember: this.checked,
-          };
-          userLogin(loginParams).then(async (res) => {
-            if (res.Ret === 200) {
-              localStorage.setItem("auth", res.Data.Authorization);
-              localStorage.setItem("userName", res.Data.RealName);
-              localStorage.setItem("Role", res.Data.RoleTypeCode);
-              localStorage.setItem("RoleIdentity", res.Data.SysRoleTypeCode);
-              localStorage.setItem("RoleType", res.Data.ProductName);
-              localStorage.setItem("ManageType", res.Data.Authority);
-              localStorage.setItem("AdminId", res.Data.AdminId);
-              localStorage.setItem("AdminName", res.Data.AdminName);
-              if (this.checked) {
-                localStorage.setItem(
-                  "account",
-                  this.b.encode(this.ruleForm.account)
-                );
-                localStorage.setItem(
-                  "checkPass",
-                  this.b.encode(this.ruleForm.checkPass)
-                );
-              } else {
-                localStorage.removeItem("account");
-                localStorage.removeItem("checkPass");
-              }
+    created() {
+        this.keyupSubmit(); //回车登录
+        this.getPhoneCode();//获取手机号区号
+    },
+    mounted(){
+        this.getRememberedInfo()
+    },
+    methods: {
+        keyupSubmit() {
+            //回车登录
+            document.onkeydown = (e) => {
+                let keyval = window.event.keyCode;
+                if (keyval === 13) {
+                    //this.handleSubmit2();
+                    !this.logining&&this.handleLogin()
+                }
+            };
+        },
+        handleSubmit2() {
+            //登录
+            let that = this;
+            this.$refs.ruleForm.validate((valid) => {
+                if (valid) {
+                    that.logining = true;
+                    var loginParams = {
+                        Username: that.ruleForm.account,
+                        Password: md5.hex_md5(that.ruleForm.checkPass),
+                        IsRemember: this.checked,
+                    };
+                    userLogin(loginParams).then(async (res) => {
+                        if (res.Ret === 200) {
+                            localStorage.setItem("auth", res.Data.Authorization);
+                            localStorage.setItem("userName", res.Data.RealName);
+                            localStorage.setItem("Role", res.Data.RoleTypeCode);
+                            localStorage.setItem("RoleIdentity", res.Data.SysRoleTypeCode);
+                            localStorage.setItem("RoleType", res.Data.ProductName);
+                            localStorage.setItem("ManageType", res.Data.Authority);
+                            localStorage.setItem("AdminId", res.Data.AdminId);
+                            localStorage.setItem("AdminName", res.Data.AdminName);
+                            if (this.checked) {
+                                localStorage.setItem("account", this.b.encode(this.ruleForm.account));
+                                localStorage.setItem("checkPass", this.b.encode(this.ruleForm.checkPass));
+                            }
+                            else {
+                                localStorage.removeItem("account");
+                                localStorage.removeItem("checkPass");
+                            }
+                            let path = "";
+                            switch (res.Data.RoleTypeCode) {
+                                case "rai_researcher":
+                                case "ficc_researcher":
+                                case "researcher":
+                                    path = "/reportlist";
+                                    break;
+                                case "compliance": //合规
+                                    path = "/contractapprovallist";
+                                    break;
+                                case "special_researcher": //特邀研究员
+                                    path = "/dataList";
+                                    break;
+                                case "special_ficc_seller":
+                                    path = "/meetingCalendar";
+                                    break;
+                                default:
+                                    path = await this.getOtherRolePath("myCalendar");
+                            }
+                            this.$router.push({ path });
+                        }
+                        that.logining = false;
+                    });
+                }
+            });
+        },
+        changePass(value) {
+            //密码输入格式切换
+            this.visible = !(value === "show");
+        },
+        getOtherRolePath(pathVal) {
+            return departInterence.getMenu().then((res) => {
+                let resolvePath = "";
+                if (res.Ret === 200) {
+                    let menuList = res.Data.List || [];
+                    if (!menuList.length) {
+                        this.$message.error('该账号没有任何菜单权限,请联系管理员');
+                        return;
+                    }
+                    // 是否已经拿到菜单信息
+                    sessionStorage.setItem("hasGetMenu", "true");
+                    sessionStorage.setItem("MenuList", JSON.stringify(menuList));
+                    /* 是否有数据报表权限 */
+                    this.$store.commit("SET_DATA_AUTH", menuList.some((item) => item.name === "数据报表"));
+                    for (let i = 0; i < menuList.length; i++) {
+                        const arr = menuList[i].children || [];
+                        if (arr.some(it => it.path == pathVal)) {
+                            resolvePath = "/" + pathVal;
+                            break;
+                        }
+                    }
+                    return resolvePath || "/" + menuList[0].children[0].path;
+                }
+                return "/" + pathVal;
+            });
+        },
+        getPhoneCode(){
+            departInterence.getPhoneAreaCode().then(res=>{
+                if(res.Ret!==200) return 
+                this.areaCode = res.Data||[]
+            })
+        },
+        handleClick(tab) {
+            //调用对应model的init方法
+            this.$refs[tab.name]&&this.$refs[tab.name].modelInit()
+            this.$refs[tab.name]&&this.$refs[tab.name].$refs.modelForm.clearValidate()
+            if(tab.name==='ordinaryModel'){
+                this.$nextTick(()=>{
+                    this.getRememberedInfo()
+                })
+            }
+        },
+        changeModel(model){
+            this.activeModel = model
+            if(model!=='forgetPassModel'){
+                this.$nextTick(()=>{
+                    this.getRememberedInfo()
+                })
+            }
+        },
+        handleLogin(){
+            //先进行判空的表单验证
+            this.$refs[this.activeModel].$refs.modelForm.validate((valid)=>{
+                if(valid){
+                    this.logining = true
+                    //根据activeName 调用不同的登陆接口
+                    //账号密码
+                        if(this.activeModel==='ordinaryModel'){
+                            this.ordinaryModelLogin()
+                        }
+                    //手机号登录
+                        if(this.activeModel==='mobileModel'){
+                            this.mobileModelLogin()
+                        }
+                    //邮箱登录
+                        if(this.activeModel==='emailModel'){
+                            this.emailModelLogin()
+                        }
+                }
+            })
+        },
+        submitCheck(){
+            this.$refs[this.checkActiveModel].$refs.modelForm.validate((valid)=>{
+                if(valid){
+                    this.checkLogining = true
+                    if(this.checkActiveModel==='checkMobileModel'){
+                        this.mobileModelLogin('checkMobileModel')
+                    }else{
+                        this.emailModelLogin('checkEmailModel')
+                    }
+                }
+            })
+        },
+        ordinaryModelLogin(){
+            const {account,checkPass,checked} = this.$refs.ordinaryModel.form
+            departInterence.userLogin({
+                LoginType:1,
+                Username:account,
+                Password:md5.hex_md5(checkPass)
+            }).then(res=>{
+                //this.logining = false
+                //账号异常 将accountCheck置为true
+                if(res.Ret===4011){
+                    this.accountCheck = true
+                    this.isCheckDialogShow = true
+                    this.$nextTick(()=>{
+                        this.$refs[this.checkActiveModel].getCodePic()
+                    })
+                }
+                //账号密码错误 将loginCheck置为true
+                if(res.Ret===4012){
+                    this.loginCheck = true
+                }
+                if(res.Ret!==200){
+                    this.logining = false
+                    return 
+                }
+                //登录成功,若设置了保存密码,在localStorage内存储一个时间戳
+                if(checked){
+                    this.setLoginDate(1)
+                    localStorage.setItem("account", this.b.encode(account));
+                    localStorage.setItem("checkPass", this.b.encode(checkPass));
+                }else {
+                    this.setLoginDate(0)
+                    localStorage.removeItem("account");
+                    localStorage.removeItem("checkPass");
+                }
+                this.setLoginInfo(res)
+                this.loginSys(res)
+            })
+        },
+        mobileModelLogin(model='mobileModel'){
+            const {mobile,checkCode} = this.$refs[model].form
+            departInterence.userLogin({
+                LoginType:2,
+                Mobile:mobile,
+                VerifyCode:checkCode
+            }).then(res=>{
+                if(res.Ret!==200){
+                    //刷新图形验证码
+                    this.$refs[model].getCodePic()
+                    this.$refs[model].form.picCode = ''
+                    model==='mobileModel'&&(this.logining = false)
+                    model!=='mobileModel'&&(this.checkLogining = false)
+                    return
+                }
+                this.setLoginInfo(res)
+                this.loginSys(res)
+            })
+        },
+        emailModelLogin(model='emailModel'){
+            const {email,checkCode} = this.$refs[model].form
+            departInterence.userLogin({
+                LoginType:3,
+                Email:email,
+                VerifyCode:checkCode
+            }).then(res=>{
+                if(res.Ret!==200){
+                    //刷新图形验证码
+                    this.$refs[model].getCodePic()
+                    this.$refs[model].form.picCode = ''
+                    model==='emailModel'&&(this.logining = false)
+                    model!=='emailModel'&&(this.checkLogining = false)
+                    return
+                }
+                this.setLoginInfo(res)
+                this.loginSys(res)
+            })
+        },
+        clearnHint(){
+            this.loginCheck = false
+            this.accountCheck = false
+        },
+        setLoginDate(type){
+            if(type===0){
+                localStorage.removeItem('timeKey')
+            }else{
+                localStorage.setItem('timeKey',Date.now())
+            }
 
-              let path = "";
-              switch (res.Data.RoleTypeCode) {
+        },
+        //判断timeKey有没有过期,目前设定的是60天,也就是5184000秒
+        checkTimeKey(timeKey){
+            const nowKey = Date.now()
+            return Math.floor((nowKey-timeKey)/1000)<5184000
+        },
+        //存储登录的信息
+        setLoginInfo(res){
+            localStorage.setItem("auth", res.Data.Authorization);
+            localStorage.setItem("userName", res.Data.RealName);
+            localStorage.setItem("Role", res.Data.RoleTypeCode);
+            localStorage.setItem("RoleIdentity", res.Data.SysRoleTypeCode);
+            localStorage.setItem("RoleType", res.Data.ProductName);
+            localStorage.setItem("ManageType", res.Data.Authority);
+            localStorage.setItem("AdminId", res.Data.AdminId);
+            localStorage.setItem("AdminName", res.Data.AdminName);
+        },
+        //根据角色判断应该进入系统的哪个页面,进入系统
+        async loginSys(res){
+            let path = ''
+            switch (res.Data.RoleTypeCode) {
                 case "rai_researcher":
                 case "ficc_researcher":
                 case "researcher":
-                  path = "/reportlist";
-                  break;
+                    path = "/reportlist";
+                    break;
                 case "compliance": //合规
-                  path = "/contractapprovallist";
-                  break;
+                    path = "/contractapprovallist";
+                    break;
                 case "special_researcher": //特邀研究员
-                  path = "/dataList";
-                  break;
+                    path = "/dataList";
+                    break;
                 case "special_ficc_seller":
-                  path = "/meetingCalendar";
-                  break;
+                    path = "/meetingCalendar";
+                    break;
                 default:
-                  path = await this.getOtherRolePath("myCalendar");
-              }
-              this.$router.push({ path });
+                    path = await this.getOtherRolePath("myCalendar");
             }
-            that.logining = false;
-          });
-        }
-      });
-    },
-    changePass(value) {
-      //密码输入格式切换
-      this.visible = !(value === "show");
-    },
-    getOtherRolePath(pathVal) {
-      return departInterence.getMenu().then((res) => {
-        let resolvePath = "";
-        if (res.Ret === 200) {
-          let menuList = res.Data.List || [];
-          if(!menuList.length){
-						this.$message.error('该账号没有任何菜单权限,请联系管理员')
-						return
-					}
-
-          // 是否已经拿到菜单信息
-          sessionStorage.setItem("hasGetMenu", "true");
-          sessionStorage.setItem("MenuList", JSON.stringify(menuList));
-          /* 是否有数据报表权限 */
-          this.$store.commit(
-            "SET_DATA_AUTH",
-            menuList.some((item) => item.name === "数据报表")
-          );
-
-          for (let i = 0; i < menuList.length; i++) {
-            const arr=menuList[i].children||[]
-						
-						if(arr.some(it => it.path == pathVal)){
-              resolvePath = "/" + pathVal;
-              break;
+            path&&this.$router.push({ path });
+            this.loading = false
+            this.checkLogining = false
+        },
+        //获取用户记住的账号密码 如果有
+        getRememberedInfo(){
+            const timeKey = localStorage.getItem("timeKey")
+            if(timeKey&&this.checkTimeKey(Number(timeKey))){
+                let userAccount = localStorage.getItem("account") || null;
+                let userCheckPass = localStorage.getItem("checkPass") || null;
+                if (userAccount) {
+                    this.$refs.ordinaryModel.form = {
+                        account:this.b.decode(userAccount),
+                        checkPass:this.b.decode(userCheckPass),
+                        checked:true
+                    }
+                }
             }
-          }
-          return resolvePath || "/" + menuList[0].children[0].path;
         }
-        return "/" + pathVal;
-      });
     },
-  },
-  destroyed() {
-    document.onkeydown = null;
-  },
+    destroyed() {
+        document.onkeydown = null;
+    }
 };
 </script>
 
+<style lang="scss">
+#login{
+	.el-tabs__nav {
+		width: 100%;
+		display: flex;
+	}
+	.el-tabs__item{
+		font-size: 18px;
+		flex: 1;
+		text-align: center;
+	}
+	.check-dialog{
+		.el-dialog{
+			border-radius: 8px;
+			.el-dialog__header{
+				background-color: transparent;
+				.el-dialog__headerbtn>i{
+					color: #C0C4CC;
+				}
+			}
+			.el-input{
+				width:100%;
+			}
+			.el-dialog__footer{
+				text-align: center;
+			}
+		}
+	}
+}
+</style>
 <style lang="scss" scoped>
 #login {
 	width: 100%;
@@ -258,22 +546,22 @@ export default {
 
 		.login-icon {
 			position: absolute;
-      top: 40px;
+			top: 40px;
 			right: 40px;
 		}
 		.login-title {
 			color: #333;
-			font-size: 30px;
+			font-size: 38px;
 			display: block;
-      text-align: center;
-			margin-bottom: 30px;
+			text-align: center;
+			margin-bottom: 60px;
 		}
 
-		#login-container {
+		#login-container ,.login-box{
 			box-sizing: border-box;
 			border-radius: 10px;
 			position: absolute;
-			top: 31%;
+			top: 27%;
 			right: 12%;
 			z-index: 100;
 			input::-webkit-input-placeholder {
@@ -284,7 +572,7 @@ export default {
 			}
 			.submit_btn {
 				width: 100%;
-				height: 60px;
+				height: 50px;
 				background: #3654C1;
 				font-size: 20px;
 				border-radius: 5px;
@@ -337,15 +625,15 @@ export default {
 			.login-bg{ 
 				display: block;
 			}
-			#login-container {
-				width: 31%;
+			#login-container ,.login-box{
+				width: 33%;
 			}
 		}
 		@media screen and (max-width: 1200px){
 			.login-bg{ 
 				display: none; 
 			}
-			#login-container {
+			#login-container ,.login-box{
 				width: 70%;
 			}
 		}

+ 8 - 0
src/views/chartRelevance_manage/fittingEquationChartEditor.vue

@@ -361,6 +361,14 @@ export default {
 	},
 	destroyed() {
 		window.removeEventListener('resize', this.reloadRightWid);
+	},
+	beforeRouteEnter(to, from, next) {
+		if(to.query.code){
+			to.matched[1].name='编辑图表'
+		}else{
+			to.matched[1].name='添加图表'
+		}
+		next()
 	}
 };
 </script>

+ 2 - 2
src/views/chartRelevance_manage/fittingEquationList.vue

@@ -392,7 +392,7 @@ export default {
 
 		/* 添加一级目录 */
 		addLevelOneHandle() {
-			this.dialog_title = '添加';
+			this.dialog_title = '添加图表分类';
 			this.classifyForm = {
 				classify_name: '',
 			}
@@ -402,7 +402,7 @@ export default {
     /* 编辑节点 */
     editNode(node, { ChartClassifyName,ChartClassifyId }) {
 
-      this.dialog_title = '编辑';
+      this.dialog_title = '编辑图表分类';
       /* 编辑目录 */
       this.classifyForm = {
         classify_name: ChartClassifyName,

+ 2 - 2
src/views/chartRelevance_manage/list.vue

@@ -464,7 +464,7 @@ export default {
 
     /* 添加一级目录 */
     addLevelOneHandle() {
-      this.dialog_title = "添加";
+      this.dialog_title = "添加图表分类";
       this.classifyForm = {
         classify_name: "",
       };
@@ -473,7 +473,7 @@ export default {
 
     /* 编辑节点 */
     editNode(node, { ChartClassifyName, ChartClassifyId }) {
-      this.dialog_title = "编辑";
+      this.dialog_title = "编辑图表分类";
       /* 编辑目录 */
       this.classifyForm = {
         classify_name: ChartClassifyName,

+ 8 - 0
src/views/chartRelevance_manage/relevanceChartEditor.vue

@@ -398,6 +398,14 @@ export default {
       };
     },
   },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.code){
+      to.matched[1].name='编辑图表'
+    }else{
+      to.matched[1].name='添加图表'
+    }
+    next()
+  },
   data() {
     return {
       chart_code: this.$route.query.code || '',

+ 8 - 0
src/views/chartRelevance_manage/statisticFeatureChartEditor.vue

@@ -586,6 +586,14 @@ export default {
   },
   destroyed() {
     window.removeEventListener('resize', this.reloadRightWid);
+  },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.code){
+      to.matched[1].name='编辑图表'
+    }else{
+      to.matched[1].name='添加图表'
+    }
+    next()
   }
 };
 </script>

+ 2 - 2
src/views/chartRelevance_manage/statisticFeatureList.vue

@@ -371,7 +371,7 @@ export default {
 
 		/* 添加一级目录 */
 		addLevelOneHandle() {
-			this.dialog_title = '添加';
+			this.dialog_title = '添加图表分类';
 			this.classifyForm = {
 				classify_name: '',
 			}
@@ -381,7 +381,7 @@ export default {
     /* 编辑节点 */
     editNode(node, { ChartClassifyName,ChartClassifyId }) {
 
-      this.dialog_title = '编辑';
+      this.dialog_title = '编辑图表分类';
       /* 编辑目录 */
       this.classifyForm = {
         classify_name: ChartClassifyName,

+ 1 - 1
src/views/classify_manage/classifyEnlist.vue

@@ -420,7 +420,7 @@ export default {
 
     editHandle({ClassifyName,Id,ParentId,Sort,ClassifyType}) {
       this.classifyForm = {
-        title: '编辑英文分类',
+        title: '编辑分类',
         show: true,
         classify_name: ClassifyName,
         parent_id: ParentId,

+ 2 - 2
src/views/classify_manage/classifylist.vue

@@ -63,10 +63,10 @@
 		  	</el-col>
 		</el-card>
 		<!-- 添加分类弹框 -->
-		<el-dialog :modal-append-to-body='false' :title="isadd?'新增分类':'编辑分类'" :visible.sync="aeDialog" :close-on-click-modal="false" :center="true" v-dialogDrag custom-class="dialogclassLog" width="700px">
+		<el-dialog :modal-append-to-body='false' :title="isadd?'添加分类':'编辑分类'" :visible.sync="aeDialog" :close-on-click-modal="false" :center="true" v-dialogDrag custom-class="dialogclassLog" width="700px">
 			<div slot="title" style="display:flex;alignItems:center;">
 				<img :src="isadd?$icons.add:$icons.edit" style="color:#fff;width:16px;height:16px;marginRight:5px;">
-				<span style="fontSize:16px;">{{isadd?'新增分类':'编辑分类'}}</span>
+				<span style="fontSize:16px;">{{isadd?'添加分类':'编辑分类'}}</span>
 			</div>
 			<el-form :model="aeForm" :rules="aerules" ref="aeForm" label-position="right" label-width="140px" class="demo-aeForm" id="login-container" @submit.native.prevent>
 				<el-form-item prop="classify_name" label="分类名称">

+ 23 - 10
src/views/dataEntry_manage/chartSetting.vue

@@ -900,7 +900,14 @@ export default {
           let node = document.getElementById(`node${this.select_node}`);
           let parent = document.getElementsByClassName('tree-cont')[0];
 
-          if(node.offsetTop > parent.offsetHeight) {
+          //parent可视区间:[scrollTop,scrollTop+offsetHeight]
+          //node位置:node.offsetTop
+          const overTop = node.offsetTop+node.clientHeight+15<parent.scrollTop
+          const overBottom = node.offsetTop+node.clientHeight+15>parent.scrollTop+parent.offsetHeight
+          if(overTop){
+              parent.scrollTop = node.offsetTop-30
+          }
+          if(overBottom){
             parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
           }
         },400)
@@ -2094,15 +2101,21 @@ export default {
       this.selected_chartid = id;
 
       //滚动到高亮节点位置
-			setTimeout(() => {
-        this.$refs.treeRef.setCurrentKey(this.select_node);
-        let node = document.getElementById(`node${this.select_node}`);
-        let parent = document.getElementsByClassName('tree-cont')[0];
-
-        if(node.offsetTop > parent.offsetHeight) {
-          parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
-        }
-      },400)
+        setTimeout(() => {
+            this.$refs.treeRef.setCurrentKey(this.select_node);
+            let node = document.getElementById(`node${this.select_node}`);
+            let parent = document.getElementsByClassName('tree-cont')[0];
+            //parent可视区间:[scrollTop,scrollTop+offsetHeight]
+            //node位置:node.offsetTop
+            const overTop = node.offsetTop+node.clientHeight+15<parent.scrollTop
+            const overBottom = node.offsetTop+node.clientHeight+15>parent.scrollTop+parent.offsetHeight
+            if(overTop){
+                parent.scrollTop = node.offsetTop-30
+            }
+            if(overBottom){
+                parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
+            }
+        },400)
     },
     
     /* 根据图表id 查找对象 */

+ 25 - 12
src/views/dataEntry_manage/codecount/index.vue

@@ -82,7 +82,20 @@
 							label-width="100px"
 						>
 							<el-form-item label="数据来源">
-								<el-select 
+
+								<el-cascader
+								v-model="fromType"
+								:options="allFromArr"
+								:props="{
+									label: 'SourceName',
+									value: 'EdbSourceId',
+									children: 'Child',
+									emitPath: false
+								}"
+								clearable
+								style="width:220px"
+								placeholder="请选择来源"/>
+								<!-- <el-select 
 								v-model="fromType" 
 								placeholder="请选择来源"
 								style="width:220px">
@@ -92,7 +105,7 @@
 										:label="item.name"
 										:value="item.key">
 									</el-option>
-								</el-select>
+								</el-select> -->
 							</el-form-item>
 							<el-form-item label="指标名称/ID">
 								<el-select
@@ -152,7 +165,7 @@
 import { dataBaseInterface } from '@/api/api.js';
 import { unitArr } from '@/utils/defaultOptions';
 import storage from '@/utils/storage.js';
-import { allFromArr } from '../databaseComponents/util';
+// import { allFromArr } from '../databaseComponents/util';
 import codeMirror from './compoments/codeMirror';
 import dataTable from './compoments/dataTable';
 import { mapState } from 'vuex';
@@ -170,7 +183,7 @@ export default {
 			formData: {},
 			fromType:"",
 			unitArr,
-			allFromArr,//所有指标来源
+			allFromArr:[],//所有指标来源
 			frequencyArr:['日度','周度','旬度','月度','季度','年度'],
 			menuOptions:[],//目录数组
 
@@ -405,16 +418,16 @@ export default {
 			this.searchApi(this.current_search,++this.search_page);
 		},
 		getTargetSource(){
-			this.allFromArr = []
-			dataBaseInterface.getDataSource().then(res=>{
+			dataBaseInterface.getCodecountEdbSources().then(res=>{
 				if(res.Ret!==200) return
 				if(res.Data){
-					this.allFromArr = res.Data.map(i=>{
-						return {
-							name:i.SourceName,
-							key:i.EdbSourceId
-						}
-					})
+					this.allFromArr = res.Data.map(_ => ({
+						..._,
+						Child: _.Child.map(_item => ({
+							..._item,
+							Child:null
+						}))
+					}))
 				}
 			})
 		}

+ 2 - 8
src/views/dataEntry_manage/databaseComponents/addTargetDiaBase.vue

@@ -4,7 +4,7 @@
 			@close="cancelHandle" custom-class="dialog" top="11vh" center width="1200px" v-dialogDrag>
 			<div slot="title" style="display:flex;alignItems:center;">
 				<img :src="$icons.add" style="color:#fff;width:16px;height:16px;marginRight:5px;">
-				<span style="fontSize:16px;">新增指标</span>
+				<span style="fontSize:16px;">添加指标</span>
 			</div>
 			<div class="dialog-top">
 				<div>
@@ -110,15 +110,9 @@ export default {
 			search_company_txt: ''
 		};
 	},
-	computed: {
-		// 是否是eta试用
-    isTrail(){
-			return this.$store.state.businessCode == this.$store.state.TRIAL_CODE
-		}
-  },
 	methods: {
 		init() {
-			this.fromType = this.isTrail?'同花顺':'wind'
+			this.fromType = 'wind'
 			this.status = ''
 			this.tableData = []
 			this.dataList = []

+ 780 - 0
src/views/dataEntry_manage/databaseComponents/chartTrendRender.vue

@@ -0,0 +1,780 @@
+<template>
+	<div class="chart-trend-render">
+		<div class="header">
+			<template v-if="chart_type===1">
+				<el-button
+					type="primary"
+					v-for="item in yearSelector"
+					:key="item.value"
+					size="mini"
+					:plain="item.value !== year_select"
+					class="year-btn"
+					@click.native="changeYear(item)"
+					>{{ item.name }}</el-button
+				>
+				<el-button type="primary" plain size="mini" class="btn-sty" @click="openDateDia">{{
+					dateTip
+				}}</el-button>
+				<el-button type="primary" plain size="mini" class="btn-sty" @click="showOnChart('toggle')" v-if="!isOnlyShowBaseChart">
+					<!-- <i class="el-icon-view"></i> -->
+					{{ isShowOnyearData ? '隐藏同比图' : '展示同比图'}}
+				</el-button>
+			</template>
+			<!-- 季节图时间选择 -->
+			<template v-else-if="chart_type===2">
+				<date-picker
+						v-model="season_year"
+						type="month"
+						value-type="format"
+						range
+						placeholder="年份日期选择"
+						@change="getDataByPath"
+				/>
+			</template>
+			<el-button type="primary" plain size="mini" class="btn-sty" style="margin-left:auto;"
+				@click="chartTypeChange" v-if="!isOnlyShowBaseChart">
+				<i class="el-icon-sort" style="transform: rotate(90deg);"></i>
+				切换{{chart_type==1?'季节性图':'曲线图'}}
+			</el-button>
+		</div>
+		<div class="min-wrapper">
+			<div class="chartWrapper" id="chartWrapper" v-if="showChart">
+				<Chart :options="options" ref="chartRef" @clickYAxisTitle="clickYAxisTitle"/>
+				<div class="range-cont left" v-if="leftIndex != -1">
+					<el-input
+						style="width: 80px; display: block"
+						size="mini"
+						type="number"
+						placeholder="上限"
+						v-model="chartInfo.MaxValue"
+						@change="() => { chart_type===1?setOptions():setSeasonOptions() }"
+					/>
+					<el-input
+						class="min-data-input"
+						size="mini"
+						type="number"
+						placeholder="下限"
+						v-model="chartInfo.MinValue"
+						@change="() => { chart_type===1?setOptions():setSeasonOptions() }"
+					/>
+				</div>
+				<div class="range-cont right" v-if="isShowOnyearData">
+					<el-input
+						style="width: 80px; display: block"
+						size="mini"
+						type="number"
+						placeholder="上限"
+						v-model="limitData.rightMax"
+						@change="changeLimit"
+					/>
+					<el-input
+						class="min-data-input"
+						size="mini"
+						type="number"
+						placeholder="下限"
+						v-model="limitData.rightMin"
+						@change="changeLimit"
+					/>
+				</div>
+				<!-- 公历农历切换 只用于季节性图 -->
+				<div style="text-align:center;">
+					<el-radio-group
+							v-model="calendar_type"
+							class="calendar-cont"
+							v-if="chart_type===2"
+							@change="getDataByPath"
+					>
+							<el-radio-button label="公历" />
+							<el-radio-button label="农历" />
+					</el-radio-group>
+				</div>
+			</div>
+		</div>
+		<div class="table-data">
+
+		</div>
+		<!-- 自定义时间段选择弹窗 -->
+		<DateChooseDia
+			:isDateDia="isDateDia"
+			:dateForm="dateForm"
+			@cancel="isDateDia = false"
+			@dateBack="dataChangeBack"
+		/>
+	</div>
+</template>
+
+<script>
+import { dataBaseInterface } from '@/api/api.js';
+import * as supplyApi from '@/api/modules/supplyApi.js';
+import { yearSelector,defaultOpts,seasonOptions } from '@/utils/defaultOptions'
+import Chart from '../components/chart'
+import DateChooseDia from '../components/DateChooseDia';
+import Highcharts from 'highcharts'
+export default {
+	components: { Chart,DateChooseDia },
+	props: {
+		edbid: {
+			type: Number,
+		},
+		// 语言 ch/en
+		chartLang:{
+			type: String,
+			default:()=> 'ch'
+		}
+	},
+	computed: {
+
+		// 同比,环比,环差,超季节性、 残差展示基础图
+		isOnlyShowBaseChart() {
+			return [6,12,13,35,37].includes(this.chartInfo.Source)
+		}
+	},
+	watch: {
+		edbid:{
+			handler(newVal){
+				console.log('??')
+				if(newVal){
+					this.chart_type = 1
+					this.isShowOnyearData = false
+					this.getDataByPath()
+				}
+			},
+			immediate:true
+		}
+	},
+	data () {
+		return {
+			year_select: 10, //年份选择项 默认全部
+			yearSelector: [
+				{
+					name: '全部',
+					value: 10,
+				},
+				...yearSelector,
+			],
+			select_date: [], // 自定义时间段项
+
+			options: {},
+			showChart: false,
+			chart_type: 1,// 1曲线 2季节
+			isShowOnyearData: false, //是否展示同比
+			chartInfo: {},
+			dataList: [],
+			leftIndex: 0,
+
+			season_year:[],//季节图日期选择
+			calendar_type:'公历',
+
+			/* 日期弹窗 */
+			isDateDia: false, // 时间段弹窗
+			dateForm: {},
+			dateTip: '请选择时间段',
+			limitData: {
+				letMin: 0,
+				leftMax: 0,
+				rightMin: 0,
+				rightMax: 0,
+			},
+			oldOptions: {
+				MinValue: 0,
+				MaxValue: 0
+			},
+		};
+	},
+	methods: {
+		
+		getDataByPath() {
+			const apiMap = {
+				'/database': this.getEdbData,
+				'/analyseVariety': this.getPlantEdbData
+			}
+
+			apiMap[this.$route.path]()
+		},
+
+		/* 获取指标所有数据 */
+		async getEdbData() {
+			let params = {
+				EdbInfoId: this.edbid,
+				DateType: this.year_select,
+				StartDate: this.select_date[0] || '',
+				EndDate: this.select_date[1] || ''
+			}
+
+			const res = this.chart_type === 1 
+				? await dataBaseInterface.ebd_data(params)
+				: await dataBaseInterface.ebdSeasonData({
+						EdbInfoId: this.edbid,
+						Calendar: this.calendar_type,
+						StartDate: this.season_year[0] || '',
+						EndDate: this.season_year[1] || '',
+					})
+				
+				if(res.Ret !== 200) return
+					const { DataList,EdbInfo } = res.Data;
+					// DataList 表格数据列表
+					this.chartInfo = (this.oldOptions.MinValue || this.oldOptions.MaxValue) ? {
+						...EdbInfo,
+						...this.oldOptions
+					} : EdbInfo;
+					this.tableData = DataList || [];
+
+					this.chart_type === 1 ? this.setOptions() : this.setSeasonOptions();
+					this.showChart = true;
+					this.$nextTick(()=>{
+						if(!EdbInfo.ChartImage){
+							//设置图表缩略图
+							this.saveEdbImg(EdbInfo)
+						}
+					})
+		},
+		//保存指标缩略图
+		async saveEdbImg(EdbInfo){
+			let svg = this.$refs.chartRef.chart.getSVG({
+				chart: {
+					width: 340,
+					height: 230,
+				},
+			});
+			let form = new FormData();
+			form.append("Img", svg);
+			let { Data } = await dataBaseInterface.uploadImgSvg(form);
+			await dataBaseInterface.saveEdbChartImg({
+				EdbInfoId: EdbInfo.EdbInfoId,
+				ImageUrl: Data.ResourceUrl,
+			});
+		},
+
+		/* 获取装置指标数据 */
+		async getPlantEdbData() {
+			let params = {
+				VarietyEdbId: this.edbid,
+				DateType: this.year_select,
+				StartDate: this.select_date[0] || '',
+				EndDate: this.select_date[1] || ''
+			}
+
+			const res = this.chart_type === 1 
+				? await supplyApi.getEdbDetailData(params)
+				: await supplyApi.getEdbSeasonData({
+						VarietyEdbId: this.edbid,
+						Calendar: this.calendar_type,
+						StartDate: this.season_year[0] || '',
+						EndDate: this.season_year[1] || '',
+					})
+				
+				if(res.Ret !== 200) return
+					const { DataList,EdbInfo } = res.Data;
+					// DataList 表格数据列表
+					this.chartInfo = (this.oldOptions.MinValue || this.oldOptions.MinValue) ? {
+						...EdbInfo,
+						...this.oldOptions
+					} : EdbInfo;
+					this.tableData = DataList || [];
+
+					this.chart_type === 1 ? this.setOptions() : this.setSeasonOptions();
+					this.showChart = true;
+		},
+
+		 /* 年份改变 重新刷新图表接口  保存当前的图表配置和上下限 只改变图表 */
+    changeYear(item) {
+      this.year_select = item.value;
+      this.select_date = [];
+      this.dateTip = '请选择时间段';
+
+			const { MinValue,MaxValue } = this.chartInfo;
+			this.oldOptions = {
+				MinValue: Number(MinValue),
+				MaxValue: Number(MaxValue)
+			}
+      this.getDataByPath()
+    },
+
+		/* 打开时间段弹窗 */
+    openDateDia() {
+      // 自定义时间段回显
+      this.dateForm = {
+        date_type: this.year_select,
+        start_date:
+          this.year_select === 5 || this.year_select === 6
+            ? this.select_date[0]
+            : '',
+        end_date: this.year_select === 5 ? this.select_date[1] : '',
+      };
+      this.isDateDia = true;
+    },
+
+    /* 保存完自定义日期 刷新数据 保存当前的图表配置和上下限 只改变图表*/
+    dataChangeBack(data) {
+      this.year_select = data.dateType;
+      this.isDateDia = false;
+      this.select_date = [data.start_date, data.end_date];
+
+      this.dateTip =
+        data.dateType === 5
+          ? `${data.start_date}~${data.end_date}`
+          : `${data.start_date}~至今`;
+
+			const { MinValue,MaxValue } = this.chartInfo;
+			this.oldOptions = {
+				MinValue,
+				MaxValue
+			}
+      this.getDataByPath();
+    },
+
+		chartTypeChange() {
+			this.chart_type = this.chart_type===1 ? 2 : 1;
+			this.init('no_reset')
+			this.getDataByPath();
+		},
+
+		// 展示同比图
+		async showOnChart(scene='') {
+			if(scene==='toggle') {
+				this.isShowOnyearData = this.isShowOnyearData ? false : true;
+				if(!this.isShowOnyearData){
+					const { MinValue,MaxValue } = this.chartInfo;
+					this.oldOptions = {
+						MinValue: Number(MinValue),
+						MaxValue: Number(MaxValue)
+					}
+					this.getDataByPath();
+				}  
+			}
+			if(!this.isShowOnyearData) return;
+
+			let params = {
+				DateType: this.year_select,
+				StartDate: this.select_date[0] || '',
+				EndDate: this.select_date[1] || ''
+			}
+			const res = this.$route.path === '/analyseVariety' 
+				? await supplyApi.getEdbOnyearData({VarietyEdbId:this.edbid,...params})
+				: await dataBaseInterface.edbOnyearData({EdbInfoId: this.edbid,...params});
+
+			if(res.Ret !== 200) return
+
+			const { EdbInfo,DataList } = res.Data;
+
+			if(!this.limitData.rightMin && !this.limitData.rightMax) {
+				this.limitData.rightMin = Number(EdbInfo.MinValue);
+				this.limitData.rightMax = Number(EdbInfo.MaxValue);
+			}
+
+			this.options.yAxis.push({
+				title: {
+					text: '',
+					align: 'high',
+					rotation: 0,
+					y: -15,
+					offset: 0
+				},
+				labels: {
+					formatter: function (ctx) {
+						return ctx.value;
+					},
+					align: 'center',
+				},
+				min: Number(this.limitData.rightMin),
+				max: Number(this.limitData.rightMax),
+				...seasonOptions.yAxis,
+				opposite: true,
+			})
+
+			this.options.series.push({
+				data: DataList.map(item=>([item.DataTimestamp, item.Value])),
+				type: 'spline',
+				yAxis: 1,
+				name: this.chartLang=='ch'?`${EdbInfo.EdbName}同比`:EdbInfo.EdbNameEn?`${EdbInfo.EdbNameEn}同比`:'无英文名称',
+				lineWidth: 1
+			})
+			console.log(this.options.series)
+		},
+
+		changeLimit() {
+			const { rightMax,rightMin } = this.limitData;
+			this.options.yAxis[1].max = Number(rightMax);
+			this.options.yAxis[1].min = Number(rightMin);
+
+		},
+
+		/* 图表配置 曲线*/
+		setOptions() {
+			const chartData = _.cloneDeep(this.tableData);
+
+      //拼接标题 数据列
+      let data = [],
+        ydata = [];
+
+			//y轴
+
+			// 单位 中文时 为无不显示   英文时 为空提示点击输入
+			// 中文不存在或等于无时 英文显示为空  中文存在且英文不存在时 显示'英文单位'
+			let yTitleText = this.chartLang=='ch'?
+			(this.chartInfo.Unit && this.chartInfo.Unit!='无') ? this.chartInfo.Unit:'':
+			!this.chartInfo.UnitEn && this.chartInfo.Unit && this.chartInfo.Unit!='无' ? '英文单位':this.chartInfo.UnitEn
+			// title样式  英文为空时,提示文字样式  英文可以点击设置
+			let yTitleStyle = {}
+			if(this.chartLang=='en'){
+				yTitleStyle.cursor='pointer'
+				if(yTitleText=='英文单位'){
+					yTitleStyle.color="#999"
+				}
+			}
+			let yItem = {
+				title: {
+					text: yTitleText,
+					align: 'high',
+					rotation: 0,
+					y: -15,
+					offset: 0,
+					style:yTitleStyle
+				},
+				labels: {
+					formatter: function (ctx) {
+						return ctx.value;
+					},
+					align: 'center',
+				},
+				min: Number(this.chartInfo.MinValue),
+				max: Number(this.chartInfo.MaxValue),
+				...seasonOptions.yAxis,
+			};
+			// 图例名称和图例文字样式
+			let dataName = this.chartLang=='ch'?this.chartInfo.EdbName:this.chartInfo.EdbNameEn?this.chartInfo.EdbNameEn:'无英文名称'
+			let color = this.chartLang=='en'&&(!this.chartInfo.EdbNameEn)?'#999':'#333'
+			let legend={
+				...defaultOpts.legend,
+				itemStyle: {
+					color
+				},
+			}
+			//数据列
+			let obj = {
+				data: [],
+				type: 'spline',
+				yAxis: 0,
+				name: dataName,
+				lineWidth: 3
+			};
+			chartData.forEach((item, index) => {
+				obj.data.push([item.DataTimestamp, item.Value]);
+			});
+			
+			data.push(obj);
+			ydata.push(yItem);
+
+      // 范围为1年内 x轴显示为月/日 否则默认年/月
+      let xAxis = {};
+      const bool_time = this.xTimeDiffer();
+      xAxis = bool_time
+        ? {
+            ...defaultOpts.xAxis,
+            labels: {
+              formatter: function (ctx) {
+                return Highcharts.dateFormat('%m/%d', ctx.value);
+              },
+            },
+          }
+        : {
+            ...defaultOpts.xAxis,
+						labels: {
+              formatter: function (ctx) {
+                return Highcharts.dateFormat('%y/%m', ctx.value);
+              },
+            },
+          };
+      this.options = {
+        series: data,
+        yAxis: ydata,
+        xAxis,
+				legend
+      };
+
+			this.showOnChart();
+		},
+
+		/* 季节图 */
+		setSeasonOptions() {
+			console.log(this.tableData)
+      const chartData = _.cloneDeep(this.tableData);
+      let seasonYdata = [],
+        seasonData = [];
+
+        /* 公历数据处理 处理数据列 y轴 */
+        if (this.calendar_type === '公历')
+        for (let j of chartData) {
+          
+          let serie_item = {
+            data: [],
+            type: 'spline',
+            yAxis: 0,
+            name: j.Year,
+          };
+          const data_array = _.cloneDeep(j.DataList);
+          data_array &&
+            data_array.forEach((item) => {
+              serie_item.data.push([item.DataTimestamp, item.Value]);
+            });
+          const index = chartData.findIndex(
+            (item) => item.Year === j.Year
+          );
+          const s_yItem = {
+            labels: {
+              formatter: function () {
+                let val = this.value;
+                return index !== 0 ? '' : val;
+              },
+              align: 'center',
+            },
+            title: {
+              text:  this.chartLang=='ch'?this.chartInfo.Unit:
+							!this.chartInfo.UnitEn && this.chartInfo.Unit && this.chartInfo.Unit!='无' ? '英文单位':this.chartInfo.UnitEn,
+              align: 'high',
+              rotation: 0,
+              y: -15,
+              offset: -(12 * this.chartInfo.Unit.length),
+            },
+            max: Number(this.chartInfo.MaxValue),
+            min: Number(this.chartInfo.MinValue),
+            ...seasonOptions.yAxis,
+          };
+          seasonData.push(serie_item);
+          seasonYdata.push(s_yItem);
+        }
+
+      /* 农历数据处理  */
+      let filterArr =
+        this.calendar_type === '农历'
+          ? chartData.List.filter((item, index) => index > 0)
+          : [];
+      if (this.calendar_type === '农历')
+        for (let j of filterArr) {
+
+          let serie_item = {
+            data: [],
+            type: 'spline',
+            yAxis: 0,
+            name: j.Year
+          };
+          const data_array = _.cloneDeep(j.Items);
+          data_array &&
+            data_array.forEach((item) => {
+              serie_item.data.push([item.DataTimestamp, item.Value]);
+            });
+          const index = filterArr.findIndex((item) => item.Year === j.Year);
+          const s_yItem = {
+            labels: {
+              formatter: function () {
+                let val = this.value;
+                return index !== 0 ? '' : val;
+              },
+              align: 'center',
+            },
+            title: {
+              text:  this.chartLang=='ch'?this.chartInfo.Unit:
+							!this.chartInfo.UnitEn && this.chartInfo.Unit && this.chartInfo.Unit!='无' ? '英文单位':this.chartInfo.UnitEn,
+              align: 'high',
+              rotation: 0,
+              y: -15,
+              offset: -(12 * this.chartInfo.Unit.length),
+            },
+            max: Number(this.chartInfo.MaxValue),
+            min: Number(this.chartInfo.MinValue),
+            ...seasonOptions.yAxis,
+          };
+          seasonData.push(serie_item);
+          seasonYdata.push(s_yItem);
+        }
+
+      /* x轴显示月日  提示框显示月日*/
+      defaultOpts.xAxis.labels = {
+        formatter: function () {
+          return Highcharts.dateFormat('%m/%d', this.value);
+        },
+      };
+      
+      const tooltip = {
+        ...defaultOpts.tooltip,
+        dateTimeLabelFormats: {
+          // 时间格式化字符
+          day: '%m/%d',
+          week: '%m/%d',
+          month: '%m/%d',
+          year: '%m/%d',
+        },
+        xDateFormat: '%m/%d',
+      }
+      let rangeSelector =
+        this.calendar_type === '农历'
+          ? {
+              enabled: true,
+              selected: 0,
+              inputStyle: {
+                display: 'none',
+              },
+              labelStyle: {
+                display: 'none',
+              },
+              buttonTheme: {
+                style: {
+                  display: 'none',
+                },
+              },
+              buttons: [
+                {
+                  type: 'month',
+                  count: 12,
+                  text: '12月',
+                },
+                {
+                  type: 'month',
+                  count: 15,
+                  text: '15月',
+                },
+                {
+                  type: 'all',
+                  text: '全部',
+                  type: 'all',
+                },
+              ],
+            }
+          : {
+              enabled: false,
+            };
+
+      this.options = {
+        colors:
+          this.calendar_type === '公历'
+            ? seasonOptions.colors.slice(-chartData.length)
+            : seasonOptions.colors.slice(-filterArr.length),
+        series: seasonData,
+        yAxis: seasonYdata,
+        rangeSelector,
+        tooltip
+      };
+			console.log(this.options)
+		},
+
+	  /* 查询范围为1年内 x轴显示为月/日 否则默认年/月 */
+    xTimeDiffer() {
+      const end_date =
+        this.year_select === 5
+          ? this.select_date[1]
+          : this.year_select === 6
+          ? new Date()
+          : '';
+      //年限差
+      const year_differ = this.$moment(end_date).diff(
+        this.$moment(this.select_date[0]),
+        'years',
+        true
+      );
+      // console.log(year_differ)
+      if ([5, 6].includes(this.year_select) && year_differ <= 1) {
+        return true;
+      } else {
+        return false;
+      }
+    },
+
+		init(type='') {
+			if(type!=='no_reset') this.chart_type = 1;
+			this.isShowOnyearData = false;
+			this.year_select = 10;
+			this.select_date = [];
+			this.options = {};
+			this.dateTip = '请选择时间段';
+			this.oldOptions = {};
+			this.calendar_type = '公历';
+			this.season_year = [];
+			this.limitData = {
+				letMin: 0,
+				leftMax: 0,
+				rightMin: 0,
+				rightMax: 0,
+			}
+		},
+		// 编辑英文信息弹窗
+		editEnName(){
+			this.$emit('editEnName','chart')
+		},
+		// 竖轴标题点击事件
+		clickYAxisTitle(){
+			console.log(this.chartLang);
+			if(this.chartLang == 'en') this.editEnName()
+		}
+	},
+	created() {},
+	mounted() {},
+}
+</script>
+<style lang='scss'>
+.chart-trend-render {
+	width:100%;
+	box-sizing: border-box;
+	@media screen and (min-width: 1711px) {
+		.min-data-input { margin-top: 300px; }
+	}
+	@media screen and (max-width:1710px) {
+		.min-data-input { margin-top: 210px; }
+	}
+	.header {
+		display: flex;
+		position: relative;
+		.year-btn,.btn-sty {
+			min-width: 98px;
+			font-size: 14px;
+			margin-right: 5px;
+			margin-bottom: 5px;
+		}
+		.btn-sty {
+			background-color: #fff;
+			color: #0052D9;
+		}
+		.change-chart-btn{
+				float: right;
+				color: #409eff;
+				font-size: 16px;
+				cursor: pointer;
+				&::before{
+						content:'';
+						display: inline-block;
+						width: 18px;
+						height: 18px;
+						background-image: url('~@/assets/img/chart_m/change.png');
+						background-size: cover;
+						position: relative;
+						top: 4px;
+						right: 4px;
+				}
+		}
+	}
+	.min-wrapper {
+		.el-input__inner {
+			padding: 0 0 0 5px;
+		}
+		/* margin: 20px 0 0 0; */
+		min-height: 320px;
+		.chartWrapper {
+			position: relative;
+			padding: 0 105px 0 100px;
+			.range-cont {
+				position: absolute;
+				top: 8%;
+				.min-data-input {
+					width: 80px;
+					display: block;
+				}
+				&.left {
+					left: 0px;
+				}
+				&.right {
+					right: 0;
+				}
+			}
+		}
+	}
+}
+</style>

+ 1 - 1
src/views/dataEntry_manage/databaseComponents/createChart.vue

@@ -224,7 +224,7 @@ export default {
 				if(res.Ret !== 200) return
 					const { DataList,EdbInfo } = res.Data;
 					// DataList 表格数据列表
-					this.chartInfo = (this.oldOptions.MinValue || this.oldOptions.MinValue) ? {
+					this.chartInfo = (this.oldOptions.MinValue || this.oldOptions.MaxValue) ? {
 						...EdbInfo,
 						...this.oldOptions
 					} : EdbInfo;

+ 150 - 0
src/views/dataEntry_manage/databaseComponents/edbDetailData.vue

@@ -0,0 +1,150 @@
+<template>
+	<div class="edb-detail-data-wrap">
+		<el-table
+			:data="tableData"
+			class="firstColumTable" border>
+			<el-table-column
+				v-for="item in tableColumsOne"
+				:key="item.label"
+				:width="item.widthsty"
+				:min-width="item.minwidthsty"
+				align="center">
+				<template slot="header" slot-scope="scope">
+					<div class="chartEn-mark" style="top: -10px;" v-show="scope.$index ==0 && tableData[0] && tableData[0].IsEnEdb" >En</div>
+					<span>{{item.label}}</span>
+				</template>	
+				<template slot-scope="scope">
+					<span v-show="currentLang=='ch'">{{ scope.row[item.key] }}</span> 
+					<span v-show="currentLang=='en'">{{scope.row[item.enKey||item.key] || scope.row[item.key]}}</span>
+				</template>
+			</el-table-column>
+		</el-table>
+		<el-table
+			:data="tableData"
+			style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);"
+			border>
+			<el-table-column
+				v-for="item in tableColumsTwo"
+				:key="item.label"
+				:label="item.label"
+				:width="item.widthsty"
+				:min-width="item.minwidthsty"
+				align="center"
+			>
+				<template #header>
+					<span>{{ item.label }}</span>
+				</template>
+				<template slot-scope="scope">
+					<span>{{ scope.row[item.key] }}</span>
+				</template>
+			</el-table-column>
+			<div slot="empty" style="padding: 50px 0 320px;">
+					<tableNoData :text="defaultWarn"/>
+			</div>
+		</el-table>
+		<ul 
+			class="value-ul" 
+			ref="valueUl" 
+			@scroll="scrollHandle" 
+			v-show="dataList.length">
+			<li
+				class="value-item"
+				v-for="item in dataList"
+				:key="item.EdbDataId"
+			>
+				<span class="value-label">
+					<span style="position: relative;">
+						<i class="new-tag" v-if="tableData[0].LatestDate===item.DataTime"></i>
+						{{item.DataTime}}
+					</span>
+				</span>
+				<span :class="['value-label',{'predict-act': tableData[0].DataInsertConfig.Date===item.DataTime}]" style="min-width:200px;text-align:center;">
+					<span :class="['value-style',{'predict-act': tableData[0].DataInsertConfig.Date===item.DataTime}]">{{item.Value}}</span>
+				</span>
+			</li>
+			<li class="nodata value-item" v-if="!dataList.length">暂无数据</li>
+		</ul>
+	</div>
+</template>
+
+<script>
+export default {
+	props:{
+		currentLang:{
+			type:String,
+			default:'ch'
+		},
+		tableData:{
+			type:Array,
+			default:()=>{return []}
+		},
+		tableColumsOne:{
+			type:Array,
+			default:()=>{return []}
+		},
+		tableColumsTwo:{
+			type:Array,
+			default:()=>{return []}
+		},
+		defaultWarn:{
+			type:String,
+			default:'暂无数据'
+		},
+		dataList:{
+			type:Array,
+			default:()=>{return []}
+		},
+		haveMore:{
+			type:Boolean,
+			default:false
+		}
+	},
+	data() {
+		return {
+
+		};
+	},
+	methods: {
+		/* 数值滚动加载 */
+		scrollHandle: _.throttle(function() {
+			let scrollTop = this.$refs.valueUl.scrollTop;
+			let clientHeight = this.$refs.valueUl.clientHeight;
+			let scrollHeight = this.$refs.valueUl.scrollHeight;
+			if(scrollTop===0) return
+			if(scrollTop + clientHeight >= scrollHeight-10 && this.haveMore){
+				this.$emit('getNextData')
+			}
+		},200),
+	},
+};
+</script>
+
+<style lang="scss">
+.edb-detail-data-wrap{
+    .el-table--enable-row-transition .el-table__body td{
+        background: #fff !important;
+    }
+    .el-table td, .el-table th.is-leaf {
+        background: #F2F6FA !important;
+    }
+
+}
+</style>
+<style scoped lang="scss">
+.edb-detail-data-wrap{
+	display: flex;
+	flex-direction: column;
+	height: 100%;
+	.firstColumTable{
+		box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);
+	}
+	.el-table{
+		flex: none;
+	}
+	.value-ul{
+		/* flex: 1;
+		overflow-y: auto; */
+        overflow-y: auto;
+	}
+}
+</style>

+ 429 - 155
src/views/dataEntry_manage/databaseList.vue

@@ -13,7 +13,7 @@
 				<el-button v-permission="permissionBtn.edbDataPermission.edbData_dataAdjust"
 					type="primary" @click="$router.push({path: '/adjustdata'})">数据调整</el-button>
 				<el-button v-permission="permissionBtn.edbDataPermission.edbData_batchUpdate"
-					type="primary" plain @click="updateHandler">一键新</el-button>
+					type="primary" plain @click="updateHandler">一键新</el-button>
 			</div>
 			<div class="top-right">
 
@@ -119,23 +119,22 @@
 									@click.stop="addNode(node,data)"
 									v-if="data.Button.AddButton"
 								/>
-								<!--如果是分类,判断data.Button.OpButton不变;如果是指标,再加上checkPermissionBtn判断-->
+								<!--如果是分类,判断data.Button.OpButton不变;如果是指标,不显示(ETA1.0.3)-->
 								<img
 									src="~@/assets/img/set_m/edit.png"
 									alt=""
 									style="width: 15px; height: 14px; margin-right: 8px"
 									@click.stop="editNode(node,data)"
-									v-if="data.EdbCode
-										?(data.Button.OpButton&&permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_edit))
-										:(data.Button.OpButton)"
+									v-if="!data.EdbCode&&(data.Button.OpButton)"
 								/>
+								<!--如果是分类,判断data.Button.DeleteButton不变;如果是指标,不显示(ETA1.0.3)-->
 								<img
 									slot="reference"
 									src="~@/assets/img/set_m/del.png"
 									alt=""
 									style="width: 14px; height: 14px;"
 									@click.stop="removeNode(node,data)"
-									v-if="data.Button.DeleteButton"
+									v-if="!data.EdbCode&&(data.Button.DeleteButton)"
 								/>
 								<i class="el-icon-view" v-if="data.EdbType===2&&![58,59,67,68].includes(data.Source)" @click.stop="viewNode(node,data)"></i>
 								<img 
@@ -171,65 +170,45 @@
 			<div class="main-right right" id="right" style="background:transparent;border:none;box-shadow:none" v-if="showAssociateChart">
 				<dataAssociateChart :edbInfoId="selected_edbid"></dataAssociateChart>
 			</div>
-			<div class="main-right right" id="right" style="background:transparent;border:none;box-shadow:none" v-if="showAssociateComputeData">
+			<div class="main-right right" id="right" style="background:transparent;border:none;box-shadow:none;padding-top: 30px;box-sizing: border-box;" v-if="showAssociateComputeData">
 				<dataAssociateComputeData :edbInfoId="selected_edbid"></dataAssociateComputeData>
 			</div>
-			<div class="main-right right" id="right" v-show="!showAssociateChart&&!showAssociateComputeData">
-				<el-table
-				:data="tableData"
-				style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);"
-				class="firstColumTable"
-				border>
-					<el-table-column
-						v-for="item in tableColumsOne"
-						:key="item.label"
-						:width="item.widthsty"
-						:min-width="item.minwidthsty"
-						align="center"
-					>
-						<template slot="header" slot-scope="scope">
-							<div class="chartEn-mark" style="top: -10px;" v-show="scope.$index ==0 && tableData[0] && tableData[0].IsEnEdb" >En</div>
-							<span>{{item.label}}</span>
-						</template>	
-						<template slot-scope="scope">
-							<!-- 中文 -->
-							<span v-show="currentLang=='ch'">{{ scope.row[item.key] }}</span> 
-							<span v-show="currentLang=='en'">{{scope.row[item.enKey||item.key] || scope.row[item.key]}}</span>
-						</template>
-					</el-table-column>
-				</el-table>
-				<el-table
-				:data="tableData"
-				style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);"
-				border>
-					<el-table-column
-						v-for="item in tableColumsTwo"
-						:key="item.label"
-						:label="item.label"
-						:width="item.widthsty"
-						:min-width="item.minwidthsty"
-						align="center"
-					>
-						<template #header>
-							<span>{{ item.label }}</span>
-						</template>
-						<template slot-scope="scope">
-							<span>{{ scope.row[item.key] }}</span>
-						</template>
-					</el-table-column>
-					<el-table-column
-						width="260"
-						align="center"
-						label="操作"
-					>
-						<template slot-scope="scope">
-							<el-button v-permission="permissionBtn.edbDataPermission.edbData_update"
-								size="mini" type="text" @click="refreshTargetHandle" >更新</el-button>
-							<el-button 
-								v-permission="permissionBtn.edbDataPermission.edbData_edit"
-								size="mini" 
-								type="text" 
-								:disabled="!scope.row.Button.OpButton"
+			<!-- 指标图表列表 -->
+			<div class="main-right right list" id="right" v-show="isShowList">
+				<p>共{{Total||0}}个指标</p>
+				<div class="list-wrap" ref="listRef" @scroll="loadMoreHandle" v-if="Total">
+					<div class="list-item" v-for="item in chartList" :key="item.EdbInfoId">
+						<div class="header">
+							<span v-show="currentLang=='ch'">{{ item.EdbName }}</span> 
+							<span v-show="currentLang=='en'">{{ item.EdbNameEn || item.EdbName }}</span>
+						</div>
+						<div class="image" @click="detailShowHandle(item)">
+							<img :src="item.ChartImage" alt=""/>
+						</div>
+						<div class="info">
+							创建时间:{{item.CreateTime.substring(0,10)}}
+						</div>
+					</div>
+					<p style="height: 40px;line-height:40px;width: 100%;"></p>
+				</div>
+				<div v-if="!Total" class="nodata">
+					<tableNoData text="暂无指标"/>
+				</div>
+			</div>
+			<!-- 指标详情 -->
+			<div class="main-right right detail" id="right" v-show="isShowDetail">
+				<div class="header">
+					<el-tabs v-model="activeTab" @tab-click="rePainChart">
+						<el-tab-pane label="走势图" name="Chart">
+						</el-tab-pane>
+						<el-tab-pane label="数据详情" name="Data">
+						</el-tab-pane>
+					</el-tabs>
+					<div class="edb-tool">
+						<el-button v-if="isEdbBtnShow('update')"
+							type="text" @click="refreshTargetHandle" >刷新</el-button>
+						<el-button v-if="isEdbBtnShow('edit')"
+								type="text" :disabled="!(EdbData.Button.OpButton)"
 								@click="editNode({
 									level: 4,
 									parent: {
@@ -241,47 +220,73 @@
 											}
 										},
 									}
-								},scope.row)"
-								>编辑</el-button>
-							<el-button size="mini" type="text" @click.stop="reCalculateHandler" v-if="scope.row.EdbType===2" :loading="calculateLoading">重新计算</el-button>
-							<el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_toImgs)"
-								size="mini" type="text" @click.stop="createChartHandle(scope.row.EdbInfoId)">一键成图</el-button>
-							<el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_copyData)"
-								size="mini" type="text" @click="copyCode">复制数据</el-button>
-							<!-- <lookEdbHistory :showType="2" :edbId="selected_edbid" v-if="scope.row.EdbType===2"/> -->
-							<el-button size="mini" type="text"
-							v-if="scope.row.EdbType===2&&permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_edbSource)" @click="isLookHistory=true;lookEdbId=selected_edbid">指标溯源</el-button>
-							
-							<el-button v-if="permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_enNameSetting)"
-								size="mini" type="text" @click="openEnNameDia">设置英文名称</el-button>
-							<el-button size="mini" type="text" @click.stop="updateNewestDataHandle" 
-							v-if="scope.row.Button.InsertNewDataButton&&permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_newestValue)" >{{scope.row.DataInsertConfig.Date?'编辑最新值':'添加最新值'}}</el-button>
-							<el-button size="mini" type="text" @click.stop="refreshBaseHandler" 
-								v-if="scope.row.EdbType===1&&permissionBtn.checkPermissionBtn(permissionBtn.edbDataPermission.edbData_refreshAll)" :loading="refreshLoading">全部刷新</el-button>
-						</template>
-					</el-table-column>
-					<div slot="empty" style="padding: 50px 0 320px;">
-						 <tableNoData :text="defaultWarn"/>
+								},EdbData)"
+							>编辑</el-button>
+						<!-- 指保存指标的上下限,在走势图才显示 -->
+						<el-button v-if="activeTab==='Chart'"
+							type="text" @click.stop="saveEdbLimit">保存</el-button>
+						<el-button v-if="isEdbBtnShow('setEn')"
+							type="text" @click="openEnNameDia">设置英文名称</el-button>
+						<el-button v-if="EdbData.Button.InsertNewDataButton&&isEdbBtnShow('newValue')"
+							type="text" @click.stop="updateNewestDataHandle" >{{(EdbData.DataInsertConfig.Date)?'编辑最新值':'添加最新值'}}</el-button>
+						<el-button v-if="EdbData.EdbType===2"
+							type="text" @click.stop="reCalculateHandler" :loading="calculateLoading">重新计算</el-button>
+						<el-button v-if="EdbData.EdbType===2&&isEdbBtnShow('toSource')"
+							type="text" @click="isLookHistory=true;lookEdbId=selected_edbid">指标溯源</el-button>
+						<el-button v-if="EdbData.EdbType===1&&isEdbBtnShow('refreshAll')"
+							type="text" @click.stop="refreshBaseHandler" :loading="refreshLoading">全部刷新</el-button>
+						<el-button v-if="isEdbBtnShow('copyData')"
+							type="text" @click="copyCode">复制数据</el-button>
+						<el-button v-if="EdbData.Button.DeleteButton"
+							type="text" @click="removeNode(_,EdbData)" style="color:#C54322;">删除</el-button>
 					</div>
-				</el-table>
-				<ul 
-				class="value-ul" 
-				ref="valueUl" 
-				@scroll="scrollHandle" 
-				v-show="showTable&&dataList.length">
-					<li
-						class="value-item"
-						v-for="item in dataList"
-						:key="item.EdbDataId"
-					>
-						<span class="value-label">
-							<i class="new-tag" v-if="tableData[0].LatestDate===item.DataTime"></i>
-							{{item.DataTime}}
-						</span>
-						<span :class="['value-label',{'predict-act': tableData[0].DataInsertConfig.Date===item.DataTime}]" style="min-width:200px;text-align:center;">{{item.Value}}</span>
-					</li>
-					<li class="nodata value-item" v-if="!dataList.length">暂无数据</li>
-				</ul>
+				</div>
+				<div class="container" id="detail-container">
+					<div class="chart" v-show="activeTab==='Chart'">
+						<chart-trend-render
+							:edbid="selected_edbid"
+							:chartLang="currentLang"
+							ref="createChart"
+							@editEnName="openEnNameDia"/>
+						<div class="info">
+							<span>数据来源:{{EdbData.SourceName}}</span>
+							<span>添加人:{{EdbData.SysUserRealName}}</span>
+						</div>
+						<ul class="value-ul"
+							v-show="showTable&&dataList.length">
+							<li class="value-item" style="background-color: #EBEFF6;">
+								<span style="width:240px">日期(频度:{{EdbData.Frequency}})</span>
+								<span style="flex:1;">值</span>
+							</li>
+							<li class="value-item"
+								v-for="item in dataList.slice(0,3)"
+								:key="item.EdbDataId">
+								<span class="value-label date" style="width:240px">
+									<span style="position: relative;">
+										<i class="new-tag" v-if="EdbData.LatestDate===item.DataTime"></i>
+										{{item.DataTime}}
+									</span>
+								</span>
+								<span :class="['value-label',{'predict-act': EdbData.DataInsertConfig.Date===item.DataTime}]" style="flex:1;">
+									<span :class="['value-style',{'predict-act': EdbData.DataInsertConfig.Date===item.DataTime}]">{{item.Value}}</span>
+								</span>
+							</li>
+							<li class="nodata value-item" v-if="!dataList.length">暂无数据</li>
+						</ul>
+					</div>
+					<div class="list" v-show="activeTab==='Data'">
+						<edb-detail-data 
+							ref="edb_detail_data"
+							:current-lang="currentLang"
+							:table-data="tableData"
+							:table-colums-one="tableColumsOne"
+							:table-colums-two="tableColumsTwo"
+							:data-list="dataList"
+							:haveMore="haveMore"
+							@getNextData="()=>{page_no++;getDataList();}"
+						/>
+					</div>
+				</div>
 			</div>
 		</div>
 		<!-- 输入英文指标弹窗 -->
@@ -369,14 +374,14 @@
 			@changeSource="changeComputedType"
 		/>
 		<!-- 一键成图弹窗 -->
-		<create-chart
+		<!-- <create-chart
 			:isCreateChart="isCreateChart"
 			:edbid="selected_edbid"
 			:chartLang="currentLang"
 			ref="createChart"
 			@close="isCreateChart = false"
 			@editEnName="openEnNameDia"
-		/>
+		/> -->
 
 		<!-- 一键更新弹窗 -->
 		<update-dialog
@@ -469,6 +474,8 @@ import batchComputedDialog from './databaseComponents/batchComptedDialog.vue';
 import diffusionIndexDialog from './databaseComponents/diffusionIndexDia.vue';
 import updateNewestDataDia from './databaseComponents/updateNewestDia.vue';
 import EdbLabelList from '@/components/edbLabelList.vue';
+import chartTrendRender from './databaseComponents/chartTrendRender.vue';
+import edbDetailData from './databaseComponents/edbDetailData.vue';
 export default {
 	name: '',
 	components: { 
@@ -489,7 +496,9 @@ export default {
 		batchComputedDialog,
 		diffusionIndexDialog,
 		updateNewestDataDia,
-		EdbLabelList
+		EdbLabelList,
+		chartTrendRender,
+		edbDetailData
 	},
 	directives: {
     drag(el, bindings) {
@@ -580,7 +589,7 @@ export default {
 				{
 					label: '指标目录',
 					key: 'Menu',
-					minwidthsty: '117px',
+					minwidthsty: '150px',
 				},
 				{
 					label: '起始时间',
@@ -590,12 +599,12 @@ export default {
 				{
 					label: '更新时间',
 					key: 'ModifyTime',
-					minwidthsty: '118px',
+					minwidthsty: '120px',
 				},
 				{
 					label: '添加人',
 					key: 'SysUserRealName',
-					widthsty: '100px',
+					widthsty: '160px',
 				}
 			],
 			haveMore: true,
@@ -666,7 +675,17 @@ export default {
 			lookEdbId: 0,
 			labelList:[],//标签列表
 
-			CanOpClassify: false
+			CanOpClassify: false,
+
+			select_classifyId:0,//指标分类id
+			PageSize:20,
+			CurrentIndex:1,
+			Total:0,
+			IsListEnd:false,//是不是到底了
+			chartList:[],
+
+			activeTab:'',
+			activeName:'second'
 		};
 	},
 	watch: {
@@ -675,7 +694,10 @@ export default {
 				this.tableData = [];
 				this.dataList = [];
 				this.defaultWarn = '请在左侧选择指标';
+				this.activeTab=''
 			}else {
+				console.log('new val')
+				this.activeTab='Chart'
 				this.initGetData();
 			}
 		},
@@ -685,26 +707,21 @@ export default {
 				let [search_obj] = this.searchOptions.filter(
 					(item) => item.EdbInfoId === newval
 				);
-				
 				this.page_no = 1;
-				this.$refs.valueUl.scrollTop = 0;
-				// 查找图表的父级code
-				//this.defaultShowNodes = this.findParentNodeHandle(this.treeData,search_obj.ClassifyId);
+				if(this.$refs.edb_detail_data){
+					this.$refs.edb_detail_data.$refs.valueUl.scrollTop=0
+				}
 				this.select_node = search_obj.UniqueCode;
 				this.selected_edbid = newval;
-
-				//滚动到高亮节点位置
-				/* setTimeout(() => {
-					this.$refs.menuTree.setCurrentKey(this.select_node);
-					let node = document.getElementById(`node${this.select_node}`);
-					let parent = document.getElementsByClassName('tree-cont')[0];
-
-					if(node.offsetTop > parent.offsetHeight) {
-						parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
-					}
-				},400) */
 			}
 		},
+		select_classifyId(newval){
+			if(this.$refs.listRef) this.$refs.listRef.scrollTop = 0;
+			if(newval){
+				this.CurrentIndex = 1
+				this.getEdbChartList()
+			}
+		}
 	},
 	computed: {
 			/* 计算弹窗控制 */
@@ -727,8 +744,35 @@ export default {
 			let id = parseInt(localStorage.getItem('AdminId'));
 			return id;
 		},
+		//指标详情,也就是tableData[0]
+		EdbData(){
+			return this.tableData[0]?this.tableData[0]:{Button:{},DataInsertConfig:{},DataList:[]}
+		},
+		//是否显示指标列表
+		isShowList(){
+			return !this.showAssociateChart&&!this.showAssociateComputeData&&!this.selected_edbid
+		},
+		//是否显示指标详情
+		isShowDetail(){
+			return !this.showAssociateChart&&!this.showAssociateComputeData&&this.selected_edbid
+		}
 	},
 	methods: {
+		//控制指标详情操作按钮
+		isEdbBtnShow(type){
+			const {edbDataPermission,checkPermissionBtn}=this.permissionBtn
+			const BtnMap = {
+				'update':edbDataPermission.edbData_update,
+				'edit':edbDataPermission.edbData_edit,
+				'toImg':edbDataPermission.edbData_toImgs,
+				'copyData':edbDataPermission.edbData_copyData,
+				'toSource':edbDataPermission.edbData_edbSource,
+				'setEn':edbDataPermission.edbData_enNameSetting,
+				'newValue':edbDataPermission.edbData_newestValue,
+				'refreshAll':edbDataPermission.edbData_refreshAll,
+			}
+			return checkPermissionBtn(BtnMap[type])
+		},
 		/* 获取树分类数据 */
 		getTreeData(params) {
 			
@@ -787,7 +831,8 @@ export default {
 						//将指标添加进标签列表中
 						const {EdbNameEn,EdbName,EdbInfoId,UniqueCode,ClassifyId}=res.Data.Item
 						this.addLabel({code:UniqueCode,id:EdbInfoId,classifyId:ClassifyId,EdbName,EdbNameEn})
-						this.defaultShowNodes=this.findParentNodeHandle(this.treeData,ClassifyId)
+						let deep_arr = _.cloneDeep(this.treeData);
+						this.defaultShowNodes=this.findParentNodeHandle(deep_arr,ClassifyId).reverse()||[]
 						//设置tree高亮
 						this.$refs.menuTree.setCurrentKey(UniqueCode);
 
@@ -799,7 +844,9 @@ export default {
 						this.$refs.menuTree.setCurrentKey(null)
 					}
 					if(type==='refresh') {
-						this.$refs.valueUl.scrollTop = 0;
+						if(this.$refs.edb_detail_data){
+							this.$refs.edb_detail_data.$refs.valueUl.scrollTop=0
+						}
 					}
 					this.$nextTick(()=>{
 						const _node = this.$refs.menuTree.getNode(this.select_node)
@@ -808,8 +855,15 @@ export default {
 						//滚动到高亮位置
 						setTimeout(() => {
 							let node = document.getElementById(`node${this.select_node}`)||{}
-							let parent = document.getElementsByClassName('tree-cont')[0];
-							if(node.offsetTop > parent.offsetHeight) {
+							let parent = document.getElementsByClassName('target_tree')[0];
+							//parent可视区间:[scrollTop,scrollTop+offsetHeight]
+							//node位置:node.offsetTop
+							const overTop = node.offsetTop+node.clientHeight+30<parent.scrollTop
+							const overBottom = node.offsetTop+node.clientHeight+30>parent.scrollTop+parent.offsetHeight
+							if(overTop){
+								parent.scrollTop = node.offsetTop-60
+							}
+							if(overBottom){
 								parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
 							}
 						},400)
@@ -818,6 +872,33 @@ export default {
 				}
 			})
 		}),
+		//获取指标图表列表
+		getEdbChartList(){
+			dataBaseInterface.getEdbChartList({
+				PageSize:this.PageSize,
+				CurrentIndex:this.CurrentIndex,
+				ClassifyId:this.select_classifyId,
+			}).then(res=>{
+				if(res.Ret!==200) return
+				if(res.Data){
+					this.chartList = this.CurrentIndex===1?res.Data.List:[...this.chartList,...res.Data.List]
+					this.Total = res.Data.Paging.Totals||0
+					this.IsListEnd = res.Data.Paging.IsEnd
+				}
+
+
+			})
+		},
+		//指标图表列表-加载更多
+		loadMoreHandle: _.throttle(function() {
+			let scrollTop = this.$refs.listRef.scrollTop;
+			let clientHeight = this.$refs.listRef.clientHeight;
+			let scrollHeight = this.$refs.listRef.scrollHeight;
+			if(scrollTop + clientHeight >= scrollHeight-10 && !this.IsListEnd){
+				this.CurrentIndex++;
+				this.getEdbChartList();
+			}
+			},300),
 		/* 搜索 */
 		searchHandle(query) {
 			this.search_page = 1;
@@ -975,17 +1056,14 @@ export default {
 		},
 		/* 节点变化时 */
 		nodeChange(data,node) {
-			this.dynamicNode = node;
 			this.search_txt = '';
-			this.showAssociateChart=false
-			this.showAssociateComputeData=false
-			// this.page_no = 1;
-			// this.$refs.valueUl.scrollTop = 0;
+			this.select_classifyId = !data.EdbInfoId?data.ClassifyId:0;
 			this.select_node = data.UniqueCode;
 			this.selected_edbid = data.EdbInfoId;
 			this.resetNodeStyle(node);
-			
-			
+			this.dynamicNode = node;
+			this.showAssociateChart=false
+			this.showAssociateComputeData=false
 		},
 		resetNodeStyle: _.debounce(function(node) {
 			const tree = $('.target_tree')[0];
@@ -1159,7 +1237,7 @@ export default {
 			if(this.selected_edbid) {
 				this.loading = this.$loading({
 					lock: true,
-					target:'.main-right',
+					target:'.detail',
 					text: '刷新数据中...',
 					spinner: 'el-icon-loading',
 					background: 'rgba(255, 255, 255, 0.8)'
@@ -1427,9 +1505,11 @@ export default {
 			this.selected_edbid = id;
 
 			//this.defaultShowNodes=this.findParentNodeForClassifyId(classifyId,code)
+			const containerDom = document.getElementById('detail-container')
+			containerDom&&(containerDom.scrollTop = 0)
 			
 			 //滚动到高亮节点位置
-			this.$nextTick(()=>{
+			/* this.$nextTick(()=>{
 				setTimeout(() => {
 					let node = document.getElementById(`node${this.select_node}`)||{}
 					let parent = document.getElementsByClassName('tree-cont')[0];
@@ -1438,7 +1518,7 @@ export default {
 						parent.scrollTop =  node.offsetTop - parent.offsetHeight/2
 					}
 				},400)
-			})
+			}) */
 		},
 		// 查找树节点所有父节点
 		findParentNodeHandle(arr, id) {
@@ -1525,8 +1605,8 @@ export default {
 
 		initGetData() {
 			this.page_no = 1;
-			if(this.$refs.valueUl){
-				this.$refs.valueUl.scrollTop = 0;
+			if(this.$refs.edb_detail_data){
+				this.$refs.edb_detail_data.$refs.valueUl.scrollTop=0
 			}
 			this.getDataList();
 		},
@@ -1653,10 +1733,18 @@ export default {
 		/* 基础指标刷新 */
 		refreshBaseHandler() {
 			this.refreshLoading = true;
+			this.loading = this.$loading({
+					lock: true,
+					target:'.detail',
+					text: '刷新数据中...',
+					spinner: 'el-icon-loading',
+					background: 'rgba(255, 255, 255, 0.8)'
+				});
 			dataBaseInterface.refreshBaseTarget({
 				EdbInfoId: Number(this.selected_edbid)
 			}).then(res => {
 				this.refreshLoading = false;
+				this.loading&&this.loading.close()
 				if(res.Ret !== 200) return;
 				this.$message.success(res.Msg);
 				this.initDataStatus();
@@ -1673,7 +1761,9 @@ export default {
 		/* 重新刷新 重新计算后重置刷数据 */
 		initDataStatus() {
 			this.page_no = 1;
-			this.$refs.valueUl.scrollTop = 0;
+			if(this.$refs.edb_detail_data){
+				this.$refs.edb_detail_data.$refs.valueUl.scrollTop=0
+			}
 			this.getDataList();
 		},
 		/* 用于复制指标 */
@@ -1771,7 +1861,7 @@ export default {
 		changeTreeNode(){
 			this.$refs.menuTree.setCurrentKey(this.select_node);
 			this.$nextTick(()=>{
-				const _node = this.$refs.menuTree.getNode(this.select_node)
+				const _node = this.$refs.menuTree.getCurrentNode()
 				this.dynamicNode = _node;
 				this.dynamicNode&&this.resetNodeStyle(this.dynamicNode)
 			})
@@ -1806,8 +1896,39 @@ export default {
 			if(node.level>maxLevel){
 				resolve([])
 			}
-		}
 		},
+		//保存指标上下限
+		saveEdbLimit(){
+			if(!this.$refs.createChart) return
+			//获取指标的上下限
+			const {MaxValue=0,MinValue=0} = this.$refs.createChart.chartInfo
+			dataBaseInterface.saveEdbChartLimit({
+				EdbInfoId:this.EdbData.EdbInfoId,
+				MaxValue:Number(MaxValue),
+				MinValue:Number(MinValue)
+			}).then(res=>{
+				if(res.Ret!==200) return 
+				this.$message.success('保存成功')
+			})
+		},
+		//重绘指标图表
+		rePainChart(){
+			if(this.activeTab!=='Chart') return
+			this.$nextTick(()=>{
+				this.$refs.createChart.getDataByPath()
+			})
+		},
+		/* 展开对应菜单 显示详情 */
+		detailShowHandle({ UniqueCode, EdbInfoId,ClassifyId}) {
+			let params = {
+				code: UniqueCode,
+				id: EdbInfoId,
+				classifyId:ClassifyId
+			};
+			this.selectCurrentNode(params);
+			this.select_classifyId = 0;
+		},
+	},
 	//离开页面时保存标签
 	beforeRouteLeave(to,from,next){
 		sessionStorage.setItem('database',JSON.stringify(this.labelList))
@@ -1815,7 +1936,7 @@ export default {
 	},
 	mounted() {
 		this.getlabelList()
-
+		this.getEdbChartList()
 		this.$route.query.code 
 		? this.getTreeData({code: this.$route.query.code,id: this.$route.query.id,classifyId:this.$route.query.classifyId})
 		: this.getTreeData();
@@ -1891,7 +2012,7 @@ export default {
 			width: 5px !important;
 		}
 		.main-left {
-			width: 500px;
+			width: 400px;
 			min-width: 300px;
 			background: #fff;
 			margin-right: 20px;
@@ -1904,11 +2025,13 @@ export default {
 			box-sizing: border-box;
 			.tree-cont {
 				padding: 30px;
-				height: calc(100vh - 290px);
-				overflow: auto;
+				/* height: calc(100vh - 290px);
+				overflow: auto; */
 			}
 			.target_tree {
 				color: #333;
+				height: calc(100vh - 350px);
+				overflow: auto;
 				.label-input .el-input__inner {
 					height: 25px;
 					line-height: 25px;
@@ -1971,7 +2094,7 @@ export default {
 				}
 			}
 			.noDepart {
-				margin: 60px 0;
+				margin: 30px 0;
 				display: flex;
 				align-items: center;
 				justify-content: center;
@@ -1995,28 +2118,51 @@ export default {
 		.main-right {
 			flex: 1;
 			/* width:70%; */
-			height: calc(100vh - 288px);
+			height: calc(100vh - 225px);
 			background: #fff;
 			border: 1px solid #ececec;
 			border-radius: 4px;
 			box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
-			padding: 30px;
 			overflow: hidden;
 			.value-ul {
 				margin-top: 10px;
-				border-bottom: 1px solid #dcdfe6;
-				max-height: calc(100vh - 560px);
-				overflow-y: auto;
+				border-bottom: 1px solid #EBEFF6;
+				//max-height: calc(100vh - 495px);
+				//overflow-y: auto;
 				.value-item {
 					/* width: 100%; */
-					padding: 14px 0;
+					padding: 10px 0;
 					border: 1px solid #dcdfe6;
 					border-bottom: none;
 					display: flex;
 					justify-content: space-around;
+					>span{
+						padding:0 16px;
+						box-sizing: border-box;
+					}
 					.value-label {
 						position: relative;
 						color: #666;
+						.value-style{
+							/* background-color: #ECF2FE;
+							color: #0052D9; */
+							padding:5px;
+							border-radius: 4px;
+							&.predict-act {
+								color: orange;
+							}
+						}
+						&.date{
+							&::after{
+								content: '';
+								position:absolute;
+								right:0;
+								top:-14px;
+								height:calc(100% + 28px);
+								width:1px;
+								background-color: #dcdfe6;
+							}
+						}
 					}
 					.predict-act {
 						color: orange;
@@ -2039,6 +2185,134 @@ export default {
 					color: #999;
 				}
 			}
+			&.list{
+				background-color: transparent;
+				box-shadow: none;
+				border:none;
+				padding:0 30px;
+				display: flex;
+				flex-direction: column;
+				.list-wrap{
+					flex: 1;
+					margin-top: 20px;
+					display: flex;
+					gap: 20px;
+					flex-wrap: wrap;
+					overflow-x: hidden;
+					overflow-y: auto;
+					.dragShdow {
+						box-shadow: 0 1px 8px rgba(64, 158, 255, 0.8);
+						opacity: 0.5;
+					}
+					.list-item{
+						width:23%;
+						height:375px;
+						background-color: #fff;
+						display: flex;
+						flex-direction: column;
+						box-sizing: border-box;
+						/* padding: 0 10px; */
+						border-radius: 4px;
+						border:1px solid #DCDFE6;
+						box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+						.header,.info{
+							padding:20px;
+							box-sizing: border-box;
+							text-align: left;
+						}
+						.header{
+							//border-bottom: 1px solid #DCDFE6;
+							white-space: nowrap;
+							overflow: hidden;
+							text-overflow: ellipsis;
+							font-size: 16px;
+							font-weight: 600;
+							box-shadow: 0 3px 6px rgba(37, 37, 239, 0.1);
+						}
+						.image{
+							padding:20px 20px 0 20px;
+							flex: 1;
+							cursor: pointer;
+							img{
+								width:100%;
+								height: 230px;
+								object-fit: cover !important;
+							}
+						}
+					}
+				}
+			}
+			&.detail{
+				display: flex;
+				flex-direction: column;
+				>.header{
+					display: flex;
+					position: relative;
+					height: 60px;
+					.el-tabs{
+						width:200px;
+						.el-tabs__header{
+							margin-bottom: 0;
+						}
+						.el-tabs__nav{
+							display: flex;
+							width: 100%;
+							.el-tabs__item{
+								flex: 1;
+								text-align: center;
+								font-size: 16px;
+								height: 60px;
+								line-height: 60px;
+							}
+						}
+					}
+					.edb-tool{
+						flex: 1;
+						text-align: right;
+						display: flex;
+						gap: 16px;
+						justify-content: flex-end;
+						padding-right: 15px;
+						position: relative;
+						&::after{
+							position: absolute;
+							content:'';
+							width:100%;
+							left: 0;
+							bottom: 0;
+							height:2px;
+							background-color: #E4E7ED;
+						}
+					}
+				}
+				.container{
+					flex: 1;
+					overflow-y: auto;
+					padding:15px;
+					.chart{
+						.info{
+							display: flex;
+							justify-content: space-between;
+						}
+						.table{
+							margin-top: 16px;
+							border:1px solid #E7E7E7 ;
+							.table-header{
+								display: flex;
+								padding:6px;
+								span{
+									flex: 1;
+									border-bottom: 1px solid #E7E7E7;
+								}
+							}
+						}
+					}
+					.list{
+						height: 100%;
+					}
+				}
+			}
+
 		}
 	}
 	.dialog-computed {

+ 8 - 0
src/views/dataEntry_manage/onlineExcelCopy.vue

@@ -185,6 +185,14 @@ created() {
       luckysheet.create(this.options)
     })
   },
+  beforeRouteEnter(to, from, next){
+    if(to.query.isEdit=='true'){
+      to.matched[1].name='编辑excel数据'
+    }else{
+      to.matched[1].name='复制excel数据'
+    }
+    next()
+  },
   beforeRouteLeave(to, from, next) {
     luckysheet.destroy()
     next();

+ 1 - 1
src/views/dataEntry_manage/targetList.vue

@@ -522,7 +522,7 @@ export default {
 				up_time = '';
 				up_day = '';
 			}
-				this.editTitle="修改指标名称";
+				this.editTitle="编辑指标";
 				this.editFormData = {
 					type:item.ClassifyName,
 					frequency:item.Frequency,

+ 8 - 0
src/views/datasheet_manage/customSheetEdit.vue

@@ -82,6 +82,14 @@ import CustomTable from './components/CustomTable.vue'
 import html2canvas from 'html2canvas';
 export default {
   components: { selectTarget,CustomTable },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.id){
+      to.matched[1].name=`编辑表格`
+    }else{
+      to.matched[1].name='添加表格'
+    }
+    next()
+  },
   data() {
     return {
       sheetId: this.$route.query.id || '',

+ 8 - 0
src/views/datasheet_manage/mixedSheetEdit.vue

@@ -61,6 +61,14 @@ import MixedTable from './components/MixedTable.vue'
 import html2canvas from 'html2canvas';
 export default {
   components: { selectTarget,MixedTable },
+  beforeRouteEnter(to, from, next) {
+    if(to.query.id){
+      to.matched[1].name=`编辑表格`
+    }else{
+      to.matched[1].name='添加表格'
+    }
+    next()
+  },
   data() {
     return {
       sheetId: this.$route.query.id || '',

+ 16 - 0
src/views/futures_manage/chartEditor.vue

@@ -580,6 +580,22 @@ export default {
 	},
 	destroyed() {
 		window.removeEventListener('resize', this.reloadRightWid);
+	},
+	beforeRouteEnter(to, from, next) {
+		if(to.query.code){
+			if(to.query.scence=='price'){
+				to.matched[1].name='编辑价格曲线'
+			}else{
+				to.matched[1].name='编辑利润曲线'
+			}
+		}else{
+			if(to.query.scence=='price'){
+				to.matched[1].name='添加价格曲线'
+			}else{
+				to.matched[1].name='添加利润曲线'
+			}
+		}
+		next()
 	}
 };
 </script>

+ 2 - 1
src/views/futures_manage/commodityChartBase.vue

@@ -747,7 +747,8 @@ export default {
 			this.$router.push({
         path: '/addCommodityChart',
         query: {
-          code: this.chartInfo.UniqueCode
+          code: this.chartInfo.UniqueCode,
+		  scence:this.chartInfo.Source==2?'price':'profit'
         }
       })
 		},

+ 139 - 0
src/views/login_manage/EmailModel.vue

@@ -0,0 +1,139 @@
+<template>
+    <div class="email-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="email">
+                <el-input
+                    type="text"
+                    v-model="form.email"
+                    auto-complete="off"
+                    placeholder="请输入邮箱"
+                >
+                </el-input>
+                <span class="inline-message el-form-item__error" 
+                    v-show="(emailCheck||accountForbidden)&&form.email.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="picCode">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.picCode"
+                    auto-complete="off"
+                    placeholder="请输入图形验证码"
+                >
+                    <div class="pic-box" slot="append" @click="getCodePic">
+                        <img :src="picSrc" alt="图形验证码"/>
+                    </div>
+                </el-input>
+            </el-form-item>
+            <el-form-item prop="checkCode" class="code-input">
+                <el-input
+                    type="text"
+                    v-model="form.checkCode"
+                    auto-complete="off"
+                    placeholder="请输入验证码"
+                ></el-input>
+                <el-button type="text" class="code-btn" @click="checkForm" :disabled="codeCountDown<60&&codeCountDown>0">{{codeStr}}</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+import {patternEmail} from '@/utils/commonOptions'
+import {departInterence} from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        emailCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountForbidden:{
+            type:Boolean,
+            default:false
+        },
+        Source:{//请求验证码来源:1登陆
+            type:Number,
+            default:1
+        }
+    },
+    data() {
+        return {
+            hasPicCode:true,
+            picSrc:'',
+            picId:'',
+            timer:0,
+            codeStr:'获取验证码',
+            codeCountDown:60,
+            form:{
+                email:'',
+                picCode:'',
+                checkCode:''
+            },
+            rules:{
+                email:[
+                    {required:true,message:'请输入邮箱',trigger:'blur'},
+                    {validator:(rule,value,callback)=>{
+                        if(!patternEmail.test(value)){
+                            callback(new Error("请输入正确的邮箱格式"))
+                        }else{
+                            callback()
+                        }
+                    },trigger:'blur'}
+                ],
+                picCode:[{required:true,message:'请输入图形验证码',trigger:'blur'}],
+                checkCode:[{required:true,message:'请输入短信验证码',trigger:'blur'}]
+            },
+            hintMessage:''
+        };
+    },
+    methods: {
+        checkForm(){
+            //首先检查是否是重新获取验证码
+            if(this.codeStr==='重新获取'){
+                //引导用户重新输入图形验证码
+                this.getCodePic()
+                this.form.picCode = ''
+            }
+            //检查邮箱和图形验证码是否正确
+            const {email,picCode} = this.form
+            if(!picCode.length){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            if(!patternEmail.test(email)){
+                this.$message.warning('请输入正确的邮箱')
+                return
+            }
+            //通过请求发送验证码
+            departInterence.getCodeVerify({
+                VerifyType:2,
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                Email:email,
+                Source:this.Source
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success('验证码已发送')
+                //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+            })
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 339 - 0
src/views/login_manage/ForgetPassModel.vue

@@ -0,0 +1,339 @@
+<template>
+    <div class="forget-pass-model">
+        <div class="header-nav" @click="changeModel">
+            <span><i class="el-icon-back"></i></span>
+            <span>忘记密码</span>
+        </div>
+        <div class="step-container model-wrap" v-show="currentStep===0">
+            <el-form 
+                ref="modelForm" 
+                label-position="right" 
+                label-width="0px"
+                :model="form"
+                :rules="rules">
+                <el-form-item prop="account">
+                    <el-input
+                        type="text"
+                        v-model="form.account"
+                        auto-complete="off"
+                        placeholder="请输入账号">
+                    </el-input>
+                </el-form-item>
+                <el-form-item prop="picCode">
+                    <el-input
+                        class="input-with-slot"
+                        type="text"
+                        v-model="form.picCode"
+                        auto-complete="off"
+                        placeholder="请输入图形验证码"
+                    >
+                        <div class="pic-box" slot="append" @click="getCodePic">
+                            <img :src="picSrc" alt="图形验证码"/>
+                        </div>
+                    </el-input>
+                </el-form-item>
+            </el-form>
+            <el-button class="submit_btn" @click="getUserInfo">下一步</el-button>
+        </div>
+        <div class="step-container" v-show="currentStep>0">
+            <div class="container-header">
+                <p>您正在找回账号{{form.account}}的密码</p>
+                <ModelSteps :active-step="currentStep"/>
+            </div>
+            <div class="container-inner model-wrap" v-show="currentStep===1">
+                <VerificationBox
+                    verifies-type="mobile"
+                    :info-text="userMobile||'暂未绑定'"
+                    :hideBtn="!userMobile"
+                    @goNext="getCode"
+                />
+                <VerificationBox
+                    verifies-type="email"
+                    :info-text="userEmail||'暂未绑定'"
+                    :hideBtn="!userEmail"
+                    @goNext="getCode"
+                />
+            </div>
+            <div class="container-inner" v-show="currentStep===2">
+                <CaptchaInput 
+                    ref="captInput"
+                />
+                <div class="btn-wrap">
+                    <el-button type="primary" plain @click="changeModel">上一步</el-button>
+                    <el-button type="primary" @click="checkInput">下一步</el-button>
+                </div>
+                
+            </div>
+            <div class="container-inner model-wrap" v-show="currentStep===3">
+                <el-form 
+                    ref="passForm" 
+                    label-position="right" 
+                    label-width="0px"
+                    :model="passForm"
+                    :rules="passRules">
+                    <el-form-item prop="pass1">
+                        <el-input
+                            type="password" show-password
+                            v-model.trim="passForm.pass1"
+                            auto-complete="off"
+                            @copy.native.capture.prevent="()=>{return false}"
+                            @cut.native.capture.prevent="()=>{return false}"
+                            @paste.native.capture.prevent="()=>{return false}"
+                            placeholder="请输入新密码">
+                        </el-input>
+                    </el-form-item>
+                    <el-form-item prop="pass2">
+                        <el-input
+                            type="password" show-password
+                            v-model.trim="passForm.pass2"
+                            auto-complete="off"
+                            @copy.native.capture.prevent="()=>{return false}"
+                            @cut.native.capture.prevent="()=>{return false}"
+                            @paste.native.capture.prevent="()=>{return false}"
+                            placeholder="请确认新密码">
+                        </el-input>
+                    </el-form-item>
+                </el-form>
+                <el-button class="submit_btn" @click="handleResetPass">{{checkPassStr}}</el-button>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import CaptchaInput from './components/CaptchaInput.vue';
+import ModelSteps from './components/ModelSteps.vue';
+import VerificationBox from './components/VerificationBox.vue';
+import modelMixins from './modelMixins';
+import{checkPassWord} from '@/utils/commonOptions';
+import http from '@/api/http.js';
+import {departInterence } from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        autoAccount:{//自动填写的账号,如果有,作为form.accout的初始值
+            type:String,
+            default:''
+        }
+    },
+    components: { VerificationBox, ModelSteps, CaptchaInput },
+    data() {
+        const validatePass = (rule,value,callback)=>{
+            if(value===''){
+                callback(new Error('请输入新密码'))
+            }
+            if(this.passForm.pass2!==''){
+                this.$refs.passForm.validateField('pass2')
+            }
+            if(!checkPassWord(value)){
+                callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+            }else{
+                callback()
+            }
+        }
+        const validateCheck = (rule,value,callback)=>{
+            if(value===''){
+                callback(new Error('请输入确认密码'))
+            }else if(value!==this.passForm.pass1){
+                callback(new Error('两次输入的密码不一致,请检查'))
+            }else{
+                callback()
+            }
+        }
+        return {
+            currentStep:0,
+            /* form */
+            form:{//步骤0的表单
+                account:this.autoAccount,
+                picCode:''
+            },
+            picSrc:'',
+            picId:'',
+            passForm:{//设置新密码的表单
+                pass1:'',
+                pass2:''
+            },
+            /* form rule */
+            rules:{},
+            passRules:{
+                pass1:[{validator: validatePass,trigger: 'blur'}],
+                pass2:[{validator: validateCheck,trigger: 'blur'}]
+            },
+            /*user info */
+            userMobile:'',//用户的手机号
+            TelAreaCode:'',//用户手机号的区号
+            userEmail:'',//用户的邮箱
+            /* check way */
+            checkWay:'',//选择的验证方式
+            authCode:'',//手机/邮箱验证码,从CaptchaInput组件中取
+            mobileCountDown:0,//手机获取验证码倒计时
+            emailCountDown:0,//邮箱验证码倒计时
+            checkPassStr:'确定',//重置密码按钮
+            countDownNum:5,
+            resetPassTimer:0,
+        };
+    },
+    created(){
+        this.getCodePic()
+    },
+    methods: {
+        //获取用户账号信息
+        getUserInfo(){
+            //检查form是否填写完整
+            const {account,picCode} = this.form
+            if(!account){
+                this.$message.warning('请输入账号')
+                return
+            }
+            if(!picCode){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            //请求接口获取账号数据,赋值userMobile,userEmail
+            departInterence.accountCheck({
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                UserName:account
+            }).then(res=>{
+                if(res.Ret!==200){
+                    //刷新图形验证码
+                    this.getCodePic()
+                    this.form.picCode=''
+                    return
+                }
+                if(res.Data){
+                    this.userMobile = res.Data.Mobile||''
+                    this.userEmail = res.Data.Email||''
+                    this.TelAreaCode = res.Data.TelAreaCode||''
+                    this.goSteps()
+                }
+                
+            })
+        },
+        //获取对应验证方式的验证码
+        getCode(way){
+            this.checkWay = way
+            departInterence.getCodeVerify({
+                VerifyType:way==='mobile'?1:2,
+                CaptchaId:this.picId,
+                CaptchaCode:this.form.picCode,
+                Mobile:way==='mobile'?this.userMobile:'',
+                TelAreaCode:way==='mobile'?this.TelAreaCode:'',
+                Email:way==='email'?this.userEmail:'',
+                Source:3
+            }).then(res=>{
+                if(res.Ret!==200) return
+                /* //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+                this.goSteps() */
+                this.goSteps()
+            })
+        },
+        //检查输入的验证码
+        checkInput(){
+            const code = this.$refs.captInput.captchas.map((x) => x.num).join("");
+            if(code.length!==6){
+                this.$message.warning('请输入完整的验证码')
+                return
+            }
+            departInterence.checkCodeVerify({
+                FindType:this.checkWay==='mobile'?1:2,
+                VerifyCode:code,
+                UserName:this.form.account,
+                Mobile:this.checkWay==='mobile'?this.userMobile:'',
+                Email:this.checkWay==='email'?this.userEmail:''
+            }).then(res=>{
+                if(res.Ret!==200) return
+                this.goSteps()
+            })
+
+        },
+        goSteps(){
+            this.currentStep++
+        },
+        changeModel(){
+            if(this.currentStep>0){
+                this.currentStep--
+                if(this.currentStep===0){
+                    this.getCodePic()
+                    this.form.picCode = ''
+                }
+            }else{
+                this.$emit('changeModel')
+            }
+            
+        },
+        handleResetPass(){
+            if(this.checkPassStr.includes('去登陆')){
+                this.$emit('changeModel')
+                return
+            }
+            this.$refs.passForm.validate((valid)=>{
+                if(valid){
+                    //重置密码
+                    departInterence.resetPass({
+                        UserName:this.form.account,
+                        Password:new http.Base64().encode(this.passForm.pass1),
+                        RePassword:new http.Base64().encode(this.passForm.pass2)
+                    }).then(res=>{
+                        if(res.Ret!==200) return
+                        this.$message.success('重置密码成功,请登陆')
+                        this.resetPassCountDown()
+                        this.resetPassTimer = setInterval(()=>{
+                            this.resetPassCountDown()
+                        },1000)
+                    })
+                }
+            })
+        },
+        resetPassCountDown(){
+            this.countDownNum--
+            this.checkPassStr = `去登陆(${this.countDownNum}s)`
+            if(this.countDownNum<=0){
+                clearInterval(this.resetPassTimer)
+                this.$emit('changeModel')
+                return
+            }
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>
+<style scoped lang="scss">
+.forget-pass-model{
+    .header-nav{
+        font-size: 38px;
+        margin-bottom: 60px;
+        cursor: pointer;
+    }
+    .step-container{
+        .container-header{
+            margin-bottom: 60px;
+            p{
+               font-size: 18px;
+               padding-bottom: 20px;
+               border-bottom: 1px solid #DCDFE6; 
+               margin-bottom: 60px;
+            }
+            .el-steps{
+                margin-top: 60px;
+            }
+        }
+        .container-inner{
+            .btn-wrap{
+                margin-top: 100px;
+                text-align: center;
+                .el-button{
+                    width:200px;
+                }
+            }
+        }
+    }
+}
+</style>

+ 156 - 0
src/views/login_manage/MobileModel.vue

@@ -0,0 +1,156 @@
+<template>
+    <div class="mobile-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="mobile">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.mobile"
+                    auto-complete="off"
+                    placeholder="请输入手机号"
+                >
+                    <el-select v-model="areaCodeSelect" slot="prepend" placeholder="请选择">
+                        <el-option v-for="item in areaCode" :key="item.Value"
+                            :label="item.Name" :value="item.Value" />
+                    </el-select>
+                </el-input>
+                <span class="inline-message el-form-item__error" 
+                    v-show="(mobileCheck||accountForbidden)&&form.mobile.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="picCode">
+                <el-input
+                    class="input-with-slot"
+                    type="text"
+                    v-model="form.picCode"
+                    auto-complete="off"
+                    placeholder="请输入图形验证码"
+                >
+                    <div class="pic-box" slot="append" @click="getCodePic">
+                        <img :src="picSrc" alt="图形验证码"/>
+                    </div>
+                </el-input>
+            </el-form-item>
+            <el-form-item prop="checkCode" class="code-input">
+                <el-input
+                    type="text"
+                    v-model="form.checkCode"
+                    auto-complete="off"
+                    placeholder="请输入验证码">
+                </el-input>
+                <el-button type="text" class="code-btn" @click="checkForm" :disabled="codeCountDown<60&&codeCountDown>0">{{codeStr}}</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+import {isMobileNo} from '@/utils/commonOptions'
+import {departInterence } from "@/api/api.js";
+export default {
+    mixins:[modelMixins],
+    props:{
+        mobileCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountForbidden:{
+            type:Boolean,
+            default:false
+        },
+        areaCode:{
+            type:Array,
+            default:()=>{return []}
+        },
+        Source:{//请求验证码来源:1登陆
+            type:Number,
+            default:1
+        }
+    },
+    data() {
+        return {
+            hasPicCode:true,//是否需要图形验证码
+            areaCodeSelect:'86',
+            picSrc:'',//图形验证码地址
+            picId:'',//图形验证码id
+            timer:0,
+            codeStr:'获取验证码',
+            codeCountDown:60,
+            form:{
+                mobile:'',
+                picCode:'',
+                checkCode:''
+            },
+            rules:{
+                mobile:[
+                    {required: true,message: "请输入手机号",trigger: "blur"},
+                    {validator:(rule,value,callback)=>{
+                        if(this.areaCodeSelect==='86'&&!isMobileNo(value)){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else if(this.areaCodeSelect!=='86'&&isNaN(value.trim())){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else{
+                            callback()
+                        }
+                    },trigger:'blur'}
+                ],
+                picCode:[{required:true,message:'请输入图形验证码',trigger:'blur'}],
+                checkCode:[{required:true,message:'请输入短信验证码',trigger:'blur'}]
+            }
+        };
+    },
+    methods: {
+        checkForm(){
+            //首先检查是否是重新获取验证码
+            if(this.codeStr==='重新获取'){
+                //引导用户重新输入图形验证码
+                this.getCodePic()
+                this.form.picCode = ''
+            }
+            //检查手机号和图形验证码是否正确
+            const {picCode,mobile} = this.form
+            if(!picCode.length){
+                this.$message.warning('请输入图形验证码')
+                return
+            }
+            if(this.areaCodeSelect==='86'&&!isMobileNo(mobile)){
+                this.$message.warning('请输入正确的手机号')
+                return
+            }
+            /* this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000) */
+            //通过请求发送验证码
+            departInterence.getCodeVerify({
+                VerifyType:1,
+                CaptchaId:this.picId,
+                CaptchaCode:picCode,
+                Mobile:mobile,
+                TelAreaCode:this.areaCodeSelect,
+                Source:this.Source
+            }).then(res=>{
+                if(res.Ret!==200) return 
+                this.$message.success('验证码已发送')
+                //60秒倒计时
+                this.countDown()
+                this.timer = setInterval(()=>{
+                    this.countDown()
+                },1000)
+            })
+
+        }
+    },
+};
+</script>
+
+<style lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 117 - 0
src/views/login_manage/OrdinaryModel.vue

@@ -0,0 +1,117 @@
+<template>
+    <div class="ordinary-model-wrap model-wrap">
+        <el-form 
+            ref="modelForm" 
+            label-position="right" 
+            label-width="0px"
+            :model="form"
+            :rules="rules">
+            <el-form-item prop="account">
+                <el-input
+                    type="text"
+                    v-model="form.account"
+                    auto-complete="off"
+                    placeholder="请输入用户名"
+                />
+                <span class="inline-message el-form-item__error" 
+                    v-show="(loginCheck||accountCheck)&&form.account.length">
+                    {{hintMessage}}
+                </span>
+            </el-form-item>
+            <el-form-item prop="checkPass">
+                <el-input
+                    type="password" show-password
+                    v-model="form.checkPass"
+                    auto-complete="off"
+                    placeholder="请输入密码"
+                    @copy.native.capture.prevent="()=>{return false}"
+                    @cut.native.capture.prevent="()=>{return false}"
+                    @paste.native.capture.prevent="()=>{return false}"
+                />
+                <span class="inline-message el-form-item__error" 
+                    v-show="(loginCheck||accountCheck)&&form.checkPass.length">
+                    {{hintMessage}}</span>
+            </el-form-item>
+            <el-form-item class="remember-cont" prop="checked">
+                <el-checkbox v-model="form.checked" class="remember">
+                    记住账号密码
+                    <el-tooltip effect="dark" content="有效期60天" placement="top">
+                        <span class="hint-text">
+                            <i class="el-icon-question"></i>
+                        </span>
+                    </el-tooltip>
+                </el-checkbox>
+                <el-button type="text" style="font-size: 16px;" @click="changeModel">忘记密码</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+
+<script>
+import modelMixins from './modelMixins';
+export default {
+    mixins:[modelMixins],
+    props:{
+        loginCheck:{
+            type:Boolean,
+            default:false
+        },
+        accountCheck:{
+            type:Boolean,
+            default:false
+        }
+    },
+    data() {
+        const validateClearn = (rule,value,callBack)=>{
+            if(this.loginCheck||this.accountCheck){
+                this.$emit('clearnHint')
+            }
+            callBack()
+        }
+        return {
+            form:{
+                account:'',
+                checkPass:'',
+                checked:false
+            },
+            rules:{
+                account:[
+                    {required: true,message: "请输入账号",trigger: "blur"},
+                    {validator:validateClearn,trigger:['change']}
+                ],
+                checkPass:[
+                    {required: true,message: "请输入密码",trigger: "blur"},
+                    {validator:validateClearn,trigger:['change']}
+                ]
+            },
+            hintMessage:''
+        };
+    },
+    watch:{
+        loginCheck(newVal){
+            //显示/隐藏inline-message
+            if(newVal){
+                this.hintMessage="账号或密码错误"
+            }else{
+                this.hintMessage=''
+            }
+        },
+        accountCheck(newVal){
+            if(newVal){
+                this.hintMessage="账号异常,请通过验证登录"
+            }else{
+                this.hintMessage=''
+            }
+        }
+    },
+    methods: {
+        changeModel(){
+            this.$emit('changeModel')
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+@import "./css/formStyle.scss";
+</style>

+ 108 - 0
src/views/login_manage/components/CaptchaInput.vue

@@ -0,0 +1,108 @@
+<template>
+    <!-- 格子验证码输入组件 -->
+    <div class="row-center captcha_input_wrap">
+        <input
+            v-for="(item, index) in captchas"
+            :key="index"
+            v-model="item.num"
+            :id="'captcha' + index"
+            @input="inputFinash(index)"
+            @focus="adjust(index)"
+            @keydown="(e)=>{inputDirection(index,e)}"
+            class="captcha_input_box row-center"
+            :class="[index <= activeInput ? 'active' : '']"
+            type="tel"
+            maxlength="1"
+        />
+  </div>
+</template>
+  
+  <script>
+export default {
+  data() {
+    return {
+      // 当前输入框
+      activeInput: 0,
+      captchas: [
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+        { num: "" },
+      ],
+    };
+  },
+  //   页面加载后聚焦第一个
+  mounted() {
+    let dom = document.getElementById("captcha" + this.activeInput);
+    dom.focus();
+  },
+ 
+  methods: {
+    // 自动校准输入顺序
+    adjust(index) {
+      let dom = document.getElementById("captcha" + this.activeInput);
+      if (index !== this.activeInput && dom) {
+        dom.focus();
+      }
+    },
+    // 控制前后方向
+    inputDirection(index,e) {
+      let val = this.captchas[index].num;
+      // 回退键处理
+      if (e.key==='Backspace' && val === "") {
+        // 重新校准
+        let dom = document.getElementById("captcha" + (index - 1));
+        this.activeInput = index - 1;
+        if (dom) dom.focus();
+      }
+      if (e.key!=='Backspace' && val !== "") {
+        let dom = document.getElementById("captcha" + (index + 1));
+        this.activeInput = index + 1;
+        if (dom) dom.focus();
+      }
+    },
+    // 输入框相互联动
+    inputFinash(index) {
+      let val = this.captchas[index].num;
+      this.activeInput = val ? index + 1 : index - 1;
+      let dom = document.getElementById("captcha" + this.activeInput);
+      if (dom) dom.focus();
+      if (index == this.captchas.length - 1) {
+        let code = this.captchas.map((x) => x.num).join("");
+        if (code.length == 6) {
+          this.$emit("finish", code);
+        }
+      }
+    },
+  },
+};
+</script>
+  
+<style scoped lang='scss'>
+.row-center {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+    gap:40px;
+}
+.captcha_input_wrap {
+    width: 100%;
+}
+.captcha_input_box {
+    width: 40px;
+    height: 40px;
+    background: rgba(255, 255, 255, 1);
+    border-radius: 6px;
+    border: 1px solid #dddddd;
+    font-size: 16px;
+    text-align: center;
+    color: #1e243a;
+    outline: none;
+}
+.active {
+    border: 1px solid #3654C1 !important;
+}
+</style>

+ 99 - 0
src/views/login_manage/components/ModelSteps.vue

@@ -0,0 +1,99 @@
+<template>
+    <ul class="model-step-wrap">
+        <li v-for="(step,index) in stepList" :key="step.text"
+            class="step-item"
+            :class="{'active':index+1===activeStep,'success':index+1<activeStep}"
+        >   
+            <div class="step-line"></div>
+            <div class="step-num" v-if="index+1>=activeStep">{{index+1}}</div>
+            <div class="step-num" v-else><i class="el-icon-check"></i></div>
+            <div class="step-text">{{step.text}}</div>
+            
+        </li>
+    </ul>
+</template>
+
+<script>
+export default {
+    props:{
+        stepList:{
+            type:Array,
+            default:()=>{
+                return [
+                    {text:'选择验证方式'},
+                    {text:'进行安全验证'},
+                    {text:'设置密码'}
+                ]
+            }
+        },
+        activeStep:{
+            type:Number,
+            default:1
+        }
+    },
+    data() {
+        return {
+
+        };
+    },
+    methods: {
+
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.model-step-wrap{
+    display: flex;
+    justify-content: center;
+    width: 100%;
+    .step-item{
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        color: #DCDCDC;
+        font-size: 20px;
+        &:first-child{
+            .step-line{
+                display: none;
+            }
+        }
+        &:last-child{
+            .step-text{
+                margin-right: 0;
+            }
+        }
+        &.active,&.success{
+            color:#3654C1;
+            .step-num{
+                border-color: #3654C1;
+                color: #3654C1;
+            }
+            .step-line{
+                background-color: #3654C1;
+            }
+        }
+        &.success{
+            color: #000;
+        }
+        .step-num{
+            width:24px;
+            height:24px;
+            font-size: 16px;
+            border:1px solid #DCDCDC;
+            border-radius: 50%;
+            text-align: center;
+            line-height: 25px;
+        }
+        .step-line{
+           flex: 1;
+           height:2px;
+           background-color:#DCDCDC ;
+           min-width: 40px;
+        }
+        .step-text{
+            margin-right: 16px;
+        }
+    }
+}
+</style>

+ 79 - 0
src/views/login_manage/components/VerificationBox.vue

@@ -0,0 +1,79 @@
+<template>
+    <div class="verification-box-wrap">
+        <div class="icon">
+            <img :src="verifiesType==='mobile'?mobile_src:email_src" />
+        </div>
+        <div class="text">{{infoText}}</div>
+        <el-button  type="primary" @click="goNext" v-if="!hideBtn" :disabled="countDown">{{countDown?`重发(${countDown}秒)`:btnText}}</el-button>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        verifiesType:{//安全验证 mobile or email
+            type:String,
+            default:'mobile'
+        },
+        infoText:{//手机号或邮箱
+            type:String,
+            default:'123456'
+        },
+        hideBtn:{
+            type:Boolean,
+            default:false
+        },
+        countDown:{
+            type:Number,
+            default:0
+        },
+        btnText:{
+            type:String,
+            default:'开始验证'
+        }
+    },
+    data() {
+        return {
+            mobile_src:require('@/assets/img/home/phone_icon.png'),
+            email_src:require('@/assets/img/home/email_icon.png'),
+        };
+    },
+    methods: {
+        goNext(){
+            this.$emit('goNext',this.verifiesType)
+        }
+    },
+};
+</script>
+
+<style scoped lang="scss">
+.verification-box-wrap{
+    display: flex;
+    align-items: center;
+    margin-bottom: 60px;
+    cursor: pointer;
+    .icon{
+        width:40px;
+        height:40px;
+        box-sizing: border-box;
+        padding:8px;
+        border-radius: 50%;
+        box-shadow: 0px 2px 12px 0px #0000001A;
+        text-align: center;
+        img{
+            width: 24px;
+            height: 24px;
+        }
+    }
+    .text{
+        margin-left: 20px;
+        font-size: 18px;
+    }
+    .el-button{
+        /* background-color: #3654C1;
+        color: #fff; */
+        margin-left: auto;
+    }
+}
+
+</style>

+ 111 - 0
src/views/login_manage/css/formStyle.scss

@@ -0,0 +1,111 @@
+.model-wrap{
+    margin-top: 25px;
+    .remember-cont{
+        margin-top: -10px;
+        margin-bottom: 60px !important;
+        width: 100%;
+        .hint-text{
+            color: #606266 !important;
+            font-size: 16px;
+        }
+        .el-form-item__content{
+            display: flex;
+            width: 100%;
+            justify-content: space-between;
+            .remember{
+                flex: 1;
+                .el-checkbox__label{
+                    font-size: 16px;
+                }
+            }
+        }
+    }
+    .el-form-item{
+        margin-bottom: 40px;
+        .el-input__inner{
+            height: 50px;
+            border-radius: 8px;
+            font-size: 16px;
+        }
+    }
+    .el-form-item.is-error{
+        .inline-message{
+            display: none;
+        }
+    }
+    .input-with-slot{
+        display: flex;
+        &.el-input-group--prepend{
+            .el-input__inner{
+                border-top-left-radius: 0;
+                border-bottom-left-radius: 0;
+            }
+        }
+        &.el-input-group--append{
+            .el-input__inner{
+                border-top-right-radius: 0;
+                border-bottom-right-radius: 0;
+            }
+        }
+        .el-input__inner{
+            flex: 1;
+            height: 50px !important;
+        }
+        .el-input-group__prepend,.el-input-group__append{
+            padding:0 !important;
+            background-color: #fff;
+            width:110px;
+            height: 50px;
+            box-sizing: border-box;
+            overflow: hidden;
+            .el-input__inner{
+                padding:0;
+            }
+            .el-select{
+                margin:0;
+                width:110px;
+                .el-input__inner{
+                    width:100%;
+                    text-align: center;
+                }
+            }
+        }    
+        .pic-box{
+            cursor: pointer;
+            width:110px;
+            height:50px;
+            overflow: hidden;
+            padding:5px;
+            box-sizing: border-box;
+            background-color: #D7F1F6;
+            img{
+                width: 100%;
+                height: 100%;
+            }
+        }
+        .code{
+            display: inline-block;
+            width:100%;
+            text-align: center;
+            line-height: 40px;
+            cursor: pointer;
+        }
+    }
+    .submit_btn {
+        width: 100%;
+        height: 50px;
+        background: #3654C1;
+        font-size: 20px;
+        border-radius: 5px;
+        color: #fff;
+    }
+    .code-input{
+        position:relative;
+        .code-btn{
+            position:absolute;
+            top:5px;
+            right: 20px;
+            font-size: 16px;
+        }
+    }
+}

+ 34 - 0
src/views/login_manage/modelMixins.js

@@ -0,0 +1,34 @@
+import {departInterence } from "@/api/api.js";
+export default {
+    methods:{
+        modelInit(){
+            //重置表单
+            this.form = this.$options.data().form
+            //如果有图形验证码,重新请求
+            this.hasPicCode && this.getCodePic()
+        },
+        //获取图片验证码
+        getCodePic(){
+            //存base64和id
+            departInterence.getCodePic().then(res=>{
+                if(res.Ret!==200) return 
+                if(res.Data){
+                    this.picSrc = res.Data.Base64Blob,
+                    this.picId = res.Data.Id
+                }
+                
+            })
+        },
+        countDown(){
+            /* if(!this.timer) return */
+            console.log('click down')
+            this.codeCountDown--
+            this.codeStr=`重新获取(${this.codeCountDown})秒`
+            if(this.codeCountDown<=0){
+                clearInterval(this.timer)
+                this.codeStr = '重新获取'
+                return
+            }
+        }
+    }
+}

+ 8 - 4
src/views/ppt_manage/mixins/pptMixins.js

@@ -10,7 +10,7 @@ import futuresInterface from '@/api/modules/futuresBaseApi';
 import { fittingEquationInterface,statisticFeatureInterface } from '@/api/modules/chartRelevanceApi';
 import chartRelevanceApi from '@/api/modules/chartRelevanceApi.js';
 import { defaultOpts } from '@/utils/defaultOptions';
-import {formatPPTDate,checkPPTpageElemant,getStrSize} from '../newVersion/utils/untils.js';
+import {formatPPTDate,checkPPTpageElemant,getStrSize,isShowPPTTitle} from '../newVersion/utils/untils.js';
 import FormatOne from '../newVersion/components/formatPage/FormatOne.vue';
 import FormatTwo from '../newVersion/components/formatPage/FormatTwo.vue';
 import FormatThree from '../newVersion/components/formatPage/FormatThree.vue';
@@ -412,10 +412,14 @@ export default {
         MyChartType: 2 季节性图,7 柱形图,  10 截面散点图,
         Source:2
         MyChartType: 8 商品价格曲线图
+        Source:5
+        MyChartType: 8 利润曲线
+        Source:6 拟合方程曲线
+        Source:7 统计特征
         以上图表需要显示标题
       */
      const {Source,MyChartType} = options
-     const isShowTitle = Source===1&&[2,7,10].includes(MyChartType)||Source===2&&MyChartType===8
+     const isShowTitle = isShowPPTTitle(Source,MyChartType)
       this.$nextTick(() => {
         let is_linear = options.series 
           ? options.series.every(_ => _.type === 'scatter' ) || options.series.some(_ => _.chartType === 'linear'  )
@@ -428,7 +432,7 @@ export default {
         let {total,newStr} = getStrSize(options.MyChartTitle,count)
         const isPublish = this.$route.path==='/pptpublish'||this.$route.path==='/pptenpublish'
         if(isShowTitle){
-          titleHTML = `<div style="white-space: normal;">${options.MyChartTitle}</div>`
+          titleHTML = `<div style="white-space: normal;font-size:18px;">${options.MyChartTitle}</div>`
         }
         let SpecialOption = {
           chart: {
@@ -439,7 +443,7 @@ export default {
           title: isPublish?{
             text: isShowTitle?newStr:null,
             useHTML:false,
-            style:{},
+            style:{fontSize:'18px'},
             align:total>count?'left':'center',
           }:{
             text: titleHTML,

+ 120 - 0
src/views/ppt_manage/newVersion/components/editor/InsertSemantics.vue

@@ -0,0 +1,120 @@
+<template>
+    <div class="import-mychart-wrap">
+        <div>
+            <el-input
+				placeholder="关键词搜索"
+				v-model="keyword"
+				size="medium"
+				prefix-icon="el-icon-search"
+                @input="handleChange"
+			/>
+		</div>
+		<div class="list" v-infinite-scroll="load" v-if="list.length>0">
+            <div class="item" v-for="item in list" :key="item.SaCompareId" @click="handleClickItem(item)">
+                <p>{{ item.Title }}</p>
+                <img :src="item.PicUrl" alt="">
+            </div>
+		</div>
+        <div v-if="list.length==0" class="empty-box">
+            无数据
+        </div>
+    </div>
+</template>
+
+<script>
+import {semanticInterface} from '@/api/modules/semanticsApi.js';
+export default {
+    data() {
+        return {
+            keyword:'',
+            pageSize:20,
+			CurrentIndex: 1,
+			list:[],
+            loading:false,
+            finished:false,
+
+        }
+    },
+    mounted(){
+        this.handleGetList()
+    },  
+    methods: {
+		async handleGetList(){
+            this.loading=true
+            const res=await semanticInterface.compareSearch({
+				PageSize: this.pageSize,
+				CurrentIndex: this.CurrentIndex,
+				Keyword: this.keyword
+			})
+            this.loading=false
+            let arr=res.Data.List||[]
+            arr=arr.map(item => {
+               return {
+                   ...item,
+                   PicUrl:item.ResultImg
+               } 
+            });
+
+            this.list=[...this.list,...arr]
+            if(!res.Data){
+                this.finished=true
+            }
+            if(res.Data&&res.Data.Paging.IsEnd){
+                this.finished=true
+            }
+		},
+
+        load(){
+            if(this.finished) return
+            this.CurrentIndex++
+            this.handleGetList()
+        },
+        handleChange(){
+            console.log('aaa');
+            this.CurrentIndex=1
+            this.finished=false
+            this.list=[]
+            this.handleGetList()
+        },
+
+        handleClickItem(item){
+           this.$parent.chooseChart(item,'sandImage')
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.import-mychart-wrap{
+    .list{
+        height: calc(100vh - 320px);
+        overflow-x: hidden;
+		overflow-y: auto;
+        .item{
+            width: 100%;
+            margin: 20px 0;
+            padding: 20px;
+            box-sizing: border-box;
+            border: 1px solid #eaeaea;
+            border-radius: 10px;
+            position: relative;
+            overflow: hidden;
+            p{
+                text-align: center;
+                font-size: 16px;
+                margin-bottom: 10px;
+                color: #5882EF;
+            }
+            img{
+                width: 100%;
+            }
+        }
+    }
+    .empty-box{
+        height: calc(100vh - 320px);
+        text-align: center;
+        color: #999;
+        padding-top: 100px;
+    }
+}
+</style>

+ 28 - 14
src/views/ppt_manage/newVersion/pptCatalog.vue

@@ -385,20 +385,34 @@ export default {
   watch:{
     searchTitle(newVal){
       let data = null
-      this.publicList.forEach((item)=>{
+      let search='private'
+      this.privateList.forEach((item)=>{
         item.children.forEach(i=>{
-          if(i.PptId===newVal){
-            data = i
-          }
+            if(i.PptId===newVal){
+                data = i
+                search='private'
+            }
         })
       })
-      this.default_tab = '3';
-      //选中该节点
-      this.$refs.publicTree.setCurrentKey('ppt'+newVal)
-      //展开该节点的父节点...
-      const node = this.$refs.publicTree.getCurrentNode()
-      this.publicExpandKeys.push(node.catalogId)
-      this.nodeChange(data,_,'public')
+      if(!data){
+        this.publicList.forEach((item)=>{
+            item.children.forEach(i=>{
+                if(i.PptId===newVal){
+                    data = i
+                    search='public'
+                }
+            })
+        })
+      }
+      if(data){
+        this.default_tab = search==='public'?'3':'1';
+        //选中该节点
+        this.$refs[`${search}Tree`].setCurrentKey('ppt'+newVal)
+        //展开该节点的父节点...
+        const node = this.$refs[`${search}Tree`].getCurrentNode()
+        this[`${search}ExpandKeys`].push(node.catalogId)
+        this.nodeChange(data,_,search)
+      }
       this.searchOptions=[]
     },
 /*     default_tab(newVal){
@@ -1055,7 +1069,7 @@ export default {
     //搜索ppt标题
     searchHandle(keyword){
       //searchPPT->searchPPTByKeyWorld
-      pptInterface.searchPPTByKeyWorld({
+      pptInterface.searchPPTByKeyWorldV2({
         Keyword:keyword
       }).then(res=>{
         if(res.Ret===200){
@@ -1259,7 +1273,7 @@ export default {
       height: 0;
     }
     .el-tabs__item.is-active {
-      border-bottom: 2px solid #409EFF;
+      border-bottom: 2px solid #0052D9;
     }
     .el-tabs__item { font-size: 16px; }
     .ppt-list-wrap{
@@ -1375,7 +1389,7 @@ export default {
       h3{
         span{
           margin-left: 20px;
-          color:#409EFF;
+          color:#0052D9;
           font-size: 12px;
           font-weight: normal;
         }

+ 6 - 2
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -176,6 +176,9 @@
               <div v-show="tabsactive == 'MyETA批量'" class="chart-tool flex-column">
                 <insert-charts @handleImportMyChart="handleImportMyChart"/>
               </div>
+              <div v-show="tabsactive == '语义分析插入'" class="chart-tool flex-column">
+                <InsertSemantics />
+              </div>
             </div>
             <!-- 图层编辑 -->
             <div class="layer-edit-box" v-else>
@@ -287,6 +290,7 @@ import InsertPageDialog from './components/editor/InsertPageDialog.vue';
 import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
 import InsertCharts from './components/editor/InsertCharts.vue';
 import ContextMenu from './components/ContextMenu.vue';
+import InsertSemantics from './components/editor/InsertSemantics.vue';
 export default {
   mixins:[pptmixin,//ppt页面共同逻辑
           mixins,//图表加载逻辑
@@ -295,7 +299,7 @@ export default {
           ],
   components: { 
         IndexItem, ChooseCover, AddFormat,ShapePreview,
-    LayerEditTool,DeletePageDialog,ChangeFormatDialog,InsertPageDialog,addMyClassifyDia,InsertCharts,ContextMenu
+    LayerEditTool,DeletePageDialog,ChangeFormatDialog,InsertPageDialog,addMyClassifyDia,InsertCharts,ContextMenu,InsertSemantics
   },
   data() {
     return {
@@ -339,7 +343,7 @@ export default {
         catalogId:0,//ppt目录id,添加ppt时需要
         ReportId:0,//ppt对应的双周报id,如果没转过,则为0
         isChartLoading:false,//是否正在加载图表/图片
-        panelTabs: [ '图表','MyETA批量','沙盘','表格' ],
+        panelTabs: [ '图表','MyETA批量','沙盘','表格','语义分析插入' ],
         sheetSearchList:[],
         sheetSearchObj: {
           Keyword:''

+ 32 - 18
src/views/ppt_manage/newVersion/pptEnCatalog.vue

@@ -373,22 +373,36 @@ export default {
   },
   watch:{
     searchTitle(newVal){
-      let data = null
-      this.publicList.forEach((item)=>{
-        item.children.forEach(i=>{
-          if(i.PptId===newVal){
-            data = i
-          }
+        let data = null
+        let search='private'
+        this.privateList.forEach((item)=>{
+            item.children.forEach(i=>{
+                if(i.PptId===newVal){
+                    data = i
+                    search='private'
+                }
+            })
         })
-      })
-      this.default_tab = '3';
-      //选中该节点
-      this.$refs.publicTree.setCurrentKey('ppt'+newVal)
-      //展开该节点的父节点...
-      const node = this.$refs.publicTree.getCurrentNode()
-      this.publicExpandKeys.push(node.catalogId)
-      this.nodeChange(data,_,'public')
-      this.searchOptions=[]
+        if(!data){
+            this.publicList.forEach((item)=>{
+                item.children.forEach(i=>{
+                    if(i.PptId===newVal){
+                        data = i
+                        search='public'
+                    }
+                })
+            })
+        }
+        if(data){
+            this.default_tab = search==='public'?'3':'1';
+            //选中该节点
+            this.$refs[`${search}Tree`].setCurrentKey('ppt'+newVal)
+            //展开该节点的父节点...
+            const node = this.$refs[`${search}Tree`].getCurrentNode()
+            this[`${search}ExpandKeys`].push(node.catalogId)
+            this.nodeChange(data,_,search)
+        }
+        this.searchOptions=[]
     },
   },
   methods: {
@@ -974,7 +988,7 @@ export default {
     },
     //搜索ppt标题
     searchHandle(keyword){
-      pptEnInterface.searchPPTByKeyWorld({
+      pptEnInterface.searchPPTByKeyWorldV2({
         Keyword:keyword
       }).then(res=>{
         if(res.Ret===200){
@@ -1154,7 +1168,7 @@ export default {
       height: 0;
     }
     .el-tabs__item.is-active {
-      border-bottom: 2px solid #409EFF;
+      border-bottom: 2px solid #0052D9;
     }
     .el-tabs__item { font-size: 16px; }
     .ppt-list-wrap{
@@ -1269,7 +1283,7 @@ export default {
       h3{
         span{
           margin-left: 20px;
-          color:#409EFF;
+          color:#0052D9;
           font-size: 12px;
           font-weight: normal;
         }

+ 7 - 2
src/views/ppt_manage/newVersion/pptEnEditor.vue

@@ -180,6 +180,9 @@
                   :showEnMark="true"
                   />
               </div>
+              <div v-show="tabsactive == '语义分析插入'" class="chart-tool flex-column">
+                <InsertSemantics />
+              </div>
             </div>
             <!-- 图层编辑 -->
             <div class="layer-edit-box" v-else>
@@ -299,6 +302,7 @@ import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyD
 import InsertCharts from './components/editor/InsertCharts.vue';
 import setEnNameDia from '@/views/dataEntry_manage/components/setEnNameDia.vue';
 import ContextMenu from './components/ContextMenu.vue';
+import InsertSemantics from './components/editor/InsertSemantics.vue';
 export default {
   mixins:[pptmixin,//ppt页面共同逻辑
           mixins,//图表加载逻辑
@@ -317,7 +321,8 @@ export default {
     setEnNameDia,
     addMyClassifyDia,
     InsertCharts,
-    ContextMenu
+    ContextMenu,
+    InsertSemantics
   },
   data() {
     return {
@@ -361,7 +366,7 @@ export default {
         catalogId:0,//ppt目录id,添加ppt时需要
         ReportId:0,//ppt对应的双周报id,如果没转过,则为0
         isChartLoading:false,//是否正在加载图表/图片
-        panelTabs: [ '图表','MyETA批量','沙盘','表格' ],
+        panelTabs: [ '图表','MyETA批量','沙盘','表格','语义分析插入' ],
         sheetSearchList:[],
         sheetSearchObj: {
           Keyword:''

+ 18 - 0
src/views/ppt_manage/newVersion/utils/untils.js

@@ -641,3 +641,21 @@ export const getContextMenuPos = (layerId) =>{
     return {clientX:menuBoundingClientRect.x - layerBoundingClientRect.x,
             clientY:menuBoundingClientRect.y - layerBoundingClientRect.y,}
 }
+
+//根据Source 和 MyChartType判断图表是否显示标题
+/*
+    Source:1
+    MyChartType: 2 季节性图,7 柱形图,  10 截面散点图,
+    Source:2 商品价格曲线图
+    Source:5 利润曲线
+    Source:6 拟合方程曲线
+    Source:7 统计特征-标准差
+    Source:9 统计特性-频率
+    Source:8 统计特性-百分位
+    以上图表需要显示标题
+*/
+export const isShowPPTTitle = (Source,MyChartType)=>{
+    const sense_1 = Source===1&&[2,7,10].includes(MyChartType)
+    const sense_2 = [2,5,6,7,8,9].includes(Source)
+    return sense_1||sense_2
+}

+ 2 - 2
src/views/predictEdb_manage/addPredicEdb.vue

@@ -605,8 +605,8 @@ export default {
             oldEdbName: res.Data.CalculateList[0].FromEdbName,
             edbName: EdbName,
             frequency: Frequency,
-            newdata: LatestValue,
-            lasetDate: LatestDate,
+            newdata:  res.Data.CalculateList[0].EndValue,
+            lasetDate: res.Data.CalculateList[0].EndDate,
             dateType: DataDateType
           };
 

+ 16 - 10
src/views/predictEdb_manage/components/chartInfo.vue

@@ -7,14 +7,14 @@
 				type="primary"
 				v-for="item in yearSelector"
 				:key="item.value"
-				size="medium"
+				size="mini"
 				:plain="item.value !== year_select"
 				class="year-btn"
 				@click.native="changeYear(item)"
 				>{{ item.name }}</el-button
 			>
 			<el-button 
-                type="text" 
+                type="primary" size="mini"
                 class="btn-sty" 
                 @click="openDateDia"
             >{{dateTip}}</el-button>
@@ -33,8 +33,14 @@
             <div v-else-if="chartInfo.ChartType === 2" @click="openDateDia" class="date-setting" style="display: inline-block;">
 				{{ season_year && season_year.length>0 ? season_year[0]+'~'+season_year[1]:"年份日期选择" }}
 			</div>
-            <span v-permission="permissionBtn.predictEdbPermission.edbPreData_switchSeason"
-                class="change-chart-btn" @click="chartTypeChange">切换{{chartInfo.ChartType==1?'季节性图':'曲线图'}}</span>
+            <!-- <span v-permission="permissionBtn.predictEdbPermission.edbPreData_switchSeason"
+                class="change-chart-btn" @click="chartTypeChange">切换{{chartInfo.ChartType==1?'季节性图':'曲线图'}}</span> -->
+            <el-button type="primary" size="mini" class="btn-sty" style="margin-left:auto;"
+                v-permission="permissionBtn.predictEdbPermission.edbPreData_switchSeason"
+                @click="chartTypeChange">
+                <i class="el-icon-sort" style="transform: rotate(90deg);"></i>
+                    切换{{chartInfo.ChartType==1?'季节性图':'曲线图'}}
+            </el-button>
         </div>
         <div class="chartWrapper">
             <Chart 
@@ -235,20 +241,20 @@ export default {
 
 <style lang="scss" scoped>
 .predicedb-chart-wrap{
-    padding: 30px;
+    /* padding: 30px; */
     .header {
+        display: flex;
         position: relative;
         margin-bottom: 30px;
-        .year-btn {
+        .year-btn,.btn-sty {
             min-width: 90px;
             font-size: 14px;
             margin-right: 5px;
             margin-bottom: 5px;
         }
         .btn-sty {
-            font-size: 16px;
-            padding: 9px;
-            border: 1px solid #409eff;
+            background-color: #fff;
+			color: #0052D9;
         }
         .date-setting{
 			width: 210px;
@@ -280,7 +286,7 @@ export default {
         }
     }
     .calendar-cont {
-        margin: 30px auto;
+        /* margin: 30px auto; */
         text-align: center;
         display: block;
         .el-radio-button__inner {

+ 104 - 41
src/views/predictEdb_manage/components/childData.vue

@@ -34,6 +34,29 @@
         <tableNoData text="暂无数据" size="mini"/>
       </div>
     </el-table>
+    <el-table
+			:data="tableData"
+			style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);"
+			border>
+			<el-table-column
+				v-for="item in tableColumsTwo"
+				:key="item.label"
+				:label="item.label"
+				:width="item.widthsty"
+				:min-width="item.minwidthsty"
+				align="center"
+			>
+				<template #header>
+					<span>{{ item.label }}</span>
+				</template>
+				<template slot-scope="scope">
+					<span>{{ scope.row[item.key] }}</span>
+				</template>
+			</el-table-column>
+			<div slot="empty" style="padding: 50px 0 320px;">
+					<tableNoData :text="defaultWarn"/>
+			</div>
+		</el-table>
     <ul
       class="value-ul"
       ref="valueUl"
@@ -46,13 +69,15 @@
         :key="item.EdbDataId"
       >
         <span class="value-label">
-          <i class="new-tag" v-if="tableData[0].LatestDate===item.DataTime"></i>
-          {{ item.DataTime }}
+            <span style="position: relative;">
+                <i class="new-tag" v-if="tableData[0].LatestDate===item.DataTime"></i>
+                {{item.DataTime}}
+            </span>
         </span>
         <span
           :class="['value-label',{'predict-act': item.isPredic}]"
           style="min-width: 200px; text-align: center"
-          >{{ item.Value }}</span
+          ><span :class="['value-style',{'predict-act': item.isPredic}]">{{item.Value}}</span></span
         >
       </li>
       <li class="nodata value-item" v-if="!dataList.length">暂无数据</li>
@@ -81,42 +106,54 @@ export default {
   data() {
     return {
       tableColums: [
-				{
-					label: '指标ID',
-					key: 'EdbCode',
-					minwidthsty: '150px'
-				},
-				{
-					label: '频度',
-					key: 'Frequency',
-					widthsty: '80px'
-				},
-				{
-					label: '单位',
-					key: 'Unit',
-					widthsty: '80px'
-				},
-				{
-					label: '起始时间',
-					key: 'StartDate',
-					widthsty: '160px'
-				},
-				{
-					label: '预测截止日期',
-					key: 'EndDate',
-					widthsty: '160px'
-				},
-				{
-					label: '更新时间',
-					key: 'ModifyTime',
-					widthsty: '160px'
-				},
-				{
-					label: '添加人',
-					key: 'SysUserRealName',
-					widthsty: '100px'
-				},
-			],
+        {
+            label: '指标ID',
+            key: 'EdbCode',
+            widthsty: '280px'
+        },
+        {
+            label: '指标名称',
+            key: 'EdbName',
+            minwidthsty: '200px'
+        },
+        {
+            label: '频度',
+            key: 'Frequency',
+            widthsty: '100px'
+        },
+        {
+            label: '单位',
+            key: 'Unit',
+            widthsty: '140px'
+        },
+      ],
+      tableColumsTwo:[
+        {
+            label: '指标目录',
+            key: 'Menu',
+            widthsty: '280px',
+        },
+        {
+            label: '起始时间',
+            key: 'StartDate',
+            minwidthsty: '100px',
+        },
+        {
+            label: '预测截止日期',
+            key: 'EndDate',
+            minwidthsty: '100px'
+        },
+        {
+            label: '更新时间',
+            key: 'ModifyTime',
+            minminwidthsty: '120px',
+        },
+        {
+            label: '添加人',
+            key: 'SysUserRealName',
+            widthsty: '140px',
+        }
+      ],
       showData: false,
       tableData: [],
       page_no: 1,
@@ -137,6 +174,10 @@ export default {
         Item.PredictDataList && Item.PredictDataList.forEach(_ => {
           _.isPredic = true;
         })
+        const classify_arr = res.Data.ClassifyList || [];
+        let str = '';
+        classify_arr.length && classify_arr.reverse().map((item) => str += item.ClassifyName + '/');
+        this.$set(Item,'Menu',str);
         this.haveMore =  this.page_no < res.Data.Paging.Pages;
         this.dataList = this.page_no === 1 ? [...Item.PredictDataList,...Item.DataList] : [...this.dataList,...Item.DataList];
 
@@ -171,15 +212,24 @@ export default {
   },
 };
 </script>
+<style lang="scss">
+.data-wrapper {
+    .el-table--enable-row-transition .el-table__body td{
+        background: #fff !important;
+    }
+    .el-table td, .el-table th.is-leaf {
+        background: #F2F6FA !important;
+    }
+}
+</style>
 <style scoped lang="scss">
 .data-wrapper {
-  padding-top: 40px;
   .value-ul {
     margin-top: 10px;
     border-bottom: 1px solid #dcdfe6;
     border-top: 1px solid #dcdfe6;
     /* max-height: 520px; */
-    max-height: calc(100vh - 450px);
+    max-height: calc(100vh - 430px);
     overflow-y: auto;
     .value-item {
       /* width: 100%; */
@@ -189,9 +239,22 @@ export default {
       display: flex;
       justify-content: space-around;
       &:first-child { border-top: none; }
+      span{
+        flex: 1;
+        text-align: center;
+      }
       .value-label {
         position: relative;
         color: #666;
+        .value-style{
+            /* background-color: #ECF2FE;
+            color: #0052D9; */
+            padding:5px;
+            border-radius: 4px;
+            &.predict-act{
+                color: orange;
+            }
+        }
       }
       .predict-act {
         color: orange;

+ 2 - 2
src/views/predictEdb_manage/components/classifyDia.vue

@@ -32,7 +32,7 @@
 					</el-form-item>
 				</template>
 
-				<el-form-item label="分类名称" prop="classify_name">
+				<el-form-item label="目录名称" prop="classify_name">
 					<el-input
 					v-model="formData.classify_name"
 					style="width: 80%"
@@ -78,7 +78,7 @@ export default {
 			formData: {},
       formRules: {
         classify_name:[
-          { required: true, message: '分类名称不能为空', trigger: 'blur' },
+          { required: true, message: '目录名称不能为空', trigger: 'blur' },
         ]
       },
 

+ 112 - 3
src/views/predictEdb_manage/components/edbDetail.vue

@@ -6,7 +6,40 @@
             @refreshData="refreshData"
             ref="chartInfo"
         />
-        <div class="author" style="float:right">添加人:{{edbData.EdbInfo.SysUserRealName}}</div>
+        <div class="info" style="display: flex;justify-content: flex-end;">
+          <!--   <span>数据来源:{{edbData.EdbInfo.SourceName}}</span> -->
+            <span>添加人:{{edbData.EdbInfo.SysUserRealName}}</span>
+        </div>
+        <ul
+            class="value-ul"
+            v-show="showData&&dataList.length"
+            >
+            <li class="value-item" style="background-color: #EBEFF6;">
+                <span style="width:240px">日期(频度:{{EdbData.Frequency}})</span>
+                <span style="flex:1;">值</span>
+            </li>
+            <li
+                class="value-item"
+                v-for="item in dataList.slice(0,3)"
+                :key="item.EdbDataId"
+            >
+                <span class="value-label date" style="width:240px">
+                    <span style="position: relative;">
+                        <i class="new-tag" v-if="EdbData.LatestDate===item.DataTime"></i>
+                        {{ item.DataTime }}
+                    </span>
+                </span>
+                <span
+                    :class="['value-label',{'predict-act': item.isPredic}]"
+                    style="flex:1;"
+                >
+                    <span :class="['value-style',{'predict-act': item.isPredic}]">{{item.Value}}</span>
+                </span
+                >
+            </li>
+            <li class="nodata value-item" v-if="!dataList.length">暂无数据</li>
+        </ul>
+
     </div>
 </template>
 
@@ -45,6 +78,9 @@ export default {
                 DataList:null,
                 EdbInfo:{}
             },
+            showData:false,
+            dataList: [],
+            EdbData:{}
         }
     },
     methods: {
@@ -110,6 +146,7 @@ export default {
                         this.setChartImage()
                     })
                 }
+                this.getData()
             })
         },
         refreshData(type=''){
@@ -139,12 +176,84 @@ export default {
                 ImageUrl: Data.ResourceUrl,
             });
         },
+        getData(){
+            preDictEdbInterface.edbDataInfo({
+                EdbInfoId: this.id,
+                CurrentIndex: 1
+            }).then(res => {
+                this.showData = true;
+                if(res.Ret!==200) return 
+                const {Item} = res.Data
+                Item.PredictDataList && Item.PredictDataList.forEach(_ => {
+                    _.isPredic = true;
+                })
+                this.EdbData = Item
+                this.dataList = [...Item.PredictDataList,...Item.DataList]
+            })
+        },
 
     },
 
 }
 </script>
 
-<style>
-
+<style lang="scss" scoped>
+.value-ul {
+    margin-top: 10px;
+    border-bottom: 1px solid #EBEFF6;
+    .value-item {
+        padding: 10px 0;
+        border: 1px solid #EBEFF6;
+        border-bottom: none;
+        display: flex;
+        justify-content: space-around;
+        >span{
+            padding:0 16px;
+            box-sizing: border-box;
+        }
+        .value-label {
+            position: relative;
+            color: #666;
+            .value-style{
+                /* background-color: #ECF2FE;
+                color: #0052D9; */
+                padding:5px;
+                border-radius: 4px;
+                &.predict-act {
+                    color: orange;
+                }
+            }
+            &.date{
+                &::after{
+                    content: '';
+                    position:absolute;
+                    right:0;
+                    top:-14px;
+                    height:calc(100% + 28px);
+                    width:1px;
+                    background-color: #EBEFF6;
+                }
+            }
+        }
+        .predict-act {
+            color: orange;
+        }
+        .new-tag {
+            width: 6px;
+            height: 6px;
+            display: inline-block;
+            position: absolute;
+            left: -12px;
+            top: 50%;
+            transform: translateY(-50%);
+            border-radius: 50%;
+            background: #f00;
+        }
+    }
+    .nodata {
+        text-align: center;
+        padding: 40px 0;
+        color: #999;
+    }
+}
 </style>

+ 101 - 31
src/views/predictEdb_manage/predictEdb.vue

@@ -149,7 +149,7 @@
 							alt=""
 							style="width: 16px; height: 16px; margin-right: 10px"
 						/>
-						<span>添加分类</span>
+						<span>添加一级目录</span>
 					</div>
 				</div>
 				<span
@@ -167,30 +167,35 @@
 
 				<!-- 详情 -->
 				<div class="edb-detail-wrapper" v-if="select_id&&!showAssociateChart&&!showAssociateComputeData">
-					<div class="detail-top">
-						<span class="title">{{ currentLang==='en'?(edb_nameEn||edbName):edbName }}</span>
-						<ul class="action-ul">
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_enNameSetting"
-								class="editsty" @click="clickEdbNameHandle" v-if="currentLang==='ch'||!edb_nameEn">
+					<div class="detail-header">
+						<el-tabs v-model="activeTab" @tab-click="changeShowType">
+							<el-tab-pane label="走势图" name="Chart">
+							</el-tab-pane>
+							<el-tab-pane label="数据详情" name="Data">
+							</el-tab-pane>
+						</el-tabs>
+						<div class="edb-tool">
+							<el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_enNameSetting"
+								type="text" @click="clickEdbNameHandle" v-if="currentLang==='ch'||!edb_nameEn">
 								设置英文名称
-							</li>
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_edbSource"
-								class="editsty" @click="isLookHistory=true;lookEdbId=select_id">指标溯源</li>
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_update"
-								class="editsty" @click="updateEdbPartHandle">更新</li>
-							<li class="editsty" @click="editEdbHandle('')" 
-								v-if="edbButton.OpButton&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_edit)">编辑</li>
-							<li class="editsty" @click="saveEdbHandle" 
-								v-if="detail_show_chart&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_save)">保存</li>
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_recalcu"
-								class="editsty" @click="updateEdbHandle">重新计算</li>
-							<li class="deletesty" @click="delEdbHandle" 
-								v-if="edbButton.DeleteButton&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_del)">删除</li>
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_copyData"
-								class="editsty" @click="copyData">复制数据</li>
-							<li v-permission="permissionBtn.predictEdbPermission.edbPreData_viewData"
-								class="editsty" @click="detail_show_chart=!detail_show_chart">{{detail_show_chart ? '查看数据' : '查看图表'}} </li>
-						</ul>
+							</el-button>
+							<el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_edbSource"
+							type="text" @click="isLookHistory=true;lookEdbId=select_id">指标溯源</el-button>
+							<el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_update"
+								type="text" @click="updateEdbPartHandle">刷新</el-button>
+							<el-button type="text" @click="editEdbHandle('')" 
+								v-if="edbButton.OpButton&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_edit)">编辑</el-button>
+							<el-button type="text" @click="saveEdbHandle" 
+								v-if="detail_show_chart&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_save)">保存</el-button>
+							<el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_recalcu"
+								type="text" @click="updateEdbHandle">重新计算</el-button>
+							<el-button class="deletesty" @click="delEdbHandle" type="text"
+								v-if="edbButton.DeleteButton&&permissionBtn.checkPermissionBtn(permissionBtn.predictEdbPermission.edbPreData_del)">删除</el-button>
+							<el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_copyData"
+								type="text" @click="copyData">复制数据</el-button>
+							<!-- <el-button v-permission="permissionBtn.predictEdbPermission.edbPreData_viewData"
+								type="text" @click="detail_show_chart=!detail_show_chart">{{detail_show_chart ? '查看数据' : '查看图表'}} </el-button> -->
+						</div>
 					</div>
 
 					<!--  -->
@@ -589,6 +594,8 @@ export default {
 
 			showAssociateChart:false,//显示指标关联的图
 			showAssociateComputeData:false,//显示指标关联的引用计算指标
+
+			activeTab:'',
 		};
 	},
 	computed: {
@@ -622,6 +629,7 @@ export default {
 		// /* 表格id */
 		select_id(newval) {
 			this.detail_show_chart = true;
+			this.activeTab='Chart'
 			this.$nextTick(()=>{
 				//切换为曲线图 重置选择状态
 				if(this.$refs.detailComponentRef){
@@ -646,6 +654,7 @@ export default {
 		select_classify(newval) {
 			if(this.$refs.listRef) this.$refs.listRef.scrollTop = 0;
 			if(newval) {
+				this.activeTab = ''
 				this.public_page = 1;
 				this.getPublicList()
 			}
@@ -680,17 +689,27 @@ export default {
 			this.$nextTick(()=>{
 				setTimeout(() => {
 				const dom = document.querySelector(".el-tree-node.is-current");
-				const parentDom = document.querySelector(".tree-cont");
+				const parentDom = document.querySelector(".target_tree");
 				if (!dom || !parentDom) {
 					this.searchLoading = false;
 					return;
 				}
-				if (dom.offsetTop > parentDom.offsetHeight) {
+				/* if (dom.offsetTop > parentDom.offsetHeight) {
 					parentDom.scrollTo({
 						top: dom.offsetTop - parentDom.offsetHeight / 2,
 						left: 0,
 						behavior: "smooth",
 					});
+				} */
+				//parent可视区间:[scrollTop,scrollTop+offsetHeight]
+				//node位置:node.offsetTop
+				const overTop = dom.offsetTop+dom.clientHeight<parentDom.scrollTop
+				const overBottom = dom.offsetTop+dom.clientHeight+30>parentDom.scrollTop+parentDom.offsetHeight
+				if(overTop){
+					parentDom.scrollTop = dom.offsetTop-30
+				}
+				if(overBottom){
+					parentDom.scrollTop =  dom.offsetTop - parentDom.offsetHeight/2
 				}
 				this.searchLoading = false;
 			}, 300);
@@ -1326,6 +1345,10 @@ export default {
 				this.dynamicNode = _node;
 				this.dynamicNode&&this.resetNodeStyle(this.dynamicNode)
 			})
+		},
+		changeShowType(){
+			if(!this.activeTab) return
+			this.detail_show_chart = this.activeTab==='Chart'?true:false
 		}
 	},
 	mounted() {
@@ -1353,6 +1376,50 @@ export default {
 	}
 }
 </script>
+<style lang="scss">
+.predictEdb-container{
+	.detail-header{
+		display: flex;
+		position: relative;
+		height: 60px;
+		.el-tabs{
+			width:200px;
+			.el-tabs__header{
+				margin-bottom: 0;
+			}
+			.el-tabs__nav{
+				display: flex;
+				width: 100%;
+				.el-tabs__item{
+					flex: 1;
+					text-align: center;
+					font-size: 16px;
+					height: 60px;
+					line-height: 60px;
+				}
+			}
+		}
+	}
+	.edb-tool{
+		flex: 1;
+		text-align: right;
+		display: flex;
+		gap: 16px;
+		justify-content: flex-end;
+		padding-right: 15px;
+		position: relative;
+		&::after{
+			position: absolute;
+			content:'';
+			width:100%;
+			left: 0;
+			bottom: 0;
+			height:2px;
+			background-color: #E4E7ED;
+		}
+	}
+}
+</style>
 <style lang='scss' scoped>
 @import "~@/styles/theme-vars.scss";
 *{ box-sizing: border-box;}
@@ -1411,11 +1478,13 @@ $mini-font: 12px; $normal-font: 14px;
 
 			.tree-cont {
 				padding: 0 20px 30px 20px;
-				max-height: calc(100vh - 280px);
-				overflow: auto;
+				/* max-height: calc(100vh - 280px);
+				overflow: auto; */
 			}
 			.target_tree {
 				color: #333;
+				max-height: calc(100vh - 400px);
+				overflow-y:auto;
 				.custom-tree-node {
 					display: flex !important;
 					justify-content: space-between;
@@ -1433,7 +1502,7 @@ $mini-font: 12px; $normal-font: 14px;
 				}
 			}
 			.noDepart {
-				margin: 60px 0;
+				margin: 30px 0;
 				display: flex;
 				align-items: center;
 				justify-content: center;
@@ -1481,8 +1550,9 @@ $mini-font: 12px; $normal-font: 14px;
 				}
 				.detail-wrap {
 					position: relative;
-					padding: 30px 20px;
-					height: calc(100vh - 190px);
+					padding: 16px;
+					height: calc(100vh - 180px);
+					overflow-y: auto;
 					.toggle-text {
 						position: absolute;
 						right: 20px;

+ 93 - 4
src/views/report_manage/addreportNew.vue

@@ -49,6 +49,12 @@
 					>存草稿</el-button
 				>
 				<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+					type="primary"
+					size="medium"
+					@click.native="clickreportadd('dsfb')"
+					>定时发布</el-button
+				>
+				<el-button
 					type="primary"
 					size="medium"
 					@click.native="clickreportadd('fb')"
@@ -293,8 +299,38 @@
 				<div v-if="tabsactive == 'MyETA批量插入'">
 					<importMyChart @handleImportMyChart="handleImportMyChart"/>
 				</div>
+				<div v-if="tabsactive == '语义分析插入'">
+					<importSemantics @handleImportSemantic="(item)=>insertHtml(item,'image')"/>
+				</div>
 			</div>
 		</div>
+
+		<!-- 定时发布弹窗 -->
+		<el-dialog 
+			v-dialogDrag 
+			:append-to-body="true" 
+			:visible.sync="showDSFB" 
+			width="500px" 
+			title="定时发布"
+		>
+			<div>
+				<div>
+					<span>发送时间</span>
+					<el-date-picker
+						v-model="taskTime"
+						type="datetime"
+						placeholder="选择日期时间"
+						value-format="yyyy-MM-dd HH:mm"
+						:picker-options="timePickerOpt"
+					/>
+				</div>
+				<p style="margin:15px 0">设置成功之后,研报将定时进行发送。</p>
+				<div style="text-align:right;margin:20px 0">
+					<el-button type="primary" plain @click="showDSFB=false">取消</el-button>
+					<el-button type="primary" @click="handleSetReportPrepublish">确定</el-button>
+				</div>
+			</div>
+		</el-dialog>
 	</div>
 </template>
 
@@ -309,7 +345,8 @@ import {
 	reportauthor,
 	getDraft,
 	dataBaseInterface,
-	sandInterface
+	sandInterface,
+	reportSetPrepublish
 } from '@/api/api.js';
 import http from '@/api/http.js';
 import VueFroala from 'vue-froala-wysiwyg';
@@ -317,6 +354,7 @@ import urlSlug from 'url-slug';
 import mixinMsg from './mixins/messagePush'
 import reportMixin from './mixins/reportMixin';
 import importMyChart from './components/importMyChart.vue'
+import importSemantics from './components/importSemantics.vue';
 export default {
 	mixins:[mixinMsg,reportMixin],
 	data() {
@@ -596,7 +634,7 @@ export default {
 						this.isMessagePost = false; 
 						this.reporteditMsg(params2,tp)
 					}else if(isPost){
-						this.$confirm('发布后,是否推送模板消息和客户群?', '发布提示', {
+						this.$confirm('发布后,是否推送模板消息?', '发布提示', {
 								confirmButtonText: '推送',
 								cancelButtonText: '不推送',
 								type: 'warning',
@@ -633,7 +671,7 @@ export default {
 						this.isMessagePost = false; 
 						this.reportaddMsg(params,tp)
 					}else if(isPost){
-						this.$confirm('发布后,是否推送模板消息和客户群?', '发布提示', {
+						this.$confirm('发布后,是否推送模板消息?', '发布提示', {
 								confirmButtonText: '推送',
 								cancelButtonText: '不推送',
 								type: 'warning',
@@ -674,6 +712,57 @@ export default {
 				}
 			});
 		},
+		// 定时发布报告
+		handleSetReportPrepublish(){
+			if(!this.taskTime){
+				this.$message.warning('请选择定时发布的时间')
+				return
+			}
+			const now=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+			console.log(now);
+			console.log(this.taskTime);
+			if(this.$moment(this.taskTime).isBefore(now,'second')){
+				this.$message.warning('定时发布不得早于当前时间')
+				return
+			}
+			console.log('定时去发布了');
+			this.$confirm('是否发布定时报告,并推送模板消息?', '发布提示', {
+				confirmButtonText: '推送',
+				cancelButtonText: '不推送',
+				type: 'warning',
+				distinguishCancelAndClose:true,
+				beforeClose:(action, instance,done)=>{
+					console.log(action, instance);
+					if(action==='close'||action==='cancel') {
+						//右上角或者不推送
+						reportSetPrepublish({
+							ReportId:Number(this.report_draft_id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:0,
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success('定时发布成功!')
+								this.$router.push({ path: '/reportlist' });
+							}
+						})
+					} else {
+						//confirmButton
+						reportSetPrepublish({
+							ReportId:Number(this.report_draft_id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:1,
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success('定时发布成功!')
+								this.$router.push({ path: '/reportlist' });
+							}
+						})
+					}
+					done()
+				}
+			})
+
+		},
 		//批量插入我的图表
 		handleImportMyChart(data){
 			//设置编辑器获取焦点
@@ -791,7 +880,7 @@ export default {
 			});
 		},
 	},
-	components: {importMyChart},
+	components: {importMyChart,importSemantics},
 	watch: {
 		'aeForm.add_type'(to, from) {
 			if (from == 2 && to == 1) {

+ 121 - 0
src/views/report_manage/components/importSemantics.vue

@@ -0,0 +1,121 @@
+<template>
+    <div class="import-mychart-wrap">
+        <div>
+            <el-input
+				placeholder="关键词搜索"
+				v-model="keyword"
+				size="medium"
+				prefix-icon="el-icon-search"
+                @input="handleChange"
+			/>
+		</div>
+		<div class="list" v-infinite-scroll="load" v-if="list.length>0">
+            <div class="item" v-for="item in list" :key="item.SaCompareId" @click="handleClickItem(item)">
+                <p>{{ item.Title }}</p>
+                <img :src="item.PicUrl" alt="">
+            </div>
+		</div>
+        <div v-if="list.length==0" class="empty-box">
+            无数据
+        </div>
+    </div>
+</template>
+
+<script>
+import {semanticInterface} from '@/api/modules/semanticsApi.js';
+export default {
+    data() {
+        return {
+            keyword:'',
+            pageSize:20,
+			CurrentIndex: 1,
+			list:[],
+            loading:false,
+            finished:false,
+
+        }
+    },
+    mounted(){
+        this.handleGetList()
+    },  
+    methods: {
+		async handleGetList(){
+            this.loading=true
+            const res=await semanticInterface.compareSearch({
+				PageSize: this.pageSize,
+				CurrentIndex: this.CurrentIndex,
+				Keyword: this.keyword
+			})
+            this.loading=false
+            let arr=res.Data.List||[]
+            arr=arr.map(item => {
+               return {
+                   ...item,
+                   PicUrl:item.ResultImg
+               } 
+            });
+
+            this.list=[...this.list,...arr]
+            if(!res.Data){
+                this.finished=true
+            }
+            if(res.Data&&res.Data.Paging.IsEnd){
+                this.finished=true
+            }
+		},
+
+        handleChange(){
+            console.log('aaa');
+            this.CurrentIndex=1
+            this.finished=false
+            this.list=[]
+            this.handleGetList()
+        },
+
+        load(){
+            if(this.finished) return
+            this.CurrentIndex++
+            this.handleGetList()
+        },
+
+        handleClickItem(item){
+           this.$emit('handleImportSemantic',item)
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.import-mychart-wrap{
+    .list{
+        height: calc(100vh - 320px);
+        overflow-x: hidden;
+		overflow-y: auto;
+        .item{
+            width: 100%;
+            margin: 20px 0;
+            padding: 20px;
+            box-sizing: border-box;
+            border: 1px solid #eaeaea;
+            border-radius: 10px;
+            position: relative;
+            overflow: hidden;
+            p{
+                text-align: center;
+                font-size: 16px;
+                margin-bottom: 10px;
+                color: #5882EF;
+            }
+            img{
+                width: 100%;
+            }
+        }
+    }
+    .empty-box{
+        height: calc(100vh - 320px);
+        text-align: center;
+        color: #999;
+        padding-top: 100px;
+    }
+}
+</style>

+ 1 - 1
src/views/report_manage/dayOrWeek.vue

@@ -120,7 +120,7 @@ export default {
         if(to.query.type){
             to.matched[1].name=`编辑${to.query.type=='day'?'晨报':'周报'}`
         }else{
-            to.matched[1].name='编辑晨报/周报'
+            to.matched[1].name='添加晨报/周报'
         }
         next()
     },

+ 100 - 90
src/views/report_manage/editChapterReport.vue

@@ -162,93 +162,91 @@
             </el-form-item>
           </el-form>
         </div>
-				<div v-if="tabsactive == '图表插入'">
-					<el-input
-						placeholder="图表名称"
-						v-model="key_word"
-						size="medium"
-						prefix-icon="el-icon-search"
-						@input="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist(key_word)}"
-					>
-					</el-input>
-					<el-radio-group v-model="chart_source" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist()}" style="margin-top: 10px;">
-						<el-radio :label="1">ETA图库</el-radio>
-						<el-radio :label="2">商品价格曲线</el-radio> 
-						<el-radio :label="3">相关性图表</el-radio>
-						<el-radio :label="6">拟合方程曲线</el-radio>
-						<el-radio :label="7">统计特征</el-radio>
-					</el-radio-group>
-					<div style="margin: 10px 0">
-						<el-checkbox v-model="isShowMe" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist(key_word)}">只看我的</el-checkbox>
-					</div>
-					<div
-						id="reportwin"
-						ref="chartListRef"
-						style="
-							height: calc(100vh - 370px);
-							overflow-x: hidden;
-							overflow-y: auto;
-						"
-						v-infinite-scroll="loadReportHandle"
-						:infinite-scroll-immediate="false"
-					>
-						<template v-if="newreportlist.length">
-							<div
-								v-for="(item, index) in newreportlist"
-								:key="item.ChartInfoId"
-								:style="item.Disabled && 'cursor: not-allowed;'"
-								class="liststy"
-							>
-								<p class="color_primary">{{ item.ChartName }}</p>
-								<img
-									:src="item.ChartImage"
-									:id="'listnode' + index"
-									@click="insertHtml(item)"
-								/>
-							</div>
-						</template>
-
-						<tableNoData text="暂无图表" size="mini" v-else/>
-					</div>
-
-				</div>
-				<div v-if="tabsactive == '沙盘插入'">
-					<el-input
-						placeholder="沙盘名称/品种"
-						v-model="sandTabelQuery.Keyword"
-						size="medium"
-						prefix-icon="el-icon-search"
-					>
-					</el-input>
-					<div
-						id="sandTable-container"
-						ref="sandTable"
-						style="
-							height: calc(100vh - 370px);
-							overflow-x: hidden;
-							overflow-y: auto;
-						"
-						@scroll="sandTableHandleScroll"
-					>
-						<template v-if="sandTableList.length">
-							<div
-								v-for="(item, index) in sandTableList"
-								:key="item.SandboxId"
-								class="liststy"
-							>
-								<p class="color_primary">{{ item.Name }}</p>
-								<img
-									:src="item.PicUrl"
-									:id="'sandTable' + index"
-									@click="insertHtml(item,'image')"
-								/>
-								<p class="source-identification">来源:弘则研究</p>
-							</div>
-						</template>
-						<tableNoData text="暂无数据" size="mini" v-else/>
-					</div>
-				</div>
-				<div v-if="tabsactive == '表格插入'">
+        <div v-if="tabsactive == '图表插入'">
+          <el-input
+            placeholder="标题/子标题/作者"
+            v-model="key_word"
+            size="medium"
+            prefix-icon="el-icon-search"
+            @input="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist(key_word)}"
+          >
+          </el-input>
+          <el-radio-group v-model="chart_source" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist()}" style="margin-top: 10px;">
+            <el-radio :label="1">ETA图库</el-radio>
+            <el-radio :label="2">商品价格曲线</el-radio>
+            <el-radio :label="3">相关性图表</el-radio>
+            <el-radio :label="6">拟合方程曲线</el-radio>
+            <el-radio :label="7">统计特征</el-radio>
+          </el-radio-group>
+          <div style="margin: 10px 0">
+            <el-checkbox v-model="isShowMe" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist(key_word)}">只看我的</el-checkbox>
+          </div>
+          <div
+            id="reportwin"
+            ref="chartListRef"
+            style="
+              height: calc(100vh - 370px);
+              overflow-x: hidden;
+              overflow-y: auto;
+            "
+            v-infinite-scroll="loadReportHandle"
+            :infinite-scroll-immediate="false"
+          >
+          <template v-if="newreportlist.length">
+            <div
+              v-for="(item, index) in newreportlist"
+              :key="item.ChartInfoId"
+              class="liststy"
+              :style="item.Disabled && 'cursor: not-allowed;'"
+            >
+              <p class="color_primary">{{ item.ChartName }}</p>
+              <img
+                :src="item.ChartImage"
+                :id="'listnode' + index"
+                @click="insertHtml(item)"
+              />
+            </div>
+          </template>
+          <tableNoData text="暂无图表" size="mini" v-else/>
+          </div>
+        </div>
+        <div v-if="tabsactive == '沙盘插入'">
+          <el-input
+            placeholder="沙盘名称/品种"
+            v-model="sandTabelQuery.Keyword"
+            size="medium"
+            prefix-icon="el-icon-search"
+          >
+          </el-input>
+          <div
+            id="sandTable-container"
+            ref="sandTable"
+            style="
+              height: calc(100vh - 370px);
+              overflow-x: hidden;
+              overflow-y: auto;
+            "
+            @scroll="sandTableHandleScroll"
+          >
+            <template v-if="sandTableList.length">
+            <div
+              v-for="(item, index) in sandTableList"
+              :key="item.SandboxId"
+              class="liststy"
+            >
+              <p class="color_primary">{{ item.Name }}</p>
+              <img
+                :src="item.PicUrl"
+                :id="'sandTable' + index"
+                @click="insertHtml(item, 'image')"
+              />
+              <p class="source-identification">来源:弘则研究</p>
+            </div>
+            </template>
+            <tableNoData text="暂无数据" size="mini" v-else/>
+          </div>
+        </div>
+        <div v-if="tabsactive == '表格插入'">
 					<el-input
 						placeholder="表格名称"
 						v-model="sheetSearchObj.Keyword"
@@ -283,8 +281,11 @@
 						<tableNoData text="暂无数据" size="mini" v-else/>
 					</div>
 				</div>
-				<div v-if="tabsactive == 'MyETA批量插入'">
-					<importMyChart @handleImportMyChart="handleImportMyChart"/>
+        <div v-if="tabsactive == 'MyETA批量插入'">
+          <importMyChart @handleImportMyChart="handleImportMyChart" />
+        </div>
+        <div v-if="tabsactive == '语义分析插入'">
+					<importSemantics @handleImportSemantic="(item)=>insertHtml(item,'image')"/>
 				</div>
       </div>
     </div>
@@ -317,6 +318,7 @@ import mixinMsg from "./mixins/messagePush";
 import reportMixin from './mixins/reportMixin';
 import moment from "moment";
 import importMyChart from "./components/importMyChart.vue";
+import importSemantics from './components/importSemantics.vue';
 let ALOSSINS = null; //阿里云上传实例
 export default {
   beforeRouteEnter(to, from, next) {
@@ -329,7 +331,15 @@ export default {
   },
   mixins: [mixinMsg,reportMixin],
   data() {
+    let that=this
     return {
+      weekPanelTabs:[
+        "基础信息",
+        "图表插入",
+        "MyETA批量插入",
+        "沙盘插入",
+        "语义分析插入"
+      ],
       //批量导入图表
       importChartNum: 0, //批量导入图表的数量 如果大于0则说明在加载
 
@@ -855,7 +865,7 @@ export default {
       }
     },
   },
-  components: { importMyChart },
+  components: { importMyChart,importSemantics },
 };
 </script>
 

+ 109 - 2
src/views/report_manage/editreportNew.vue

@@ -49,6 +49,12 @@
 					>存草稿</el-button
 				>
 				<el-button v-permission="permissionBtn.reportManageBtn.reportManage_publish"
+					type="primary"
+					size="medium"
+					@click.native="clickreportadd('dsfb')"
+					>定时发布</el-button
+				>
+				<el-button
 					type="primary"
 					size="medium"
 					@click.native="clickreportadd('fb')"
@@ -290,8 +296,38 @@
 				<div v-if="tabsactive == 'MyETA批量插入'">
 					<importMyChart @handleImportMyChart="handleImportMyChart"/>
 				</div>
+				<div v-if="tabsactive == '语义分析插入'">
+					<importSemantics @handleImportSemantic="(item)=>insertHtml(item,'image')"/>
+				</div>
 			</div>
 		</div>
+
+		<!-- 定时发布弹窗 -->
+		<el-dialog 
+			v-dialogDrag 
+			:append-to-body="true" 
+			:visible.sync="showDSFB" 
+			width="500px" 
+			title="定时发布"
+		>
+			<div>
+				<div>
+					<span>发送时间</span>
+					<el-date-picker
+						v-model="taskTime"
+						type="datetime"
+						placeholder="选择日期时间"
+						value-format="yyyy-MM-dd HH:mm"
+						:picker-options="timePickerOpt"
+					/>
+				</div>
+				<p style="margin:15px 0">设置成功之后,研报将定时进行发送。</p>
+				<div style="text-align:right;margin:20px 0">
+					<el-button type="primary" plain @click="showDSFB=false">取消</el-button>
+					<el-button type="primary" @click="handleSetReportPrepublish">确定</el-button>
+				</div>
+			</div>
+		</el-dialog>
 	</div>
 </template>
 
@@ -305,7 +341,8 @@ import {
 	reportauthor,
 	classifyIdDetail,
 	dataBaseInterface,
-	sandInterface
+	sandInterface,
+	reportSetPrepublish
 } from 'api/api.js';
 import VueFroala from 'vue-froala-wysiwyg';
 import urlSlug from 'url-slug';
@@ -313,6 +350,7 @@ import http from '@/api/http.js';
 import mixinMsg from './mixins/messagePush'
 import reportMixin from './mixins/reportMixin';
 import importMyChart from './components/importMyChart.vue'
+import importSemantics from './components/importSemantics.vue';
 export default {
 	mixins:[mixinMsg,reportMixin],
 	data() {
@@ -530,6 +568,10 @@ export default {
 						content: data.Content,
 					};
 					this.ThsMsgIsSend=data.ThsMsgIsSend
+					// 回显定时发布时间
+					if(data.PrePublishTime){
+						this.taskTime=data.PrePublishTime
+					}
 				}
 			});
 		},
@@ -663,6 +705,71 @@ export default {
 				}
 			});
 		},
+		// 定时发布报告
+		handleSetReportPrepublish(){
+			if(!this.taskTime){
+				this.$message.warning('请选择定时发布的时间')
+				return
+			}
+			const now=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+			console.log(now);
+			console.log(this.taskTime);
+			if(this.$moment(this.taskTime).isBefore(now,'second')){
+				this.$message.warning('定时发布不得早于当前时间')
+				return
+			}
+			console.log('定时去发布了');
+			// 如果改报告已经推送过模板消息
+			if(this.ThsMsgIsSend==1){
+				reportSetPrepublish({
+					ReportId:Number(this.report_id),
+					PrePublishTime:this.taskTime,
+					PreMsgSend:0,
+				}).then(res=>{
+					if(res.Ret===200){
+						this.$message.success('定时发布成功!')
+						this.$router.push({ path: '/reportlist' });
+					}
+				})
+				return
+			}
+			this.$confirm('是否发布定时报告,并推送模板消息?', '发布提示', {
+				confirmButtonText: '推送',
+				cancelButtonText: '不推送',
+				type: 'warning',
+				distinguishCancelAndClose:true,
+				beforeClose:(action, instance,done)=>{
+					console.log(action, instance);
+					if(action==='close'||action==='cancel') {
+						//右上角或者不推送
+						reportSetPrepublish({
+							ReportId:Number(this.report_id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:0,
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success('定时发布成功!')
+								this.$router.push({ path: '/reportlist' });
+							}
+						})
+					} else {
+						//confirmButton
+						reportSetPrepublish({
+							ReportId:Number(this.report_id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:1,
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success('定时发布成功!')
+								this.$router.push({ path: '/reportlist' });
+							}
+						})
+					}
+					done()
+				}
+			})
+
+		},
 		//批量插入我的图表
 		handleImportMyChart(data){
 			//设置编辑器获取焦点
@@ -779,7 +886,7 @@ export default {
 			});
 		},
 	},
-	components: {importMyChart},
+	components: {importMyChart,importSemantics},
 };
 </script>
 

+ 4 - 2
src/views/report_manage/mixins/messagePush.js

@@ -27,7 +27,8 @@ export default {
             } else {
               this.publishreport(res.Data.ReportId);
             }
-          } else {
+          } else if(tp=='dsfb'){
+            this.showDSFB=true
             // this.$router.push({path:'/reportlist'});
           }
         }
@@ -54,7 +55,8 @@ export default {
             } else {
               this.publishreport(res.Data.ReportId);
             }
-          } else {
+          } else if(tp=='dsfb'){
+            this.showDSFB=true
             // this.$router.push({path:'/reportlist'});
           }
           //已经添加过报告

+ 28 - 0
src/views/report_manage/mixins/reportMixin.js

@@ -7,6 +7,23 @@ import {
   statisticFeatureInterface,
 } from "@/api/modules/chartRelevanceApi";
 export default {
+  watch:{
+    'taskTime'(){
+          this.taskTime=this.$moment(this.taskTime).format('YYYY-MM-DD HH:mm')+':00'
+			    const date = this.$moment(this.taskTime).startOf('day').format('x');
+	        const nowDate = this.$moment().startOf('day').format('x');
+	        // 如果选择的是今天 则需要禁用已经过去的时间节点
+	        if (date <= nowDate) {
+	            // 默认选择的最新时间 是当前时间的两分钟后 (留出2分钟的富裕时间)
+	            this.timePickerOpt.selectableRange = (
+	                `${this.$moment().add(2,'m').format('HH:mm:ss')} - 23:59:59`
+	            );
+	        }else {
+				// 如果是以后的日期,则不需要禁用时间节点
+	            this.timePickerOpt.selectableRange = '00:00:00 - 23:59:59';
+	        }
+		},
+  },
   data() {
     let that = this;
     return {
@@ -139,6 +156,7 @@ export default {
         "MyETA批量插入",
         "表格插入",
         "沙盘插入",
+        "语义分析插入"
       ],
 
       sheetSearchObj: {},
@@ -163,6 +181,16 @@ export default {
 
       isShowMe: false,
       autoSaveFlag: true, //是否开启自动保存
+
+      showDSFB:false,//显示定时发布弹窗
+			taskTime:'',//定时发布的时间
+			timePickerOpt:{
+				disabledDate(e){
+					return e.getTime()< new Date().getTime()-24 * 60 * 60 * 1000
+				},
+				selectableRange:'00:00:00 - 23:59:59',
+        format:'HH:mm'
+			},
     };
   },
 

+ 103 - 2
src/views/report_manage/reportEn/reportEditor.vue

@@ -64,6 +64,12 @@
 					>存草稿</el-button
 				>
 				<el-button v-permission="permissionBtn.enReportManageBtn.enReport_publish"
+					type="primary"
+					size="medium"
+					@click.native="clickreportadd('dsfb')"
+					>定时发布</el-button
+				>
+				<el-button
 					type="primary"
 					size="medium"
 					@click.native="clickreportadd('fb')"
@@ -299,6 +305,9 @@
 				<div v-if="tabsactive == 'MyETA批量插入'">
 					<importMyChart @handleImportMyChart="handleImportMyChart" :showEnMark="true" />
 				</div>
+				<div v-if="tabsactive == '语义分析插入'">
+					<importSemantics @handleImportSemantic="(item)=>insertHtml(item,'image')"/>
+				</div>
 			</div>
 		</div>
 
@@ -313,6 +322,33 @@
       :edblist="enChartInfo.ChartType===10?enEdblist:[]"
 		/>
 
+		<!-- 定时发布弹窗 -->
+		<el-dialog 
+			v-dialogDrag 
+			:append-to-body="true" 
+			:visible.sync="showDSFB" 
+			width="500px" 
+			title="定时发布"
+		>
+			<div>
+				<div>
+					<span>发送时间</span>
+					<el-date-picker
+						v-model="taskTime"
+						type="datetime"
+						placeholder="选择日期时间"
+						value-format="yyyy-MM-dd HH:mm"
+						:picker-options="timePickerOpt"
+					/>
+				</div>
+				<p style="margin:15px 0">设置成功之后,研报将定时进行发送。</p>
+				<div style="text-align:right;margin:20px 0">
+					<el-button type="primary" plain @click="showDSFB=false">取消</el-button>
+					<el-button type="primary" @click="handleConfirmDSFB">确定</el-button>
+				</div>
+			</div>
+		</el-dialog>
+
 	</div>
 </template>
 
@@ -329,6 +365,7 @@ import mixinMsg from '../mixins/messagePush'
 import reportMixin from '../mixins/reportMixin';
 import importMyChart from '../components/importMyChart.vue'
 import setEnNameDia from '@/views/dataEntry_manage/components/setEnNameDia.vue'
+import importSemantics from '../components/importSemantics.vue';
 export default {
 	mixins:[mixinMsg,reportMixin],
 	data() {
@@ -439,9 +476,26 @@ export default {
         language: "zh_cn",
         //允许粘贴的样式
         pasteAllowedStyleProps: ['font-family', 'font-size', 'color']
-      }
+      },
+
+			showDSFB:false,//显示定时发布弹窗
+			taskTime:'',//定时发布的时间
+			timePickerOpt:{
+				disabledDate(e){
+					return e.getTime()< new Date().getTime()-24 * 60 * 60 * 1000
+				},
+				selectableRange:'00:00:00 - 23:59:59'
+			},
 		};
 	},
+	beforeRouteEnter(to, from, next) {
+        if(to.query.id){
+            to.matched[1].name=`编辑英文研报`
+		}else{
+			to.matched[1].name=`添加英文研报`
+		}
+        next()
+    },
 	mounted() {
 		this.$route.query.id && this.getreportdetail();
 		this.getclassifylist();
@@ -473,6 +527,20 @@ export default {
 			this.$refs.sandTable.scrollTop=0
 			this.sandTabelQuery.CurrentIndex = 1
 			this.getSandTable()
+		},
+		'taskTime'(){
+			const date = this.$moment(this.taskTime).startOf('day').format('x');
+	        const nowDate = this.$moment().startOf('day').format('x');
+	        // 如果选择的是今天 则需要禁用已经过去的时间节点
+	        if (date <= nowDate) {
+	            // 默认选择的最新时间 是当前时间的两分钟后 (留出2分钟的富裕时间)
+	            this.timePickerOpt.selectableRange = (
+	                `${this.$moment().add(2,'m').format('HH:mm:ss')} - 23:59:59`
+	            );
+	        }else {
+				// 如果是以后的日期,则不需要禁用时间节点
+	            this.timePickerOpt.selectableRange = '00:00:00 - 23:59:59';
+	        }
 		}
 	},
 	methods: {
@@ -598,6 +666,10 @@ export default {
 						content: data.Content,
             overview:data.Overview||''
 					};
+					// 回显定时发布时间
+					if(data.PrePublishTime){
+						this.taskTime=data.PrePublishTime
+					}
 				}
 			});
 		},
@@ -674,7 +746,12 @@ export default {
 					});
 					window.open(href, "_blank");
 				} else if (tp === "fb") {
+					this.$confirm('是否确定立即发布报告?','提示',{type: 'warning'}).then(()=>{
 						this.publishreport(this.report_id);
+					})
+				}else if(tp==='dsfb'){
+					//定时发布
+					this.showDSFB=true
 				}
 			// if (tp == 'yl') { //预览
 			// 	sessionStorage.setItem('reportdtl', JSON.stringify(params));
@@ -698,6 +775,30 @@ export default {
 			});
 		},
 
+		//定时发布报告
+		handleConfirmDSFB(){
+			if(!this.taskTime){
+				this.$message.warning('请选择定时发布的时间')
+				return
+			}
+			const now=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+			console.log(now);
+			console.log(this.taskTime);
+			if(this.$moment(this.taskTime).isBefore(now,'second')){
+				this.$message.warning('定时发布不得早于当前时间')
+				return
+			}
+			reportEnInterface.enReportPrepblish({
+				ReportId:this.report_id,
+				PrePublishTime:this.taskTime
+			}).then(res=>{
+				if(res.Ret===200){
+					this.$message.success('定时发布成功!')
+					this.$router.push({ path: '/reportEnList' });
+				}
+			})
+		},
+
 		//批量插入我的图表
 		handleImportMyChart(data){
 			//设置编辑器获取焦点
@@ -817,7 +918,7 @@ export default {
 			});
 		},
 	},
-	components: {importMyChart,setEnNameDia},
+	components: {importMyChart,setEnNameDia,importSemantics},
 };
 </script>
 

+ 46 - 9
src/views/report_manage/reportEn/reportlist.vue

@@ -20,6 +20,17 @@
               @click="handlePullReport"
             >同步策略报告</el-button>
           </el-form-item>
+          <el-form-item label="">
+            <el-select
+              v-model="searchform.timeType"
+              placeholder="选择时间类型"
+              size="medium"
+              style="width:110px"
+            >
+              <el-option label="发布时间" value="publish_time"></el-option>
+              <el-option label="更新时间" value="modify_time"></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item label="">
             <el-date-picker
               v-model="searchform.dateValue"
@@ -53,11 +64,23 @@
               size="medium"
             ></el-cascader>
           </el-form-item>
+          <el-form-item label="">
+            <el-select
+              v-model.number="searchform.publishState"
+              placeholder="发布筛选"
+              size="medium"
+              clearable
+              style="width: 140px"
+            >
+              <el-option label="已发布" :value="2"></el-option>
+              <el-option label="未发布" :value="1"></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item label="">
             <el-select
               v-permission="permissionBtn.enReportManageBtn.enReport_sendEmail"
               v-model.number="searchform.EmailState"
-              placeholder="状态筛选"
+              placeholder="群发状态筛选"
               size="medium"
               clearable
               style="width: 140px"
@@ -68,7 +91,7 @@
           </el-form-item>
           <el-form-item>
             <el-input
-              placeholder="标题 / 作者"
+              placeholder="标题 / 创建人"
               v-model="searchform.key_word"
               clearable
               size="medium"
@@ -124,6 +147,12 @@
                 <span v-if="row.PvEmail&&row.Pv" style="color:#333">/</span>
                 <span v-if="row.Pv" style="color:#333">{{row.Pv}}</span>
               </span>
+              <span v-else-if="item.key==='PublishTime'">
+                <span>{{row.PrePublishTime?row.PrePublishTime:row.PublishTime}}</span>
+                <svg v-if="row.PrePublishTime&&row.State===1" width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+                  <path d="M15.2002 8C15.2002 4.13401 12.0662 1 8.20019 1C4.3342 1 1.20019 4.13401 1.2002 8C1.2002 11.866 4.3342 15 8.2002 15C12.0662 15 15.2002 11.866 15.2002 8ZM5.2002 10L5.2002 9L8.17491 9L11.2002 4.5L11.9073 5.20711L8.58912 10L5.2002 10Z" fill="#0052D9"/>
+                </svg>
+              </span>
 
               <span v-else-if="item.key==='handle'">
                 <template v-if="row.State===1">
@@ -326,12 +355,14 @@ export default {
   data() {
     return {
       searchform: {
+        timeType:'publish_time',
         dateValue:[],
         frequency:'',
         classifynameArr:'',
         state:'',
         key_word:'',
-        EmailState:''
+        EmailState:'',
+        publishState:''
       },
       optionsArr:[],
       frequencyArr: [ '年度','半年度','季度','月度','双周度','周度','日度','不定时' ],
@@ -460,7 +491,9 @@ export default {
         KeyWord:this.searchform.key_word,
         StartDate: this.searchform.dateValue ? this.searchform.dateValue[0] : '',
         EndDate: this.searchform.dateValue ? this.searchform.dateValue[1] : '',
-        EmailState:this.searchform.EmailState
+        EmailState:this.searchform.EmailState,
+        TimeType:this.searchform.timeType,
+        State:this.searchform.publishState.toString()
 			};
 			this.listLoading = true;
 			reportEnInterface.reportList(params).then(res => {
@@ -499,13 +532,17 @@ export default {
     },
 
     /* 发布报告 */
-    publishReport({Id}) {
-      reportEnInterface.reportPublish({ReportIds:String(Id)}).then(res=>{
-				if(res.Ret!==200) return
+    publishReport(item) {
+      this.$confirm(item.PrePublishTime?'该报告已设置定时发布,是否修改为立即发布?':'是否确定立即发布报告?','提示',{type: 'warning'}).then(()=>{
 
-        this.$message.success('发布成功');
-        this.getTableData();
+				reportEnInterface.reportPublish({ReportIds:String(item.Id)}).then(res=>{
+          if(res.Ret!==200) return
+          this.$message.success('发布成功');
+          this.getTableData();
+        })
+        
 			})
+      
     },
 
     /* 编辑报告 */

+ 1 - 1
src/views/report_manage/reportVariety.vue

@@ -40,7 +40,7 @@
         <!-- 品种编辑弹窗 -->
         <el-dialog 
             :modal-append-to-body='false' 
-            :title="!editBreedData.id?'新增分类':'编辑分类'" 
+            :title="!editBreedData.id?'添加品种':'编辑品种'" 
             :visible.sync="showEditBreed" 
             :close-on-click-modal="false"
             :center="true" 

+ 53 - 11
src/views/report_manage/reportlist.vue

@@ -33,6 +33,18 @@
               </a>
             </template>
           </el-form-item>
+          <el-form-item label="">
+            <el-select
+              v-model="searchform.timeType"
+              placeholder="选择时间类型"
+              size="medium"
+              style="width:110px"
+              @change="search"
+            >
+              <el-option label="发布时间" value="publish_time"></el-option>
+              <el-option label="更新时间" value="modify_time"></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item label="">
             <el-date-picker
               @change="search"
@@ -76,12 +88,25 @@
               size="medium"
             ></el-cascader>
           </el-form-item>
+          <el-form-item label="">
+            <el-select
+              v-model.number="searchform.publishState"
+              placeholder="发布筛选"
+              size="medium"
+              clearable
+              style="width: 140px"
+              @change="search"
+            >
+              <el-option label="已发布" :value="2"></el-option>
+              <el-option label="未发布" :value="1"></el-option>
+            </el-select>
+          </el-form-item>
           <el-form-item label="">
             <el-select
               v-permission="permissionBtn.reportManageBtn.reportManage_reportList_sendTime"
               @change="search"
               v-model.number="searchform.msgIsSend"
-              placeholder="状态筛选"
+              placeholder="推送消息状态"
               size="medium"
               clearable
               style="width: 140px"
@@ -93,7 +118,7 @@
           <el-form-item>
             <el-input
               @input="search"
-              placeholder="标题 / 作者"
+              placeholder="标题 / 创建人"
               v-model="searchform.key_word"
               clearable
               size="medium"
@@ -184,7 +209,14 @@
             min-width="124"
             align="center"
             :formatter="formatterColumn"
-          ></el-table-column>
+          >
+            <template slot-scope="scope">
+              <span>{{scope.row.PrePublishTime?scope.row.PrePublishTime:scope.row.PublishTime|formatTime}}</span>
+              <svg style="position: relative;top:2px" v-if="scope.row.PrePublishTime&&scope.row.State == '1'" width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15.2002 8C15.2002 4.13401 12.0662 1 8.20019 1C4.3342 1 1.20019 4.13401 1.2002 8C1.2002 11.866 4.3342 15 8.2002 15C12.0662 15 15.2002 11.866 15.2002 8ZM5.2002 10L5.2002 9L8.17491 9L11.2002 4.5L11.9073 5.20711L8.58912 10L5.2002 10Z" fill="#0052D9"/>
+              </svg>
+            </template>
+          </el-table-column>
           <el-table-column v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_reportList_sendTime)"
             prop="MsgSendTime"
             label="报告推送时间"
@@ -214,14 +246,14 @@
 							<a :href="hostapi+'?ReportId='+parseInt(scope.row.Id)" v-if="scope.row.VideoUrl" :download="scope.row.VideoName" style="cursor:pointer; color:#4099ef;">下载</a>
 						</template>
 					</el-table-column> -->
-          <el-table-column v-if="permissionBtn.checkPermissionBtn(permissionBtn.reportManageBtn.reportManage_reportList_uv)"
-            label="PV / UV"
+          <el-table-column
+            :label="hasUV?'PV / UV':'PV'"
             align="center"
             :render-header="renderHeader"
             width="140"
           >
             <template slot-scope="scope"
-              >{{ scope.row.Pv }}/{{ scope.row.Uv }}</template
+              >{{ hasUV? scope.row.Pv+'/'+scope.row.Uv:scope.row.Pv }}</template
             >
           </el-table-column>
           <el-table-column label="操作" align="center" min-width="130">
@@ -507,7 +539,7 @@
             class="el-icon-warning"
             style="font-size: 24px; color: #e6a23c; vertical-align: middle"
           ></i>
-          是否发布报告,且推送模板消息和客户群?
+          {{isDSFB?'该报告已设置定时发布,是否立即发布报告并推送模板消息?':'是否立即发布报告,并推送模板消息?'}}
         </div>
         <div style="margin-bottom: 20px; text-align: center">
           <el-button
@@ -515,7 +547,7 @@
             plain
             style="width: 100px"
             @click="handleClosePublish"
-            >取消发布</el-button
+            >取消</el-button
           >
           <el-button
             type="primary"
@@ -573,13 +605,17 @@ export default {
       let tag = false;
       this.tableData.forEach((item) => {
         if (this.batches.includes(item.Id)) {
-          if (item.NeedThsMsg != 0 && item.ThsMsgIsSend == 0) {
+          if (item.MsgIsSend== 0) {
             tag = true;
           }
         }
       });
       return tag;
     },
+    //是否有UV
+    hasUV(){
+      return this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_reportList_uv)
+    }
   },
   data() {
     return {
@@ -595,6 +631,7 @@ export default {
       listLoading: false,
       tableData: [],
       searchform: {
+        timeType:'publish_time',
         dateValue: "",
         frequency: "",
         classifynameArr: "",
@@ -602,6 +639,7 @@ export default {
         key_word: "",
         publish_sort: "desc",
         msgIsSend: "",
+        publishState:'',
       },
       batches: [],
       uploadloading: false,
@@ -622,6 +660,7 @@ export default {
       },
 
       showPublish: false,
+      isDSFB:false,//是否为定时发布
       tableKey:0,
     };
   },
@@ -694,14 +733,14 @@ export default {
             },
             "pv:报告被打开的次数,每次打开都计算一次(只统计有权限用户)"
           ),
-          h(
+          this.hasUV?h(
             "p",
             {
               slot: "content",
               attrs: { style: "display:block;padding:5px 0;width:420px;" },
             },
             "uv:访问报告的人数,每篇报告同一个人访问只计算一次(只统计有权限用户)"
-          ),
+          ):h(''),
           h(
             "el-button",
             {
@@ -877,6 +916,7 @@ export default {
       //发布报告
       this.batches = [];
       this.batches.push(item.Id);
+      this.isDSFB=item.PrePublishTime?true:false
 
       // 周报不需要弹窗直接发布
       // 2023/3/6 研报后台5.5中修改 周报校验是否上传了音频
@@ -1007,6 +1047,8 @@ export default {
         KeyWord: this.searchform.key_word,
         MsgIsSend: this.searchform.msgIsSend,
         // PublishSort:this.searchform.publish_sort,
+        State:this.searchform.publishState,
+        TimeType:this.searchform.timeType
       };
       if (this.searchform.dateValue) {
         params.StartDate = this.searchform.dateValue[0];

+ 18 - 2
src/views/resetpassword.vue

@@ -86,7 +86,7 @@
             ></i>
           </el-input>
         </el-form-item>
-        <el-form-item style="text-align: center; padding-top: 20px">
+        <el-form-item style="text-align: center;">
           <el-button type="primary" size="medium" @click.native="addSubmit"
             >确定</el-button
           >
@@ -107,6 +107,7 @@
 import { modifyPwd } from "@/api/api.js";
 import http from "@/api/http.js";
 import md5 from "@/utils/md5.js";
+import{checkPassWord} from '@/utils/commonOptions';
 export default {
   data() {
     return {
@@ -126,6 +127,15 @@ export default {
           },
         ],
         NewPwd: [
+            {
+                validator:(rule,value,callback)=>{
+                    if(!checkPassWord(value)){
+                        callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+                    }else{
+                        callback()
+                    }
+                }
+            },
           {
             required: true,
             message: "请输入确认密码",
@@ -188,4 +198,10 @@ export default {
 };
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.box-card{
+    .el-form-item{
+        margin-bottom: 40px;
+    }
+}
+</style>

+ 15 - 13
src/views/sandbox_manage/sandFlow/index.vue

@@ -119,9 +119,10 @@ export default {
 		},
 
 		/* 获取画布内容 */
-		getGraphData() {
+		getGraphData(SandboxVersionCode,modifyType) {
 			const { id,type } = this.$route.query;
-
+			const sandbox_versioncode = id||SandboxVersionCode
+			const modify_type = type||modifyType
 			// type === 'edit' && sandInterface.sandData({
 			// 	SandboxId: id
 			// }).then(res => {
@@ -137,9 +138,9 @@ export default {
 			// 	// 轮询
 			// 	this.$route.query.type === 'edit' && this.autoSave();
 			// })
-
+			if(!sandbox_versioncode) return
 			sandInterface.versionData({
-				SandboxVersionCode: id
+				SandboxVersionCode: id||SandboxVersionCode
 			}).then(res => {
 				if(res.Ret !== 200) return
 
@@ -149,14 +150,14 @@ export default {
 					classify: ChartPermissionId
 				}
 				this.initData = JSON.parse(Content);
-                this.$nextTick(()=>{
-                    this.graph.centerContent()
-                })
-				if(type === 'edit') {
+				this.$nextTick(()=>{
+					this.graph.centerContent()
+				})
+				if(modify_type === 'edit') {
 					this.sandInfo = res.Data;
 					// 轮询
 					this.autoSave();
-                    //this.graph.centerContent();
+					//this.graph.centerContent();
 				}
 			})
 		},
@@ -182,9 +183,9 @@ export default {
 				const params = new FormData();
 				params.append('Img',dataUri)
 				const { Data } = await dataBaseInterface.uploadImgSvg(params);
-				let SandboxVersionCode = (this.sand_id && classify === this.sandInfo.ChartPermissionId)  ? this.sand_id : '';
-				
-				const { Ret , Data : sandData} =	await sandInterface.sandSave({
+				//let SandboxVersionCode = (this.sand_id && classify === this.sandInfo.ChartPermissionId)  ? this.sand_id : '';
+				let SandboxVersionCode = this.sand_id
+				const { Ret , Data : sandData} = await sandInterface.sandSave({
 					SandboxVersionCode,
 					Name: name,
 					ChartPermissionId: Number(classify),
@@ -207,7 +208,8 @@ export default {
 						type:'edit',
 						},
 					});
-					this.getGraphData();
+					this.getGraphData(sandData.VersionCode,'edit');
+					return
 				}
 				
 				callback && callback();

+ 2 - 2
src/views/semantics_manage/components/canvasTable.vue

@@ -112,7 +112,7 @@ export default {
   height: 450px;
   overflow: scroll;
   table{
-    width:100%;
+    width:1000px;
     height: 100%;
     border-collapse: collapse;
     /* position: relative; */
@@ -164,7 +164,7 @@ export default {
       }
     }
     td{
-      min-width: 200px;
+      // min-width: 200px;
       min-height: 45px;
       border: 1px solid black;
       padding:5px;

+ 4 - 0
src/views/semantics_manage/semantics/components/selectFileDialog.vue

@@ -139,6 +139,10 @@ export default {
       })
       //获取选择对比文档ids 结果抛出
       if(selectKeys.length){
+        if(selectKeys.length>10){
+          this.$message.warning('最多支持选择10个文档')
+          return
+        }
         this.$emit('selectFile',selectKeys)
       }else{
         this.closeDialog()

File diff suppressed because it is too large
+ 38 - 4
src/views/semantics_manage/semanticsPage.vue


+ 54 - 8
src/views/system_manage/components/addUserDialog.vue

@@ -13,22 +13,29 @@
                 </el-input>
             </el-form-item>
             <el-form-item label="登录密码" prop="pwd" v-if="userForm.title == '添加用户'">
-                <el-input v-model="userForm.pwd" placeholder="6-12位数字与字母的组合" 
+                <el-input v-model.trim="userForm.pwd" placeholder="6-12位数字与字母的组合" 
                     :type="userForm.title == '添加用户' ? 'text' : 'password' " clearable></el-input>
             </el-form-item>
             <el-form-item label="姓名" prop="name">
                 <el-input v-model="userForm.name" placeholder="请输入用户名称"  clearable>
                 </el-input>
             </el-form-item>
-            <el-form-item label="手机号码" prop="mobile">
-                <el-input v-model="userForm.mobile" placeholder="请输入手机号码" :disabled="userForm.disabledForm" clearable>
+            <el-form-item label="手机号码" prop="mobile" class="mobile-input-item">
+                <el-input v-model.trim="userForm.mobile" placeholder="请输入手机号码" clearable class="mobile-input">
                 </el-input>
+                <el-select v-model="userForm.areacode" class="mobile-select" placeholder="请选择">
+                    <el-option v-for="item in areaCode" :key="item.Value"
+                        :label="item.Name" :value="item.Value" />
+                </el-select>
             </el-form-item>
             <el-form-item label="所属部门" prop="depart" v-if="userForm.title == '添加用户'">
                 <el-cascader :options="departArr" v-model="userForm.depart" :props="form_departProp"
                     placeholder="请选择部门分组" :disabled="userForm.disabledForm" clearable>
                 </el-cascader>
             </el-form-item>
+            <el-form-item label="邮箱" prop="email">
+                <el-input v-model="userForm.email" placeholder="请输入邮箱"></el-input>
+            </el-form-item>
             <el-form-item label="工号" prop="employeeNumber">
                 <el-input :disabled="hasEmployeeNo" v-model="userForm.employeeNumber" placeholder="请输入工号"></el-input>
             </el-form-item>
@@ -68,7 +75,8 @@
 </template>
 
 <script>
-import searchDistPicker from '@/components/searchDistPicker.vue'
+import searchDistPicker from '@/components/searchDistPicker.vue';
+import {patternEmail,isMobileNo,checkPassWord} from '@/utils/commonOptions';
     export default {
         props: {
             isAddUserDialogShow: {
@@ -96,6 +104,10 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             researchGroup:{
                 type:Array,
                 default:()=>{return []}
+            },
+            areaCode:{
+                type:Array,
+                default:()=>{return []}
             }
         },
         components:{searchDistPicker},
@@ -103,13 +115,33 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             return {
                 userRule: {
                     account:[{required: true, message: '登录账号不能为空', trigger: 'blur'}],
-                    pwd:[{ required: true, message: '登录密码不能为空', trigger: 'blur' }],
+                    pwd:[{validator:(rule,value,callback)=>{
+                        if(value===''){
+                            callback(new Error('请输入新密码'))
+                        }
+                        if(!checkPassWord(value)){
+                            callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
+                        }else{
+                            callback()
+                        }
+                    }}],
                     name:[{ required: true, message: '姓名不能为空', trigger: 'blur' }],
                     mobile:[{ validator: (rule, value, callback) => {
-                        if (value === '') {
-                            callback(new Error('手机号码不能为空'));
-                        }else if(isNaN(value.trim())) {
+                        if (value === ''&&!this.userForm.email) {
+                            callback(new Error('手机号码和邮箱至少填一个'));
+                        }else if(value&&this.userForm.areacode==='86'&&!isMobileNo(value)) {
                             callback(new Error('请输入正确的手机号格式'));
+                        } else if(this.userForm.areacode!=='86'&&isNaN(value.trim())){
+                            callback(new Error('请输入正确的手机号格式'));
+                        }else {
+                            callback();
+                        }
+                    }, trigger: 'blur'}],
+                    email:[{ validator: (rule, value, callback) => {
+                        if (value === ''&&!this.userForm.mobile) {
+                            callback(new Error('手机号码和邮箱至少填一个'));
+                        }else if(value&&!patternEmail.test(value)) {
+                            callback(new Error('请输入正确的邮箱格式'));
                         } else {
                             callback();
                         }
@@ -163,6 +195,20 @@ import searchDistPicker from '@/components/searchDistPicker.vue'
             width:145px;
         }
     }
+    .mobile-input-item{
+        position:relative;
+        .mobile-select{
+            position:absolute;
+            top:0;
+            left:0;
+            width:115px !important;
+        }
+        .mobile-input{
+            .el-input__inner{
+                padding-left: 125px !important;
+            }
+        }
+    }
 }
 </style>
 <style scoped lang="scss">

+ 10 - 5
src/views/system_manage/dataAuthManage.vue

@@ -1,6 +1,7 @@
 <template>
-	<div class="dataAuth-container" v-if="showData">
-		<el-cascader 
+	<div class="dataAuth-container">
+		<el-cascader
+		v-model="default_user"
 		:options="classifyArr"
 		:props="classifyProp"
 		:show-all-levels="false"
@@ -10,7 +11,7 @@
 		clearable
 		@change="chooseUser"
 		/>
-		<ul class="user-list-cont">
+		<!-- <ul class="user-list-cont">
 			<li
 				v-for="item in userList"
 				:key="item.AdminId"
@@ -19,7 +20,7 @@
 			>
 				{{ item.AdminRealName }}
 			</li>
-		</ul>
+		</ul> -->
 		<div class="setting-cont" v-if="authList.length">
 			<ul class="menu_lists">
 				<li v-for="item in authList" :key="item.id" class="menu_item">
@@ -101,7 +102,8 @@ export default {
 			classifyProp:{
 				value:'ItemId',
 				label:'ItemName',
-				children:'Children'
+				children:'Children',
+				emitPath:false
 			},
 			default_user: '',
 			new_label:'',//输入框新值
@@ -119,6 +121,8 @@ export default {
 			handler(val) {
 				if (val) {
 					this.getAuth();
+				}else{
+					this.getAuth()
 				}
 			}
 		}
@@ -173,6 +177,7 @@ export default {
 		},
 		/* 选择人员 */
 		chooseUser(val) {
+			if(!val) return
 			if(val.length) {
 				// console.log(val)
 				let id = val[2];

+ 39 - 136
src/views/system_manage/departManage.vue

@@ -3,7 +3,7 @@
 		<div class="left_cont">
 			<div class="company_top" @click="initDepart">
 				<img src="~@/assets/img/set_m/home_ico.png" alt="" style="width:30px;height:30px;">
-				<span :class="!defaultGroup&&!defaultDepart?'act':''">{{isTrail?global.company_name:'弘则研究'}}</span>
+				<span :class="!defaultGroup&&!defaultDepart?'act':''">部门信息</span>
 			</div>
 			<el-tree
 				ref="departTree"
@@ -12,7 +12,6 @@
 				:data="departArr"
 				node-key="unicodeKey"
 				:props="defaultProp"
-				default-expand-all
 				draggable 
 				:allow-drag="checkAllowDrag"
 				:allow-drop="checkAllowDrop"
@@ -85,6 +84,11 @@
 							<span style="position: relative;">{{scope.row.RealName}}</span>
 						</template>
 					</el-table-column>
+					<el-table-column 
+						prop="AdminName"
+						label="账号"
+						align="center"
+					/>
 					<el-table-column
 					prop="Mobile"
 					label="手机号"
@@ -112,7 +116,6 @@
 						<template slot-scope="scope">
 							<div style="color:#4099ef; font-size:24px;display: flex;gap:0 10px;">
 								<span  v-permission="permissionBtn.sysDepartPermission.sysDepart_saveUser"
-								v-if="!isTrail || (!(scope.row.DepartmentGroup=='ETA试用客户'&&scope.row.Enabled===0))"
 									class="editsty" @click.stop="editUser(scope.row)">编辑</span>
 								<span v-permission="permissionBtn.sysDepartPermission.sysDepart_resetPass"
 									class="editsty" @click.stop="resetPassWord(scope.row)">重置密码</span>
@@ -285,127 +288,6 @@
 				<el-button  style="width:80px;" @click="cancelHandle(2)">取消</el-button>
 			</div>
 		</el-dialog>
-		<!-- 添加用户
-			研报后台5.9后拆成组件重写了,这块没实际用到,留着参考
-		 -->
-		<!-- <el-dialog
-		:title="userForm.title"
-		:visible.sync="isAddUser"
-		:close-on-click-modal="false"
-		:modal-append-to-body='false'
-		@close="cancelHandle(3)"
-		center
-		width="700px"
-		top="5vh"
-		v-dialogDrag>
-			<div slot="title" style="display:flex;alignItems:center;">
-				<img :src="userForm.title=='添加用户'?$icons.add:$icons.edit" style="color:#fff;width:16px;height:16px;marginRight:5px;">
-				<span style="fontSize:16px;">{{userForm.title}}</span>
-			</div>
-			<el-form @submit.native.prevent :model="userForm" :rules="userRule" ref="userForm" label-width="100px" class="demo-ruleForm" style="marginTop:15px;">
-				<el-form-item label="登录账号" prop="account">
-					<el-input
-					v-model="userForm.account"
-					placeholder="建议使用邮箱前缀或者手机号码"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="登录密码" prop="pwd">
-					<el-input 
-					v-model="userForm.pwd"
-					placeholder="6-12位数字与字母的组合"
-					style="width:90%"
-					:type="userForm.title == '添加用户' ? 'text' : 'password' "
-					clearable></el-input>
-				</el-form-item>
-				<el-form-item label="工号" prop="employeeNumber">
-					<el-input :disabled="hasEmployeeNo"
-					v-model="userForm.employeeNumber"
-					placeholder="请输入工号"
-					style="width:90%"></el-input>
-				</el-form-item>
-				<el-form-item label="姓名" prop="name">
-					<el-input
-					v-model="userForm.name"
-					placeholder="请输入用户名称"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="所属部门" prop="depart">
-					<el-cascader
-						:options="departArr"
-						v-model="userForm.depart"
-						:props="form_departProp"
-						placeholder="请选择部门分组"
-						:key="cascaderIdx"
-						style="width:90%"
-						clearable
-						></el-cascader>
-				</el-form-item>
-				<el-form-item label="分配角色" prop="role">
-					<el-select v-model="userForm.role" placeholder="分配角色" @change="roleChange" style="width:90%">
-						<el-option
-							v-for="item in roleArr"
-							:key="item.RoleId"
-							:label="item.RoleName"
-							:value="item.RoleId">
-						</el-option>
-					</el-select>
-				</el-form-item>
-					<el-form-item label="研究方向" prop="direct">
-						<el-cascader
-						collapse-tags
-						:show-all-levels="false"
-						:options="researchGroup"
-						v-model="userForm.direct"
-						:props="form_directProp"
-						placeholder="请选择研究方向"
-						style="width:90%"
-						clearable
-						></el-cascader>
-					</el-form-item>
-					<el-form-item label="工作地点" prop="city"
-					:rules="[2,6,18].includes(userForm.role)?{ required: true, message: '工作地点不能为空', trigger: 'change' }:{}">
-						<v-distpicker 
-              :province-source="province_sorce"
-              :city-source="city_sorce"
-							:province="userForm.province"
-							:city="userForm.city"
-							hide-area 
-							@selected="selectRegion"
-							@province="provinceChange"
-						></v-distpicker>
-					</el-form-item>
-				<el-form-item label="职务" prop="post">
-					<el-input
-					v-model="userForm.post"
-					placeholder="请输入职务"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="手机号码" prop="mobile">
-					<el-input
-					v-model="userForm.mobile"
-					placeholder="请输入手机号码"
-					style="width:90%"
-					clearable>
-					</el-input>
-				</el-form-item>
-				<el-form-item label="状态" prop="status">
-					<el-radio-group v-model="userForm.status">
-						<el-radio :label="1">启用</el-radio>
-						<el-radio :label="0">禁用</el-radio>
-					</el-radio-group>
-				</el-form-item>
-			</el-form>	
-			<div style="display:flex;justify-content:center;margin:75px 0 26px;">
-				<el-button type="primary" style="width:80px;marginRight:24px;" @click="saveUser">保存</el-button>
-				<el-button  style="width:80px;" @click="cancelHandle(3)">取消</el-button>
-			</div>
-		</el-dialog> -->
 		<!-- 编辑分组 -->
 		<el-dialog
 		title="编辑分组"
@@ -448,6 +330,7 @@
 			:roleArr="roleArr"
 			:hasEmployeeNo="hasEmployeeNo"
 			:researchGroup="researchGroup"
+			:areaCode="areaCode"
 			@close="cancelHandle(3)"
 			@save="saveUser"
 			@selectRegion="selectRegion"
@@ -463,10 +346,13 @@
 		>
 			<div class="dialog-container">
 				<el-form ref="resetForm" :model="resetForm" :rules="resetRules" label-width="100px">
+					<el-form-item label="账号">
+						<span>{{modifyAdminName}}</span>
+					</el-form-item>
 					<el-form-item label="新密码" prop="password">
 						<el-input v-model="resetForm.password" style="width:100%" :show-password="true"></el-input>
 					</el-form-item>
-					<el-form-item label="确认新密码" prop="check">
+					<el-form-item label="确认新密码" prop="check" style="margin-bottom: 40px;">
 						<el-input v-model="resetForm.check" style="width:100%" :show-password="true"></el-input>
 					</el-form-item>
 				</el-form>
@@ -485,6 +371,10 @@
 			@close="isMoveDepartShow=false" center width="460px" v-dialogDrag
 		>
 			<div class="dialog-cotainer">
+				<div class="form-item" style="display: flex;align-items: center;margin-bottom:20px">
+					<p style="width:90px">账号</p>
+					<span>{{modifyAdminName}}</span>
+				</div>
 				<div class="form-item" style="display: flex;align-items: center;">
 					<p style="width:90px">选择分组</p>
 					<el-cascader :options="departArr" v-model="resetDepart" :props="form_departProp" style="width:100%"
@@ -506,7 +396,6 @@ import { departInterence } from '@/api/api.js';
 import http from '@/api/http.js'
 import md5 from '@/utils/md5.js';
 import mixin from './mixin/departManageMixin.js';
-import global from '@/config/setting'
 //自定义省市数据
 import{province_sorce,city_sorce} from '@/utils/distpicker'; 
 export default {
@@ -534,7 +423,6 @@ export default {
         }
 		}
 		return {
-			global,
 			isAddDepart:false,//添加部门弹窗
 			departForm:{
 				title:"添加部门",
@@ -596,6 +484,8 @@ export default {
 				post:'',
 				employeeNumber:'',
 				mobile:'',
+				email:'',
+				areacode:'86',
 				auth:0,
 				status:1,//状态 1启用 0禁用
 				disabledForm:false,//是否禁用表单的某些选项
@@ -682,6 +572,7 @@ export default {
 				direct:'',
 				province:'',
 				city:'',
+				email:'',
 			},//用户详情信息
 			authList:[],//权限列表
 			click_roleId:'',//角色id
@@ -711,11 +602,8 @@ export default {
     }
 	},
 	computed:{
-		// 有些是试用平台独有的内容和判断
-		// 是否是eta试用
 		isTrail(){
-			// console.log(this.$store.state.businessCode,this.$store.state.TRIAL_CODE,'this.$store.state.businessCode == this.$store.state.TRIAL_CODE');
-			return this.$store.state.businessCode == this.$store.state.TRIAL_CODE
+			return this.$store.state.hasTrialUserPermisson
 		}
 	},
 	created() {
@@ -725,6 +613,7 @@ export default {
 		}else if(process.env.NODE_ENV == 'production'){
 			this.shareCustomDepartmentId = 37
 		}
+		this.getAreaCode()
 	},
 	mounted() {
 		this.getDepartArr();
@@ -760,7 +649,7 @@ export default {
 					this.departArr = res.Data.List || []
 					if(this.isTrail){
 						this.departArr = this.departArr.map(item=>{
-							//如果部门为ETA试用客户,则屏蔽所有操作
+							//如果部门为ETA试用客户,则屏蔽所有操作 CRM12.4
 							if(item.DepartmentName==='ETA试用客户'){
 								item.disabled = true
 								item.canEdit = false
@@ -1080,7 +969,7 @@ export default {
 			this.userForm = {
 				title:'添加用户',
 				account:'',
-				pwd:'123456a',
+				pwd:'',
 				employeeNumber:'',
 				name:'',
 				depart:'',
@@ -1090,6 +979,8 @@ export default {
 				city:'',
 				post:'',
 				mobile:'',
+				email:'',
+				areacode:'86',
 				auth:0,
 				status:1
 			}
@@ -1145,6 +1036,8 @@ export default {
 							ResearchGroupIds:ResearchGroupIds.join(','),
 							Province:this.userForm.province,
 							City:this.userForm.city,
+							Email:this.userForm.email,
+							TelAreaCode:this.userForm.areacode
 						}
 						//console.log('testAdd',params)
 						departInterence.addUser(params).then(res => {
@@ -1164,6 +1057,8 @@ export default {
 									city:'',
 									post:'',
 									mobile:'',
+									email:'',
+									areacode:'86',
 									auth:0,
 									status:1
 								}
@@ -1192,7 +1087,9 @@ export default {
 							Enabled:Number(this.userForm.status),
 							ResearchGroupIds:ResearchGroupIds.join(','),
 							Province:this.userForm.province,
-							City:this.userForm.city
+							City:this.userForm.city,
+							Email:this.userForm.email,
+							TelAreaCode:this.userForm.areacode
 						}
 						//console.log('testEdit',params)
 						departInterence.editUser(params).then(res => {
@@ -1212,6 +1109,8 @@ export default {
 									city:'',
 									post:'',
 									mobile:'',
+									email:'',
+									areacode:'86',
 									auth:0,
 									status:1
 								}
@@ -1252,6 +1151,8 @@ export default {
 					city:'',
 					post:'',
 					mobile:'',
+					email:'',
+					areacode:'86',
 					auth:'无',
 					status:1
 				},
@@ -1348,14 +1249,16 @@ export default {
 				direct:direct,
 				departmentName:item.DepartmentGroup,
         disabledForm:false,
-				disabledStatus:false
+				disabledStatus:false,
+				email:item.Email,
+				areacode:item.TelAreaCode
 			}
 			this.hasEmployeeNo=!!item.EmployeeId
 			this.isAddUser = true;
 		},
 		/* 删除用户 */
 		delUser(item) {
-			this.$confirm('是否确认删除该用户?','提示',{
+			this.$confirm(`是否确认删除用户【${item.AdminName}】`,'提示',{
 				type:'warning'
 			}).then(() => {
 				departInterence.delUser({

+ 5 - 5
src/views/system_manage/enAuthManage.vue

@@ -77,7 +77,7 @@
             <el-tooltip
               effect="dark"
               placement="top-start"
-              content="此项删除仅删除该用户的英文销售权限"
+              content="删除操作仅删除该用户的英文权限"
             >
               <i class="el-icon-question" />
             </el-tooltip>
@@ -193,16 +193,16 @@ export default {
       authOptions:[
         {
           code:'english_company_admin',
-          label:'英文客户列表'
+          label:'英文客户列表管理员'
         },{
           code:'english_report_admin',
-          label:'英文研报'
+          label:'英文研报管理员'
         },{
           code:'english_ppt_admin',
-          label:'英文PPT'
+          label:'英文PPT管理员'
         },{
           code:'english_day_new_admin',
-          label: '每日资讯'
+          label: '每日资讯管理员'
         }],//权限设置页面选项
       isIndeterminate:false,//权限设置 全选样式
       checkAll:true,//权限设置 全选值

+ 21 - 6
src/views/system_manage/mixin/departManageMixin.js

@@ -5,7 +5,8 @@
  */
 import { departInterence } from '@/api/api.js';
 import http from '@/api/http.js';
-import AddUserDialog from '../components/addUserDialog.vue'
+import AddUserDialog from '../components/addUserDialog.vue';
+import{checkPassWord} from '@/utils/commonOptions';
 
 export default {
     components:{AddUserDialog},
@@ -13,10 +14,13 @@ export default {
         const validatePass = (rule,value,callback)=>{
             if(value===''){
                 callback(new Error('请输入新密码'))
+            }
+            if(this.resetForm.check!==''){
+                this.$refs.resetForm.validateField('check')
+            }
+            if(!checkPassWord(value)){
+                callback(new Error('密码要求8位及以上,包含数字、大写字母、小写字母、特殊字符中的三个类型'))
             }else{
-                if(this.resetForm.check!==''){
-                    this.$refs.resetForm.validateField('check')
-                }
                 callback()
             }
         }
@@ -25,8 +29,9 @@ export default {
                 callback(new Error('请输入确认密码'))
             }else if(value!==this.resetForm.password){
                 callback(new Error('两次输入的密码不一致'))
+            }else{
+                callback()
             }
-            callback()
         }
         return {
             isExtraUserFormItemShow: false, //是否显示额外的用户表单项
@@ -53,7 +58,9 @@ export default {
                 check:''
             },
             resetDepart:'',
-            modifyAdminId:0
+            modifyAdminId:0,
+            areaCode:[],
+            modifyAdminName:'',
 
         }
     },
@@ -175,6 +182,7 @@ export default {
             if(type==='show'){
                 this.$refs.resetForm&&this.$refs.resetForm.clearValidate()
                 this.modifyAdminId = data.AdminId
+                this.modifyAdminName=data.AdminName
                 this.isResetPasswordShow = true
             }else{
                 this.$refs.resetForm.validate((valid)=>{
@@ -208,6 +216,7 @@ export default {
                 data.TeamId ?departArr.push(data.TeamId):''
                 this.resetDepart = departArr
                 this.modifyAdminId = data.AdminId
+                this.modifyAdminName=data.AdminName
                 this.isMoveDepartShow = true
             }else{
                 //选择分组接口
@@ -223,6 +232,12 @@ export default {
                     this.getTableUser();
                 })
             }
+        },
+        getAreaCode(){
+            departInterence.getPhoneAreaCode().then(res=>{
+                if(res.Ret!==200) return 
+                this.areaCode = res.Data||[]
+            })
         }
     }
 

+ 14 - 9
src/views/system_manage/newAuthManage.vue

@@ -2,13 +2,16 @@
     <div class="authManage_container">
         <div class="auth_cont_top">
             <div>
-                <span>角色</span>
-                <el-select v-model="role" placeholder="请选择角色" style="width:360px;marginLeft:30px;">
+                <span>角色:</span>
+                <span>{{Role.RoleName}}</span>
+                <!-- <el-select v-model="role" placeholder="请选择角色" style="width:360px;marginLeft:30px;">
                     <el-option v-for="item in roleList" :key="item.RoleId" :label="item.RoleName" :value="item.RoleId">
                     </el-option>
-                </el-select>
+                </el-select> -->
             </div>
-            <el-button type="primary" style="marginRight:50px;width:140px;" @click="saveAuth" v-if="!isLook">确定
+            <el-button style="margin-left:auto;marginRight:50px;width:140px;" @click="$router.back()" v-if="!isLook">取消
+            </el-button>
+            <el-button type="primary" style="marginRight:50px;width:140px;" @click="saveAuth" v-if="!isLook">保存
             </el-button>
         </div>
         <div class="auth_bot">
@@ -38,6 +41,7 @@ export default {
             defaultCheckedKeys: [],
             loading: null, //loading
             isLook: false, //是否仅查看
+            Role:{},//角色
         };
     },
     watch: {
@@ -58,10 +62,11 @@ export default {
         getRoles() {
             departInterence.getRole().then(res => {
                 if (res.Ret === 200) {
-                    this.roleList = res.Data.List;
-                    if (res.Data.List.length && !this.role) {
+                    this.roleList = res.Data.List||[];
+                    /* if (res.Data.List.length && !this.role) {
                         this.role = res.Data.List[0].RoleId
-                    }
+                    } */
+                    this.Role = this.roleList.find(i=>i.RoleId===this.role)||{}
                 }
             })
         },
@@ -103,6 +108,7 @@ export default {
             }).then(res=>{
                 if(res.Ret!==200) return 
                 this.$message.success('权限设置成功')
+                this.$router.back()
             })
         },
         formatTree(data,type){
@@ -120,10 +126,9 @@ export default {
         },
     },
     created() {
-        //只查看权限 不可编辑
         if (this.$route.query.id) {
             this.role = Number(this.$route.query.id);
-            this.isLook = true;
+            //this.isLook = true;
         }
     },
     mounted() {

+ 125 - 0
src/views/system_manage/outlinkList.vue

@@ -0,0 +1,125 @@
+<template>
+  <div id="out-link-list" class="out-link-list">
+    <div v-if="outlinkData && outlinkData.length>0" class="outlink-box">
+      <div class="outlink-item" v-for="item in outlinkData" :key="item.Id" @click="gotoOutlink(item)">
+        <img src="~@/assets/img/eta_base_config/outlink.png">
+        <div class="outlink-item-text-zone">
+          <span>{{ item.Title }}</span>
+          <span>{{ item.Url }}</span>
+        </div>
+      </div>
+    </div>
+    <div class="no-outlink" v-else>
+      <img src="~@/assets/img/data_m/nodata.png"/>
+      <span>暂无数据</span>
+    </div>
+
+  </div>
+</template>
+
+<script>
+import {outlinkConfigInterence} from "@/api/modules/etaBaseConfigApi.js"
+  export default {
+    name:"outlinkList",
+    data() {
+      return {
+        outlinkData:[]
+      }
+    },
+    created(){
+      this.getOutlinkData()
+    },
+    methods: {
+      getOutlinkData(){
+        outlinkConfigInterence.getOutlinkListAll().then(res=>{
+          if(res.Ret == 200){
+            this.outlinkData = res.Data.List || []
+            // console.log(this.outlinkData);
+          }
+        })
+      },
+      gotoOutlink(item){
+        window.open(item.Url, '_blank')
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .out-link-list{
+    min-height: calc(100vh - 110px);
+    height:calc(100vh - 110px);
+    background-color: white;
+    border: solid 1px #DCDFE6;
+    box-sizing: border-box;
+    padding: 30px;
+    .outlink-box{
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+      justify-content: flex-start;
+      margin-right: -30px;
+      .outlink-item{
+        display: flex;
+        align-items: flex-start;
+        height: 100px;
+        width: 250px;
+        border-radius: 8px;
+        box-sizing: border-box;
+        padding: 30px 40px 30px 13px;
+        border: solid 2px #0052D9;
+        cursor: pointer;
+        margin: 0 30px 30px 0;
+        background-color: #F2F3FF;
+        img{
+          height: 55px;
+          margin-top: -6px;
+          width: 55px;
+        }
+        .outlink-item-text-zone{
+          overflow: hidden;
+          text-overflow: ellipsis;
+          span{
+            font-size: 16px;
+            font-weight: bold;
+            color: #333;
+            white-space: nowrap;
+            &:last-child{
+              font-size: 12px;
+              color: #999999;
+              font-weight: 400;
+              display: block;
+              margin-top: 4px;
+            }
+          }
+        }
+        &:hover{
+          background-color: #0052D9;
+          .outlink-item-text-zone{
+            span{
+              color: #ffffff;
+              &:last-child{
+                color: rgba($color: #ffffff, $alpha: 0.65);
+              }
+            }
+          }
+        }
+      }
+    }
+    .no-outlink{
+      margin: 70px auto;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+      width: 260px;
+      img{
+        width: 260px;
+      }
+      span{
+       font-size: 16px;
+       color: #999999; 
+      }
+    }
+  }
+</style>

+ 194 - 0
src/views/system_manage/outlinkListConfig.vue

@@ -0,0 +1,194 @@
+<template>
+  <div id="outlink-list-config" class="outlink-list-config">
+    <div class="outlink-top-button-zone">
+      <el-button type="primary" @click="addOutlink" 
+      v-permission="permissionBtn.outlinkConfigPermission.outlinkListConfig_add">添加菜单</el-button>
+    </div>
+    <el-table :data="outlinkData" border @sort-change="sortChange">
+      <el-table-column label="菜单名称" prop="Title" align="center">
+        <template slot-scope="{ row }">
+          {{ row.Title }}
+        </template>
+      </el-table-column>
+      <el-table-column label="页面链接" prop="Url" align="center">
+        <template slot-scope="{ row }">
+          {{ row.Url }}
+        </template>
+      </el-table-column>
+      <el-table-column label="创建时间" prop="CreateTime" align="center" sortable >
+        <template slot-scope="{ row }">
+          {{ row.CreateTime }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center">
+        <template slot-scope="{ row }">
+          <span class="table-button" @click="editOutlink(row)" 
+          v-permission="permissionBtn.outlinkConfigPermission.outlinkListConfig_edit">编辑</span>
+          <span class="table-button" style="color: #C54322;" @click="deleteOutlink(row)"
+          v-permission="permissionBtn.outlinkConfigPermission.outlinkListConfig_del">删除</span>
+        </template>
+      </el-table-column>
+      <div slot="empty" style="line-height: 44px; margin: 60px 0; color: #999">
+        <tableNoData text="暂无数据" size="mini"/>
+      </div>
+    </el-table>
+    <m-page
+      :page_no="queryParams.CurrentIndex"
+      :pageSize="queryParams.PageSize"
+      :total="total"
+      @handleCurrentChange="pageChange"
+      style="margin-top: 20px;"
+    />
+    <el-dialog 
+    :append-to-body="true" 
+    :visible.sync="addOutlinkShow" 
+    width="600px" 
+    :title="dialogTitle"
+    :close-on-click-modal="false"
+    center @close="resetForm">
+      <div class="form-box">
+        <el-form
+        :model="outlinkForm"
+        ref="outlinkFormRef"
+        label-width="90px">
+          <el-form-item prop="Title" label="菜单名称" :rules="{required:true,message:'菜单名称不能为空',trigger:'blur'}">
+              <el-input v-model="outlinkForm.Title" placeholder="请输入菜单名称" style="width: 295px;"></el-input>
+          </el-form-item>
+          <el-form-item prop="Url" label="页面链接" :rules="{required:true,message:'URL不能为空',trigger:'blur'}">
+              <el-input v-model="outlinkForm.Url" placeholder="请输入URL" style="width: 295px;"></el-input>
+          </el-form-item>
+          <div class="form-box-buttons-zone">
+            <el-button style="width: 120px;height: 40px;" @click="addOutlinkShow=false">取消</el-button>
+            <el-button type="primary" @click="addOutlinkSave" style="margin-left:30px;width: 120px;height: 40px;">确定</el-button>
+          </div>
+        </el-form>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {outlinkConfigInterence} from "@/api/modules/etaBaseConfigApi.js"
+import mPage from '@/components/mPage.vue';
+
+  export default {
+    name:"outlinkListConfig",
+    components:{mPage},
+    data() {
+      return {
+        outlinkData:[],
+        queryParams:{
+          CurrentIndex:1,
+          PageSize:10,
+          SortParam:'create_time',
+          SortType:''
+        },
+        total:0,
+        dialogTitle:"",
+        addOutlinkShow:false,
+        outlinkForm:{
+          Title:"",
+          Url:""
+        }
+      }
+    },
+    created(){
+      this.getOutlinkData()
+    },
+    methods: {
+      getOutlinkData(){
+        if(!this.permissionBtn.checkPermissionBtn(this.permissionBtn.outlinkConfigPermission.outlinkListConfig_list)) return 
+        outlinkConfigInterence.getOutlinkList(this.queryParams).then(res=>{
+          if(res.Ret == 200){
+            this.outlinkData = res.Data.List || []
+            this.total =res.Data.Paging?res.Data.Paging.Totals || 0:0
+          }
+        })
+      },
+      pageChange(page_no){
+        this.queryParams.CurrentIndex=page_no
+        this.getOutlinkData()
+      },
+      sortChange({ prop,order }){
+        // console.log(prop,order);
+        this.queryParams.SortType = order?order=="descending"?"desc":"asc":""
+        this.getOutlinkData()
+      },
+      addOutlink(){
+        this.dialogTitle="添加菜单"
+        this.addOutlinkShow=true
+      },
+      editOutlink(item){
+        this.outlinkForm=item
+        this.dialogTitle="编辑菜单"
+        this.addOutlinkShow=true
+      },
+      resetForm(){
+        this.outlinkForm={
+          Title:"",
+          Url:""
+        }
+        this.$refs.outlinkFormRef.clearValidate()
+      },
+      addOutlinkSave(){
+        this.$refs.outlinkFormRef.validate((valid)=>{
+          if(valid){
+            outlinkConfigInterence.outlinkSave(this.outlinkForm).then(res=>{
+              if(res.Ret == 200){
+                this.$message.success(`${this.dialogTitle}成功`)
+                this.addOutlinkShow=false
+                this.getOutlinkData()
+              }
+            })
+          }
+        })
+      },
+      deleteOutlink(item){
+        this.$confirm("删除后不可恢复,确认删除吗?", "提示", {
+          type: "warning"
+        }).then(() => {
+          outlinkConfigInterence.outlinkDelete({Id:item.Id}).then(res=>{
+            if(res.Ret == 200){
+              this.$message.success("删除菜单成功")
+              this.getOutlinkData()
+            }
+          })
+        }).catch(() => {});
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .outlink-list-config{
+    min-height: calc(100vh - 110px);
+    height:calc(100vh - 110px);
+    background-color: white;
+    border: solid 1px #DCDFE6;
+    box-sizing: border-box;
+    padding: 30px;
+    .outlink-top-button-zone{
+      margin-bottom: 30px;
+    }
+    .table-button{
+      font-size: 14px;
+      cursor: pointer;
+      color: #0052D9;
+      margin-right: 8px;
+      &:last-child{
+        margin-right: 0;
+      }
+    }
+  }
+  .form-box{
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding-top: 30px;
+      .form-box-buttons-zone{
+        text-align:center;
+        margin-bottom:35px;
+        margin-top:120px;
+      }
+    }
+</style>

+ 11 - 6
src/views/system_manage/roleManage.vue

@@ -4,8 +4,8 @@
 			<div>
 				<el-button v-permission="permissionBtn.sysDepartPermission.sysRole_addRole"
 					type="primary" @click="addRole" style="marginRight:14px;">添加角色</el-button>
-				<el-button v-permission="permissionBtn.sysDepartPermission.sysRole_settingAuth"
-					type="primary" @click="setAuth">设置权限</el-button>
+				<!-- <el-button v-permission="permissionBtn.sysDepartPermission.sysRole_settingAuth"
+					type="primary" @click="setAuth">设置权限</el-button> -->
 			</div>
 			<el-input
 				placeholder="角色搜索"
@@ -44,9 +44,12 @@
 				<el-table-column label="操作" align="center">
 					<template slot-scope="scope">
 						<div style="color:#4099ef; font-size:24px;">
-							<span v-permission="permissionBtn.sysDepartPermission.sysRole_settingAuth"
-								class="editsty" @click.stop="getAuthDetail(scope.row)" style="marginRight:20px;">查看权限</span>
-							<!-- <span class="editsty" @click.stop="editRole(scope.row)" style="marginRight:20px;">编辑</span> -->
+							<!-- <span v-permission="permissionBtn.sysDepartPermission.sysRole_settingAuth"
+								class="editsty" @click.stop="getAuthDetail(scope.row)" style="marginRight:20px;">查看权限</span> -->
+								<span v-permission="permissionBtn.sysDepartPermission.sysRole_settingAuth"
+									class="editsty" @click.stop="getAuthDetail(scope.row)" style="marginRight:20px;">设置权限</span>
+							<span v-permission="permissionBtn.sysDepartPermission.sysRole_addRole"
+								class="editsty" @click.stop="editRole(scope.row)" style="marginRight:20px;">编辑</span>
 							<span v-permission="permissionBtn.sysDepartPermission.sysRole_del"
 								class="deletesty" @click.stop="delRole(scope.row)">删除</span>
 						</div>
@@ -216,7 +219,8 @@ export default {
 					}else {
 						departInterence.editRole({
 							RoleId:Number(this.roleForm.role_id),
-							RoleName:this.roleForm.name
+							RoleName:this.roleForm.name,
+							RoleType:this.roleForm.roleType
 						}).then(res =>{
 							if(res.Ret === 200) {
 								this.$message.success(res.Msg);
@@ -235,6 +239,7 @@ export default {
 				title:'编辑角色',
 				name:item.RoleName,
 				role_id:item.RoleId,
+				roleType:item.RoleType
 			}
 		},
 		/*  删除角色*/

+ 4 - 2
src/vuex/index.js

@@ -27,8 +27,10 @@ const state = {
   breadSelfName: '',//面包屑自定义当前页面name
 
   dynamicOutLinks:{},//外部动态链接配置 iframe链接 研报详情分享link
-  businessCode:"", //商家code
-  TRIAL_CODE:"e069d0a024e09636a1225e72a964b4b6", //试用平台的 商家code
+  // 是否执行过页面监听
+  hasDoPageListening:false,
+  // 是否有 试用用户行为权限
+  hasTrialUserPermisson:false,
 };
 
 export default {

+ 10 - 0
src/vuex/modules/permissionButton.js

@@ -1,4 +1,6 @@
 import {departInterence} from '@/api/api.js';
+import{doPageEventListener}from'@/utils/TimeOnPage.js';
+
 // 权限配置按钮
 const permissionButtons = {
     state:()=>({
@@ -15,6 +17,14 @@ const permissionButtons = {
                 departInterence.getRoleBtnAuth().then(res=>{
                     const buttons = res.Data || []
                     commit('SET_PERMISSION_BUTTONS',buttons)
+                    
+                    let trialUserPermisson = !!buttons.find(item => item.ButtonCode =="trialUserAction")
+                    commit('SET_ETRIAL',trialUserPermisson)
+
+                    if(!this.state.hasDoPageListening && trialUserPermisson){
+                        //有ETA用户行为记录权限 而且没有执行过页面监听
+                        doPageEventListener()
+                    }
                     resolve('获取权限按钮成功')
                 })
 /*                 const buttons = [

+ 6 - 0
src/vuex/mutations.js

@@ -30,6 +30,12 @@ const mutations = {
     setting.dynamicOutLinks = state.dynamicOutLinks;
 
   },
+  SET_PAGE_EVENT_LISTENER:(state,flag)=>{
+    state.hasDoPageListening = flag
+  },
+  SET_ETRIAL(state,flag){
+    state.hasTrialUserPermisson = flag
+  },
   //设置商家code
   SET_BUSINESS_CODE(state,code) {
     state.businessCode = code || ""

Some files were not shown because too many files changed in this diff