musicScore.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { defineComponent, ref, nextTick, onMounted, watch } from 'vue';
  2. import styles from './musicScore.module.less';
  3. import qs from 'query-string';
  4. import iconStart from '../image/icon-start.svg';
  5. import { listenerMessage, postMessage } from '@/helpers/native-message';
  6. import { Loading, Popup, Skeleton } from 'vant';
  7. import { usePageVisibility } from '@vant/use';
  8. import { useRoute } from 'vue-router';
  9. import { browser, vaildMusicScoreUrl } from '@/helpers/utils';
  10. import { storage } from '@/helpers/storage';
  11. import { ACCESS_TOKEN } from '@/store/mutation-types';
  12. import TheVip from '@/components/the-vip';
  13. import { state } from '@/state';
  14. import request from '@/helpers/request';
  15. export default defineComponent({
  16. name: 'musicScore',
  17. props: {
  18. pageVisibility: {
  19. type: String,
  20. default: ''
  21. },
  22. show: {
  23. type: Boolean,
  24. default: false
  25. },
  26. music: {
  27. type: Object,
  28. default: () => {}
  29. },
  30. activeModel: {
  31. type: Boolean
  32. }
  33. },
  34. emits: ['setIframe'],
  35. setup(props, { emit }) {
  36. const browserInfo = browser();
  37. const route = useRoute();
  38. const isLoading = ref(false);
  39. /** 页面显示和隐藏 */
  40. watch(
  41. () => props.pageVisibility,
  42. value => {
  43. if (value == 'hidden') {
  44. isLoading.value = false;
  45. }
  46. if (value == 'hidden' && props.show) {
  47. iframeRef.value?.contentWindow?.postMessage(
  48. { api: 'setPlayState' },
  49. '*'
  50. );
  51. }
  52. }
  53. );
  54. // 是否显示当前曲谱
  55. watch(
  56. () => props.show,
  57. val => {
  58. if (!val) {
  59. iframeRef.value?.contentWindow?.postMessage(
  60. { api: 'setPlayState' },
  61. '*'
  62. );
  63. }
  64. }
  65. );
  66. const iframeRef = ref();
  67. const isLoaded = ref(false);
  68. const renderError = ref(false);
  69. const renderSuccess = ref(false);
  70. const showVip = ref(false);
  71. const Authorization = storage.get(ACCESS_TOKEN);
  72. // const origin = /(localhost|192)/.test(location.host)
  73. // ? 'https://test.lexiaoya.cn'
  74. // : location.origin;
  75. let src = qs.stringifyUrl({
  76. url: vaildMusicScoreUrl() + '/instrument/',
  77. query: {
  78. id: props.music.content,
  79. modelType: 'practise',
  80. Authorization: Authorization,
  81. showGuide: true,
  82. showWebGuide: false,
  83. showCourseMember: true,
  84. iscurseplay: 'play'
  85. }
  86. });
  87. const checkView = () => {
  88. fetch(src)
  89. .then(() => {
  90. renderSuccess.value = true;
  91. renderError.value = false;
  92. })
  93. .catch(err => {
  94. renderError.value = true;
  95. });
  96. };
  97. watch(props.music, () => {
  98. if (renderSuccess.value) return;
  99. renderError.value = false;
  100. if (props.music.display) {
  101. checkView();
  102. }
  103. });
  104. // 去云练习完整版
  105. const gotoAccomany = () => {
  106. // if (!state.user.data?.vipMember) {
  107. // // showVip.value = true;
  108. // return;
  109. // }
  110. if (isLoading.value) return;
  111. if (!browserInfo.ios) {
  112. isLoading.value = true;
  113. }
  114. const Authorization = storage.get(ACCESS_TOKEN);
  115. // const origin = /(localhost|192)/.test(location.host)
  116. // ? 'https://test.lexiaoya.cn'
  117. // : location.origin;
  118. let src = qs.stringifyUrl({
  119. url: vaildMusicScoreUrl() + '/instrument/',
  120. query: {
  121. id: props.music.content,
  122. Authorization: Authorization,
  123. showGuide: true
  124. }
  125. });
  126. postMessage(
  127. {
  128. api: 'openAccompanyWebView',
  129. content: {
  130. url: src,
  131. orientation: 0,
  132. isHideTitle: true,
  133. statusBarTextColor: false,
  134. isOpenLight: true,
  135. c_orientation: 0
  136. }
  137. },
  138. () => {
  139. if (browserInfo.ios) {
  140. isLoading.value = true;
  141. }
  142. }
  143. );
  144. };
  145. const getUserInfo = async () => {
  146. const res = await request.get('/edu-app/user/getUserInfo', {
  147. initRequest: true, // 初始化接口
  148. requestType: 'form',
  149. hideLoading: true
  150. });
  151. if (res?.code === 200) {
  152. state.user.data.vipMember = res.data.vipMember;
  153. }
  154. };
  155. listenerMessage('webViewOnResume', () => {
  156. isLoading.value = false;
  157. getUserInfo();
  158. });
  159. return () => (
  160. <div class={styles.musicScore}>
  161. <iframe
  162. ref={iframeRef}
  163. onLoad={(e: Event) => {
  164. emit('setIframe', iframeRef.value);
  165. isLoaded.value = true;
  166. }}
  167. class={[styles.container, 'musicIframe']}
  168. frameborder="0"
  169. src={src}></iframe>
  170. {isLoaded.value && (
  171. <div
  172. style={{
  173. display:
  174. props.activeModel || !state.user.data?.vipMember ? '' : 'none'
  175. }}
  176. class={styles.startBtn}
  177. onClick={(e: Event) => {
  178. e.stopPropagation();
  179. gotoAccomany();
  180. }}>
  181. <img src={iconStart} />
  182. </div>
  183. )}
  184. <div class={styles.skeletonWrap}>
  185. <Skeleton class={styles.skeleton} row={8} />
  186. </div>
  187. <Popup
  188. teleport="body"
  189. class="popup-custom van-scale"
  190. transition="van-scale"
  191. closeOnClickOverlay={false}
  192. v-model:show={showVip.value}>
  193. <TheVip
  194. onClose={val => {
  195. if (val) {
  196. postMessage({
  197. api: 'openWebView',
  198. content: {
  199. url: `${location.origin}${location.pathname}#/member-center`,
  200. orientation: 1
  201. }
  202. });
  203. }
  204. showVip.value = false;
  205. }}
  206. />
  207. </Popup>
  208. </div>
  209. );
  210. }
  211. });