view-alarm.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <template>
  2. <div class="view-alarm">
  3. <a-row class="grid-demo" style="margin-bottom: 16px">
  4. <a-col flex="100px">
  5. <div>{{ $t('previewList.bjlx') }}</div>
  6. </a-col>
  7. <a-col flex="auto">
  8. <div>{{ data.Name }}</div>
  9. </a-col>
  10. </a-row>
  11. <a-row class="grid-demo" style="margin-bottom: 16px">
  12. <a-col flex="100px">
  13. <div>{{ $t('previewList.bjsj') }}</div>
  14. </a-col>
  15. <a-col flex="auto">
  16. <div>{{ data.timeN }}</div>
  17. </a-col>
  18. </a-row>
  19. <template v-if="isShowCl">
  20. <a-divider />
  21. <a-row class="grid-demo" justify="center" style="margin-bottom: 16px">
  22. <a-col :span="19">
  23. <a-radio-group v-model="alarmArchiving" type="button" size="small">
  24. <a-radio
  25. v-for="(item, i) in alarmArchivingOptions"
  26. :key="i"
  27. :value="item.value"
  28. ><div style="display: flex; align-items: center; gap: 4px"
  29. ><Icon :icon="item.icon" />{{ item.label }}</div
  30. ></a-radio
  31. >
  32. <a-button size="small" @click="() => (alarmArchiving = '0')">
  33. <template #icon>
  34. <icon-refresh />
  35. </template>
  36. </a-button>
  37. </a-radio-group>
  38. </a-col>
  39. </a-row>
  40. </template>
  41. <a-divider />
  42. <div class="view-alarm-pic">
  43. <img id="image" class="view-pic" :src="data.tImg" alt="Picture" />
  44. </div>
  45. <div id="image-preview">
  46. <div v-if="loading" class="va-loading">
  47. <a-spin dot />
  48. </div>
  49. </div>
  50. </div>
  51. </template>
  52. <script setup lang="ts">
  53. import { onMounted, onUnmounted, ref, watch } from 'vue';
  54. import { Icon } from '@iconify/vue';
  55. import { getSetArchived } from '@/api/system';
  56. import Viewer from 'viewerjs';
  57. import 'viewerjs/dist/viewer.css';
  58. interface DataProps {
  59. [key: string]: any;
  60. }
  61. const props = defineProps<{
  62. data: DataProps;
  63. guid: any;
  64. isShowCl: boolean;
  65. }>();
  66. const emits = defineEmits(['alarmArchiving']);
  67. const viewer = ref<Viewer | null>(null);
  68. const loading = ref(true);
  69. let url: string;
  70. const init = () => {
  71. const canvas = document.createElement('canvas');
  72. const { imgJson, img } = props.data;
  73. canvas.width = imgJson.imageWidth;
  74. canvas.height = imgJson.imageHeight;
  75. const ctx: CanvasRenderingContext2D | null = canvas.getContext('2d');
  76. const imgObj = new Image(imgJson.imageWidth, imgJson.imageHeight);
  77. imgObj.setAttribute('crossOrigin', 'anonymous');
  78. imgObj.src = img;
  79. imgObj.onload = () => {
  80. if (ctx) {
  81. ctx.drawImage(imgObj, 0, 0);
  82. imgJson.resultData.objectList.forEach((item: any) => {
  83. // 绘制矩形
  84. ctx.strokeStyle = 'red';
  85. ctx.lineWidth = 4;
  86. ctx.strokeRect(
  87. item.rect.x,
  88. item.rect.y,
  89. item.rect.width,
  90. item.rect.height
  91. );
  92. // 绘制标题
  93. ctx.fillStyle = 'red';
  94. ctx.fillRect(
  95. item.rect.x - 2,
  96. item.rect.y - 30,
  97. item.rect.width + 4,
  98. 40
  99. );
  100. // 在矩形框内绘制矩形文字
  101. ctx.fillStyle = 'white';
  102. ctx.font = '26px Arial';
  103. ctx.fillText(props.data.Name, item.rect.x + 6, item.rect.y - 4);
  104. });
  105. }
  106. canvas.toBlob((blob: any) => {
  107. // 创建一个指向该 Blob 的 URL
  108. url = URL.createObjectURL(blob);
  109. viewer.value = new Viewer(
  110. document.getElementById('image') as HTMLImageElement,
  111. {
  112. inline: false,
  113. navbar: false,
  114. backdrop: false,
  115. button: false,
  116. title: false,
  117. toolbar: {
  118. zoomIn: 4,
  119. zoomOut: 4,
  120. oneToOne: 4,
  121. reset: 4,
  122. prev: 0,
  123. play: {
  124. show: 4,
  125. size: 'large',
  126. },
  127. next: 0,
  128. rotateLeft: 4,
  129. rotateRight: 4,
  130. flipHorizontal: 4,
  131. flipVertical: 4,
  132. },
  133. className: 'viewer-box',
  134. container: '#image-preview',
  135. url: () => url,
  136. viewed() {
  137. const viewImg: any = document.querySelector('.viewer-canvas>img');
  138. viewer.value?.scale(0.8);
  139. viewer.value?.moveTo(
  140. (window.innerWidth - 340) / 2 - viewImg.offsetWidth / 2,
  141. window.innerHeight / 2 - viewImg.offsetHeight / 2
  142. );
  143. loading.value = false;
  144. },
  145. }
  146. );
  147. viewer.value?.show(true);
  148. }, 'image/jpeg');
  149. };
  150. };
  151. const alarmArchiving = ref('0');
  152. const alarmArchivingOptions = ref<any[]>([
  153. {
  154. label: '正确报警',
  155. value: '1',
  156. icon: 'mdi:alarm-light-outline',
  157. },
  158. {
  159. label: '错误报警',
  160. value: '2',
  161. icon: 'mdi:alarm-light-off-outline',
  162. },
  163. ]);
  164. watch(alarmArchiving, async (Archived) => {
  165. if (Archived === props.data.AlarmArchiving) return;
  166. emits('alarmArchiving', Archived);
  167. await getSetArchived(
  168. {
  169. AlarmID: props.data.Id,
  170. Archived,
  171. },
  172. { GUID: props.guid }
  173. );
  174. });
  175. onMounted(() => {
  176. alarmArchiving.value = props.data.AlarmArchiving;
  177. init();
  178. });
  179. onUnmounted(() => {
  180. viewer.value?.destroy();
  181. URL.revokeObjectURL(url);
  182. });
  183. </script>
  184. <style lang="less">
  185. .viewer-box {
  186. width: 100%;
  187. position: absolute;
  188. }
  189. #image-preview {
  190. position: fixed;
  191. left: 0;
  192. top: 0;
  193. width: calc(100% - 340px);
  194. height: 100%;
  195. }
  196. .viewer-canvas {
  197. background-color: #000000a1;
  198. }
  199. .view-alarm {
  200. .va-loading {
  201. width: 100%;
  202. height: 100%;
  203. display: flex;
  204. justify-content: center;
  205. align-items: center;
  206. background-color: #000000a1;
  207. }
  208. .view-alarm-pic {
  209. width: 200px;
  210. img {
  211. width: 100%;
  212. }
  213. }
  214. }
  215. </style>