浏览代码

v1.7_EDB基础指标上线

jwyu 1 年之前
父节点
当前提交
956b0b3fb2
共有 55 个文件被更改,包括 5121 次插入84 次删除
  1. 1 1
      index.html
  2. 2 0
      package.json
  3. 18 0
      src/api/common.js
  4. 274 0
      src/api/dataEDB.js
  5. 15 0
      src/api/dataPredictEDB.js
  6. 3 1
      src/api/index.js
  7. 二进制
      src/assets/imgs/chartETA/icon_chartETA_logo.png
  8. 二进制
      src/assets/imgs/dataEDB/icon_edit.png
  9. 二进制
      src/assets/imgs/dataEDB/icon_menu.png
  10. 二进制
      src/assets/imgs/dataEDB/icon_opt.png
  11. 二进制
      src/assets/imgs/myETA/icon_myETA_logo.png
  12. 二进制
      src/assets/imgs/ppt/ppt_icon_en.png
  13. 二进制
      src/assets/imgs/ppt/ppt_icon_zh.png
  14. 二进制
      src/assets/imgs/report/report_icon.png
  15. 二进制
      src/assets/imgs/report/report_icon_en.png
  16. 二进制
      src/assets/imgs/tabbar/home-s.png
  17. 二进制
      src/assets/imgs/tabbar/home.png
  18. 二进制
      src/assets/imgs/tabbar/icon_EDB.png
  19. 二进制
      src/assets/imgs/tabbar/icon_PPT.png
  20. 二进制
      src/assets/imgs/tabbar/icon_chart.png
  21. 二进制
      src/assets/imgs/tabbar/icon_dataSource.png
  22. 二进制
      src/assets/imgs/tabbar/icon_myChart.png
  23. 二进制
      src/assets/imgs/tabbar/icon_preEDB.png
  24. 二进制
      src/assets/imgs/tabbar/icon_report.png
  25. 二进制
      src/assets/imgs/tabbar/icon_table.png
  26. 二进制
      src/assets/imgs/tabbar/user-s.png
  27. 二进制
      src/assets/imgs/tabbar/user.png
  28. 32 2
      src/assets/styles/common.scss
  29. 2 1
      src/assets/styles/var.scss
  30. 38 0
      src/hooks/chart/config.js
  31. 5 4
      src/hooks/common.js
  32. 35 0
      src/hooks/edb/useCopyEdbData.js
  33. 1 0
      src/layouts/Index.vue
  34. 3 0
      src/main.js
  35. 59 0
      src/router/dataEDB.js
  36. 3 0
      src/router/index.js
  37. 324 0
      src/views/dataEDB/AddBaseEDB.vue
  38. 346 0
      src/views/dataEDB/Detail.vue
  39. 545 0
      src/views/dataEDB/Index.vue
  40. 191 0
      src/views/dataEDB/RelationChart.vue
  41. 157 0
      src/views/dataEDB/RelationEDB.vue
  42. 165 0
      src/views/dataEDB/SearchList.vue
  43. 1035 0
      src/views/dataEDB/components/EDBChartDetail.vue
  44. 522 0
      src/views/dataEDB/components/EDBClassify.vue
  45. 237 0
      src/views/dataEDB/components/EDBDataDetail.vue
  46. 124 0
      src/views/dataEDB/components/EDBHistory.vue
  47. 291 0
      src/views/dataEDB/components/EditBaseEDB.vue
  48. 118 0
      src/views/dataEDB/components/SetEDBInfoEn.vue
  49. 222 0
      src/views/dataEDB/components/SetEDBNewData.vue
  50. 63 0
      src/views/dataEDB/hooks/useEDBDelete.js
  51. 20 0
      src/views/dataEDB/util/config.js
  52. 29 0
      src/views/myETA/ChartDetail.vue
  53. 14 1
      src/views/myETA/components/EDBInfo.vue
  54. 222 69
      src/views/tabbar/Home.vue
  55. 5 5
      src/views/tabbar/Index.vue

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" type="image/x-icon" href="/fa.ico"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
-    <title>移动ETA</title>
+    <title>ETA投研平台</title>
     <link href='/froala_editor.pkgd.min.css' rel='stylesheet' type='text/css' />
   </head>
   <body>

+ 2 - 0
package.json

@@ -32,6 +32,8 @@
     "vconsole": "^3.15.0",
     "vue": "^3.2.47",
     "vue-router": "^4.1.6",
+    "vue3-clipboard": "^1.0.0",
+    "vue3-tree-org": "^4.2.2",
     "vuedraggable": "^4.1.0"
   },
   "devDependencies": {

+ 18 - 0
src/api/common.js

@@ -32,4 +32,22 @@ export function apiGetOSSSign(){
  */
 export function apiGetWXQRCodeImg(params){
     return post('/report/getSunCode',params)
+}
+
+/**
+ * 设置系统配置项
+ * @param ConfigCode edb指标库语言edb_language;预测指标库语言predict_edb_language
+ *                   ETA图库语言chart_language
+ * @param ConfigValue 中文CN 英文EN
+ */
+export function apiCommonSetSysConfig(params){
+    return post('/system/sysuser/config/set',params)
+}
+
+/**
+ * 获取系统中模块语言设置
+ * @param SourceKey edb指标库语言edb_language;预测指标库语言predict_edb_language;ETA图库语言chart_language
+ */
+export function apiGetLanguageConfig(params){
+    return get('/system/config/language',params)
 }

+ 274 - 0
src/api/dataEDB.js

@@ -0,0 +1,274 @@
+//ETA指标库
+import { get,post } from "./index";
+
+export default{
+    /**
+     * ETA指标列表
+     */
+    edbChartList(params){
+        return get('/datamanage/edb_info/chart/list',params)
+    },
+
+    /**
+     * ETA指标搜索
+     * @param KeyWord
+     * @param CurrentIndex
+     * @param PageSize
+     */
+    edbChartSearchList(params){
+        return get('/datamanage/edb_info/filter_by_es',params)
+    },
+
+    /**
+     * ETA指标库分类列表
+     */
+    edbClassifyList(){
+        return get('/datamanage/classify/items/v3',{})
+    },
+
+    /**
+     * 新增ETA指标库分类
+     * @param ClassifyName
+     * @param Level
+     * @param ParentId
+     */
+    edbClassifyAdd(params){
+        return post('/datamanage/classify/add',params)
+    },
+
+    /**
+     * 编辑ETA指标库分类
+     * @param ClassifyName
+     * @param ClassifyId
+     */
+    edbClassifyEdit(params){
+        return post('/datamanage/classify/edit',params)
+    },
+
+    /**
+     * 删除ETA指标库分类检测
+     * @param ClassifyId
+     * @param EdbInfoId
+     */
+    edbClassifyDeleteCheck(params){
+        return post('/datamanage/classify/delete/check',params)
+    },
+
+    /**
+     * 删除ETA指标库分类(包含指标的删除)
+     * @param ClassifyId
+     * @param EdbInfoId
+     */
+    edbClassifyDelete(params){
+        return post('/datamanage/classify/delete',params)
+    },
+
+    /**
+     * 移动ETA指标库分类
+     * @param ClassifyId
+     * @param ParentClassifyId
+     * @param PrevClassifyId
+     * @param NextClassifyId
+     */
+    edbClassifyMove(params){
+        return post('/datamanage/edb_classify/move',params)
+    },
+
+    /**
+     * 移动ETA指标
+     * @param ClassifyId 移动到哪个分类
+     * @param EdbInfoId
+     * @param PrevEdbInfoId
+     * @param NextEdbInfoId
+     */
+    edbMove(params){
+        return post('/datamanage/edb_info/move',params)
+    },
+
+    /**
+     * 基础指标详情
+     * @param EdbInfoId
+     */
+    getBaseEdbInfo(params){
+        return get('/datamanage/edb_info/detail',params)
+    },
+
+    /**
+     * 基础指标编辑
+     * @param EdbInfoId
+     * @param ClassifyId
+     * @param EdbName
+     * @param Frequency
+     * @param Unit
+     */
+    editBaseEdbInfo(params){
+        return post('/datamanage/edb_info/edit',params)
+    },
+
+    /**
+     * 指标关联的图表数据
+     * @param EdbInfoId
+     * @param CurrentIndex
+     * @param PageSize
+     */
+    edbRelationChartList(params){
+        return get('/datamanage/edb_info/relation/chart_list',params)
+    },
+
+    /**
+     * 指标数据列表
+     * @param PageSize
+     * @param CurrentIndex
+     * @param EdbInfoId
+     * @param KeyWord
+     */
+    edbDataList(params){
+        return get('/datamanage/edb_info/list',params)
+    },
+
+    /**
+     * ETA指标引用的计算指标
+     * @param EdbInfoId
+     * @param CurrentIndex
+     * @param PageSize
+     */
+    edbRelationEdbList(params){
+        return get('/datamanage/edb_info/relation/edbinfo_list',params)
+    },
+
+    /**
+     * 指标曲线图的数据
+     * @param EdbInfoId
+     * @param DateType
+     * @param StartDate
+     * @param EndDate
+     */
+    edbLineChartData(params){
+        return get('/datamanage/edb_info/data',params)
+    },
+
+    /**
+     * 指标季节性图的数据
+     * @param EdbInfoId
+     * @param Calendar
+     * @param StartDate
+     * @param EndDate
+     */
+    edbSeasonChartData(params){
+        return get('/datamanage/edb_info/data/seasonal',params)
+    },
+
+    /**
+     * 指标同比图的数据
+     * @param EdbInfoId
+     * @param DateType
+     * @param StartDate
+     * @param EndDate
+     */
+    edbTBChartData(params){
+        return get('/datamanage/edb_info/data/tb',params)
+    },
+
+    /**
+     * 计算指标详情
+     * @param EdbInfoId
+     */
+    getCalculateEdbInfo(params){
+        return get('/datamanage/edb_info/calculate/detail',params)
+    },
+
+    /**
+     * 指标刷新
+     * @param EdbInfoId
+     */
+    edbRefresh(params){
+        return get('/datamanage/edb_info/refresh',params)
+    },
+
+    /**
+     * 设置指标英文信息
+     * @param EdbInfoId
+     * @param EdbNameEn
+     * @param UnitEn
+     */
+    edbInfoEnEdit(params){
+        return post('/datamanage/edb_info/en/edit',params)
+    },
+
+    /**
+     * 设置指标最新值
+     * @param EdbInfoId
+     * @param Date
+     * @param Value
+     */
+    edbNewDataEdit(params){
+        return post('/datamanage/edb_info/insert_config/set',params)
+    },
+
+    /**
+     * 基础指标全部刷新
+     * @param EdbInfoId
+     */
+    refreshBaseEDBData(params){
+        return get('/datamanage/edb_info/refresh/all',params)
+    },
+
+    /**
+     * 计算指标重新计算
+     * @param EdbInfoId
+     */
+    calculateEDBReset(params){
+        return post('/datamanage/edb_info/calculate/batch/reset',params)
+    },
+
+    /**
+     * 获取指标历史生成记录
+     * @param EdbInfoId
+     */
+    edbCreateHistory(params){
+        return get('/datamanage/edb_info/trace',params)
+    },
+
+    /**
+     * 保存指标图表信息
+     * @param EdbInfoId
+     * @param MaxValue 上限
+     * @param MinValue 下限
+     */
+    edbChartInfoSave(params){
+        return post('/datamanage/edb_info/modify',params)
+    },
+
+    /**
+     * 指标搜索
+     * @param Source 数据来源 1:同花顺,2:wind
+     * @param EdbCode
+     * @param CompanyCode
+     */
+    edbSearch(params){
+        return get('/datamanage/edb_info/search',params)
+    },
+
+    /**
+     * 新增基础指标
+     * @param EdbCode
+     * @param EndDate
+     * @param StartDate
+     * @param Source
+     * @param EdbName
+     * @param ClassifyId
+     * @param Frequency
+     * @param Unit
+     */
+    AddBaseEdbInfo(params){
+        return post('/datamanage/edb_info/add',params)
+    },
+
+    /**
+     * 获取指标来源集合
+     * @param IsBase
+     */
+    getEDBSourceOpts(params){
+        return get('/datamanage/edb_source/list',params)
+    }
+}

+ 15 - 0
src/api/dataPredictEDB.js

@@ -0,0 +1,15 @@
+//预测指标库
+import { get,post } from "./index";
+
+export default{
+    /**
+     * 预测指标数据列表
+     * @param PageSize
+     * @param CurrentIndex
+     * @param EdbInfoId
+     * @param KeyWord
+     */
+    edbDataList(params){
+        return get('/datamanage/predict_edb_info/list',params)
+    }
+}

+ 3 - 1
src/api/index.js

@@ -14,7 +14,9 @@ const LOADINGWHITELIST=[
   '/public/wechat_warning',
   '/report/saveReportContent',
   '/report/editDayWeekChapter',
-  '/english_report/saveReportContent'
+  '/english_report/saveReportContent',
+  '/datamanage/edb_info/refresh',
+  '/datamanage/edb_info/refresh/all'
 ]
 // 请求数
 let LOADINGCOUNT = 0;

二进制
src/assets/imgs/chartETA/icon_chartETA_logo.png


二进制
src/assets/imgs/dataEDB/icon_edit.png


二进制
src/assets/imgs/dataEDB/icon_menu.png


二进制
src/assets/imgs/dataEDB/icon_opt.png


二进制
src/assets/imgs/myETA/icon_myETA_logo.png


二进制
src/assets/imgs/ppt/ppt_icon_en.png


二进制
src/assets/imgs/ppt/ppt_icon_zh.png


二进制
src/assets/imgs/report/report_icon.png


二进制
src/assets/imgs/report/report_icon_en.png


二进制
src/assets/imgs/tabbar/home-s.png


二进制
src/assets/imgs/tabbar/home.png


二进制
src/assets/imgs/tabbar/icon_EDB.png


二进制
src/assets/imgs/tabbar/icon_PPT.png


二进制
src/assets/imgs/tabbar/icon_chart.png


二进制
src/assets/imgs/tabbar/icon_dataSource.png


二进制
src/assets/imgs/tabbar/icon_myChart.png


二进制
src/assets/imgs/tabbar/icon_preEDB.png


二进制
src/assets/imgs/tabbar/icon_report.png


二进制
src/assets/imgs/tabbar/icon_table.png


二进制
src/assets/imgs/tabbar/user-s.png


二进制
src/assets/imgs/tabbar/user.png


+ 32 - 2
src/assets/styles/common.scss

@@ -18,7 +18,7 @@ html,body,#app{
     }
 }
 
