jwyu 1 year ago
parent
commit
7e1f09f4c3

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
     "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": {

+ 74 - 3
src/api/dataEDB.js

@@ -5,8 +5,18 @@ export default{
     /**
      * ETA指标列表
      */
-    edbList(params){
-        return get('/datamanage/classify/edb_info/list?ClassifyId=535',params)
+    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)
     },
 
     /**
@@ -165,6 +175,67 @@ export default{
      */
     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)
+    }
 }

+ 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;

+ 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轴

+ 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')

+ 19 - 1
src/router/dataEDB.js

@@ -35,7 +35,25 @@ export const dataEDBRoutes=[
         name:"DataEDBDetail",
         component: () => import("@/views/dataEDB/Detail.vue"),
         meta: { 
-            title: "ETA指标详情",
+            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: "添加指标"
         },
     },
 ]

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

@@ -0,0 +1,136 @@
+<script setup name="DataEDBAddBaseEDB">
+import {ref} from 'vue'
+import {baseEDBSourceOpts} from './util/config'
+
+// 数据来源
+const dataSourceOpts=baseEDBSourceOpts.map(item=>{return{text:item,value:item}})
+const showSelectDataSource=ref(false)
+const dataSource=ref('wind')
+function onConfirmDataSource(e){
+    dataSource.value=e.selectedValues[0]
+    showSelectDataSource.value=false
+}
+
+// 指标名称/ID
+const searchEDBTxt=ref('')
+// 公司ID
+const searchCompanyTxt=ref('')
+
+
+
+
+
+
+
+</script>
+
+<template>
+    <div class="add-baseEDB-page">
+        <van-cell title="数据来源" is-link :value="dataSource" @click="showSelectDataSource=true"/>
+        <div class="search-box">
+            <van-search
+                v-model="searchEDBTxt"
+                show-action
+                shape="round"
+                placeholder="指标ID/指标名称"
+                @search="onSearch"
+            >
+                <template #action>
+                    <span class="right-btn">查询</span>
+                </template>
+            </van-search>
+        </div>
+        <div class="search-box" style="padding-top:0" v-show="dataSource==='彭博财务'">
+            <van-search
+                v-model="searchCompanyTxt"
+                show-action
+                shape="round"
+                placeholder="公司ID"
+                @search="onSearch"
+            >
+                <template #action>
+                    <span class="right-btn">查询</span>
+                </template>
+            </van-search>
+        </div>
+        <van-cell title="指标ID" :value="dataSource" />
+        <van-cell title="起始时间" :value="dataSource" />
+        <van-cell title="终止时间" :value="dataSource" />
+        <ul class="data-value-wrap">
+            <li class="item" style="font-weight:bold">时间</li>
+            <li class="item" style="font-weight:bold">值</li>
+            <li class="item">2023-08-20</li>
+            <li class="item"><span class="val-box">123</span></li>
+        </ul>
+    </div>
+
+    <!-- 选择数据来源 -->
+    <van-popup 
+        v-model:show="showSelectDataSource"
+        round
+        position="bottom"
+    >
+        <van-picker
+            title="数据来源"
+            :columns="dataSourceOpts"
+            @confirm="onConfirmDataSource"
+            @cancel="showSelectDataSource=false"
+        />
+    </van-popup>
+</template>
+
+<style lang="scss" scoped>
+.add-baseEDB-page{
+    :deep(.van-cell__right-icon){
+        color: #333;
+    }
+}
+.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;
+        }
+    }
+}
+</style>

+ 222 - 13
src/views/dataEDB/Detail.vue

@@ -3,26 +3,166 @@ import {ref} from 'vue'
 import apiDataEDB from '@/api/dataEDB'
 import EDBChartDetailVue from './components/EDBChartDetail.vue'
 import EDBDataDetailVue from './components/EDBDataDetail.vue'
-import { useRoute } from 'vue-router'
+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('chart')
 
+const chartDetailIns=ref(null)//图表组件实例
+const dataDetailIns=ref(null)//数据详情组件实例
+
 // 获取指标详情
 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)})
