index.tsx 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. import {
  2. Transition,
  3. TransitionGroup,
  4. computed,
  5. defineComponent,
  6. nextTick,
  7. onMounted,
  8. onUnmounted,
  9. reactive,
  10. ref,
  11. watch
  12. } from 'vue';
  13. import styles from './index.module.less';
  14. import icon_back from './images/icon_back.png';
  15. import icon_separator from './images/icon_separator.png';
  16. import {
  17. NBreadcrumb,
  18. NBreadcrumbItem,
  19. NButton,
  20. NEmpty,
  21. NImage,
  22. NModal,
  23. NPopselect,
  24. NSpace,
  25. NSpin,
  26. NPopover
  27. } from 'naive-ui';
  28. import TheSearch from '/src/components/TheSearch';
  29. import { IMusicItem } from './type';
  30. import icon_arrow from './images/icon_arrow.png';
  31. import icon_play from './images/icon_play.png';
  32. import icon_pause from './images/icon_pause.png';
  33. import icon_goXiaoku from './images/icon_goXiaoku.png';
  34. import icon_favitor from '/src/common/images/icon-collect-default.png';
  35. import icon_favitorActive from '/src/common/images/icon-collect-active.png';
  36. import icon_default from './images/icon_default.png';
  37. import icon_close from './images/icon-close.png';
  38. import icon_trans from './images/icon_trans.png';
  39. import { useRoute, useRouter } from 'vue-router';
  40. import PlayItem from './component/play-item';
  41. import PlayLoading from './component/play-loading';
  42. import TheNoticeBar from '/src/components/TheNoticeBar';
  43. import { useCatchStore } from '/src/store/modules/catchData';
  44. import {
  45. api_materialFavorite,
  46. api_materialFavoriteStatus,
  47. api_musicSheetPage,
  48. api_subjectList
  49. } from '../xiaoku-ai/api';
  50. import { useUserStore } from '/src/store/modules/users';
  51. import Musicguide from '@/custom-plugins/guide-page/music-guide';
  52. import TheEmpty from '/src/components/TheEmpty';
  53. import { state } from '/src/state';
  54. import { useResizeObserver } from '@vueuse/core';
  55. import { vaildMusicScoreUrl } from '/src/utils/urlUtils';
  56. import { getInstrumentName, sortMusical } from '/src/utils';
  57. export default defineComponent({
  58. name: 'XiaokuMusic',
  59. setup() {
  60. const catchStore = useCatchStore();
  61. const user = useUserStore();
  62. const route = useRoute();
  63. const router = useRouter();
  64. const forms = reactive({
  65. page: 1,
  66. rows: 20,
  67. status: true,
  68. name: '', // 关键词
  69. musicSheetCategoriesId: route.query.id || ''
  70. });
  71. const data = reactive({
  72. loading: false,
  73. finshed: false,
  74. reshing: false,
  75. tags: [] as any[],
  76. tagIndex: 0,
  77. list: [] as unknown as IMusicItem[],
  78. listActive: 0,
  79. musicInstrumentIndex: 0,
  80. playState: 'pause' as 'play' | 'pause',
  81. showPlayer: false,
  82. previewModal: false,
  83. showPreivew: false,
  84. previewUrl: '',
  85. showCloseBtn: true,
  86. iframeSrc: '',
  87. showMusicImg: 'staff' as 'staff' | 'first' | 'fixed', // 显示哪种曲谱
  88. trackList: [] as any, // 可筛选的分轨信息
  89. showTransBtn: true, // 是否显示转谱按钮
  90. trackName: '切换声轨' as any // 分轨名字
  91. });
  92. const showGuide = ref(false);
  93. const userStore = useUserStore();
  94. let musicsrc = '';
  95. const getSubjects = async () => {
  96. // const res = await api_subjectList();
  97. // if (Array.isArray(res?.data)) {
  98. const tempSubjectList = catchStore.getSubjectInstruments;
  99. const subjectList = sessionStorage.getItem('musicSubjectList')
  100. ? JSON.parse(sessionStorage.getItem('musicSubjectList') as any)
  101. : [];
  102. const resultList: any[] = [];
  103. tempSubjectList.forEach((item: any) => {
  104. const hasItem = subjectList.find((s: any) => s.id === item.id);
  105. if (hasItem) {
  106. resultList.push(item);
  107. }
  108. });
  109. data.tags = [
  110. { name: '全部', id: 0, value: 0, label: '全部' },
  111. ...resultList
  112. ];
  113. // }
  114. };
  115. const getList = async () => {
  116. data.loading = true;
  117. let res = {} as any;
  118. try {
  119. res = await api_musicSheetPage({
  120. ...forms,
  121. // musicSubject: data.tagIndex ? data.tagIndex : ''
  122. musicalInstrumentId: data.tagIndex ? data.tagIndex : ''
  123. });
  124. } catch (error) {
  125. console.log(error);
  126. }
  127. // console.log(res, 'data', data.reshing, 'musicSubject');
  128. if (data.reshing) {
  129. data.list = [];
  130. data.reshing = false;
  131. }
  132. if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
  133. data.list = [...data.list, ...res.data.rows];
  134. data.finshed = res.data.rows.length < forms.rows;
  135. }
  136. if (data.list[data.listActive]) {
  137. getFavitor(data.list[data.listActive]);
  138. }
  139. data.loading = false;
  140. setTimeout(() => {
  141. showGuide.value = true;
  142. }, 500);
  143. };
  144. const handleGetList = () => {
  145. data.listActive = 0;
  146. data.showPlayer = false;
  147. data.playState = 'pause';
  148. forms.page = 1;
  149. data.finshed = false;
  150. getList();
  151. };
  152. const spinRef = ref();
  153. const handleResh = () => {
  154. if (data.loading || data.finshed) return;
  155. forms.page = forms.page + 1;
  156. getList();
  157. };
  158. // ifram事件处理
  159. const iframeHandle = (ev: MessageEvent) => {
  160. if (ev.data?.api === 'api_fingerPreView') {
  161. data.showCloseBtn = !ev.data.state;
  162. }
  163. };
  164. onMounted(async () => {
  165. // 获取声部列表
  166. await catchStore.getSubjects();
  167. // musicList-container
  168. useResizeObserver(
  169. document.querySelector('.musicList-container') as HTMLElement,
  170. (entries: any) => {
  171. const entry = entries[0];
  172. const { height } = entry.contentRect;
  173. // console.log(height, 'height - 11');
  174. document.documentElement.style.setProperty(
  175. '--xiaoku-music-height',
  176. height + 'px'
  177. );
  178. }
  179. );
  180. getSubjects();
  181. await getList();
  182. const obv = new IntersectionObserver(entries => {
  183. if (entries[0].intersectionRatio > 0) {
  184. handleResh();
  185. }
  186. });
  187. obv.observe(spinRef.value);
  188. analyzeXml();
  189. window.addEventListener('message', iframeHandle);
  190. });
  191. onUnmounted(() => {
  192. window.removeEventListener('message', iframeHandle);
  193. });
  194. /** 查看收藏状态 */
  195. const getFavitor = async (item: any) => {
  196. const res = await api_materialFavoriteStatus({
  197. type: 'MUSIC',
  198. materialId: item.id
  199. });
  200. if (res?.code === 200) {
  201. item.favitor = res.data;
  202. }
  203. };
  204. /** 改变模仿的曲谱 */
  205. const handleChange = (item: IMusicItem) => {
  206. const index = data.list.findIndex(_item => _item.id === item.id);
  207. if (index > -1) {
  208. data.listActive = index;
  209. }
  210. getFavitor(item);
  211. };
  212. const selectChildObj = (item: any) => {
  213. const obj: any = {};
  214. item?.forEach((child: any) => {
  215. if (child.id === data.tagIndex) {
  216. obj.selected = true;
  217. obj.name = child.name;
  218. }
  219. });
  220. return obj;
  221. };
  222. /** 选中的item */
  223. const activeItem = computed(() => {
  224. if (data.list[data.listActive]) {
  225. // const origin = /(localhost|192)/.test(location.host)
  226. // ? 'https://dev.kt.colexiu.com'
  227. // : location.origin;
  228. // console.log(
  229. // data.list[data.listActive].xmlFileUrl,
  230. // 'data.list[data.listActive]'
  231. // );
  232. musicsrc = `${vaildMusicScoreUrl()}/instrument?modelType=practise&id=${
  233. data.list[data.listActive].xmlFileUrl
  234. }&Authorization=${userStore.getToken}/#/preview`;
  235. } else {
  236. musicsrc = '';
  237. }
  238. return data.list[data.listActive] || {};
  239. });
  240. /** 收藏曲谱 */
  241. const handleFavitor = () => {
  242. data.list[data.listActive].favitor = !data.list[data.listActive].favitor;
  243. api_materialFavorite({
  244. favoriteFlag: data.list[data.listActive].favitor,
  245. type: 'MUSIC',
  246. materialId: data.list[data.listActive].id
  247. });
  248. };
  249. /** 播放曲目 */
  250. const handlePlay = (item: IMusicItem) => {
  251. const index = data.list.findIndex(_item => _item.id === item.id);
  252. if (index > -1) {
  253. if (data.listActive === index) {
  254. data.playState = data.playState === 'play' ? 'pause' : 'play';
  255. } else {
  256. data.playState = 'play';
  257. }
  258. data.showPlayer = true;
  259. data.listActive = index;
  260. }
  261. };
  262. const musicalInstruments = computed(() => {
  263. const details: any = data.list[data.listActive];
  264. const musics = details?.musicalInstruments || [];
  265. const temp: any = [];
  266. musics.forEach((item: any, index: number) => {
  267. temp.push({
  268. label: item.name,
  269. value: index
  270. });
  271. });
  272. return temp;
  273. });
  274. const isEnsemble = computed(() => {
  275. const details: any = data.list[data.listActive];
  276. const musics: any = details?.musicalInstruments;
  277. if (musics && musics.length > 1) {
  278. return true;
  279. } else {
  280. return false;
  281. }
  282. });
  283. const musicIframeLoad = () => {
  284. const token = userStore.getToken;
  285. const details = data.list[data.listActive];
  286. // const origin = /(localhost|192)/.test(location.host)
  287. // ? 'https://test.lexiaoya.cn'
  288. // : location.origin;
  289. // console.log(
  290. // origin,
  291. // 'origin',
  292. // `${origin}/instrument/?id=${details.id}&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${data.musicInstrumentIndex}`
  293. // );
  294. const musicRenderType =
  295. data.showMusicImg === 'first'
  296. ? 'firstTone'
  297. : data.showMusicImg === 'fixed'
  298. ? 'fixedTone'
  299. : data.showMusicImg === 'staff'
  300. ? 'staff'
  301. : 'firstTone';
  302. data.iframeSrc = `${vaildMusicScoreUrl()}/instrument/?id=${
  303. details.id
  304. }&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${
  305. data.musicInstrumentIndex
  306. }&musicRenderType=${musicRenderType}`;
  307. };
  308. /** 音频控制 */
  309. const handleChangeAudio = (
  310. type: 'play' | 'pause' | 'pre' | 'next' | 'favitor'
  311. ) => {
  312. if (type === 'play') {
  313. data.playState = 'play';
  314. } else if (type === 'pause') {
  315. data.playState = 'pause';
  316. } else if (type === 'pre') {
  317. if (data.list[data.listActive - 1]) {
  318. handlePlay(data.list[data.listActive - 1]);
  319. }
  320. } else if (type === 'next') {
  321. if (data.list[data.listActive + 1]) {
  322. handlePlay(data.list[data.listActive + 1]);
  323. }
  324. } else if (type === 'favitor') {
  325. handleFavitor();
  326. }
  327. };
  328. const _actions = [
  329. {
  330. value: 'staff',
  331. label: '五线谱'
  332. },
  333. {
  334. value: 'first',
  335. label: '首调'
  336. },
  337. {
  338. value: 'fixed',
  339. label: '固定调'
  340. }
  341. ];
  342. // 解析xml,获取分轨信息
  343. const analyzeXml = async () => {
  344. const details: any = data.list[data.listActive];
  345. if (details.musicalInstruments?.length > 1) {
  346. if (details.xmlFileUrl) {
  347. const res = await fetch(details.xmlFileUrl).then(response =>
  348. response.text()
  349. );
  350. filterTracks(res);
  351. }
  352. } else {
  353. // showMusicImg: 'first' as 'staff' | 'first' | 'fixed',
  354. const { defaultScore, transferFlag } =
  355. details.musicalInstruments[0] || {};
  356. let musicImgType: 'staff' | 'first' | 'fixed' = 'staff';
  357. musicImgType =
  358. defaultScore === 'STAVE'
  359. ? 'staff'
  360. : defaultScore === 'JIAN'
  361. ? 'fixed'
  362. : defaultScore === 'FIRST'
  363. ? 'first'
  364. : 'staff';
  365. data.showMusicImg = musicImgType;
  366. data.showTransBtn = transferFlag;
  367. }
  368. };
  369. // 过滤出能切换的分轨
  370. const filterTracks = (xml: any) => {
  371. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml');
  372. const partList =
  373. xmlParse
  374. .getElementsByTagName('part-list')?.[0]
  375. ?.getElementsByTagName('score-part') || [];
  376. const partListNames = Array.from(partList).map(
  377. item =>
  378. item.getElementsByTagName('part-name')?.[0]?.textContent?.trim() || ''
  379. );
  380. const parts: any = xmlParse.getElementsByTagName('part');
  381. /** 第一分谱如果是约定的配置分谱则跳过 */
  382. if (partListNames[0]?.toLocaleUpperCase?.() === 'COMMON') {
  383. partListNames.shift();
  384. }
  385. // 根据后台已选择的分轨筛选出能切换的声轨
  386. const multiTracksSelection: any =
  387. data.list[data.listActive]?.multiTracksSelection;
  388. const canSelectTracks = multiTracksSelection
  389. ? multiTracksSelection?.split(',')
  390. : [];
  391. const arr = partListNames
  392. .map((item: any, index: number) => {
  393. // 该声轨能否被选
  394. const canselect =
  395. canSelectTracks.length == 0 || canSelectTracks.includes(item)
  396. ? true
  397. : false;
  398. // console.log(canselect,index)
  399. const instrumentName = getInstrumentName(item);
  400. const sortId = sortMusical(instrumentName, index);
  401. return {
  402. label: item + (instrumentName ? `(${instrumentName})` : ''),
  403. value: index,
  404. sortId,
  405. canselect,
  406. track: item
  407. };
  408. })
  409. .filter((item: any) => item.canselect)
  410. .sort((a: any, b: any) => a.sortId - b.sortId);
  411. data.trackList = arr;
  412. let track = arr.find(
  413. (item: any) => item.value === data.musicInstrumentIndex
  414. )?.track;
  415. track = track
  416. .replace(/[0-9]+/g, '')
  417. .replace(/\s/g, '')
  418. .toLocaleLowerCase();
  419. let musicRenderType: 'staff' | 'first' | 'fixed' = 'first';
  420. let canTrans = true;
  421. data.list[data.listActive]?.musicalInstruments.forEach((item: any) => {
  422. if (item.code.toLocaleLowerCase() === track) {
  423. musicRenderType =
  424. item.defaultScore === 'STAVE'
  425. ? 'staff'
  426. : item.defaultScore === 'JIAN'
  427. ? 'fixed'
  428. : item.defaultScore === 'FIRST'
  429. ? 'first'
  430. : 'first';
  431. canTrans = item.transferFlag;
  432. }
  433. });
  434. data.showTransBtn = canTrans;
  435. data.showMusicImg = musicRenderType;
  436. };
  437. watch(
  438. () => data.listActive,
  439. async () => {
  440. data.musicInstrumentIndex = 0;
  441. analyzeXml();
  442. }
  443. );
  444. watch(
  445. () => data.musicInstrumentIndex,
  446. async () => {
  447. data.trackName =
  448. data.trackList.find(
  449. (item: any) => item.value === data.musicInstrumentIndex
  450. )?.label || '切换声轨';
  451. musicIframeLoad();
  452. }
  453. );
  454. // 合奏曲谱转换时,更新曲谱信息
  455. watch(
  456. () => data.showMusicImg,
  457. () => {
  458. if (isEnsemble.value) {
  459. musicIframeLoad();
  460. }
  461. }
  462. );
  463. const musicImg = computed(() => {
  464. let imgs: any = [];
  465. if (data.showMusicImg === 'first') {
  466. const img = activeItem.value?.musicFirstImg;
  467. imgs = img ? img.split(',') : [];
  468. } else if (data.showMusicImg === 'fixed') {
  469. const img = activeItem.value?.musicJianImg;
  470. imgs = img ? img.split(',') : [];
  471. } else if (data.showMusicImg === 'staff') {
  472. const img = activeItem.value?.musicImg || activeItem.value?.musicSvg;
  473. imgs = img ? img.split(',') : [];
  474. }
  475. return imgs;
  476. });
  477. return () => (
  478. <div class={styles.container}>
  479. <NSpace align="center" wrapItem={false} size={16}>
  480. <img
  481. style={{ cursor: 'pointer' }}
  482. src={icon_back}
  483. class={styles.iconBack}
  484. onClick={() => router.push({ path: '/xiaoku-ai' })}
  485. />
  486. <NBreadcrumb separator="">
  487. <NBreadcrumbItem
  488. onClick={() => router.push({ path: '/xiaoku-ai' })}>
  489. 全部列表
  490. </NBreadcrumbItem>
  491. <img class={styles.separator} src={icon_separator} />
  492. <NBreadcrumbItem>{route.query.name}</NBreadcrumbItem>
  493. </NBreadcrumb>
  494. </NSpace>
  495. <div class={[styles.wrap, data.showPlayer ? styles.wrapBottom : '']}>
  496. <div class={styles.content}>
  497. <div class={styles.tools}>
  498. <NSpace
  499. style={{ width: '100%' }}
  500. size={[24, 12]}
  501. wrapItem={false}>
  502. <div
  503. {...{
  504. id: 'music-0'
  505. }}>
  506. <NSpace
  507. style={{ width: '100%' }}
  508. size={[24, 12]}
  509. wrapItem={false}>
  510. {data.tags.map(item =>
  511. item.instruments && item.instruments.length > 1 ? (
  512. <NPopselect
  513. options={item.instruments}
  514. trigger="hover"
  515. v-model:value={data.tagIndex}
  516. onUpdate:value={() => {
  517. // onSearch();
  518. data.reshing = true;
  519. document
  520. .querySelector('.musicList-container')
  521. .scroll(0, 0);
  522. handleGetList();
  523. }}
  524. key={item.value}
  525. class={[styles.popSelect1]}>
  526. <NButton
  527. round
  528. textColor={
  529. selectChildObj(item.instruments).selected
  530. ? '#fff'
  531. : '#000'
  532. }
  533. color={
  534. selectChildObj(item.instruments).selected
  535. ? '#198CFE'
  536. : '#fff'
  537. }
  538. type={
  539. selectChildObj(item.instruments).selected
  540. ? 'primary'
  541. : 'default'
  542. }
  543. class={[
  544. styles.textBtn,
  545. selectChildObj(item.instruments).selected &&
  546. styles.textBtnActive
  547. ]}>
  548. {selectChildObj(item.instruments).name || item.name}
  549. <i class={styles.iconArrow}></i>
  550. </NButton>
  551. </NPopselect>
  552. ) : (
  553. <NButton
  554. round
  555. textColor={
  556. data.tagIndex === item.value ? '#fff' : '#000'
  557. }
  558. color={
  559. data.tagIndex === item.value ? '#198CFE' : '#fff'
  560. }
  561. type={
  562. data.tagIndex === item.value ? 'primary' : 'default'
  563. }
  564. onClick={() => {
  565. data.tagIndex = item.value || 0;
  566. data.reshing = true;
  567. document
  568. .querySelector('.musicList-container')
  569. .scroll(0, 0);
  570. handleGetList();
  571. }}>
  572. {item.name}
  573. </NButton>
  574. )
  575. )}
  576. </NSpace>
  577. </div>
  578. </NSpace>
  579. <TheSearch
  580. style={{ marginLeft: 'auto' }}
  581. round
  582. border={false}
  583. onSearch={val => {
  584. forms.name = val;
  585. data.reshing = true;
  586. handleGetList();
  587. }}
  588. />
  589. </div>
  590. <div class={styles.contentWrap}>
  591. <div class={[styles.musicList, 'musicList-container']}>
  592. <div class={[styles.wrapList, 'music-wrap-list']}>
  593. {data.list.map((item: IMusicItem, index) => {
  594. return (
  595. <div class={styles.itemContainer}>
  596. <div
  597. class={[
  598. styles.item,
  599. data.listActive === index && styles.active
  600. ]}
  601. onClick={() => {
  602. handleChange(item);
  603. musicIframeLoad();
  604. }}>
  605. <div class={styles.img}>
  606. <NImage
  607. lazy
  608. objectFit="cover"
  609. previewDisabled={true}
  610. src={item.titleImg || icon_default}
  611. onLoad={e => {
  612. (e.target as any).dataset.loaded = 'true';
  613. }}
  614. />
  615. <PlayLoading
  616. class={[
  617. data.listActive === index &&
  618. data.playState === 'play'
  619. ? ''
  620. : styles.showPlayLoading
  621. ]}
  622. />
  623. </div>
  624. <div class={styles.title}>
  625. <div class={styles.titleName}>
  626. <TheNoticeBar text={item.musicSheetName} />
  627. </div>
  628. <div class={styles.titleDes}>{item.composer}</div>
  629. </div>
  630. {index == 0 ? (
  631. <NButton
  632. color="#259CFE"
  633. textColor="#fff"
  634. {...{ id: 'music-1' }}
  635. round
  636. class={styles.btn}
  637. type="primary"
  638. onClick={(e: Event) => {
  639. e.stopPropagation();
  640. handlePlay(item);
  641. if (
  642. data.listActive === index &&
  643. data.playState === 'play' &&
  644. isEnsemble.value
  645. ) {
  646. musicIframeLoad();
  647. }
  648. }}>
  649. 试听
  650. <img
  651. src={
  652. data.listActive === index &&
  653. data.playState === 'play'
  654. ? icon_pause
  655. : icon_play
  656. }
  657. />
  658. </NButton>
  659. ) : (
  660. <NButton
  661. color="#259CFE"
  662. textColor="#fff"
  663. round
  664. class={styles.btn}
  665. type="primary"
  666. onClick={(e: Event) => {
  667. e.stopPropagation();
  668. handlePlay(item);
  669. if (
  670. data.listActive === index &&
  671. data.playState === 'play' &&
  672. isEnsemble.value
  673. ) {
  674. musicIframeLoad();
  675. }
  676. }}>
  677. 试听
  678. <img
  679. src={
  680. data.listActive === index &&
  681. data.playState === 'play'
  682. ? icon_pause
  683. : icon_play
  684. }
  685. />
  686. </NButton>
  687. )}
  688. <img class={styles.arrow} src={icon_arrow} />
  689. </div>
  690. </div>
  691. );
  692. })}
  693. <div
  694. ref={spinRef}
  695. class={[
  696. styles.loadingWrap,
  697. data.finshed && styles.showLoading
  698. ]}>
  699. <NSpin show={true}></NSpin>
  700. </div>
  701. {!data.loading && data.list.length === 0 && (
  702. <div class={styles.empty}>
  703. <TheEmpty></TheEmpty>
  704. </div>
  705. )}
  706. </div>
  707. </div>
  708. <div class={styles.musicStaff}>
  709. <div class={styles.musicName}>
  710. {activeItem.value.musicSheetName}
  711. </div>
  712. <img
  713. id="music-2"
  714. style={{
  715. display: activeItem.value.id ? '' : 'none'
  716. }}
  717. class={[styles.goBtn]}
  718. src={icon_goXiaoku}
  719. onClick={() => {
  720. handleChangeAudio('pause');
  721. // const origin = /(localhost|192)/.test(location.host)
  722. // ? 'https://test.lexiaoya.cn'
  723. // : location.origin;
  724. // 默认进页面显示对应的曲谱
  725. let lineType = 'staff';
  726. if (data.showMusicImg === 'first') {
  727. lineType = 'firstTone';
  728. } else if (data.showMusicImg === 'fixed') {
  729. lineType = 'fixedTone';
  730. } else if (data.showMusicImg === 'staff') {
  731. lineType = 'staff';
  732. }
  733. const src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&showGuide=true&id=${
  734. activeItem.value.id
  735. }&Authorization=${
  736. user.getToken
  737. }&musicRenderType=${lineType}&showGuide=true&part-index=${
  738. data.musicInstrumentIndex
  739. }`;
  740. if (
  741. window.matchMedia('(display-mode: standalone)').matches
  742. ) {
  743. state.application = window.matchMedia(
  744. '(display-mode: standalone)'
  745. ).matches;
  746. data.previewModal = true;
  747. data.previewUrl = src;
  748. data.showPreivew = false;
  749. } else {
  750. window.open(src);
  751. }
  752. }}
  753. />
  754. <div
  755. class={styles.rightBtns}
  756. style={{ display: activeItem.value.id ? '' : 'none' }}>
  757. {isEnsemble.value && (
  758. <NPopselect
  759. options={data.trackList}
  760. trigger="hover"
  761. v-model:value={data.musicInstrumentIndex}
  762. onUpdate:value={async (val: any) => {
  763. //
  764. }}
  765. // key={item.id}
  766. class={[styles.popSelect]}>
  767. <NButton round class={[styles.textBtn]}>
  768. {data.trackName}
  769. <i class={styles.iconArrow}></i>
  770. </NButton>
  771. </NPopselect>
  772. )}
  773. {/* 转谱按钮 */}
  774. {data.showTransBtn && (
  775. <NPopselect
  776. options={_actions}
  777. trigger="hover"
  778. v-model:value={data.showMusicImg}
  779. onUpdate:value={async (val: any) => {
  780. data.showMusicImg = val;
  781. // musicIframeLoad();
  782. }}
  783. // key={item.id}
  784. class={[styles.popTrans]}>
  785. <img class={[styles.transBtn]} src={icon_trans} />
  786. </NPopselect>
  787. )}
  788. <div class={styles.favitor} onClick={() => handleFavitor()}>
  789. <Transition name="favitor" mode="out-in">
  790. {activeItem.value.favitor ? (
  791. <img src={icon_favitorActive} key="1" />
  792. ) : (
  793. <img src={icon_favitor} key="2" />
  794. )}
  795. </Transition>
  796. </div>
  797. </div>
  798. <div class={styles.staffImgs}>
  799. {isEnsemble.value ? (
  800. <iframe
  801. id="staffIframeRef"
  802. style={{
  803. width: '100%',
  804. height: '100%',
  805. paddingTop: '20px'
  806. // opacity: loading.value ? 0 : 1
  807. }}
  808. src={data.iframeSrc}
  809. onLoad={musicIframeLoad}></iframe>
  810. ) : (
  811. <>
  812. {/* <TransitionGroup name="van-fade"> */}
  813. {musicImg.value.length > 0 ? (
  814. musicImg.value.map((item: string) => {
  815. return <img src={item} key={item} />;
  816. })
  817. ) : (
  818. <TheEmpty></TheEmpty>
  819. )}
  820. {/* </TransitionGroup> */}
  821. </>
  822. )}
  823. </div>
  824. </div>
  825. </div>
  826. </div>
  827. </div>
  828. {data.list.length !== 0 && (
  829. <PlayItem
  830. show={data.showPlayer}
  831. playState={data.playState}
  832. item={activeItem.value}
  833. onChange={value => handleChangeAudio(value)}
  834. />
  835. )}
  836. {showGuide.value ? <Musicguide></Musicguide> : null}
  837. <NModal
  838. v-model:show={data.previewModal}
  839. onUpdate:show={(val: any) => {
  840. if (!val) {
  841. data.previewUrl = '';
  842. }
  843. }}
  844. class={styles.previewWindow}
  845. showIcon={false}
  846. displayDirective="show">
  847. <NSpin show={data.showPreivew} style="--n-opacity-spinning: 1;">
  848. <img
  849. style={{ display: data.showCloseBtn ? '' : 'none' }}
  850. src={icon_close}
  851. class={styles.previewClose}
  852. onClick={() => {
  853. data.previewModal = false;
  854. data.previewUrl = '';
  855. }}
  856. />
  857. <iframe
  858. class={styles.previewIframe}
  859. onLoad={() => {
  860. data.showPreivew = false;
  861. }}
  862. frameborder="0"
  863. src={data.previewUrl}></iframe>
  864. </NSpin>
  865. </NModal>
  866. </div>
  867. );
  868. }
  869. });