edbDetail.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. <template>
  2. <div class="edb-detail-data-wrap">
  3. <div class="handle-list">
  4. <span class="editsty" @click="$emit('handle',{item:edbInfo.Detail,type:'edit'})" v-if="hasEditAuth"><!-- 编辑 -->{{$t('Table.edit_btn')}}</span>
  5. <span class="editsty" @click="$emit('handle',{item:edbInfo.Detail,type:'addToBase'})" v-if="edbInfo.Detail&&edbInfo.Detail.IsJoinEdb===0&&permissionBtn.isShowBtn('dataSourcePermission','manualDataWrite_add')"><!-- 加入指标库 -->{{$t('ManualEntryPage.add_tobase')}}</span>
  6. <span class="editsty" @click="$emit('handle',{item:edbInfo.Detail,type:'logs'})"><!-- 操作日志 -->{{$t('ManualEntryPage.opera_logs')}}</span>
  7. <span class="deletesty" @click="$emit('handle',{item:edbInfo.Detail,type:'del'})" v-if="edbInfo.Detail&&edbInfo.Detail.IsJoinEdb===0&&permissionBtn.isShowBtn('dataSourcePermission','manualDataWrite_del')"><!-- 删除 -->{{$t('Table.delete_btn')}}</span>
  8. </div>
  9. <el-table
  10. :data="tableData"
  11. class="firstColumTable"
  12. border
  13. >
  14. <el-table-column
  15. v-for="item in tableColumsOne"
  16. :key="item.key"
  17. :width="item.widthsty"
  18. :label="item.label"
  19. :min-width="item.minwidthsty"
  20. align="center">
  21. <template slot-scope="scope">
  22. <span v-if="item.key === 'Unit'">{{ getUnitTrans(scope.row.Unit) }}</span>
  23. <span v-else-if="item.key === 'Frequency'">{{ getFrequencyTrans(scope.row.Frequency) }}</span>
  24. <span v-else>{{ scope.row[item.key] }}</span>
  25. </template>
  26. </el-table-column>
  27. </el-table>
  28. <el-table
  29. :data="tableData"
  30. style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);"
  31. border>
  32. <el-table-column
  33. v-for="item in tableColumsTwo"
  34. :key="item.label"
  35. :label="item.label"
  36. :width="item.widthsty"
  37. :min-width="item.minwidthsty"
  38. align="center"
  39. >
  40. <template slot-scope="scope">
  41. <span>{{ scope.row[item.key] }}</span>
  42. </template>
  43. </el-table-column>
  44. <div slot="empty" style="padding: 50px 0 50px;">
  45. <tableNoData :text="$t('Table.prompt_slogan')"/>
  46. </div>
  47. </el-table>
  48. <div class="bottom">
  49. <div class="left-select" ref="url" v-if="yearsList.length">
  50. <el-button
  51. type="primary"
  52. v-for="year in yearsList"
  53. :key="year"
  54. @click="handleLinkPostion(year)"
  55. >{{year}}</el-button>
  56. </div>
  57. <div
  58. class="value-ul"
  59. ref="valueUl"
  60. @scroll="handleLoadData"
  61. >
  62. <div class="total-cont" :style="{height: totalHeight}" v-if="dataList.length"></div>
  63. <ul
  64. class="list-wrapper"
  65. @contextmenu.prevent="handleRightClick"
  66. v-if="dataList.length"
  67. >
  68. <li
  69. class="value-item"
  70. v-for="(item,rindex) in renderDataList"
  71. :key="rindex"
  72. >
  73. <div
  74. :class="['value-label',
  75. { 'select': rindex===rightMouseMenu.rindex && rightMouseMenu.cindex === 0 }
  76. ]"
  77. >
  78. <el-date-picker
  79. v-model="item.Dt"
  80. type="date"
  81. :placeholder="$t('Edb.InputHolderAll.input_date')"
  82. :data-rindex="rindex"
  83. :data-cindex="0"
  84. :clearable="false"
  85. :editable="false"
  86. value-format="yyyy-MM-dd"
  87. :readonly="readonly"
  88. :disabled="!hasEditAuth"
  89. @mousedown.native="e=> { readonly = e.button===2?true:false }"
  90. prefix-icon="none"
  91. @input="handleTimeChange(rindex, item)"
  92. @focus="handleTimeFocus(rindex, item)"
  93. ></el-date-picker>
  94. </div>
  95. <div
  96. :class="['value-label',
  97. { 'select': rindex===rightMouseMenu.rindex && rightMouseMenu.cindex === 1 }
  98. ]"
  99. :data-rindex="rindex"
  100. :data-cindex="1"
  101. >
  102. <input
  103. @focus="handleInputFocus(item, rindex, 1)"
  104. @blur="handleInputChange(item)"
  105. @input="handleInput(item)"
  106. class="input-val-box"
  107. type="number"
  108. v-model="item.Close"
  109. :data-rindex="rindex"
  110. :data-cindex="1"
  111. :disabled="!hasEditAuth"
  112. />
  113. </div>
  114. </li>
  115. </ul>
  116. <tableNoData :text="$t('Table.prompt_slogan')" v-else/>
  117. </div>
  118. </div>
  119. <!-- 右键菜单 -->
  120. <div
  121. class="right-lick-menu"
  122. @mouseleave="hideContextMenu"
  123. >
  124. <div class="item" @click="handleOptTable('insert_up_row')">
  125. <!-- 向上插入 -->{{$t('ManualEntryPage.insert_up_row')}}
  126. <el-input v-model="rightMouseMenu.insertUpRows" size="mini" style="width:50px;" @change="val => { rightMouseMenu.insertUpRows = Number(val) }" @click.native.stop/>
  127. </div>
  128. <div class="item" @click="handleOptTable('insert_down_row')">
  129. <!-- 向下插入 -->{{$t('ManualEntryPage.insert_down_row')}}
  130. <el-input v-model="rightMouseMenu.insertDownRows" size="mini" style="width:50px;" @change="val => { rightMouseMenu.insertDownRows = Number(val) }" @click.native.stop/>
  131. </div>
  132. <div class="item" @click="handleOptTable('del_row')"><!-- 删除行 -->{{$t('ManualEntryPage.right_op_delrow')}}</div>
  133. </div>
  134. </div>
  135. </template>
  136. <script>
  137. import { dataInterence } from '@/api/api.js';
  138. export default {
  139. props: {
  140. id: {
  141. type: String
  142. }
  143. },
  144. computed: {
  145. tableColumsOne(){
  146. return [
  147. {
  148. label: this.$t('Edb.Detail.e_id'),
  149. key: 'TradeCode',
  150. minwidthsty: '150px'
  151. },
  152. {
  153. label: this.$t('Edb.Detail.e_name'),
  154. key: 'SecName',
  155. minwidthsty: '200px'
  156. },
  157. {
  158. label: this.$t('Edb.Detail.e_fre'),
  159. key: 'Frequency',
  160. widthsty: '100px'
  161. },
  162. {
  163. label: this.$t('Edb.Detail.e_unit'),
  164. key: 'Unit',
  165. widthsty: '100px'
  166. },
  167. ]
  168. },
  169. tableColumsTwo() {
  170. return [
  171. {
  172. label: this.$t('Edb.Detail.e_menu'),
  173. key: 'ClassifyName',
  174. minwidthsty: '150px',
  175. },
  176. {
  177. label: this.$t('Edb.Detail.e_start_time'),
  178. key: 'StartDate',
  179. minwidthsty: '115px',
  180. },
  181. {
  182. label: this.$t('Edb.Detail.e_update_time'),
  183. key: 'ModifyTime',
  184. minwidthsty: '120px',
  185. },
  186. {
  187. label: this.$t('Edb.creater'),
  188. key: 'UserName',
  189. widthsty: '160px',
  190. }
  191. ]
  192. },
  193. yearsList() {
  194. if(!this.edbInfo.Detail) return []
  195. if(!['日度','周度'].includes(this.edbInfo.Detail.Frequency)) return []
  196. let years = [];
  197. this.dataList.forEach(_ => {
  198. if(!years.includes(_.Dt.substring(0,4))&&_.Dt) {
  199. years.push(_.Dt.substring(0,4))
  200. }
  201. })
  202. return years;
  203. },
  204. totalHeight() {
  205. return `${this.dataList.length*45}px`
  206. },
  207. renderDataList() {
  208. console.log(this.startIndex,this.endIndex)
  209. console.log(this.dataList.slice(this.startIndex,this.endIndex))
  210. return this.dataList.slice(this.startIndex,this.endIndex)
  211. },
  212. hasEditAuth() {
  213. return this.permissionBtn.isShowBtn('dataSourcePermission','manualDataWrite_edit')
  214. }
  215. },
  216. watch: {
  217. id(newval) {
  218. if(!newval) return
  219. this.$refs.valueUl.scrollTop = 0;
  220. this.rightMouseMenu.rindex=-1;
  221. this.rightMouseMenu.cindex=-1;
  222. this.getEdbDetail()
  223. }
  224. },
  225. data() {
  226. return {
  227. tableData: [],
  228. edbInfo: {},
  229. // yearsList: [],
  230. dataList: [],
  231. startIndex: 0,
  232. endIndex: 100,
  233. readonly: false,//日期只读
  234. temInputVal:{},
  235. tempTime:'',
  236. rightMouseMenu: {
  237. rindex:-1,
  238. cindex:-1,
  239. insertUpRows: 1,
  240. insertDownRows: 1,
  241. }
  242. }
  243. },
  244. mounted(){
  245. this.getEdbDetail()
  246. },
  247. methods:{
  248. /* 获取指标详情 */
  249. async getEdbDetail() {
  250. let loading = this.$loading({
  251. lock: true,
  252. text: `${this.$t('Table.data_loading')}...`,
  253. target: '.edb-detail-data-wrap',
  254. spinner: 'el-icon-loading',
  255. background: 'rgba(255, 255, 255, 0.8)'
  256. })
  257. const res = await dataInterence.getEdbDetailV2({
  258. TradeCode: this.id
  259. })
  260. loading.close()
  261. if(res.Ret !== 200) return
  262. this.edbInfo = res.Data;
  263. res.Data.Detail.ClassifyName = res.Data.ClassifyList.map(_ => _.ClassifyName).join('/')
  264. this.tableData = [res.Data.Detail]
  265. this.dataList = res.Data.Detail.DataList||[];
  266. this.dataList.length && this.$nextTick(() => {
  267. this.handleLoadData()
  268. })
  269. },
  270. /* 滚动加载位置数据 */
  271. handleLoadData: _.throttle(function() {
  272. const scrollTop = this.$refs.valueUl.scrollTop;
  273. const visibleCount = Math.ceil(
  274. this.$refs.valueUl.clientHeight / 45
  275. )+5;
  276. console.log(visibleCount)
  277. this.startIndex = Math.floor(scrollTop / 45);
  278. this.endIndex = this.startIndex + visibleCount;
  279. this.$nextTick(() => {
  280. $('.list-wrapper')[0].style=`transform: translateY(${this.startIndex*45}px)`
  281. })
  282. },300),
  283. handleLinkPostion(year) {
  284. let index = this.dataList.findIndex(_ => _.Dt.substring(0,4)===year)
  285. console.log(index)
  286. this.$refs.valueUl.scrollTop = index*45
  287. this.handleLoadData()
  288. },
  289. /* 更改日期 */
  290. async handleTimeChange(index, e) {
  291. // 判断选择的日期是否重复
  292. let arr = this.dataList.filter((item) => item.Dt&&(item.Dt===e.Dt));
  293. if (arr.length>1) {
  294. if (!this.tempTime) {
  295. // 如果是新增行的
  296. e.Dt = "";
  297. } else {
  298. e.Dt = this.tempTime;
  299. }
  300. this.$message.warning(/* "该日期已存在" */this.$t('Edb.MsgPrompt.date_haved_msg'));
  301. } else {
  302. if(!this.tempTime) return
  303. // 修改日期
  304. let params = {
  305. TradeCode: e.TradeCode,
  306. CreateDate: e.Dt, //新录入日期
  307. OldCreateDate: this.tempTime, //之前日期
  308. Close: e.Close,
  309. };
  310. const res = await dataInterence.editData(params);
  311. if (res.Ret === 200) {
  312. this.$message.success("修改成功");
  313. }
  314. }
  315. },
  316. // 日期获取焦点存放日期
  317. handleTimeFocus(index, e) {
  318. if(!this.hasEditAuth) return
  319. this.tempTime = e.Dt;
  320. this.rightMouseMenu.rindex = index;
  321. this.rightMouseMenu.cindex = 0;
  322. },
  323. // input 获取焦点
  324. handleInputFocus(e, rindex, cindex) {
  325. console.log(e, rindex, cindex)
  326. if(!this.hasEditAuth) return
  327. this.rightMouseMenu.rindex = rindex;
  328. this.rightMouseMenu.cindex = cindex;
  329. this.temInputVal = _.cloneDeep(e)
  330. },
  331. // input 值改变 失去焦点
  332. async handleInputChange(e) {
  333. console.log(e);
  334. // 如果input 为改变 且 之前也为空
  335. if (!this.temInputVal.Close && !e.Close) {
  336. return;
  337. }
  338. // 没有选择日期
  339. if (!e.Dt) {
  340. e.Close = "";
  341. this.$message.warning(/* "请选择日期" */this.$t('Edb.InputHolderAll.input_date'));
  342. return;
  343. }
  344. // 判断值是否改变
  345. if (
  346. this.temInputVal.TradeCode === e.TradeCode &&
  347. this.temInputVal.Close === e.Close
  348. ) {
  349. console.log("值未改变");
  350. return;
  351. }
  352. // 删除情况
  353. if (!e.Close) {
  354. this.handleDelete(e);
  355. return;
  356. }
  357. // 修改情况
  358. // 检查该日期下是否存在数据
  359. let checkRes = await dataInterence.checkData({
  360. TradeCode: e.TradeCode,
  361. CreateDate: e.Dt,
  362. });
  363. if (checkRes.Data.Status === 0) {
  364. const editRes = await dataInterence.editData({
  365. TradeCode: e.TradeCode,
  366. CreateDate: e.Dt,
  367. Close: e.Close,
  368. OldCreateDate: "",
  369. });
  370. if (editRes.Ret === 200) {
  371. this.$message({
  372. message: /* "新增成功" */this.$t('MsgPrompt.add_msg'),
  373. type: "success",
  374. });
  375. } else {
  376. this.$message({
  377. message: editRes.msg,
  378. type: "warning",
  379. });
  380. this.getTableList();
  381. }
  382. } else if (checkRes.Data.Status === 1) {
  383. this.$confirm(
  384. this.$t('Edb.MsgPrompt.date_have_value_msg',{val:checkRes.Data.Close}),
  385. /* "提示" */this.$t('Dialog.warn_tit'),
  386. {
  387. type: "warning",
  388. }
  389. )
  390. .then(async () => {
  391. const editRes = await dataInterence.editData({
  392. TradeCode: e.TradeCode,
  393. CreateDate: e.Dt,
  394. Close: e.Close,
  395. OldCreateDate: e.Dt,
  396. });
  397. if (editRes.Ret === 200) {
  398. this.$message({
  399. message: /* "修改成功" */this.$t('MsgPrompt.edit_msg'),
  400. type: "success",
  401. });
  402. } else {
  403. this.$message({
  404. message: editRes.msg,
  405. type: "warning",
  406. });
  407. this.getTableList();
  408. }
  409. })
  410. .catch(() => {
  411. this.getTableList();
  412. });
  413. }
  414. },
  415. // 只允许输入整数或者小数点后四位
  416. handleInput(e) {
  417. if (e.Close.indexOf(".") > 0) {
  418. e.Close = e.Close.slice(0, e.Close.indexOf(".") + 5);
  419. }
  420. },
  421. /* 右键 */
  422. handleRightClick(e) {
  423. if(!this.hasEditAuth) return
  424. let dom = $('.right-lick-menu')[0];
  425. if(e.clientY > window.innerHeight/2) {
  426. dom.style.left = e.clientX-3 + 'px';
  427. dom.style.top = e.clientY-dom.offsetHeight-3 + 'px';
  428. }else {
  429. dom.style.left = e.clientX-3 + 'px';
  430. dom.style.top = e.clientY-3 + 'px';
  431. }
  432. },
  433. // 隐藏
  434. hideContextMenu() {
  435. let dom = $('.right-lick-menu')[0];
  436. dom.style.left = '-9999px';
  437. dom.style.top = '-9999px';
  438. this.rightMouseMenu.insertUpRows = 1;
  439. this.rightMouseMenu.insertDownRows = 1
  440. },
  441. // 插入操作
  442. handleOptTable(type) {
  443. const handlesMap = {
  444. 'insert_up_row': this.insertRow,
  445. 'insert_down_row': this.insertRow,
  446. 'del_row': this.delRow
  447. }
  448. handlesMap[type] && handlesMap[type](type)
  449. },
  450. //插入行
  451. insertRow(type) {
  452. let newItem = {
  453. Close: '',
  454. Dt: '',
  455. TradeCode: this.edbInfo.Detail.TradeCode
  456. }
  457. if(type==='insert_up_row') {
  458. let insertArr = new Array(this.rightMouseMenu.insertUpRows).fill('').map(item => _.cloneDeep(newItem))
  459. this.dataList.splice(this.rightMouseMenu.rindex, 0, ...insertArr);
  460. }else {
  461. let insertArr = new Array(this.rightMouseMenu.insertDownRows).fill('').map(item => _.cloneDeep(newItem))
  462. this.dataList.splice(this.rightMouseMenu.rindex+1, 0, ...insertArr);
  463. }
  464. console.log(this.dataList)
  465. },
  466. delRow() {
  467. this.dataList.splice(this.rightMouseMenu.rindex, 1);
  468. }
  469. },
  470. }
  471. </script>
  472. <style scoped lang='scss'>
  473. .edb-detail-data-wrap{
  474. display: flex;
  475. flex-direction: column;
  476. height: 100%;
  477. .firstColumTable{
  478. box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);
  479. }
  480. .handle-list {
  481. flex: 0;
  482. display: flex;
  483. justify-content: flex-end;
  484. gap: 20px;
  485. margin-bottom: 15px;
  486. }
  487. .el-table{
  488. flex: none;
  489. }
  490. .bottom {
  491. flex: 1;
  492. display: flex;
  493. overflow: hidden;
  494. .value-ul{
  495. flex: 1;
  496. max-height: 100%;
  497. overflow-y: auto;
  498. border: 1px solid #EBEFF6;
  499. box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2);
  500. position: relative;
  501. .total-cont {
  502. position: absolute;
  503. left: 0;
  504. right: 0;
  505. top: 0;
  506. bottom: 0;
  507. z-index: -2;
  508. }
  509. .list-wrapper {
  510. left: 0;
  511. right: 0;
  512. top: 0;
  513. position: absolute;
  514. .value-item {
  515. border-bottom: 1px solid #dcdfe6;
  516. display: flex;
  517. .value-label {
  518. width: 50%;
  519. padding: 2px;
  520. position: relative;
  521. text-align: center;
  522. color: #666;
  523. &:first-child {
  524. border-right: 1px solid #dcdfe6;
  525. }
  526. &.select::after {
  527. position: absolute;
  528. top: 0;
  529. left: 0;
  530. right: 0;
  531. bottom: 0;
  532. content: " ";
  533. display: block;
  534. outline: 0;
  535. border: 2px solid #0033ff;
  536. box-shadow: 0 0 5px rgba(73, 177, 249, 0.5);
  537. }
  538. .value-style{
  539. padding:5px;
  540. border-radius: 4px;
  541. &.predict-act {
  542. color: orange;
  543. }
  544. }
  545. }
  546. .input-val-box {
  547. width: 100%;
  548. height: 100%;
  549. border: none;
  550. text-align: center;
  551. color: #666;
  552. }
  553. .input-val-box:disabled {
  554. background: transparent;
  555. }
  556. input::-webkit-outer-spin-button,
  557. input::-webkit-inner-spin-button {
  558. -webkit-appearance: none !important;
  559. margin: 0;
  560. }
  561. input[type="number"] {
  562. -moz-appearance: textfield;
  563. }
  564. }
  565. }
  566. .nodata {
  567. text-align: center;
  568. padding: 40px 0;
  569. color: #999;
  570. }
  571. }
  572. .left-select {
  573. width: fit-content;
  574. max-height: 90%;
  575. border: 1px solid #EBEFF6;
  576. padding: 10px 15px;
  577. overflow-y: auto;
  578. .el-button { display: block;margin:10px 0; }
  579. }
  580. }
  581. .right-lick-menu {
  582. position: fixed;
  583. z-index: 99;
  584. top: -9999px;
  585. left: -9999px;
  586. background: #fff;
  587. padding: 10px 0;
  588. min-width: 180px;
  589. max-height: 400px;
  590. overflow-y: auto;
  591. /* border: 1px solid #999; */
  592. box-shadow: 0 1px 4px #999;
  593. .item {
  594. padding: 10px 25px;
  595. cursor: pointer;
  596. &:hover {
  597. background-color: #f5f7fa;
  598. }
  599. &:hover .subMenu-wrapper {
  600. display: block;
  601. }
  602. }
  603. }
  604. }
  605. </style>
  606. <style lang="scss">
  607. .edb-detail-data-wrap {
  608. .value-ul {
  609. .el-date-editor.el-input {
  610. width: 100%;
  611. }
  612. .el-date-editor .el-input__inner {
  613. border: none;
  614. text-align: center;
  615. }
  616. .el-input.is-disabled .el-input__inner {
  617. background-color: #fff;
  618. color: #666;
  619. }
  620. }
  621. }
  622. </style>