TimelineSheet.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. <script setup>
  2. // import Sheet from '@/components/Sheet.vue'
  3. import { ref, computed, onMounted } from 'vue'
  4. const props = defineProps({
  5. TableInfo:{
  6. type:Object,
  7. default:{}
  8. }
  9. })
  10. const tableHeight = ref(0)
  11. const rowTable = ref(null)
  12. const disabled = ref(true)
  13. const EdbKeys = ref(["EdbName", "Unit"])
  14. const cellRef = ref(null)
  15. const indexCellRef = ref(null);
  16. const dateCellRef = ref(null);
  17. const nameTh = ref(null)
  18. const unitTh = ref(null)
  19. const dateArr = computed (() => {
  20. return props.TableInfo.TableData.Data.length ? props.TableInfo.TableData.Data[0].Data.map(_ => _.DataTime) : []
  21. })
  22. const columnHeader = computed(() => {
  23. return getColumnHeaderCode(
  24. props.TableInfo.TableData.Data ? props.TableInfo.TableData.Data.length : 0
  25. );
  26. });
  27. const rowHeader = computed(() => {
  28. let total_length = dateArr.value.length + props.TableInfo.TableData.TextRowData.length;
  29. return getRowHeaderCode(total_length);
  30. });
  31. // 提取公共路径到局部变量
  32. const tableFreeze = computed(() => props.TableInfo.ExtraConfig.TableFreeze);
  33. const minRow = computed(() => {
  34. const { FreezeStartRow, FreezeEndRow } = tableFreeze.value;
  35. return Math.min(FreezeStartRow, FreezeEndRow) === 0 ? 1 : Math.min(FreezeStartRow, FreezeEndRow)
  36. });
  37. const maxRow = computed(() => {
  38. const { FreezeStartRow, FreezeEndRow } = tableFreeze.value;
  39. return Math.max(FreezeStartRow, FreezeEndRow);
  40. });
  41. const minCol = computed(() => {
  42. const { FreezeStartCol, FreezeEndCol } = tableFreeze.value;
  43. return Math.min(FreezeStartCol, FreezeEndCol) === 0 ? 1 : Math.min(FreezeStartCol, FreezeEndCol);
  44. });
  45. const maxCol = computed(() => {
  46. const { FreezeStartCol, FreezeEndCol } = tableFreeze.value;
  47. return Math.max(FreezeStartCol, FreezeEndCol);
  48. });
  49. const isFreezeColumns = computed(() => {
  50. return tableFreeze.value && maxCol.value > 0;
  51. });
  52. const isFreezeRows = computed(() => {
  53. return tableFreeze.value && maxRow.value > 0;
  54. });
  55. const isFreezeAll = computed(() => {
  56. return tableFreeze.value && isFreezeColumns.value && isFreezeRows.value;
  57. });
  58. const isFreezeRowsOrColumns = computed(() => {
  59. return tableFreeze.value && isFreezeColumns.value || isFreezeRows.value;
  60. });
  61. const cornerWidth = computed(() => {
  62. return indexCellRef.value ? indexCellRef.value.offsetWidth : 23;
  63. });
  64. const cornerHeight = computed(() => {
  65. return indexCellRef.value ? indexCellRef.value.offsetHeight : 24;
  66. });
  67. const dateCellRefHeight = computed(() => {
  68. return dateCellRef.value ? dateCellRef.value.offsetWidth : 68;
  69. });
  70. const nameThWidth = computed(() => {
  71. return nameTh.value ? nameTh.value.offsetWidth : 191;
  72. });
  73. const unitThWidth = computed(() => {
  74. return unitTh.value ? unitTh.value.offsetWidth : 62;
  75. });
  76. //手机端pc端不同样式
  77. const dynamicSty = computed(()=>{
  78. return isMobile() ? 'mobile-sty' : 'pc-sty';
  79. })
  80. //判断是否是手机设备
  81. function isMobile() {
  82. // 判断是否是移动设备的正则表达式
  83. const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
  84. // 获取用户代理信息
  85. const userAgent = navigator.userAgent;
  86. // 使用正则表达式检查用户代理信息
  87. return mobileRegex.test(userAgent);
  88. }
  89. // 字母列标
  90. function getColumnHeaderCode(len) {
  91. let tag_arr = [];
  92. for(let i=0;i<len;i++) tag_arr.push(String.fromCharCode(65+i));
  93. return tag_arr;
  94. }
  95. // 行标
  96. function getRowHeaderCode(len) {
  97. let tag_arr = [];
  98. for(let i=0;i<len;i++) tag_arr.push(String(1+i));
  99. return tag_arr;
  100. }
  101. // 判断展示小数位数值还是原来的值
  102. function showCellValue(cell){
  103. // console.log(cell)
  104. let Value=''
  105. if("Decimal" in cell&&cell.Decimal!=-1){
  106. const multiplier = Math.pow(10, cell.Decimal);
  107. const cellValue=+cell.Value
  108. Value= cell.Decimal == 0 ? Math.round(cellValue) : Math.round(cellValue * multiplier) / multiplier;
  109. }else{
  110. Value=cell.ShowValue
  111. }
  112. return Value
  113. }
  114. onMounted(() => {
  115. tableHeight.value = rowTable.value ? rowTable.value.offsetHeight : cornerHeight.value;
  116. })
  117. // 是否固定列
  118. function isWithinColRange (index) {
  119. return rowHeader.value[index] >= minCol.value && rowHeader.value[index] <= maxCol.value
  120. }
  121. // 是否固定行
  122. function isBetweenTargetRows (index) {
  123. return rowHeader.value[index] >= minRow.value && rowHeader.value[index] <= maxRow.value
  124. }
  125. // 获取某一列的宽度
  126. function getColumnHeaderWidth (index) {
  127. if (!cellRef.value || cellRef.value.length === 0 || index <= 0) return cornerWidth.value;
  128. let ColumnHeaderWidth = cornerWidth.value;
  129. let minWidth = 0
  130. // 计算冻结列的宽度总和
  131. for (let i = 0; i < index; i++) {
  132. ColumnHeaderWidth += cellRef.value[i] ? cellRef.value[i].offsetWidth : 68
  133. }
  134. // 计算冻结最小列之外的宽度总和
  135. for (let i = 0; i < minCol.value - 1; i++) {
  136. minWidth += cellRef.value[i] ? cellRef.value[i].offsetWidth : 68;
  137. }
  138. return ColumnHeaderWidth - minWidth;
  139. }
  140. // 文本行冻结效果动态计算
  141. function getInsertClass(cell) {
  142. return [2, 3, 5].includes(cell.DataType) && cell.ShowValue ? 'insert' : '';
  143. }
  144. function getFixColClass(cell_index, index, freezeData, isFreezeColumns, dateArr) {
  145. return (freezeData && (isWithinColRange(cell_index - 1) || isBetweenTargetRows(index + dateArr.length))) || (isFreezeColumns && cell_index === 0) ? 'fix-col' : '';
  146. }
  147. function getIndexOutsideClass(cell_index, index, maxRow, minRow, maxCol, minCol, dateArr) {
  148. return (index + dateArr.length >= maxRow || index + dateArr.length < minRow - 1) && (cell_index > maxCol || cell_index < minCol - 1) && cell_index !== 0 ? 'index-outside' : '';
  149. }
  150. function getIndexOverlapClass(cell_index, index, dateArr) {
  151. return isBetweenTargetRows(index + dateArr.length) && isWithinColRange(cell_index - 1) ? 'index-overlap' : '';
  152. }
  153. function getIndexClass(cell_index, index, dateArr) {
  154. return cell_index === 0 && !isBetweenTargetRows(index + dateArr.length) ? 'index' : '';
  155. }
  156. function getDateOverlapClass(cell_index, index, dateArr) {
  157. return cell_index === 0 && isBetweenTargetRows(index + dateArr.length) ? 'index-overlap' : '';
  158. }
  159. </script>
  160. <template>
  161. <div class="sheet-show-wrapper">
  162. <div :class="['table-wrapper',dynamicSty ]" v-if="props.TableInfo.ExcelType === 1">
  163. <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''" style="position: relative;">
  164. <thead>
  165. <tr ref="rowTable">
  166. <!-- 行头 -->
  167. <th
  168. ref="indexCellRef"
  169. class="th-tg sm index-overlap"
  170. :class="[isFreezeRowsOrColumns ? 'fix-col ' : '']"
  171. :style="isFreezeAll ? {left: '0', top: '0'} : (isFreezeColumns ? {left: '0'} : (isFreezeRows ? {top: '0'} : ''))"
  172. ></th>
  173. <th
  174. ref="dateCellRef"
  175. class="th-tg index-overlap"
  176. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  177. :style="[isFreezeAll ? {left: getColumnHeaderWidth(-1) + 'px', top: 0} : '', isFreezeColumns ? {left: getColumnHeaderWidth(-1) + 'px'} : '', isFreezeRows ? {top: 0} : '']"
  178. >
  179. </th>
  180. <!-- 列头 -->
  181. <th
  182. ref="cellRef"
  183. v-for="(item, index) in columnHeader"
  184. :key="index"
  185. class="th-tg th-col"
  186. :style="[isFreezeRows ? {top: 0} : '', isFreezeColumns && isWithinColRange(index) ? {left: getColumnHeaderWidth(index) + 68 + 'px'} : '',]"
  187. :class="[isFreezeRows || isFreezeColumns ? 'fix-col' : '', isFreezeColumns && maxCol <= index ? 'index' : '', tableFreeze && isWithinColRange(index) ? 'index-overlap' : '']"
  188. :data-cindex="item"
  189. :data-rindex="-1">
  190. {{item}}
  191. </th>
  192. </tr>
  193. </thead>
  194. <tbody>
  195. <tr
  196. v-for="(item, index) in EdbKeys"
  197. :key="item"
  198. :style="isFreezeRows ? `top: ${(index + 1) * tableHeight}px;` : ''"
  199. :class="isFreezeRows && index !== 1 ? 'fix' : ''"
  200. >
  201. <!-- 行头 -->
  202. <th
  203. class="th-tg sm index-highest"
  204. :style="[isFreezeAll ? {left: 0,top: (index)*tableHeight + 24 + 'px'} : '', isFreezeColumns ? {left: 0} : '', isFreezeRows ? {top: (index)*tableHeight + 24 + 'px'} : '']"
  205. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  206. >
  207. </th>
  208. <td
  209. rowspan="2"
  210. v-if="index === 0"
  211. class="head-column"
  212. :class="[isFreezeRowsOrColumns ? 'fix-col index-highest' : 'index-highest']"
  213. :style="[isFreezeAll ? {left: 23 + 'px', top: 24 + 'px'} : '', isFreezeColumns ? {left: 23 + 'px'} : '', isFreezeRows ? {top: 24 + 'px'} : '']"
  214. >
  215. 日期
  216. </td>
  217. <td
  218. v-for="(edb, sub_index) in TableInfo.TableData.Data"
  219. :key="sub_index"
  220. :data-rindex="-1"
  221. :data-cindex="columnHeader[sub_index]"
  222. :style="[tableFreeze && isWithinColRange(sub_index) ? {left: getColumnHeaderWidth(sub_index) + dateCellRefHeight + 'px'} : '', isFreezeRows ? {top: (index)*tableHeight + 24 + 'px'} : '']"
  223. :class="['data-cell',{
  224. 'one-bg':(index+1)%2&&index>0,
  225. 'tow-bg': (index+1)%2!==0&&index>0,
  226. 'head-column': index === 0,
  227. 'fix-col':isFreezeRows,
  228. 'index-overlap': tableFreeze && isWithinColRange(sub_index)
  229. }]"
  230. >
  231. <template v-if="item === 'EdbName'">
  232. <span :class="{'edbname-td':disabled}" @click="edbJumpToBase(edb)">{{ edb.EdbAliasName||edb[item] }}</span>
  233. </template>
  234. <template v-else>{{ edb[item] }} / {{edb.Frequency }}</template>
  235. </td>
  236. </tr>
  237. <!-- 数据行 第一列日期-->
  238. <tr
  239. v-for="(date, dateIndex) in dateArr"
  240. :key="date"
  241. :style="isFreezeRows && maxRow > dateIndex ? `top: ${(dateIndex- minRow+1)*tableHeight}px;` : ''"
  242. :class="tableFreeze && isBetweenTargetRows(dateIndex) ? 'fix' : ''"
  243. >
  244. <!-- 行头 -->
  245. <th
  246. class="th-tg th-row sm"
  247. :data-cindex="-1"
  248. :data-rindex="rowHeader[dateIndex]"
  249. @contextmenu.prevent="rightClickHandle"
  250. :style="[isFreezeColumns ? {left: 0} : '', isFreezeRows && isBetweenTargetRows(dateIndex) ? {top: (dateIndex- minRow+1)*tableHeight + cornerHeight * 3 + 'px'} : '' ]"
  251. :class="[isFreezeRowsOrColumns ? 'fix-col' : '', !isBetweenTargetRows(dateIndex) ? 'index' : 'index-overlap']"
  252. >{{rowHeader[dateIndex]}}</th>
  253. <td
  254. :data-rindex="rowHeader[dateIndex]"
  255. :data-cindex="-1"
  256. :style="[isFreezeColumns ? {left: getColumnHeaderWidth(-1) + 'px'} : '', isFreezeRows && isBetweenTargetRows(dateIndex) ? {top: (dateIndex- minRow+1)*tableHeight + cornerHeight * 3 + 'px'} : '']"
  257. :class="[isFreezeRowsOrColumns ? 'fix-col' : '', !isBetweenTargetRows(dateIndex) ? 'index' : 'index-overlap', ]"
  258. >{{date}}</td>
  259. <td
  260. v-for="(edb, edb_index) in TableInfo.TableData.Data"
  261. :key="edb_index"
  262. :data-rindex="rowHeader[dateIndex]"
  263. :data-cindex="columnHeader[edb_index]"
  264. :style="[tableFreeze && isWithinColRange(edb_index) ? {left: getColumnHeaderWidth(edb_index) + dateCellRefHeight + 'px'} : '', isFreezeRows && isBetweenTargetRows(dateIndex) ? {top: (dateIndex- minRow+1)*tableHeight + cornerHeight * 3 + 'px'} : '']"
  265. :class="[([2,3,5].includes(edb.Data.find(_ =>_.DataTime === date).DataType)&&edb.Data.find(_ =>_.DataTime === date).ShowValue)?'insert': '', tableFreeze ? 'fix-col' : '' , (dateIndex >= maxRow || dateIndex < minRow - 1) && (edb_index >= maxCol || edb_index < minCol - 1) ? 'index-outside' : '', isBetweenTargetRows(dateIndex) && isWithinColRange(edb_index) ? 'index-overlap' : '']"
  266. >
  267. <!-- 实际值/插值 -->
  268. <span
  269. :data-rindex="rowHeader[dateIndex]"
  270. :data-cindex="columnHeader[edb_index]"
  271. v-if="(edb.Data.find(_ =>_.DataTime === date)?.ShowValue&&!edb.Data.find(_ =>_.DataTime === date).CanEdit)||disabled"
  272. >
  273. {{showCellValue(edb.Data.find(_ =>_.DataTime === date)) || '-'}}
  274. </span>
  275. </td>
  276. </tr>
  277. <!-- 文本行 -->
  278. <tr
  279. v-for="(row,index) in TableInfo.TableData.TextRowData"
  280. :key="index"
  281. :style="isFreezeRows && maxRow > index+dateArr.length ? `top: ${(index+dateArr.length-minRow+1)*tableHeight + cornerHeight * 3}px;` : ''"
  282. :class="tableFreeze && isBetweenTargetRows(index+dateArr.length) ? 'fix' : ''"
  283. >
  284. <!-- 行头 -->
  285. <th
  286. class="th-tg th-row sm"
  287. @contextmenu.prevent="rightClickHandle"
  288. :data-rindex="rowHeader[index+dateArr.length]"
  289. :data-cindex="-1"
  290. :style="[isFreezeColumns ? {left: 0} : '', isFreezeRows && isBetweenTargetRows(index+dateArr.length) ? {top: (index+dateArr.length- minRow+1)*tableHeight + cornerHeight * 3 + 'px'} : '']"
  291. :class="[isFreezeRowsOrColumns ? 'fix-col' : '', !isBetweenTargetRows(index+dateArr.length) ? 'index' : 'index-overlap']"
  292. >{{rowHeader[index+dateArr.length]}}</th>
  293. <td
  294. v-for="(cell, cell_index) in row"
  295. :key="`${index}_${cell_index}`"
  296. :data-rindex="rowHeader[index+dateArr.length]"
  297. :data-cindex="cell_index===0?-1:columnHeader[cell_index-1]"
  298. :style="[tableFreeze && isWithinColRange(cell_index-1) ? {left: getColumnHeaderWidth(cell_index-1) + (cell_index !== 0 ? dateCellRefHeight : 0) + 'px'} : '', isFreezeRows && isBetweenTargetRows(index+dateArr.length) ? {top: (index+dateArr.length- minRow+1)*tableHeight + cornerHeight * 3 + 'px'} : '', isFreezeColumns && cell_index == 0 ? {left: getColumnHeaderWidth(-1) + 'px'} : '']"
  299. :class="[
  300. getInsertClass(cell),
  301. getFixColClass(cell_index, index, tableFreeze, isFreezeColumns, dateArr),
  302. getIndexOutsideClass(cell_index, index, maxRow, minRow, maxCol, minCol, dateArr),
  303. getIndexOverlapClass(cell_index, index, dateArr),
  304. getIndexClass(cell_index, index, dateArr),
  305. getDateOverlapClass(cell_index, index, dateArr)
  306. ]"
  307. >
  308. <span
  309. :data-rindex="rowHeader[index+dateArr.length]"
  310. :data-cindex="cell_index===0?-1:columnHeader[cell_index-1]"
  311. v-if="(cell.ShowValue&&!cell.CanEdit)||disabled"
  312. > {{cell.ShowValue}}</span>
  313. </td>
  314. </tr>
  315. </tbody>
  316. </table>
  317. </div>
  318. <div :class="['table-wrapper',dynamicSty ]" v-else>
  319. <table width="auto" border="0" class="table" :style="disabled ? 'width:100%':''" style="position: relative;">
  320. <thead>
  321. <tr ref="rowTable">
  322. <!-- 行头 -->
  323. <th
  324. class="th-tg sm index-overlap"
  325. :style="isFreezeAll ? {left: '0', top: '0'} : (isFreezeColumns ? {left: '0'} : (isFreezeRows ? {top: '0'} : ''))"
  326. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  327. >
  328. </th>
  329. <th
  330. class="th-tg index-overlap"
  331. ref="nameTh"
  332. :style="[isFreezeAll ? {left: 21 + 'px',top: 0} : '', isFreezeColumns ? {left: 21 + 'px'} : '', isFreezeRows ? {top: 0} : '']"
  333. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  334. >
  335. </th>
  336. <th
  337. class="th-tg index-overlap"
  338. ref="unitTh"
  339. :style="[isFreezeAll ? {left: nameThWidth + 21 + 'px', top: 0} : '', isFreezeColumns ? {left:nameThWidth + 21 + 'px'} : '', isFreezeRows ? {top: 0} : '']"
  340. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  341. >
  342. </th>
  343. <!-- 列头 -->
  344. <th
  345. v-for="(item, index) in rowHeader"
  346. :key="index"
  347. ref="cellRef"
  348. class="th-tg th-col"
  349. :style="[isFreezeRows ? {top: 0} : '', isFreezeColumns && (maxCol > index && index >= minCol - 1) ? {left: getColumnHeaderWidth(index) + nameThWidth + unitThWidth + 'px'} : '']"
  350. :class="[isFreezeRows || (maxCol > index && index >= minCol - 1) ? 'fix-col' : '', isFreezeColumns && maxCol <= index ? 'index' : '', tableFreeze && isWithinColRange(index) ? 'index-overlap' : '']"
  351. :data-cindex="-1"
  352. :data-rindex="rowHeader[index]">
  353. {{item}}
  354. </th>
  355. </tr>
  356. </thead>
  357. <tbody>
  358. <tr
  359. :style="tableFreeze ? `top: ${1 * tableHeight}px;` : ''"
  360. :class="tableFreeze && maxRow > 0 ? 'fix' : ''"
  361. >
  362. <!-- 行头 -->
  363. <th
  364. class="th-tg sm"
  365. :style="isFreezeAll ? {left: 0,top:1*tableHeight + 'px'} : (isFreezeColumns ? {left: 0} : (isFreezeRows ? {top: 1*tableHeight + 'px'} : ''))"
  366. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  367. >
  368. </th>
  369. <td
  370. colspan="2"
  371. class="head-column"
  372. :class="[isFreezeRowsOrColumns ? 'fix-col' : '']"
  373. :style="[isFreezeAll ? {left: 21 + 'px', top: 22 + 'px'} : (isFreezeColumns ? {left: 21 + 'px'} : (isFreezeRows ? {top: 22 + 'px'} : ''))]"
  374. >
  375. 日期
  376. </td>
  377. <!-- 日期列 -->
  378. <td
  379. v-for="(date, sub_index) in dateArr"
  380. :key="date"
  381. :data-rindex="rowHeader[sub_index]"
  382. :data-cindex="-1"
  383. :style="[tableFreeze && isWithinColRange(sub_index) ? {left: getColumnHeaderWidth(sub_index) + nameThWidth + unitThWidth + 'px'} : '']"
  384. :class="[
  385. 'data-cell',
  386. 'head-column',
  387. tableFreeze && isWithinColRange(sub_index) ? 'fix-col' : ''
  388. ]"
  389. >{{ date }}</td>
  390. <!-- 文本列 -->
  391. <td
  392. v-for="(column,index) in TableInfo.TableData.TextRowData"
  393. :key="index"
  394. :data-cindex="-1"
  395. :data-rindex="rowHeader[index+dateArr.length]"
  396. :style="tableFreeze && isWithinColRange(index+dateArr.length) ? `left: ${getColumnHeaderWidth(index+dateArr.length) + nameThWidth + unitThWidth}px;` : ''"
  397. :class="[([2,3,5].includes(column[0].DataType)&&column[0].ShowValue)?'insert': '', tableFreeze && isWithinColRange(index+dateArr.length) ? 'fix-col' : '']"
  398. @click="clickCell($event,column[0])"
  399. @dblclick="dblClickCell($event,column[0])"
  400. @copy="copyCellHandle($event,column[0])"
  401. @paste="pasteCellHandle($event,column[0])"
  402. >
  403. <span
  404. :data-cindex="-1"
  405. :data-rindex="rowHeader[index+dateArr.length]"
  406. > {{column[0].ShowValue}}</span>
  407. </td>
  408. </tr>
  409. <!-- 指标行 -->
  410. <tr v-for="(edb, edb_index) in TableInfo.TableData.Data" :key="edb.EdbInfoId" :style="tableFreeze ? `top: ${(edb_index- minRow+1)*tableHeight + 44}px;` : ''" :class="tableFreeze && rowHeader[edb_index] >= minRow && rowHeader[edb_index] <= maxRow ? 'fix' : ''">
  411. <!-- 行头 -->
  412. <th
  413. class="th-tg th-row sm"
  414. :data-cindex="columnHeader[edb_index]"
  415. :data-rindex="-1"
  416. @contextmenu.prevent="rightClickHandle"
  417. :style="[isFreezeColumns ? {left: 0} : '']"
  418. :class="[isFreezeColumns ? 'fix-col' : '']"
  419. >
  420. {{columnHeader[edb_index]}}
  421. </th>
  422. <!-- 名称 单位 -->
  423. <td
  424. v-for="(item, index) in EdbKeys"
  425. :key="index"
  426. :data-rindex="-1"
  427. :data-cindex="columnHeader[edb_index]"
  428. @click="() => { !disabled && item==='EdbName' && clickEdbName(edb)}"
  429. :style="[isFreezeColumns ? {left: index === 1 ? nameThWidth + 21 + 'px' : getColumnHeaderWidth(index) + 'px' } : '', tableFreeze && isWithinColRange(index) ? {top: (index- minRow+1)*tableHeight + 22 + 'px'} : '']"
  430. :class="{
  431. 'fix-col': isFreezeColumns
  432. }"
  433. >
  434. <template v-if="item === 'EdbName'">
  435. <span :class="{'edbname-td':disabled}" @click="edbJumpToBase(edb)">{{ edb.EdbAliasName||(edb[item]) }}</span>
  436. </template>
  437. <template v-else>{{ edb[item] }}/{{edb.Frequency }}</template>
  438. </td>
  439. <!-- 数据列 -->
  440. <td
  441. v-for="(data, data_index) in edb.Data"
  442. :key="`${edb.EdbInfoId}_${rowHeader[data_index]}_${columnHeader[edb_index]}`"
  443. :data-rindex="rowHeader[data_index]"
  444. :data-cindex="columnHeader[edb_index]"
  445. :style="tableFreeze && isWithinColRange(data_index) ? `left: ${getColumnHeaderWidth(data_index) + unitThWidth + nameThWidth}px;` : ''"
  446. :class="[([2,3,5].includes(data.DataType)&&data.ShowValue)?'insert': '', tableFreeze && isWithinColRange(data_index) ? 'fix-col' : '']"
  447. @click="clickCell($event,data)"
  448. @dblclick="dblClickCell($event,data)"
  449. @copy="copyCellHandle($event,data)"
  450. @paste="pasteCellHandle($event,data)"
  451. >
  452. <!-- 实际值/插值 -->
  453. <span
  454. :data-rindex="rowHeader[data_index]"
  455. :data-cindex="columnHeader[edb_index]"
  456. >
  457. {{data.ShowValue || '-'}}
  458. </span>
  459. </td>
  460. <!-- 文本列 -->
  461. <td
  462. v-for="(column,column_index) in TableInfo.TableData.TextRowData"
  463. :key="`${rowHeader[column_index+dateArr.length]}_${columnHeader[edb_index]}`"
  464. :data-rindex="rowHeader[column_index+dateArr.length]"
  465. :data-cindex="columnHeader[edb_index]"
  466. :style="tableFreeze && isWithinColRange(column_index+dateArr.length) ? `left: ${getColumnHeaderWidth(column_index+dateArr.length) + nameThWidth + unitThWidth}px;` : ''"
  467. :class="[([2,3,5].includes(column[edb_index+1].DataType)&&column[edb_index+1].ShowValue)?'insert': '', tableFreeze && isWithinColRange(column_index+dateArr.length) ? 'fix-col' : '']"
  468. @click="clickCell($event,column[edb_index+1])"
  469. @dblclick="dblClickCell($event,column[edb_index+1])"
  470. @copy="copyCellHandle($event,column[edb_index+1])"
  471. @paste="pasteCellHandle($event,column[edb_index+1])"
  472. >
  473. <span
  474. :data-rindex="rowHeader[column_index+dateArr.length]"
  475. :data-cindex="columnHeader[edb_index]"
  476. > {{column[edb_index+1].ShowValue}}</span>
  477. />
  478. </td>
  479. </tr>
  480. </tbody>
  481. </table>
  482. </div>
  483. <div class="tool sheet-bottom">
  484. <div class="sheet-source"
  485. v-if="TableInfo.SourcesFrom&&JSON.parse(TableInfo.SourcesFrom).isShow"
  486. :style="`
  487. color: ${ JSON.parse(TableInfo.SourcesFrom).color };
  488. font-size: ${ JSON.parse(TableInfo.SourcesFrom).fontSize }px;
  489. `"
  490. >
  491. source:<em>{{ JSON.parse(TableInfo.SourcesFrom).text}}</em>
  492. </div>
  493. </div>
  494. </div>
  495. </template>
  496. <style lang='scss' scoped>
  497. // sheet-show-wrapper 相关样式
  498. .sheet-show-wrapper {
  499. max-width: 1200px;
  500. overflow: hidden;
  501. position: relative;
  502. margin: 0 auto;
  503. background: #fff;
  504. // table-wrapper 样式
  505. .table-wrapper {
  506. max-width: calc(100vw - 20px);
  507. max-height: calc(100vh - 400px);
  508. margin: 0 auto;
  509. overflow: auto;
  510. -webkit-overflow-scrolling: touch; /* ios滚动条 */
  511. }
  512. .tool {
  513. margin-top: 5px;
  514. span {
  515. cursor: pointer;
  516. }
  517. }
  518. .sheet-bottom {
  519. display: flex;
  520. align-items: center;
  521. justify-content: space-between;
  522. white-space: nowrap;
  523. padding: 0 10px;
  524. .sheet-source {
  525. width: 30%;
  526. min-width: 150px;
  527. overflow: hidden;
  528. text-overflow: ellipsis;
  529. }
  530. }
  531. }
  532. // 表格相关样式
  533. .table {
  534. width: 100%;
  535. font-size: 14px;
  536. color: #333;
  537. td, th {
  538. width: 104px;
  539. min-width: 104px;
  540. height: 35px;
  541. background: #fff;
  542. text-align: center;
  543. word-break: break-all;
  544. border: none;
  545. outline-color: #dcdfe6;
  546. outline-style: solid;
  547. outline-width: 1px;
  548. word-wrap: break-word;
  549. white-space: nowrap;
  550. overflow: hidden;
  551. text-overflow: ellipsis;
  552. position: relative;
  553. &:first-child {
  554. border-left: 1px solid #dcdfe6;
  555. }
  556. &.td-chose::after {
  557. position: absolute;
  558. top: 0;
  559. left: 0;
  560. right: 0;
  561. bottom: 0;
  562. content: "";
  563. display: block;
  564. outline: 0;
  565. border: 2px solid #0033FF;
  566. box-shadow: 0 0 5px rgba(73, 177, 249, .5);
  567. }
  568. &.insert {
  569. background: #FFEFDD;
  570. }
  571. .edbname-td {
  572. &:hover {
  573. text-decoration: underline;
  574. }
  575. }
  576. &.fix-col {
  577. position: sticky;
  578. z-index: 97; // 表格右键操作弹窗为99
  579. }
  580. &.index {
  581. z-index: 96; // 冻结的行列z-index为97,此处为96确保表格行不遮挡表格行内容
  582. }
  583. &.index-outside {
  584. z-index: 95; // 同上
  585. }
  586. &.index-overlap {
  587. z-index: 98; // 冻结的行列z-index为97,此处为行列交叉的地方层级要比冻结的行列高一层
  588. }
  589. &.index-highest {
  590. z-index: 99;
  591. }
  592. }
  593. .th-tg {
  594. background: #EBEEF5;
  595. &:hover {
  596. cursor: pointer;
  597. background: #ddd;
  598. }
  599. &.sm {
  600. width: 36px;
  601. min-width: 36px;
  602. max-width: 36px;
  603. }
  604. }
  605. .data-cell {
  606. color: #333;
  607. &.one-bg {
  608. background-color: #EFEEF1;
  609. }
  610. &.two-bg {
  611. background-color: #fff;
  612. }
  613. }
  614. .thead-sticky {
  615. position: sticky;
  616. top: 0;
  617. }
  618. .head-column {
  619. background-color: #505B78;
  620. color: #fff;
  621. }
  622. .split-word {
  623. span {
  624. display: inline;
  625. }
  626. }
  627. }
  628. tr {
  629. &.fix {
  630. position: sticky;
  631. top: 0;
  632. z-index: 98; // 表格右键操作弹窗为99
  633. }
  634. }
  635. // 滚动条样式
  636. ::-webkit-scrollbar {
  637. width: 6px;
  638. height: 6px;
  639. }
  640. ::-webkit-scrollbar-track {
  641. background: rgb(239, 239, 239);
  642. border-radius: 2px;
  643. }
  644. ::-webkit-scrollbar-thumb {
  645. background: #ccc;
  646. border-radius: 10px;
  647. &:hover {
  648. background: #888;
  649. }
  650. }
  651. ::-webkit-scrollbar-corner {
  652. background: #666;
  653. }
  654. // PC端表格样式
  655. .pc-sty table {
  656. table-layout: auto;
  657. td, th {
  658. width: auto;
  659. height: auto;
  660. padding: 0.4em 0;
  661. }
  662. }
  663. // 移动端表格样式
  664. .mobile-sty table {
  665. table-layout: auto;
  666. td, th {
  667. min-width: 120px;
  668. height: 40px;
  669. }
  670. }
  671. // 背景水印样式
  672. .background-watermark {
  673. background-repeat: no-repeat;
  674. background-position: center center;
  675. background-size: 100%;
  676. }
  677. @media screen and (min-width: 650px) {
  678. .sheet-show-wrapper {
  679. .table-wrapper {
  680. max-height: calc(100vh - 220px);
  681. }
  682. .tool {
  683. margin-top: 3px;
  684. }
  685. .sheet-bottom {
  686. padding: 0 5px;
  687. .sheet-source {
  688. width: 15%;
  689. min-width: 75px;
  690. }
  691. }
  692. }
  693. // 表格相关样式
  694. .table {
  695. width: 100%;
  696. font-size: 7px;
  697. color: #333;
  698. td, th {
  699. width: 52px;
  700. min-width: 52px;
  701. height: 17px;
  702. }
  703. .th-tg {
  704. &.sm {
  705. width: 18px;
  706. min-width: 18px;
  707. max-width: 18px;
  708. }
  709. }
  710. }
  711. // 滚动条样式
  712. ::-webkit-scrollbar {
  713. width: 3px;
  714. height: 3px;
  715. }
  716. ::-webkit-scrollbar-track {
  717. background: rgb(239, 239, 239);
  718. border-radius: 1px;
  719. }
  720. ::-webkit-scrollbar-thumb {
  721. background: #ccc;
  722. border-radius: 5px;
  723. }
  724. // 移动端表格样式
  725. .mobile-sty table {
  726. td, th {
  727. min-width: 60px;
  728. height: 20px;
  729. }
  730. }
  731. }
  732. </style>