SheetViewModal.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <teleport to="body">
  3. <div v-if="store.sheetViewModal" class="dialog-container">
  4. <header class="tw-flex tw-place-content-between tw-items-center">
  5. <div class="tw-text-2xl ctw-text-base tw-ml-5 tw-my-2">原图</div>
  6. <div class="tw-flex tw-items-center tw-gap-2 tw-mx-8 tw-flex-grow">
  7. <span
  8. v-for="(u, index) in dataUrls"
  9. :key="index"
  10. class="image-index hover:tw-bg-gray-300"
  11. :class="checkedIndex === index && 'tw-bg-gray-300'"
  12. @click="checkedIndex = index"
  13. >{{ index + 1 }}</span
  14. >
  15. </div>
  16. <a-button shape="circle" @click="store.sheetViewModal = false">
  17. <template #icon><CloseOutlined /></template>
  18. </a-button>
  19. </header>
  20. <div>
  21. <div
  22. v-for="(url, index) in dataUrls"
  23. :key="index"
  24. style="display: none"
  25. :class="index === checkedIndex && 'show-image'"
  26. >
  27. <img :src="url" />
  28. </div>
  29. </div>
  30. </div>
  31. </teleport>
  32. </template>
  33. <script setup lang="ts">
  34. import { reactive, watch } from "vue";
  35. import { CloseOutlined } from "@ant-design/icons-vue";
  36. import { store } from "@/store/store";
  37. import { loadImage } from "@/utils/utils";
  38. import type { PictureSlice } from "@/types";
  39. const dataUrls: string[] = reactive([]);
  40. watch(
  41. () => store.sheetViewModal,
  42. async () => {
  43. if (!store.sheetViewModal) return;
  44. dataUrls.splice(0);
  45. const urls = store.currentTask?.sheetUrls ?? [];
  46. const images = [];
  47. for (const url of urls) {
  48. images.push(await loadImage(url));
  49. }
  50. const sheetConfig = store.setting.sheetConfig;
  51. for (let i = 0; i < images.length; i++) {
  52. if (sheetConfig.length === 0) {
  53. dataUrls.push(
  54. getDataUrlForSheetConfig(
  55. images[i],
  56. i % 2 === 0
  57. ? [
  58. // 通过-1来标记该用默认遮盖规则
  59. { i: -1, x: 0, y: 0, w: 0, h: 0 },
  60. ]
  61. : []
  62. )
  63. );
  64. } else {
  65. const scs = sheetConfig.filter((s) => s.i - 1 === i);
  66. dataUrls.push(getDataUrlForSheetConfig(images[i], scs));
  67. }
  68. }
  69. }
  70. );
  71. let checkedIndex = $ref(0);
  72. function getDataUrlForSheetConfig(
  73. image: HTMLImageElement,
  74. sliceConfigs: Array<PictureSlice>
  75. ) {
  76. const canvas = document.createElement("canvas");
  77. canvas.width = image.naturalWidth;
  78. canvas.height = image.naturalHeight;
  79. const ctx = canvas.getContext("2d");
  80. if (!ctx) {
  81. console.log('canvas.getContext("2d") error');
  82. return "null";
  83. }
  84. // drawImage 画图软件透明色
  85. ctx?.drawImage(image, 0, 0);
  86. ctx.fillStyle = "grey";
  87. for (const sc of sliceConfigs) {
  88. if (sc.i === -1) {
  89. ctx.fillRect(0, 0, image.naturalWidth / 2, image.naturalHeight / 3);
  90. } else if (sc.w === 0 && sc.h === 0) {
  91. ctx.fillRect(0, 0, image.naturalWidth, image.naturalHeight);
  92. } else {
  93. ctx.fillRect(sc.x, sc.y, sc.w, sc.h);
  94. }
  95. }
  96. const dataurl = canvas.toDataURL();
  97. return dataurl;
  98. }
  99. </script>
  100. <style scoped>
  101. .dialog-container {
  102. /* always top */
  103. z-index: 99999;
  104. position: absolute;
  105. background-color: var(--app-container-bg-color);
  106. top: 0;
  107. left: 0;
  108. width: 100vw;
  109. height: 100vh;
  110. overflow: auto;
  111. min-width: var(--app-min-width);
  112. }
  113. header {
  114. color: var(--app-main-text-color);
  115. border-bottom: 1px solid var(--app-main-bg-color);
  116. }
  117. .image-index {
  118. display: inline-block;
  119. border: 1px solid grey;
  120. width: 25px;
  121. text-align: center;
  122. border-radius: 5px;
  123. cursor: pointer;
  124. }
  125. .show-image {
  126. display: block !important;
  127. }
  128. </style>