jwyu 1 年之前
父节点
当前提交
823ea1a7b7

+ 1 - 1
src/api/dataEDB.js

@@ -15,7 +15,7 @@ export default{
      * @param CurrentIndex
      * @param PageSize
      */
-    edbChartSearchList(params){
+    edbSearchList(params){
         return get('/datamanage/edb_info/filter_by_es',params)
     },
 

+ 16 - 0
src/router/dataEDB.js

@@ -56,4 +56,20 @@ export const dataEDBRoutes=[
             title: "添加指标"
         },
     },
+    {
+        path:"/dataEDB/calculate/index",
+        name:"DataEDBCalculateIndex",
+        component: () => import("@/views/dataEDB/calculate/Index.vue"),
+        meta: { 
+            title: "计算指标"
+        },
+    },
+    {
+        path:"/dataEDB/calculate/detail",
+        name:"DataEDBCalculateDetail",
+        component: () => import("@/views/dataEDB/calculate/Detail.vue"),
+        meta: { 
+            title: "指标运算"
+        },
+    },
 ]

+ 2 - 1
src/views/dataEDB/Index.vue

@@ -296,7 +296,8 @@ async function goSearch(){
                 path:'/dataEDB/addbaseEDB'
             },
             {
-                name:'计算指标'
+                name:'计算指标',
+                path:'/dataEDB/calculate/index'
             },
             {
                 name:'替换指标'

+ 2 - 2
src/views/dataEDB/SearchList.vue

@@ -17,13 +17,13 @@ const listState = reactive({
 })
 async function getList(){
     listState.loading=true
-    const res=await apiDataEDB.edbChartSearchList({
+    const res=await apiDataEDB.edbSearchList({
         CurrentIndex:listState.page,
         PageSize:listState.pageSize,
         KeyWord:keyword.value
     })
+    listState.loading=false
     if(res.Ret===200){
-        listState.loading=false
         if(!res.Data){
             listState.finished=true
             return

+ 17 - 0
src/views/dataEDB/calculate/Detail.vue

@@ -0,0 +1,17 @@
+<script setup name="DataEDBCalculateDetail">
+import {ref} from 'vue'
+import { useRoute } from "vue-router";
+import FormulaCalculate from './components/FormulaCalculate.vue';
+
+
+const route=useRoute()
+const type=ref(route.query.type||'')//计算类型
+document.title=route.query.name||'指标运算'
+
+ 
+</script>
+
+<template>
+    <!-- 指标运算 -->
+    <FormulaCalculate v-if="['4'].includes(type)"/>
+</template>

+ 426 - 0
src/views/dataEDB/calculate/Index.vue

@@ -0,0 +1,426 @@
+<script setup name="DataEDBCalculateIndex">
+import {ref} from 'vue'
+import { Dialog } from 'vant';
+import { useRouter } from 'vue-router';
+
+const router=useRouter()
+
+//计算类型说明tips
+const calculateTypeTipsMap=new Map([
+	[4,`指标运算:选择指标参数,按照输入的计算公式进行计算,生成新的指标<br>
+	在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天`],
+	[5,`累计值转月值计算方法:<br>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:45%">1月无值:1月=2月/2</span>
+		<span style="width:40%">1月有值:1月=1月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">2月=2月/2</span>
+		<span style="width:40%">2月=2月-1月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">3月=3月-2月</span>
+		<span style="width:40%">3月=3月-2月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">4月=4月-3月</span>
+		<span style="width:40%">4月=4月-3月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">以此类推</span>
+		<span style="width:40%">以此类推</span>
+	</p>
+	<p>特别说明:若1月和2月均无值,则该年不做计算</p>`],
+	['toMonthSeason',`1、累计值转月值计算方法:<br>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:45%">1月无值:1月=2月/2</span>
+		<span style="width:40%">1月有值:1月=1月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">2月=2月/2</span>
+		<span style="width:40%">2月=2月-1月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">3月=3月-2月</span>
+		<span style="width:40%">3月=3月-2月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">4月=4月-3月</span>
+		<span style="width:40%">4月=4月-3月</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">以此类推</span>
+		<span style="width:40%">以此类推</span>
+	</p>
+	<p>特别说明:若1月和2月均无值,则该年不做计算</p>
+	2、累计值转季值计算方法:<br>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:45%">1季度无值:1季度=2季度/2 </span>
+		<span style="width:40%">1季度有值:1季度=1季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">2季度=2季度/2</span>
+		<span style="width:40%">2季度=2季度-1季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">3季度=3季度-2季度</span>
+		<span style="width:40%">3季度=3季度-2季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">4季度=4季度-3季度</span>
+		<span style="width:40%">4季度=4季度-3季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">以此类推</span>
+		<span style="width:40%">以此类推</span>
+	</p>
+	<p>特别说明:若1季度和2季度均无值,则该年不做计算</p>`],
+	[6,`同比公式:今年同期/去年同期-1<br>
+	1、锁定当前数值对应的日期<br>
+	2、匹配上一年同期:寻找过去一年有数值的对应日期中,
+	与当前数值对应日期相等或者最为接近的那一天,如果有
+	两个日期与当前数值对应日期的距离相等,则取降序日期
+	排列下的第一个日期。<br>
+	3、取到匹配的上一年同期对应的数值<br>
+	4、将当期的数值与上一年匹配的同期的值计算比例<br>
+	5、将计算得到的比例填充至当前数值对应的日期,生成
+	新的数据序列<br>
+	6、遍历允许跨年,对于日度/周度/季度数据,遍历往前
+	最多35天,往后最多35天`],
+	[7,`同差公式:今年同期-去年同期<br>
+	1、锁定当前数值对应的日期<br>
+	2、匹配上一年同期:寻找过去一年有数值的对应日期中,
+	与当前数值对应日期相等或者最为接近的那一天,如果有
+	两个日期与当前数值对应日期的距离相等,则取降序日期
+	排列下的第一个日期。<br>
+	3、取到匹配的上一年同期对应的数值<br>
+	4、将当期的数值与上一年匹配的同期的值计算差值<br>
+	5、将计算得到的差值填充至当前数值对应的日期,生成
+	新的数据序列<br>
+	6、遍历允许跨年,对于日度/周度/季度数据,遍历往前
+	最多35天,往后最多35天`],
+	[8,`计算公式:=AVERAGE(N个数值的和),N为取数个数<br>
+	1、计算当前的数值的N值移动平均,则时间向前追溯
+	N个值(包括当前值),如果遇到空格值的日期,则自
+	动跳过空格数值,继续往前追溯<br>
+	2、如果当前日期对应的原始数据为空值,则N值移动
+	平均也为空值`],
+	[12,`环比公式:(当期-上期)/上期<br>
+	1、选择当期对应值,若是当期值为空,则环比值为空;若当期有值,上期值往 前遍历查询,默认N等于1,找最近的一个上期值;可根据设置的N值选择最 近的第N个上期值 <br>
+	2、将当期的数值与匹配到的上期值按照公式进行计算 <br>
+	3、将计算得到值填充至当期数值对应的日期,生成新的 数据序列<br>
+	4、原始数据中出现0和负值时,提示该指标不能进行环比运算`],
+	[13,`环差公式:当期-上期<br>
+	1、选择当期对应值,若是当期值为空,则环差值为空;若当期有值,上期值往 前遍历查询,默认N等于1,找最近的一个上期值;可根据设置的N值选择最 近的第N个上期值找到最近的一个上期值即可<br>
+	2、将当期的数值与匹配到的上期值按照公式进行计算<br>
+	3、将计算得到值填充至当期数值对应的日期,生成新的数据序列`],
+	[14,`升频:支持转换所有频度指标为日度指标<br>
+	1、规则:若将月度指标转换为日度指标,如当前月为9月,但9月数据还未更新,假设9月数据是9.30更新,则9.1~9.29的数据等于8.31的数据<br>
+	2、其他频度规则相同
+	`],
+	['joint',`1、直接拼接说明:将指标A和指标B按照选取的拼接日期进行拼接;<br>
+	2、累计值同比拼接说明:指标A最后一个12月31日有值的年份数据乘以指标B的同比增长率得到指标A下一年的数据,从指标A最后一个12月31日有值的日期开始拼接计算得到指标A下一年的数据;`],
+	[22,`时间移位:把数据的时间序列加(领先)减(滞后)相应的时间,形成新的数据系列。<br>例:<br>
+	<p>
+		领先10天,即将指标每个数据点的日期加10天。原始数据点(2022-1-1,100)将转化成(2022-1-11,100)
+	</p>
+	<p>
+		滞后1月,即将日期减30天,原始数据点(2022-1-1,100)将转化成(2021-12-2,100)
+	</p>`],
+	[35,`计算公式:现值 - AVERAGE(过去N年同期数值和),N为取数个数<br>
+	1、计算过去N年同期数值和,则时间向前追溯 N年(包括最新一年)<br>
+	2、参与计算的指标数据通过线性方程补全为日度的数据(包括周末)<br>
+	3、遇到闰二月,如2.29,去掉该天数据<br>
+	4、进行农历计算时,只计算11月--次年5月,如果当前月为12月,则取第二年的春节为时间位移标准点<br>
+	5、计算生成的结果的数据频度与原始指标频度保持一致
+	`],
+	[37,`拟合残差:计算一个指标(B)的实际值和拟合值(B’)的差值。拟合值B’由指标A(自变量)和指标B(因变量)通过线性回归拟合得到,具体算法如下:<br>
+	根据指标A(自变量)和指标B(因变量)过去一个时间段内(这个N期可以是从最新值往前倒退N期,包含最新,也可以是选取历史数据的一个时间段内的数据),生成线性回归方程 Y=aX+b<br>
+	由指标A(自变量)和拟合方程的系数a,b,计算得到拟合出来的系列B’=aA b 再计算拟合系列B’和原始系列B的差值得到新的数据系列Delta,Delta=B-B'
+	`],
+	[40,`数据调整:将所选指标的历史数据经过调整后保存,该指标更新时将在调整数据的基础上更新最新数据。<br>
+	注:系统只取A、B列数据,且调整数据的日期不得晚于指标的实际最新日期
+	`],
+	[52,`年化值=S / a (S表示指标数值,a表示年化平均占比)<br>
+	1、读取指标最新值对应的日期T和指标数值S<br>
+	2、计算该指标在过去三年日期T对应的值与当年最后一个日期对应的值的比值,即截止到日期T的累计值占全年值的比重<br>
+	3、计算三年的占比平均值,即过去三年平均占比a<br>
+	4、若历史数据不足三年,则至少按两年计算,少于两年不生成年化值<br>
+	5、如果某一年日期T没有值,则通过日期T前后的两个值,用线性插值法【(Y-Y1)/(X-X1)=(Y2-Y1)/(X2-X1)】计算得到日期T的值
+	`],
+	[51,`降频:将高频指标转换为低频指标,需选择转换的频度<br>
+	1、选择转换的频度,日度可以选择降频成周度、旬度、月度、季度、年度;周度可以选择降频成旬度、月度、季度、年度;旬度可以选择降频成月度、季度、年度;月度可降成季度、年度,季度可降成年度<br>
+	2、降频后数据日期,周度的降频数据系列日期取每周五;旬度取每月10日、20日、最后一日;月度取每月最后一天,季度取季度最后一天,年度取年度最后一天<br>
+	3、数据点取值提供两种选择:a、期末值,取区间最后一个日期的数据值。b、取区间平均值。<br>
+	4、最新值的处理:最新的高频数据,正好处于所要降频的低频的两个日期之间时,例如当前1月3号,1月已经有了数据,但1月31号还未到来,则降成月频数据时最新数据日期为1月31号`],
+	[53,`扩散指数:AVERAGE(所选指标环差指数和)<br>
+	1、选择多个指标,设定扩散指标日期并集<br>
+	2、所选指标在日期并集内有缺失值的用前期值填充<br>
+	3、计算日期并集内所选指标的每期环差指数(环差>0,取1,环差=0,取0.5,环差<0,取0),并计算环差指数均值`],
+	['accumulate',`1、累计值计算方法:<br>
+	日度转周度:日期选周五,计算上周六到本周五的日度值的加总,最新日期为最新值对应的周五。<br>
+	日度转月度:日期选每个月最后一天,计算当月所有日度值的加总,最新日期为最新值对应当月最后一天。<br>
+	日度转季度、年度:方法类似转月度。<br>
+	周度转月度/季度/年度:将周度值转成日度,空值用插值法插值,计算当月/当季/当年所有值的加总,然后除以7。<br>
+	月度转季度/年度: 当季/当年月度值相加。<br>
+	以此类推 特别说明:旬度指标可以转成更低频指标,更高频指标不能转成旬度<br>
+	2、年初至今计算方法:<br>
+	日度数据年初至今:日期同原日度数据。将每年1月1日(含)到日度数据所在日期(含)之间的日度值,进行加总。<br>
+	周度数据年初至今:日期同原周度数据。将周度值转成日度频率,空值用插值法插值,然后算法同日度年度至今,再除以7<br>
+	月度/季度数据年初至今:日期同原月度/季度数据,将每年1月1日(含)到月度数据所在日期(含)之间的月度/季度值,进行加总<br>
+	以此类推`],
+	[61,`累计值转季值计算方法:<br>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:45%">1季度无值:1季度=2季度/2 </span>
+		<span style="width:40%">1季度有值:1季度=1季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">2季度=2季度/2</span>
+		<span style="width:40%">2季度=2季度-1季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">3季度=3季度-2季度</span>
+		<span style="width:40%">3季度=3季度-2季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">4季度=4季度-3季度</span>
+		<span style="width:40%">4季度=4季度-3季度</span>
+	</p>
+	<p style="display:flex;justify-content: space-between;">
+		<span style="width:40%">以此类推</span>
+		<span style="width:40%">以此类推</span>
+	</p>
+	<p>特别说明:若1季度和2季度均无值,则该年不做计算</p>`],
+	[62,`累计值计算方法:<br>
+	日度转周度:日期选周五,计算上周六到本周五的日度值的加总,最新日期为最新值对应的周五。<br>
+	日度转月度:日期选每个月最后一天,计算当月所有日度值的加总,最新日期为最新值对应当月最后一天。<br>
+	日度转季度、年度:方法类似转月度。<br>
+	周度转月度/季度/年度:将周度值转成日度,空值用插值法插值,计算当月/当季/当年所有值的加总,然后除以7。<br>
+	月度转季度/年度: 当季/当年月度值相加。<br>
+	以此类推 特别说明:旬度指标可以转成更低频指标,更高频指标不能转成旬度<br>`],
+	[63,`年初至今计算方法:<br>
+	日度数据年初至今:日期同原日度数据。将每年1月1日(含)到日度数据所在日期(含)之间的日度值,进行加总。<br>
+	周度数据年初至今:日期同原周度数据。将周度值转成日度频率,空值用插值法插值,然后算法同日度年度至今,再除以7<br>
+	月度/季度数据年初至今:日期同原月度/季度数据,将每年1月1日(含)到月度数据所在日期(含)之间的月度/季度值,进行加总<br>
+	以此类推`]
+])
+
+// 常规计算类型
+const calculateType=[
+    {
+		name:'指标运算',
+		type:4,
+	},
+	{
+		name:'累计值转月/季值',
+		type:'toMonthSeason',
+    },
+	{
+		name:'同比值',
+		type:6
+	},
+	{
+		name:'同差值',
+		type:7
+	},
+	{
+		name:'N数值移动平均计算',
+		type:8
+	},
+	{
+		name:'N数值环比值',
+		type:12
+	},
+	{
+		name:'N数值环差值',
+		type:13
+	},
+	{
+		name:'升频',
+		type:14
+	},
+	{
+		name:'指标拼接',
+		type: 'joint'
+	},
+	{
+		name: '时间移位',
+		type: 22
+	},
+	{
+		name: '超季节性',
+		type: 35
+	},
+	{
+		name: '拟合残差',
+		type: 37
+	},
+	{
+		name: '年化',
+		type: 52
+	},
+	{
+		name: '降频',
+		type: 51
+	},
+	{
+		name: '扩散指数',
+		type: 53
+	},
+	{
+		name: '累计值',
+		type: 'accumulate'
+	}
+]
+
+// 批量计算类型
+const calculateBatchType=[
+    {
+		name:'同比值',
+		type:6
+	},
+	{
+		name:'同差值',
+		type:7
+	},
+	{
+		name:'N数值移动平均计算',
+		type:8
+	},
+	{
+		name:'N数值环比值',
+		type:12
+	},
+	{
+		name:'N数值环差值',
+		type:13
+	},
+	{
+		name:'升频',
+		type:14
+	},
+	{
+		name:'累计值转月/季值',
+		type:'toMonthSeason'
+	},
+	{
+		name: '累计值',
+		type: 'accumulate'
+	}
+]
+
+const showTips=ref(false)
+const tipsTitle=ref('')
+const tipsContent=ref('')
+function handleShowTips(item){
+    tipsTitle.value=`【${item.name}】公式说明`
+    tipsContent.value=calculateTypeTipsMap.get(item.type)
+    showTips.value=true
+}
+
+function handleGoDetail(item){
+    router.push({
+        path:'/dataEDB/calculate/detail',
+        query:{
+            type:item.type,
+            name:item.name
+        }
+    })
+}
+
+</script>
+
+<template>
+    <div class="calculate-index-page">
+        <van-tabs sticky swipeable border title-active-color="#0052D9" title-inactive-color="#333" line-width="16px">
+            <van-tab title="常规计算">
+                <ul class="type-list-wrap">
+                    <li 
+                        class="type-item" 
+                        v-for="item in calculateType" 
+                        :key="item.type"
+                        @click="handleGoDetail(item)"
+                    >
+                        <div class="tips-box" @click.stop="handleShowTips(item)"> 
+                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21" fill="none">
+                                <path d="M18.75 10.5C18.75 15.3325 14.8325 19.25 10 19.25C5.16751 19.25 1.25 15.3325 1.25 10.5C1.25 5.66751 5.16751 1.75 10 1.75C14.8325 1.75 18.75 5.66751 18.75 10.5ZM10.625 5.50038H9.375V12.375H10.625V5.50038ZM9.24286 14.25V15.75H10.7429V14.25H9.24286Z" fill="#0052D9"/>
+                            </svg>
+                            <span>公式说明</span>
+                        </div>
+                        <h3 class="name">{{item.name}}</h3>
+                    </li>
+                </ul>
+            </van-tab>
+            <van-tab title="批量计算">
+                <ul class="type-list-wrap">
+                    <li 
+                        class="type-item" 
+                        v-for="item in calculateBatchType" 
+                        :key="item.type"
+                        @click="handleGoDetail(item)"
+                    >
+                        <div class="tips-box" @click.stop="handleShowTips(item)"> 
+                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21" fill="none">
+                                <path d="M18.75 10.5C18.75 15.3325 14.8325 19.25 10 19.25C5.16751 19.25 1.25 15.3325 1.25 10.5C1.25 5.66751 5.16751 1.75 10 1.75C14.8325 1.75 18.75 5.66751 18.75 10.5ZM10.625 5.50038H9.375V12.375H10.625V5.50038ZM9.24286 14.25V15.75H10.7429V14.25H9.24286Z" fill="#0052D9"/>
+                            </svg>
+                            <span>公式说明</span>
+                        </div>
+                        <h3 class="name">{{item.name}}</h3>
+                    </li>
+                </ul>
+            </van-tab>
+        </van-tabs>
+    </div>
+    <!-- 公式说明 -->
+    <van-dialog 
+        v-model:show="showTips" 
+        :title="tipsTitle"
+        confirmButtonText='知道啦'
+    >
+        <div class="tips-html-box" v-html="tipsContent"></div>
+    </van-dialog>
+</template>
+
+<style lang="scss" scoped>
+.type-list-wrap{
+    padding: $page-padding;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    .type-item{
+        padding: 30px 20px;
+        border-radius: 16px;
+        background: #F8F9FF;
+        width: 331px;
+        .tips-box{
+            width: 140px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background-color: #fff;
+            height: 31px;
+            border-radius: 42px;
+            font-size: 22px;
+            color: $theme-color;
+            line-height: 1;
+            svg{
+                width: 20px;
+                height: 20px;
+            }
+        }
+        .name{
+            margin-top: 9px;
+            margin-bottom: 0;
+            font-size: 28px;
+        }
+    }
+}
+.tips-html-box{
+    font-size: var(--van-dialog-font-size);
+    color: $font-grey;
+    line-height: 1.5;
+    padding: 36px;
+    max-height: 60vh;
+    overflow-y: auto;
+}
+</style>

+ 171 - 0
src/views/dataEDB/calculate/components/FormulaCalculate.vue

@@ -0,0 +1,171 @@
+<script setup>
+import { showToast } from 'vant';
+import {ref} from 'vue'
+import SelectEDB from './SelectEDB.vue'
+
+const letterOpts = [];//字母数据
+function initLetterOpt(){
+    for(let i=0;i<26;i++){
+        letterOpts.push(String.fromCharCode(65+i));
+    }
+}
+initLetterOpt()
+
+//选择的指标集合
+const edbList=ref([
+    {
+        tag:letterOpts[0],
+        target:'',
+        startDate:'',
+        endDate:''
+    },
+    {
+        tag:letterOpts[1],
+        target:'',
+        startDate:'',
+        endDate:''
+    },
+    {
+        tag:letterOpts[2],
+        target:'',
+        startDate:'',
+        endDate:''
+    },
+    {
+        tag:letterOpts[3],
+        target:'',
+        startDate:'',
+        endDate:''
+    }
+])
+function handleAddEdbList(){
+    if(edbList.value.length>=26){
+        showToast('添加指标个数已达上限')
+        return
+    }
+    let tag = edbList.value[edbList.value.length-1].tag;
+	let index = letterOpts.findIndex(item => item === tag);
+	const item = {
+		tag: letterOpts[index+1],
+		target: '',
+		start_date: '',
+		end_date: ''
+	};
+	edbList.value.push(item);
+}
+function handleDeleteEDBItem(index){
+    edbList.value.splice(index, 1)
+}
+
+// 选择指标
+const showSelectEDB=ref(false)
+let whichIndex=0
+function handleShowSelectEDB(index){
+    whichIndex=index
+    showSelectEDB.value=true
+}
+
+
+
+
+</script>
+
+<template>
+    <div class="formula-calculate-wrap">
+        <section class="section select-edb-box">
+            <van-swipe-cell  v-for="(item,index) in edbList" :key="item.tag" :disabled="index<4">
+                <van-field 
+                    :label="item.tag"
+                    is-link
+                    @click-input="handleShowSelectEDB(index)"
+                >
+                    <template #left-icon>
+                        <div class="left-icon"></div>
+                    </template>
+                    <template #input>
+                        <div class="edb-info-box">
+                            <div class="edb-info" v-if="true">
+                                <span class="name">指标名称</span>
+                                <span class="time">2019-11-25至2023-08-23</span>
+                            </div>
+                            <span class="placeholder" v-else>请选择指标</span>
+                        </div>
+                    </template>
+                </van-field>
+                <template #right>
+                    <van-button square type="danger" text="删除" @click="handleDeleteEDBItem(index)"/>
+                </template>
+            </van-swipe-cell>
+            <div class="add-edb-box" @click="handleAddEdbList">
+                <img src="@/assets/imgs/icon01.png" alt="">
+                <span>添加更多参数</span>
+            </div>
+        </section>
+        <section class="section formula-box">
+            <!-- <van-field 
+                v-model="item.target" 
+                :label="item.tag"
+                is-link
+                readonly
+                input-align="right"
+                placeholder="请选择指标"
+            >
+                <template #left-icon>
+                    <div class="left-icon"></div>
+                </template>
+            </van-field> -->
+        </section>
+    </div>
+
+    <!-- 选择指标 -->
+    <SelectEDB v-model:show="showSelectEDB"/>
+</template>
+
+<style lang="scss" scoped>
+.formula-calculate-wrap{
+    min-height: 80vh;
+    background-color: $page-bg-grey;
+}
+.section{
+    background-color: #fff;
+    margin-bottom: 32px;
+}
+.select-edb-box{
+    .left-icon{
+        width: 48px;
+        height: 48px;
+    }
+    :deep(.van-cell__right-icon){
+        align-self: center;
+        color: #333;
+    }
+    .edb-info-box{
+        width: 100%;
+        text-align: right;
+        .placeholder{
+            color: var(--van-text-color-3);
+        }
+        .edb-info{
+            display: flex;
+            flex-direction: column;
+        }
+        .time{
+            color: $font-grey_999;
+            font-size: 24px;
+        }
+    }
+    .add-edb-box{
+        display: flex;
+        justify-content: flex-end;
+        align-items: center;
+        color: $theme-color;
+        font-size: 32px;
+        padding: 32px var(--van-cell-horizontal-padding);
+        img{
+            width: 48px;
+            height: 48px;
+        }
+    }
+
+}
+</style>

+ 161 - 0
src/views/dataEDB/calculate/components/SelectEDB.vue

@@ -0,0 +1,161 @@
+<script setup>
+import {reactive, ref} from 'vue'
+import apiDataEDB from '@/api/dataEDB'
+
+const props=defineProps({
+    show:{
+        type:Boolean,
+        default:false
+    },
+})
+const emits=defineEmits(['update:show'])
+
+const listState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    finished:false,
+    loading:false,
+})
+async function getEDBList(){
+    listState.loading=true
+    const res=await apiDataEDB.edbSearchList({
+        KeyWord:searchEDBTxt.value,
+        CurrentIndex:listState.page,
+        PageSize:listState.pageSize
+    })
+    listState.loading=false
+    if(res.Ret===200){
+        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++
+    getEDBList()
+}
+const searchEDBTxt=ref('')
+function onSearch(){
+    listState.page=1
+    listState.list=[]
+    listState.finished=false
+    getEDBList()
+}
+
+const checked=ref('')
+
+</script>
+
+<template>
+    <van-popup 
+        :show="props.show"
+        position="bottom"
+        :style="{ height: '100%' }"
+    >
+        <div class="select-edb-box">
+            <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="list-wrap">
+                <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"
+                >   
+                    <van-radio-group v-model="checked">
+                        <ul class="list-box">
+                            <li class="item" v-for="item in listState.list" :key="item.EdbInfoId">
+                                <van-radio :name="item.EdbInfoId">
+                                    <div class="con">
+                                        <div class="name">{{item.EdbName}}</div>
+                                        
+                                    </div>
+                                </van-radio>
+                            </li>
+                        </ul>
+                    </van-radio-group>
+                </van-list>
+            </div>
+            <div class="btns-box">
+                <van-button @click="handleClose">取消</van-button>
+                <van-button type="primary" @click="handleSave">保存</van-button>
+            </div>
+        </div>
+    </van-popup>
+</template>
+
+<style lang="scss" scoped>
+.select-edb-box{
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    .list-wrap{
+        flex: 1;
+        overflow-y: auto;
+        padding-left: var(--van-padding-md);
+        .item{
+            :deep(.van-radio__label){
+                flex: 1;
+            }
+            .con{
+                padding: 32px 0;
+                border-bottom: 1px solid $border-color;
+            }
+        }
+    }
+    .btns-box{
+        padding: 20px var(--van-padding-md);
+        display: flex;
+        justify-content: space-between;
+        .van-button{
+            width: 48%;
+        }
+    }
+}
+.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);
+    }
+}
+
+</style>