OtherCalculate.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. <script setup>
  2. import {ref,reactive} from 'vue'
  3. import { useRoute, useRouter } from "vue-router";
  4. import SelectEDB from './SelectEDB.vue'
  5. import SelectEDBClassify from '../../components/SelectEDBClassify.vue'
  6. import SelectEDBUnit from '../../components/SelectEDBUnit.vue'
  7. import SelectEDBFrequency from '../../components/SelectEDBFrequency.vue'
  8. import SeeEDBDataList from './SeeEDBDataList.vue'
  9. import {calculateTypeTipsMap} from '../../util/config'
  10. import { showToast } from 'vant';
  11. import apiDataEDB from '@/api/dataEDB'
  12. const route=useRoute()
  13. const router=useRouter()
  14. const moveTypeOpts=[{name:'领先',key:1},{name:'滞后',key:2}]
  15. const moveUnitOpts=[
  16. {name:'天',key:'天'},
  17. {name:'周',key:'周'},
  18. {name:'月',key:'月'},
  19. {name:'季',key:'季'},
  20. {name:'年',key:'年'},
  21. ]
  22. //公式说明
  23. const showTips=ref(false)
  24. const tipsContent=ref(calculateTypeTipsMap.get(['toMonthSeason','accumulate'].includes(route.query.source)? route.query.source: Number(route.query.source))||'')
  25. //提交计算按钮文字
  26. function getCalculateBtnText(){
  27. let str='生成计算指标'
  28. const btnTextMap=new Map([
  29. [5,'转月值计算'],
  30. [6,'同比值计算'],
  31. [7,'同差值计算'],
  32. [8,'移动平均计算'],
  33. [12,'环比值计算'],
  34. [13,'环差值计算'],
  35. [14,'升频计算'],
  36. [22,'保存'],
  37. [35,'超季节性计算'],
  38. [52,'年化计算'],
  39. [51,'降频计算'],
  40. [61,'转季值计算'],
  41. [62,'累计值计算'],
  42. [63,'年初至今计算'],
  43. ])
  44. str=btnTextMap.get(source.value)
  45. return str
  46. }
  47. const editEdbInfoId=ref(route.query.edbInfoId||0)//编辑时的指标id
  48. const source=ref(0)//计算类型
  49. const tabsArr=ref([])
  50. // 初始化
  51. function init(){
  52. // 累计值转月/季值
  53. if(route.query.source==='toMonthSeason'){
  54. tabsArr.value=[{ label: '累计值转月值',key: 5 },{ label: '累计值转季值',key: 61 }]
  55. source.value=5
  56. }else if(route.query.source==='accumulate'){//累计值
  57. tabsArr.value=[{ label: '累计值',key: 62 },{ label: '年初至今累计值',key: 63 }]
  58. source.value=62
  59. }else{
  60. tabsArr.value=[]
  61. source.value=Number(route.query.source)
  62. }
  63. }
  64. init()
  65. // 选择指标
  66. const showSelectEDB=ref(false)
  67. const selectEDBinfo=ref(null)
  68. function handleConfirmSelectEDB(e){
  69. selectEDBinfo.value=e
  70. updateBaseInfoData(e)
  71. }
  72. // 选择指标更新基础信息
  73. function updateBaseInfoData(data){
  74. const tMap=new Map([
  75. ['日度','D'],
  76. ['周度','W'],
  77. ['旬度','T'],
  78. ['月度','M'],
  79. ['季度','Q'],
  80. ['年度','Y'],
  81. ])
  82. const name_map = {
  83. 5: data.EdbName,
  84. 8: `${data.EdbName}/${baseInfo.numberN}${tMap.get(data.Frequency)}MA`,
  85. 14: `${data.EdbName}/${data.Frequency}升频`,
  86. 6: `${data.EdbName}同比`,
  87. 7: `${data.EdbName}同差`,
  88. 12: `${data.EdbName}${baseInfo.numberN}${data.Frequency.slice(0,1)}环比`,
  89. 13: `${data.EdbName}${baseInfo.numberN}${data.Frequency.slice(0,1)}环差`,
  90. 35: `${data.EdbName}超季节性/${baseInfo.numberN}年${baseInfo.calendarType==='公历'?'':'/'+baseInfo.calendarType}`,
  91. 52: `${data.EdbName}年化`,
  92. 51: `${data.EdbName}/${data.Frequency}降频`,
  93. 61: data.EdbName,
  94. 62: data.EdbName,
  95. 63: data.EdbName,
  96. }
  97. baseInfo.name=name_map[source.value]||''
  98. baseInfo.unit=[5,8,14,7,35].includes(source.value) ? data.Unit : '无',
  99. baseInfo.frequency=source.value === 14 ? '日度' : source.value === 61 ? '季度' : source.value === 62 ? '' : data.Frequency
  100. // baseInfo.classify=data.ClassifyId
  101. // selectEDBClassifyINS.value?.getSelectClassifyOpt(data.ClassifyId)//获取选择的分类目录
  102. }
  103. // 基础信息
  104. const edbNameInputFocus=ref(false)
  105. const numberNInputFocus=ref(false)
  106. const baseInfo=reactive({
  107. name:'',
  108. unit:'',
  109. classify:'',
  110. frequency:'',
  111. numberN:1,//N值
  112. moveVal:'',
  113. moveType:1,
  114. moveUnit:'天',
  115. calendarType:'公历',
  116. valueType:'期末值'
  117. })
  118. // 选择单位
  119. const showSelectUnit=ref(false)
  120. function onConfirmSelectUnit(value){
  121. baseInfo.unit=value
  122. }
  123. //选择分类
  124. const showSelectClassify=ref(false)
  125. const classifyStr=ref('')
  126. const selectEDBClassifyINS=ref(null)
  127. function handleConfirmClassify({value,selectedOptions}){
  128. baseInfo.classify=value
  129. classifyStr.value=`${selectedOptions[0].ClassifyName}/${selectedOptions[1].ClassifyName}/${selectedOptions[2].ClassifyName}`
  130. }
  131. //选择频度
  132. const showSelectFrequency=ref(false)
  133. function handleConfirmFrequency(value){
  134. baseInfo.frequency=value
  135. }
  136. //移动方式类型选择
  137. const showMoveType=ref(false)
  138. function onSelectMoveType(e){
  139. baseInfo.moveType=e.key
  140. }
  141. function getMoveTypeName(e){
  142. return moveTypeOpts.filter(item=>item.key===e)[0].name
  143. }
  144. //移动方式单位选择
  145. const showMoveUnit=ref(false)
  146. function onSelectMoveUnit(e){
  147. baseInfo.moveUnit=e.key
  148. }
  149. //超季节性日历选择
  150. const showSelectCalendar=ref(false)
  151. //降频数据取值选择
  152. const showDataValSelect=ref(false)
  153. //查看指标数据详情
  154. const showSeeEDBDataList=ref(false)
  155. // 提交计算
  156. const saveBtnLoading=ref(false)
  157. async function handleSave(){
  158. if(!selectEDBinfo.value){
  159. showToast('指标不能为空')
  160. return
  161. }
  162. if(!baseInfo.name){
  163. showToast('指标名称不能为空')
  164. return
  165. }
  166. if(!baseInfo.unit){
  167. showToast('指标单位不能为空')
  168. return
  169. }
  170. if(!baseInfo.classify){
  171. showToast('指标目录不能为空')
  172. return
  173. }
  174. if(!baseInfo.frequency){
  175. showToast('指标频度不能为空')
  176. return
  177. }
  178. const valueMap = {
  179. 22: 'moveVal',
  180. 51: 'valueType'
  181. }
  182. const params={
  183. FromEdbInfoId: selectEDBinfo.value.EdbInfoId,
  184. Source: source.value,
  185. EdbName: baseInfo.name,
  186. Unit: baseInfo.unit,
  187. ClassifyId: baseInfo.classify,
  188. Frequency: baseInfo.frequency,
  189. Formula: valueMap[source.value] ? String(baseInfo[valueMap[source.value]]) : String(baseInfo.numberN),
  190. MoveFrequency: baseInfo.moveUnit,
  191. MoveType: baseInfo.moveType,
  192. Calendar: baseInfo.calendarType,
  193. }
  194. saveBtnLoading.value=true
  195. const res=await apiDataEDB.addCalculateEDB(params)
  196. saveBtnLoading.value=false
  197. if(res.Ret===200){
  198. showToast(res.Msg)
  199. setTimeout(() => {
  200. router.back()
  201. }, 1500);
  202. }
  203. }
  204. // tab切换重置表单
  205. function handleTabChange(){
  206. selectEDBinfo.value=null
  207. baseInfo.name=''
  208. baseInfo.unit=''
  209. baseInfo.classify=''
  210. baseInfo.frequency=''
  211. baseInfo.numberN=1
  212. baseInfo.moveVal=''
  213. baseInfo.moveType=1
  214. baseInfo.moveUnit='天'
  215. baseInfo.calendarType='公历'
  216. baseInfo.valueType='期末值'
  217. classifyStr.value=''
  218. }
  219. </script>
  220. <template>
  221. <div class="other-calculate-wrap">
  222. <van-tabs
  223. v-model:active="source"
  224. sticky
  225. border
  226. title-active-color="#0052D9"
  227. title-inactive-color="#333"
  228. line-width="16px"
  229. @change="handleTabChange"
  230. v-if="tabsArr.length"
  231. >
  232. <van-tab
  233. :title="tab.label"
  234. :name="tab.key"
  235. v-for="tab in tabsArr"
  236. :key="tab.key"
  237. />
  238. </van-tabs>
  239. <section class="section select-edb-box">
  240. <van-field
  241. :modelValue="selectEDBinfo?.EdbName"
  242. label="选择指标"
  243. is-link
  244. readonly
  245. placeholder="请选择指标"
  246. input-align="right"
  247. @click-input="showSelectEDB=true"
  248. >
  249. <template #left-icon>
  250. <div class="left-icon" v-if="selectEDBinfo">
  251. <svg-icon name="edb-history-tag" size="24px"/>
  252. </div>
  253. </template>
  254. </van-field>
  255. </section>
  256. <section class="section edbinfo-box">
  257. <div class="van-cell__title">已选指标</div>
  258. <div v-if="!selectEDBinfo">
  259. <img class="list-empty-img" src="https://hzstatic.hzinsights.com/static/ETA_mobile/empty_img.png" alt="">
  260. <p style="text-align:center;color:#999">暂无指标</p>
  261. </div>
  262. <div class="info-box" v-else>
  263. <h2 class="name">{{selectEDBinfo?.EdbName}}</h2>
  264. <ul class="info-list">
  265. <li class="info-item">ID:{{selectEDBinfo.EdbCode}}</li>
  266. <li class="info-item">起始时间:{{selectEDBinfo.StartDate}}</li>
  267. <li class="info-item">频度:{{selectEDBinfo.Frequency}}</li>
  268. <li class="info-item">最新日期:{{selectEDBinfo.LatestDate}}</li>
  269. <li class="info-item">单位:{{selectEDBinfo.Unit}}</li>
  270. <li class="info-item">最新值:{{selectEDBinfo.LatestValue}}</li>
  271. <li class="info-item" style="width:100%">最近更新:{{selectEDBinfo.ModifyTime}}</li>
  272. <li class="info-item" style="width:100%">数据来源:{{selectEDBinfo.SourceName}}</li>
  273. </ul>
  274. <div style="text-align:right">
  275. <van-button color="#0052D9" size="small" @click="showSeeEDBDataList=true">查看数据</van-button>
  276. </div>
  277. </div>
  278. </section>
  279. <section class="section baseinfo-box">
  280. <!-- 时间位移(移动方式) -->
  281. <van-field
  282. label="移动方式"
  283. required
  284. v-if="source===22"
  285. >
  286. <template #input>
  287. <div class="move-type-box">
  288. <div class="btn" @click="showMoveType=true">
  289. <svg-icon name="swap"></svg-icon>
  290. <span>{{getMoveTypeName(baseInfo.moveType)}}</span>
  291. </div>
  292. <input class="input" type="number" :min="0" v-model="baseInfo.moveVal">
  293. <div class="btn" @click="showMoveUnit=true">
  294. <svg-icon name="swap"></svg-icon>
  295. <span>{{baseInfo.moveUnit}}</span>
  296. </div>
  297. </div>
  298. </template>
  299. </van-field>
  300. <van-field
  301. v-model="baseInfo.name"
  302. label="指标名称"
  303. placeholder="指标名称"
  304. input-align="right"
  305. required
  306. @focus="edbNameInputFocus=true"
  307. @blur="edbNameInputFocus=false"
  308. >
  309. <template #right-icon>
  310. <svg-icon class="edit-icon" name="edit" :color="edbNameInputFocus?'#0052D9':'#333333'"/>
  311. </template>
  312. </van-field>
  313. <van-field
  314. :modelValue="baseInfo.unit"
  315. readonly
  316. label="单位"
  317. placeholder="请选择单位"
  318. input-align="right"
  319. right-icon="arrow"
  320. required
  321. @click-input="showSelectUnit=true"
  322. :disabled="!editEdbInfoId&&[6,7].includes(source)"
  323. />
  324. <van-field
  325. :modelValue="classifyStr"
  326. readonly
  327. label="指标目录"
  328. placeholder="请选择指标目录"
  329. input-align="right"
  330. right-icon="arrow"
  331. required
  332. @click-input="showSelectClassify=true"
  333. />
  334. <van-field
  335. :modelValue="baseInfo.frequency"
  336. readonly
  337. label="频度"
  338. placeholder="请选择指标频度"
  339. input-align="right"
  340. right-icon="arrow"
  341. required
  342. @click-input="showSelectFrequency=true"
  343. :disabled="[5,14,61,63].includes(source)||(!editEdbInfoId&&[6,7].includes(source))"
  344. />
  345. <van-field
  346. v-if="[8,12,13,35].includes(source)"
  347. v-model.number="baseInfo.numberN"
  348. label="N等于"
  349. placeholder="请输入N数值"
  350. input-align="right"
  351. required
  352. @focus="numberNInputFocus=true"
  353. @blur="numberNInputFocus=false"
  354. >
  355. <template #right-icon>
  356. <svg-icon class="edit-icon" name="edit" :color="numberNInputFocus?'#0052D9':'#333333'"/>
  357. </template>
  358. </van-field>
  359. <!-- 超季节性日历 -->
  360. <van-field
  361. v-if="source===35"
  362. :modelValue="baseInfo.calendarType"
  363. readonly
  364. label="日历"
  365. placeholder="请选择日历"
  366. input-align="right"
  367. right-icon="arrow"
  368. required
  369. @click-input="showSelectCalendar=true"
  370. />
  371. <!-- 降频数据取值 -->
  372. <van-field
  373. v-if="source===51"
  374. :modelValue="baseInfo.valueType"
  375. readonly
  376. label="数据取值"
  377. placeholder="请选择"
  378. input-align="right"
  379. right-icon="arrow"
  380. @click-input="showDataValSelect=true"
  381. />
  382. </section>
  383. <div class="formula-intro-btn" @click="showTips=true">
  384. <svg-icon class="icon" name="warning"></svg-icon>
  385. <span>公式说明</span>
  386. </div>
  387. <div class="opt-btns">
  388. <van-button class="primary2" @click="$router.back()">取消</van-button>
  389. <van-button
  390. type="primary"
  391. :loading="saveBtnLoading"
  392. loading-text="计算中..."
  393. @click="handleSave"
  394. >{{getCalculateBtnText()}}</van-button>
  395. </div>
  396. </div>
  397. <!-- 选择指标 -->
  398. <SelectEDB v-model:show="showSelectEDB" :source='source' @select="handleConfirmSelectEDB"/>
  399. <!-- 选择单位 -->
  400. <SelectEDBUnit v-model:show="showSelectUnit" @select="onConfirmSelectUnit"/>
  401. <!-- 选择分类 -->
  402. <SelectEDBClassify ref="selectEDBClassifyINS" v-model:show="showSelectClassify" :defaultId="baseInfo.classify" @select="handleConfirmClassify" />
  403. <!-- 选择频度 -->
  404. <SelectEDBFrequency v-model:show="showSelectFrequency" @select="handleConfirmFrequency"/>
  405. <!-- 查看指标数据 -->
  406. <SeeEDBDataList v-model:show="showSeeEDBDataList" :edbInfoId="selectEDBinfo?.EdbInfoId" />
  407. <!-- 移动方式类型选择 -->
  408. <van-action-sheet v-model:show="showMoveType" close-on-click-action :actions="moveTypeOpts" @select="onSelectMoveType" />
  409. <!-- 移动方式单位选择 -->
  410. <van-action-sheet v-model:show="showMoveUnit" close-on-click-action :actions="moveUnitOpts" @select="onSelectMoveUnit" />
  411. <!-- 超季节性日历选择 -->
  412. <van-action-sheet v-model:show="showSelectCalendar" close-on-click-action :actions="[{name:'公历'},{name:'农历'}]" @select="e=>baseInfo.calendarType=e.name" />
  413. <!-- 降频数据取值 -->
  414. <van-action-sheet v-model:show="showDataValSelect" close-on-click-action :actions="[{name:'期末值'},{name:'平均值'}]" @select="e=>baseInfo.valueType=e.name" />
  415. <!-- 公式说明 -->
  416. <van-dialog
  417. v-model:show="showTips"
  418. :title="$route.query.name"
  419. confirmButtonText='知道啦'
  420. >
  421. <div class="edb-formula-tips-html-box" v-html="tipsContent"></div>
  422. </van-dialog>
  423. </template>
  424. <style lang="scss" scoped>
  425. .other-calculate-wrap{
  426. min-height: 90vh;
  427. background-color: $page-bg-grey;
  428. padding-bottom: 210px ;
  429. }
  430. .section{
  431. background-color: #fff;
  432. margin-bottom: 32px;
  433. }
  434. .edbinfo-box{
  435. padding: var(--van-cell-horizontal-padding);
  436. .info-box{
  437. margin-top: 14px;
  438. border-radius: 8px;
  439. border: 1px solid $border-color;
  440. box-shadow: $box-shadow;
  441. padding: 20px;
  442. .name{
  443. font-size: 32px;
  444. margin: 0 0 10px 0;
  445. }
  446. .info-list{
  447. display: flex;
  448. flex-wrap: wrap;
  449. gap: 10px 0;
  450. color: $font-grey;
  451. margin-bottom: 10px;
  452. .info-item{
  453. width: 50%;
  454. }
  455. }
  456. }
  457. }
  458. .move-type-box{
  459. width: 100%;
  460. display: flex;
  461. align-items: center;
  462. justify-content: flex-end;
  463. gap: 20px;
  464. .input{
  465. box-sizing: border-box;
  466. display: block;
  467. border-radius: 12px;
  468. width: 150px;
  469. height: 72px;
  470. padding: 0 32px;
  471. background-color: #f6f6f6;
  472. }
  473. .btn{
  474. flex-shrink: 0;
  475. display: flex;
  476. align-items: center;
  477. justify-content: center;
  478. width: 130px;
  479. height: 72px;
  480. border-radius: 12px;
  481. background-color: #F2F3FF;
  482. color: $theme-color;
  483. }
  484. }
  485. .formula-intro-btn{
  486. width: 180px;
  487. height: 60px;
  488. display: flex;
  489. align-items: center;
  490. justify-content: center;
  491. gap: 5px;
  492. color: $theme-color;
  493. line-height: 1;
  494. background-color: #fff;
  495. border-radius: 32px;
  496. margin-left: auto;
  497. margin-right: var(--van-cell-horizontal-padding);
  498. .icon{
  499. width: 24px;
  500. height: 24px;
  501. }
  502. }
  503. .opt-btns{
  504. position: fixed;
  505. left: 0;
  506. right: 0;
  507. bottom: 0;
  508. background-color: #fff;
  509. z-index: 99;
  510. padding: 48px;
  511. display: flex;
  512. justify-content: space-between;
  513. .van-button{
  514. width: 48%;
  515. }
  516. }
  517. </style>