+// 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
+        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()
+        }
     }
 }
-getEDBInfo()
 
+//点击编辑
+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>
@@ -34,35 +174,82 @@ getEDBInfo()
         </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 
+                <EDBChartDetailVue
+                    ref="chartDetailIns" 
                     :edbInfo="edbInfo"
                 />
             </van-tab>
             <van-tab title="数据详情" name="data">
-                <EDBDataDetailVue 
+                <EDBDataDetailVue
+                    ref="dataDetailIns"
                     :edbInfo="edbInfo"
                 />
             </van-tab>
         </van-tabs>
         <div class="fix-bottom-box">
-            <div class="item">
+            <div class="item" @click="handleRefreshEDBInfo">
                 <img class="icon" src="@/assets/imgs/report/icon_refresh.png" alt="">
                 <span>刷新</span>
             </div>
-            <div class="item">
+            <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">
+            <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">
+            <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>
@@ -76,6 +263,9 @@ getEDBInfo()
         line-height: 52px;
     }
 }
+.edb-detail-page{
+    padding-bottom: 120px;
+}
 .fix-bottom-box{
     position: fixed;
     height: 112px;
@@ -85,6 +275,7 @@ getEDBInfo()
     right: 0;
     bottom: 0;
     display: flex;
+    background-color: #fff;
     .item{
         flex: 1;
         display: flex;
@@ -98,4 +289,22 @@ getEDBInfo()
     }
 
 }
+.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;
+    }
+}
 </style>

+ 32 - 69
src/views/dataEDB/Index.vue

@@ -2,19 +2,18 @@
 import {reactive,ref, watch} from 'vue'
 import apiDataEDB from '@/api/dataEDB'
 import EDBClassify from './components/EDBClassify.vue'
-import EditBaseEDB from './components/EditBaseEDB.vue'
-import {useEDBDelete} from './hooks/useEDBDelete'
 import { showToast } from 'vant'
 import {useRouter} from 'vue-router'
+import {useCachedViewsStore} from '@/store/modules/cachedViews'
 
