JointCalculate.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. <script setup>
  2. import apiDataEDB from '@/api/dataEDB'
  3. import {ref,reactive, computed,watch} from 'vue'
  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 SelectDate from '@/components/SelectDate.vue'
  9. import { showToast } from 'vant'
  10. import { useRoute, useRouter } from 'vue-router'
  11. const route=useRoute()
  12. const router=useRouter()
  13. const props=defineProps({
  14. edbInfo:{
  15. type:Object,
  16. default:null
  17. }
  18. })
  19. watch(
  20. ()=>props.edbInfo,
  21. ()=>{
  22. if(['edit','preview'].includes(route.query.type)){
  23. const edbInfoData=props.edbInfo.EdbInfoDetail
  24. if(edbInfoData.Source===24){//累计同比拼接
  25. tabActive.value=2
  26. }else{
  27. tabActive.value=1
  28. jointDate.value=edbInfoData.CalculateFormula
  29. }
  30. const temBeforeEDBInfo=props.edbInfo.CalculateList.find(item => item.FromTag === 'A')
  31. const temAfterEDBInfo=props.edbInfo.CalculateList.find(item => item.FromTag === 'B')
  32. beforeEDBInfo.value={
  33. EdbName:temBeforeEDBInfo.FromEdbName,
  34. EdbInfoId:temBeforeEDBInfo.FromEdbInfoId,
  35. EndDate:temBeforeEDBInfo.EndDate,
  36. StartDate:temBeforeEDBInfo.StartDate
  37. }
  38. afterEBDInfo.value={
  39. EdbName:temAfterEDBInfo.FromEdbName,
  40. EdbInfoId:temAfterEDBInfo.FromEdbInfoId,
  41. EndDate:temAfterEDBInfo.EndDate,
  42. StartDate:temAfterEDBInfo.StartDate
  43. }
  44. baseInfo.name=edbInfoData.EdbName
  45. baseInfo.unit=edbInfoData.Unit
  46. baseInfo.classify=edbInfoData.ClassifyId
  47. baseInfo.frequency=edbInfoData.Frequency
  48. setTimeout(() => {
  49. selectEDBClassifyINS.value?.getSelectClassifyOpt(props.edbInfo.EdbInfoDetail.ClassifyId)//获取选择的分类目录
  50. }, 1000);
  51. }
  52. }
  53. )
  54. // 预览页面
  55. const isPreview=ref(route.query.type==='preview'||false)
  56. //公式说明
  57. const tipsConfig=new Map([
  58. [1,`
  59. 直接拼接说明:<br>
  60. 1、选取拼接日期<br>
  61. 2、在拼接日期之前的数据选择指标A<br>
  62. 3、拼接日期之后的数据选择指标B<br>
  63. 4、新指标的起始日期为A的开始日期,更新时间跟随指标B进行更新<br>
  64. 5、指标A和B可以是原始指标,也可以是计算指标
  65. `],
  66. [2,`
  67. 累计值同比拼接说明:<br>
  68. 1、只支持月频度的指标进行累计值同比拼接<br>
  69. 2、如果出现有空值运算,则返回空值<br>
  70. 3、选取待拼接指标A和同比值指标B<br>
  71. 4、搜索到指标A最后一个12月31日有值的年份,并且向前回溯12个值(12个月),分别乘以下一年同期对应的同比增长率(B),公式为【A*(1+同期增长率(B)/100)】,得到下一年每个月的绝对值,再用新得到的下一年的12个月的值再乘以再下一年同期对应的同比增长率,得到再下一年每个月的绝对值<br>
  72. 5、以此类推,直到运算至指标B的最新值,得到新的序列C<br>
  73. 6、新指标是将序列C和指标A进行直接拼接,拼接日期选取指标A中有值的年份的年末最后一天即12月31日,再与序列C的起始日期做拼接<br>
  74. 7、新指标跟随指标B进行更新
  75. `],
  76. ])
  77. const showTips=ref(false)
  78. const tipsContent=computed(()=>{
  79. return tipsConfig.get(tabActive.value)
  80. })
  81. const tabsArr=ref([{ label: '直接拼接',key: 1 },{ label: '累计同比拼接',key: 2 }])
  82. const tabActive=ref(1)
  83. function handleTabChange(){
  84. jointDate.value=''
  85. beforeEDBInfo.value=null
  86. afterEBDInfo.value=null
  87. baseInfo.name=''
  88. baseInfo.unit=''
  89. baseInfo.classify=''
  90. baseInfo.frequency=''
  91. }
  92. //拼接日期
  93. const jointDate=ref('')
  94. const showSelectJointDate=ref(false)
  95. function handleConfirmJointDate(e){
  96. jointDate.value=e
  97. }
  98. // 选择指标
  99. const selectEDBSearchParams=ref({})
  100. const beforeEDBInfo=ref(null)
  101. const afterEBDInfo=ref(null)
  102. const showSelectEDB=ref(false)
  103. let currentSelectEDBType=''//当前是选择哪个指标
  104. function handleShowSelectEDB(type){
  105. if(isPreview.value) return
  106. currentSelectEDBType=type
  107. if(tabActive.value===2&&type==='before'){//累计同比值拼接选择待拼接指标搜索指标时Frequency传月度
  108. selectEDBSearchParams.value={Frequency:'月度'}
  109. }else{
  110. selectEDBSearchParams.value={}
  111. }
  112. showSelectEDB.value=true
  113. }
  114. function handleConfirmSelectEDB(e){
  115. if(currentSelectEDBType==='before'){
  116. beforeEDBInfo.value=e
  117. }else{
  118. afterEBDInfo.value=e
  119. }
  120. }
  121. // 基础信息
  122. const edbNameInputFocus=ref(false)
  123. const baseInfo=reactive({
  124. name:'',
  125. unit:'',
  126. classify:'',
  127. frequency:''
  128. })
  129. // 选择单位
  130. const showSelectUnit=ref(false)
  131. function onConfirmSelectUnit(value){
  132. baseInfo.unit=value
  133. }
  134. //选择分类
  135. const showSelectClassify=ref(false)
  136. const classifyStr=ref('')
  137. const selectEDBClassifyINS=ref(null)
  138. function handleConfirmClassify({value,selectedOptions}){
  139. if(selectedOptions.length===0){
  140. baseInfo.classify=''
  141. classifyStr.value=''
  142. return
  143. }
  144. baseInfo.classify=value
  145. const textArr=selectedOptions.map(item=>item.ClassifyName)
  146. classifyStr.value=`${textArr.join('/')}`
  147. }
  148. //选择频度
  149. const showSelectFrequency=ref(false)
  150. function handleConfirmFrequency(value){
  151. baseInfo.frequency=value
  152. }
  153. // 提交计算
  154. const saveBtnLoading=ref(false)
  155. async function handleSave(){
  156. if(tabActive.value===1&&!jointDate.value){
  157. showToast('拼接日期不能为空')
  158. return
  159. }
  160. if(!beforeEDBInfo.value){
  161. showToast(tabActive.value===1?'指标不能为空':'待拼接指标不能为空')
  162. return
  163. }
  164. if(!afterEBDInfo.value){
  165. showToast(tabActive.value===1?'指标不能为空':'指标不能为空')
  166. return
  167. }
  168. if(!baseInfo.name){
  169. showToast('指标名称不能为空')
  170. return
  171. }
  172. if(!baseInfo.unit){
  173. showToast('指标单位不能为空')
  174. return
  175. }
  176. if(!baseInfo.classify){
  177. showToast('指标目录不能为空')
  178. return
  179. }
  180. if(!baseInfo.frequency){
  181. showToast('指标频度不能为空')
  182. return
  183. }
  184. const baseParams={
  185. ClassifyId:baseInfo.classify,
  186. EdbName:baseInfo.name,
  187. Frequency:baseInfo.frequency,
  188. Unit:baseInfo.unit,
  189. }
  190. const params=tabActive.value===1?{
  191. ...baseParams,
  192. EdbInfoIdArr:[
  193. {EdbInfoId:afterEBDInfo.value.EdbInfoId}
  194. ],
  195. Formula:jointDate.value,
  196. FromEdbInfoId:beforeEDBInfo.value.EdbInfoId,
  197. Source:23
  198. }:{
  199. ...baseParams,
  200. EdbInfoIdArr:[
  201. {EdbInfoId:afterEBDInfo.value.EdbInfoId}
  202. ],
  203. FromEdbInfoId:beforeEDBInfo.value.EdbInfoId,
  204. Source:24
  205. }
  206. saveBtnLoading.value=true
  207. const res=route.query.type==='edit'?await apiDataEDB.editCalculateEDB({...params,EdbInfoId:Number(route.query.edbInfoId)}) : await apiDataEDB.addCalculateEDB(params)
  208. saveBtnLoading.value=false
  209. if(res.Ret===200){
  210. showToast(route.query.type==='edit'?'编辑成功':'新增成功')
  211. setTimeout(() => {
  212. if(route.query.type==='edit'){
  213. router.back()
  214. }else{
  215. router.replace({
  216. path:'/dataEDB/detail',
  217. query:{
  218. edbInfoId:res.Data.EdbInfoId
  219. }
  220. })
  221. }
  222. }, 1500);
  223. }
  224. }
  225. </script>
  226. <template>
  227. <div class="joint-calculate-wrap">
  228. <van-tabs
  229. v-model:active="tabActive"
  230. sticky
  231. border
  232. title-active-color="#0052D9"
  233. title-inactive-color="#333"
  234. line-width="16px"
  235. @change="handleTabChange"
  236. v-if="!['edit','preview'].includes($route.query.type)"
  237. >
  238. <van-tab
  239. :title="tab.label"
  240. :name="tab.key"
  241. v-for="tab in tabsArr"
  242. :key="tab.key"
  243. />
  244. </van-tabs>
  245. <section class="section select-edb-box">
  246. <van-field
  247. :modelValue="jointDate"
  248. readonly
  249. label="拼接日期"
  250. placeholder="请选择日期"
  251. input-align="right"
  252. :right-icon="!isPreview?'arrow':''"
  253. required
  254. @click-input="showSelectJointDate=true"
  255. v-if="tabActive===1"
  256. :disabled="isPreview"
  257. />
  258. <van-field
  259. label-width="7em"
  260. :label="tabActive===1?'拼接日期之前':'待拼接指标'"
  261. required
  262. :right-icon="!isPreview?'arrow':''"
  263. @click-input="handleShowSelectEDB('before')"
  264. :disabled="isPreview"
  265. >
  266. <template #input>
  267. <div class="edb-info-box">
  268. <div class="edb-info" v-if="beforeEDBInfo">
  269. <span class="name">{{beforeEDBInfo.EdbName}}</span>
  270. <span class="time" v-if="tabActive===1">(起始日期:{{beforeEDBInfo.StartDate}})</span>
  271. <span class="time" v-if="tabActive===2">(截至日期:{{beforeEDBInfo.EndDate}})</span>
  272. </div>
  273. <span class="placeholder" v-else>请选择指标</span>
  274. </div>
  275. </template>
  276. </van-field>
  277. <van-field
  278. label-width="7em"
  279. :label="tabActive===1?'拼接日期之后':'同比值指标'"
  280. :right-icon="!isPreview?'arrow':''"
  281. required
  282. @click-input="handleShowSelectEDB('after')"
  283. :disabled="isPreview"
  284. >
  285. <template #input>
  286. <div class="edb-info-box">
  287. <div class="edb-info" v-if="afterEBDInfo">
  288. <span class="name">{{afterEBDInfo.EdbName}}</span>
  289. <span class="time" v-if="tabActive===1">(最新日期:{{afterEBDInfo.EndDate}})</span>
  290. </div>
  291. <span class="placeholder" v-else>请选择指标</span>
  292. </div>
  293. </template>
  294. </van-field>
  295. </section>
  296. <section class="section baseinfo-box">
  297. <van-field
  298. v-model="baseInfo.name"
  299. label="指标名称"
  300. placeholder="指标名称"
  301. input-align="right"
  302. required
  303. @focus="edbNameInputFocus=true"
  304. @blur="edbNameInputFocus=false"
  305. :disabled="isPreview"
  306. >
  307. <template #right-icon>
  308. <svg-icon v-if="!isPreview" class="edit-icon" name="edit" :color="edbNameInputFocus?'#0052D9':'#333333'"/>
  309. </template>
  310. </van-field>
  311. <van-field
  312. :modelValue="baseInfo.unit"
  313. readonly
  314. label="单位"
  315. placeholder="请选择单位"
  316. input-align="right"
  317. :right-icon="!isPreview?'arrow':''"
  318. required
  319. @click-input="showSelectUnit=true"
  320. :disabled="isPreview"
  321. />
  322. <van-field
  323. :modelValue="classifyStr"
  324. readonly
  325. label="指标目录"
  326. placeholder="请选择指标目录"
  327. input-align="right"
  328. :right-icon="!isPreview?'arrow':''"
  329. required
  330. @click-input="showSelectClassify=true"
  331. :disabled="isPreview"
  332. />
  333. <van-field
  334. :modelValue="baseInfo.frequency"
  335. readonly
  336. label="频度"
  337. placeholder="请选择指标频度"
  338. input-align="right"
  339. :right-icon="!isPreview?'arrow':''"
  340. required
  341. @click-input="showSelectFrequency=true"
  342. :disabled="isPreview"
  343. />
  344. </section>
  345. <div class="formula-intro-btn" @click="showTips=true">
  346. <svg-icon class="icon" name="warning"></svg-icon>
  347. <span>公式说明</span>
  348. </div>
  349. <div class="opt-btns" v-if="!isPreview">
  350. <van-button class="primary2" @click="$router.back()">取消</van-button>
  351. <van-button
  352. type="primary"
  353. :loading="saveBtnLoading"
  354. loading-text="计算中..."
  355. @click="handleSave"
  356. >保存</van-button>
  357. </div>
  358. </div>
  359. <!-- 选择拼接日期 -->
  360. <SelectDate v-model:show="showSelectJointDate" @select="handleConfirmJointDate"/>
  361. <!-- 选择指标 -->
  362. <SelectEDB v-model:show="showSelectEDB" :params="selectEDBSearchParams" @select="handleConfirmSelectEDB"/>
  363. <!-- 选择单位 -->
  364. <SelectEDBUnit v-model:show="showSelectUnit" @select="onConfirmSelectUnit"/>
  365. <!-- 选择分类 -->
  366. <SelectEDBClassify ref="selectEDBClassifyINS" :defaultId="baseInfo.classify" v-model:show="showSelectClassify" @select="handleConfirmClassify" />
  367. <!-- 选择频度 -->
  368. <SelectEDBFrequency v-model:show="showSelectFrequency" @select="handleConfirmFrequency"/>
  369. <!-- 公式说明 -->
  370. <van-dialog
  371. v-model:show="showTips"
  372. :title="$route.query.name"
  373. confirmButtonText='知道啦'
  374. >
  375. <div class="edb-formula-tips-html-box" v-html="tipsContent"></div>
  376. </van-dialog>
  377. </template>
  378. <style lang="scss" scoped>
  379. .joint-calculate-wrap{
  380. min-height: 90vh;
  381. background-color: $page-bg-grey;
  382. padding-bottom: 210px ;
  383. }
  384. .section{
  385. background-color: #fff;
  386. margin-bottom: 32px;
  387. }
  388. .select-edb-box{
  389. :deep(.van-cell__right-icon){
  390. align-self: center;
  391. color: #333;
  392. }
  393. .edb-info-box{
  394. width: 100%;
  395. text-align: right;
  396. .placeholder{
  397. color: var(--van-text-color-3);
  398. }
  399. .edb-info{
  400. display: flex;
  401. flex-direction: column;
  402. }
  403. .time{
  404. color: $font-grey_999;
  405. font-size: 24px;
  406. }
  407. }
  408. }
  409. .formula-intro-btn{
  410. width: 180px;
  411. height: 60px;
  412. display: flex;
  413. align-items: center;
  414. justify-content: center;
  415. gap: 5px;
  416. color: $theme-color;
  417. line-height: 1;
  418. background-color: #fff;
  419. border-radius: 32px;
  420. margin-left: auto;
  421. margin-right: var(--van-cell-horizontal-padding);
  422. .icon{
  423. width: 24px;
  424. height: 24px;
  425. }
  426. }
  427. .opt-btns{
  428. position: fixed;
  429. left: 0;
  430. right: 0;
  431. bottom: 0;
  432. background-color: #fff;
  433. z-index: 99;
  434. padding: 48px;
  435. display: flex;
  436. justify-content: space-between;
  437. .van-button{
  438. width: 48%;
  439. max-width: 300PX;
  440. }
  441. }
  442. @media screen and (min-width:$media-width){
  443. .joint-calculate-wrap{
  444. padding-bottom: 105px;
  445. }
  446. .section{
  447. margin-bottom: 16px;
  448. }
  449. .formula-intro-btn{
  450. width: 90px;
  451. height: 30px;
  452. gap: 2px;
  453. border-radius: 16px;
  454. .icon{
  455. width: 12px;
  456. height: 12px;
  457. }
  458. }
  459. .opt-btns{
  460. padding: 24px;
  461. justify-content: center;
  462. gap: 10px;
  463. }
  464. }
  465. </style>