index.tsx 8.8 KB

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