|
@@ -70,15 +70,99 @@
|
|
|
添加更多参数
|
|
|
</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="nullValueForm.nullValueWay"
|
|
|
+ placeholder="请选择"
|
|
|
+ :disabled="calulateForm.view"
|
|
|
+ >
|
|
|
+ <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="nullValueForm.maxNullWay"
|
|
|
+ placeholder="请选择"
|
|
|
+ :disabled="calulateForm.view"
|
|
|
+ >
|
|
|
+ <el-option label="等于0" :value="1" />
|
|
|
+ <el-option label="跳过空值" :value="2" />
|
|
|
+ </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) 函数支持:MAX(),MIN(),ln(A),log(a,A),abs(),exp(),pow(),round()</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="选择日期"
|
|
|
+ :disabled="calulateForm.view"
|
|
|
+ @change="selectFormulaDate($event,item)"
|
|
|
+ />
|
|
|
+
|
|
|
+ <i class="el-icon-circle-close" style="font-size:20px;" v-if="!calulateForm.view" @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
|
|
|
+ v-if="!calulateForm.view"
|
|
|
+ icon="el-icon-plus"
|
|
|
+ style="margin-left:70px;"
|
|
|
+ @click="addFormulaHandle"
|
|
|
+ >新增分段</el-button>
|
|
|
+
|
|
|
</div>
|
|
|
<el-form
|
|
|
ref="diaForm"
|
|
@@ -148,7 +232,7 @@
|
|
|
placement="top-start"
|
|
|
width="360"
|
|
|
trigger="click">
|
|
|
- <p style="padding:30px;line-height:25px;" v-html="$parent.tips.get(4)"/>
|
|
|
+ <p style="padding:30px;line-height:25px;" v-html="$parent.tips.get(type)"/>
|
|
|
<span slot="reference" class="tip-label">公式说明</span>
|
|
|
</el-popover>
|
|
|
</el-dialog>
|
|
@@ -156,6 +240,7 @@
|
|
|
|
|
|
<script>
|
|
|
import { dataBaseInterface } from '@/api/api.js';
|
|
|
+import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
|
|
|
import { formRules } from '../databaseComponents/util';
|
|
|
import { unitArr } from '@/utils/defaultOptions';
|
|
|
const tag_arr = [];
|
|
@@ -176,6 +261,26 @@ export default {
|
|
|
calulateList: {
|
|
|
type: Array,
|
|
|
},
|
|
|
+ edbSource: { // ''||'predict'
|
|
|
+ type: String,
|
|
|
+ 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.nullValueForm.nullValueWay===4
|
|
|
+ },
|
|
|
+
|
|
|
+ formulaDateArr() {
|
|
|
+ return this.formulaList.map(_ => _.date).filter(_ => _).sort((a,b) => new Date(a)-new Date(b))
|
|
|
+ }
|
|
|
},
|
|
|
watch: {
|
|
|
isOpenComputed(newval) {
|
|
@@ -184,7 +289,10 @@ export default {
|
|
|
/* 回显 */
|
|
|
if (this.calulateList.length && newval) {
|
|
|
this.addList = _.cloneDeep(this.calulateList);
|
|
|
- this.formula = this.calulateForm.formula;
|
|
|
+ this.formulaList = JSON.parse(this.calulateForm.formula).map(_ => ({
|
|
|
+ formula: _.f,
|
|
|
+ date: _.d||''
|
|
|
+ }));
|
|
|
this.formData = {
|
|
|
targetName: this.calulateForm.targetName,
|
|
|
unit: this.calulateForm.unit,
|
|
@@ -192,6 +300,11 @@ export default {
|
|
|
frequency: this.calulateForm.frequency,
|
|
|
};
|
|
|
|
|
|
+ this.nullValueForm = {
|
|
|
+ nullValueWay: this.calulateForm.emptyType,
|
|
|
+ maxNullWay: this.calulateForm.maxEmptyType,
|
|
|
+ }
|
|
|
+
|
|
|
this.searchOptions = this.calulateList.map(item => ({
|
|
|
EdbInfoId: item.target,
|
|
|
EdbName: item.edb_name,
|
|
@@ -241,6 +354,9 @@ export default {
|
|
|
],
|
|
|
searchOptions: [],
|
|
|
formula: '', //计算公式
|
|
|
+ formulaList: [ //公式数组
|
|
|
+ { formula: '', }
|
|
|
+ ],
|
|
|
dataloading: false,
|
|
|
formData: {
|
|
|
targetName: '',
|
|
@@ -252,18 +368,46 @@ export default {
|
|
|
search_page: 1,
|
|
|
current_search:'',
|
|
|
|
|
|
- newestDate: ''
|
|
|
+ newestDate: '',
|
|
|
+
|
|
|
+ nullValueForm: {
|
|
|
+ nullValueWay: 0,
|
|
|
+ maxNullWay: 1
|
|
|
+ },//空值处理
|
|
|
+ nullWayOptions: [
|
|
|
+ { label: '查找前后35天最近值',value: 0 },
|
|
|
+ { label: '不计算',value: 1 },
|
|
|
+ { label: '前值填充',value: 2 },
|
|
|
+ { label: '后值填充',value: 3 },
|
|
|
+ { label: '等于0',value: 4 },
|
|
|
+ ],
|
|
|
+ formTips: {
|
|
|
+ 'null-val': `1、查找前后35天最近值:在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天<br>
|
|
|
+ 2、不计算:只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值 <br>
|
|
|
+ 3、前值填充:空值优先以最近的前值填充,没有前值时,用后值填充 <br>
|
|
|
+ 4、后值填充:空值优先以最近的后值填充,没有前值时,用后值填充 <br>
|
|
|
+ 5、等于0:空值以0值参与计算 <br>
|
|
|
+ 注意:此处缺失值的处理,作用于数据全部时间段`,
|
|
|
+ 'max-null-val': `MAX、MIN公式中指标存在空值时按如下规则处理:<br>
|
|
|
+ 1、等于0,空值用0参与计算;<br>
|
|
|
+ 2、跳过空值,去除空值指标,剩余指标进行计算,若该日期所有指标均为空值,则该日期无值;`,
|
|
|
+ 'formula':`1、支持新增分段,实现不同分段使用不同的计算公式,若未新增分段,则所有日期序列用统一公式计算<br>
|
|
|
+ 2、新增分段需配置新公式和时间节点,在时间节点之前(不含)使用新公式,在时间节点之后(含)使用已配置公式,每个分段公式支持修改<br>
|
|
|
+ 3、分段时间节点不允许重复,不允许超出第一个指标的日期区间`
|
|
|
+ }
|
|
|
+
|
|
|
};
|
|
|
},
|
|
|
methods: {
|
|
|
/* 获取目录结构 */
|
|
|
- getMenu() {
|
|
|
- dataBaseInterface.menuListV3().then((res) => {
|
|
|
- if (res.Ret === 200) {
|
|
|
- this.filterNodes(res.Data.AllNodes||[]);
|
|
|
- this.options = res.Data.AllNodes || [];
|
|
|
- }
|
|
|
- });
|
|
|
+ async getMenu() {
|
|
|
+ const res = this.edbSource === 'predict'
|
|
|
+ ? await preDictEdbInterface.classifyListV2()
|
|
|
+ : await dataBaseInterface.menuListV3()
|
|
|
+ if (res.Ret !== 200) return
|
|
|
+
|
|
|
+ this.filterNodes(res.Data.AllNodes||[]);
|
|
|
+ this.options = res.Data.AllNodes || [];
|
|
|
},
|
|
|
// 递归改变第三级目录结构
|
|
|
filterNodes(arr) {
|
|
@@ -302,18 +446,25 @@ export default {
|
|
|
this.searchApi(this.current_search);
|
|
|
},
|
|
|
|
|
|
- searchApi(query,page=1) {
|
|
|
- dataBaseInterface.targetSearchByPage({
|
|
|
- KeyWord:query,
|
|
|
- CurrentIndex: page
|
|
|
- }).then(res => {
|
|
|
+ async searchApi(query,page=1) {
|
|
|
+ const res = this.edbSource === 'predict'
|
|
|
+ ? await preDictEdbInterface.edbSearch({
|
|
|
+ Keyword: query,
|
|
|
+ CurrentIndex: page,
|
|
|
+ FilterSource: this.type === 45 ? 3 : this.type === 66 ? 6 : 1,
|
|
|
+ Frequency: this.type===64?'季度': ''
|
|
|
+ })
|
|
|
+ : await dataBaseInterface.targetSearchByPage({
|
|
|
+ KeyWord:query,
|
|
|
+ CurrentIndex: page,
|
|
|
+ FilterSource: this.type === 14 ? 3 : this.type === 63 ? 6 : 1,
|
|
|
+ Frequency: this.type===61?'季度': ''
|
|
|
+ })
|
|
|
if(res.Ret !== 200) return
|
|
|
|
|
|
const { List,Paging } = res.Data;
|
|
|
this.search_have_more = page < Paging.Pages;
|
|
|
this.searchOptions = page === 1 ? List : this.searchOptions.concat(List);
|
|
|
-
|
|
|
- })
|
|
|
},
|
|
|
|
|
|
searchLoad() {
|
|
@@ -361,30 +512,41 @@ export default {
|
|
|
this.getNewestDate();
|
|
|
},
|
|
|
async saveHandle() {
|
|
|
- if (!this.formula) return this.$message.warning('计算公式不能为空');
|
|
|
+ if (!this.formulaList[0].formula) return this.$message.warning('计算公式不能为空');
|
|
|
await this.$refs.diaForm.validate();
|
|
|
|
|
|
// 指标id数组
|
|
|
- let target_arr = this.addList
|
|
|
- .filter((item) => item.target)
|
|
|
- .map((item) => {
|
|
|
- return {
|
|
|
- EdbInfoId: item.target,
|
|
|
- FromTag: item.tag,
|
|
|
- };
|
|
|
- });
|
|
|
+ let EdbInfoIdArr = this.addList.filter((item) => item.target).map((item) => ({
|
|
|
+ EdbInfoId: item.target,
|
|
|
+ FromTag: item.tag,
|
|
|
+ }));
|
|
|
+
|
|
|
+ let formulaArr = this.formulaList
|
|
|
+ .filter((_,index) => index===0||(index>0&&_.formula&&_.date))
|
|
|
+ .map(_ => ({f: _.formula,d: _.date}))
|
|
|
+
|
|
|
+ const { nullValueWay,maxNullWay } = this.nullValueForm;
|
|
|
+
|
|
|
let params = {
|
|
|
- CalculateFormula: this.formula,
|
|
|
+ CalculateFormula: JSON.stringify(formulaArr),
|
|
|
ClassifyId: this.formData.menu[this.formData.menu.length - 1] || 0,
|
|
|
EdbName: this.formData.targetName,
|
|
|
Frequency: this.formData.frequency,
|
|
|
Unit: this.formData.unit,
|
|
|
- EdbInfoIdArr: target_arr,
|
|
|
+ EdbInfoIdArr,
|
|
|
+ EmptyType: nullValueWay,
|
|
|
+ MaxEmptyType: maxNullWay
|
|
|
};
|
|
|
this.dataloading = true;
|
|
|
- const res = this.calulateForm.edb_id
|
|
|
- ? await dataBaseInterface.calculateEdit({...params,EdbInfoId: this.calulateForm.edb_id})
|
|
|
- : await dataBaseInterface.calculateAdd(params)
|
|
|
+
|
|
|
+ let res;
|
|
|
+ if(this.edbSource === 'predict') {
|
|
|
+ res = await preDictEdbInterface.calculateEdbSave(this.calulateForm.edb_id ? {...params,EdbInfoId:this.calulateForm.edb_id } : params)
|
|
|
+ }else {
|
|
|
+ res = this.calulateForm.edb_id
|
|
|
+ ? await dataBaseInterface.calculateEdit({...params,EdbInfoId: this.calulateForm.edb_id})
|
|
|
+ : await dataBaseInterface.calculateAdd(params)
|
|
|
+ }
|
|
|
|
|
|
this.dataloading = false;
|
|
|
if (res.Ret !== 200) return
|
|
@@ -394,6 +556,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[this.formulaList.length-1].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 = [
|
|
@@ -430,6 +628,14 @@ export default {
|
|
|
menu: '',
|
|
|
frequency: '',
|
|
|
};
|
|
|
+ this.formulaList = [
|
|
|
+ { formula: '' }
|
|
|
+ ]
|
|
|
+ this.nullValueForm = {
|
|
|
+ nullValueWay: 0,
|
|
|
+ maxNullWay: 1
|
|
|
+ }
|
|
|
+
|
|
|
},
|
|
|
cancelHandle(type) {
|
|
|
this.init();
|
|
@@ -437,7 +643,6 @@ export default {
|
|
|
type==='cancel' && !this.calulateForm.edb_id && this.$emit('openPrev');
|
|
|
},
|
|
|
},
|
|
|
- created() {},
|
|
|
mounted() {},
|
|
|
};
|
|
|
</script>
|
|
@@ -501,10 +706,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;
|
|
|
}
|
|
|
}
|
|
|
}
|