index.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. Button,
  5. Grid,
  6. GridItem,
  7. Icon,
  8. Image,
  9. closeToast,
  10. showFailToast,
  11. showLoadingToast,
  12. showSuccessToast,
  13. showToast
  14. } from 'vant';
  15. import iconDownload from './images/icon-download.png';
  16. import iconFirend from './images/icon-friend.png';
  17. import iconWeChat from './images/icon-wechat.png';
  18. import iconFriendRing from './images/icon-friend-ring.png';
  19. import iconLink from './images/icon-link.png';
  20. import iconLogo from './images/icon-logo.png';
  21. import audioLabel from './images/audioLabel.png';
  22. import videoLabel from './images/videoLabel.png';
  23. import videoShareBg from './images/video-share-bg.png';
  24. import audioShareBg from './images/audio-share-bg.png';
  25. import audioPan from '../images/audio-pan.png';
  26. import smallLogo from '@common/images/logo.png';
  27. import musicBg from './images/music-bg.png';
  28. import QRCode from 'qrcode';
  29. import { promisefiyPostMessage, postMessage } from '@/helpers/native-message';
  30. import html2canvas from 'html2canvas';
  31. export default defineComponent({
  32. name: 'sahre-model',
  33. props: {
  34. musicDetail: {
  35. type: Object,
  36. default: () => {}
  37. },
  38. playType:{
  39. type: String,
  40. default: ''
  41. }
  42. },
  43. emits: ['close'],
  44. setup(props, { emit }) {
  45. const canvasRef = ref();
  46. const state = reactive({
  47. saveLoading: false,
  48. image: null as any,
  49. url: ''
  50. });
  51. const saveImg = async () => {
  52. showLoadingToast({
  53. message: '图片生成中...',
  54. forbidClick: true
  55. });
  56. setTimeout(() => {
  57. state.saveLoading = false;
  58. }, 100);
  59. const res = await promisefiyPostMessage({
  60. api: 'savePicture',
  61. content: {
  62. base64: state.image
  63. }
  64. });
  65. if (res?.content?.status === 'success') {
  66. showSuccessToast('已保存到相册');
  67. } else {
  68. showFailToast('保存失败');
  69. }
  70. };
  71. const onSaveWe = async (type: string) => {
  72. setTimeout(() => {
  73. state.saveLoading = false;
  74. }, 100);
  75. const res = await promisefiyPostMessage({
  76. api: 'shareTripartite',
  77. content: {
  78. title: '我在音乐数字课堂发布了演奏作品',
  79. desc: props.musicDetail.desc,
  80. // image: state.image,
  81. video: '',
  82. type: 'link',
  83. url: state.url,
  84. thumb: encodeURI(decodeURI(props.musicDetail.img)),
  85. shareType: type
  86. }
  87. // 作品的封面图
  88. });
  89. if (res?.content?.status) {
  90. showSuccessToast('分享成功');
  91. } else {
  92. showFailToast('分享失败');
  93. }
  94. };
  95. const onSavePath = (type: string) => {
  96. // 判断是否在保存中...
  97. if (state.saveLoading) {
  98. return;
  99. }
  100. state.saveLoading = true;
  101. // 判断是否已经生成图片
  102. if (state.image) {
  103. if (type) {
  104. onSaveWe(type);
  105. } else {
  106. saveImg();
  107. }
  108. } else {
  109. const container: any = document.getElementById('shareContent');
  110. html2canvas(container, {
  111. allowTaint: true,
  112. useCORS: true,
  113. backgroundColor: null
  114. })
  115. .then(async canvas => {
  116. const url = canvas.toDataURL('image/png');
  117. state.image = url;
  118. if (type) {
  119. onSaveWe(type);
  120. } else {
  121. saveImg();
  122. }
  123. })
  124. .catch(() => {
  125. closeToast();
  126. state.saveLoading = false;
  127. });
  128. }
  129. };
  130. const copyText = (text: string) => {
  131. // 数字没有 .length 不能执行selectText 需要转化成字符串
  132. const textString = text.toString();
  133. let input = document.querySelector('#copy-input') as HTMLInputElement;
  134. if (!input) {
  135. input = document.createElement('input');
  136. input.id = 'copy-input';
  137. input.readOnly = true; // 防止ios聚焦触发键盘事件
  138. input.style.position = 'fixed';
  139. input.style.left = '-1000px';
  140. input.style.zIndex = '-1000';
  141. // 为了处理,页面滑动到底部的问题
  142. document.body.appendChild(input);
  143. // document.querySelector('#input-copy-container')?.appendChild(input)
  144. }
  145. input.value = textString;
  146. // ios必须先选中文字且不支持 input.select();
  147. selectText(input, 0, textString.length);
  148. console.log(document.execCommand('copy'), 'execCommand');
  149. if (document.execCommand('copy')) {
  150. document.execCommand('copy');
  151. showToast('复制成功');
  152. }
  153. input.blur();
  154. // input自带的select()方法在苹果端无法进行选择,所以需要自己去写一个类似的方法
  155. // 选择文本。createTextRange(setSelectionRange)是input方法
  156. function selectText(textbox: any, startIndex: any, stopIndex: any) {
  157. if (textbox.createTextRange) {
  158. //ie
  159. const range = textbox.createTextRange();
  160. range.collapse(true);
  161. range.moveStart('character', startIndex); //起始光标
  162. range.moveEnd('character', stopIndex - startIndex); //结束光标
  163. range.select(); //不兼容苹果
  164. } else {
  165. //firefox/chrome
  166. textbox.setSelectionRange(startIndex, stopIndex);
  167. textbox.focus();
  168. }
  169. }
  170. };
  171. onMounted(() => {
  172. const canvas = canvasRef.value;
  173. state.url =
  174. location.origin +
  175. location.pathname +
  176. '#/shareCreation?id=' +
  177. props.musicDetail.id;
  178. QRCode.toCanvas(
  179. canvas,
  180. state.url,
  181. {
  182. margin: 1
  183. },
  184. (error: any) => {
  185. if (error) console.log(error);
  186. console.log('success');
  187. }
  188. );
  189. });
  190. return () => (
  191. <div class={styles.shareModel}>
  192. <div class={styles.shareContent} id="shareContent">
  193. <img src={props.playType === "Audio" ? audioShareBg : videoShareBg} class={styles.shareBg} />
  194. <div class={styles.share_content__title}>
  195. <p class={styles.large}>我在音乐数字课堂发布了演奏作品</p>
  196. <p class={styles.small}>赶快扫码看看吧!</p>
  197. </div>
  198. <div class={[styles.share_music__container, styles.sectionFile]}>
  199. <div class={styles.uploadImg}>
  200. <img
  201. src={audioPan}
  202. class={styles.audioPan}
  203. crossorigin="anonymous"
  204. />
  205. <img
  206. src={
  207. props.musicDetail.img
  208. ? props.musicDetail.img + '?t' + new Date().getTime()
  209. : musicBg
  210. }
  211. class={styles.muploader}
  212. crossorigin="anonymous"
  213. />
  214. <img class={styles.imgLabel} src={props.playType === "Audio" ? audioLabel : videoLabel} />
  215. </div>
  216. <div class={styles.musicDetail}>
  217. <p class={[styles.musicName, 'van-ellipsis']}>
  218. {props.musicDetail.musicSheetName}
  219. </p>
  220. <p class={styles.username}>
  221. 演奏者:{props.musicDetail.username}
  222. </p>
  223. </div>
  224. </div>
  225. <div class={styles.downloadSection}>
  226. <div class={styles.qrcode}>
  227. <canvas ref={canvasRef} class={styles.qrcodeCanvas}></canvas>
  228. <img src={smallLogo} class={styles.qrcodeLogo} />
  229. </div>
  230. <div class={styles.qrtips}>
  231. <div>温馨提示:</div>
  232. <p class={styles.tip}>
  233. 保存图片到相册后,请在微信里扫码查看~
  234. </p>
  235. <img src={iconLogo} class={styles.iconLogo} />
  236. {/* <p class={styles.downTip}>扫码下载音乐数字课堂App</p> */}
  237. </div>
  238. </div>
  239. </div>
  240. <div class={styles.shareBottom}>
  241. <Icon
  242. name="cross"
  243. class={styles.iconClose}
  244. onClick={() => emit('close')}
  245. />
  246. <div class={styles.share__header}>海报已生成!快来分享吧!</div>
  247. <Grid columnNum={4} border={false} class={styles.gridSection}>
  248. <GridItem
  249. icon={iconDownload}
  250. text="保存本地"
  251. onClick={() => onSavePath('')}></GridItem>
  252. {/* <GridItem icon={iconFirend} text="群聊"></GridItem> */}
  253. <GridItem
  254. icon={iconWeChat}
  255. text="微信好友"
  256. onClick={() => onSavePath('wechat')}></GridItem>
  257. <GridItem
  258. icon={iconFriendRing}
  259. text="朋友圈"
  260. onClick={() => onSavePath('wechat_circle')}></GridItem>
  261. <GridItem
  262. icon={iconLink}
  263. text="复制链接"
  264. onClick={() => copyText(state.url)}></GridItem>
  265. </Grid>
  266. <div
  267. class={[styles.btn, 'van-hairline--top']}
  268. onClick={() => emit('close')}>
  269. 取消
  270. </div>
  271. </div>
  272. </div>
  273. );
  274. }
  275. });