CustomTable.vue 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. <template>
  2. <div class="custom-table">
  3. <div v-if="config.data.length">
  4. <div class="formula-wrapper" v-if="!disabled">
  5. <span style="flex-shrink: 0;color:#C0C4CC">{{$t('OnlineExcelPage.formula_lable')}}</span>
  6. <el-input
  7. v-show="selectCell.DataType===4"
  8. v-model="selectCell.Value"
  9. @change="updateValueByFormula"
  10. />
  11. </div>
  12. <!-- 日期行表格 -->
  13. <div class="table-wrapper" v-if="config.type === 1">
  14. <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''">
  15. <thead>
  16. <tr>
  17. <!-- 行头 -->
  18. <th class="th-tg sm"></th>
  19. <th class="th-tg"></th>
  20. <!-- 列头 -->
  21. <th
  22. v-for="(item, index) in columnHeader"
  23. :key="index"
  24. class="th-tg th-col"
  25. :data-cindex="item"
  26. :data-rindex="-1"
  27. @contextmenu.prevent="rightClickHandle">
  28. {{item}}
  29. </th>
  30. </tr>
  31. </thead>
  32. <tbody>
  33. <tr v-for="(item, index) in config.EdbKeys" :key="item">
  34. <!-- 行头 -->
  35. <th class="th-tg sm"></th>
  36. <td rowspan="2" v-if="index === 0">
  37. {{$t('OnlineExcelPage.date_row_table')}}
  38. <i class="el-icon-sort" @click="changeSort"></i>
  39. </td>
  40. <td
  41. v-for="(edb, sub_index) in config.data"
  42. :key="sub_index"
  43. :data-rindex="-1"
  44. :data-cindex="columnHeader[sub_index]"
  45. @click="() => { !disabled && item==='EdbName' && clickEdbName(edb)}"
  46. >
  47. <template v-if="item === 'EdbName'">
  48. <span :class="{'edbname-td':disabled}" @click="edbJumpToBase(edb)">{{ edb.EdbAliasName||edb[item] }}</span>
  49. </template>
  50. <template v-else>{{ edb[item] }}/{{ edb.Frequency }}</template>
  51. </td>
  52. </tr>
  53. <!-- 数据行 第一列日期-->
  54. <tr v-for="(date, dateIndex) in dateArr" :key="date">
  55. <!-- 行头 -->
  56. <th
  57. class="th-tg th-row sm"
  58. :data-cindex="-1"
  59. :data-rindex="rowHeader[dateIndex]"
  60. @contextmenu.prevent="rightClickHandle"
  61. >{{rowHeader[dateIndex]}}</th>
  62. <td
  63. :data-rindex="rowHeader[dateIndex]"
  64. :data-cindex="-1"
  65. >{{date}}</td>
  66. <td
  67. v-for="(edb, edb_index) in config.data"
  68. :key="edb_index"
  69. :data-rindex="rowHeader[dateIndex]"
  70. :data-cindex="columnHeader[edb_index]"
  71. :class="([2,3,5].includes(edb.Data.find(_ =>_.DataTime === date).DataType)&&edb.Data.find(_ =>_.DataTime === date).ShowValue)?'insert': ''"
  72. @click="clickCell($event,edb.Data.find(_ =>_.DataTime === date))"
  73. @dblclick="dblClickCell($event,edb.Data.find(_ =>_.DataTime === date))"
  74. @copy="copyCellHandle($event,edb.Data.find(_ =>_.DataTime === date))"
  75. @paste="pasteCellHandle($event,edb.Data.find(_ =>_.DataTime === date))"
  76. >
  77. <!-- 实际值/插值 -->
  78. <span
  79. :data-rindex="rowHeader[dateIndex]"
  80. :data-cindex="columnHeader[edb_index]"
  81. v-if="(edb.Data.find(_ =>_.DataTime === date).ShowValue&&!edb.Data.find(_ =>_.DataTime === date).CanEdit)||disabled"
  82. >
  83. {{edb.Data.find(_ =>_.DataTime === date).ShowValue}}
  84. </span>
  85. <!-- 输入值/公式 -->
  86. <el-input
  87. v-else
  88. :data-rindex="rowHeader[dateIndex]"
  89. :data-cindex="columnHeader[edb_index]"
  90. v-model="edb.Data.find(_ =>_.DataTime === date).Value"
  91. @click="clickCell($event,edb.Data.find(_ =>_.DataTime === date))"
  92. @blur="changeVal($event,edb.Data.find(_ =>_.DataTime === date))"
  93. @keydown.native="e =>{ e.keyCode===13 && changeVal(e,edb.Data.find(_ =>_.DataTime === date)) }"
  94. />
  95. </td>
  96. </tr>
  97. <!-- 文本行 -->
  98. <tr v-for="(row,index) in config.textRowData" :key="index">
  99. <!-- 行头 -->
  100. <th
  101. class="th-tg th-row sm"
  102. @contextmenu.prevent="rightClickHandle"
  103. :data-rindex="rowHeader[index+dateArr.length]"
  104. :data-cindex="-1"
  105. >{{rowHeader[index+dateArr.length]}}</th>
  106. <td
  107. v-for="(cell, cell_index) in row"
  108. :key="`${index}_${cell_index}`"
  109. :data-rindex="rowHeader[index+dateArr.length]"
  110. :data-cindex="cell_index===0?-1:columnHeader[cell_index-1]"
  111. :class="([2,3,5].includes(cell.DataType)&&cell.ShowValue)?'insert': ''"
  112. @click="clickCell($event,cell)"
  113. @dblclick="dblClickCell($event,cell)"
  114. @copy="copyCellHandle($event,cell)"
  115. @paste="pasteCellHandle($event,cell)"
  116. >
  117. <span
  118. :data-rindex="rowHeader[index+dateArr.length]"
  119. :data-cindex="cell_index===0?-1:columnHeader[cell_index-1]"
  120. v-if="(cell.ShowValue&&!cell.CanEdit)||disabled"
  121. > {{cell.ShowValue}}</span>
  122. <!-- 输入值/公式 -->
  123. <el-input
  124. v-else
  125. v-model="cell.Value"
  126. :data-rindex="rowHeader[index+dateArr.length]"
  127. :data-cindex="cell_index===0?-1:columnHeader[cell_index-1]"
  128. @click="clickCell($event,cell)"
  129. @blur="changeVal($event,cell)"
  130. @keydown.native="e =>{ e.keyCode===13 && changeVal(e,cell) }"
  131. />
  132. </td>
  133. </tr>
  134. </tbody>
  135. </table>
  136. </div>
  137. <!-- 日期列表格 -->
  138. <div class="table-wrapper" v-else>
  139. <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''">
  140. <thead>
  141. <tr>
  142. <!-- 行头 -->
  143. <th class="th-tg sm"></th>
  144. <th class="th-tg"></th>
  145. <th class="th-tg"></th>
  146. <!-- 列头 -->
  147. <th
  148. v-for="(item, index) in rowHeader"
  149. :key="index"
  150. class="th-tg th-col"
  151. :data-cindex="-1"
  152. :data-rindex="rowHeader[index]"
  153. @contextmenu.prevent="rightClickHandle">
  154. {{item}}
  155. </th>
  156. </tr>
  157. </thead>
  158. <tbody>
  159. <tr>
  160. <!-- 行头 -->
  161. <th class="th-tg sm"></th>
  162. <td colspan="2">
  163. {{$t('OnlineExcelPage.date_row_table')}}
  164. <i class="el-icon-sort" style="transform: rotate(90deg)" @click="changeSort"></i>
  165. </td>
  166. <!-- 日期列 -->
  167. <td
  168. v-for="(date, sub_index) in dateArr"
  169. :key="date"
  170. :data-rindex="rowHeader[sub_index]"
  171. :data-cindex="-1"
  172. >{{ date }}</td>
  173. <!-- 文本列 -->
  174. <td
  175. v-for="(column,index) in config.textRowData"
  176. :key="index"
  177. :data-cindex="-1"
  178. :data-rindex="rowHeader[index+dateArr.length]"
  179. :class="([2,3,5].includes(column[0].DataType)&&column[0].ShowValue)?'insert': ''"
  180. @click="clickCell($event,column[0])"
  181. @dblclick="dblClickCell($event,column[0])"
  182. @copy="copyCellHandle($event,column[0])"
  183. @paste="pasteCellHandle($event,column[0])"
  184. >
  185. <span
  186. :data-cindex="-1"
  187. :data-rindex="rowHeader[index+dateArr.length]"
  188. v-if="(column[0].ShowValue&&!column[0].CanEdit)||disabled"
  189. > {{column[0].ShowValue}}</span>
  190. <!-- 输入值/公式 -->
  191. <el-input
  192. v-else
  193. v-model="column[0].Value"
  194. :data-cindex="-1"
  195. :data-rindex="rowHeader[index+dateArr.length]"
  196. @click="clickCell($event,column[0])"
  197. @blur="changeVal($event,column[0])"
  198. @keydown.native="e =>{ e.keyCode===13 && changeVal(e,column[0]) }"
  199. />
  200. </td>
  201. </tr>
  202. <!-- 指标行 -->
  203. <tr v-for="(edb, edb_index) in config.data" :key="edb.EdbInfoId">
  204. <!-- 行头 -->
  205. <th
  206. class="th-tg th-row sm"
  207. :data-cindex="columnHeader[edb_index]"
  208. :data-rindex="-1"
  209. @contextmenu.prevent="rightClickHandle"
  210. >
  211. {{columnHeader[edb_index]}}
  212. </th>
  213. <!-- 名称 单位 -->
  214. <td
  215. v-for="(item, index) in config.EdbKeys"
  216. :key="index"
  217. :data-rindex="-1"
  218. :data-cindex="columnHeader[edb_index]"
  219. @click="() => { !disabled && item==='EdbName' && clickEdbName(edb)}"
  220. >
  221. <template v-if="item === 'EdbName'">
  222. <span :class="{'edbname-td':disabled}" @click="edbJumpToBase(edb)">{{ edb.EdbAliasName||edb[item] }}</span>
  223. </template>
  224. <template v-else>{{ edb[item] }}/{{ edb.Frequency }}</template>
  225. </td>
  226. <!-- 数据列 -->
  227. <td
  228. v-for="(data, data_index) in edb.Data"
  229. :key="`${edb.EdbInfoId}_${rowHeader[data_index]}_${columnHeader[edb_index]}`"
  230. :data-rindex="rowHeader[data_index]"
  231. :data-cindex="columnHeader[edb_index]"
  232. :class="([2,3,5].includes(data.DataType)&&data.ShowValue)?'insert': ''"
  233. @click="clickCell($event,data)"
  234. @dblclick="dblClickCell($event,data)"
  235. @copy="copyCellHandle($event,data)"
  236. @paste="pasteCellHandle($event,data)"
  237. >
  238. <!-- 实际值/插值 -->
  239. <span
  240. :data-rindex="rowHeader[data_index]"
  241. :data-cindex="columnHeader[edb_index]"
  242. v-if="(data.ShowValue&&!data.CanEdit)||disabled"
  243. >
  244. {{data.ShowValue}}
  245. </span>
  246. <!-- 输入值/公式 -->
  247. <el-input
  248. v-else
  249. :data-rindex="rowHeader[data_index]"
  250. :data-cindex="columnHeader[edb_index]"
  251. v-model="data.Value"
  252. @click="clickCell($event,data)"
  253. @blur="changeVal($event,data)"
  254. @keydown.native="e =>{ e.keyCode===13 && changeVal(e,data) }"
  255. />
  256. </td>
  257. <!-- 文本列 -->
  258. <td
  259. v-for="(column,column_index) in config.textRowData"
  260. :key="`${rowHeader[column_index+dateArr.length]}_${columnHeader[edb_index]}`"
  261. :data-rindex="rowHeader[column_index+dateArr.length]"
  262. :data-cindex="columnHeader[edb_index]"
  263. :class="([2,3,5].includes(column[edb_index+1].DataType)&&column[edb_index+1].ShowValue)?'insert': ''"
  264. @click="clickCell($event,column[edb_index+1])"
  265. @dblclick="dblClickCell($event,column[edb_index+1])"
  266. @copy="copyCellHandle($event,column[edb_index+1])"
  267. @paste="pasteCellHandle($event,column[edb_index+1])"
  268. >
  269. <span
  270. :data-rindex="rowHeader[column_index+dateArr.length]"
  271. :data-cindex="columnHeader[edb_index]"
  272. v-if="(column[edb_index+1].ShowValue&&!column[edb_index+1].CanEdit)||disabled"
  273. > {{column[edb_index+1].ShowValue}}</span>
  274. <!-- 输入值/公式 -->
  275. <el-input
  276. v-else
  277. v-model="column[edb_index+1].Value"
  278. :data-rindex="rowHeader[column_index+dateArr.length]"
  279. :data-cindex="columnHeader[edb_index]"
  280. @click="clickCell($event,column[edb_index+1])"
  281. @blur="changeVal($event,column[edb_index+1])"
  282. @keydown.native="e =>{ e.keyCode===13 && changeVal(e,column[edb_index+1]) }"
  283. />
  284. </td>
  285. </tr>
  286. </tbody>
  287. </table>
  288. </div>
  289. <!-- 添加 -->
  290. <div class="add-fixed" v-if="!disabled" draggable @dragend="dragEnd" :style="isCollapse?'left:70px;':'left:200px;'">
  291. <div class="add-wrapper" v-show="!isSlideLeft">
  292. <div @click="addDateRow"> <i class="el-icon-circle-plus-outline"></i> {{$t('OnlineExcelPage.add_date_wrapper')}}</div>
  293. <div @click="addTextRow"> <i class="el-icon-circle-plus-outline"></i> {{$t('OnlineExcelPage.add_text_wrapper')}}</div>
  294. <span class="slide-icon slide-left" @click="isSlideLeft=!isSlideLeft">
  295. <i class="el-icon-d-arrow-left"></i>
  296. </span>
  297. </div>
  298. <!-- 折叠icon -->
  299. <div class="slide-cont" v-show="isSlideLeft">
  300. <span
  301. class="slide-icon slide-right"
  302. @click="isSlideLeft=!isSlideLeft"
  303. >
  304. <i class="el-icon-d-arrow-right"></i>
  305. </span>
  306. </div>
  307. </div>
  308. </div>
  309. <div class="nodata" v-else>
  310. <tableNoData :text="$t('Table.prompt_slogan')"/>
  311. </div>
  312. <!-- 右键菜单 -->
  313. <div class="contextMenu-wrapper" id="contextMenu-wrapper" @mouseleave="hideContextMenu">
  314. <div class="item" v-for="menu in contextMenuOption" :key="menu.key" @click="handleContext(menu.key)">{{menu.label}}</div>
  315. </div>
  316. <!-- 添加日期弹窗 -->
  317. <addDateCellDia
  318. :isOpenDialog.sync="isAddDateDia"
  319. @success="concatData"
  320. />
  321. <!-- 指标别名 -->
  322. <m-dialog
  323. :show.sync="isEditEdbAliasDialog"
  324. width="650px"
  325. :title="$t('OnlineExcelPage.edit_indicator_tle')"
  326. @close="isEditEdbAliasDialog = false"
  327. >
  328. <div style="padding-left:80px">
  329. <el-form
  330. ref="formRef"
  331. label-position="left"
  332. hide-required-asterisk
  333. label-width="80px"
  334. :model="editEdb"
  335. >
  336. <el-form-item :label="$t('OnlineExcelPage.indicator_name_lbl')">
  337. <span>{{ editEdb.EdbName }}</span>
  338. </el-form-item>
  339. <el-form-item :label="$t('OnlineExcelPage.indicator_alias_lbl')" prop="EdbAliasName">
  340. <el-input v-model="editEdb.EdbAliasName" style="width:80%"/>
  341. </el-form-item>
  342. </el-form>
  343. </div>
  344. <div style="display: flex;justify-content: center;margin-top:30px">
  345. <el-button
  346. type="primary"
  347. style="margin-right: 60px"
  348. @click="saveEdbAlias"
  349. >{{$t('Dialog.confirm_save_btn')}}</el-button
  350. >
  351. <el-button type="primary" plain @click="isEditEdbAliasDialog = false"
  352. >{{$t('Dialog.cancel_btn')}}</el-button
  353. >
  354. </div>
  355. </m-dialog>
  356. </div>
  357. </template>
  358. <script>
  359. import {
  360. getRowHeaderCode,
  361. getColumnHeaderCode,
  362. selectCellStyle,
  363. selectMoreCellStyle,
  364. extractFactorsFromFormula,
  365. findCellByFactor,
  366. splitString,
  367. toUpperCase,
  368. resetStyle,
  369. setFocus
  370. } from '../common/customTable';
  371. import addDateCellDia from './addDateCellDia';
  372. import * as sheetInterface from '@/api/modules/sheetApi.js';
  373. import { dataBaseInterface } from '@/api/api.js';
  374. import mDialog from '@/components/mDialog.vue'
  375. export default {
  376. props: {
  377. sheetType: {
  378. type: Number
  379. },
  380. disabled: { //是否只预览
  381. type: Boolean,
  382. default: false
  383. }
  384. },
  385. watch: {
  386. sheetType(nval) {
  387. this.config.type = nval;
  388. this.$nextTick(() => {
  389. resetStyle();
  390. })
  391. },
  392. // 'config.data':{
  393. // handler(value){
  394. // console.log(value,'valuevaluevalue');
  395. // if(!this.disabled && this.hasInit){
  396. // this.$emit("autoSave")
  397. // }
  398. // },
  399. // deep:true
  400. // },
  401. 'config.textRowData':{
  402. handler(value){
  403. if(!this.disabled && this.hasInit){
  404. this.$emit("autoSave")
  405. }
  406. },
  407. deep:true
  408. },
  409. 'config.order':{
  410. handler(value){
  411. if(!this.disabled && this.hasInit){
  412. this.$emit("autoSave")
  413. }
  414. }
  415. }
  416. },
  417. components: {addDateCellDia,mDialog},
  418. computed: {
  419. //列头
  420. columnHeader() {
  421. return getColumnHeaderCode(this.config.data.length)
  422. },
  423. //行头
  424. rowHeader() {
  425. let total_length = this.dateArr.length + this.config.textRowData.length;
  426. return getRowHeaderCode(total_length)
  427. },
  428. dateArr() {
  429. console.log(this.config.data)
  430. return this.config.data.length ? this.config.data[0].Data.map(_ => _.DataTime) : []
  431. },
  432. isCollapse() {
  433. return this.$store.state.isCollapse
  434. },
  435. contextMenuOption(){
  436. return [{ label: this.$t('ETable.Btn.delete_btn') ,key: 'del' }]
  437. }
  438. },
  439. data() {
  440. return {
  441. isSlideLeft: false,
  442. formula: '',
  443. config:{
  444. type: this.sheetType,
  445. order: 2,// 1降序 2升序
  446. EdbKeys: ["EdbName", "Unit"],
  447. data: [], //单元格类型 1默认格 2补充格 3自定义输入 4公式求值格 5预测值
  448. textRowData: [],
  449. },
  450. //选中的cell
  451. selectCell: {},
  452. //右击记录表格位置
  453. rightClickCell: {
  454. rindex: '',
  455. cindex: ''
  456. },
  457. isAddDateDia: false,
  458. //指标别名弹窗
  459. isEditEdbAliasDialog: false,
  460. editEdb: {},
  461. copyCellItem: {},
  462. hasInit:false
  463. };
  464. },
  465. methods: {
  466. /* 选择指标后push新数据 */
  467. updateEdbData(edb) {
  468. this.config.data.push(edb);
  469. //如果有文本行 文本行的数据长度也要增加
  470. if(this.config.textRowData.length) {
  471. let cell_item = {
  472. ShowValue: '',
  473. Value: '',
  474. DataType: 3,
  475. DataTime: '',
  476. }
  477. this.config.textRowData.forEach(row => {
  478. row.push(_.cloneDeep(cell_item))
  479. })
  480. }
  481. if(!this.disabled && this.hasInit){
  482. this.$emit("autoSave")
  483. }
  484. },
  485. /* 改变排序 */
  486. changeSort() {
  487. this.config.order = this.config.order === 1 ? 2 : 1;
  488. this.selectCell = {};
  489. this.config.data.forEach(edb => {
  490. edb.Data = this.config.order === 1
  491. ? edb.Data.sort((x,y) => new Date(y.DataTime)-new Date(x.DataTime))
  492. : edb.Data.sort((x,y) => new Date(x.DataTime)-new Date(y.DataTime))
  493. })
  494. if(!this.disabled && this.hasInit){
  495. this.$emit("autoSave")
  496. }
  497. },
  498. // 单击指标名称修改别名
  499. clickEdbName(edb) {
  500. // console.log(edb)
  501. const { EdbName,EdbAliasName,EdbInfoId } = edb;
  502. this.editEdb = {
  503. EdbName,
  504. EdbAliasName,
  505. EdbInfoId
  506. };
  507. this.isEditEdbAliasDialog = true;
  508. },
  509. /* 保存别名 */
  510. saveEdbAlias() {
  511. this.config.data.find(_ =>_.EdbInfoId === this.editEdb.EdbInfoId).EdbAliasName = this.editEdb.EdbAliasName;
  512. if(!this.disabled && this.hasInit){
  513. this.$emit("autoSave")
  514. }
  515. this.isEditEdbAliasDialog = false;
  516. },
  517. /* 单机单元格 */
  518. clickCell(e,cell) {
  519. if(this.disabled) return
  520. this.selectCell = cell;
  521. selectCellStyle(e)
  522. setFocus(e)
  523. },
  524. /* 双击单元格 3 4可编辑 */
  525. dblClickCell(e,cell) {
  526. if(this.disabled || ![3,4].includes(cell.DataType) || !cell.ShowValue) return
  527. this.$set(cell,'CanEdit',true)
  528. this.$nextTick(() => {
  529. // console.log(e.target.childNodes[0])
  530. if(e.target.childNodes[0].childNodes[1].nodeName==='INPUT') {
  531. e.target.childNodes[0].childNodes[1].focus()
  532. }
  533. })
  534. },
  535. /* 添加一行空行/空列 */
  536. addTextRow() {
  537. let row = new Array(this.config.data.length+1).fill('').map(_ =>({
  538. ShowValue: '',
  539. Value: '',
  540. DataType: 3,
  541. DataTime: '',
  542. }))
  543. this.config.textRowData.push(_.cloneDeep(row))
  544. console.log(this.config.textRowData)
  545. },
  546. /* 添加日期 */
  547. addDateRow() {
  548. this.isAddDateDia = true
  549. },
  550. /* 添加日期后拼接数据 */
  551. concatData({type,data}) {
  552. let concatData = data.map( _ => ({
  553. ..._,
  554. Data: _.Data.map(_ => ({..._,DataTimeType: type==='past'?1:2})),
  555. }))
  556. this.config.data.forEach(edb => {
  557. let edb_concat_data = concatData.find(_ => _.EdbInfoId === edb.EdbInfoId).Data;
  558. edb.Data = this.config.order === 1
  559. ? [...edb.Data,...edb_concat_data].sort((x,y) => new Date(y.DataTime)-new Date(x.DataTime))
  560. : [...edb.Data,...edb_concat_data].sort((x,y) => new Date(x.DataTime)-new Date(y.DataTime))
  561. })
  562. if(!this.disabled && this.hasInit){
  563. this.$emit("autoSave")
  564. }
  565. },
  566. /* 输入框失焦 存值或公式计算 val,行标 列标 指标信息 */
  567. async changeVal(e,cell) {
  568. //判断是否有= 判定为输入公式DataType为4
  569. //否则是自填数 DataType为3
  570. const {value} = e.target;
  571. if(!value){
  572. cell.DataType = 3;
  573. cell.ShowValue = '';
  574. if(!this.disabled && this.hasInit){
  575. this.$emit("autoSave")
  576. }
  577. return
  578. }
  579. if(value.startsWith('=')) {
  580. cell.DataType = 4;
  581. let calculateVal = await this.getValueByFormula(value);
  582. cell.ShowValue = calculateVal;
  583. }else { //更新显示
  584. cell.DataType = 3;
  585. cell.ShowValue = value
  586. }
  587. this.$set(cell,'CanEdit',false)
  588. if(!this.disabled && this.hasInit){
  589. this.$emit("autoSave")
  590. }
  591. },
  592. /* 输入公式的计算值 */
  593. async getValueByFormula(val) {
  594. // 提取因数数组
  595. let factors = extractFactorsFromFormula(val)
  596. console.log(factors)
  597. //根据因数找单元格
  598. let isAllCell = factors.some(_ => findCellByFactor(_)=== null)
  599. if(isAllCell) {
  600. this.$message.warning(this.$t('OnlineExcelPage.error_parameter_not_msg') )
  601. return '';
  602. }
  603. let TagMap = {};
  604. factors.forEach(_ => {
  605. if(!TagMap[_]) {
  606. TagMap[_] = Number(findCellByFactor(_))
  607. }
  608. });
  609. const res = await sheetInterface.calculateCustomCellData({
  610. CalculateFormula: val,
  611. TagMap
  612. })
  613. if(res.Ret !== 200) return
  614. return res.Data
  615. },
  616. /* 顶部公式改变 */
  617. async updateValueByFormula(value) {
  618. this.changeVal({target: {value}},this.selectCell)
  619. },
  620. /* 行头和列头右键删除 */
  621. rightClickHandle(e) {
  622. if(this.disabled) return
  623. const {rindex,cindex} = e.target.dataset;
  624. this.rightClickCell = {
  625. rindex,
  626. cindex
  627. }
  628. const dom = $('#contextMenu-wrapper')[0];
  629. dom.style.left = e.clientX-3 + 'px';
  630. dom.style.top = e.clientY-3 + 'px';
  631. selectMoreCellStyle(e,this.config.type)
  632. },
  633. /* */
  634. hideContextMenu() {
  635. const dom = $('#contextMenu-wrapper')[0];
  636. dom.style.left = '-9999px';
  637. dom.style.top = '-9999px';
  638. },
  639. /* 右键事件 */
  640. async handleContext(key) {
  641. let { rindex,cindex } = this.rightClickCell;
  642. if(rindex==='-1') { //删除列
  643. console.log('删除列',cindex)
  644. if(cindex === 'A') {
  645. await this.$confirm(this.$t('OnlineExcelPage.dlt_the_all_msg') ,this.$t('Confirm.prompt') ,{ type: 'warning' })
  646. this.reset()
  647. return
  648. }
  649. let index = this.columnHeader.findIndex(_ => _ === cindex);
  650. this.config.data.splice(index,1)
  651. this.config.textRowData.forEach(row => {
  652. row.splice(index+1,1)
  653. })
  654. }else if(cindex === '-1') { //删除行
  655. console.log('删除行',rindex)
  656. if(this.dateArr.length === 1) return this.$message.warning(this.$t('OnlineExcelPage.please_keep_one_msg') )
  657. let index = this.rowHeader.findIndex(_ => _ === rindex)
  658. if(index >= this.dateArr.length) {
  659. this.config.textRowData.splice(index-this.dateArr.length,1)
  660. }else {
  661. this.dateArr.splice(index,1)
  662. this.config.data.forEach(_ => {
  663. _.Data.splice(index,1)
  664. })
  665. }
  666. }
  667. if(!this.disabled && this.hasInit){
  668. this.$emit("autoSave")
  669. }
  670. this.hideContextMenu()
  671. },
  672. /* 保存时处理参数 */
  673. getSaveParams() {
  674. const { data,textRowData,order } = this.config;
  675. let TextRowData = textRowData.map(_ => {
  676. return _.map(cell => ({
  677. ...cell,
  678. RelationEdbInfoList: cell.DataType===4?this.dealFormulaConstruction(cell.Value):[]
  679. }))
  680. })
  681. let Data = data.map((_,index) => {
  682. return {
  683. EdbInfoId: _.EdbInfoId,
  684. EdbAliasName: _.EdbAliasName,
  685. Tag: this.columnHeader[index],
  686. Data: _.Data.map(cell => ({
  687. ...cell,
  688. RelationEdbInfoList: cell.DataType===4?this.dealFormulaConstruction(cell.Value):[]
  689. }))
  690. }
  691. })
  692. let params = {
  693. EdbInfoIdList: this.config.data.map(_ => _.EdbInfoId),
  694. Sort: order,
  695. TextRowData,
  696. Data,
  697. }
  698. console.log(params)
  699. return params
  700. },
  701. /* 处理因数结构 =a1+b1 => [{ Tag: a,Row:1 }] */
  702. dealFormulaConstruction(val) {
  703. // 提取因数数组
  704. let factors = extractFactorsFromFormula(val)
  705. let arr = factors.map(str => ({
  706. Tag: splitString(toUpperCase(str))[0],
  707. Row: splitString(toUpperCase(str))[1],
  708. }))
  709. return arr
  710. },
  711. /* 详情initData */
  712. initSheetData(initData) {
  713. this.hasInit=false
  714. if(initData.Data) {
  715. const { Data,Sort,TextRowData } = initData;
  716. this.config.order = Sort;
  717. this.config.data = Data;
  718. this.config.textRowData = TextRowData;
  719. }
  720. this.$nextTick(()=>{
  721. this.hasInit=true
  722. })
  723. },
  724. /* 跳转到指标库 */
  725. async edbJumpToBase(edb) {
  726. //非详情页不跳转
  727. if(!this.disabled) return
  728. if(!edb.HaveOperaAuth) return this.$message.warning(this.$t('MsgPrompt.no_edb_auth'))
  729. const res = await dataBaseInterface.targetDetail({EdbInfoId:edb.EdbInfoId})
  730. if(res.Ret !== 200) return
  731. //EdbInfoType=1 跳预测指标详情,=0跳指标库详情
  732. const {ClassifyId,UniqueCode,EdbInfoId,EdbInfoType} = res.Data;
  733. let {href} = this.$router.resolve({
  734. path:EdbInfoType===1?'/predictEdb':'/database',
  735. query:{code:UniqueCode,id:EdbInfoId,classifyId:ClassifyId}
  736. });
  737. window.open(href,'_blank');
  738. },
  739. /* 清空所有数据 */
  740. reset() {
  741. this.config.data = [];
  742. if(!this.disabled && this.hasInit){
  743. this.$emit("autoSave")
  744. }
  745. this.config.textRowData = [];
  746. },
  747. dragEnd(e) {
  748. let dom = document.querySelector('.add-fixed');
  749. dom.style.top = e.clientY-10 + 'px';
  750. },
  751. /* 要支持复制粘贴把公式也带过去 公式单元格类型为6 其余就正常复制文本 */
  752. copyCellHandle(e,cell) {
  753. this.copyCellItem = cell;
  754. // 阻止默认的复制操作
  755. e.preventDefault();
  756. },
  757. /* 要支持复制粘贴把公式也带过去 公式单元格类型为4 其余就正常复制文本 */
  758. pasteCellHandle(e,cell) {
  759. if(this.copyCellItem.DataType === 4) {
  760. cell.DataType = this.copyCellItem.DataType;
  761. cell.ShowValue = this.copyCellItem.ShowValue;
  762. cell.Value = this.copyCellItem.Value;
  763. }else {
  764. cell.DataType = 3;
  765. cell.ShowValue = this.copyCellItem.ShowValue;
  766. cell.Value = this.copyCellItem.ShowValue;
  767. }
  768. // 阻止默认的粘贴操作
  769. e.preventDefault();
  770. }
  771. },
  772. };
  773. </script>
  774. <style scoped lang="scss">
  775. .custom-table {
  776. * { box-sizing: border-box; }
  777. .formula-wrapper {
  778. height: 42px;
  779. display: flex;
  780. align-items: center;
  781. background: #fff;
  782. border-radius: 4px;
  783. box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
  784. border: 1px solid #DCDFE6;
  785. margin-bottom: 15px;
  786. padding: 0 15px;
  787. }
  788. .table-wrapper {
  789. width: 100%;
  790. overflow: auto;
  791. }
  792. .nodata {
  793. text-align: center;
  794. font-size: 16px;
  795. color: #666;
  796. padding: 100px 0;
  797. }
  798. .table td,th {
  799. width: 104px;
  800. min-width: 104px;
  801. height: 35px;
  802. background: #fff;
  803. text-align: center;
  804. word-break: break-all;
  805. border: 1px solid #dcdfe6;
  806. word-wrap: break-word;
  807. word-break: break-all;
  808. white-space: nowrap;
  809. overflow: hidden;
  810. text-overflow: ellipsis;
  811. position: relative;
  812. &.td-chose::after {
  813. position: absolute;
  814. top: 0;
  815. left: 0;
  816. right: 0;
  817. bottom: 0;
  818. content: "";
  819. display: block;
  820. outline: 0;
  821. border: 2px solid #0033FF;
  822. box-shadow: 0 0 5px rgba(73, 177, 249, .5)
  823. }
  824. &.td-col-select::after {
  825. position: absolute;
  826. top: 0;
  827. left: 0;
  828. right: 0;
  829. bottom: 0;
  830. content: "";
  831. display: block;
  832. outline: 0;
  833. border: 1px solid rgb(24, 173, 24);
  834. border-bottom: none;
  835. border-top: none;
  836. }
  837. &.td-row-select::after {
  838. position: absolute;
  839. top: 0;
  840. left: 0;
  841. right: 0;
  842. bottom: 0;
  843. content: "";
  844. display: block;
  845. outline: 0;
  846. border: 1px solid rgb(24, 173, 24);
  847. border-left: none;
  848. border-right: none;
  849. }
  850. &.insert {
  851. background: #FFEFDD;
  852. }
  853. .edbname-td {
  854. &:hover {
  855. text-decoration: underline;
  856. }
  857. }
  858. }
  859. .th-tg {
  860. background: #EBEEF5;
  861. &:hover {
  862. cursor: pointer;
  863. background: #ddd;
  864. /* border: 2px solid #409eff; */
  865. }
  866. &.sm {
  867. width: 36px;
  868. min-width: 36px;
  869. max-width: 36px;
  870. }
  871. }
  872. //整行选中
  873. tr {
  874. position: relative;
  875. &.choose-all::after {
  876. position: absolute;
  877. top: 0;
  878. left: 0;
  879. right: 0;
  880. bottom: 0;
  881. content: "";
  882. display: block;
  883. outline: 0;
  884. border: 2px solid #5897fb;
  885. box-shadow: 0 0 5px rgba(73, 177, 249, .5)
  886. }
  887. }
  888. .el-icon-sort {
  889. color: #409eff;
  890. cursor: pointer;
  891. font-size: 16px;
  892. }
  893. .add-fixed {
  894. cursor: move;
  895. position: fixed;
  896. top: 70%;
  897. left: 0;
  898. z-index: 99;
  899. .add-wrapper {
  900. position: relative;
  901. padding: 5px 50px 5px 20px;
  902. background: #fff;
  903. border-radius: 0px 64px 64px 0px;
  904. font-size: 16px;
  905. box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
  906. border: 1px solid #DCDFE6;
  907. div { margin: 5px 0; cursor: pointer;color: #409eff; }
  908. .slide-icon {
  909. position: absolute;
  910. cursor: pointer;
  911. right: 20px;
  912. top: 50%;
  913. transform: translateY(-50%);
  914. }
  915. }
  916. .slide-cont {
  917. position: absolute;
  918. .slide-icon {
  919. padding: 20px 0;
  920. box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
  921. border-radius: 5px;
  922. cursor: pointer;
  923. &:hover {
  924. background-color: rgba(0, 0, 0, 0.05);
  925. }
  926. }
  927. }
  928. }
  929. .contextMenu-wrapper {
  930. position: fixed;
  931. z-index: 99;
  932. top: -9999px;
  933. left: -9999px;
  934. background: #fff;
  935. padding: 10px 0;
  936. /* border: 1px solid #999; */
  937. box-shadow: 0 1px 4px #999;
  938. .item {
  939. padding: 10px 25px;
  940. cursor: pointer;
  941. &:hover {
  942. background-color: #f5f7fa;
  943. }
  944. }
  945. }
  946. }
  947. </style>
  948. <style lang="scss">
  949. .custom-table {
  950. td,.formula-wrapper {
  951. .el-input__inner { border: none; outline: none; }
  952. }
  953. td .el-input__inner { text-align: center;height: 34px; line-height: 34px; }
  954. .el-input.is-disabled .el-input__inner {
  955. background-color: #fff;
  956. }
  957. }
  958. </style>