-div{
+div,ul,li{
     box-sizing: border-box;
 }
 
@@ -126,4 +126,34 @@ img {
 .fr-second-toolbar {
     display: none !important;
 }
-a[href="https://froala.com/wysiwyg-editor"], a[href="https://www.froala.com/wysiwyg-editor?k=u"]{ border:1px solid #eaeaea; background:#fff !important; color:#ccc !important; }
+a[href="https://froala.com/wysiwyg-editor"], a[href="https://www.froala.com/wysiwyg-editor?k=u"]{ border:1px solid #eaeaea; background:#fff !important; color:#ccc !important; }
+
+
+.rename-wrap{
+    padding:48px;
+    input{
+        padding: 24px 32px;
+        border-radius: 12px;
+        background-color: #F6F6F6;
+        width: 100%;
+    }
+    .label{
+        color: #666666;
+        margin-bottom: 32px;
+        text-align: center;
+    }
+}
+@media screen and (min-width:650px){
+    .rename-wrap{
+        padding:24px;
+        input{
+            padding: 12px 16px;
+            border-radius: 6px;
+            background-color: #F6F6F6;
+            width: 100%;
+        }
+        .label{
+            margin-bottom: 16px;
+        }
+    }
+}

+ 2 - 1
src/assets/styles/var.scss

@@ -8,4 +8,5 @@ $theme-red:#C54322;
 $theme-warning:#E37318;
 $media-width:650px;
 $page-padding:34px;//页面边距
-$page-bg-grey:#F6F6F6;//灰色背景
+$page-bg-grey:#F6F6F6;//灰色背景
+$box-shadow:0px 4px 12px 0px rgba(0, 0, 0, 0.05);

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

@@ -107,6 +107,44 @@ export const chartDefaultOpts={
 	rangeSelector: {
 		enabled: false,
 	},
+	xAxis: {
+		tickPosition: 'inside',
+		lineColor: '#bfbfbf',
+    	tickColor: '#bfbfbf',
+		tickLength:5,
+		type: 'datetime',
+		ordinal: false,
+		dateTimeLabelFormats: {
+			day: '%y/%m',
+			week: '%y/%m',
+			month: '%y/%m',
+			year: '%y/%m',
+		}
+		// gridLineWidth:0
+	}
+}
+
+/* 季节性图配置 */
+export const seasonOptions = {
+	//默认颜色配置
+	colors:['#4B0082','#7FFFAA','#FF4500','#808000','#EEE8AA','#849EC1','#8A4294','#578B5A','#FDA8C7','#53B3FF','#999999','#000000','#FFDF0C','#FF0000','#0033FF'],
+	yAxis: {
+		lineWidth: 1,
+		lineColor: '#bfbfbf',
+		tickColor: '#bfbfbf',
+		offset: 0,
+		opposite: false,
+		reversed: false,
+		visible: true,
+		gridLineWidth: 0,
+		tickWidth: 1,
+		tickLength:5,
+		tickPosition: 'inside',
+		endOnTick: false,
+		startOnTick: false,
+		showLastLabel: true, //显示最后刻度值
+		tickPixelInterval: 50
+	}
 }
 
 // 散点x轴

+ 5 - 4
src/hooks/common.js

@@ -58,16 +58,17 @@ export function transfImgTobase64(url) {
 /**
  * 设置剪切板
  * @param text 文本
+ * @param msg 提示文案
  */
-export async function setClipboardData(text){
+export async function setClipboardData(text,msg){
     if(navigator.clipboard&&window.isSecureContext){
         try{
            await navigator.clipboard.writeText(text)
-           showToast({message:'复制链接成功',type:'success'})
+           showToast({message:msg||'复制链接成功',type:'success'})
        }catch(err){
            console.log(err);
            throw new Error(JSON.stringify(err)) 
-           showToast({message:'复制链接失败',type:'fail'})
+           showToast({message:msg||'复制失败',type:'fail'})
        }
    }else{
        const input = document.createElement('input')
@@ -77,6 +78,6 @@ export async function setClipboardData(text){
        input.select();
        document.execCommand('copy');
        document.body.removeChild(input);
-       showToast({message:'复制链接成功',type:'success'})
+       showToast({message:msg||'复制链接成功',type:'success'})
    }
 }

+ 35 - 0
src/hooks/edb/useCopyEdbData.js

@@ -0,0 +1,35 @@
+// 复制指标数据
+import apiDataEDB from '@/api/dataEDB'
+import apiDataPredictEDB from '@/api/dataPredictEDB'
+import { showToast } from 'vant'
+import { copyText } from 'vue3-clipboard'
+
+export function useCopyEdbData(){
+
+    async function copyData(e){
+        const params={
+            PageSize: 100000,
+            CurrentIndex: 1,
+            EdbInfoId:e.EdbInfoId
+        }
+        const res=params.EdbInfoCategoryType===1?await apiDataPredictEDB.edbDataList(params):await apiDataEDB.edbDataList(params)
+        if(res.Ret===200){
+            const arr=res.Data.Item.DataList || [];
+            let str = '日期\t 值\n';
+            arr.forEach((item) => (str += `${item.DataTime}\t${item.Value}\n`));
+            copyText(str,undefined,(error,event)=>{
+                if(error){
+                    showToast('复制失败')
+                    console.log('复制数据失败',error);
+                    throw new Error(error)
+                }else{
+                    showToast('复制成功')
+                }
+            })
+        }
+    }
+
+    return {
+        copyData
+    }
+}

+ 1 - 0
src/layouts/Index.vue

@@ -144,6 +144,7 @@ function goBack(){
             font-size: 16px;
             display: flex;
             align-items: center;
+            cursor: pointer;
             &::before{
                 content: '';
                 display: block;

+ 3 - 0
src/main.js

@@ -10,6 +10,8 @@ import '@vant/touch-emulator';
 import {RegisterDirective} from '@/directives/Index.js'
 import {setupStore} from '@/store'
 import VConsole from 'vconsole';
+import vue3TreeOrg from 'vue3-tree-org';
+import "vue3-tree-org/lib/vue3-tree-org.css";
 
 
 if(import.meta.env.MODE==='test'){
@@ -24,5 +26,6 @@ reportErr(app)//设置全局错误上报
 registerVant(app)
 RegisterDirective(app)
 setupStore(app)
+app.use(vue3TreeOrg)
 app.use(router)
 app.mount('#app')

+ 59 - 0
src/router/dataEDB.js

@@ -0,0 +1,59 @@
+// ETA指标库模块
+export const dataEDBRoutes=[
+    {
+        path:"/dataEDB/index",
+        name:"DataEDBIndex",
+        component: () => import("@/views/dataEDB/Index.vue"),
+        meta: { 
+            title: "ETA指标库",
+            keepAlive:true,
+            hasBackTop:true,
+        },
+    },
+    {
+        path:"/dataEDB/relationChart",
+        name:"DataEDBRelationChart",
+        component: () => import("@/views/dataEDB/RelationChart.vue"),
+        meta: { 
+            title: "关联图表",
+            keepAlive:false,
+            hasBackTop:true,
+        },
+    },
+    {
+        path:"/dataEDB/relationEDB",
+        name:"DataEDBRelationEDB",
+        component: () => import("@/views/dataEDB/RelationEDB.vue"),
+        meta: { 
+            title: "关联指标",
+            keepAlive:false,
+            hasBackTop:true,
+        },
+    },
+    {
+        path:"/dataEDB/detail",
+        name:"DataEDBDetail",
+        component: () => import("@/views/dataEDB/Detail.vue"),
+        meta: { 
+            title: "ETA指标详情"
+        },
+    },
+    {
+        path:"/dataEDB/search",
+        name:"DataEDBSearch",
+        component: () => import("@/views/dataEDB/SearchList.vue"),
+        meta: { 
+            title: "ETA指标库",
+            keepAlive:true,
+            hasBackTop:true,
+        },
+    },
+    {
+        path:"/dataEDB/addbaseEDB",
+        name:"DataEDBAddBaseEDB",
+        component: () => import("@/views/dataEDB/AddBaseEDB.vue"),
+        meta: { 
+            title: "添加指标"
+        },
+    },
+]

+ 3 - 0
src/router/index.js

@@ -17,6 +17,7 @@ import {myETARoutes} from './myETA'
 import {reportRoutes} from './report'
 import {reportEnRoutes} from './reportEn'
 import {chartETARoutes} from './chartETA'
+import {dataEDBRoutes} from './dataEDB'
 
 const routes = [
   	{
@@ -67,6 +68,8 @@ const routes = [
 			...reportEnRoutes,
             //ETA图库模块
             ...chartETARoutes,
+			//ETA指标库模块
+			...dataEDBRoutes,
 		]
 	},
 	

+ 324 - 0
src/views/dataEDB/AddBaseEDB.vue

@@ -0,0 +1,324 @@
+<script setup name="DataEDBAddBaseEDB">
+import {ref} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import { showToast } from 'vant'
+import EditBaseEDB from './components/EditBaseEDB.vue'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+
+//显示目录
+function getClassifyName(data){
+    const arr=data||[]
+    let str=''
+    arr.reverse().map((item) => str += item.ClassifyName + '/')
+    return str
+}
+
+// 数据来源
+const showSelectDataSource=ref(false)
+const edbSourceOpts=ref([])
+const dataSourceText=ref('')
+const dataSourceVal=ref(0)
+async function getEDBSourceOpts(){
+    const res=await apiDataEDB.getEDBSourceOpts({IsBase:1})
+    if(res.Ret===200){
+        edbSourceOpts.value=res.Data||[]
+        dataSourceText.value=edbSourceOpts.value[0]?.SourceName
+        dataSourceVal.value=edbSourceOpts.value[0]?.EdbSourceId
+    }
+}
+getEDBSourceOpts()
+function onConfirmDataSource(e){
+    console.log(e);
+    dataSourceText.value=e.selectedOptions[0].SourceName
+    dataSourceVal.value=e.selectedOptions[0].EdbSourceId
+    showSelectDataSource.value=false
+}
+
+// 指标名称/ID
+const searchEDBTxt=ref('')
+// 公司ID
+const searchCompanyTxt=ref('')
+
+// 搜索指标
+const result=ref(null)
+async function getEDBInfo(){
+    const res=await apiDataEDB.edbSearch({
+        Source:dataSourceVal.value,
+        EdbCode:searchEDBTxt.value,
+        CompanyCode:searchCompanyTxt.value
+    })
+    if(res.Ret===200){
+        result.value=res.Data
+    }else{
+        result.value=null
+    }
+
+}
+
+function onSearch(){
+    if(!searchEDBTxt.value){
+        showToast('请输入指标ID')
+        return
+    }
+    if(dataSourceText.value==='彭博财务'&&!searchCompanyTxt.value){
+        showToast('请输入公司ID')
+        return
+    }
+    getEDBInfo()
+}
+
+// 下一步指标基本信息填写
+const showEditBaseEDB=ref(false)
+const baseInfo=ref({})
+function handleShowEditBaseEDB(){
+    let obj={
+        EdbCode: result.value.SearchItem.EdbCode,
+		EndDate: result.value.SearchItem.EndDate,
+		StartDate: result.value.SearchItem.StartDate,
+		Source: dataSourceVal.value,
+    }
+    //隆众指标和手工指标、交易所等将名称 频度 单位带到下一步
+    if([9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 26,38,41,57,60,71].includes(dataSourceVal.value)){
+        obj={
+            ...obj,
+            edb_name: result.value.SearchItem.EdbName,
+			unit: result.value.SearchItem.Unit,
+			frequency: result.value.SearchItem.Frequency,
+        }
+    }
+    baseInfo.value=obj
+    showEditBaseEDB.value=true
+}
+function handleEditBaseEdbSuccess(){
+    setTimeout(() => {
+        router.back()
+    }, 1500);
+}
+
+//清空状态
+function handleClearPage(){
+    searchEDBTxt.value=''
+    searchCompanyTxt.value=''
+    result.value=null
+}
+
+</script>
+
+<template>
+    <div class="add-baseEDB-page">
+        <van-cell title="数据来源" is-link :value="dataSourceText" @click="showSelectDataSource=true"/>
+        <div class="search-box">
+            <van-search
+                v-model="searchEDBTxt"
+                show-action
+                shape="round"
+                placeholder="指标ID/指标名称"
+                @clear="searchEDBTxt=''"
+                @search="onSearch"
+            >
+                <template #action>
+                    <span class="right-btn" @click="onSearch">查询</span>
+                </template>
+            </van-search>
+        </div>
+        <div class="search-box" style="padding-top:0" v-if="dataSourceText==='彭博财务'">
+            <van-search
+                v-model="searchCompanyTxt"
+                show-action
+                shape="round"
+                placeholder="公司ID"
+                @clear="searchCompanyTxt=''"
+                @search="onSearch"
+            >
+                <template #action>
+                    <span class="right-btn" @click="onSearch">查询</span>
+                </template>
+            </van-search>
+        </div>
+
+        <div class="warn_txt" v-if="result?.Status===1">
+            该数据已存在数据库,名称为:{{result.SearchItem.EdbName}},目录为:{{ getClassifyName(result.ClassifyList) }},如需重新添加,请删除原指标
+        </div>
+        <div class="warn_txt" v-if="result?.Status===3">
+            该数据已存在数据库,名称为:{{result.SearchItem.EdbName}},目录为:{{ getClassifyName(result.ClassifyList) }}
+        </div>
+
+        <div class="no-auth" v-if="result?.Status===3">您当前暂无权限查看该指标,如需查看,请联系管理员</div>
+        <template v-else>
+            <template v-if="result?.Status===1||result?.SearchItem.DataList?.length">
+                <van-cell title="指标ID" :value="result?.SearchItem.EdbCode" />
+                <van-cell title="起始时间" :value="result?.SearchItem.StartDate" />
+                <van-cell title="终止时间" :value="result?.SearchItem.EndDate"/>
+                <ul class="data-value-wrap">
+                    <li class="item" style="font-weight:bold">时间</li>
+                    <li class="item" style="font-weight:bold">值</li>
+                    <template v-if="result?.SearchItem.DataList">
+                        <template v-for="item,index in result?.SearchItem.DataList" :key="index">
+                            <li class="item">{{item.DataTime}}</li>
+                            <li class="item"><span class="val-box">{{item.Value}}</span></li>
+                        </template>
+                    </template>
+                    <div class="data-empty" v-else>
+                        <img src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+                        <p>暂无对应的数据</p>
+                    </div>
+                </ul>
+            </template>
+
+            <div class="search-empty-wrap" v-else>
+                <img src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+                <p>未搜索到该指标</p>
+            </div>
+        </template>
+
+        <div class="btns-wrap">
+            <van-button block type="primary" v-if="result?.Status===2" :disabled="!result?.SearchItem.DataList?.length" @click="handleShowEditBaseEDB">下一步</van-button>
+            <van-button block type="primary" v-else-if="[1,3].includes(result?.Status)" @click="handleClearPage">知道了</van-button>
+        </div>
+    </div>
+
+    <!-- 选择数据来源 -->
+    <van-popup 
+        v-model:show="showSelectDataSource"
+        round
+        position="bottom"
+    >
+        <van-picker
+            title="数据来源"
+            :columns="edbSourceOpts"
+            :columns-field-names="{text:'SourceName',value:'EdbSourceId'}"
+            @confirm="onConfirmDataSource"
+            @cancel="showSelectDataSource=false"
+        />
+    </van-popup>
+
+    <!-- 新增基础指标 -->
+    <EditBaseEDB 
+        v-model="showEditBaseEDB" 
+        :baseInfo="baseInfo"
+        @addSuccess="handleEditBaseEdbSuccess"
+    />
+</template>
+
+<style lang="scss" scoped>
+.add-baseEDB-page{
+    padding-bottom: 100PX;
+    :deep(.van-cell__right-icon){
+        color: #333;
+    }
+}
+.warn_txt{
+    text-align: center;
+    padding: var(--van-padding-md);
+    color: #FF4E00;
+    line-height: 1.7;
+}
+.search-box{
+    padding: var(--van-padding-md);
+    .van-search{
+        padding: 6px;
+        background-color: #F0F2F6;
+        border-radius: var(--van-radius-max);
+    }
+    :deep(.van-search__content){
+        background: transparent !important;
+        border: none;
+    }
+    :deep(.van-search__field .van-field__left-icon){
+        color: #333;
+    }
+    .right-btn{
+        display: inline-block;
+        color: #fff;
+        background-color: $theme-color;
+        width: 112px;
+        height: 56px;
+        text-align: center;
+        line-height: 56px;
+        border-radius: var(--van-radius-max);
+    }
+}
+.data-value-wrap{
+    margin-top: 66px;
+    display: flex;
+    flex-wrap: wrap;
+    border-top: 1px solid $border-color;
+    .item{
+        width: 50%;
+        padding: 32px;
+        border-bottom: 1px solid $border-color;
+        &:nth-child(odd){
+            border-right: 1px solid $border-color;
+        }
+        .val-box{
+            display: inline-block;
+            background-color: #F2F3FF;
+            color: $theme-color;
+            text-align: center;
+            padding: 0 30px;
+            line-height: 48px;
+            border-radius: 8px;
+        }
+    }
+    .data-empty{
+        width: 100%;
+        text-align: center;
+        color: $font-grey;
+        img{
+            width: 200PX;
+        }
+    }
+}
+.search-empty-wrap{
+    text-align: center;
+    color: $font-grey;
+    img{
+        width: 200PX;
+    }
+}
+.no-auth{
+    width: 80%;
+    max-width: 500PX;
+    padding: 10PX 20PX;
+	margin: 30PX auto;
+	text-align: center;
+	background: #ECECEC;
+	color: #FF4E00;
+	border: 1px dashed #FF4E00;
+}
+.btns-wrap{
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    padding: 20PX;
+    z-index: 99;
+    background-color: #fff;
+}
+
+@media screen and (min-width:$media-width){
+    .search-box{
+        .van-search{
+            padding: 6px;
+        }
+        .right-btn{
+            width: 56px;
+            height: 28px;
+            line-height: 28px;
+        }
+    }
+    .data-value-wrap{
+        margin-top: 33px;
+        .item{
+            padding: 16px;
+            .val-box{
+                padding: 0 15px;
+                line-height: 28px;
+                border-radius: 4px;
+            }
+        }
+    }
+}
+</style>

+ 346 - 0
src/views/dataEDB/Detail.vue

@@ -0,0 +1,346 @@
+<script setup name="DataEDBDetail">
+import {ref} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import {apiGetLanguageConfig} from '@/api/common'
+import EDBChartDetailVue from './components/EDBChartDetail.vue'
+import EDBDataDetailVue from './components/EDBDataDetail.vue'
+import EditBaseEDB from './components/EditBaseEDB.vue'
+import SetEBDInfoEn from './components/SetEDBInfoEn.vue'
+import SetEDBNewData from './components/SetEDBNewData.vue'
+import EDBHistory from './components/EDBHistory.vue'
+import { useRoute, useRouter } from 'vue-router'
+import {showLoadingToast,showToast} from 'vant'
+import {useCopyEdbData} from '@/hooks/edb/useCopyEdbData'
+import {useEDBDelete} from './hooks/useEDBDelete'
+import {useCachedViewsStore} from '@/store/modules/cachedViews'
+
+const cachedViewsStore=useCachedViewsStore()
+const {edbClassifyDelete} =useEDBDelete()
+const {copyData} =useCopyEdbData()
+
+const route=useRoute()
+const router=useRouter()
+
+const activeType=ref(route.query.showType||'chart')
+
+const chartDetailIns=ref(null)//图表组件实例
+const dataDetailIns=ref(null)//数据详情组件实例
+
+const langType=ref('zh')
+// 获取当前要显示的语言版本
+async function getLangType(){
+    const res=await apiGetLanguageConfig({SourceKey:'edb_language'})
+    if(res.Ret===200){
+        langType.value=res.Data==='CN'?'zh':'en'
+    }
+}
+getLangType()
+
+// 获取指标详情
+const edbInfo=ref(null)
+// async function getEDBInfo(){
+//     const res=route.query.edbType==1
+//         ? await apiDataEDB.getBaseEdbInfo({EdbInfoId:Number(route.query.edbInfoId)})
+//         : await apiDataEDB.getCalculateEdbInfo({EdbInfoId:Number(route.query.edbInfoId)})
+//     if(res.Ret===200){
+//         edbInfo.value=res.Data
+//     }
+// }
+// getEDBInfo()
+
+//获取指标的按钮操作权限和详情
+//由于指标详情接口中没有按钮权限 只能获取一下指标数据接口了
+async function getEDBOptAuth(){
+    const res=await apiDataEDB.edbDataList({
+        EdbInfoId:route.query.edbInfoId,
+        PageSize: 1,
+        CurrentIndex: 1,
+    })
+    if(res.Ret===200){
+        edbInfo.value=res.Data.Item
+    }
+}
+getEDBOptAuth()
+
+
+// 调整上下限
+function handleShowLimit(){
+    chartDetailIns.value.handleShowLimitPop()
+}
+
+//点击复制
+function handleCopyData(){
+    copyData({EdbInfoId:edbInfo.value.EdbInfoId})
+}
+
+//点击刷新
+async function handleRefreshEDBInfo(){
+    const LOADING = showLoadingToast ({
+        message: "刷新中...",
+        duration: 0,
+        forbidClick: true,
+    });
+    const res=await apiDataEDB.edbRefresh({EdbInfoId:Number(route.query.edbInfoId)})
+    LOADING.close()
+    if(res.Ret===200){
+        if(activeType.value==='chart'){
+            chartDetailIns?.value.getEDBDataList()
+        }else{
+            dataDetailIns?.value.refreshList()
+        }
+    }
+}
+
+//点击编辑
+const showEditBaseEDB=ref(false)
+function handleEdit(){
+    const data=edbInfo.value
+    // 基础指标
+    if(data.EdbType===1 || [58,59,67,68].includes(data.Source)){
+        showEditBaseEDB.value=true
+    }
+    // 计算指标
+    if(data.EdbType === 2 && ![27,40,58,59].includes(data.Source)){
+        showToast('待开发,计算指标请在pc端操作')
+    }
+    //代码运算
+    if(data.Source===27){
+        showToast('代码运算指标请在pc端操作')
+    }
+    //数据调整
+    if(data.Source===40){
+        showToast('数据调整指标请在pc端操作')
+    }
+}
+//编辑基础指标成功回调
+function handleEditBaseEdbSuccess(e){
+    edbInfo.value.EdbName=e.EdbName
+}
+
+// 更多操作
+const showMoreOpt=ref(false)
+
+// 设置英文
+const showSetEn=ref(false)
+
+// 设置指标最新值
+const showSetNewData=ref(false)
+
+//指标溯源
+const showEDBHistory=ref(false)
+
+//删除指标
+function handleEDBDelete(){
+    edbClassifyDelete(edbInfo.value).then(async(res)=>{
+        if(res===true){
+            await cachedViewsStore.removeCaches('DataEDBIndex')
+            router.back()
+        }
+    })
+}
+
+//基础指标全部刷新
+async function handleRefreshBaseEDBData(){
+    const LOADING = showLoadingToast ({
+        message: "刷新中...",
+        duration: 0,
+        forbidClick: true,
+    });
+    const res=await apiDataEDB.refreshBaseEDBData({EdbInfoId:edbInfo.value.EdbInfoId})
+    LOADING.close()
+    if(res.Ret===200){
+        if(activeType.value==='chart'){
+            chartDetailIns?.value.getEDBDataList()
+        }else{
+            dataDetailIns?.value.refreshList()
+        }
+    }
+}
+
+//计算指标重新计算
+async function handleCalculateReset(){
+    const res=await apiDataEDB.calculateEDBReset({EdbInfoId:edbInfo.value.EdbInfoId})
+    if(res.Ret===200){
+        showToast(res.Msg)
+        if(activeType.value==='chart'){
+            chartDetailIns?.value.getEDBDataList()
+        }else{
+            dataDetailIns?.value.refreshList()
+        }
+    }
+}
+
+//保存图表上下限
+function handleSave(){
+    chartDetailIns?.value.handleSaveChartLimit()
+}
+
+
+</script>
+
+<template>
+    <div class="edb-detail-page" v-if="edbInfo">
+        <div class="top-box">
+            <div class="van-multi-ellipsis--l2 edb-name-box">{{langType==='zh'?edbInfo.EdbName:edbInfo.EdbNameEn||edbInfo.EdbName}}</div>
+        </div>
+        <van-tabs v-model:active="activeType" sticky line-width="16" title-active-color="#0052D9" title-inactive-color="#333">
+            <van-tab title="图表详情" name="chart">
+                <EDBChartDetailVue
+                    ref="chartDetailIns" 
+                    :edbInfo="edbInfo"
+                    :langType="langType"
+                />
+            </van-tab>
+            <van-tab title="数据详情" name="data">
+                <EDBDataDetailVue
+                    ref="dataDetailIns"
+                    :edbInfo="edbInfo"
+                    :langType="langType"
+                />
+            </van-tab>
+        </van-tabs>
+        <div class="fix-bottom-box">
+            <div class="item" @click="handleRefreshEDBInfo">
+                <img class="icon" src="@/assets/imgs/report/icon_refresh.png" alt="">
+                <span>刷新</span>
+            </div>
+            <div class="item" v-if="edbInfo.Button.OpButton" @click="handleEdit">
+                <img class="icon" src="@/assets/imgs/dataEDB/icon_edit.png" alt="">
+                <span>编辑</span>
+            </div>
+            <div class="item" v-if="activeType==='chart'" @click="handleShowLimit">
+                <img class="icon" src="@/assets/imgs/myETA/icon_limit.png" alt="">
+                <div>上下限</div>
+            </div>
+            <div class="item" v-if="activeType==='data'" @click="handleCopyData">
+                <img class="icon" src="@/assets/imgs/myETA/icon_copy.png" alt="">
+                <div>复制</div>
+            </div>
+            <div class="item" @click="showMoreOpt=true">
+                <img class="icon" src="@/assets/imgs/myETA/icon_menu.png" alt="">
+                <div>更多</div>
+            </div>
+        </div>
+    </div>
+
+    <!-- 编辑基础指标 -->
+    <EditBaseEDB 
+        v-model="showEditBaseEDB" 
+        :edbInfoId="edbInfo?.EdbInfoId"
+        @success="handleEditBaseEdbSuccess"
+    />
+
+    <!-- 更多操作 -->
+    <van-action-sheet
+        teleport="body"
+        v-model:show="showMoreOpt"
+        cancel-text="取消"
+        close-on-click-action
+    >
+        <template #default>
+            <ul class="edb-opt-list">
+                <li class="van-ellipsis item name">{{edbInfo.EdbName}}</li>
+
+                <li class="item" @click="showSetEn=true">设置英文名称</li>
+                <li class="item" 
+                    v-if="edbInfo.Button.InsertNewDataButton"
+                    @click="showSetNewData=true"
+                >{{edbInfo.DataInsertConfig.Date?'编辑最新值':'添加最新值'}}</li>
+                <li class="item" v-if="edbInfo.EdbType===1" @click="handleRefreshBaseEDBData">全部刷新</li>
+                <li class="item" v-if="edbInfo.EdbType===2" @click="showEDBHistory=true">指标溯源</li>
+                <li class="item" v-if="edbInfo.EdbType===2" @click="handleCalculateReset">重新计算</li>  
+                <li class="item" v-if="activeType==='chart'" @click="handleSave">保存</li>
+                <li class="item color-red" @click="handleEDBDelete">删除</li>
+            </ul>
+        </template>
+    </van-action-sheet>
+
+    <!-- 设置英文 -->
+    <SetEBDInfoEn v-model:show="showSetEn" :edbInfo="edbInfo"/>
+
+    <!-- 设置最新值 -->
+    <SetEDBNewData v-model:show="showSetNewData" :edbInfo="edbInfo"/>
+
+    <!-- 指标溯源 -->
+    <EDBHistory v-model:show="showEDBHistory" :edbInfoId="edbInfo?.EdbInfoId" />
+</template>
+
+<style lang="scss" scoped>
+:deep(.van-tabs__wrap){
+    border-bottom: 1px solid $border-color;
+}
+.top-box{
+    padding: $page-padding $page-padding 10px;
+    .edb-name-box{
+        font-size: 36px;
+        line-height: 52px;
+    }
+}
+.edb-detail-page{
+    padding-bottom: 120px;
+}
+.fix-bottom-box{
+    position: fixed;
+    height: 112px;
+    border-top: 1px solid $border-color;
+    z-index: 99;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    background-color: #fff;
+    .item{
+        cursor: pointer;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        .icon{
+            width: 40px;
+            height: 40px;
+        }
+    }
+
+}
+.edb-opt-list{
+    .item{
+        font-size: 14PX;
+        text-align: center;
+        line-height: 44PX;
+        border-bottom: 1px solid $border-color;
+    }
+    .name{
+        font-weight: bold;
+        font-size: 15PX;
+    }
+    .color-blue{
+        color: $theme-color;
+    }
+    .color-red{
+        color: $theme-red;
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .top-box{
+        padding: 20px $page-padding 10px;
+        .edb-name-box{
+            font-size: 18px;
+            line-height: 27px;
+        }
+    }
+    .edb-detail-page{
+        padding-bottom: 70px;
+    }
+    .fix-bottom-box{
+        height: 56px;
+        .item{
+            .icon{
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
+}
+</style>

+ 545 - 0
src/views/dataEDB/Index.vue

@@ -0,0 +1,545 @@
+<script setup name="DataEDBIndex">
+import {reactive,ref, watch} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import {apiCommonSetSysConfig,apiGetLanguageConfig} from '@/api/common'
+import EDBClassify from './components/EDBClassify.vue'
+import { showSuccessToast, showToast } from 'vant'
+import {useRouter} from 'vue-router'
+import {useCachedViewsStore} from '@/store/modules/cachedViews'
+import langIconZH from '@/assets/imgs/chartETA/lang-icon.png'
+import langIconEN from '@/assets/imgs/chartETA/langEn-icon.png'
+
+const cachedViewsStore=useCachedViewsStore()
+const router=useRouter()
+
+const langType=ref('zh')
+// 获取当前要显示的语言版本
+async function getLangType(){
+    const res=await apiGetLanguageConfig({SourceKey:'edb_language'})
+    if(res.Ret===200){
+        langType.value=res.Data==='CN'?'zh':'en'
+        // 修改分类的语言显示
+        classifyPopIns.value.langTypeChange(langType.value)
+    }
+}
+getLangType()
+//设置语言
+async function langTypeChange(){
+    const res=await apiCommonSetSysConfig({
+        ConfigCode: 'edb_language',
+		ConfigValue: langType.value === 'en' ? 'CN' : 'EN'
+    })
+    if(res.Ret===200){
+        showSuccessToast('设置成功')
+        langType.value=langType.value === 'en' ? 'zh' : 'en'
+        classifyPopIns.value.langTypeChange(langType.value)
+    }
+}
+
+
+const listState = reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false,
+    total:0,
+    activeClassifyName:'',//当前选中的分类名称
+    activeClassifyId:0,
+})
+async function getEDBList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbChartList({
+        PageSize:listState.pageSize,
+        CurrentIndex:listState.page,
+        ClassifyId:listState.activeClassifyId
+    })
+    listState.loading=false 
+    if(res.Ret===200){ 
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+        listState.total=res.Data.Paging.Totals
+        listState.finished=res.Data.Paging.IsEnd
+    }
+}
+getEDBList()
+// 触底加载
+function onLoad(){
+    listState.page++
+    getEDBList()
+}
+// 刷新列表
+function refreshEBDList(){
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getEDBList()
+}
+
+//基础操作
+const showActionPop=ref(false)
+function handleSelectActionOpt(e){
+    console.log(e);
+    if(e.path){
+        router.push(e.path)
+        return
+    }
+    showToast('敬请期待')
+}
+
+// 分类弹窗
+const classifyPopIns=ref(null)
+const showClassifyPop=ref(false)
+function handleSelectClassifyChange(e){
+    listState.activeClassifyName=e.selectClassifyNameStr
+    listState.activeClassifyId=e.selectClassifyId
+}
+watch(
+    ()=>listState.activeClassifyId,
+    ()=>{
+        listState.page=1
+        listState.list=[]
+        listState.finished=false
+        listState.total=0
+        getEDBList()
+    }
+)
+
+// 单个指标操作数据
+const edbOptState=reactive({
+    show:false,
+    data:null,
+})
+watch(
+    ()=>edbOptState.show,
+    (n)=>{
+        if(!n){
+            edbOptState.data=null
+        }
+    }
+)
+function handleShowEdbOpt(item){
+    edbOptState.data=item
+
+    edbOptState.show=true
+}
+// 控制指标操作中的计算指标查看
+function seeComputeEDBInfo(data){
+    return data?.EdbType===2&&![58,59,67,68].includes(data?.Source)
+}
+
+
+const activeEditEDBData=ref(null)//当前编辑的指标项数据
+const showEditBaseEDB=ref(false)// 显示编辑基础指标
+// 指标操作
+function handleEDBOpt(type,data){
+    // 移动至
+    if(type==='move'){
+        handleShowEDBMove(data)
+    }
+
+    //查看关联的图表
+    if(type==='relationChart'){
+        router.push({
+            path:'/dataEDB/RelationChart',
+            query:{
+                edbInfoId:data.EdbInfoId
+            }
+        })
+    }
+
+    //查看关联指标
+    if(type==='relationEDB'){
+        router.push({
+            path:'/dataEDB/relationEDB',
+            query:{
+                edbInfoId:data.EdbInfoId
+            }
+        })
+    }
+
+    edbOptState.show=false
+}
+
+// 移动指标
+const edbMoveState=reactive({
+    show:false,
+    selectValue:'',
+    options:[],
+    edbInfoId:0,//要移动的分类id
+    tabIndex:2,
+})
+async function handleShowEDBMove(data){
+    edbMoveState.options=classifyPopIns.value.classifyList
+    edbMoveState.selectValue=data.ClassifyId
+    edbMoveState.edbInfoId=data.EdbInfoId
+    edbMoveState.tabIndex=2
+    edbMoveState.show=true
+}
+function handleEdbMoveSelectValueChange({value,selectedOptions,tabIndex}){
+    console.log(value,selectedOptions,tabIndex);
+    edbMoveState.tabIndex=tabIndex
+}
+async function handleConfirmEDBMove(){
+    if(edbMoveState.tabIndex!==2){
+        showToast('请选择第三级目录')
+        return
+    }
+    apiDataEDB.edbMove({
+        ClassifyId:edbMoveState.selectValue,
+        EdbInfoId:edbMoveState.edbInfoId,
+        PrevEdbInfoId:0,
+        NextEdbInfoId:0
+    }).then(res=>{
+        if(res.Ret===200){
+            showToast('移动成功!')
+            refreshEBDList()
+            edbMoveState.show=false
+        }
+    })
+}
+
+// 跳转详情
+function handleEDBDetail(item){
+    router.push({
+        path:'/dataEDB/detail',
+        query:{
+            edbInfoId:item.EdbInfoId
+        }
+    })
+}
+
+async function goSearch(){
+    // 删除指标搜索页的缓存
+    await cachedViewsStore.removeCaches('DataEDBSearch')
+    router.push('/dataEDB/search')
+}
+
+</script>
+
+<template>
+    <div class="dataEDB-index-page">
+        <div class="top-sticky-box">
+            <div class="search-box">
+                <van-search 
+                    shape="round" 
+                    readonly 
+                    placeholder="请输入指标ID/指标名称"
+                    style="flex:1;padding-left:0"
+                    @click-input="goSearch"
+                />
+                <div class="lang-icon icon">
+                    <img :src="langType==='zh'?langIconZH:langIconEN" alt="" @click="langTypeChange">
+                </div>
+            </div>
+            <div class="count-box">
+                <div class="con">
+                    <div class="van-ellipsis label">{{listState.activeClassifyName||'全部'}}</div>
+                    <span class="num">共{{listState.total}}个指标</span>
+                </div>
+                <img class="menu-icon" src="@/assets/imgs/dataEDB/icon_menu.png" alt="" @click="showClassifyPop=true">
+            </div>
+        </div>
+        <div class="edb-list-wrap">
+            <van-list
+                v-model:loading="listState.loading"
+                :finished="listState.finished"
+                :finished-text="listState.list.length>0?'没有更多了':'暂无数据'"
+                :immediate-check="false"
+                @load="onLoad"
+            >
+                <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+                <ul class="edb-list">
+                    <li class="edb-item" v-for="item in listState.list" :key="item.EdbInfoId" @click="handleEDBDetail(item)">
+                        <div class="van-multi-ellipsis--l2 name">{{langType==='zh'?item.EdbName:item.EdbNameEn||item.EdbName}}</div>
+                        <van-image
+                            class="img"
+                            :src="item.ChartImage"
+                        />
+                        <div>
+                            <span class="time">{{item.CreateTime.substring(0,10)}}</span>
+                            <svg 
+                                class="opt-icon" 
+                                xmlns="http://www.w3.org/2000/svg" 
+                                width="28" 
+                                height="28" 
+                                viewBox="0 0 28 28" 
+                                fill="none"
+                                @click.stop="handleShowEdbOpt(item)"
+                            >
+                                <rect width="28" height="28" rx="4" :fill="item.EdbInfoId===edbOptState.data?.EdbInfoId?'#0052D9':'none'"/>
+                                <path d="M14 19.25C14.9625 19.25 15.75 20.0375 15.75 21C15.75 21.9625 14.9625 22.75 14 22.75C13.0375 22.75 12.25 21.9625 12.25 21C12.25 20.0375 13.0375 19.25 14 19.25ZM12.25 14C12.25 14.9625 13.0375 15.75 14 15.75C14.9625 15.75 15.75 14.9625 15.75 14C15.75 13.0375 14.9625 12.25 14 12.25C13.0375 12.25 12.25 13.0375 12.25 14ZM12.25 7C12.25 7.9625 13.0375 8.75 14 8.75C14.9625 8.75 15.75 7.9625 15.75 7C15.75 6.0375 14.9625 5.25 14 5.25C13.0375 5.25 12.25 6.0375 12.25 7Z" :fill="item.EdbInfoId===edbOptState.data?.EdbInfoId?'#fff':'#333333'"/>
+                            </svg>
+                        </div>
+                    </li>
+                </ul>
+            </van-list>
+        </div>
+        
+    </div>
+
+    <!-- 悬浮操作按钮 -->
+    <div class="fixed-opt-btn" @click="showActionPop=true">
+        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+            <path fill-rule="evenodd" clip-rule="evenodd" d="M43.4855 12.7505L25.4062 2.31235C24.536 1.80995 23.4639 1.80995 22.5937 2.31235L4.5144 12.7505V33.6267C4.5144 34.6315 5.05046 35.5599 5.92065 36.0623L24 46.5005L42.0793 36.0623C42.9495 35.5599 43.4855 34.6315 43.4855 33.6267V12.7505ZM23.997 22.2665L9.01233 13.6153L24 4.96245L38.9859 13.6158L23.997 22.2665ZM25.5 24.8665L40.485 16.2149V33.5165L25.5 42.1666V24.8665ZM22.5 24.8665V42.1667L7.51198 33.5165V16.2132L22.5 24.8665Z" fill="white"/>
+        </svg>
+    </div>
+
+    <!-- 基础操作弹窗 -->
+    <van-action-sheet
+        teleport="body"
+        v-model:show="showActionPop"
+        cancel-text="取消"
+        close-on-click-action
+        :actions="[
+            {
+                name:'添加指标',
+                path:'/dataEDB/addbaseEDB'
+            },
+            {
+                name:'计算指标'
+            },
+            {
+                name:'替换指标'
+            }
+        ]"
+        @select="handleSelectActionOpt"
+    >
+    </van-action-sheet>
+
+    <!-- 分类弹窗 -->
+    <EDBClassify ref="classifyPopIns" v-model="showClassifyPop" @change="handleSelectClassifyChange"/>
+
+    <!-- 指标的操作 -->
+    <van-action-sheet
+        teleport="body"
+        v-model:show="edbOptState.show"
+        cancel-text="取消"
+        close-on-click-action
+    >
+        <template #default>
+            <ul class="edb-opt-list">
+                <!-- 计算指标查看 -->
+                <!-- <li class="item" v-if="seeComputeEDBInfo(edbOptState.data)">查看</li> -->
+                <li class="item" v-if="edbOptState.data?.Button.ShowEdbRelation" @click="handleEDBOpt('relationEDB',edbOptState.data)">关联指标</li>
+                <li class="item" v-if="edbOptState.data?.Button.ShowChartRelation" @click="handleEDBOpt('relationChart',edbOptState.data)">关联图表</li>
+                <li class="item" v-if="edbOptState.data?.Button.MoveButton" @click="handleEDBOpt('move',edbOptState.data)">移动至</li>
+            </ul>
+        </template>
+    </van-action-sheet>
+
+    <!-- 指标移动 -->
+    <van-popup 
+        v-model:show="edbMoveState.show" 
+        round 
+        position="bottom"
+    >
+        <van-cascader
+            v-model="edbMoveState.selectValue"
+            title="移动至"
+            :options="edbMoveState.options"
+            :field-names="{text:'ClassifyName',value:'ClassifyId',children:'Children'}"
+            @close="edbMoveState.show = false"
+            @change="handleEdbMoveSelectValueChange"
+        />
+        <div style="width:300px;margin:0 auto;padding:20px 0">
+            <van-button type="primary" round block @click="handleConfirmEDBMove">确定</van-button>
+        </div>
+    </van-popup>
+</template>
+
+<style lang="scss" scoped>
+.dataEDB-index-page{
+    min-height: 100vh;
+    background-color: $page-bg-grey;
+}
+.fixed-opt-btn{
+    cursor: pointer;
+    width: var(--van-back-top-size);
+    height: var(--van-back-top-size);
+    position: fixed;
+    right: var(--van-back-top-right);
+    bottom: calc(var(--van-back-top-bottom) + var(--van-back-top-size) + 10px);
+    background-color: $theme-color;
+    border-radius: 50%;
+    box-shadow: 0px 6px 28px 4px rgba(0, 0, 0, 0.05), 0px 16px 20px 2px rgba(0, 0, 0, 0.06), 0px 10px 10px -6px rgba(0, 0, 0, 0.1);
+    svg{
+        width: 40px;
+        height: 40px;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%,-50%);
+    }
+}
+.top-sticky-box{
+    top: 0;
+    left: 0;
+    right: 0;
+    z-index: 99;
+    position: sticky;
+    background-color: #fff;
+    .search-box{
+        display: flex;
+        align-items: center;
+        padding: 20px $page-padding;
+        border-bottom: 1px solid $border-color;
+        :deep(.van-search){
+            padding: 0;
+        }
+        .lang-icon{
+            cursor: pointer;
+            margin-left: 10px;
+            width: 70px;
+            height:70px;
+            background-color: #F2F3FF;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            img{
+                width:45px;
+                height:45px;
+            }
+        }
+    }
+    .count-box{
+        display: flex;
+        align-items: center;
+        padding: 20px $page-padding;
+        .con{
+            flex: 1;
+            display: flex;
+            overflow: hidden;
+            .lable{
+                flex: 1;
+            }
+            .num{
+                color: $font-grey_999;
+                margin-left: 12px;
+                flex-shrink: 0;
+            }
+        }
+        .menu-icon{
+            cursor: pointer;
+            width: 48px;
+            height: 48px;
+            flex-shrink: 0;
+            margin-left: 10px;
+        }
+    }
+}
+.edb-list-wrap{
+    padding: 32px $page-padding;
+    .edb-list{
+        display: flex;
+        justify-content: space-between;
+        flex-wrap: wrap;
+        gap: 30px 0;
+        .edb-item{
+            cursor: pointer;
+            width: 326px;
+            border-radius: 8px;
+            background: #FFF;
+            box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.08);
+            padding: 10px;
+            .name{
+                min-height: 70px;
+            }
+            .img{
+                width: 100%;
+                height: 220px;
+                margin: 14px 0;
+            }
+            .time{
+                font-size: 24px;
+            }
+            .opt-icon{
+                cursor: pointer;
+                float: right;
+                width: 28px;
+                height: 28px;
+            }
+        }
+    }
+    
+}
+.edb-opt-list{
+    .item{
+        font-size: 14PX;
+        text-align: center;
+        line-height: 44PX;
+        border-bottom: 1px solid $border-color;
+    }
+    .color-blue{
+        color: $theme-color;
+    }
+    .color-red{
+        color: $theme-red;
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .fixed-opt-btn{
+        bottom: calc(var(--van-back-top-bottom) + var(--van-back-top-size) + 10px);
+        svg{
+            width: 20px;
+            height: 20px;
+        }
+    }
+    .top-sticky-box{
+        top: 60px;
+        .search-box{
+            padding: 20px $page-padding;
+            .lang-icon{
+                margin-left: 10px;
+                width: 35px;
+                height: 35px;
+                img{
+                    width: 23px;
+                    height: 23px;
+                }
+            }
+        }
+        .count-box{
+            padding: 20px $page-padding;
+            .con{
+                .num{
+                    margin-left: 12px;
+                }
+            }
+            .menu-icon{
+                width: 30px;
+                height: 30px;
+            }
+        }
+    }
+    .edb-list-wrap{
+        padding: 32px $page-padding;
+        .edb-list{
+            gap: 15px;
+            justify-content: flex-start;
+            .edb-item{
+                width: 308px;
+                border-radius: 8px;
+                padding: 10px;
+                .name{
+                    min-height: 36px;
+                }
+                .img{
+                    height: 220px;
+                    margin: 14px 0;
+                }
+                .time{
+                    font-size: 14px;
+                }
+                .opt-icon{
+                    width: 28px;
+                    height: 28px;
+                }
+            }
+        }
+    }
+}
+
+</style>

+ 191 - 0
src/views/dataEDB/RelationChart.vue

@@ -0,0 +1,191 @@
+<script setup name="DataEDBRelationChart">
+import {ref,reactive} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import apiChart from '@/api/chart'
+import {useRoute, useRouter} from 'vue-router'
+import { useWindowSize } from '@vueuse/core'
+import AddChartToMyETA from '@/views/chartETA/components/AddChartToMyETA.vue'
+
+const route=useRoute()
+const router=useRouter()
+const { width } = useWindowSize()
+
+
+const edbInfoId=route.query.edbInfoId//当前指标的id
+
+const listState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    totals:0,
+    loading:false,
+    finished:false
+})
+// 获取关联的图列表
+async function getEdbRelationChartList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbRelationChartList({
+        PageSize:listState.pageSize,
+        CurrentIndex:listState.page,
+        EdbInfoId:edbInfoId
+    })
+    listState.loading=false
+    if(res.Ret===200){
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        const arr=res.Data?.List||[]
+        listState.list=[...listState.list,...arr]
+        listState.finished=res.Data?.Paging.IsEnd
+        listState.totals=res.Data?.Paging.Totals
+    }
+}
+getEdbRelationChartList()
+function onLoad(){
+    listState.page++
+    getEdbRelationChartList()
+}
+
+// 加入我的图库
+const isShowAddToMyETADialog=ref(false)
+const chartInfo=ref({})
+async function handleShowAddToMyChart(e){
+    // 获取一下图详情
+    const res=await apiChart.chartInfoByCode({UniqueCode:e.UniqueCode})
+    if(res.Ret===200){
+        chartInfo.value=res.Data.ChartInfo
+        isShowAddToMyETADialog.value=true
+    }
+}
+
+//跳转图详情
+function goChartDetail(item){
+    router.push({
+        path:'/myETA/chartdetail',
+        query:{
+            code:item.UniqueCode,
+            iscommon:true,
+            from:'edbRelationChart',
+            edbInfoId:edbInfoId
+        }
+    })
+}
+
+
+</script>
+
+<template>
+    <div class="edb-relation-chart-page">
+        <div class="total-box">共{{listState.totals}}张图表</div>
+        <div class="chart-list-wrap">
+            <van-list
+                v-model:loading="listState.loading"
+                :finished="listState.finished"
+                :finished-text="listState.list.length>0?'没有更多了':'暂无关联图表'"
+                :immediate-check="false"
+                @load="onLoad"
+            >
+                <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+                <ul class="chart-list">
+                    <li class="item" v-for="item in listState.list" :key="item.ChartInfoId" @click="goChartDetail(item)">
+                        <div class="van-multi-ellipsis--l2 name">{{item.ChartName}}</div>
+                        <van-image
+                            class="img"
+                            :src="item.ChartImage"
+                        />
+                        <div class="time">{{item.CreateTime.slice(0,10)}}</div>
+                        <svg @click.stop="handleShowAddToMyChart(item)" class="opt-icon" xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36" fill="none">
+                            <path d="M11.7892 19.081H16.9192V24.211C16.9192 24.3595 17.0407 24.481 17.1892 24.481H18.8092C18.9577 24.481 19.0792 24.3595 19.0792 24.211V19.081H24.2092C24.3577 19.081 24.4792 18.9595 24.4792 18.811V17.191C24.4792 17.0425 24.3577 16.921 24.2092 16.921H19.0792V11.791C19.0792 11.6425 18.9577 11.521 18.8092 11.521H17.1892C17.0407 11.521 16.9192 11.6425 16.9192 11.791V16.921H11.7892C11.6407 16.921 11.5192 17.0425 11.5192 17.191V18.811C11.5192 18.9595 11.6407 19.081 11.7892 19.081Z" fill="#0052D9"/>
+                            <path d="M30.42 4.5H5.58C4.98262 4.5 4.5 4.98262 4.5 5.58V30.42C4.5 31.0174 4.98262 31.5 5.58 31.5H30.42C31.0174 31.5 31.5 31.0174 31.5 30.42V5.58C31.5 4.98262 31.0174 4.5 30.42 4.5ZM29.07 29.07H6.93V6.93H29.07V29.07Z" fill="#0052D9"/>
+                        </svg>
+                    </li>
+                </ul>
+            </van-list>
+        </div>
+    </div>
+
+    <!-- 加入我的图库 -->
+    <AddChartToMyETA 
+        :isShowDialog="isShowAddToMyETADialog"
+        :dialogPosition="width>650?'center':'bottom'"
+        :chartInfo="chartInfo"
+        @close="isShowAddToMyETADialog=false"
+    />
+</template>
+
+<style lang="scss" scoped>
+.edb-relation-chart-page{
+    padding:$page-padding;
+}
+.total-box{
+    margin-bottom: 20px;
+    color: $font-grey_999;
+}
+.chart-list{
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    gap: 30px 0;
+    .item{
+        width: 326px;
+        border-radius: 8px;
+        background: #FFF;
+        border: 1px solid $border-color;
+        padding: 14px;
+        position: relative;
+        .name{
+            min-height: 70px;
+        }
+        .img{
+            width: 100%;
+            height: 220px;
+            margin: 14px 0;
+        }
+        .time{
+            font-size: 24px;
+        }
+        .opt-icon{
+            position: absolute;
+            bottom: 14px;
+            right: 14px;
+            width: 36px;
+            height: 36px;
+        }
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .edb-relation-chart-page{
+        padding:$page-padding;
+    }
+    .total-box{
+        margin-bottom: 10px;
+    }
+    .chart-list{
+        justify-content: flex-start;
+        gap: 10px;
+        .item{
+            width: 313px;
+            border-radius: 8px;
+            padding: 10px;
+            .name{
+                min-height: 36px;
+            }
+            .img{
+                height: 220px;
+                margin: 10px 0;
+            }
+            .time{
+                font-size: 12px;
+            }
+            .opt-icon{
+                bottom: 10px;
+                right: 10px;
+                width: 20px;
+                height: 20px;
+            }
+        }
+    }
+}
+</style>

+ 157 - 0
src/views/dataEDB/RelationEDB.vue

@@ -0,0 +1,157 @@
+<script setup name="DataEDBRelationEDB">
+import {ref,reactive} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import {useRoute, useRouter} from 'vue-router'
+import {useCopyEdbData} from '@/hooks/edb/useCopyEdbData'
+
+const {copyData} =useCopyEdbData()
+
+const route=useRoute()
+const router=useRouter()
+
+
+const edbInfoId=route.query.edbInfoId//当前指标的id
+
+const listState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    totals:0,
+    loading:false,
+    finished:false
+})
+// 获取关联的图列表
+async function getEdbRelationEDBList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbRelationEdbList({
+        PageSize:listState.pageSize,
+        CurrentIndex:listState.page,
+        EdbInfoId:edbInfoId
+    })
+    listState.loading=false
+    if(res.Ret===200){
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+        listState.finished=res.Data.Paging.IsEnd
+        listState.totals=res.Data.Paging.Totals
+    }
+}
+getEdbRelationEDBList()
+function onLoad(){
+    listState.page++
+    getEdbRelationEDBList()
+}
+
+//复制数据
+function handleCopyEDBData(e){
+    copyData({EdbInfoId:e.EdbInfoId})
+}
+
+// 查看数据
+function goDetail(e){
+    router.push({
+        path:'/dataEDB/detail',
+        query:{
+            edbInfoId:e.EdbInfoId,
+            showType:'data'
+        }
+    })
+}
+
+</script>
+
+<template>
+    <div class="edb-relation-edb-page">
+        <div class="total-box">共{{listState.totals}}个关联指标</div>
+        <div class="edb-list-wrap">
+            <van-list
+                v-model:loading="listState.loading"
+                :finished="listState.finished"
+                :finished-text="listState.list.length>0?'没有更多了':'暂无关联指标'"
+                :immediate-check="false"
+                @load="onLoad"
+            >
+                <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+                <ul class="edb-list">
+                    <li class="item" v-for="item in listState.list" :key="item">
+                        <h2 class="name">{{item.EdbName}}</h2>
+                        <ul class="info-list">
+                            <li class="info-item">ID:{{item.EdbCode}}</li>
+                            <li class="info-item">起始时间:{{item.StartDate}}</li>
+                            <li class="info-item">频度:{{item.Frequency}}</li>
+                            <li class="info-item">最新日期:{{item.LatestDate}}</li>
+                            <li class="info-item">单位:{{item.Unit}}</li>
+                            <li class="info-item">最新值:{{item.LatestValue}}</li>
+                            <li class="info-item">最近更新:{{item.ModifyTime}}</li>
+                            <li class="info-item">数据来源:{{item.SourceName}}</li>
+                        </ul>
+                        <div style="text-align:right">
+                            <van-button color="#F2F3FF" size="small" style="color:#0052D9;margin-right:10px" @click="handleCopyEDBData(item)">复制数据</van-button>
+                            <van-button color="#0052D9" size="small" @click="goDetail(item)">查看数据</van-button>
+                        </div>
+                    </li>
+                </ul>
+            </van-list>
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.edb-relation-edb-page{
+    padding:$page-padding;
+}
+.total-box{
+    margin-bottom: 20px;
+    color: $font-grey_999;
+}
+.edb-list{
+    .item{
+        margin-bottom: 36px;
+        border-radius: 8px;
+        border: 1px solid $border-color;
+        box-shadow: $box-shadow;
+        padding: 20px;
+        .name{
+            font-size: 32px;
+        }
+        .info-list{
+            color: $font-grey;
+            margin-bottom: 10px;
+            .info-item{
+                margin-bottom: 10px;
+            }
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .edb-relation-edb-page{
+        padding:$page-padding;
+    }
+    .total-box{
+        margin-bottom: 10px;
+    }
+    .edb-list{
+        .item{
+            margin-bottom: 18px;
+            border-radius: 4px;
+            padding: 10px;
+            .name{
+                font-size: 16px;
+            }
+            .info-list{
+                margin-bottom: 5px;
+                .info-item{
+                    margin-bottom: 5px;
+                }
+            }
+        }
+    }
+
+}
+</style>
+
+

+ 165 - 0
src/views/dataEDB/SearchList.vue

@@ -0,0 +1,165 @@
+<script setup name="DataEDBSearch">
+import {ref,reactive} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import { showToast } from 'vant'
+import moment from 'moment'
+import { useRouter } from 'vue-router'
+
+const router=useRouter()
+
+const keyword=ref('')
+const listState = reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false
+})
+async function getList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbChartSearchList({
+        CurrentIndex:listState.page,
+        PageSize:listState.pageSize,
+        KeyWord:keyword.value
+    })
+    if(res.Ret===200){
+        listState.loading=false
+        if(!res.Data){
+            listState.finished=true
+            return
+        }
+        
+        listState.finished=res.Data.Paging.IsEnd
+        const arr=res.Data.List||[]
+        listState.list=[...listState.list,...arr]
+    }
+}
+function onLoad(){
+    listState.page++
+    getList()
+}
+
+function handleSearch(){
+    if(!keyword.value){
+        showToast('请输入关键词')
+        return
+    }
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getList()
+}
+
+function goDetail(item){
+    router.push({
+        path:"/dataEDB/detail",
+        query:{
+            edbInfoId:item.EdbInfoId
+        }
+    })
+}
+
+</script>
+
+<template>
+    <div class="edb-search-list-page">
+        <div class="search-box">
+            <van-search 
+                shape="round"
+                placeholder="请输入指标ID/指标名称"
+                v-model="keyword"
+                @search="handleSearch"
+            />
+        </div>
+        <img v-if="listState.list.length==0&&listState.finished&&keyword" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+        <van-list
+            v-model:loading="listState.loading"
+            :finished="listState.finished"
+            :finished-text="listState.list.length>0?'没有更多了':'暂无数据'"
+            :immediate-check="false"
+            @load="onLoad"
+        >
+            <ul class="list-wrap">
+                <li class="item" v-for="item in listState.list" :key="item.EdbInfoId" @click="goDetail(item)">
+                    <div class="van-multi-ellipsis--l2 name">{{item.EdbName}}</div>
+                    <van-image
+                        class="img"
+                        :src="item.ChartImage"
+                    />
+                    <div class="time">
+                        <span>{{item.StartDate}}</span>
+                        <span>{{item.SysUserRealName}}</span>
+                    </div>
+                </li>
+            </ul>
+        </van-list>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.search-box{
+    position: sticky;
+    top: 0;
+    background-color: #fff;
+    z-index: 99;
+}
+.list-wrap{
+    padding: $page-padding;
+    display: flex;
+    flex-wrap: wrap;
+    box-sizing: border-box;
+    justify-content: space-between;
+    .item{
+        box-sizing: border-box;
+        width: 326px;
+        padding: 10px 14px;
+        border: 1px solid $border-color;
+        margin-bottom: 20px;
+        border-radius: 12px;
+        .name{
+            min-height: 70px;
+        }
+        .img{
+            width: 100%;
+            height: 220px;
+            display: block;
+            margin: 10px 0;
+        }
+        .time{
+            font-size: 28px;
+            color: $font-grey_999;
+            position: relative;    
+            display: flex;
+            justify-content: space-between; 
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .search-box{
+        top: 60px;
+    }
+    .list-wrap{
+        padding: var(--van-search-padding);
+        justify-content: flex-start;
+        .item{
+            width: 310px;
+            padding: 5px 7px;
+            margin-bottom: 10px;
+            border-radius: 6px;
+            margin-left: 5px;
+            margin-right: 5px;
+            .name{
+                min-height: 35px;
+            }
+            .img{
+                height: 220px;
+                margin: 5px 0;
+            }
+            .time{
+                font-size: 14px;
+            }
+        }
+        
+    }
+}
+</style>

+ 1035 - 0
src/views/dataEDB/components/EDBChartDetail.vue

@@ -0,0 +1,1035 @@
+<script setup>
+import {ref,onMounted, reactive, nextTick} from 'vue'
+import moment from 'moment'
+import {yearSelectOpt} from '@/hooks/chart/config'
+import apiDataEDB from '@/api/dataEDB'
+import { useWindowSize } from '@vueuse/core'
+import {chartDefaultOpts,seasonOptions} from '@/hooks/chart/config'
+import lodash from 'lodash'
+import Highcharts from 'highcharts/highstock';
+import Boost from 'highcharts/modules/boost'
+import HighchartszhCN  from '@/hooks/chart/highcahrts-zh_CN.js'
+HighchartszhCN(Highcharts)
+Boost(Highcharts)
+
+import { useRoute } from 'vue-router'
+import { showToast } from 'vant'
+
+const { width } = useWindowSize()
+const route=useRoute()
+
+const props=defineProps({
+    edbInfo:{
+        type:Object,
+        default:null,
+        require:true
+    },
+    langType:{//当前显示的语言
+        type:String,
+        default:'zh'
+    }
+})
+
+defineExpose({handleShowLimitPop,getEDBDataList,handleSaveChartLimit})
+
+// 获取指标数据
+const edbDataInfo=ref(null)
+async function getEDBDataList(){
+    const res=await apiDataEDB.edbDataList({
+        PageSize: 3,
+        CurrentIndex: 1,
+        EdbInfoId:route.query.edbInfoId
+    })
+    if(res.Ret===200){
+        edbDataInfo.value=res.Data.Item
+    }
+}
+getEDBDataList()
+
+
+const oldOptions=reactive({
+    MinValue:0,
+    MaxValue:0,
+})
+const chartInfo=ref({})
+const tableData=ref([])
+const options=ref({})
+const limitData=reactive({
+    leftMin: 0,
+	leftMax: 0,
+	rightMin: 0,
+	rightMax: 0,
+})
+
+// 渲染图
+function renderChart(){
+    const chartRenderOpt={...chartDefaultOpts,...options.value}
+    console.log(chartRenderOpt);
+    //stock不支持线形图只支持时间图 某些用chart
+    let is_linear = options.value.series 
+    ? options.value.series.every(_ => _.type === 'scatter') || options.value.series.some(_ => _.chartType === 'linear')
+    : false ;
+    is_linear ?Highcharts.chart('chart-box',chartRenderOpt) : Highcharts.stockChart('chart-box',chartRenderOpt);
+}
+
+//查询范围为1年内 x轴显示为月/日 否则默认年/月
+function xTimeDiffer(){
+    const end_date =
+        selectYear.value === 5
+          ? selectEndDate.value
+          : selectYear.value === 6
+          ? new Date()
+          : '';
+    //年限差
+    const year_differ = moment(end_date).diff(
+        moment(selectStartDate.value),
+        'years',
+        true
+    );
+    // console.log(year_differ)
+    if ([5, 6].includes(selectYear.value) && year_differ <= 1) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// 设置曲线图
+function setLineChart(){
+    let data=[],ydata=[];
+
+    //y轴
+    // 单位 中文时 为无不显示   英文时 为空提示点击输入
+	// 中文不存在或等于无时 英文显示为空  中文存在且英文不存在时 显示'英文单位'
+    let yTitleText = props.langType=='zh'?
+	(chartInfo.value.Unit && chartInfo.value.Unit!='无') ? chartInfo.value.Unit:'':
+	!chartInfo.value.UnitEn && chartInfo.value.Unit && chartInfo.value.Unit!='无' ? '英文单位':chartInfo.value.UnitEn
+	// title样式  英文为空时,提示文字样式  英文可以点击设置
+    let yTitleStyle = {}
+    if(props.langType=='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(chartInfo.value.MinValue),
+		max: Number(chartInfo.value.MaxValue),
+		...seasonOptions.yAxis,
+	};
+
+    // 图例名称和图例文字样式
+	let dataName = props.langType=='zh'?chartInfo.value.EdbName:chartInfo.value.EdbNameEn?chartInfo.value.EdbNameEn:'无英文名称'
+	let color = props.langType=='en'&&(!chartInfo.value.EdbNameEn)?'#999':'#333'
+	let legend={
+		...chartDefaultOpts.legend,
+		itemStyle: {
+			color
+		},
+	}
+    //数据列
+	let obj = {
+		data: [],
+		type: 'spline',
+		yAxis: 0,
+		name: dataName,
+		lineWidth: 3
+	};
+    tableData.value.forEach((item, index) => {
+		obj.data.push([item.DataTimestamp, item.Value]);
+	});
+    data.push(obj);
+    ydata.push(yItem);
+
+    // 范围为1年内 x轴显示为月/日 否则默认年/月
+    let xAxis = {};
+    const bool_time = xTimeDiffer();
+    if(bool_time){
+        xAxis={
+            ...chartDefaultOpts.xAxis,
+            labels: {
+              formatter: function (ctx) {
+                return Highcharts.dateFormat('%m/%d', ctx.value);
+              },
+            },
+        }
+    }else{
+        xAxis={
+            ...chartDefaultOpts.xAxis,
+			labels: {
+                formatter: function (ctx) {
+                    return Highcharts.dateFormat('%y/%m', ctx.value);
+                },
+            },
+        }
+    }
+
+    options.value={
+        series: data,
+        yAxis: ydata,
+        xAxis,
+        legend
+    }
+    // 如果是渲染同比图要先获取曲线图数据然后再获取同比图数据再渲染图
+    if(chartType.value==='同比图'){
+        getEDBTBChartData()
+    }else{
+        nextTick(()=>{
+            renderChart()
+        })
+    }
+}
+
+//设置同比图
+function setTBChart(data){
+    const { DataList,EdbInfo } = data;
+    if(!limitData.rightMin && !limitData.rightMax) {
+		limitData.rightMin = Number(EdbInfo.MinValue);
+		limitData.rightMax = Number(EdbInfo.MaxValue);
+	}
+    options.value.yAxis.push({
+        title: {
+			text: '',
+			align: 'high',
+			rotation: 0,
+			y: -15,
+			offset: 0
+		},
+		labels: {
+			formatter: function (ctx) {
+				return ctx.value;
+			},
+			align: 'center',
+		},
+		min: Number(limitData.rightMin),
+		max: Number(limitData.rightMax),
+		...seasonOptions.yAxis,
+		opposite: true,
+    })
+    options.value.series.push({
+		data: DataList.map(item=>([item.DataTimestamp, item.Value])),
+		type: 'spline',
+		yAxis: 1,
+		name: props.langType=='zh'?`${EdbInfo.EdbName}同比`:EdbInfo.EdbNameEn?`${EdbInfo.EdbNameEn}同比`:'无英文名称',
+		lineWidth: 1
+	})
+    nextTick(()=>{
+        renderChart()
+    })
+}
+
+//设置季节性图
+function setSeasonChart(){
+    let seasonYdata = [],seasonData = [];
+    /* 公历数据处理 处理数据列 y轴 */
+    if (calendarType.value === '公历'){
+        for (let j of tableData.value) {
+            let serie_item = {
+                data: [],
+                type: 'spline',
+                yAxis: 0,
+                name: j.Year,
+            };
+            const data_array = j.DataList||[];
+            data_array.forEach((item) => {
+                serie_item.data.push([item.DataTimestamp, item.Value]);
+            });
+            const index = tableData.value.findIndex((item) => item.Year === j.Year);
+            const s_yItem = {
+                labels: {
+                    formatter: function () {
+                        let val = this.value;
+                        return index !== 0 ? '' : val;
+                    },
+                    align: 'center',
+                },
+                title: {
+                    text:  props.langType=='zh'?chartInfo.value.Unit:
+                                    !chartInfo.value.UnitEn && chartInfo.value.Unit && chartInfo.value.Unit!='无' ? '英文单位':chartInfo.value.UnitEn,
+                    align: 'high',
+                    rotation: 0,
+                    y: -15,
+                    offset: -(12 * chartInfo.value.Unit.length),
+                },
+                max: Number(chartInfo.value.MaxValue),
+                min: Number(chartInfo.value.MinValue),
+                ...seasonOptions.yAxis,
+            };
+            seasonData.push(serie_item);
+            seasonYdata.push(s_yItem);
+        }
+    }
+
+    /* 农历数据处理  */
+    let filterArr =calendarType.value === '农历'?tableData.value.List.filter((item, index) => index > 0):[]
+    if (calendarType.value === '农历'){
+        for (let j of filterArr) {
+            let serie_item = {
+                data: [],
+                type: 'spline',
+                yAxis: 0,
+                name: j.Year
+            };
+            const data_array =j.Items||[];
+            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:  props.langType=='zh'?chartInfo.value.Unit:
+                                    !chartInfo.value.UnitEn && chartInfo.value.Unit && chartInfo.value.Unit!='无' ? '英文单位':chartInfo.value.UnitEn,
+                    align: 'high',
+                    rotation: 0,
+                    y: -15,
+                    offset: -(12 * chartInfo.value.Unit.length),
+                },
+                max: Number(chartInfo.value.MaxValue),
+                min: Number(chartInfo.value.MinValue),
+                ...seasonOptions.yAxis,
+            };
+            seasonData.push(serie_item);
+            seasonYdata.push(s_yItem);
+        }
+    }
+
+    /* x轴显示月日  提示框显示月日*/
+    let xAxis={
+        labels:{
+            formatter: function () {
+                return Highcharts.dateFormat('%m/%d', this.value);
+            },
+        }
+    }
+    const tooltip = {
+        ...chartDefaultOpts.tooltip,
+        dateTimeLabelFormats: {
+            // 时间格式化字符
+            day: '%m/%d',
+            week: '%m/%d',
+            month: '%m/%d',
+            year: '%m/%d',
+        },
+        xDateFormat: '%m/%d',
+    }
+    let rangeSelector ={}
+    if(calendarType.value==='农历'){
+        rangeSelector={
+            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',
+                },
+            ],
+        }
+    }else{
+        rangeSelector={enabled: false,}
+    }
+    options.value={
+        colors:calendarType.value === '公历'
+            ? seasonOptions.colors.slice(-tableData.value.length)
+            : seasonOptions.colors.slice(-filterArr.length),
+        series: seasonData,
+        yAxis: seasonYdata,
+        xAxis:xAxis,
+        rangeSelector,
+        tooltip
+    }
+    nextTick(()=>{
+        renderChart()
+    })
+}
+
+// 获取指标曲线图数据
+async function getEDBLineChartData(){
+    const res=await apiDataEDB.edbLineChartData({
+        EdbInfoId:route.query.edbInfoId,
+        DateType:selectYear.value,
+        StartDate:selectStartDate.value,
+        EndDate:selectEndDate.value
+    })
+    if(res.Ret===200){
+        const { DataList,EdbInfo } = res.Data;
+        // DataList 表格数据列表
+		chartInfo.value = (oldOptions.MinValue || oldOptions.MaxValue) ? {
+			...EdbInfo,
+			MinValue:oldOptions.MinValue,
+            MaxValue:oldOptions.MaxValue
+		} : EdbInfo;
+		tableData.value = DataList || [];
+        limitData.leftMin=chartInfo.value.MinValue
+        limitData.leftMax=chartInfo.value.MaxValue
+        setLineChart()
+    }
+}
+
+//获取同比图数据
+async function getEDBTBChartData(){
+    const res=await apiDataEDB.edbTBChartData({
+        EdbInfoId:route.query.edbInfoId,
+        DateType:selectYear.value,
+        StartDate:selectStartDate.value,
+        EndDate:selectEndDate.value
+    })
+    if(res.Ret===200){
+        setTBChart(res.Data)
+    }
+}
+
+//获取季节性图数据
+async function getEDBSeasonChartData(){
+    const res=await apiDataEDB.edbSeasonChartData({
+        EdbInfoId:route.query.edbInfoId,
+        Calendar:calendarType.value,
+        StartDate:selectStartDate.value,
+        EndDate:selectEndDate.value
+    })
+    if(res.Ret===200){
+        const { DataList,EdbInfo } = res.Data;
+        // DataList 表格数据列表
+		chartInfo.value = (oldOptions.MinValue || oldOptions.MaxValue) ? {
+			...EdbInfo,
+			MinValue:oldOptions.MinValue,
+            MaxValue:oldOptions.MaxValue
+		} : EdbInfo;
+		tableData.value = DataList || [];
+        limitData.leftMin=chartInfo.value.MinValue
+        limitData.leftMax=chartInfo.value.MaxValue
+        setSeasonChart()
+    }
+}
+
+onMounted(() => {
+    getEDBLineChartData()
+})
+
+
+
+// 图表类型
+const chartTypeOpts=[
+    {
+        name:'曲线图'
+    },
+    {
+        name:'同比图'
+    },
+    {
+        name:'季节性图'
+    }
+]
+let beforeChartType='曲线图'
+const chartType=ref('曲线图')
+const showChartType=ref(false)
+function onChartTypeSelect(e){
+    chartType.value=e.name
+    if(chartType.value==='季节性图'){
+        initData()
+        getEDBSeasonChartData()
+    }else{
+        // 如果是从同比图和曲线图之间切换则不重置选项
+        if(beforeChartType==='季节性图'){
+            initData()
+        }
+        getEDBLineChartData()
+    }
+    showChartType.value=false
+    beforeChartType=e.name
+}
+
+// 初始化选项数据
+function initData(){
+    console.log('init data');
+    selectStartDate.value=''
+    selectEndDate.value=''
+    selectYear.value=10
+    options.value={}
+    oldOptions.MinValue=0
+    oldOptions.MaxValue=0
+    chartInfo.value={}
+    tableData.value=[]
+    limitData.leftMin=0
+    limitData.leftMax=0
+    limitData.rightMin=0
+    limitData.rightMax=0
+    calendarType.value='公历'
+}
+
+
+// 自定义时间段数据
+const minDate=new Date(1970, 0, 1)
+const maxDate=new Date(2050, 11, 31)
+const temStartDate=ref([moment().format('YYYY'),moment().format('MM')])
+const temEndDate=ref([moment().format('YYYY'),moment().format('MM')])
+const showSelectDate=ref(false)
+const selectStartDate=ref('')
+const selectEndDate=ref('')
+function handleConfrimSelectDate(e){
+    selectStartDate.value=e[0].selectedValues.join('-')
+    selectEndDate.value=e[1].selectedValues.join('-')
+    selectYear.value=5
+    if(chartType.value==='季节性图'){
+        getEDBSeasonChartData()
+    }else{
+        getEDBLineChartData()
+    }
+    showSelectDate.value=false
+}
+
+// 时间选项
+const yearOpts=ref([{name: '全部',value:10},...yearSelectOpt])
+const selectYear=ref(10)
+function handleSelectYearChange(e){
+    selectStartDate.value=''
+    selectEndDate.value=''
+    selectYear.value=e.value
+    getEDBLineChartData()
+}
+
+//季节性图公历农历切换
+const calendarType=ref('公历')
+function handleSeasonTypeChange(e){
+    calendarType.value=e
+    getEDBSeasonChartData()
+}
+
+//调整上下限
+const showLimitPop=ref(false)
+const temLimitData=reactive({
+    leftMin: 0,
+	leftMax: 0,
+	rightMin: 0,
+	rightMax: 0,
+})
+function handleShowLimitPop(){
+    temLimitData.leftMin=limitData.leftMin
+    temLimitData.leftMax=limitData.leftMax
+    temLimitData.rightMin=limitData.rightMin
+    temLimitData.rightMax=limitData.rightMax
+    showLimitPop.value=true
+}
+function handleConfirmLimitChange(){
+    limitData.leftMin=temLimitData.leftMin
+    limitData.leftMax=temLimitData.leftMax
+    limitData.rightMin=temLimitData.rightMin
+    limitData.rightMax=temLimitData.rightMax
+    options.value.yAxis[0].min=limitData.leftMin
+    options.value.yAxis[0].max=limitData.leftMax
+    if(chartType.value==='同比图'){
+        options.value.yAxis[1].min=limitData.rightMin
+        options.value.yAxis[1].max=limitData.rightMax
+    }
+    renderChart()
+    showLimitPop.value=false
+}
+
+async function handleSaveChartLimit(){
+    const res=await apiDataEDB.edbChartInfoSave({
+        EdbInfoId:Number(route.query.edbInfoId),
+        MaxValue:limitData.leftMax,
+        MinValue:limitData.leftMin
+    })
+    if(res.Ret===200){
+        showToast('保存成功')
+    }
+}
+
+</script>
+
+<template>
+    <div class="edb-chart-detail-page">
+        <div class="top-filter-box">
+
+            <!-- 选择日期 -->
+            <div class="select-date-box" @click="showSelectDate=true">
+                <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
+                    <path d="M20 6H12L12 3H10L10 6H6C4.89543 6 4 6.89543 4 8V26C4 27.1046 4.89543 28 6 28H26C27.1046 28 28 27.1046 28 26V8C28 6.89543 27.1046 6 26 6H22V3H20L20 6ZM10 10L12 10L12 8H20L20 10L22 10V8H26V12H6V8H10L10 10ZM6 14H26V26H6L6 14Z" fill="#999999"/>
+                </svg>
+                <span :style="{color:!selectStartDate?'#999':'#333'}">{{selectStartDate||'开始日期'}}</span>
+                <span style="display:inline-block;margin:0 5px">-</span>
+                <span :style="{color:!selectEndDate?'#999':'#333'}">{{selectEndDate||'结束日期'}}</span>
+            </div>
+            <!-- 图类型切换 -->
+            <div class="chart-type-box" @click="showChartType=true">
+                 <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
+                    <path d="M2.50049 11.9999L26.0165 11.9999L18.3281 4.50217L19.7244 3.07031L29.0668 12.181C29.7475 12.8447 29.2776 13.9999 28.3268 13.9999L2.50049 13.9999V11.9999Z" fill="#0052D9"/>
+                    <path d="M29.5 19.9999L6.04053 19.9999L13.6611 27.2007L12.2874 28.6544L2.94908 19.8303C2.2522 19.1718 2.71812 17.9999 3.6771 17.9999L29.5 17.9999V19.9999Z" fill="#0052D9"/>
+                </svg>
+                <span>{{chartType}}</span>
+            </div>
+        </div>
+        <!-- 图表渲染区域 -->
+        <div class="chart-render-box">
+            <div class="chart-box" id="chart-box"></div>
+        </div>
+        <div class="calendar-type-box" v-show="chartType==='季节性图'">
+            <span 
+                :class="calendarType=='公历'?'active':''"
+                @click="handleSeasonTypeChange('公历')"
+            >公历</span>
+            <span 
+                :class="calendarType=='农历'?'active':''"
+                @click="handleSeasonTypeChange('农历')"
+            >农历</span>
+        </div>
+        <!-- 来源和作者 -->
+        <div class="data-source-auth">
+            <span>数据来源:{{props.edbInfo.SourceName}}</span>
+            <span>作者:{{props.edbInfo.SysUserRealName}}</span>
+        </div>
+        <!-- 选择时间选项 -->
+        <div class="select-year-box" v-if="chartType!=='季节性图'">
+            <span 
+                :class="['item',selectYear===item.value?'active':'']"
+                v-for="item in yearOpts" 
+                :key="item.value"
+                @click="handleSelectYearChange(item)"
+            >{{item.name}}</span>
+        </div>
+        <!-- 指标数据 -->
+        <ul class="edb-data-list-box">
+            <li class="item" v-for="item in edbDataInfo?.DataList" :key="item.DataTime">
+                <span class="frequency">{{edbDataInfo.Frequency}}</span>
+                <span class="time">{{item.DataTime}}</span>
+                <span class="value">{{item.Value}}</span>
+            </li>
+        </ul>
+    </div>
+
+    <!-- 选择时间段 -->
+    <van-popup 
+        v-model:show="showSelectDate"
+        :position="width>650?'center':'bottom'"
+        :style="width>650?{ width: '400px'}:''"
+        round
+    >
+        <div class="time-picker-wrap">
+            <van-picker-group
+                title="选择起始时间"
+                :tabs="['开始时间', '结束时间']"
+                next-step-text="下一步"
+                @cancel="showSelectDate=false"
+                @confirm="handleConfrimSelectDate"
+            >
+                <van-date-picker
+                    v-model="temStartDate"
+                    :min-date="minDate"
+                    :max-date="maxDate"
+                    :columns-type="['year','month']"
+                />
+                <van-date-picker
+                    v-model="temEndDate"
+                    :min-date="minDate" 
+                    :max-date="maxDate"
+                    :columns-type="['year','month']"
+                />
+            </van-picker-group>
+        </div>
+    </van-popup>
+
+    <!-- 图表类型 -->
+    <van-action-sheet 
+        v-model:show="showChartType" 
+        :actions="chartTypeOpts" 
+        @select="onChartTypeSelect" 
+    />
+
+    <!-- 调整上下限 -->
+    <van-popup 
+        v-model:show="showLimitPop"
+        :position="width>650?'center':'bottom'"
+        round
+        closeable
+        :style="width>650?{ width: '400px'}:''"
+    >
+        <div class="global-pop-wrap_mobile chart-set-limit-wrap">
+            <div class="head-box">
+                <div class="title">上下限设置</div>
+            </div>
+            <div class="content">
+                <!-- 左轴 -->
+                <div class="item-box">
+                    <span class="lable-text">左轴</span>
+                    <div class="input-box">
+                        <div class="item">
+                            <div class="type-text">上限</div>
+                            <div class="step-box">
+                                <van-stepper input-width="60px" :min="-99999999999999999" v-model.number="temLimitData.leftMax" />
+                            </div>
+                        </div>
+                        <div class="item">
+                            <div class="type-text">下限</div>
+                            <div class="step-box">
+                                <van-stepper input-width="60px" :min="-99999999999999999" v-model.number="temLimitData.leftMin" />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <!-- 右轴 -->
+                <div class="item-box" v-if="chartType==='同比图'">
+                    <span class="lable-text">右轴</span>
+                    <div class="input-box">
+                        <div class="item">
+                            <div class="type-text">上限</div>
+                            <div class="step-box">
+                                <van-stepper input-width="60px" :min="-99999999999999999" v-model.number="temLimitData.rightMax" />
+                            </div>
+                        </div>
+                        <div class="item">
+                            <div class="type-text">下限</div>
+                            <div class="step-box">
+                                <van-stepper input-width="60px" :min="-99999999999999999" v-model.number="temLimitData.rightMin" />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="bot-btn-box" @click="handleConfirmLimitChange">确定</div>
+        </div>
+    </van-popup>
+
+</template>
+
+<style lang="scss" scoped>
+.edb-chart-detail-page{
+    .chart-render-box{
+        .chart-box{
+            width: 100%;
+            height: 700px;
+        }
+    }
+}
+.top-filter-box{
+    padding: $page-padding;
+    display: flex;
+    align-items: center;
+    .select-date-box{
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background-color: $page-bg-grey;
+        padding: 0 32px;
+        border-radius: 12px;
+        flex: 1;
+        height: 72px;
+        .icon{
+            width: 32px;
+            height: 32px;
+            margin-right: 10px;
+        }
+    }
+    .chart-type-box{
+        cursor: pointer;
+        margin-left: 20px;
+        flex-shrink: 0;
+        display: flex;
+        align-items: center;
+        height: 72px;
+        padding: 0 16px;
+        color: $theme-color;
+        background-color: #F2F3FF;
+        border-radius: 12px;
+        .icon{
+            width: 32px;
+            height: 32px;
+            margin-right: 10px;
+        }
+    }
+}
+.data-source-auth{
+    padding: 0 $page-padding;
+    display: flex;
+    justify-content: space-between;
+    color: $font-grey;
+    margin-bottom: 20px;
+}
+.select-year-box{
+        width: 100vw;
+        position: relative;
+        margin-top: 30px;
+        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.08);
+        height: 88px;
+        display: flex;
+        align-items: center;
+        gap: 0 40px;
+        overflow-y: auto;
+        padding: 0 $page-padding;
+        &::-webkit-scrollbar{
+            height: 0;
+        }
+        .item{
+            cursor: pointer;
+            line-height: 88px;
+            position: relative;
+            height: 100%;
+            flex-shrink: 0;
+            display: inline-block;
+            font-size: 32px;
+            &.active{
+                color: $theme-color;
+                &::after{
+                    content: '';
+                    display: block;
+                    width: 50px;
+                    height: 6px;
+                    border-radius: 3px;
+                    background-color: $theme-color;
+                    position: absolute;
+                    bottom: 0;
+                    left: 50%;
+                    transform: translateX(-50%);
+                }
+            }
+        }
+}
+.calendar-type-box{
+    width: 404px;
+    margin: 30px auto;
+    text-align: center;
+    border: 1px solid $theme-color;
+    border-radius: 12px;
+    overflow: hidden;
+    span{
+        display: inline-block;
+        width: 200px;
+        height: 80px;
+        line-height: 80px;
+        color: $theme-color;
+        font-weight: bold;
+        &.active{
+            background-color: $theme-color;
+            color: #fff;
+        }
+    }
+}
+.chart-set-limit-wrap{
+    .head-box{
+        .title{
+            padding: 0 $page-padding;
+            font-size: 36px;
+            font-weight: 600;
+            line-height: 120px;
+        }
+    }
+    .bot-btn-box{
+        line-height: 112px;
+        text-align: center;
+        color: $theme-color;
+        font-size: 32px;
+    }
+    .content{
+        padding: $page-padding;
+        .item-box{
+            display: flex;
+            align-items: flex-end;
+            margin-bottom: 30px;
+            .lable-text{
+                width: 100px;
+            }
+            .input-box{
+                flex: 1;
+                display: flex;
+                .item{
+                    flex: 1;
+                    text-align: center;
+                    .type-text{
+                        margin-bottom: 40px;
+                    }
+                    .step-box{
+                        display: inline-block;
+                        :deep(.van-stepper){
+                            display: flex;
+                            justify-content: center;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+.edb-data-list-box{
+    padding: $page-padding;
+    .item{
+        display: flex;
+        height: 86px;
+        align-items: center;
+        border-bottom: 1px solid $border-color;
+        span{
+            flex-shrink: 0;
+        }
+        .frequency{
+            width: 150px;
+        }
+        .time{
+            flex: 1;
+        }
+        .value{
+            display: inline-block;
+            padding: 0 10px;
+            line-height: 48px;
+            background-color: #F2F3FF;
+            color: $theme-color;
+            border-radius: 4px;
+            min-width: 60px;
+            text-align: center;
+        }
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .edb-chart-detail-page{
+        .chart-render-box{
+            .chart-box{
+                height: 440px;
+            }
+        }
+    }
+    .top-filter-box{
+        padding: $page-padding;
+        .select-date-box{
+            padding: 0 16px;
+            border-radius: 6px;
+            height: 48px;
+            max-width: 300px;
+            .icon{
+                width: 20px;
+                height: 20px;
+            }
+        }
+        .chart-type-box{
+            margin-left: 10px;
+            height: 48px;
+            padding: 0 8px;
+            border-radius: 6px;
+            .icon{
+                width: 20px;
+                height: 20px;
+                margin-right: 10px;
+            }
+        }
+    }
+    .data-source-auth{
+        padding: 0 $page-padding;
+        margin-bottom: 10px;
+    }
+    .select-year-box{
+        margin-top: 15px;
+        height: 44px;
+        gap: 0 20px;
+        padding: 0 $page-padding;
+        box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08);
+        .item{
+            line-height: 44px;
+            font-size: 16px;
+            &.active{
+                &::after{
+                    width: 25px;
+                    height: 3px;
+                    border-radius: 3px;
+                }
+            }
+        }
+    }
+    .calendar-type-box{
+        width: 224px;
+        margin: 20px auto;
+        border-radius: 4px;
+        span{
+            width: 111px;
+            height: 38px;
+            line-height: 38px;
+        }
+    }
+    .chart-set-limit-wrap{
+            .head-box{
+                .title{
+                    font-size: 18px;
+                    line-height: 50px;
+                    padding-left: 16px;
+                }
+            }
+            .bot-btn-box{
+                font-size: 16px;
+                line-height: 56px;
+                border-top-width: 8px;
+            }
+            .content{
+                max-height: 500px;
+                padding: 30px;
+                .item-box{
+                    margin-bottom: 15px;
+                    .lable-text{
+                        width: 50px;
+                    }
+                    .input-box{
+                        .item{
+                            .type-text{
+                                margin-bottom: 20px;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    .edb-data-list-box{
+        padding: $page-padding;
+        .item{
+            height: 43px;
+            .frequency{
+                width: 80px;
+            }
+            .value{
+                padding: 0 5px;
+                line-height: 28px;
+                border: 2px;
+                min-width: 40px;
+            }
+        }
+    }
+}
+</style>

+ 522 - 0
src/views/dataEDB/components/EDBClassify.vue

@@ -0,0 +1,522 @@
+<script setup>
+import {reactive, ref,watch} from 'vue'
+import { useWindowSize } from '@vueuse/core'
+import apiDataEDB from '@/api/dataEDB'
+import { showDialog , showToast } from 'vant';
+import {useEDBDelete} from '../hooks/useEDBDelete'
+
+const {edbClassifyDelete}=useEDBDelete()
+const { width } = useWindowSize()
+
+const props=defineProps({
+    modelValue:{
+        type:Boolean,
+        default:false
+    }
+})
+const emits=defineEmits(['update:modelValue','change'])
+
+
+const langType=ref('zh')
+function langTypeChange(type){
+    langType.value=type
+}
+
+// 当前点击了哪些分类
+let selectClassifyNameStr=''
+let selectClassifyId=0
+function handleSelectClassify(level1,level2,level3){
+    // console.log(level1,level2,level3);
+    if(level1){
+        selectClassifyId=level1.ClassifyId
+        selectClassifyNameStr=`${level1.ClassifyName}`
+    }
+    if(level2){
+        selectClassifyId=level2.ClassifyId
+        selectClassifyNameStr=`${level1.ClassifyName}/${level2.ClassifyName}`
+    }
+    if(level3){
+        selectClassifyId=level3.ClassifyId
+        selectClassifyNameStr=`${level1.ClassifyName}/${level2.ClassifyName}/${level3.ClassifyName}`
+    }
+}
+
+// 关闭弹窗
+function handleClose(){
+    emits('change',{selectClassifyNameStr,selectClassifyId})
+    emits('update:modelValue',false)
+}
+
+// 设置显示的分类名称(中英文)
+function getClassifyItemName(item){
+    return langType.value==='zh'?item.ClassifyName:item.ClassifyNameEn||item.ClassifyName
+}
+
+// 获取分类数据
+const classifyList=ref([])
+async function getEDBClassifyList(){
+    const res=await apiDataEDB.edbClassifyList()
+    if(res.Ret===200){
+        classifyList.value=res.Data.AllNodes||[]
+        // langType.value=res.Data.Language==='CN'?'zh':'en'
+    }
+}
+getEDBClassifyList()
+
+const openClassify=ref([])//当前展开的分类
+
+// 分类操作数据
+const classifyState=reactive({
+    show:false,
+    title:'',
+    name:'',//输入框中的值
+    placeholderText:'',
+    type:'add',//新增、编辑
+    level:1,//1新增/编辑一级目录,2新增/编辑二级目录
+    level1Text:'',
+    level2Text:'',
+    parentId:0,
+    classifyId:0,
+})
+watch(
+    ()=>classifyState.show,
+    (n)=>{
+        if(!n){
+            classifyState.title=''
+            classifyState.name=''
+            classifyState.placeholderText=''
+            classifyState.type='add'
+            classifyState.level=1
+            classifyState.level1Text=''
+            classifyState.level2Text=''
+            classifyState.parentId=0
+            classifyState.classifyId=0
+        }
+    }
+)
+function handleAddLevel1(){
+    classifyState.title='添加一级目录'
+    classifyState.placeholderText='请输入一级目录名称'
+    classifyState.show=true
+}
+async function handleConfirmClassifyState(){
+    let params={}
+    if(classifyState.type==='add'){
+        params={
+            ClassifyName:classifyState.name,
+            Level:classifyState.level,
+            ParentId:classifyState.parentId
+        }
+    }else{
+        params={
+            ClassifyName:classifyState.name,
+            ClassifyId:classifyState.classifyId
+        }
+    }
+    const res=classifyState.type==='add'?await apiDataEDB.edbClassifyAdd(params):await apiDataEDB.edbClassifyEdit(params)
+    if(res.Ret===200){
+        getEDBClassifyList()
+        classifyState.show=false
+    }
+}
+
+// 显示分类操作按钮数据
+const classifyOptState=reactive({
+    show:false,
+    actions:[],
+    level:1,//点击的是几级
+    level1Data:null,
+    level2Data:null,
+    level3Data:null
+})
+watch(
+    ()=>classifyOptState.show,
+    (n)=>{
+        if(!n){
+            classifyOptState.actions=[]
+            classifyOptState.level=1
+            classifyOptState.level1Data=null
+            classifyOptState.level2Data=null
+            classifyOptState.level3Data=null
+        }
+    }
+)
+// 显示分类的具体操作选项
+function handleShowClassifyOpt(level,level1,level2,level3){
+    let optArr=[
+        {name:'重命名',type:'edit'},
+        {name:'删除',type:'delete',color:"#C54322"}
+    ]
+    if(level===1){
+        // 判断操作权限
+        if(level1.Button.AddButton){//添加权限
+            optArr.unshift({name:'添加二级目录',type:'add'})
+        }
+        if(!level1.Button.OpButton){//编辑权限
+            optArr=optArr.filter(item=>item.type!='edit')
+        }
+        if(!level1.Button.DeleteButton){//删除
+            optArr=optArr.filter(item=>item.type!='delete')
+        }
+    }else if(level===2){
+        // 判断操作权限
+        if(level2.Button.AddButton){//添加权限
+            optArr.unshift({name:'添加三级目录',type:'add'})
+        }
+        if(level2.Button.MoveButton){//移动权限
+            optArr.push({name:'移动至',type:'move'})
+        }
+        if(!level2.Button.OpButton){//编辑权限
+            optArr=optArr.filter(item=>item.type!='edit')
+        }
+        if(!level2.Button.DeleteButton){//删除
+            optArr=optArr.filter(item=>item.type!='delete')
+        }
+    }else if(level===3){
+        // 判断操作权限
+        if(level3.Button.MoveButton){//移动权限
+            optArr.push({name:'移动至',type:'move'})
+        }
+        if(!level3.Button.OpButton){//编辑权限
+            optArr=optArr.filter(item=>item.type!='edit')
+        }
+        if(!level3.Button.DeleteButton){//删除
+            optArr=optArr.filter(item=>item.type!='delete')
+        }
+    }
+    classifyOptState.actions=optArr
+    classifyOptState.level=level
+    classifyOptState.level1Data=level1
+    classifyOptState.level2Data=level2
+    classifyOptState.level3Data=level3
+    classifyOptState.show=true
+}
+function handleSelectOpt(e){
+    if(e.type==='add'){
+        classifyState.title=e.name
+        classifyState.placeholderText='请输入目录名称'
+        classifyState.type='add'
+        classifyState.level1Text=classifyOptState.level1Data?.ClassifyName
+        classifyState.level2Text=classifyOptState.level2Data?.ClassifyName
+        if(classifyOptState.level===1){
+            classifyState.parentId=classifyOptState.level1Data?.ClassifyId
+            classifyState.level=1
+        }
+        if(classifyOptState.level===2){
+            classifyState.parentId=classifyOptState.level2Data?.ClassifyId
+            classifyState.level=2
+        }
+        classifyState.show=true
+    }
+    if(e.type==='edit'){
+        classifyState.title='重命名'
+        classifyState.placeholderText='请输入目录名称'
+        classifyState.type='edit'
+        classifyState.level=classifyOptState.level
+        if(classifyOptState.level===1){
+            classifyState.classifyId=classifyOptState.level1Data?.ClassifyId
+            classifyState.name=classifyOptState.level1Data?.ClassifyName
+        }else if(classifyOptState.level===2){
+            classifyState.level1Text=classifyOptState.level1Data?.ClassifyName
+            classifyState.classifyId=classifyOptState.level2Data?.ClassifyId
+            classifyState.name=classifyOptState.level2Data?.ClassifyName
+        }else if(classifyOptState.level===3){
+            classifyState.level1Text=classifyOptState.level1Data?.ClassifyName
+            classifyState.level2Text=classifyOptState.level2Data?.ClassifyName
+            classifyState.classifyId=classifyOptState.level3Data?.ClassifyId
+            classifyState.name=classifyOptState.level3Data?.ClassifyName
+        }
+        classifyState.show=true
+    }
+    if(e.type==='delete'){
+        let data=null
+        if(classifyOptState.level===1){
+            data=classifyOptState.level1Data
+        }else if(classifyOptState.level===2){
+            data=classifyOptState.level2Data
+        }else if(classifyOptState.level===3){
+            data=classifyOptState.level3Data
+        }
+        edbClassifyDelete(data).then(res=>{
+            console.log(res===true);
+            if(res===true){
+                getEDBClassifyList()
+            }
+        })
+    }
+    if(e.type==='move'){
+        classifyMoveState.selectValue=''
+        classifyMoveState.tabIndex=0
+        if(classifyOptState.level===2){
+            //移动二级
+            classifyMoveState.options=classifyList.value.map(item=>{
+                return {
+                    ...item,
+                    Children:null
+                }
+            })
+            classifyMoveState.classifyId=classifyOptState.level2Data.ClassifyId
+            classifyMoveState.moveLevel=2
+        }
+        if(classifyOptState.level===3){
+            //移动三级
+            classifyMoveState.options=classifyList.value.map(item=>{
+                const children=item.Children.map(_item=>{
+                    return {
+                        ..._item,
+                        Children:null
+                    }
+                })
+                return {
+                    ...item,
+                    Children:children
+                }
+            })
+            classifyMoveState.classifyId=classifyOptState.level3Data.ClassifyId
+            classifyMoveState.moveLevel=3
+        }
+        
+        classifyMoveState.show=true
+    }
+    classifyOptState.show=false
+}
+
+// 移动分类数据
+const classifyMoveState=reactive({
+    show:false,
+    selectValue:'',
+    options:[],
+    classifyId:0,//要移动的分类id
+    tabIndex:0,//当前选择了哪一级的分类
+    moveLevel:2,//要移动的分类是哪级
+})
+function handleSelectMoveClassifyChange({value,selectedOptions,tabIndex}){
+    classifyMoveState.tabIndex=tabIndex
+}
+function handleConfirmMove(){
+    if(!classifyMoveState.selectValue){
+        showToast('请选择要移动至的目录')
+        return
+    }
+    if(classifyMoveState.moveLevel===3&&classifyMoveState.tabIndex!=1){
+        showToast('请选择要移动至的二级目录')
+        return
+    }
+    let NextClassifyId=0
+    if(classifyMoveState.moveLevel===2){
+        const index=classifyMoveState.options.findIndex(e=>e.ClassifyId===classifyMoveState.selectValue)
+        console.log(index);
+        NextClassifyId=classifyList.value[index].Children[0]?.ClassifyId
+    }else if(classifyMoveState.moveLevel===3){
+        let index1=0,index2=0;
+        classifyMoveState.options.forEach((e,idx)=>{
+            e.Children?.forEach((e2,idx2)=>{
+                if(e2.ClassifyId===classifyMoveState.selectValue){
+                    index1=idx
+                    index2=idx2
+                }
+            })
+        })
+        NextClassifyId=classifyList.value[index1].Children[index2].Children[0]?.ClassifyId
+    }
+    // console.log(NextClassifyId);
+    apiDataEDB.edbClassifyMove({
+        ClassifyId:classifyMoveState.classifyId,
+        ParentClassifyId:classifyMoveState.selectValue,
+        PrevClassifyId:0,
+        NextClassifyId:NextClassifyId
+    }).then(res=>{
+        if(res.Ret===200){
+            showToast('移动成功')
+            getEDBClassifyList()
+            classifyMoveState.show=false
+        }
+    })
+}
+
+
+
+defineExpose({classifyList,langTypeChange})
+</script>
+
+<template>
+    <van-popup 
+        :show="props.modelValue"
+        position="right"
+        closeable
+        :style="{width:width>650?'400px':'100%',height:'100%'}"
+        @click-close-icon="handleClose"
+    >
+        <div class="edb-classify-wrap">
+            <div class="top-box"></div>
+            <div class="classify-box">
+                <van-collapse v-model="openClassify" :border="false">
+                    <van-collapse-item
+                        v-for="level1 in classifyList"
+                        :key="level1.ClassifyId"
+                        :name="level1.ClassifyId"
+                        :is-link="false"
+                        :border="false"
+                    >
+                        <template #title>
+                            <div class="van-ellipsis" @click="handleSelectClassify(level1)">
+                                <van-icon :name="openClassify.includes(level1.ClassifyId)?'arrow-down':'arrow'" style="margin-right:4px;cursor: pointer;"/>
+                                <span :style="{color:selectClassifyId===level1.ClassifyId?'#0052D9':''}">{{getClassifyItemName(level1)}}</span>
+                            </div>
+                        </template>
+                        <template #value>
+                            <img style="width:22px;height:22px;cursor: pointer;" src="@/assets/imgs/dataEDB/icon_opt.png" alt="" @click.stop="handleShowClassifyOpt(1,level1)">
+                        </template>
+                        <div class="level2-box">
+                            <van-collapse-item
+                                v-for="level2 in level1.Children"
+                                :key="level2.ClassifyId"
+                                :name="level2.ClassifyId"
+                                :is-link="false"
+                                :border="false"
+                            >
+                                <template #title>
+                                    <div class="van-ellipsis" @click="handleSelectClassify(level1,level2)">
+                                        <van-icon :name="openClassify.includes(level2.ClassifyId)?'arrow-down':'arrow'" style="margin-right:4px;cursor: pointer;"/>
+                                        <span :style="{color:selectClassifyId===level2.ClassifyId?'#0052D9':''}">{{getClassifyItemName(level2)}}</span>
+                                    </div>
+                                </template>
+                                <template #value>
+                                    <img style="width:22px;height:22px;cursor: pointer;" src="@/assets/imgs/dataEDB/icon_opt.png" alt="" @click.stop="handleShowClassifyOpt(2,level1,level2)">
+                                </template>
+                                <div class="level3-box">
+                                    <van-collapse-item
+                                        v-for="level3 in level2.Children"
+                                        :key="level3.ClassifyId"
+                                        :title="getClassifyItemName(level3)" 
+                                        :name="level3.ClassifyId"
+                                        :is-link="false"
+                                        :border="false"
+                                    >
+                                        <template #title>
+                                            <div class="van-ellipsis" @click="handleSelectClassify(level1,level2,level3)">
+                                                <span :style="{color:selectClassifyId===level3.ClassifyId?'#0052D9':''}">{{getClassifyItemName(level3)}}</span>
+                                            </div>
+                                        </template>
+                                        <template #value>
+                                            <img style="width:22px;height:22px;cursor: pointer;" src="@/assets/imgs/dataEDB/icon_opt.png" alt="" @click.stop="handleShowClassifyOpt(3,level1,level2,level3)">
+                                        </template>
+                                    </van-collapse-item>
+                                </div>
+                            </van-collapse-item>
+                        </div>
+                    </van-collapse-item>
+                </van-collapse>
+            </div>
+            <div class="bot-btn-box">
+                <van-button type="primary" block @click="handleAddLevel1">添加一级目录</van-button>
+            </div>
+        </div>
+    </van-popup>
+
+    <!-- 分类操作选项 -->
+    <van-action-sheet
+        v-model:show="classifyOptState.show"
+        :actions="classifyOptState.actions"
+        cancel-text="取消"
+        @select="handleSelectOpt"
+    />
+
+    <!-- 创建/编辑分类 -->
+    <van-dialog 
+        v-model:show="classifyState.show" 
+        :title="classifyState.title" 
+        show-cancel-button
+        @confirm="handleConfirmClassifyState"
+    >
+        <div class="edit-classify-wrap">
+            <p v-if="classifyState.level1Text" style="margin-bottom:8px">一级目录:{{classifyState.level1Text}}</p>
+            <p v-if="classifyState.level2Text" style="margin-bottom:8px">二级目录:{{classifyState.level2Text}}</p>
+            <input class="input-box" type="text" :placeholder="classifyState.placeholderText" v-model="classifyState.name">
+        </div>
+    </van-dialog>
+
+    <!-- 移动分类 -->
+    <van-popup 
+        v-model:show="classifyMoveState.show" 
+        round 
+        position="bottom"
+    >
+        <van-cascader
+            v-model="classifyMoveState.selectValue"
+            title="移动至"
+            :options="classifyMoveState.options"
+            :field-names="{text:'ClassifyName',value:'ClassifyId',children:'Children'}"
+            @close="classifyMoveState.show = false"
+            @change="handleSelectMoveClassifyChange"
+        />
+        <div style="width:300px;margin:0 auto;padding:20px 0">
+            <van-button type="primary" round block @click="handleConfirmMove">确定</van-button>
+        </div>
+    </van-popup>
+</template>
+
+<style lang="scss" scoped>
+.edb-classify-wrap{
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    .top-box{
+        height: calc(var(--van-popup-close-icon-margin) + 50px);
+        background-color: #fff;
+        flex-shrink: 0;
+    }
+    .classify-box{
+        flex: 1;
+        overflow-y: auto;
+        :deep(.van-cell__title){
+            flex: 2;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            color: #333;
+        }
+        :deep(.van-collapse-item__content){
+            padding-right: 0;
+            padding-top: 0;
+            padding-bottom: 0;
+        }
+    }
+    .bot-btn-box{
+        padding: 48px;
+        flex-shrink: 0;
+    }
+    
+}
+
+.edit-classify-wrap{
+    padding: 32px 48px;
+    .input-box{
+        width: 100%;
+        box-sizing: border-box;
+        display: block;
+        padding: 24px 32px;
+        background-color: #f6f6f6;
+        border-radius: 12px;
+    }
+}
+
+
+@media screen and (min-width:$media-width){
+    .edb-classify-wrap{
+        .top-box{
+            height: calc(var(--van-popup-close-icon-margin) + 50px);
+        }
+        .bot-btn-box{
+            padding: 24px;
+        }
+    }
+    .edit-classify-wrap{
+        padding: 16px 24px;
+        .input-box{
+            padding: 12px 16px;
+            border-radius: 6px;
+        }
+    }
+}
+</style>

+ 237 - 0
src/views/dataEDB/components/EDBDataDetail.vue

@@ -0,0 +1,237 @@
+<script setup>
+import moment from 'moment'
+import {reactive, ref} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import { useRoute } from 'vue-router'
+
+const route=useRoute()
+
+const props=defineProps({
+    edbInfo:{
+        type:Object,
+        default:null,
+        require:true
+    },
+    langType:{//当前显示的语言
+        type:String,
+        default:'zh'
+    }
+})
+
+defineExpose({refreshList})
+
+const activeBaseInfo=ref([])
+
+// 获取指标数据
+const listState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false,
+    LatestDate:'',
+    insertDate:'',//插入的日期
+    classifyVal:''
+})
+async function getEDBDataList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbDataList({
+        PageSize: listState.pageSize,
+        CurrentIndex: listState.page,
+        EdbInfoId:route.query.edbInfoId
+    })
+    listState.loading=false
+    if(res.Ret===200){
+        const arr=res.Data?.Item.DataList||[]
+        listState.list=[...listState.list,...arr]
+        listState.LatestDate=res.Data?.Item.LatestDate
+        listState.finished=res.Data.Paging.IsEnd
+        const classifyNameArr=[]
+        res.Data.ClassifyList.forEach(e=>{
+            classifyNameArr.unshift(e.ClassifyName)
+        })
+        listState.classifyVal=classifyNameArr.join('/')
+    }
+}
+getEDBDataList()
+// 触底加载
+function onLoad(){
+    listState.page++
+    getEDBDataList()
+}
+// 刷新列表
+function refreshList(){
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getEDBDataList()
+}
+
+</script>
+
+<template>
+    <div class="edb-data-wrap">
+        <van-collapse  v-model="activeBaseInfo" :border="false">
+            <van-collapse-item title="指标信息" name="baseInfo" :border="false">
+                <template #right-icon>
+                    <van-icon :name="activeBaseInfo.includes('baseInfo')?'arrow-down':'arrow'" size="18"></van-icon>
+                </template>
+                <ul class="info-list">
+                    <li class="info-item">
+                        <span>指标ID</span>
+                        <span class="con">{{props.edbInfo.EdbCode}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>频度</span>
+                        <span class="con">{{props.langType==='zh'?props.edbInfo.Frequency:props.edbInfo.FrequencyEn||props.edbInfo.Frequency}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>单位</span>
+                        <span class="con">{{props.langType==='zh'?props.edbInfo.Unit:props.edbInfo.UnitEn||props.edbInfo.Unit}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>数据来源</span>
+                        <span class="con">{{props.edbInfo.SourceName}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>指标目录</span>
+                        <span class="con">{{listState.classifyVal}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>起始时间</span>
+                        <span class="con">{{props.edbInfo.StartDate}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>更新时间</span>
+                        <span class="con">{{props.edbInfo.ModifyTime}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>添加人</span>
+                        <span class="con">{{props.edbInfo.SysUserRealName}}</span>
+                    </li>
+                </ul>
+            </van-collapse-item>
+        </van-collapse>
+        <ul class="data-list-box">
+            <div class="label">数据信息</div>
+            <img v-if="listState.list.length==0&&listState.finished" class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
+            <van-list
+                v-model:loading="listState.loading"
+                :finished="listState.finished"
+                :finished-text="listState.list.length>0?'没有更多了':'暂无数据'"
+                :immediate-check="false"
+                @load="onLoad"
+            >
+                <li class="data-item" v-for="item in listState.list" :key="item">
+                    <span :class="['time',listState.LatestDate===item.DataTime?'new-data':'']">{{item.DataTime}}</span>
+                    <span class="val">{{item.Value}}</span>
+                </li>
+            </van-list>
+        </ul>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.edb-data-wrap{
+    :deep(.van-collapse-item__content){
+        padding: 0;
+    }
+}
+.info-list{
+    .info-item{
+        padding: 32px;
+        display: flex;
+        justify-content: space-between;
+        border-bottom: 1px solid $border-color;
+        color: #333;
+        font-size: 32px;
+        span{
+            flex-shrink: 0;
+        }
+        .con{
+            width: 60%;
+            text-align: right;
+            word-break: break-all;
+            word-wrap: break-word;
+        }
+    }
+}
+.data-list-box{
+    border-top: 10px solid #F2F6FA;
+    .label{
+        font-size: 36px;
+        font-weight: 500;
+        padding-top: 48px;
+        padding-left: 34px;
+        margin-bottom: 28px;
+    }
+    .data-item{
+        padding: 0 34px;
+        display: flex;
+        height: 86px;
+        justify-content: space-between;
+        align-items: center;
+        border-bottom: 1px solid $border-color;
+        span{
+            flex-shrink: 0;
+        }
+        .new-data{
+            position: relative;
+            &::after{
+                content: '';
+                display: block;
+                width: 8PX;
+                height: 8PX;
+                border-radius: 50%;
+                background-color: #D54941;
+                position: absolute;
+                left: 103%;
+                top: 50%;
+                transform: translateY(-50%);
+            }
+        }
+        .val{
+            display: inline-block;
+            padding: 0 10px;
+            line-height: 48px;
+            background-color: #FFF5ED;
+            color: $theme-color;
+            border-radius: 4px;
+            min-width: 60px;
+            text-align: center;
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .edb-data-wrap{
+        :deep(.van-cell){
+            padding-left: $page-padding;
+        }
+    }
+    .info-list{
+        .info-item{
+            padding: 16px 16px 16px $page-padding ;
+            font-size: 16px;
+        }
+    }
+    .data-list-box{
+        border-top-width: 8px;
+        .label{
+            font-size: 18px;
+            padding-top: 24px;
+            padding-left: $page-padding;
+            margin-bottom: 14px;
+        }
+        .data-item{
+            padding: 0 $page-padding;
+            height: 43px;
+            .val{
+                padding: 0 10px;
+                line-height: 28px;
+                border-radius: 4px;
+                min-width: 40px;
+            }
+        }
+    }
+}
+</style>

+ 124 - 0
src/views/dataEDB/components/EDBHistory.vue

@@ -0,0 +1,124 @@
+<script setup>
+import {nextTick, ref,watch} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import html2canvas from 'html2canvas'
+
+const props=defineProps({
+    show:{
+        type:Boolean,
+        default:false
+    },
+    edbInfoId:{
+        type:Number,
+        default:0
+    }
+})
+const emits=defineEmits(['update:show'])
+
+function handleClose(){
+    emits('update:show',false)
+}
+
+const imgUrl=ref('')
+function getImg(){
+    const targetEl = document.getElementById('render-wrap');
+        if(targetEl){
+            html2canvas(targetEl,{
+                backgroundColor: "#ffffff",
+                useCORS: true, // 允许图片跨域
+                allowTaint: true, // 在渲染前测试图片
+                imageTimeout: 0, // 加载延时
+                scale:3,
+            }).then(res=>{
+                let img = res.toDataURL("image/png");
+                // console.log(img);
+                imgUrl.value=img
+            })
+        }
+}
+
+// 获取记录
+const treeData=ref({})
+async function getHistory(){
+    const res=await apiDataEDB.edbCreateHistory({EdbInfoId:Number(props.edbInfoId)})
+    if(res.Ret===200){
+        treeData.value=res.Data
+        nextTick(()=>{
+            getImg()
+        })
+    }
+}
+watch(
+    ()=>props.show,
+    ()=>{
+        if(props.show&&props.edbInfoId){
+            getHistory()
+        }
+    }
+)
+
+</script>
+
+<template>
+    <van-popup 
+        :show="props.show"
+        round
+        closeable
+        @click-overlay="handleClose"
+        @click-close-icon="handleClose"
+    >
+        <div class="img-wrap">
+            <h2 class="name">指标溯源</h2>
+            <img class="img" :src="imgUrl" alt="">
+        </div>
+    </van-popup>
+    <div class="render-wrap" id="render-wrap" v-if="props.show">
+        <vue3TreeOrg
+            :data="treeData"
+            center
+            :props="{
+                label: 'EdbName',
+                children: 'Child',
+            }"
+            :horizontal="false"
+            :toolBar="{scale: false, restore: false, expand: false, zoom: false, fullscreen: false, }"
+        />
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.img-wrap{
+    width: 90vw;
+    max-width: 600PX;
+    max-height: 80vh;
+    overflow-y: auto;
+    .name{
+        line-height: 30PX;
+        font-size: 16PX;
+        text-align: center;
+    }
+    .img{
+        display: block;
+        width: 100%;
+        margin: 0 auto;
+    }
+}
+.render-wrap{
+    position: absolute;
+    z-index: -1;
+    width: 400PX;
+    height: 1000PX;
+    :deep(.tree-org-node__content){
+        background-color: #409EFF;
+        color: #fff;
+        border-radius: 4PX;
+    }
+    :deep(.tree-org-node__children){
+        .tree-org-node__content{
+            background-color: #F2F6FA;
+            color: #333333;
+            border-radius: 4PX;
+        }
+    }
+}
+</style>

+ 291 - 0
src/views/dataEDB/components/EditBaseEDB.vue

@@ -0,0 +1,291 @@
+<script setup>
+import {watch,ref, reactive, computed} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+import {edbFrequencyOpts,edbUnitOpts} from '../util/config'
+import { showToast } from 'vant'
+
+const props=defineProps({
+    modelValue:{
+        type:Boolean,
+        default:false
+    },
+    edbInfoId:{
+        type:Number,
+        default:0
+    },//当前指标id
+    baseInfo:{},//新增指标时传来的初始数据
+})
+const emits=defineEmits(['update:modelValue','success','addSuccess'])
+
+const edbNameInputFocus=ref(false)//指标名称输入框聚焦状态
+
+const formState=reactive({
+    name:'',
+    classify:'',
+    frequency:'',
+    unit:''
+})
+// 获取指标详情
+async function getEDBInfo(){
+    const res=await apiDataEDB.getBaseEdbInfo({EdbInfoId:props.edbInfoId})
+    if(res.Ret===200){
+        formState.name=res.Data.EdbName
+        formState.classify=res.Data.ClassifyId
+        formState.frequency=res.Data.Frequency
+        formState.unit=res.Data.Unit
+
+        getEdbClassifyList()
+    }
+}
+watch(
+    ()=>props.modelValue,
+    ()=>{
+        if(props.modelValue){
+            // 编辑
+            if(props.edbInfoId){
+                getEDBInfo()
+            }else{
+                // 新增
+                formState.name=props.baseInfo.edb_name
+                formState.frequency=props.baseInfo.frequency
+                formState.unit=props.baseInfo.unit
+                getEdbClassifyList()
+            }
+        }
+    }
+)
+
+function handleClose(){
+    emits('update:modelValue',false)
+}
+
+// 获取指标库分类
+const edbClassifyList=ref([])
+function getEdbClassifyList(){
+    apiDataEDB.edbClassifyList().then(res=>{
+        if(res.Ret===200){
+            edbClassifyList.value=res.Data.AllNodes||[]
+        }
+    })
+}
+const showSelectClassify=ref(false)
+const selectClassifyNameStr=computed(()=>{
+    if(!formState.classify) return ''
+    let str=''
+    edbClassifyList.value.forEach(level1=>{
+        level1.Children?.forEach(level2=>{
+            level2.Children?.forEach(level3=>{
+                if(level3.ClassifyId===formState.classify){
+                    str=`${level1.ClassifyName}/${level2.ClassifyName}/${level3.ClassifyName}`
+                }
+            })
+        })
+    })
+    return str
+
+})
+
+// 选择频率
+const showSelectFrequency=ref(false)
+const frequencyOpts=edbFrequencyOpts.map(item=>{
+    return {
+        text:item,
+        value:item
+    }
+})
+function onConfirmSelectFrequency(e){
+    formState.frequency=e.selectedValues[0]
+    showSelectFrequency.value=false
+}
+
+// 选择单位
+const showSelectUnit=ref(false)
+const unitOpts=edbUnitOpts.map(item=>{return{text:item,value:item}})
+function onConfirmSelectUnit(e){
+    formState.unit=e.selectedValues[0]
+    showSelectUnit.value=false
+}
+
+// 保存编辑
+async function handleSave(){
+    let params={
+        ClassifyId:formState.classify,
+        EdbName:formState.name,
+        Frequency:formState.frequency,
+        Unit:formState.unit
+    }
+    if(!params.EdbName){
+        showToast('指标名称不能为空')
+        return
+    }
+    if(!params.ClassifyId){
+        showToast('目录名称不能为空')
+        return
+    }
+    if(!params.Frequency){
+        showToast('频率不能为空')
+        return
+    }
+    if(!params.Unit){
+        showToast('单位不能为空')
+        return
+    }
+    if(props.edbInfoId){
+        params={
+            EdbInfoId:props.edbInfoId,
+            ...params
+        }
+        const res=await apiDataEDB.editBaseEdbInfo(params)
+        if(res.Ret===200){
+            showToast(res.Msg)
+            emits('update:modelValue',false)
+            emits('success',params)
+        }
+    }else{
+        params={
+            ...props.baseInfo,
+            ...params
+        }
+        const res=await apiDataEDB.AddBaseEdbInfo(params)
+        if(res.Ret===200){
+            showToast('新增指标成功!')
+            emits('update:modelValue',false)
+            emits('addSuccess')
+        }
+    }
+    
+}
+
+</script>
+
+<template>
+    <van-popup 
+        :show="props.modelValue"
+        position="bottom"
+        style="width:100%;height:100%"
+    >
+        <div class="edit-baseEDB-wrap">
+            <van-field 
+                v-model="formState.name" 
+                label="指标名称" 
+                placeholder="指标名称"
+                input-align="right"
+                @focus="edbNameInputFocus=true"
+                @blur="edbNameInputFocus=false"
+            >
+                <template #right-icon>
+                    <svg class="edit-icon" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48" fill="none">
+                        <path d="M23.4 13.2L34.8 24.6L19.4 40H8V28.6L23.4 13.2ZM23.4 19L12 30.4V36H17.6L29 24.6L23.4 19ZM28.8 8L40 19.4L36.6 22.8L25.2 11.4L28.8 8Z" :fill="edbNameInputFocus?'#0052D9':'#333333'"/>
+                    </svg>
+                </template>
+            </van-field>
+            <van-field 
+                :modelValue="selectClassifyNameStr"
+                readonly
+                label="所属目录" 
+                placeholder="请选择所属目录"
+                input-align="right"
+                right-icon="arrow"
+                @click-input="showSelectClassify=true"
+            />
+            <van-field 
+                :modelValue="formState.frequency"
+                readonly
+                label="频率" 
+                placeholder="请选择频率"
+                input-align="right"
+                right-icon="arrow"
+                @click-input="showSelectFrequency=true"
+            />
+            <van-field 
+                :modelValue="formState.unit"
+                readonly
+                label="单位" 
+                placeholder="请选择单位"
+                input-align="right"
+                right-icon="arrow"
+                @click-input="showSelectUnit=true"
+            />
+
+            <div class="btn-box">
+                <van-button @click="handleClose">取消</van-button>
+                <van-button type="primary" @click="handleSave">保存</van-button>
+            </div>
+            
+        </div>
+    </van-popup>
+
+    <!-- 选择分类 -->
+    <van-popup 
+        v-model:show="showSelectClassify" 
+        round 
+        position="bottom"
+    >
+        <van-cascader
+            v-model="formState.classify"
+            title="选择目录"
+            :options="edbClassifyList"
+            :field-names="{text:'ClassifyName',value:'ClassifyId',children:'Children'}"
+            @close="showSelectClassify = false"
+        />
+    </van-popup>
+
+    <!-- 选择频率 -->
+    <van-popup 
+        v-model:show="showSelectFrequency" 
+        round 
+        position="bottom"
+    >
+        <van-picker
+            title="请选择频率"
+            :columns="frequencyOpts"
+            @cancel="showSelectFrequency=false"
+            @confirm="onConfirmSelectFrequency"
+        />
+    </van-popup>
+
+    <!-- 选择单位 -->
+    <van-popup 
+        v-model:show="showSelectUnit" 
+        round 
+        position="bottom"
+    >
+        <van-picker
+            title="选择单位"
+            :columns="unitOpts"
+            @cancel="showSelectUnit=false"
+            @confirm="onConfirmSelectUnit"
+        />
+    </van-popup>
+</template>
+
+<style lang="scss" scoped>
+.edit-baseEDB-wrap{
+    .edit-icon{
+        width: 48px;
+        height: 48px;
+    }
+    :deep(.van-field__right-icon){
+        width: 60px;
+    }
+    .btn-box{
+        margin-top: 50PX;
+        text-align: center;
+        .van-button{
+            width: 150PX;
+            margin: 0 10PX;
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .edit-baseEDB-wrap{
+        .edit-icon{
+            width: 24px;
+            height: 24px;
+        }
+        :deep(.van-field__right-icon){
+            width: 30px;
+        }
+    }
+}
+</style>

+ 118 - 0
src/views/dataEDB/components/SetEDBInfoEn.vue

@@ -0,0 +1,118 @@
+<script setup>
+import { reactive, watch } from "vue"
+import apiDataEDB from '@/api/dataEDB'
+import { showToast } from "vant"
+
+
+const props=defineProps({
+    show:{
+        type:Boolean,
+        default:false
+    },
+    edbInfo:null
+})
+const emit=defineEmits(['update:show'])
+
+function handleClose(){
+    emit('update:show',false)
+}
+
+const formState=reactive({
+    enName:'',
+    enUnit:''
+})
+watch(
+    ()=>props.show,
+    ()=>{
+        if(props.show){
+            formState.enName=props.edbInfo?.EdbNameEn||''
+            formState.enUnit=props.edbInfo?.UnitEn||''
+        }else{
+            formState.enName=''
+            formState.enUnit=''
+        }
+    }
+)
+
+async function handleSave(){
+    const res=await apiDataEDB.edbInfoEnEdit({
+        EdbInfoId:props.edbInfo.EdbInfoId,
+        EdbNameEn:formState.enName,
+        UnitEn:formState.enUnit
+    })
+    if(res.Ret===200){
+        showToast(res.Msg)
+        handleClose()
+    }
+}
+
+</script>
+
+<template>
+    <van-dialog 
+        :show="props.show" 
+        title="设置英文名称" 
+        show-cancel-button
+        @confirm="handleSave"
+        @cancel="handleClose"
+    >
+        <div class="edb-info-set-en-wrap">
+            <div class="info-item">
+                <h3 class="label">指标名称</h3>
+                <p class="text">{{props.edbInfo?.EdbName}}</p>
+            </div>
+            <div class="info-item" v-if="props.edbInfo?.Unit&&props.edbInfo?.Unit!='无'">
+                <h3 class="label">单位</h3>
+                <p class="text">{{props.edbInfo?.Unit}}</p>
+            </div>
+            <div class="info-item">
+                <input class="input" type="text" placeholder="请输入英文指标名称" v-model="formState.enName">
+            </div>
+            <div class="info-item" v-if="props.edbInfo?.Unit&&props.edbInfo?.Unit!='无'">
+                <input class="input" type="text" placeholder="请输入英文单位" v-model="formState.enUnit">
+            </div>
+        </div>
+    </van-dialog>
+</template>
+
+<style lang="scss" scoped>
+.edb-info-set-en-wrap{
+    padding: 48px;
+    .info-item{
+        margin-bottom: 32px;
+        .label{
+            font-size: 32px;
+            margin: 0;
+            line-height: 48px;
+        }
+        .text{
+            color: $font-grey;
+            margin: 0;
+        }
+        .input{
+            background-color: $page-bg-grey;
+            box-sizing: border-box;
+            display: block;
+            width: 100%;
+            padding: 24px 32px;
+            border-radius: 12px;
+        }
+    }
+}
+@media screen and (min-width:$media-width){
+    .edb-info-set-en-wrap{
+        padding: 24px;
+        .info-item{
+            margin-bottom: 16px;
+            .label{
+                font-size: 16px;
+                line-height: 28px;
+            }
+            .input{
+                padding: 12px 16px;
+                border-radius: 6px;
+            }
+        }
+    }
+}
+</style>

+ 222 - 0
src/views/dataEDB/components/SetEDBNewData.vue

@@ -0,0 +1,222 @@
+<script setup>
+import { reactive, watch,ref } from "vue"
+import apiDataEDB from '@/api/dataEDB'
+import { showToast } from "vant"
+import moment from "moment"
+
+const props=defineProps({
+    show:{
+        type:Boolean,
+        default:false
+    },
+    edbInfo:null
+})
+const emit=defineEmits(['update:show'])
+
+function handleClose(){
+    emit('update:show',false)
+}
+
+const minDate=new Date(1970, 0, 1)
+const maxDate=new Date(2050, 11, 31)
+const currentDate=ref(moment().format('YYYY-MM-DD').split('-'))
+const showDate=ref(false)
+function handleConfirmDate({ selectedValues, selectedOptions }){
+    console.log(selectedValues);
+    formState.date=selectedValues.join('-')
+    showDate.value=false
+}
+
+const formState=reactive({
+    date:'',
+    val:''
+})
+
+watch(
+    ()=>props.show,
+    ()=>{
+        if(props.show){
+            if(props.edbInfo?.DataInsertConfig.Date){
+                formState.date=props.edbInfo?.DataInsertConfig.Date
+                const val=props.edbInfo?.DataInsertConfig.Value
+                formState.val=val?Number(val):''
+                currentDate.value=formState.date.split('-')
+            }
+        }else{
+            formState.date=''
+            formState.val=''
+        }
+    }
+)
+
+async function handleSave(){
+    if(!formState.date){
+        showToast('请选择日期')
+        return
+    }
+    if(!formState.val){
+        showToast('请填写值')
+        return
+    }
+    
+    const res=await apiDataEDB.edbNewDataEdit({
+        EdbInfoId:props.edbInfo.EdbInfoId,
+        Date:formState.date,
+        Value:formState.val
+    })
+    if(res.Ret===200){
+        showToast('保存成功')
+        handleClose()
+    }
+}
+
+</script>
+
+<template>
+    <van-dialog 
+        :show="props.show" 
+        :title="props.edbInfo?.DataInsertConfig.Date?'编辑最新值':'设置最新值'" 
+        show-cancel-button
+        @confirm="handleSave"
+        @cancel="handleClose"
+    >
+        <div class="set-edb-newdata-wrap">
+            <div class="edb-name">
+                <div class="label">指标名称</div>
+                <div class="grey-text">{{props.edbInfo?.EdbName}}</div>
+            </div>
+            <div class="flex-data-box">
+                <div class="item">
+                    <div class="label">频度</div>
+                    <div class="grey-text">{{props.edbInfo?.Frequency}}</div>
+                </div>
+                <div class="item">
+                    <div class="label">最新日期</div>
+                    <div class="grey-text">{{props.edbInfo?.LatestDate}}</div>
+                </div>
+                <div class="item">
+                    <div class="label">最新值</div>
+                    <div class="grey-text">{{props.edbInfo?.LatestValue}}</div>
+                </div>
+            </div>
+            <div class="input-box">
+                <div class="label">预测日期</div>
+                <div class="select-date-box" @click="showDate=true">
+                    <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
+                        <path d="M20 6H12L12 3H10L10 6H6C4.89543 6 4 6.89543 4 8V26C4 27.1046 4.89543 28 6 28H26C27.1046 28 28 27.1046 28 26V8C28 6.89543 27.1046 6 26 6H22V3H20L20 6ZM10 10L12 10L12 8H20L20 10L22 10V8H26V12H6V8H10L10 10ZM6 14H26V26H6L6 14Z" fill="#999999"/>
+                    </svg>
+                    <input type="text" readonly placeholder="请选择日期" v-model="formState.date">
+                </div>
+            </div>
+            <div class="input-box">
+                <div class="label">预测值</div>
+                <input class="val-input" type="number" placeholder="输入值" v-model.number="formState.val"> 
+            </div>
+        </div>
+    </van-dialog>
+    
+    <!-- 选择日期 -->
+    <van-popup
+        v-model:show="showDate"
+        position="bottom"
+    >
+        <van-date-picker
+            v-model="currentDate"
+            title="选择日期"
+            :min-date="minDate"
+            :max-date="maxDate"
+            @confirm="handleConfirmDate"
+            @cancel="showDate=false"
+        />
+    </van-popup>
+    
+</template>
+
+<style lang="scss" scoped>
+.set-edb-newdata-wrap{
+    padding: 20px 42px;
+    .label{
+        line-height: 48px;
+        font-size: 32px;
+    }
+    .grey-text{
+        color: $font-grey;
+    }
+    .flex-data-box{
+        margin: 40px 0;
+        display: flex;
+        justify-content: space-between;
+        .item{
+            // flex: 1;
+            text-align: center;
+            padding: 0 10px;
+        }
+    }
+    .input-box{
+        margin-top: 40px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .select-date-box{
+            background-color: $page-bg-grey;
+            display: flex;
+            align-items: center;
+            padding: 12px 32px;
+            max-width: 350px;
+            border-radius: 12px;
+            svg{
+                width: 32px;
+                height: 32px;
+                flex-shrink: 0;
+            }
+            input{
+                background-color: transparent;
+                max-width: 220px;
+            }
+        }
+        .val-input{
+            background-color: $page-bg-grey;
+            padding: 12px 32px;
+            border-radius: 12px;
+            max-width: 200px;
+            text-align: center;
+        }
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .set-edb-newdata-wrap{
+        padding: 10px 21px;
+        .label{
+            line-height: 28px;
+            font-size: 16px;
+        }
+        .flex-data-box{
+            margin: 20px 0;
+            .item{
+                padding: 0 5px;
+            }
+        }
+        .input-box{
+            margin-top: 20px;
+            .select-date-box{
+                padding: 6px 16px;
+                max-width: 180px;
+                border-radius: 6px;
+                svg{
+                    width: 20px;
+                    height: 20px;
+                }
+                input{
+                    width: 110px;
+                }
+            }
+            .val-input{
+                padding: 6px 16px;
+                border-radius: 6px;
+                max-width: 100px;
+            }
+        }
+    }
+}
+</style>

+ 63 - 0
src/views/dataEDB/hooks/useEDBDelete.js

@@ -0,0 +1,63 @@
+// 目录或者指标的删除
+import apiDataEDB from '@/api/dataEDB'
+import { showDialog , showToast } from 'vant';
+
+
+export function useEDBDelete(){
+    // 删除分类
+    async function handleClassifyDelete(data){
+        const res=await apiDataEDB.edbClassifyDelete({
+            ClassifyId:data.ClassifyId,
+            EdbInfoId:data.EdbInfoId
+        })
+        if(res.Ret===200){
+            showToast('删除成功')
+            return true
+        }
+    }
+
+    async function edbClassifyDelete(data){
+        const res=await apiDataEDB.edbClassifyDeleteCheck({
+            ClassifyId:data.ClassifyId,
+            EdbInfoId:data.EdbInfoId
+        })
+        if(res.Ret===200){
+            if([1,3,4].includes(res.Data.DeleteStatus)){
+                let message=res.Data.TipsMsg
+                if(res.Data.DeleteStatus === 1) message='该目录关联指标不可删除'
+                if(res.Data.DeleteStatus === 3) message='当前指标已用作画图,不可删除'
+                showDialog({
+                    title: '删除失败',
+                    message: message,
+                    confirmButtonText:'知道了'
+                })
+                
+            }else if(res.Data.DeleteStatus === 0 && !data.EdbCode){
+                await showDialog({
+                    title: '提示',
+                    message: '确定删除当前目录吗?',
+                    showCancelButton:true,
+                })
+                return  handleClassifyDelete(data)
+            }else if(res.Data.DeleteStatus === 0 && data.EdbCode){
+                await showDialog({
+                    title: '提示',
+                    message: '删除后指标和指标值均不可使用,确认删除吗?',
+                    showCancelButton:true,
+                })
+                return handleClassifyDelete(data)
+            }else if(res.Data.DeleteStatus === 2){
+                await showDialog({
+                    title: '提示',
+                    message: '确认删除当前目录及包含的子目录吗?',
+                    showCancelButton:true,
+                })
+                return handleClassifyDelete(data)
+            }
+        }
+    }
+
+    return {
+        edbClassifyDelete
+    }
+}

+ 20 - 0
src/views/dataEDB/util/config.js

@@ -0,0 +1,20 @@
+//指标频率配置项
+export const edbFrequencyOpts=['日度','周度','旬度','月度','季度','年度']
+
+// 指标单位配置项
+export const edbUnitOpts=[
+    '无',
+    '万吨',
+    '亿元',
+    '元',
+    '元/吨',
+    '元/湿吨',
+    '千克',
+    '吨',
+    '短吨',
+    '美元/吨',
+    '万平方米',
+    '美元/桶',
+    '美分/加仑',
+    '手'
+]

+ 29 - 0
src/views/myETA/ChartDetail.vue

@@ -6,6 +6,7 @@ import apiCorrelationChart from '@/api/correlationChart'
 import apiLineEquationChart from '@/api/lineEquationChart'
 import apiStatisticFeatureChart from '@/api/statisticFeatureChart'
 import apiMyETAChart from '@/api/myETA'
+import apiDataEDB from '@/api/dataEDB'
 import { useRoute, useRouter } from 'vue-router'
 import {useChartRender} from '@/hooks/chart/render'
 import {yearSelectOpt,sameOptionType} from '@/hooks/chart/config'
@@ -18,6 +19,7 @@ import { useWindowSize } from '@vueuse/core'
 import {setClipboardData} from '@/hooks/common'
 import SetChartEnName from '@/components/SetChartEnName.vue'
 import {useCachedViewsStore} from '@/store/modules/cachedViews'
+import AddChartToMyETA from '@/views/chartETA/components/AddChartToMyETA.vue'
 
 const { width, height } = useWindowSize()
 const cachedViewsStore=useCachedViewsStore()
@@ -32,6 +34,19 @@ let CHARTINS=null//图表实例
 // 获取当前图表所在分类下的所有图表数据 用于上一张下一张切换
 let allChartList=ref([])
 async function getAllChartList(){
+    // 如果是从ETA指标库的指标关联的图列表跳转来的
+    if(route.query.from==='edbRelationChart'){
+        const res=await apiDataEDB.edbRelationChartList({
+            PageSize:1000000,
+            CurrentIndex:1,
+            EdbInfoId:route.query.edbInfoId
+        })
+        if(res.Ret===200){
+            allChartList.value=res.Data.List||[]
+        }
+        return
+    }
+    // 我的图库列表跳转来的
     if(!route.query.cid) return
     const res=await apiMyETAChart.myChartList({
         CurrentIndex:1,
@@ -482,6 +497,9 @@ function handleEditEnNameSuccess(){
     reloadChartInfo()
 }
 
+// 加入我的图库
+const isShowAddToMyETADialog=ref(false)
+
 </script>
 
 <template>
@@ -747,6 +765,9 @@ function handleEditEnNameSuccess(){
             <div class="item" @click.stop="handleShowCopyTo" v-if="$route.query.iscommon!='true'">
                 复制到
             </div>
+            <div class="item" @click.stop="isShowAddToMyETADialog=true" v-if="$route.query.from==='edbRelationChart'">
+                加入我的图库
+            </div>
             <div class="item" @click.stop="showSaveChartOther=true" v-if="chartInfo.Button.IsCopy">
                 另存为
             </div>
@@ -821,6 +842,14 @@ function handleEditEnNameSuccess(){
             @success="handleEditEnNameSuccess"
         />
     </van-popup>
+
+    <!-- 加入我的图库 -->
+    <AddChartToMyETA 
+        :isShowDialog="isShowAddToMyETADialog"
+        :dialogPosition="width>650?'center':'bottom'"
+        :chartInfo="chartInfo"
+        @close="isShowAddToMyETADialog=false"
+    />
 </template>
 
 <style lang="scss" scoped>

+ 14 - 1
src/views/myETA/components/EDBInfo.vue

@@ -5,6 +5,9 @@ import {sameOptionType} from '@/hooks/chart/config'
 import _ from 'lodash'
 // import apiChart from '@/api/chart'
 import SourceDetail from '@/views/chartETA/components/SourceDetail.vue'
+import {useCopyEdbData} from '@/hooks/edb/useCopyEdbData'
+
+const {copyData} =useCopyEdbData()
 
 const leadUnitOpt=[{text:'年'}, {text:'季'}, {text:'月'}, {text:'周'}, {text:'天'}]//领先指标频度配置
 
@@ -128,6 +131,10 @@ function handleLeadUnitChange(e){
 // 显示数据来源历史
 const showSourceDetail=ref(false)
 
+function handleCopyEDBData(){
+    copyData(props.data)
+}
+
 </script>
 
 <template>
@@ -143,9 +150,10 @@ const showSourceDetail=ref(false)
                     <van-icon name="arrow" v-if="item.key==='SourceName'&&data.EdbType===2" @click="showSourceDetail=true" />
                 </li>
             </ul>
-            <div class="opt-box" v-if="sameOptionType.includes(chartInfo.ChartType) && chartInfo.ChartType!==5 && chartInfo.Source===1">
+            <div class="opt-box">
                 <div class="lable">指标操作</div>
                 <div class="con">
+                    <template v-if="sameOptionType.includes(chartInfo.ChartType) && chartInfo.ChartType!==5 && chartInfo.Source===1">
                     <div class="item-box" v-if="showYOptionsHandle">
                         <div 
                             :class="['radio-box',temData.IsOrder?'active':'']"
@@ -229,6 +237,11 @@ const showSourceDetail=ref(false)
                             <van-stepper input-width="40px" v-model.number="temData.ChartWidth" />
                         </div>
                     </div>
+                    </template>
+                    <div class="item-box">
+                        <van-button color="#F2F3FF" size="small" style="color:#0052D9;margin-right:10px" @click="handleCopyEDBData">复制数据</van-button>
+                        <van-button color="#0052D9" size="small">查看数据</van-button>
+                    </div>
                 </div>
             </div>
         </div>

+ 222 - 69
src/views/tabbar/Home.vue

@@ -1,16 +1,23 @@
 <script setup>
-import {ref} from 'vue'
+import {ref,computed} from 'vue'
 import { useRouter } from "vue-router";
 import {apiMenuList} from '@/api/user'
 import {getStaticImg} from '@/hooks/common'
 import {useCachedViewsStore} from '@/store/modules/cachedViews'
+import { showToast } from 'vant';
+import { useWindowSize } from '@vueuse/core'
 
+const { width } = useWindowSize()
 const cachedViewsStore=useCachedViewsStore()
 cachedViewsStore.removeCaches(-1)
 
 const router=useRouter()
 
 function goNext(path){
+    if(!path){
+        showToast('功能开发中,敬请期待!')
+        return
+    }
     const routerEl=router.resolve({path})
     window.open(routerEl.href,'_blank')
 }
@@ -19,94 +26,186 @@ if(!localStorage.getItem('token')){
     router.replace('/login')
 }
 
+const language_version=ref('zh')//语言版本 zh en 
+function languageVersionChange(){
+    if(language_version.value==='zh'){
+        language_version.value='en'
+    }else{
+        language_version.value='zh'
+    }
+}
+const topImg=computed(()=>{
+    let url=''
+    if(width.value>650){//大屏
+        if(language_version.value==='zh'){
+            url='https://hzstatic.hzinsights.com/static/ETA_mobile/tabbar_home_topimg_en_big.png'
+        }else{
+            url='https://hzstatic.hzinsights.com/static/ETA_mobile/tabbar_home_topimg_zh_big.png'
+        }
+    }else{
+        if(language_version.value==='zh'){
+            url='https://hzstatic.hzinsights.com/static/ETA_mobile/tabbar_home_topimg_en.png'
+        }else{
+            url='https://hzstatic.hzinsights.com/static/ETA_mobile/tabbar_home_topimg_zh.png'
+        }
+    }
+    return url
+})
 /**
  * name 显示的名称
  * key 对应接口中的 name
  * level 说明该菜单在数据中的第几级查找
+ * type 类型 zh中文 en英文
  */
 const menuConfig=[
     {
         name:'中文研报',
+        des:'研报一体化管理',
         key:'研报列表',
+        type:'zh',
         level:2,
         path:'/report/list',
-        icon:getStaticImg('report/report_icon.png'),
+        icon:getStaticImg('tabbar/icon_report.png'),
+        backgroundColor:'#FFFBF6',
         show:false
     },
     {
-        name:'英文研报',
+        name:'English Research Report',
+        des:'Integrated Research Report Management',
         key:'英文研报',
+        type:'en',
         level:2,
         path:'/reportEn/list',
-        icon:getStaticImg('report/report_icon_en.png'),
+        icon:getStaticImg('tabbar/icon_report.png'),
+        backgroundColor:'#FFFBF6',
         show:false
     },
     {
         name:'智能PPT',
+        des:"支持共享协作编辑",
         key:'智能ppt',
+        type:'zh',
         level:1,
         path:'/ppt/index',
-        icon:getStaticImg('ppt/ppt_icon_zh.png'),
+        icon:getStaticImg('tabbar/icon_PPT.png'),
+        backgroundColor:'#FFF5F3',
         show:false
     },
     {
-        name:'英文PPT',
+        name:'PPT in English',
+        des:'Support for collaborative editing',
         key:'英文ppt',
+        type:'en',
         level:1,
         path:'/ppten/index',
-        icon:getStaticImg('ppt/ppt_icon_en.png'),
+        icon:getStaticImg('tabbar/icon_PPT.png'),
+        backgroundColor:'#FFF5F3',
         show:false
     },
     {
-        name:'My ETA',
-        key:'My ETA',
+        name:'数据源',
+        des:'数据对接与整合',
+        key:'数据源',
+        type:'zh',
         level:1,
-        path:'/myETA/index',
-        icon:getStaticImg('myETA/icon_myETA_logo.png'),
+        path:'',
+        icon:getStaticImg('tabbar/icon_dataSource.png'),
+        backgroundColor:'#F8F9FF',
+        show:false
+    },
+    {
+        name:'指标库',
+        des:'数据归类与分析',
+        key:'ETA指标库',
+        type:'zh',
+        level:1,
+        path:'/dataEDB/index',
+        icon:getStaticImg('tabbar/icon_EDB.png'),
+        backgroundColor:'#F5FAFF',
+        show:false
+    },
+    {
+        name:'预测指标',
+        des:'模型预测趋势',
+        key:'ETA预测指标',
+        type:'zh',
+        level:1,
+        path:'',
+        icon:getStaticImg('tabbar/icon_preEDB.png'),
+        backgroundColor:'#FFF5F3',
         show:false
     },
     {
         name:'ETA图库',
+        des:'数据可视化平台',
         key:'ETA图库',
+        type:'zh',
         level:1,
         path:'/chartETA/list',
-        icon:getStaticImg('chartETA/icon_chartETA_logo.png'),
+        icon:getStaticImg('tabbar/icon_chart.png'),
+        backgroundColor:'#F8F9FF',
         show:false
-    }
+    },
+    {
+        name:'My ETA',
+        des:'图表收藏',
+        key:'My ETA',
+        type:'zh',
+        level:1,
+        path:'/myETA/index',
+        icon:getStaticImg('tabbar/icon_myChart.png'),
+        backgroundColor:'#F5FAFF',
+        show:false
+    },
+    {
+        name:'ETA表格',
+        des:'快速建立平衡表',
+        key:'ETA表格',
+        type:'zh',
+        level:1,
+        path:'',
+        icon:getStaticImg('tabbar/icon_table.png'),
+        backgroundColor:'#FFFBF6',
+        show:false
+    },
 ]
-const menuOpts=ref([])
+const menuOpts=computed(()=>{
+    // 过滤中英文
+    let arr=menuConfig.filter(item=>item.type===language_version.value)
+    
+    // 根据菜单数据权限过滤
+    arr.forEach(item=>{
+        if(item.level===1){
+            resMenuList.value.forEach(f=>{
+                if(f.name.trim()===item.key){
+                    item.show=true
+                }
+            })
+        }
+        if(item.level===2){
+            resMenuList.value.forEach(f=>{
+                f.children.forEach(s=>{
+                    if(s.name.trim()===item.key){
+                        item.show=true
+                    }
+                })
+            })
+        }
+    })
+
+    arr=arr.filter(item=>item.show)
+    return arr||[]
+})
 
 // 获取菜单权限数据
+const resMenuList=ref([])
 async function getMenuList(){
     menuConfig.forEach(item=>{
         item.show=false
     })
     const res=await apiMenuList()
     if(res.Ret===200){
-        if(res.Data.List){
-            const arr=res.Data.List
-            menuConfig.forEach(item=>{
-                if(item.level===1){
-                    arr.forEach(f=>{
-                        if(f.name.trim()===item.key){
-                            item.show=true
-                        }
-                    })
-                }
-                if(item.level===2){
-                    arr.forEach(f=>{
-                        f.children.forEach(s=>{
-                            if(s.name.trim()===item.key){
-                                item.show=true
-                            }
-                        })
-                    })
-                }
-            })
-            menuOpts.value=menuConfig.filter(item=>item.show)
-        }else{
-            menuOpts.value=[]
-        }
+        resMenuList.value=res.Data.List||[]
     }
 }
 getMenuList()
@@ -115,23 +214,29 @@ getMenuList()
 
 <template>
     <div class="home-page">
+        <img 
+            class="top-img"
+            :src="topImg" 
+            alt=""
+            @click="languageVersionChange"
+        >
+
         <div class="list">
             <div 
                 v-for="item in menuOpts"
                 :key="item.name"
-                class="item-box" 
+                :class="['item-box',item.type==='en'?'item-box_en':'']"
+                :style="{backgroundColor:item.backgroundColor}"
                 @click="goNext(item.path)"
             >
-                <img :src="item.icon" alt="">
-                <div>{{item.name}}</div>
+                <img class="icon" :src="item.icon" alt="">
+                <div class="content">
+                    <div class="name">{{item.name}}</div>
+                    <div class="des">{{item.des}}</div>
+                </div>
             </div>
-            
-            <div class="item-box" style="border:none;height:0"></div>
-            <div class="item-box" style="border:none;height:0"></div>
-            <div class="item-box" style="border:none;height:0"></div>
-            <div class="item-box" style="border:none;height:0"></div>
-            <div class="item-box" style="border:none;height:0"></div>
-            <div class="item-box" style="border:none;height:0"></div>
+            <div class="item-box" style="height:0;min-height:0;padding:0"></div>
+            <div class="item-box" style="height:0;min-height:0;padding:0"></div>
         </div>
         
     </div>
@@ -140,28 +245,53 @@ getMenuList()
 <style lang="scss" scoped>
 .home-page{
     padding: 30px 34px;
+    padding-bottom: 140px;
+    .top-img{
+        display: block;
+        width: 100%;
+        margin-bottom: 40px;
+        cursor: pointer;
+    }
     .list{
         display: flex;
-        justify-content: space-between;
+        gap: 20px;
         flex-wrap: wrap;
         .item-box{
-            width: 326px;
-            height: 326px;
-            margin-bottom: 20px;
+            width: 331px;
+            min-height: 228px;
+            padding: 40px 20px;
             display: flex;
-            flex-direction: column;
             justify-content: center;
             align-items: center;
-            font-size: 32px;
-            border: 1px solid $border-color;
             border-radius: 32px;
-            filter: drop-shadow(3px 4px 12px rgba(0, 0, 0, 0.08));
-            img{
-                width: 140px;
-                height: 140px;
-                margin-bottom: 40px;
+            cursor: pointer;
+            .icon{
+                width: 90px;
+                height: 90px;
+                margin-right: 12px;
+            }
+            .content{
+                .name{
+                    font-size: 36px;
+                    font-weight: 600;
+                }
+                .des{
+                    font-size: 24px;
+                    color: $font-grey_999;
+                    margin-top: 12px;
+                }
+            }
+        }
+        .item-box_en{
+            flex-direction: column;
+            justify-content: flex-start;
+            align-items: flex-start;
+            .icon{
+                width: 48px;
+                height: 48px;
+                margin-bottom: 12px;
+                margin-right: 0;
             }
-
         }
     }
 }
@@ -169,18 +299,41 @@ getMenuList()
 @media screen and (min-width:$media-width){
     .home-page{
         padding: 30px 34px;
+        max-width: 1180px;
+        margin: 0 auto;
+        padding-bottom: 30px;
+        .top-img{
+            width: 100%;
+            margin-bottom: 20px;
+        }
         .list{
+            gap: 20px;
             justify-content: center;
             .item-box{
-                width: 240px;
-                height: 240px;
-                margin: 0 20px 20px;
-                font-size: 20px;
+                width: 260px;
+                min-height: 161px;
                 border-radius: 32px;
-                img{
-                    width: 80px;
-                    height: 80px;
-                    margin-bottom: 30px;
+                padding: 36px 11px;
+                .icon{
+                    width: 70px;
+                    height: 70px;
+                    margin-right: 6px;
+                }
+                .content{
+                    .name{
+                        font-size: 32px;
+                    }
+                    .des{
+                        font-size: 20px;
+                        margin-top: 6px;
+                    }
+                }
+            }
+            .item-box_en{
+                .icon{
+                    width: 70px;
+                    height: 70px;
+                    margin-bottom: 6px;
                 }
             }
         }

+ 5 - 5
src/views/tabbar/Index.vue

@@ -79,8 +79,8 @@ function goPage(item){
             align-items: center;
             height: 100%;
             .icon{
-                width: 40px;
-                height: 40px;
+                width: 48px;
+                height: 48px;
             }
             .text{
                 font-size: 20px;
@@ -95,9 +95,9 @@ function goPage(item){
         .tabbar-item-con{
             background-color: #F2F3FF;
             border-radius: 112px;
-            .text{
-                color: $theme-color;
-            }
+            // .text{
+            //     color: $theme-color;
+            // }
         }
     }
 }