-const {edbClassifyDelete} =useEDBDelete()
+const cachedViewsStore=useCachedViewsStore()
 const router=useRouter()
 
 
 const listState = reactive({
     list:[],
     page:1,
-    pageSize:15,
+    pageSize:20,
     finished:false,
     loading:false,
     total:0,
@@ -22,19 +21,17 @@ const listState = reactive({
     activeClassifyId:0,
 })
 async function getEDBList(){
-    const res=await apiDataEDB.edbList()
+    const res=await apiDataEDB.edbChartList({
+        PageSize:listState.pageSize,
+        CurrentIndex:listState.page,
+        ClassifyId:listState.activeClassifyId
+    })
     if(res.Ret===200){
-        listState.loading=false
-        if(!res.Data){
-            listState.finished=true
-            listState.total=0
-            return
-        }
-        
-        listState.finished=true
-        const arr=res.Data.EdbInfoList||[]
+        listState.loading=false        
+        const arr=res.Data.List||[]
         listState.list=[...listState.list,...arr]
-        listState.total=20
+        listState.total=res.Data.Paging.Totals
+        listState.finished=res.Data.Paging.IsEnd
     }
 }
 getEDBList()
@@ -45,13 +42,20 @@ function onLoad(){
 }
 // 刷新列表
 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('敬请期待')
 }
 
@@ -103,36 +107,6 @@ const activeEditEDBData=ref(null)//当前编辑的指标项数据
 const showEditBaseEDB=ref(false)// 显示编辑基础指标
 // 指标操作
 function handleEDBOpt(type,data){
-    // 编辑
-    if(type==='edit'){
-        activeEditEDBData.value=data
-        // 基础指标
-        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(item.Source===27){
-            showToast('代码运算指标请在pc端操作')
-        }
-        //数据调整
-        if(item.Source===40){
-            showToast('数据调整指标请在pc端操作')
-        }
-    }
-
-    // 删除
-    if(type==='delete'){
-        edbClassifyDelete(data).then((res)=>{
-            if(res===true){
-                refreshEBDList()
-            }
-        })
-    }
-
     // 移动至
     if(type==='move'){
         handleShowEDBMove(data)
@@ -160,15 +134,6 @@ function handleEDBOpt(type,data){
 
     edbOptState.show=false
 }
-//编辑基础指标信息成功回调
-function handleEditBaseEdbSuccess(e){
-    // 更新列表中指标的名称
-    listState.list.forEach(item=>{
-        if(item.EdbInfoId===e.EdbInfoId){
-            item.ClassifyName=e.EdbName
-        }
-    })
-}
 
 // 移动指标
 const edbMoveState=reactive({
@@ -238,6 +203,12 @@ function handleEDBDetail(item){
     })
 }
 
+async function goSearch(){
+    // 删除指标搜索页的缓存
+    await cachedViewsStore.removeCaches('DataEDBSearch')
+    router.push('/dataEDB/search')
+}
+
 </script>
 
 <template>
@@ -249,7 +220,7 @@ function handleEDBDetail(item){
                     readonly 
                     placeholder="请输入指标ID/指标名称"
                     style="flex:1;padding-left:0"
-                    @click-input="$router.push('/chartETA/search')"
+                    @click-input="goSearch"
                 />
                 <div class="lang-icon icon">
                     <img v-if="true" src="@/assets/imgs/chartETA/lang-icon.png" alt="">
@@ -259,7 +230,7 @@ function handleEDBDetail(item){
             <div class="count-box">
                 <div class="con">
                     <div class="van-ellipsis label">{{listState.activeClassifyName||'全部'}}</div>
-                    <span class="num">共70个指标</span>
+                    <span class="num">共{{listState.total}}个指标</span>
                 </div>
                 <img class="menu-icon" src="@/assets/imgs/dataEDB/icon_menu.png" alt="" @click="showClassifyPop=true">
             </div>
@@ -275,10 +246,10 @@ function handleEDBDetail(item){
                 <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">{{item.ClassifyName}}</div>
+                        <div class="van-multi-ellipsis--l2 name">{{item.EdbName}}</div>
                         <van-image
                             class="img"
-                            src=""
+                            :src="item.ChartImage"
                         />
                         <div>
                             <span class="time">{{item.StartDate}}</span>
@@ -317,7 +288,8 @@ function handleEDBDetail(item){
         close-on-click-action
         :actions="[
             {
-                name:'添加指标'
+                name:'添加指标',
+                path:'/dataEDB/addbaseEDB'
             },
             {
                 name:'计算指标'
@@ -344,8 +316,6 @@ function handleEDBDetail(item){
             <ul class="edb-opt-list">
                 <!-- 计算指标查看 -->
                 <!-- <li class="item" v-if="seeComputeEDBInfo(edbOptState.data)">查看</li> -->
-                <!-- <li class="item color-blue" v-if="edbOptState.data?.Button.OpButton" @click="handleEDBOpt('edit',edbOptState.data)">编辑</li>
-                <li class="item color-red" v-if="edbOptState.data?.Button.DeleteButton" @click="handleEDBOpt('delete',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>
@@ -353,13 +323,6 @@ function handleEDBDetail(item){
         </template>
     </van-action-sheet>
 
-    <!-- 编辑基础指标 -->
-    <EditBaseEDB 
-        v-model="showEditBaseEDB" 
-        :edbInfoId="activeEditEDBData?.EdbInfoId"
-        @success="handleEditBaseEdbSuccess"
-    />
-
     <!-- 指标移动 -->
     <van-popup 
         v-model:show="edbMoveState.show" 

+ 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(){
+    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,
+            edbType:item.EdbType
+        }
+    })
+}
+
+</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: 326px;
+            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>

+ 707 - 15
src/views/dataEDB/components/EDBChartDetail.vue

@@ -1,10 +1,19 @@
 <script setup>
-import {ref,onMounted} from 'vue'
+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()
@@ -17,9 +26,361 @@ const props=defineProps({
     }
 })
 
+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 chartLang='zh'
+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 = chartLang=='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(chartLang=='en'){
+		yTitleStyle.cursor='pointer'
+		if(yTitleText=='英文单位'){
+			yTitleStyle.color="#999"
+		}
+	}
+    let yItem = {
+		title: {
+			text: yTitleText,
+			align: 'high',
+			rotation: 0,
+			y: -15,
+			offset: 0,
+			style:yTitleStyle
+		},
+		labels: {
+			formatter: function (ctx) {
+				return ctx.value;
+			},
+			align: 'center',
+		},
+		min: Number(chartInfo.value.MinValue),
+		max: Number(chartInfo.value.MaxValue),
+		...seasonOptions.yAxis,
+	};
+
+    // 图例名称和图例文字样式
+	let dataName = chartLang=='zh'?chartInfo.value.EdbName:chartInfo.value.EdbNameEn?chartInfo.value.EdbNameEn:'无英文名称'
+	let color = chartLang=='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: chartLang=='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:  chartLang=='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:  chartLang=='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()
+    })
 }
 
 // 获取指标曲线图数据
@@ -31,7 +392,53 @@ async function getEDBLineChartData(){
         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()
     }
 }
 
@@ -53,11 +460,41 @@ const chartTypeOpts=[
         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='公历'
 }
 
 
@@ -72,13 +509,72 @@ const selectEndDate=ref('')
 function handleConfrimSelectDate(e){
     selectStartDate.value=e[0].selectedValues.join('-')
     selectEndDate.value=e[1].selectedValues.join('-')
+    selectYear.value=''
+    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>
 
@@ -108,26 +604,38 @@ const selectYear=ref(10)
         <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>
         <!-- 选择时间选项 -->
-        <van-tabs 
-            v-model:active="selectYear"
-            title-active-color="#0052D9"
-            title-inactive-color="#333"
-            line-width="16"
-        >
-            <van-tab 
-                :title="item.name" 
-                :name="item.value" 
+        <div class="select-year-box" v-if="chartType!=='季节性图'">
+            <span 
+                :class="['item',selectYear===item.value?'active':'']"
                 v-for="item in yearOpts" 
-                :key="item.value" 
-            />
-        </van-tabs>
-
+                :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>
 
     <!-- 选择时间段 -->
@@ -167,6 +675,60 @@ const selectYear=ref(10)
         @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>
@@ -221,5 +783,135 @@ const selectYear=ref(10)
     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{
+            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;
+        }
+    }
+}
 </style>

