RenderTable.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <script setup lang="ts">
  2. import { magicApi } from "@/utils/database/magic-api-request";
  3. import { useResizeObserver } from "@vueuse/core";
  4. import { stringIsBlank } from "@/utils/blank-utils";
  5. defineOptions({
  6. name: "RenderTable",
  7. });
  8. const props = defineProps<{
  9. htmlData: string;
  10. wardCode: string;
  11. }>();
  12. const store = reactive({
  13. htmlData: "",
  14. data: [],
  15. spans: [] as { span: HTMLSpanElement; code: string }[],
  16. business: new Set(),
  17. businessData: {},
  18. });
  19. const divRaf = ref<HTMLDivElement>();
  20. useResizeObserver(divRaf, () => {
  21. if (stringIsBlank(props.htmlData)) return;
  22. nextTick(() => {
  23. if (props.htmlData) renderTable(false);
  24. });
  25. });
  26. async function replace(query = true) {
  27. if (query) {
  28. store.businessData = await magicApi({
  29. url: "/public/dashboard/dataSource",
  30. method: "post",
  31. data: {
  32. isSource: false,
  33. business: Array.from(store.business.values()),
  34. wardCode: props.wardCode,
  35. },
  36. })
  37. .then(res => {
  38. return res;
  39. })
  40. .catch(() => {
  41. return {};
  42. });
  43. }
  44. store.spans.forEach(item => {
  45. item.span.innerHTML = store.businessData[item.code] ?? "";
  46. });
  47. await nextTick();
  48. store.spans.forEach(item => {
  49. const td = (item.span as Element).closest("td");
  50. if (td == null) {
  51. return;
  52. }
  53. if (!(td.className as string).includes("td-text_hidden")) {
  54. td.className += " td-text_hidden " + td.className;
  55. }
  56. if (td.clientWidth !== td.scrollWidth) {
  57. const marqueeDiv = document.createElement("div");
  58. marqueeDiv.className = "marquee";
  59. marqueeDiv.style.setProperty(
  60. "--translate-scroll-px",
  61. `-${td.scrollWidth}px`
  62. );
  63. marqueeDiv.innerHTML = td.innerHTML;
  64. td.innerHTML = "";
  65. td.appendChild(marqueeDiv);
  66. }
  67. });
  68. }
  69. function getBusiness(spans: HTMLSpanElement[]) {
  70. spans.forEach(span => {
  71. const code = span.getAttribute("data-element-code");
  72. span.innerHTML = "";
  73. store.business.add(code);
  74. store.spans.push({
  75. span,
  76. code,
  77. });
  78. });
  79. }
  80. async function renderTable(query = true) {
  81. await nextTick();
  82. store.business = new Set();
  83. store.spans = [];
  84. divRaf.value.innerHTML = store.htmlData;
  85. const table = divRaf.value.querySelector("table");
  86. const trs = table.querySelectorAll("tr");
  87. trs.forEach(tr => {
  88. const tds = tr.querySelectorAll("td");
  89. tds.forEach(td => {
  90. const business = td.querySelectorAll("span[data-element-code]");
  91. if (business.length > 0) {
  92. // @ts-ignore
  93. getBusiness(business);
  94. }
  95. });
  96. });
  97. replace(query);
  98. }
  99. watch(
  100. () => props.htmlData,
  101. async () => {
  102. await nextTick();
  103. store.htmlData = props.htmlData;
  104. renderTable();
  105. }
  106. );
  107. defineExpose({
  108. reloadData() {
  109. renderTable();
  110. },
  111. });
  112. </script>
  113. <template>
  114. <div class="layout_container render-table" ref="divRaf"></div>
  115. </template>
  116. <style lang="scss">
  117. .render-table {
  118. background: #0f1628;
  119. font-size: 1.13rem;
  120. table {
  121. width: 100%;
  122. border-collapse: collapse;
  123. border: 1px solid white;
  124. height: 100% !important;
  125. table-layout: fixed;
  126. color: white;
  127. }
  128. td {
  129. border: 1px solid white;
  130. text-align: center !important;
  131. }
  132. .td-text_hidden {
  133. white-space: nowrap;
  134. text-overflow: ellipsis;
  135. overflow: hidden;
  136. }
  137. .marquee {
  138. white-space: nowrap; /* 不换行 */
  139. animation: marquee 10s linear infinite; /* 动画效果 */
  140. line-height: 100%;
  141. text-align: center;
  142. }
  143. @keyframes marquee {
  144. 0% {
  145. transform: translateX(0px);
  146. }
  147. 100% {
  148. transform: translateX(var(--translate-scroll-px));
  149. }
  150. }
  151. }
  152. </style>