index.tsx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. import {
  2. TransitionGroup,
  3. computed,
  4. defineComponent,
  5. nextTick,
  6. onMounted,
  7. reactive,
  8. ref,
  9. watch
  10. } from 'vue';
  11. import styles from './index.module.less';
  12. import MSearch from '@/components/m-search';
  13. // import icon_play from '@/common/images/icon_play.svg';
  14. import {
  15. Empty,
  16. Icon,
  17. List,
  18. Loading,
  19. NoticeBar,
  20. Popover,
  21. Popup,
  22. showLoadingToast,
  23. showToast
  24. } from 'vant';
  25. import icon_back from './image/icon_back.svg';
  26. import icon_down from '@/common/images/icon_down.svg';
  27. // import icon_jianpu from '@/common/images/icon_jianpu.svg';
  28. import icon_jianpuActive from '@/common/images/icon_jianpuActive.svg';
  29. import icons from '@/common/images/index.json';
  30. import {
  31. listenerMessage,
  32. postMessage,
  33. promisefiyPostMessage
  34. } from '@/helpers/native-message';
  35. import html2canvas from 'html2canvas';
  36. import {
  37. api_musicSheetCategoriesPage,
  38. api_musicSheetPage,
  39. api_subjectList
  40. } from './api';
  41. import { state } from '@/state';
  42. import MEmpty from '@/components/m-empty';
  43. import Coaiguide from '@/custom-plugins/guide-page/coai-guide';
  44. import TheVip from '@/components/the-vip';
  45. import request from '@/helpers/request';
  46. import { useRoute } from 'vue-router';
  47. import { addWatermark, convasToImg, imgToCanvas } from './imageFunction';
  48. import ChangeVoice from './change-voice';
  49. import { storage } from '@/helpers/storage';
  50. import { ACCESS_TOKEN } from '@/store/mutation-types';
  51. import {
  52. sortMusical,
  53. getInstrumentName,
  54. vaildMusicScoreUrl
  55. } from '@/helpers/utils';
  56. export default defineComponent({
  57. name: 'co-ai',
  58. setup() {
  59. const route = useRoute();
  60. const categorForms = reactive({
  61. page: 1,
  62. rows: 999,
  63. subjectId: state.user.data?.subjectId || '',
  64. musicTagIds: route.query.musicTagId ? [route.query.musicTagId] : []
  65. });
  66. const musicForms = reactive({
  67. page: 1,
  68. rows: 20,
  69. status: 1,
  70. keyword: '', // 关键词
  71. musicSheetCategoriesId: route.query.id as any,
  72. musicalInstrumentId: ''
  73. });
  74. const data = reactive({
  75. musicSheetCategoriesName: route.query.name as any,
  76. /** 教材Index */
  77. typeIndex: 0,
  78. /** 音乐Index */
  79. musicIndex: 0,
  80. /** 显示哪种曲谱 */
  81. showMusicImg: 'staff' as 'staff' | 'first' | 'fixed',
  82. popoverShow: false,
  83. popoverMusicShow: false,
  84. /** 教材列表 */
  85. types: [] as any[],
  86. /** 音乐列表 */
  87. musics: [] as any[],
  88. loading: true,
  89. finshed: false,
  90. showChangeVoice: false,
  91. selectMusicInstrumentIndex: 0,
  92. iframeSrc: '',
  93. searchNoticeShow: false,
  94. searchNotice: {
  95. left: '',
  96. top: '',
  97. width: '',
  98. height: ''
  99. },
  100. showVip: false,
  101. vipMember: state.user.data?.vipMember,
  102. subjectStatus: false,
  103. subjectList: [],
  104. subjectItem: {} as any, // 当前乐器,
  105. trackList: [] as any, // 可筛选的分轨信息
  106. showTransBtn: true // 是否显示转谱按钮
  107. });
  108. const downRef = ref();
  109. const showGuide = ref(false);
  110. const _actions = computed(() => {
  111. return [
  112. {
  113. value: 'staff',
  114. text: '五线谱'
  115. },
  116. {
  117. value: 'first',
  118. text: '首调'
  119. },
  120. {
  121. value: 'fixed',
  122. text: '固定调'
  123. }
  124. ].map((item, index) => {
  125. return {
  126. ...item,
  127. color:
  128. data.showMusicImg === item.value ? 'var(--van-primary-color)' : '',
  129. className: data.showMusicImg === item.value ? 'fontBlod' : ''
  130. };
  131. });
  132. });
  133. const _types = computed(() => {
  134. return data.types.map((item: any) => {
  135. return {
  136. ...item,
  137. color:
  138. musicForms.musicSheetCategoriesId == item.value
  139. ? 'var(--van-primary-color)'
  140. : '',
  141. className:
  142. musicForms.musicSheetCategoriesId == item.value ? 'fontBlod' : ''
  143. };
  144. });
  145. });
  146. // 返回
  147. const goback = () => {
  148. postMessage({ api: 'goBack' });
  149. };
  150. /** 去云教练 */
  151. const handleGoto = () => {
  152. if (!data.vipMember) {
  153. data.showVip = true;
  154. return;
  155. }
  156. // 默认进页面显示对应的曲谱
  157. let lineType = 'staff';
  158. if (data.showMusicImg === 'first') {
  159. lineType = 'firstTone';
  160. } else if (data.showMusicImg === 'fixed') {
  161. lineType = 'fixedTone';
  162. } else if (data.showMusicImg === 'staff') {
  163. lineType = 'staff';
  164. }
  165. let src = `${vaildMusicScoreUrl()}/instrument?id=${
  166. data.musics[data.musicIndex]?.id
  167. }&musicRenderType=${lineType}&showGuide=true&part-index=${
  168. data.selectMusicInstrumentIndex
  169. }`;
  170. postMessage({
  171. api: 'openAccompanyWebView',
  172. content: {
  173. url: src,
  174. orientation: 0,
  175. isHideTitle: true,
  176. statusBarTextColor: false,
  177. isOpenLight: true,
  178. c_orientation: 0 // 0 横屏 1 竖屏
  179. }
  180. });
  181. };
  182. /** 保存图片 */
  183. const handleSave = async () => {
  184. showLoadingToast({ message: '正在保存', duration: 0 });
  185. try {
  186. html2canvas(downRef.value, {
  187. backgroundColor: '#fff',
  188. allowTaint: true,
  189. useCORS: true
  190. })
  191. .then(async canvas => {
  192. // 添加水印
  193. const waterCanvasImg = await addWatermark(canvas);
  194. // canvas转图片
  195. const dataURL = await convasToImg(waterCanvasImg);
  196. console.log(dataURL, 'dataURL');
  197. setTimeout(() => {
  198. showToast('已保存到相册');
  199. }, 500);
  200. await promisefiyPostMessage({
  201. api: 'savePicture',
  202. content: {
  203. base64: dataURL
  204. }
  205. });
  206. })
  207. .catch(() => {
  208. setTimeout(() => {
  209. showToast('保存失败');
  210. }, 500);
  211. });
  212. } catch (error) {
  213. setTimeout(() => {
  214. showToast('保存失败');
  215. }, 500);
  216. }
  217. };
  218. /** 获取音乐教材列表 */
  219. const getMusicSheetCategories = async () => {
  220. try {
  221. const res = await api_musicSheetCategoriesPage({
  222. ...categorForms
  223. });
  224. if (res.code === 200 && Array.isArray(res?.data?.rows)) {
  225. const temp: any = [];
  226. res.data.rows.forEach((item: any) => {
  227. temp.push({
  228. value: item.id,
  229. text: item.name
  230. });
  231. });
  232. data.types = temp;
  233. }
  234. } catch (error) {
  235. console.log('🚀 ~ error:', error);
  236. }
  237. };
  238. /** 获取曲谱列表 */
  239. const getMusicList = async () => {
  240. data.loading = true;
  241. try {
  242. const res = await api_musicSheetPage({
  243. ...musicForms,
  244. musicalInstrumentId: data.subjectItem.value || null
  245. });
  246. if (res.code === 200) {
  247. if (Array.isArray(res?.data?.rows)) {
  248. data.musics = [...data.musics, ...res.data.rows];
  249. data.finshed = !res.data.next;
  250. } else {
  251. data.finshed = true;
  252. }
  253. } else showGuide.value = true;
  254. } catch (error) {
  255. console.log('🚀 ~ error:', error);
  256. }
  257. data.loading = false;
  258. };
  259. const handleReset = () => {
  260. musicForms.page = 1;
  261. data.musics = [];
  262. getMusicList();
  263. };
  264. const spinRef = ref();
  265. const handleResh = () => {
  266. if (data.loading || data.finshed) return;
  267. musicForms.page = musicForms.page + 1;
  268. getMusicList();
  269. };
  270. const musicIframeLoad = () => {
  271. const token = storage.get(ACCESS_TOKEN);
  272. const details = data.musics[data.musicIndex];
  273. // 如果在配置里面匹配不到,则默认显示五线谱
  274. const musicRenderType =
  275. data.showMusicImg === 'first'
  276. ? 'firstTone'
  277. : data.showMusicImg === 'fixed'
  278. ? 'fixedTone'
  279. : data.showMusicImg === 'staff'
  280. ? 'staff'
  281. : 'staff';
  282. const origin = /(localhost|192)/.test(location.host)
  283. ? 'https://test.lexiaoya.cn'
  284. : location.origin;
  285. // data.iframeSrc = `${origin}/instrument/?id=${details.id}&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${data.selectMusicInstrumentIndex}&musicRenderType=${musicRenderType}`;
  286. data.iframeSrc = `${vaildMusicScoreUrl()}/instrument/?id=${
  287. details.id
  288. }&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${
  289. data.selectMusicInstrumentIndex
  290. }&musicRenderType=${musicRenderType}`;
  291. };
  292. const setSearchBox = () => {
  293. const el = document.querySelector('.searchNotice .van-field__control');
  294. if (el) {
  295. const rect = el.getBoundingClientRect();
  296. data.searchNotice.left = rect.x + 'px';
  297. data.searchNotice.top = rect.y + 'px';
  298. data.searchNotice.width = rect.width + 'px';
  299. data.searchNotice.height = rect.height + 'px';
  300. }
  301. };
  302. const isEnsemble = computed(() => {
  303. const musics = data.musics[data.musicIndex]?.musicalInstruments;
  304. if (musics && musics.length) {
  305. let list: any = [];
  306. const arr = musics.forEach((item: any) => {
  307. list.push({ name: item.name, code: item.code });
  308. });
  309. }
  310. if (musics && musics.length > 1) {
  311. return true;
  312. } else {
  313. return false;
  314. }
  315. });
  316. const getSubjecList = async () => {
  317. try {
  318. let subjectIds = state.user.data?.subjectId || '';
  319. subjectIds = subjectIds.split(',');
  320. const subjectId = subjectIds[0] || '';
  321. const res = await api_subjectList({
  322. enableFlag: true,
  323. delFlag: 0,
  324. page: 1,
  325. subjectId: subjectId || '',
  326. rows: 999
  327. });
  328. if (subjectId) {
  329. const result = res.data || [];
  330. let tempSubjects: any = [];
  331. result.forEach((item: any) => {
  332. const instruments = item.instruments || [];
  333. if (Number(subjectId) === item.id && instruments.length > 0) {
  334. instruments.forEach((child: any, index: number) => {
  335. tempSubjects.push({
  336. text: child.name,
  337. value: child.id,
  338. className: index === 0 ? 'selected' : ''
  339. });
  340. });
  341. }
  342. });
  343. data.subjectList = tempSubjects;
  344. if (tempSubjects.length > 0) {
  345. data.subjectItem = tempSubjects[0];
  346. }
  347. }
  348. } catch {
  349. //
  350. }
  351. };
  352. // 解析xml,获取分轨信息
  353. const analyzeXml = async () => {
  354. const details = data.musics[data.musicIndex];
  355. if (details?.musicalInstruments?.length > 1) {
  356. if (details.xmlFileUrl) {
  357. const res = await fetch(details.xmlFileUrl).then(response =>
  358. response.text()
  359. );
  360. filterTracks(res);
  361. }
  362. } else {
  363. // showMusicImg: 'first' as 'staff' | 'first' | 'fixed',
  364. const { defaultScore, transferFlag } =
  365. details.musicalInstruments[0] || {};
  366. let musicImgType: 'staff' | 'first' | 'fixed' = 'staff';
  367. musicImgType =
  368. defaultScore === 'STAVE'
  369. ? 'staff'
  370. : defaultScore === 'JIAN'
  371. ? 'fixed'
  372. : defaultScore === 'FIRST'
  373. ? 'first'
  374. : 'staff';
  375. data.showMusicImg = musicImgType;
  376. data.showTransBtn = transferFlag;
  377. }
  378. };
  379. // 过滤出能切换的分轨
  380. const filterTracks = (xml: any) => {
  381. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml');
  382. const partList =
  383. xmlParse
  384. .getElementsByTagName('part-list')?.[0]
  385. ?.getElementsByTagName('score-part') || [];
  386. const partListNames = Array.from(partList).map(
  387. item =>
  388. item.getElementsByTagName('part-name')?.[0]?.textContent?.trim() || ''
  389. );
  390. const parts: any = xmlParse.getElementsByTagName('part');
  391. /** 第一分谱如果是约定的配置分谱则跳过 */
  392. if (partListNames[0]?.toLocaleUpperCase?.() === 'COMMON') {
  393. partListNames.shift();
  394. }
  395. // 根据后台已选择的分轨筛选出能切换的声轨
  396. const multiTracksSelection =
  397. data.musics[data.musicIndex]?.multiTracksSelection;
  398. const canSelectTracks = multiTracksSelection
  399. ? multiTracksSelection?.split(',')
  400. : [];
  401. console.log(canSelectTracks, partListNames);
  402. const arr = partListNames
  403. .map((item: any, index: number) => {
  404. // 该声轨能否被选
  405. const canselect =
  406. canSelectTracks.length == 0 || canSelectTracks.includes(item)
  407. ? true
  408. : false;
  409. // console.log(canselect,index)
  410. const instrumentName = getInstrumentName(item);
  411. const sortId = sortMusical(instrumentName, index);
  412. return {
  413. text: item + (instrumentName ? `(${instrumentName})` : ''),
  414. value: index,
  415. sortId,
  416. canselect,
  417. track: item
  418. };
  419. })
  420. .filter((item: any) => item.canselect)
  421. .sort((a: any, b: any) => a.sortId - b.sortId);
  422. data.trackList = arr;
  423. let track = arr.find(
  424. (item: any) => item.value === data.selectMusicInstrumentIndex
  425. )?.track;
  426. track = track
  427. .replace(/[0-9]+/g, '')
  428. .replace(/\s/g, '')
  429. .toLocaleLowerCase();
  430. // 如果在配置里面匹配不到,则默认显示五线谱
  431. let musicRenderType: 'staff' | 'first' | 'fixed' = 'staff';
  432. let canTrans = true;
  433. data.musics[data.musicIndex]?.musicalInstruments.forEach((item: any) => {
  434. if (item.code.toLocaleLowerCase() === track) {
  435. musicRenderType =
  436. item.defaultScore === 'STAVE'
  437. ? 'staff'
  438. : item.defaultScore === 'JIAN'
  439. ? 'fixed'
  440. : item.defaultScore === 'FIRST'
  441. ? 'first'
  442. : 'first';
  443. canTrans = item.transferFlag;
  444. }
  445. });
  446. data.showTransBtn = canTrans;
  447. data.showMusicImg = musicRenderType;
  448. };
  449. watch(
  450. () => data.musicIndex,
  451. async () => {
  452. data.selectMusicInstrumentIndex = 0;
  453. analyzeXml();
  454. }
  455. );
  456. onMounted(async () => {
  457. // 安卓的状态栏
  458. postMessage({
  459. api: 'setStatusBarVisibility',
  460. content: {
  461. isVisibility: 0
  462. }
  463. });
  464. await getSubjecList();
  465. await getMusicSheetCategories();
  466. await getMusicList();
  467. const obv = new IntersectionObserver(entries => {
  468. if (entries[0].intersectionRatio > 0) {
  469. handleResh();
  470. }
  471. });
  472. nextTick(() => {
  473. spinRef.value && obv.observe(spinRef.value);
  474. });
  475. const getUserInfo = async () => {
  476. const res = await request.get('/edu-app/user/getUserInfo', {
  477. initRequest: true, // 初始化接口
  478. requestType: 'form',
  479. hideLoading: true
  480. });
  481. if (res?.code === 200) {
  482. data.vipMember = res.data.vipMember;
  483. }
  484. };
  485. analyzeXml();
  486. listenerMessage('webViewOnResume', () => {
  487. console.log('页面显示');
  488. getUserInfo();
  489. data.typeIndex = 0;
  490. data.musicIndex = 0;
  491. handleReset();
  492. });
  493. setSearchBox();
  494. });
  495. return () => (
  496. <div class={styles.container}>
  497. <div class={styles.back} onClick={goback}>
  498. <img src={icon_back} />
  499. </div>
  500. <div class={styles.musicCFixed}>
  501. <Popover
  502. v-model:show={data.popoverMusicShow}
  503. class={styles.popoverMusic}
  504. actions={_types.value}
  505. placement="bottom"
  506. showArrow={false}
  507. onSelect={(item: any) => {
  508. // data.showMusicImg = item.value;
  509. if (item.value == musicForms.musicSheetCategoriesId) {
  510. return;
  511. }
  512. data.musics = [];
  513. musicForms.musicSheetCategoriesId = item.value;
  514. data.musicSheetCategoriesName = item.text;
  515. data.popoverMusicShow = false;
  516. getMusicList();
  517. }}>
  518. {{
  519. reference: () => (
  520. <span class={styles.musicName}>
  521. {data.musicSheetCategoriesName}
  522. <Icon name="arrow-down"></Icon>
  523. </span>
  524. )
  525. }}
  526. </Popover>
  527. </div>
  528. <div class={styles.content}>
  529. <div class={[styles.leftContent]}>
  530. <div class={styles.leftBg2}></div>
  531. <div class={styles.center}>
  532. <div class={styles.centerSearch}>
  533. <div id="coai-0">
  534. <MSearch
  535. class={[
  536. 'searchNotice',
  537. data.searchNoticeShow ? styles.searchNoticeShow : ''
  538. ]}
  539. shape="round"
  540. // background="transparent"
  541. clearable={false}
  542. placeholder="请输入关键字"
  543. modelValue={musicForms.keyword}
  544. onFocus={() => (data.searchNoticeShow = false)}
  545. onBlur={val => {
  546. musicForms.keyword = val?.trim() || '';
  547. requestAnimationFrame(() => {
  548. requestAnimationFrame(() => {
  549. if (musicForms.keyword) {
  550. data.searchNoticeShow = true;
  551. }
  552. });
  553. });
  554. }}
  555. onSearch={val => {
  556. if (!data.loading) {
  557. musicForms.keyword = val;
  558. handleReset();
  559. }
  560. }}>
  561. {{
  562. left: () =>
  563. data.subjectItem.value &&
  564. data.subjectList.length > 1 && (
  565. <div class={styles.subjects}>
  566. <Popover
  567. v-model:show={data.subjectStatus}
  568. offset={[0, 18]}
  569. actions={data.subjectList}
  570. placement="bottom-start"
  571. class={styles.subjectListContainer}
  572. onSelect={(item: any) => {
  573. data.subjectList.forEach((c: any) => {
  574. c.className = '';
  575. });
  576. data.subjectItem = {
  577. ...item,
  578. className: 'selected'
  579. };
  580. handleReset();
  581. }}>
  582. {{
  583. reference: () => (
  584. <div
  585. class={[
  586. styles.subjectName,
  587. data.subjectStatus && styles.active
  588. ]}>
  589. <span>{data.subjectItem.text}</span> <i></i>
  590. </div>
  591. )
  592. }}
  593. </Popover>
  594. </div>
  595. )
  596. }}
  597. </MSearch>
  598. </div>
  599. </div>
  600. <div class={styles.musicContent}>
  601. {data.musics.map((item: any, index: number) => {
  602. return (
  603. <div
  604. class={[
  605. styles.musicItem,
  606. data.musicIndex === index
  607. ? styles.musicActive
  608. : styles.disableNotic
  609. ]}
  610. onClick={() => {
  611. data.musicIndex = index;
  612. musicIframeLoad();
  613. }}>
  614. <img
  615. class={styles.musicAvtor}
  616. src={item.titleImg}
  617. onLoad={(e: Event) => {
  618. const el = e.target as HTMLImageElement;
  619. el.setAttribute('loaded', 'true');
  620. }}
  621. />
  622. <div class={styles.musicInfo}>
  623. <div class={styles.musicName}>
  624. <NoticeBar
  625. text={item.musicSheetName}
  626. class={styles.noticeBar}
  627. background="none"
  628. />
  629. </div>
  630. <div class={styles.musicDes}>
  631. <div class={styles.musicFavitor}>{item.usedNum}</div>
  632. <div class={[styles.musicAuthor, 'van-ellipsis']}>
  633. {item.composer || '佚名'}
  634. </div>
  635. </div>
  636. </div>
  637. {/* <img class={[styles.musicIcon]} src={icon_play} /> */}
  638. </div>
  639. );
  640. })}
  641. {!data.finshed && (
  642. <div ref={spinRef} class={styles.loadingWrap}>
  643. <Loading color="#259CFE" />
  644. </div>
  645. )}
  646. {!data.loading && data.musics.length === 0 && (
  647. <div class={styles.empty}>
  648. <MEmpty description="暂无曲谱" />
  649. </div>
  650. )}
  651. </div>
  652. </div>
  653. </div>
  654. <div class={[styles.opacityBg, styles.right]}>
  655. <div class={styles.rightBox}>
  656. {isEnsemble.value && (
  657. <div
  658. class={styles.iconTransfer}
  659. onClick={() => (data.showChangeVoice = true)}>
  660. 切换声轨
  661. </div>
  662. )}
  663. <div ref={downRef}>
  664. <div class={styles['right-musicName']}>
  665. {data.musics[data.musicIndex]?.musicSheetName}
  666. </div>
  667. {/* ensembleDetail */}
  668. {isEnsemble.value ? (
  669. <div>
  670. <>
  671. {/* {loading.value && (
  672. <div>
  673. <Vue3Lottie
  674. animationData={AstronautJSON}
  675. class={styles.finch}></Vue3Lottie>
  676. <p class={styles.finchLoad}>加载中...</p>
  677. </div>
  678. )} */}
  679. <iframe
  680. id="staffIframeRef"
  681. style={{
  682. width: '100%'
  683. // opacity: loading.value ? 0 : 1
  684. }}
  685. src={data.iframeSrc}
  686. onLoad={musicIframeLoad}></iframe>
  687. {/* <OsmdPreview ref={osmdPreviewRef} /> */}
  688. </>
  689. </div>
  690. ) : (
  691. <>
  692. {data.showMusicImg === 'first' ? (
  693. <>
  694. {data.musics[data.musicIndex]?.musicFirstImg
  695. ?.split(',')
  696. .map((item: any, index: number) => {
  697. return (
  698. <img
  699. class={styles.staff}
  700. src={item + '?v=' + Date.now()}
  701. key={item}
  702. crossorigin="anonymous"
  703. />
  704. );
  705. })}
  706. </>
  707. ) : data.showMusicImg === 'fixed' ? (
  708. <>
  709. <TransitionGroup name="van-fade">
  710. {data.musics[data.musicIndex]?.musicJianImg
  711. ?.split(',')
  712. .map((item: any, index: number) => {
  713. return (
  714. <img
  715. class={styles.staff}
  716. src={item + '?v=' + Date.now()}
  717. key={item}
  718. crossorigin="anonymous"
  719. />
  720. );
  721. })}
  722. </TransitionGroup>
  723. </>
  724. ) : (
  725. <>
  726. {data.musics[data.musicIndex]?.musicImg
  727. ?.split(',')
  728. .map((item: any, index: number) => {
  729. return (
  730. <img
  731. class={styles.staff}
  732. src={item + '?v=' + Date.now()}
  733. key={item}
  734. crossorigin="anonymous"
  735. />
  736. );
  737. })}
  738. </>
  739. )}
  740. </>
  741. )}
  742. </div>
  743. </div>
  744. <div class={styles.rightBtns}>
  745. {data.showTransBtn && (
  746. <Popover
  747. v-model:show={data.popoverShow}
  748. class={styles.popover}
  749. actions={_actions.value}
  750. placement="top-start"
  751. onSelect={(item: any) => {
  752. data.showMusicImg = item.value;
  753. data.popoverShow = false;
  754. musicIframeLoad();
  755. }}
  756. // onSelect={onSelect}
  757. >
  758. {{
  759. reference: () => <img id="coai-1" src={icon_jianpuActive} />
  760. }}
  761. </Popover>
  762. )}
  763. {!isEnsemble.value && (
  764. <img id="coai-2" src={icon_down} onClick={handleSave} />
  765. )}
  766. <div class={styles.rightBtnsRight} id="coai-3">
  767. <img src={icons.icon_start} onClick={() => handleGoto()} />
  768. </div>
  769. </div>
  770. </div>
  771. </div>
  772. {data.searchNotice.width && data.searchNoticeShow && (
  773. <div class={styles.searchNotice} style={{ ...data.searchNotice }}>
  774. <NoticeBar
  775. text={musicForms.keyword}
  776. color="#333"
  777. background="none"
  778. />
  779. </div>
  780. )}
  781. {showGuide.value && <Coaiguide></Coaiguide>}
  782. <Popup
  783. class="popup-custom van-scale"
  784. transition="van-scale"
  785. closeOnClickOverlay={false}
  786. v-model:show={data.showVip}>
  787. <TheVip
  788. onClose={val => {
  789. if (val) {
  790. postMessage({
  791. api: 'openWebView',
  792. content: {
  793. url: `${location.origin}${location.pathname}#/member-center`,
  794. orientation: 1
  795. }
  796. });
  797. }
  798. data.showVip = false;
  799. }}
  800. />
  801. </Popup>
  802. <Popup
  803. class="popup-custom van-scale"
  804. transition="van-scale"
  805. closeOnClickOverlay={false}
  806. v-model:show={data.showVip}>
  807. <TheVip
  808. onClose={val => {
  809. if (val) {
  810. postMessage({
  811. api: 'openWebView',
  812. content: {
  813. url: `${location.origin}${location.pathname}#/member-center`,
  814. orientation: 1
  815. }
  816. });
  817. }
  818. data.showVip = false;
  819. }}
  820. />
  821. </Popup>
  822. {data.showChangeVoice && (
  823. <Popup
  824. class="popup-custom van-scale"
  825. transition="van-scale"
  826. closeOnClickOverlay={false}
  827. v-model:show={data.showChangeVoice}>
  828. <ChangeVoice
  829. musicalInstruments={data.trackList || []}
  830. musicalInstrumentIndex={data.selectMusicInstrumentIndex}
  831. onClose={() => (data.showChangeVoice = false)}
  832. onConfirm={async (index: number) => {
  833. data.selectMusicInstrumentIndex = index;
  834. await analyzeXml();
  835. musicIframeLoad();
  836. data.showChangeVoice = false;
  837. }}
  838. />
  839. </Popup>
  840. )}
  841. </div>
  842. );
  843. }
  844. });