Browse Source

指标运算改版

Karsa 1 year ago
parent
commit
2212411ba0

+ 186 - 12
src/views/dataEntry_manage/databaseComponents/computedDialog.vue

@@ -71,15 +71,91 @@
 				添加更多参数
 			</span>
 			<div class="computed-min">
-				<div class="computed-top">
-					<span style="margin-right: 8px">计算公式</span>
-					<el-input placeholder="请输入公式" v-model="formula" clearable :disabled="calulateForm.view">
-					</el-input>
+				<div class="computed-section">
+					<div>
+						<label class="label">空值处理
+							<el-tooltip placement="top">
+								<div slot="content" v-html="formTips['null-val']" style="width:300px;line-height:20px;"/>
+								<i class="el-icon-question"/>
+							</el-tooltip>
+						</label>
+						<el-select
+							v-model="otherForm.nullValueWay"
+							placeholder="请选择"
+						>
+							<el-option
+								v-for="item in nullWayOptions"
+								:key="item.value"
+								:label="item.label"
+								:value="item.value"
+							>
+							</el-option>
+						</el-select>
+					</div>
+
+					<div style="margin-left: 120px" v-if="showMaxNullDeal">
+						<label class="label">MAX、MIN空值处理
+							<el-tooltip placement="top">
+								<div slot="content" v-html="formTips['max-null-val']" style="width:300px;line-height:20px;"/>
+								<i class="el-icon-question"/>
+							</el-tooltip>
+						</label>
+						<el-select
+							v-model="otherForm.maxNullWay"
+							placeholder="请选择"
+						>
+							<el-option label="等于0" value="等于0" />
+							<el-option label="跳过空值" value="跳过空值" />
+						</el-select>
+					</div>
+				</div>	
+				<div class="computed-section">
+					<label class="label">计算公式
+						<el-tooltip placement="top">
+							<div slot="content" v-html="formTips['formula']" style="width:300px;line-height:20px;"/>
+							<i class="el-icon-question"/>
+						</el-tooltip>
+					</label>
+					<!-- <el-input placeholder="请输入公式" v-model="formula" clearable :disabled="calulateForm.view">
+					</el-input> -->
+					<ul class="formula-list">
+						<li style="margin-bottom: 15px;">
+							<el-input placeholder="请输入公式" v-model="formulaList[0].formula" clearable :disabled="calulateForm.view" style="width: 220px"/>
+							
+							<span v-if="formulaDateArr.length" class="date-section-text">{{formulaDateArr[formulaDateArr.length-1]}}(含)之后</span>
+
+							<span class="example-txt">公式示例:A*0.5+B*C*1.2+120-MAX(A,B,C) &nbsp;函数支持:MAX(),MIN(),ln(A),log(a,A)</span>
+						</li>
+
+						<li class="formula-item" v-for="(item,index) in formulaList.slice(1)" :key="index+1">
+							<el-input 
+								placeholder="请输入公式" 
+								v-model="item.formula" 
+								clearable 
+								:disabled="calulateForm.view"
+								style="width: 220px"
+							/>
+
+							<el-date-picker
+								v-model="item.date"
+								type="date"
+								value-format="yyyy-MM-dd"
+								style="margin: 0 10px;width: 220px"
+								placeholder="选择日期"
+								@change="selectFormulaDate($event,item)"
+							/>
+
+							<i class="el-icon-circle-close" style="font-size:20px;" @click="removeFormulaItem(index+1)"/>
+
+							<template v-if="formulaDateArr.length&&item.date">
+								<span v-if="item.date===formulaDateArr[0]" class="date-section-text">{{formulaDateArr[0]}}之前</span>
+								<span v-else class="date-section-text">{{formulaDateArr[formulaDateArr.findIndex(_ =>_ ===item.date)-1]}}(含)——{{item.date}}</span>
+							</template>
+						</li>
+					</ul>
 				</div>
-				<span class="example-txt"
-					>公式示例:A*0.5+B*C*1.2+120-MAX(A,B,C)</span
-				>
-				<span class="example-txt">函数支持:MAX(),MIN(),ln(A),log(a,A)</span>
+				<el-button icon="el-icon-plus" style="margin-left:70px;" @click="addFormulaHandle">新增分段</el-button>
+
 			</div>
 			<el-form
 				ref="diaForm"
