index.tsx 8.5 KB

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