+ 190 - 3
src/views/dataEDB/components/EDBDataDetail.vue

@@ -1,13 +1,200 @@
 <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
+    }
+})
+
+defineExpose({refreshList})
+
+const activeBaseInfo=ref([])
+
+// 获取指标数据
+const listState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false,
+    LatestDate:'',
+    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>
-        data
+    <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.edbInfo.Frequency}}</span>
+                    </li>
+                    <li class="info-item">
+                        <span>单位</span>
+                        <span class="con">{{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>
+            <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;
+        }
+    }
+}
 </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>

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

@@ -0,0 +1,102 @@
+<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;
+        }
+    }
+}
+</style>

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

@@ -0,0 +1,185 @@
+<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: 280px;
+            border-radius: 12px;
+            svg{
+                width: 32px;
+                height: 32px;
+            }
+            input{
+                background-color: transparent;
+                width: 180px;
+            }
+        }
+        .val-input{
+            background-color: $page-bg-grey;
+            padding: 12px 32px;
+            border-radius: 12px;
+            max-width: 200px;
+            text-align: center;
+        }
+    }
+}
+</style>

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

@@ -17,4 +17,11 @@ export const edbUnitOpts=[
     '美元/桶',
     '美分/加仑',
     '手'
+]
+
+// 添加基础指标来源
+export const baseEDBSourceOpts=[
+    'wind','同花顺','彭博','彭博财务','路透','手工指标','隆众指标','SMM','Mysteel','郑商所',
+    '大商所','上期所','中金所','上期能源','欧洲天然气','中国煤炭市场网','谷歌出行指数',
+    'EIA STEO报告','UN','卓创数据(红桃3)','百川盈孚','国家统计局','富宝数据',
 ]