computedDialog.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. <template>
  2. <el-dialog
  3. :visible.sync="isOpenComputed"
  4. :close-on-click-modal="false"
  5. :modal-append-to-body="false"
  6. @close="cancelHandle"
  7. custom-class="computed-dialog fit-screen-dialog"
  8. center
  9. top="6vh"
  10. v-dialogDrag
  11. >
  12. <div slot="title" style="display: flex; align-items: center">
  13. <img
  14. :src="$icons.computed"
  15. style="color: #fff; width: 16px; height: 16px; margin-right: 5px"
  16. />
  17. <span style="font-size: 16px">{{ titleMap.get(title) }}</span>
  18. </div>
  19. <div class="dialog-main">
  20. <ul class="add-cont">
  21. <li class="add-li" v-for="(list, index) in addList" :key="index">
  22. <span class="li-tag">{{ list.tag }}</span>
  23. <el-select
  24. v-model="list.target"
  25. v-loadMore="searchLoad"
  26. :filterable="!list.target"
  27. clearable
  28. :placeholder="$t('Edb.InputHolderAll.input_name')"
  29. style="width: 400px"
  30. @change="chooseTarget"
  31. @clear="clearHandle(index)"
  32. :disabled="calulateForm.view"
  33. remote
  34. :remote-method="searchTarget"
  35. @click.native="inputFocusHandle"
  36. >
  37. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  38. <el-option
  39. v-for="item in searchOptions"
  40. :key="item.EdbInfoId"
  41. :label="$parent.currentLang==='en'?(item.EdbNameEn||item.EdbName):item.EdbName"
  42. :value="item.EdbInfoId"
  43. :disabled="!item.HaveOperaAuth"
  44. >
  45. <edbDetailPopover :info="item">
  46. <div slot="reference">
  47. <img
  48. :src="$icons.lock_ico2"
  49. width="18"
  50. height="18"
  51. style="vertical-align:middle"
  52. v-if="!item.HaveOperaAuth"
  53. />
  54. {{$parent.currentLang==='en'?(item.EdbNameEn||item.EdbName):item.EdbName}}
  55. </div>
  56. </edbDetailPopover>
  57. </el-option>
  58. </el-select>
  59. <i class="el-icon-tickets" style="color:#409EFF;font-size:18px" @click="$emit('lookHistory',list.target)" v-if="list.target"/>
  60. <i
  61. class="el-icon-error del-tag"
  62. v-if="index > 3 && !calulateForm.view"
  63. @click="delTarget(index)"
  64. />
  65. <span :class="{
  66. 'target-date': true,
  67. 'newest': list.end_date===newestDate
  68. }" v-if="list.start_date">{{
  69. `${list.start_date}${$t('Common.to')}${list.end_date}`
  70. }}</span>
  71. </li>
  72. </ul>
  73. <span class="add-icon" @click="addTargetHandle" v-if="!calulateForm.view">
  74. <i
  75. class="el-icon-circle-plus-outline"
  76. style="color: #5882ef; font-size: 16px"
  77. />
  78. <!-- 添加更多参数 -->{{$t('EtaBasePage.add_more_param')}}
  79. </span>
  80. <div class="computed-min">
  81. <div class="computed-section">
  82. <div>
  83. <label class="label"><!-- 生成指标时间序列 -->{{$t('EtaBasePage.create_edb_time_index')}}</label>
  84. <div style="width:200px;display: inline-block;">
  85. <el-cascader
  86. v-model="selectTimeSeriesVal"
  87. style="width:100%"
  88. :options="timeSeriesOpt"
  89. :props="{emitPath:false}"
  90. :show-all-levels="false"
  91. :placeholder="$t('Edb.please_select')"
  92. :disabled="calulateForm.view"
  93. ></el-cascader>
  94. </div>
  95. </div>
  96. </div>
  97. <div class="computed-section">
  98. <div>
  99. <label class="label"><!-- 空值处理 -->{{$t('EtaBasePage.null_val_deal')}}
  100. <el-tooltip placement="top">
  101. <div slot="content" v-html="formTips['null-val']" style="width:300px;line-height:20px;"/>
  102. <i class="el-icon-question"/>
  103. </el-tooltip>
  104. </label>
  105. <el-select
  106. v-model="nullValueForm.nullValueWay"
  107. :placeholder="$t('Edb.please_select')"
  108. :disabled="calulateForm.view"
  109. >
  110. <el-option
  111. v-for="item in nullWayOptions"
  112. :key="item.value"
  113. :label="item.label"
  114. :value="item.value"
  115. >
  116. </el-option>
  117. </el-select>
  118. </div>
  119. <div style="margin-left: 120px" v-if="showMaxNullDeal">
  120. <label class="label"><!-- MAX、MIN空值处理 --> {{$t('EtaBasePage.max_null_val')}}
  121. <el-tooltip placement="top">
  122. <div slot="content" v-html="formTips['max-null-val']" style="width:300px;line-height:20px;"/>
  123. <i class="el-icon-question"/>
  124. </el-tooltip>
  125. </label>
  126. <el-select
  127. v-model="nullValueForm.maxNullWay"
  128. :placeholder="$t('Edb.please_select')"
  129. :disabled="calulateForm.view"
  130. >
  131. <el-option :label="$t('EtaBasePage.null_val_deal_4')" :value="1" />
  132. <el-option :label="$t('EtaBasePage.max_null_val_2')" :value="2" />
  133. </el-select>
  134. </div>
  135. </div>
  136. <div class="computed-section">
  137. <label class="label"><!-- 计算公式 -->{{$t('EtaBasePage.calculate_formula')}}
  138. <el-tooltip placement="top">
  139. <div slot="content" v-html="formTips['formula']" style="width:300px;line-height:20px;"/>
  140. <i class="el-icon-question"/>
  141. </el-tooltip>
  142. </label>
  143. <!-- <el-input placeholder="请输入公式" v-model="formula" clearable :disabled="calulateForm.view">
  144. </el-input> -->
  145. <ul class="formula-list">
  146. <li style="margin-bottom: 15px;">
  147. <el-input :placeholder="$t('EtaBasePage.input_formula_msg')" v-model="formulaList[0].formula" clearable :disabled="calulateForm.view" style="width: 600px"/>
  148. <span v-if="formulaDateArr.length" class="date-section-text">{{formulaDateArr[formulaDateArr.length-1]}}(含)之后</span>
  149. <span class="example-txt">{{$t('EtaBasePage.formula_examp')}}:A*0.5+B*C*1.2+120-MAX(A,B,C) &nbsp;{{$t('EtaBasePage.func_examp')}}:MAX(),MIN(),ln(A),log(a,A),abs(),exp(),pow(),round()</span>
  150. </li>
  151. <li class="formula-item" v-for="(item,index) in formulaList.slice(1)" :key="index+1">
  152. <el-input
  153. :placeholder="$t('EtaBasePage.input_formula_msg')"
  154. v-model="item.formula"
  155. clearable
  156. :disabled="calulateForm.view"
  157. style="width: 220px"
  158. />
  159. <el-date-picker
  160. v-model="item.date"
  161. type="date"
  162. value-format="yyyy-MM-dd"
  163. style="margin: 0 10px;width: 220px"
  164. :placeholder="$t('EtaBasePage.input_date_msg')"
  165. :disabled="calulateForm.view"
  166. @change="selectFormulaDate($event,item)"
  167. />
  168. <i class="el-icon-circle-close" style="font-size:20px;" v-if="!calulateForm.view" @click="removeFormulaItem(index+1)"/>
  169. <template v-if="formulaDateArr.length&&item.date">
  170. <span v-if="item.date===formulaDateArr[0]" class="date-section-text">{{formulaDateArr[0]}}之前</span>
  171. <span v-else class="date-section-text">{{formulaDateArr[formulaDateArr.findIndex(_ =>_ ===item.date)-1]}}(含)——{{item.date}}</span>
  172. </template>
  173. </li>
  174. </ul>
  175. </div>
  176. <el-button
  177. v-if="!calulateForm.view"
  178. icon="el-icon-plus"
  179. style="margin-left:70px;"
  180. @click="addFormulaHandle"
  181. ><!-- 新增分段 -->{{$t('EtaBasePage.add_segm')}}</el-button>
  182. </div>
  183. <el-form
  184. ref="diaForm"
  185. label-position="right"
  186. inline
  187. label-width="120px"
  188. :model="formData"
  189. :rules="formRules"
  190. :disabled="calulateForm.view"
  191. >
  192. <el-form-item :label="$t('Edb.Detail.e_name')" prop="targetName">
  193. <el-input
  194. v-model="formData.targetName"
  195. style="width: 340px"
  196. :placeholder="$t('Edb.InputHolderAll.input_name')"
  197. />
  198. </el-form-item>
  199. <el-form-item :label="$t('Edb.Detail.e_unit')" prop="unit">
  200. <selectUnit v-model="formData.unit" style="width: 340px" />
  201. </el-form-item>
  202. <el-form-item :label="$t('Edb.Detail.e_menu')" prop="menu">
  203. <cascader
  204. v-model="formData.menu"
  205. :options="options"
  206. clearable
  207. :placeholder="$t('Edb.InputHolderAll.input_menu')"
  208. :config="{ checkStrictly: true }"
  209. />
  210. </el-form-item>
  211. <el-form-item :label="$t('Edb.Detail.e_fre')" prop="frequency">
  212. <el-select
  213. v-model="formData.frequency"
  214. :placeholder="$t('Edb.InputHolderAll.input_fre')"
  215. style="width: 340px"
  216. clearable
  217. >
  218. <el-option
  219. v-for="item in frequencyArr"
  220. :key="item"
  221. :label="item"
  222. :value="item"
  223. >
  224. </el-option>
  225. </el-select>
  226. </el-form-item>
  227. </el-form>
  228. </div>
  229. <div class="dia-bot" v-if="!calulateForm.view">
  230. <el-button
  231. type="primary"
  232. style="margin-right: 20px"
  233. @click="saveHandle"
  234. :loading="dataloading"
  235. v-if="title==='计算指标'"
  236. ><!-- 生成计算指标 -->{{$t('Edb.CalculateBtns.calculate')}}</el-button
  237. >
  238. <el-button
  239. type="primary"
  240. style="margin-right: 20px"
  241. @click="saveHandle"
  242. v-else
  243. ><!-- 保存 -->{{$t('Dialog.confirm_save_btn')}}</el-button
  244. >
  245. <el-button type="primary" plain @click="cancelHandle('cancel')"><!-- 取消 -->{{$t('Dialog.cancel_btn')}}</el-button>
  246. </div>
  247. <el-popover
  248. placement="top-start"
  249. width="360"
  250. trigger="click">
  251. <p style="padding:30px;line-height:25px;" v-html="$parent.tips.get(type)"/>
  252. <span slot="reference" class="tip-label"><!-- 公式说明 -->{{$t('Edb.formula_instru')}}</span>
  253. </el-popover>
  254. </el-dialog>
  255. </template>
  256. <script>
  257. import { dataBaseInterface } from '@/api/api.js';
  258. import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
  259. import { formRules,frequencyArr } from '../databaseComponents/util';
  260. import { unitArr } from '@/utils/defaultOptions';
  261. import {generateSeriesArray} from './util'
  262. const MAXEDBNUM=50//最大可添加的指标数量
  263. const tag_arr = generateSeriesArray();
  264. // for(let i=0;i<26;i++) tag_arr.push(String.fromCharCode(65+i));
  265. export default {
  266. name: '',
  267. props: {
  268. isOpenComputed: {
  269. type: Boolean,
  270. },
  271. title: {
  272. type: String,
  273. default: '计算指标',
  274. },
  275. calulateForm: {
  276. type: Object,
  277. },
  278. calulateList: {
  279. type: Array,
  280. },
  281. edbSource: { // ''||'predict'
  282. type: String,
  283. default: ''
  284. }
  285. },
  286. computed: {
  287. type() {
  288. return this.edbSource ? 31 : 4;
  289. },
  290. /* max空值处理显示 当输入的公式包含MAX、MIN且空值处理为0时,输入公式失焦后出现右侧选项; */
  291. showMaxNullDeal() {
  292. let haveMaxOrMin = this.formulaList.some(_ => _.formula.toUpperCase().includes('MAX') || _.formula.toUpperCase().includes('MIN'))
  293. return haveMaxOrMin && this.nullValueForm.nullValueWay===4
  294. },
  295. formulaDateArr() {
  296. return this.formulaList.map(_ => _.date).filter(_ => _).sort((a,b) => new Date(a)-new Date(b))
  297. },
  298. timeSeriesOpt(){
  299. const arr=[
  300. {
  301. label:'指定指标时间序列',
  302. value:'0',
  303. children:[]
  304. },
  305. {
  306. label:'所有指标时间序列并集',
  307. value:'all',
  308. }
  309. ]
  310. arr[0].children=this.addList.filter(item=>item.target).map(item=>{
  311. return {
  312. label:`指标${item.tag}`,
  313. value:item.tag
  314. }
  315. })
  316. return arr
  317. },
  318. titleMap(){
  319. return new Map([
  320. ['计算指标',this.$t('EtaBasePage.calculate_title')],
  321. ['编辑计算指标',this.$t('EtaBasePage.calculate_edit_title')],
  322. ['查看计算指标',this.$t('EtaBasePage.calculate_view_title')],
  323. ])
  324. },
  325. nullWayOptions(){
  326. return [
  327. { label: this.$t('EtaBasePage.null_val_deal_0'),value: 0 },
  328. { label: this.$t('EtaBasePage.null_val_deal_1'),value: 1 },
  329. { label: this.$t('EtaBasePage.null_val_deal_2'),value: 2 },
  330. { label: this.$t('EtaBasePage.null_val_deal_3'),value: 3 },
  331. { label: this.$t('EtaBasePage.null_val_deal_4'),value: 4 },
  332. ]
  333. },
  334. formTips(){
  335. return {
  336. 'null-val':this.$t('EtaBasePage.null_val_del_hint'),
  337. 'max-null-val':this.$t('EtaBasePage.max_null_val_hint'),
  338. 'formula':this.$t('EtaBasePage.formula_examp_hint')
  339. }
  340. }
  341. },
  342. watch: {
  343. isOpenComputed(newval) {
  344. newval && this.getMenu();
  345. // newval && this.searchTarget('');
  346. /* 回显 */
  347. if (this.calulateList.length && newval) {
  348. this.addList = _.cloneDeep(this.calulateList);
  349. this.formulaList = JSON.parse(this.calulateForm.formula).map(_ => ({
  350. formula: _.f,
  351. date: _.d||''
  352. }));
  353. this.formData = {
  354. targetName: this.calulateForm.targetName,
  355. unit: this.calulateForm.unit,
  356. menu: this.calulateForm.menu,
  357. frequency: this.calulateForm.frequency,
  358. };
  359. this.nullValueForm = {
  360. nullValueWay: this.calulateForm.emptyType,
  361. maxNullWay: this.calulateForm.maxEmptyType,
  362. }
  363. this.searchOptions = this.calulateList.map(item => ({
  364. EdbInfoId: item.target,
  365. EdbName: item.edb_name,
  366. }))
  367. if(this.calulateForm.Extra){
  368. const ExtraObj=JSON.parse(this.calulateForm.Extra)
  369. this.selectTimeSeriesVal=ExtraObj.DateTag
  370. }
  371. this.getNewestDate();
  372. }
  373. },
  374. 'addList':{
  375. handler(n){
  376. if(this.selectTimeSeriesVal=='all') return
  377. const arr=this.addList.filter(item=>item.target).map(item=>{
  378. return {
  379. label:`指标${item.tag}`,
  380. value:item.tag
  381. }
  382. })
  383. if(!arr.length) return
  384. if(!this.selectTimeSeriesVal){
  385. this.selectTimeSeriesVal=arr[0].value
  386. }else{//已经有选择的值了
  387. let flag=false
  388. arr.forEach(item=>{
  389. if(item.value==this.selectTimeSeriesVal){
  390. flag=true
  391. }
  392. })
  393. if(!flag){
  394. this.selectTimeSeriesVal=arr[0].value
  395. }
  396. }
  397. },
  398. deep:true
  399. }
  400. },
  401. data() {
  402. return {
  403. options: [],
  404. levelProps: {
  405. label: 'ClassifyName',
  406. value: 'ClassifyId',
  407. children: 'Children',
  408. checkStrictly: true
  409. },
  410. frequencyArr,
  411. formRules,
  412. unitArr,
  413. addList: [
  414. {
  415. tag: tag_arr[0],
  416. target: '',
  417. start_date: '',
  418. end_date: '',
  419. },
  420. {
  421. tag: tag_arr[1],
  422. target: '',
  423. start_date: '',
  424. end_date: '',
  425. },
  426. {
  427. tag: tag_arr[2],
  428. target: '',
  429. start_date: '',
  430. end_date: '',
  431. },
  432. {
  433. tag: tag_arr[3],
  434. target: '',
  435. start_date: '',
  436. end_date: '',
  437. },
  438. ],
  439. searchOptions: [],
  440. formula: '', //计算公式
  441. formulaList: [ //公式数组
  442. { formula: '', }
  443. ],
  444. dataloading: false,
  445. formData: {
  446. targetName: '',
  447. unit: '',
  448. menu: '',
  449. frequency: '',
  450. },
  451. search_have_more: false,
  452. search_page: 1,
  453. current_search:'',
  454. newestDate: '',
  455. nullValueForm: {
  456. nullValueWay: 0,
  457. maxNullWay: 1
  458. },//空值处理
  459. /* nullWayOptions: [
  460. { label: '查找前后35天最近值',value: 0 },
  461. { label: '不计算',value: 1 },
  462. { label: '前值填充',value: 2 },
  463. { label: '后值填充',value: 3 },
  464. { label: '等于0',value: 4 },
  465. ], */
  466. selectTimeSeriesVal:'',
  467. /* formTips: {
  468. 'null-val': `1、查找前后35天最近值:在参与计算的日期序列上某指标无值时,该指标往前/往后找距离最近的值作为当天的值进行计算,遍历允许跨年,往前最多35天,往后最多35天<br>
  469. 2、不计算:只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值 <br>
  470. 3、前值填充:空值优先以最近的前值填充,没有前值时,用后值填充 <br>
  471. 4、后值填充:空值优先以最近的后值填充,没有前值时,用后值填充 <br>
  472. 5、等于0:空值以0值参与计算 <br>
  473. 注意:此处缺失值的处理,作用于数据全部时间段`,
  474. 'max-null-val': `MAX、MIN公式中指标存在空值时按如下规则处理:<br>
  475. 1、等于0,空值用0参与计算;<br>
  476. 2、跳过空值,去除空值指标,剩余指标进行计算,若该日期所有指标均为空值,则该日期无值;`,
  477. 'formula':`1、支持新增分段,实现不同分段使用不同的计算公式,若未新增分段,则所有日期序列用统一公式计算<br>
  478. 2、新增分段需配置新公式和时间节点,在时间节点之前(不含)使用新公式,在时间节点之后(含)使用已配置公式,每个分段公式支持修改<br>
  479. 3、分段时间节点不允许重复,不允许超出第一个指标的日期区间`
  480. }, */
  481. /* titleMap: new Map([
  482. ['计算指标',this.$t('EtaBasePage.calculate_title')],
  483. ['编辑计算指标',this.$t('EtaBasePage.calculate_edit_title')],
  484. ['查看计算指标',this.$t('EtaBasePage.calculate_view_title')],
  485. ]) */
  486. };
  487. },
  488. methods: {
  489. /* 获取目录结构 */
  490. async getMenu() {
  491. const res = this.edbSource === 'predict'
  492. ? await preDictEdbInterface.classifyListV2()
  493. : await dataBaseInterface.menuListV3({ClassifyType:2})
  494. if (res.Ret !== 200) return
  495. this.filterNodes(res.Data.AllNodes||[]);
  496. this.options = res.Data.AllNodes || [];
  497. },
  498. // 递归改变第三级目录结构
  499. filterNodes(arr) {
  500. arr.length &&
  501. arr.forEach((item) => {
  502. item.Children.length && this.filterNodes(item.Children);
  503. if (!item.Children.length) {
  504. delete item.Children;
  505. }
  506. });
  507. },
  508. /* 添加额外的指标列 */
  509. addTargetHandle() {
  510. const MAXNUM=this.edbSource === 'predict'?26:MAXEDBNUM
  511. if(this.addList.length >=MAXNUM) return this.$message.warning(this.$t('EtaBasePage.num_overrun_msg'))
  512. let tag = this.addList[this.addList.length-1].tag;
  513. let index = tag_arr.findIndex(item => item === tag);
  514. const item = {
  515. tag: tag_arr[index+1],
  516. target: '',
  517. start_date: '',
  518. end_date: ''
  519. };
  520. this.addList.push(item);
  521. },
  522. /* 搜索指标 */
  523. searchTarget(query) {
  524. this.search_page = 1;
  525. this.current_search = query;
  526. this.searchApi(this.current_search);
  527. },
  528. /* 聚焦获取当前检索 */
  529. inputFocusHandle(e) {
  530. this.search_page = 1;
  531. this.current_search = e.target.value;
  532. this.searchApi(this.current_search);
  533. },
  534. async searchApi(query,page=1) {
  535. const res = this.edbSource === 'predict'
  536. ? await preDictEdbInterface.edbSearch({
  537. Keyword: query,
  538. CurrentIndex: page,
  539. FilterSource: this.type === 45 ? 3 : this.type === 66 ? 6 : 1,
  540. Frequency: this.type===64?'季度': ''
  541. })
  542. : await dataBaseInterface.targetSearchByPage({
  543. KeyWord:query,
  544. CurrentIndex: page,
  545. FilterSource: this.type === 14 ? 3 : this.type === 63 ? 6 : 1,
  546. Frequency: this.type===61?'季度': ''
  547. })
  548. if(res.Ret !== 200) return
  549. const { List,Paging } = res.Data;
  550. this.search_have_more = page < Paging.Pages;
  551. this.searchOptions = page === 1 ? List : this.searchOptions.concat(List);
  552. },
  553. searchLoad() {
  554. if(!this.search_have_more) return;
  555. this.searchApi(this.current_search,++this.search_page)
  556. },
  557. /* 选中指标 显示开始日期结束日期 */
  558. chooseTarget(val) {
  559. if (val) {
  560. const choose_obj = this.searchOptions.find(
  561. (item) => item.EdbInfoId === val
  562. );
  563. this.addList.forEach((list) => {
  564. if (list.target === val) {
  565. list.start_date = choose_obj.StartDate;
  566. list.end_date = choose_obj.EndDate;
  567. this.getNewestDate();
  568. }
  569. });
  570. }
  571. },
  572. /* 获取所选日期最早日期 */
  573. getNewestDate() {
  574. let dateArr = this.addList.filter(_ => _.end_date).map(_ => new Date(_.end_date).getTime())
  575. let earliestDate = Math.min(...dateArr);
  576. let sameDateArr = dateArr.filter(_ => _===earliestDate)
  577. if(dateArr.length === 1 || sameDateArr.length===dateArr.length) {
  578. this.newestDate = '';
  579. return
  580. }
  581. this.newestDate = this.$moment(Math.min(...dateArr)).format('YYYY-MM-DD');
  582. },
  583. /* 清空指标和关联日期 */
  584. clearHandle(index) {
  585. this.addList[index].start_date = '';
  586. this.addList[index].end_date = '';
  587. this.getNewestDate();
  588. },
  589. // 删除指标
  590. delTarget(index) {
  591. this.addList.splice(index, 1);
  592. this.getNewestDate();
  593. },
  594. async saveHandle() {
  595. if (!this.formulaList[0].formula) return this.$message.warning(/* '计算公式不能为空' */this.$t('EtaBasePage.input_formula_valid'));
  596. await this.$refs.diaForm.validate();
  597. // 指标id数组
  598. let EdbInfoIdArr = this.addList.filter((item) => item.target).map((item) => ({
  599. EdbInfoId: item.target,
  600. FromTag: item.tag,
  601. }));
  602. let formulaArr = this.formulaList
  603. .filter((_,index) => index===0||(index>0&&_.formula&&_.date))
  604. .map(_ => ({f: _.formula,d: _.date}))
  605. const { nullValueWay,maxNullWay } = this.nullValueForm;
  606. let params = {
  607. CalculateFormula: JSON.stringify(formulaArr),
  608. ClassifyId: this.formData.menu[this.formData.menu.length - 1] || 0,
  609. EdbName: this.formData.targetName,
  610. Frequency: this.formData.frequency,
  611. Unit: this.formData.unit,
  612. EdbInfoIdArr,
  613. EmptyType: nullValueWay,
  614. MaxEmptyType: maxNullWay,
  615. Extra:JSON.stringify({
  616. DateTag:this.selectTimeSeriesVal
  617. })
  618. };
  619. this.dataloading = true;
  620. let res;
  621. if(this.edbSource === 'predict') {
  622. res = await preDictEdbInterface.calculateEdbSave(this.calulateForm.edb_id ? {...params,EdbInfoId:this.calulateForm.edb_id } : params)
  623. }else {
  624. res = this.calulateForm.edb_id
  625. ? await dataBaseInterface.calculateEdit({...params,EdbInfoId: this.calulateForm.edb_id})
  626. : await dataBaseInterface.calculateAdd(params)
  627. }
  628. this.dataloading = false;
  629. if (res.Ret !== 200) return
  630. this.$message.success(res.Msg);
  631. this.calulateForm.edb_id
  632. ? this.$emit('addCallBack','edit')
  633. : this.$emit('addCallBack','add',{ code:res.Data.UniqueCode,id:res.Data.EdbInfoId,classifyId:params.ClassifyId });
  634. this.init();
  635. },
  636. /* 新增公式分段 */
  637. addFormulaHandle() {
  638. let addItem = {
  639. formula: this.formulaList[this.formulaList.length-1].formula,
  640. date: ''
  641. }
  642. this.formulaList.push(addItem)
  643. },
  644. /* 移除公式 */
  645. removeFormulaItem(index) {
  646. this.formulaList.splice(index,1)
  647. },
  648. /* 选择日期 检验排 */
  649. selectFormulaDate(val,item) {
  650. console.log(val,item)
  651. const { start_date,end_date } = this.addList[0];
  652. if(!start_date) return
  653. let dateStamp = new Date(val).getTime(),
  654. startStamp = new Date(start_date).getTime(),
  655. endStamp = new Date(end_date).getTime();
  656. if (dateStamp > endStamp || dateStamp < startStamp) {
  657. item.date = '';
  658. return this.$message.warning('分段日期必须在第一个指标日期区间')
  659. }
  660. else if(this.formulaList.filter(_ => _.date===val).length>1) {
  661. item.date = '';
  662. return this.$message.warning('分段日期不可重复')
  663. }
  664. },
  665. init() {
  666. this.$refs.diaForm.resetFields();
  667. this.addList = [
  668. {
  669. tag: tag_arr[0],
  670. target: '',
  671. start_date: '',
  672. end_date: '',
  673. },
  674. {
  675. tag: tag_arr[1],
  676. target: '',
  677. start_date: '',
  678. end_date: '',
  679. },
  680. {
  681. tag: tag_arr[2],
  682. target: '',
  683. start_date: '',
  684. end_date: '',
  685. },
  686. {
  687. tag: tag_arr[3],
  688. target: '',
  689. start_date: '',
  690. end_date: '',
  691. },
  692. ];
  693. this.searchOptions = [];
  694. this.formula = '';
  695. this.formData = {
  696. targetName: '',
  697. unit: '',
  698. menu: '',
  699. frequency: '',
  700. };
  701. this.formulaList = [
  702. { formula: '' }
  703. ]
  704. this.nullValueForm = {
  705. nullValueWay: 0,
  706. maxNullWay: 1
  707. }
  708. },
  709. cancelHandle(type) {
  710. this.init();
  711. this.$emit('cancel');
  712. type==='cancel' && !this.calulateForm.edb_id && this.$emit('openPrev');
  713. },
  714. },
  715. mounted() {},
  716. };
  717. </script>
  718. <style lang="scss">
  719. .computed-dialog {
  720. max-width: 1200px !important;
  721. width:85vw;
  722. overflow: hidden;
  723. div::-webkit-scrollbar {
  724. width: 6px !important;
  725. }
  726. .el-dialog__body {
  727. max-height: 840px;
  728. overflow: auto;
  729. }
  730. .dialog-main {
  731. padding: 25px 42px 25px 25px;
  732. @media screen and (max-height:850px){
  733. box-sizing: border-box;
  734. height: 65vh;
  735. overflow-y: auto;
  736. }
  737. .el-cascader .el-input {
  738. width: 340px;
  739. }
  740. .add-cont {
  741. display: flex;
  742. flex-wrap: wrap;
  743. justify-content: space-between;
  744. .add-li {
  745. position: relative;
  746. margin-bottom: 48px;
  747. .li-tag {
  748. font-size: 16px;
  749. margin-right: 8px;
  750. }
  751. .del-tag {
  752. position: absolute;
  753. right: -30px;
  754. top: 12px;
  755. font-size: 16px;
  756. cursor: pointer;
  757. }
  758. .target-date {
  759. color: #5882ef;
  760. position: absolute;
  761. bottom: -25px;
  762. left: 24px;
  763. &.newest {
  764. color: #f00;
  765. }
  766. }
  767. }
  768. }
  769. .add-icon {
  770. font-size: 16px;
  771. color: #5882ef;
  772. cursor: pointer;
  773. }
  774. .computed-min {
  775. margin: 50px 0;
  776. padding-bottom: 40px;
  777. border-bottom: 1px dashed #aab4cc;
  778. .computed-section {
  779. display: flex;
  780. margin-top: 20px;
  781. .el-cascader .el-input {
  782. width: 100%;
  783. }
  784. }
  785. .label {
  786. padding:10px 10px 10px 0;
  787. }
  788. .example-txt {
  789. display: block;
  790. margin-top: 10px;
  791. }
  792. .formula-item {
  793. display: flex;
  794. align-items: center;
  795. margin-bottom: 15px;
  796. }
  797. .date-section-text {
  798. margin-left: 15px;
  799. }
  800. }
  801. }
  802. .dia-bot {
  803. padding-bottom: 40px;
  804. display: flex;
  805. justify-content: center;
  806. }
  807. .tip-label {
  808. position: absolute;
  809. bottom: 30px;
  810. right: 30px;
  811. color: #409EFF;
  812. cursor: pointer;
  813. }
  814. }
  815. </style>