diffusionIndexDia.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. <template>
  2. <el-dialog
  3. :visible.sync="isShow"
  4. :close-on-click-modal="false"
  5. :modal-append-to-body="false"
  6. @close="cancelHandle"
  7. custom-class="diffusionIndex-dialog"
  8. center
  9. width="1200px"
  10. top="5vh"
  11. v-dialogDrag
  12. >
  13. <div slot="title" style="display: flex; align-items: center">
  14. <img
  15. :src="$icons.computed"
  16. style="color: #fff; width: 16px; height: 16px; margin-right: 5px"
  17. />
  18. <span style="font-size: 16px"><!-- 扩散指数 -->{{$t('Edb.CalculatesAll.diff_index')}}</span>
  19. </div>
  20. <div class="dialog-main">
  21. <div class="main-top">
  22. <ul class="target-ul">
  23. <li class="target-li" v-for="(list, index) in targetList" :key="index">
  24. <span class="li-tag">{{ list.tag }}</span>
  25. <el-select
  26. v-model="list.target"
  27. v-loadMore="searchLoad"
  28. :filterable="!list.target"
  29. clearable
  30. :placeholder="$t('Edb.InputHolderAll.input_name')"
  31. style="width: 400px"
  32. @change="chooseTarget"
  33. @clear="clearHandle(index)"
  34. remote
  35. :remote-method="searchTarget"
  36. @click.native="inputFocusHandle"
  37. >
  38. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  39. <el-option
  40. v-for="item in searchOptions"
  41. :key="item.EdbInfoId"
  42. :label="$parent.currentLang==='en'?(item.EdbNameEn||item.EdbName):item.EdbName"
  43. :value="item.EdbInfoId"
  44. :disabled="!item.HaveOperaAuth"
  45. >
  46. <div>
  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. </el-option>
  57. </el-select>
  58. <i
  59. class="el-icon-error del-tag"
  60. v-if="index > 1"
  61. @click="delTarget(index)"
  62. />
  63. <span class="target-date" v-if="list.start_date">{{
  64. `${list.start_date}${$t('Common.to')}${list.end_date}`
  65. }}</span>
  66. </li>
  67. </ul>
  68. <span class="add-icon" @click="addTargetHandle">
  69. <i class="el-icon-circle-plus-outline" style="color: #5882ef; font-size: 16px"/>
  70. {{$t('EtaBasePage.add_more_edb')}}
  71. </span>
  72. <div class="date_select_wrapper">
  73. <label style="flex-shrink:0"><!-- 扩散指标日期 -->{{$t('EtaBasePage.label_diff_date')}}</label>
  74. <el-radio-group
  75. v-model="formData.date_type"
  76. style="margin: 0 30px;flex-shrink:0"
  77. @change="initSelectHandle"
  78. :disabled="operationForm.view"
  79. >
  80. <el-radio :label="1">{{$t('EtaBasePage.label_date_tab1')}}</el-radio>
  81. <el-radio :label="2">{{$t('EtaBasePage.label_date_tab2')}}</el-radio>
  82. </el-radio-group>
  83. <el-checkbox-group v-model="formData.select_date" v-if="formData.date_type===2" :disabled="operationForm.view">
  84. <el-checkbox v-for="item in targetList" :key="item.target" :label="item.tag" style="margin: 0 15px 10px 0" @change="setConcatDate">{{item.tag}}</el-checkbox>
  85. </el-checkbox-group>
  86. </div>
  87. <div class="concat-date" v-if="formData.date_type===2 && formData.select_date.length && concat_date.start">{{concat_date.start}} {{$t('Common.to')}} {{concat_date.end}}</div>
  88. </div>
  89. <el-form
  90. ref="form"
  91. inline
  92. class="form-cont"
  93. label-position="left"
  94. label-width="120px"
  95. :model="formData"
  96. :rules="formRules"
  97. :disabled="operationForm.view"
  98. >
  99. <el-form-item :label="$t('Edb.Detail.e_name')" prop="targetName" style="margin-right: 40px;">
  100. <el-input
  101. v-model="formData.targetName"
  102. style="width: 340px"
  103. :placeholder="$t('Edb.InputHolderAll.input_name')"
  104. />
  105. </el-form-item>
  106. <el-form-item :label="$t('Edb.Detail.e_unit')" prop="unit">
  107. <selectUnit
  108. v-model="formData.unit"
  109. style="width:340px"
  110. :disabled="type===53"
  111. />
  112. </el-form-item>
  113. <el-form-item :label="$t('Edb.Detail.e_menu')" prop="menu" style="margin-right: 40px;">
  114. <el-cascader
  115. v-model="formData.menu"
  116. :options="options"
  117. :props="levelProps"
  118. clearable
  119. :placeholder="$t('Edb.InputHolderAll.input_menu')"
  120. style="width: 340px"
  121. />
  122. </el-form-item>
  123. <el-form-item :label="$t('Edb.Detail.e_fre')" prop="frequency">
  124. <el-select
  125. v-model="formData.frequency"
  126. :placeholder="$t('Edb.InputHolderAll.input_fre')"
  127. style="width: 340px"
  128. clearable
  129. >
  130. <el-option
  131. v-for="item in frequencyArr"
  132. :key="item.label"
  133. :label="item.label"
  134. :value="item.value"
  135. >
  136. </el-option>
  137. </el-select>
  138. </el-form-item>
  139. </el-form>
  140. </div>
  141. <div class="dia-bot" v-if="!operationForm.view">
  142. <el-button
  143. type="primary"
  144. style="margin-right: 20px"
  145. @click="saveHandle"
  146. :loading="loading"
  147. >{{loading ? $t('Edb.calculate_ing') : operationForm.edb_id ? $t('Dialog.confirm_save_btn') : $t('Edb.CalculateBtns.diff_index')}}</el-button
  148. >
  149. <el-button type="primary" plain @click="cancelHandle('cancel')"><!-- 取消 -->{{$t('Dialog.cancel_btn')}}</el-button>
  150. </div>
  151. <el-popover
  152. placement="top-start"
  153. width="360"
  154. trigger="click">
  155. <p v-if="isPredict" style="padding:30px;line-height:25px;" v-html="$parent.tips.get(type)"/>
  156. <p v-else style="padding:30px;line-height:25px;" v-html="$parent.tips.get(type)"/>
  157. <span slot="reference" class="tip-label"><!-- 公式说明 -->{{$t('Edb.formula_instru')}}</span>
  158. </el-popover>
  159. </el-dialog>
  160. </template>
  161. <script>
  162. import { dataBaseInterface } from '@/api/api.js';
  163. import { formRules,generateSeriesArray } from './util';
  164. import * as preDictEdbInterface from '@/api/modules/predictEdbApi.js';
  165. import { unitArr,frequencySelectList } from '@/utils/defaultOptions';
  166. const MAXEDBNUM=50//最大可添加的指标数量
  167. const tag_arr = generateSeriesArray();
  168. // for(let i=0;i<26;i++) tag_arr.push(String.fromCharCode(65+i));
  169. export default {
  170. name:'',
  171. props: {
  172. isShow: {
  173. type: Boolean
  174. },
  175. type: {
  176. type: Number
  177. },
  178. operationForm: {
  179. type: Object,
  180. },
  181. isPredict:{//是否是预测指标
  182. type: Boolean,
  183. default:false
  184. }
  185. },
  186. watch: {
  187. isShow(newval) {
  188. newval && this.getMenu();
  189. if(newval && this.operationForm.edb_id) {
  190. const backData = _.cloneDeep(this.operationForm);
  191. this.formData = {
  192. targetName: backData.targetName,
  193. menu: backData.menu,
  194. frequency: backData.frequency,
  195. unit: backData.unit,
  196. date_type: JSON.parse(backData.date).DateType,
  197. select_date: JSON.parse(backData.date).CheckList || []
  198. }
  199. this.targetList = backData.from_arr.map(item => ({
  200. tag: item.FromTag,
  201. target: item.FromEdbInfoId,
  202. start_date: item.StartDate,
  203. end_date: item.EndDate
  204. })
  205. )
  206. //options 回显
  207. this.searchOptions = backData.from_arr.map(item => ({
  208. EdbInfoId: item.FromEdbInfoId,
  209. EdbName: item.FromEdbName,
  210. StartDate: item.StartDate,
  211. EndDate: item.EndDate,
  212. }))
  213. this.formData.select_date.length && this.formData.date_type === 2 && this.setConcatDate()
  214. }
  215. if(newval&&this.type===53&&!this.operationForm.edb_id){
  216. this.formData.unit='无'
  217. }
  218. }
  219. },
  220. data () {
  221. return {
  222. searchOptions:[],//指标列表
  223. formData: {
  224. targetName:'',
  225. unit:'',
  226. menu:'',
  227. frequency:'',
  228. date_type: 1,
  229. select_date: []
  230. },
  231. formRules,
  232. unitArr,
  233. options: [],
  234. levelProps: {
  235. label: 'ClassifyName',
  236. value: 'ClassifyId',
  237. children: 'Children',
  238. checkStrictly: true
  239. },
  240. /* frequencyArr, */
  241. fre_options: ['天','周','月','季','年'],
  242. loading:false,
  243. search_have_more: false,
  244. search_page: 1,
  245. current_search: '',
  246. targetList: [
  247. {
  248. tag: tag_arr[0],
  249. target: '',
  250. start_date: '',
  251. end_date: '',
  252. },
  253. {
  254. tag: tag_arr[1],
  255. target: '',
  256. start_date: '',
  257. end_date: '',
  258. }
  259. ],
  260. concat_date: {
  261. start: '',
  262. end: ''
  263. }
  264. };
  265. },
  266. computed:{
  267. frequencyArr(){
  268. return frequencySelectList(['半年度'])
  269. }
  270. },
  271. methods: {
  272. /* 指标列表 */
  273. searchTarget(query) {
  274. this.search_page = 1;
  275. this.current_search = query;
  276. this.searchApi(this.current_search);
  277. },
  278. /* 聚焦获取当前检索 */
  279. inputFocusHandle(e) {
  280. this.search_page = 1;
  281. this.current_search = e.target.value;
  282. this.searchApi(this.current_search);
  283. },
  284. async searchApi(query,page=1) {
  285. const params={
  286. KeyWord:query,
  287. CurrentIndex: page
  288. }
  289. const res=this.isPredict
  290. ? await preDictEdbInterface.edbSearch(params)
  291. : await dataBaseInterface.targetSearchByPage(params)
  292. if(res.Ret !== 200) return
  293. const { List,Paging } = res.Data;
  294. this.search_have_more = page < Paging.Pages;
  295. let arr = page === 1 ? List : this.searchOptions.concat(List);
  296. this.searchOptions = this.operationForm.edb_id ? arr.filter(item => item.EdbInfoId !== this.operationForm.edb_id) : arr;
  297. },
  298. searchLoad() {
  299. if(!this.search_have_more) return;
  300. this.searchApi(this.current_search,++this.search_page)
  301. },
  302. /* 选中指标 显示开始日期结束日期 */
  303. chooseTarget(val) {
  304. if (val) {
  305. const choose_obj = this.searchOptions.find(item => item.EdbInfoId === val);
  306. this.targetList.forEach(list => {
  307. if (list.target === val) {
  308. list.start_date = choose_obj.StartDate;
  309. list.end_date = choose_obj.EndDate;
  310. }
  311. });
  312. this.formData.select_date.length && this.formData.date_type === 2 && this.setConcatDate()
  313. }
  314. },
  315. /* 清空指标和关联日期 */
  316. clearHandle(index) {
  317. this.targetList[index].start_date = '';
  318. this.targetList[index].end_date = '';
  319. },
  320. initSelectHandle() {
  321. this.formData.select_date=[];
  322. this.concat_date = {
  323. start: '',
  324. end: ''
  325. }
  326. },
  327. /* 获取目录结构 */
  328. async getMenu() {
  329. const res = this.isPredict
  330. ? await preDictEdbInterface.classifyListV2()
  331. : await dataBaseInterface.menuListV3()
  332. if (res.Ret === 200) {
  333. this.filterNodes(res.Data.AllNodes||[]);
  334. this.options = res.Data.AllNodes || [];
  335. }
  336. },
  337. // 递归改变第三级目录结构
  338. filterNodes(arr) {
  339. arr.length &&
  340. arr.forEach((item) => {
  341. item.Children.length && this.filterNodes(item.Children);
  342. if (!item.Children.length) {
  343. delete item.Children;
  344. }
  345. });
  346. },
  347. /* 显示合并日期 */
  348. setConcatDate() {
  349. if(!this.formData.select_date) {
  350. this.concat_date = {
  351. start: '',
  352. end: ''
  353. }
  354. return
  355. }
  356. let arr = this.targetList.filter(_ => this.formData.select_date.includes(_.tag)&&_.target)
  357. .map(_ =>([ new Date(_.start_date).getTime(),new Date(_.end_date).getTime()])).flat(Infinity)
  358. this.concat_date = arr.length ? {
  359. start: this.$moment(Math.min(...arr)).format('YYYY-MM-DD'),
  360. end:this.$moment(Math.max(...arr)).format('YYYY-MM-DD'),
  361. } : { start: '', end: '' }
  362. },
  363. /* 过滤负数 小数点*/
  364. filterCode(item) {
  365. item.moveVal=item.moveVal.replace(/[^\.\d]/g,'').replace('.','');
  366. },
  367. /* 添加指标 */
  368. addTargetHandle() {
  369. const NUM=this.isPredict?26:MAXEDBNUM
  370. if(this.targetList.length === NUM) return this.$message.warning(this.$t('EtaBasePage.num_overrun_msg'))
  371. let tag = this.targetList[this.targetList.length-1].tag;
  372. let index = tag_arr.findIndex(item => item === tag);
  373. const item = {
  374. tag: tag_arr[index+1],
  375. target: '',
  376. start_date: '',
  377. end_date: ''
  378. };
  379. this.targetList.push(item);
  380. },
  381. // 删除指标
  382. delTarget(index) {
  383. this.targetList.splice(index, 1);
  384. },
  385. init() {
  386. this.searchOptions = [];
  387. this.formData = {
  388. targetName:'',
  389. unit:'',
  390. menu:'',
  391. frequency:'',
  392. date_type: 1,
  393. select_date: []
  394. };
  395. this.targetList = [
  396. {
  397. tag: tag_arr[0],
  398. target: '',
  399. start_date: '',
  400. end_date: '',
  401. },
  402. {
  403. tag: tag_arr[1],
  404. target: '',
  405. start_date: '',
  406. end_date: '',
  407. }
  408. ]
  409. this.$refs.form.resetFields();
  410. },
  411. /* 保存 */
  412. async saveHandle() {
  413. let filterArr = this.targetList.filter(item=> item.target);
  414. if(!filterArr.length) return this.$message.warning('请选择指标');
  415. await this.$refs.form.validate();
  416. this.loading = true;
  417. const {
  418. targetName,
  419. unit,
  420. menu,
  421. frequency,
  422. date_type,
  423. select_date
  424. } = this.formData;
  425. let params ={
  426. Source: this.type,
  427. EdbName: targetName,
  428. Unit: unit,
  429. ClassifyId: menu[menu.length - 1],
  430. Frequency: frequency,
  431. Formula: JSON.stringify({ DateType: date_type,CheckList: select_date }),
  432. EdbInfoIdArr: filterArr.map(_=>({ EdbInfoId: _.target,FromTag: _.tag })),
  433. }
  434. const res = this.operationForm.edb_id
  435. ? this.isPredict?await preDictEdbInterface.operateEdbSave({...params,EdbInfoId: this.operationForm.edb_id}):await dataBaseInterface.calculateTargetEdit({ ...params,EdbInfoId: this.operationForm.edb_id })
  436. : this.isPredict?await preDictEdbInterface.operateEdbSave(params):await dataBaseInterface.calculateTargetSave(params)
  437. this.loading = false;
  438. if (res.Ret !== 200) return
  439. this.$message.success(res.Msg);
  440. this.operationForm.edb_id
  441. ? this.$emit('addCallBack','edit')
  442. : this.$emit('addCallBack','add',{ code:res.Data.UniqueCode,id:res.Data.EdbInfoId,classifyId:params.ClassifyId });
  443. this.init();
  444. },
  445. /* 关闭弹窗 */
  446. cancelHandle(type) {
  447. this.init()
  448. this.$emit('cancel');
  449. type==='cancel' && !this.operationForm.edb_id && this.$emit('openPrev');
  450. },
  451. },
  452. }
  453. </script>
  454. <style lang="scss">
  455. .diffusionIndex-dialog {
  456. div::-webkit-scrollbar {
  457. width: 6px !important;
  458. }
  459. .el-input-number .el-input__inner {
  460. padding: 0 34px 0 4px;
  461. }
  462. .el-dialog__body {
  463. max-height: 780px;
  464. overflow: auto;
  465. }
  466. .el-cascader .el-input {
  467. width: 100%;
  468. }
  469. }
  470. </style>
  471. <style lang='scss' scoped>
  472. .diffusionIndex-dialog {
  473. position: relative;
  474. .form-cont {
  475. margin-top: 40px;
  476. padding-top: 30px;
  477. border-top: 1px dashed #AAB4CC;
  478. }
  479. .date_select_wrapper {
  480. display: flex;
  481. margin-top: 30px;
  482. }
  483. .concat-date {
  484. margin-top: 40px;
  485. color:#5882ef
  486. }
  487. .dialog-main {
  488. padding: 0 50px 30px;
  489. .target-ul {
  490. display: flex;
  491. flex-wrap: wrap;
  492. justify-content: space-between;
  493. margin-bottom: 30px;
  494. .target-li {
  495. position: relative;
  496. margin-bottom: 30px;
  497. .li-tag {
  498. font-size: 16px;
  499. margin-right: 8px;
  500. }
  501. .del-tag {
  502. position: absolute;
  503. right: -30px;
  504. top: 12px;
  505. font-size: 16px;
  506. cursor: pointer;
  507. }
  508. .target-date {
  509. color: #5882ef;
  510. position: absolute;
  511. bottom: -25px;
  512. left: 24px;
  513. }
  514. }
  515. }
  516. .add-icon {
  517. font-size: 16px;
  518. color: #5882ef;
  519. cursor: pointer;
  520. }
  521. }
  522. .dia-bot {
  523. padding: 20px 0 30px;
  524. display: flex;
  525. justify-content: center;
  526. }
  527. .tip-cont {
  528. padding: 30px;
  529. }
  530. .tip-label {
  531. position: absolute;
  532. bottom: 30px;
  533. right: 30px;
  534. color: #409EFF;
  535. cursor: pointer;
  536. }
  537. }
  538. </style>