index.tsx 29 KB

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