@@ -186,6 +262,17 @@ export default {
 	computed: {
 		type() {
 			return this.edbSource ? 31 : 4;
+		},
+
+		/* max空值处理显示 当输入的公式包含MAX、MIN且空值处理为0时,输入公式失焦后出现右侧选项; */
+		showMaxNullDeal() {
+			let haveMaxOrMin = this.formulaList.some(_ => _.formula.toUpperCase().includes('MAX') || _.formula.toUpperCase().includes('MIN'))
+
+			return haveMaxOrMin && this.otherForm.nullValueWay===5
+		},
+
+		formulaDateArr() {
+			return this.formulaList.map(_ => _.date).filter(_ => _).sort((a,b) => new Date(a)-new Date(b))
 		}
 	},
 	watch: {
@@ -252,6 +339,10 @@ export default {
 			],
 			searchOptions: [],
 			formula: '', //计算公式
+			formulaList: [
+				{ formula: '', },
+				{ formula: '',date: '' }
+			],
 			dataloading: false,
 			formData: {
 				targetName: '',
@@ -263,7 +354,33 @@ export default {
 			search_page: 1,
 			current_search:'',
 
-			newestDate: ''
+			newestDate: '',
+
+			otherForm: {
+				nullValueWay: 1,
+				maxNullWay: '等于0'
+			},//空值处理
+			nullWayOptions: [
+				{ label: '查找前后35天最近值',value: 1 },
+				{ label: '不计算',value: 2 },
+				{ label: '前值填充',value: 3 },
+				{ label: '后值填充',value: 4 },
+				{ label: '等于0',value: 5 },
+			],
+			formTips: {
+				'null-val': `1、查找前后35天最近值:在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天,<br>
+				2、不计算:只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值 <br>
+				3、前值填充:空值优先以最近的前值填充,没有前值时,用后值填充 <br>
+				4、后值填充:空值优先以最近的后值填充,没有前值时,用后值填充 <br>
+				5、等于0:空值以0值参与计算 注意:此处缺失值的处理,作用于数据全部时间段`,
+				'max-null-val': `MAX、MIN公式中指标存在空值时按如下规则处理:<br>
+				1、等于0,空值用0参与计算;<br>
+				2、跳过空值,去除空值指标,剩余指标进行计算,若该日期所有指标均为空值,则该日期无值;`,
+				'formula':`1、支持新增分段,实现不同分段使用不同的计算公式,若未新增分段,则所有日期序列用统一公式计算<br>
+				2、新增分段需配置新公式和时间节点,在时间节点之前(不含)使用新公式,在时间节点之后(含)使用已配置公式,每个分段公式支持修改<br>
+				3、分段时间节点不允许重复,不允许超出第一个指标的日期区间`
+			}
+
 		};
 	},
 	methods: {
@@ -419,6 +536,42 @@ export default {
 						: this.$emit('addCallBack','add',{ code:res.Data.UniqueCode,id:res.Data.EdbInfoId,classifyId:params.ClassifyId });
 				this.init();
 		},
+
+		/* 新增公式分段 */
+		addFormulaHandle() {
+			let addItem = {
+				formula: this.formulaList[0].formula,
+				date: ''
+			}
+			this.formulaList.push(addItem)
+		},
+
+		/* 移除公式 */
+		removeFormulaItem(index) {
+			this.formulaList.splice(index,1)
+		},
+
+		/* 选择日期 检验排 */
+		selectFormulaDate(val,item) {
+			console.log(val,item)
+			const { start_date,end_date } = this.addList[0];
+
+			if(!start_date) return
+
+			let dateStamp = new Date(val).getTime(), 
+					startStamp = new Date(start_date).getTime(),
+					endStamp = new Date(end_date).getTime();
+			if (dateStamp > endStamp || dateStamp < startStamp) {
+				item.date = '';
+				return this.$message.warning('分段日期必须在第一个指标日期区间')
+			}
+
+			else if(this.formulaList.filter(_ => _.date===val).length>1) {
+				item.date = '';
+				return this.$message.warning('分段日期不可重复')
+			}
+		},
+
 		init() {
 			this.$refs.diaForm.resetFields();
 			this.addList = [
@@ -455,6 +608,14 @@ export default {
 				menu: '',
 				frequency: '',
 			};
+			this.formulaList = [
+				{ formula: '' }
+			]
+			this.otherForm = {
+				nullValueWay: 1,
+				maxNullWay: '等于0'
+			}
+
 		},
 		cancelHandle(type) {
 			this.init();
@@ -462,7 +623,6 @@ export default {
 			type==='cancel' && !this.calulateForm.edb_id && this.$emit('openPrev');
 		},
 	},
-	created() {},
 	mounted() {},
 };
 </script>
@@ -519,10 +679,24 @@ export default {
 			margin: 50px 0;
 			padding-bottom: 40px;
 			border-bottom: 1px dashed #aab4cc;
+			.computed-section {
+				display: flex;
+				margin-top: 20px;
+			}
+			.label {
+				padding:10px 10px 10px 0;
+			}
 			.example-txt {
 				display: block;
-				margin-left: 70px;
-				margin-top: 15px;
+				margin-top: 10px;
+			}
+			.formula-item {
+				display: flex;
+				align-items: center;
+				margin-bottom: 15px;
+			}
+			.date-section-text {
+				margin-left: 15px;
 			}
 		}
 	}

+ 4 - 2
src/views/dataEntry_manage/databaseComponents/util.js

@@ -227,8 +227,10 @@ export const allFromArr = [
 
 //公式说明 eta指标库
 export const formulaTip = new Map([
-	[4,`指标运算:选择指标参数,按照输入的计算公式进行计算,生成新的指标<br>
-	在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天`],
+	[4,`指标运算:<br>
+	1、选择指标参数<br>
+	2、生成指标的时间序列:以第一个指标为准,其他指标去匹配第一个指标的日期序列,没有值的,按照所选空值处理方式处理<br>
+	3、按照输入的计算公式进行计算`],
 	[5,`累计值转月值计算方法:<br>
 	<p style="display:flex;justify-content: space-between;">
 		<span style="width:45%">1月无值:1月=2月/2</span>

+ 185 - 10
src/views/predictEdb_manage/components/dynamicRingdiffer.vue

@@ -58,15 +58,93 @@
 				添加更多参数
 			</span>
 			<div class="computed-min">
-				<div class="computed-top">
-					<span>计算公式</span>
-					<el-input placeholder="请输入公式" v-model="formula" clearable style="margin: 0 8px"/>
-          <el-button type="primary" @click="getResult">一键计算</el-button>
+				
+				<div class="computed-section">
+					<div>
+						<label class="label">空值处理
+							<el-tooltip placement="top">
+								<div slot="content" v-html="formTips['null-val']" style="width:300px;line-height:20px;"/>
+								<i class="el-icon-question"/>
+							</el-tooltip>
+						</label>
+						<el-select
+							v-model="otherForm.nullValueWay"
+							placeholder="请选择"
+						>
+							<el-option
+								v-for="item in nullWayOptions"
+								:key="item.value"
+								:label="item.label"
+								:value="item.value"
+							>
+							</el-option>
+						</el-select>
+					</div>
+
+					<div style="margin-left: 120px" v-if="showMaxNullDeal">
+						<label class="label">MAX、MIN空值处理
+							<el-tooltip placement="top">
+								<div slot="content" v-html="formTips['max-null-val']" style="width:300px;line-height:20px;"/>
+								<i class="el-icon-question"/>
+							</el-tooltip>
+						</label>
+						<el-select
+							v-model="otherForm.maxNullWay"
+							placeholder="请选择"
+						>
+							<el-option label="等于0" value="等于0" />
+							<el-option label="跳过空值" value="跳过空值" />
+						</el-select>
+					</div>
+
+          <el-button type="primary" @click="getResult" style="margin-left: 10px">一键计算</el-button>
 				</div>
-				<span class="example-txt"
-					>公式示例:A*0.5+B*C*1.2+120-MAX(A,B,C)</span
-				>
-				<span class="example-txt">函数支持:MAX(),MIN()</span>
+
+				<div class="computed-section">
+					<label class="label">计算公式
+						<el-tooltip placement="top">
+							<div slot="content" v-html="formTips['formula']" style="width:300px;line-height:20px;"/>
+							<i class="el-icon-question"/>
+						</el-tooltip>
+					</label>
+
+					<ul class="formula-list">
+						<li style="margin-bottom: 15px;">
+							<el-input placeholder="请输入公式" v-model="formulaList[0].formula" clearable style="width: 220px"/>
+							
+							<span v-if="formulaDateArr.length" class="date-section-text">{{formulaDateArr[formulaDateArr.length-1]}}(含)之后</span>
+
+							<span class="example-txt">公式示例:A*0.5+B*C*1.2+120-MAX(A,B,C) &nbsp;函数支持:MAX(),MIN(),ln(A),log(a,A)</span>
+						</li>
+
+						<li class="formula-item" v-for="(item,index) in formulaList.slice(1)" :key="index+1">
+							<el-input 
+								placeholder="请输入公式" 
+								v-model="item.formula" 
+								clearable
+								style="width: 220px"
+							/>
+
+							<el-date-picker
+								v-model="item.date"
+								type="date"
+								value-format="yyyy-MM-dd"
+								style="margin: 0 10px;width: 220px"
+								placeholder="选择日期"
+								@change="selectFormulaDate($event,item)"
+							/>
+
+							<i class="el-icon-circle-close" style="font-size:20px;" @click="removeFormulaItem(index+1)"/>
+
+							<template v-if="formulaDateArr.length&&item.date">
+								<span v-if="item.date===formulaDateArr[0]" class="date-section-text">{{formulaDateArr[0]}}之前</span>
+								<span v-else class="date-section-text">{{formulaDateArr[formulaDateArr.findIndex(_ =>_ ===item.date)-1]}}(含)——{{item.date}}</span>
+							</template>
+						</li>
+					</ul>
+				</div>
+
+				<el-button icon="el-icon-plus" style="margin-left:70px;" @click="addFormulaHandle">新增分段</el-button>
 			</div>
       
       <el-table
@@ -125,6 +203,18 @@ export default {
 			type: Array,
 		},
 	},
+	computed: {
+		/* max空值处理显示 当输入的公式包含MAX、MIN且空值处理为0时,输入公式失焦后出现右侧选项; */
+		showMaxNullDeal() {
+			let haveMaxOrMin = this.formulaList.some(_ => _.formula.toUpperCase().includes('MAX') || _.formula.toUpperCase().includes('MIN'))
+
+			return haveMaxOrMin && this.otherForm.nullValueWay===5
+		},
+
+		formulaDateArr() {
+			return this.formulaList.map(_ => _.date).filter(_ => _).sort((a,b) => new Date(a)-new Date(b))
+		}
+	},
 	watch: {
 		isOpenDialog(newval) {
 			/* 回显 */
@@ -190,6 +280,35 @@ export default {
 				},
       ],
 
+			formulaList: [
+				{ formula: '', },
+				{ formula: '',date: '' }
+			],
+			otherForm: {
+				nullValueWay: 1,
+				maxNullWay: '等于0'
+			},//空值处理
+			nullWayOptions: [
+				{ label: '查找前后35天最近值',value: 1 },
+				{ label: '不计算',value: 2 },
+				{ label: '前值填充',value: 3 },
+				{ label: '后值填充',value: 4 },
+				{ label: '等于0',value: 5 },
+			],
+			formTips: {
+				'null-val': `1、查找前后35天最近值:在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天,<br>
+				2、不计算:只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值 <br>
+				3、前值填充:空值优先以最近的前值填充,没有前值时,用后值填充 <br>
+				4、后值填充:空值优先以最近的后值填充,没有前值时,用后值填充 <br>
+				5、等于0:空值以0值参与计算 注意:此处缺失值的处理,作用于数据全部时间段`,
+				'max-null-val': `MAX、MIN公式中指标存在空值时按如下规则处理:<br>
+				1、等于0,空值用0参与计算;<br>
+				2、跳过空值,去除空值指标,剩余指标进行计算,若该日期所有指标均为空值,则该日期无值;`,
+				'formula':`1、支持新增分段,实现不同分段使用不同的计算公式,若未新增分段,则所有日期序列用统一公式计算<br>
+				2、新增分段需配置新公式和时间节点,在时间节点之前(不含)使用新公式,在时间节点之后(含)使用已配置公式,每个分段公式支持修改<br>
+				3、分段时间节点不允许重复,不允许超出第一个指标的日期区间`
+			},
+
       resultData: [],//
 		};
 	},
@@ -301,6 +420,40 @@ export default {
 				isPredict: _.DataTimestamp > this.$moment(Data.LatestDate+' 8:00').valueOf()
 			})) || [];
 		},
+
+		/* 新增公式分段 */
+		addFormulaHandle() {
+			let addItem = {
+				formula: this.formulaList[0].formula,
+				date: ''
+			}
+			this.formulaList.push(addItem)
+		},
+
+		/* 移除公式 */
+		removeFormulaItem(index) {
+			this.formulaList.splice(index,1)
+		},
+
+		/* 选择日期 检验 */
+		selectFormulaDate(val,item) {
+			const { start_date,end_date } = this.addList[0];
+
+			if(!start_date) return
+
+			let dateStamp = new Date(val).getTime(), 
+					startStamp = new Date(start_date).getTime(),
+					endStamp = new Date(end_date).getTime();
+			if (dateStamp > endStamp || dateStamp < startStamp) {
+				item.date = '';
+				return this.$message.warning('分段日期必须在第一个指标日期区间')
+			}
+
+			else if(this.formulaList.filter(_ => _.date===val).length>1) {
+				item.date = '';
+				return this.$message.warning('分段日期不可重复')
+			}
+		},
 		
 		init() {
 			this.addList = [
@@ -336,6 +489,14 @@ export default {
 			this.searchOptions = [];
 			this.formula = '';
 			this.resultData = [];
+
+			this.formulaList = [
+				{ formula: '' }
+			]
+			this.otherForm = {
+				nullValueWay: 1,
+				maxNullWay: '等于0'
+			}
 		},
 		cancelHandle() {
 			this.init();
@@ -395,8 +556,22 @@ export default {
 			margin: 50px 0;
 			.example-txt {
 				display: block;
-				margin-left: 70px;
-				margin-top: 15px;
+				margin-top: 10px;
+			}
+			.computed-section {
+				display: flex;
+				margin-top: 20px;
+			}
+			.label {
+				padding:10px 10px 10px 0;
+			}
+			.formula-item {
+				display: flex;
+				align-items: center;
+				margin-bottom: 15px;
+			}
+			.date-section-text {
+				margin-left: 15px;
 			}
 		}
 	}