pen.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import { promisefiyPostMessage } from '@/helpers/native-message';
  2. import html2canvas from 'html2canvas';
  3. import {
  4. closeToast,
  5. showFailToast,
  6. showLoadingToast,
  7. showSuccessToast
  8. } from 'vant';
  9. import {
  10. defineComponent,
  11. toRefs,
  12. ref,
  13. reactive,
  14. onMounted,
  15. onUnmounted,
  16. nextTick
  17. } from 'vue';
  18. import styles from './pen.module.less';
  19. import Tips, { tipState } from '../tips';
  20. export default defineComponent({
  21. name: 'tools-pen',
  22. props: {
  23. isWhite: {
  24. type: Boolean,
  25. default: false
  26. },
  27. tip: {
  28. type: String,
  29. default: '请确认是否退出?'
  30. },
  31. show: {
  32. type: Boolean,
  33. default: false
  34. },
  35. close: {
  36. type: Function,
  37. default: () => ({})
  38. }
  39. },
  40. setup(props) {
  41. const { show } = toRefs(props);
  42. const firstRender = ref(true);
  43. const src = /(localhost|192)/.test(location.host)
  44. ? 'https://test.lexiaoya.cn/whiteboard-noCollab?platform=daya'
  45. : `https://online.lexiaoya.cn/whiteboard-noCollab?platform=daya`;
  46. const exportImg = (event: MessageEvent) => {
  47. const data = event.data;
  48. // console.log('🚀 ~ event:', data)
  49. if (data.api === 'excalidraw_exportImg') {
  50. imgs.base64 = data.base64;
  51. imgs.exported = true;
  52. nextTick(() => {
  53. onSaveImg();
  54. });
  55. }
  56. };
  57. onMounted(() => {
  58. window.addEventListener('message', exportImg);
  59. });
  60. onUnmounted(() => {
  61. window.removeEventListener('message', exportImg);
  62. });
  63. const imgs = reactive({
  64. exported: false,
  65. saveLoading: false,
  66. base64: '',
  67. image: ''
  68. });
  69. const saveImg = async () => {
  70. showLoadingToast({ message: '图片生成中...', forbidClick: true });
  71. setTimeout(() => {
  72. imgs.saveLoading = false;
  73. }, 100);
  74. const res = await promisefiyPostMessage({
  75. api: 'savePicture',
  76. content: {
  77. base64: imgs.image
  78. }
  79. });
  80. if (res?.content?.status === 'success') {
  81. showSuccessToast('保存成功');
  82. } else {
  83. showFailToast('保存失败');
  84. }
  85. imgs.exported = false;
  86. };
  87. const onSaveImg = async () => {
  88. // 判断是否在保存中...
  89. if (imgs.saveLoading) {
  90. return;
  91. }
  92. console.log('开始');
  93. imgs.saveLoading = true;
  94. const container: any = document.getElementById(`app`);
  95. html2canvas(container, {
  96. allowTaint: true,
  97. useCORS: true,
  98. backgroundColor: null
  99. })
  100. .then(async canvas => {
  101. // console.log("🚀 ~ canvas:", canvas)
  102. // document.body.appendChild(canvas)
  103. // const url = await canvas.toDataURL()
  104. try {
  105. imgs.image = canvas.toDataURL();
  106. } catch (error) {
  107. console.log(error);
  108. }
  109. console.log('🚀 ~ imgs.image:', imgs.image);
  110. saveImg();
  111. })
  112. .catch(error => {
  113. console.log('🚀 ~ error:', error);
  114. closeToast();
  115. imgs.saveLoading = false;
  116. imgs.exported = false;
  117. });
  118. };
  119. return () => (
  120. <div
  121. class={[
  122. styles.pen,
  123. firstRender.value ? styles.dely : '',
  124. show.value ? styles.open : styles.hide
  125. ]}>
  126. <iframe
  127. class={styles.iframe}
  128. style={{
  129. background: props.isWhite ? '#fff' : 'transparent'
  130. }}
  131. frameborder="0"
  132. width="100vw"
  133. height="100vh"
  134. src={src}
  135. onLoad={() => {
  136. firstRender.value = false;
  137. }}></iframe>
  138. {imgs.exported ? (
  139. <img crossorigin="anonymous" class={styles.img} src={imgs.base64} />
  140. ) : (
  141. <div class={styles.rightItem} onClick={() => {
  142. tipState.content = props.tip
  143. tipState.show = true
  144. }}>
  145. <svg width="22px" height="20px" viewBox="0 0 22 20">
  146. <path
  147. transform="translate(-1.000000, -2.000000)"
  148. fill="#FFFFFF"
  149. d="M13,2 C13.5522847,2 14,2.44771525 14,3 C14,3.51283584 13.6139598,3.93550716 13.1166211,3.99327227 L13,4 L3,4 L3,20 L13,20 C13.5128358,20 13.9355072,20.3860402 13.9932723,20.8833789 L14,21 C14,21.5128358 13.6139598,21.9355072 13.1166211,21.9932723 L13,22 L2,22 C1.48716416,22 1.06449284,21.6139598 1.00672773,21.1166211 L1,21 L1,3 C1,2.48716416 1.38604019,2.06449284 1.88337887,2.00672773 L2,2 L13,2 Z M17.7071068,7.05025253 L21.9497475,11.2928932 L21.9497475,11.2928932 C22.3402718,11.6834175 22.3402718,12.3165825 21.9497475,12.7071068 L17.7071068,16.9497475 C17.3165825,17.3402718 16.6834175,17.3402718 16.2928932,16.9497475 C15.9023689,16.5592232 15.9023689,15.9260582 16.2928932,15.5355339 L18.828,12.999 L9.29368112,13 C8.74139637,13 8.29368112,12.5522847 8.29368112,12 C8.29368112,11.4871642 8.67972131,11.0644928 9.17706,11.0067277 L9.29368112,11 L18.827,10.999 L16.2928932,8.46446609 C15.9023689,8.0739418 15.9023689,7.44077682 16.2928932,7.05025253 C16.6834175,6.65972824 17.3165825,6.65972824 17.7071068,7.05025253 Z"></path>
  150. </svg>
  151. </div>
  152. )}
  153. <Tips onConfirm={() => {
  154. props.close()
  155. tipState.show = false
  156. }} />
  157. </div>
  158. );
  159. }
  160. });