index.tsx 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  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 { modalClickMask, 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. import { audioPlayType } from '/src/utils/contants';
  58. import CCascader from '/src/components/CCascader';
  59. export default defineComponent({
  60. name: 'XiaokuMusic',
  61. setup() {
  62. const catchStore = useCatchStore();
  63. const user = useUserStore();
  64. const route = useRoute();
  65. const router = useRouter();
  66. const forms = reactive({
  67. page: 1,
  68. rows: 20,
  69. status: true,
  70. name: '', // 关键词
  71. audioPlayTypes: '',
  72. musicSheetCategoriesId: route.query.id || ''
  73. });
  74. const data = reactive({
  75. loading: false,
  76. finshed: false,
  77. reshing: false,
  78. tags: [] as any[],
  79. tagIndex: 0,
  80. musicalInstrumentId: '',
  81. musicSubject: '',
  82. list: [] as unknown as IMusicItem[],
  83. listActive: 0,
  84. musicInstrumentIndex: 0,
  85. playState: 'pause' as 'play' | 'pause',
  86. showPlayer: false,
  87. previewModal: false,
  88. showPreivew: false,
  89. previewUrl: '',
  90. showCloseBtn: true,
  91. audioPlayTypeList: [] as any,
  92. iframeSrc: '',
  93. showMusicImg: 'staff' as 'staff' | 'first' | 'fixed', // 显示哪种曲谱
  94. trackList: [] as any, // 可筛选的分轨信息
  95. showTransBtn: true, // 是否显示转谱按钮
  96. trackName: '切换声部' as any // 分轨名字
  97. });
  98. const subjects = ref('');
  99. const showGuide = ref(false);
  100. const userStore = useUserStore();
  101. let musicsrc = '';
  102. const formatParentCurrentValue = (list: any) => {
  103. for (const item of list) {
  104. if (item.instruments && item.instruments.length > 0) {
  105. item.instruments.forEach((child: any) => {
  106. child.columnName = '乐器';
  107. });
  108. item.children = item.instruments;
  109. formatParentCurrentValue(item.instruments);
  110. }
  111. }
  112. };
  113. const getSubjects = async () => {
  114. // const res = await api_subjectList();
  115. // if (Array.isArray(res?.data)) {
  116. const tempSubjectList = catchStore.getSubjectList;
  117. const subjectList = sessionStorage.getItem('musicSubjectList')
  118. ? JSON.parse(sessionStorage.getItem('musicSubjectList') as any)
  119. : [];
  120. const resultList: any[] = [];
  121. console.log(tempSubjectList, subjectList, 'subjectList');
  122. tempSubjectList.forEach((item: any) => {
  123. const hasItem = subjectList.find((s: any) => s.id === item.id);
  124. if (hasItem) {
  125. resultList.push(item);
  126. }
  127. });
  128. // data.tags = [
  129. // { name: '全部', id: 0, value: 0, label: '全部' },
  130. // ...resultList
  131. // ];
  132. formatParentCurrentValue(resultList);
  133. data.tags = [
  134. {
  135. columnName: '声部',
  136. name: '全部声部',
  137. id: ''
  138. },
  139. ...resultList
  140. ];
  141. // }
  142. };
  143. const getList = async () => {
  144. data.loading = true;
  145. let res = {} as any;
  146. try {
  147. const { audioPlayTypes, ...result } = forms;
  148. res = await api_musicSheetPage({
  149. ...result,
  150. audioPlayTypes: audioPlayTypes
  151. ? audioPlayTypes === 'PLAY_SING'
  152. ? ['PLAY', 'SING']
  153. : [audioPlayTypes]
  154. : [],
  155. musicSubject: data.musicSubject,
  156. musicalInstrumentId: data.musicalInstrumentId
  157. });
  158. } catch (error) {
  159. console.log(error);
  160. }
  161. // console.log(res, 'data', data.reshing, 'musicSubject');
  162. if (data.reshing) {
  163. data.list = [];
  164. data.reshing = false;
  165. }
  166. if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
  167. console.log(res?.data?.rows);
  168. const tempResult = res?.data?.rows || [];
  169. tempResult.forEach((item: any) => {
  170. item.audioPlayTypeArray = item.audioPlayTypes
  171. ? item.audioPlayTypes.split(',')
  172. : [];
  173. });
  174. data.list = [...data.list, ...res.data.rows];
  175. data.finshed = res.data.rows.length < forms.rows;
  176. // 是否显示总谱
  177. const selectMusic = data.list[data.listActive];
  178. if (selectMusic && selectMusic.isScoreRender && data.listActive === 0) {
  179. data.musicInstrumentIndex = 999;
  180. }
  181. } else {
  182. data.finshed = true;
  183. }
  184. if (data.list[data.listActive]) {
  185. getFavitor(data.list[data.listActive]);
  186. }
  187. data.loading = false;
  188. setTimeout(() => {
  189. showGuide.value = true;
  190. }, 500);
  191. };
  192. const handleGetList = () => {
  193. data.listActive = 0;
  194. data.showPlayer = false;
  195. data.playState = 'pause';
  196. forms.page = 1;
  197. data.finshed = false;
  198. getList();
  199. };
  200. const spinRef = ref();
  201. const handleResh = () => {
  202. if (data.loading || data.finshed) return;
  203. forms.page = forms.page + 1;
  204. getList();
  205. };
  206. // ifram事件处理
  207. const iframeHandle = (ev: MessageEvent) => {
  208. if (ev.data?.api === 'api_fingerPreView') {
  209. data.showCloseBtn = !ev.data.state;
  210. }
  211. };
  212. onMounted(async () => {
  213. // 场景
  214. const tempAudio = Object.keys(audioPlayType).map(key => {
  215. return {
  216. value: key,
  217. label: audioPlayType[key]
  218. };
  219. });
  220. data.audioPlayTypeList = [{ label: '全部', value: '' }, ...tempAudio];
  221. // 获取声部列表
  222. await catchStore.getSubjects();
  223. // musicList-container
  224. useResizeObserver(
  225. document.querySelector('.musicList-container') as HTMLElement,
  226. (entries: any) => {
  227. const entry = entries[0];
  228. const { height } = entry.contentRect;
  229. // console.log(height, 'height - 11');
  230. document.documentElement.style.setProperty(
  231. '--xiaoku-music-height',
  232. height + 'px'
  233. );
  234. }
  235. );
  236. getSubjects();
  237. await getList();
  238. const obv = new IntersectionObserver(entries => {
  239. if (entries[0].intersectionRatio > 0) {
  240. handleResh();
  241. }
  242. });
  243. obv.observe(spinRef.value);
  244. analyzeXml();
  245. musicIframeLoad();
  246. window.addEventListener('message', iframeHandle);
  247. });
  248. onUnmounted(() => {
  249. window.removeEventListener('message', iframeHandle);
  250. });
  251. /** 查看收藏状态 */
  252. const getFavitor = async (item: any) => {
  253. const res = await api_materialFavoriteStatus({
  254. type: 'MUSIC',
  255. materialId: item.id
  256. });
  257. if (res?.code === 200) {
  258. item.favitor = res.data;
  259. }
  260. };
  261. /** 改变模仿的曲谱 */
  262. const handleChange = (item: IMusicItem) => {
  263. const index = data.list.findIndex(_item => _item.id === item.id);
  264. if (index > -1) {
  265. data.listActive = index;
  266. }
  267. getFavitor(item);
  268. };
  269. const selectChildObj = (item: any) => {
  270. const obj: any = {};
  271. item?.forEach((child: any) => {
  272. if (child.id === data.tagIndex) {
  273. obj.selected = true;
  274. obj.name = child.name;
  275. }
  276. });
  277. return obj;
  278. };
  279. /** 选中的item */
  280. const activeItem = computed(() => {
  281. if (data.list[data.listActive]) {
  282. // const origin = /(localhost|192)/.test(location.host)
  283. // ? 'https://dev.kt.colexiu.com'
  284. // : location.origin;
  285. // console.log(
  286. // data.list[data.listActive].xmlFileUrl,
  287. // 'data.list[data.listActive]'
  288. // );
  289. musicsrc = `${vaildMusicScoreUrl()}/instrument/?modelType=practise&id=${
  290. data.list[data.listActive]?.xmlFileUrl
  291. }&Authorization=${userStore.getToken}/#/preview`;
  292. } else {
  293. musicsrc = '';
  294. }
  295. return data.list[data.listActive] || {};
  296. });
  297. /** 收藏曲谱 */
  298. const handleFavitor = () => {
  299. data.list[data.listActive].favitor = !data.list[data.listActive].favitor;
  300. api_materialFavorite({
  301. favoriteFlag: data.list[data.listActive].favitor,
  302. type: 'MUSIC',
  303. materialId: data.list[data.listActive].id
  304. });
  305. };
  306. /** 播放曲目 */
  307. const handlePlay = (item: IMusicItem) => {
  308. const index = data.list.findIndex(_item => _item.id === item.id);
  309. if (index > -1) {
  310. if (data.listActive === index) {
  311. data.playState = data.playState === 'play' ? 'pause' : 'play';
  312. } else {
  313. data.playState = 'play';
  314. }
  315. data.showPlayer = true;
  316. data.listActive = index;
  317. }
  318. };
  319. const musicalInstruments = computed(() => {
  320. const details: any = data.list[data.listActive];
  321. const musics = details?.musicalInstruments || [];
  322. const temp: any = [];
  323. musics.forEach((item: any, index: number) => {
  324. temp.push({
  325. label: item.name,
  326. value: index
  327. });
  328. });
  329. return temp;
  330. });
  331. // 根据musicSheetType返回的值,判断是否显示切换声部按钮
  332. const isEnsemble = computed(() => {
  333. // const details: any = data.list[data.listActive];
  334. // const musics: any = details?.musicalInstruments;
  335. // if (musics && musics.length > 1) {
  336. // return true;
  337. // } else {
  338. // return false;
  339. // }
  340. if (data.list.length) {
  341. const musicSheetType: any = data.list[data.listActive]?.musicSheetType;
  342. if (musicSheetType === 'SINGLE') {
  343. return false;
  344. } else {
  345. return true;
  346. }
  347. } else {
  348. return false;
  349. }
  350. });
  351. // 判断是否可转谱 - 为空也可以转谱
  352. const checkConverTible = (isConvertibleScore: any, scoreType: string) => {
  353. if (
  354. isConvertibleScore ||
  355. isConvertibleScore === '' ||
  356. isConvertibleScore === undefined ||
  357. isConvertibleScore === null ||
  358. (['JIAN', 'FIRST'].includes(scoreType) && !isConvertibleScore)
  359. ) {
  360. return true;
  361. } else {
  362. return false;
  363. }
  364. };
  365. const musicIframeLoad = () => {
  366. const token = userStore.getToken;
  367. const details = data.list[data.listActive];
  368. // const origin = /(localhost|192)/.test(location.host)
  369. // ? 'https://test.lexiaoya.cn'
  370. // : location.origin;
  371. // console.log(
  372. // origin,
  373. // 'origin',
  374. // `${origin}/instrument/?id=${details.id}&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${data.musicInstrumentIndex}`
  375. // );
  376. const musicRenderType =
  377. data.showMusicImg === 'first'
  378. ? 'firstTone'
  379. : data.showMusicImg === 'fixed'
  380. ? 'fixedTone'
  381. : data.showMusicImg === 'staff'
  382. ? 'staff'
  383. : 'staff';
  384. data.iframeSrc = `${vaildMusicScoreUrl()}/instrument/?id=${
  385. details.id
  386. }&modelType=practise&modeType=json&Authorization=${token}&isPreView=true&part-index=${
  387. data.musicInstrumentIndex
  388. }&musicRenderType=${musicRenderType}`;
  389. console.log(data.iframeSrc, 'iframeSrc');
  390. };
  391. /** 音频控制 */
  392. const handleChangeAudio = (
  393. type: 'play' | 'pause' | 'pre' | 'next' | 'favitor'
  394. ) => {
  395. if (type === 'play') {
  396. data.playState = 'play';
  397. } else if (type === 'pause') {
  398. data.playState = 'pause';
  399. } else if (type === 'pre') {
  400. if (data.list[data.listActive - 1]) {
  401. handlePlay(data.list[data.listActive - 1]);
  402. }
  403. } else if (type === 'next') {
  404. if (data.list[data.listActive + 1]) {
  405. handlePlay(data.list[data.listActive + 1]);
  406. }
  407. } else if (type === 'favitor') {
  408. handleFavitor();
  409. }
  410. };
  411. const _actions = computed(() => {
  412. const details = data.list[data.listActive];
  413. const { scoreType, isConvertibleScore } = details || {};
  414. const action: any[] = [
  415. {
  416. value: 'first',
  417. label: '首调'
  418. },
  419. {
  420. value: 'fixed',
  421. label: '固定调'
  422. }
  423. ];
  424. // 首调 固定调 并且 不显示可转谱 则不显示五线谱
  425. console.log(scoreType, isConvertibleScore, 'isConvertibleScore');
  426. if (
  427. !(
  428. ['JIAN', 'FIRST'].includes(scoreType) && isConvertibleScore === false
  429. ) &&
  430. !(isConvertibleScore === undefined || isConvertibleScore === null)
  431. ) {
  432. console.log('true ----- inin in in ');
  433. action.unshift({
  434. value: 'staff',
  435. label: '五线谱'
  436. });
  437. }
  438. return action;
  439. });
  440. // 解析xml,获取分轨信息
  441. const analyzeXml = async () => {
  442. const details: any = data.list[data.listActive];
  443. if (details?.musicSheetType === 'CONCERT') {
  444. if (details.xmlFileUrl) {
  445. const res = await fetch(details.xmlFileUrl).then(response =>
  446. response.text()
  447. );
  448. filterTracks(res);
  449. }
  450. } else {
  451. // if (details.xmlFileUrl) {
  452. // const res = await fetch(details.xmlFileUrl).then(response =>
  453. // response.text()
  454. // );
  455. // console.log(res, '23233');
  456. // const xmlParse = new DOMParser().parseFromString(res, 'text/xml');
  457. // const partList =
  458. // xmlParse
  459. // .getElementsByTagName('part-list')?.[0]
  460. // ?.getElementsByTagName('score-part') || [];
  461. // const partListNames = Array.from(partList).map(
  462. // item =>
  463. // item
  464. // .getElementsByTagName('part-name')?.[0]
  465. // ?.textContent?.trim() || ''
  466. // );
  467. // }
  468. // showMusicImg: 'first' as 'staff' | 'first' | 'fixed',
  469. // const { defaultScore, transferFlag } =
  470. // details.musicalInstruments[0] || {};
  471. // let musicImgType: 'staff' | 'first' | 'fixed' = 'staff';
  472. // musicImgType =
  473. // defaultScore === 'STAVE'
  474. // ? 'staff'
  475. // : defaultScore === 'JIAN'
  476. // ? 'fixed'
  477. // : defaultScore === 'FIRST'
  478. // ? 'first'
  479. // : 'staff';
  480. // console.log(musicImgType, 'musicImgType1');
  481. // data.showMusicImg = musicImgType;
  482. // data.showTransBtn = transferFlag;
  483. const { scoreType, isConvertibleScore } = details || {};
  484. let musicImgType: 'staff' | 'first' | 'fixed' = 'first';
  485. musicImgType =
  486. scoreType === 'STAVE'
  487. ? 'staff'
  488. : scoreType === 'JIAN'
  489. ? 'fixed'
  490. : scoreType === 'FIRST'
  491. ? 'first'
  492. : 'first';
  493. data.showMusicImg = musicImgType;
  494. data.showTransBtn = checkConverTible(isConvertibleScore, scoreType);
  495. }
  496. };
  497. // 过滤出能切换的分轨
  498. const filterTracks = (xml: any) => {
  499. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml');
  500. const partList =
  501. xmlParse
  502. .getElementsByTagName('part-list')?.[0]
  503. ?.getElementsByTagName('score-part') || [];
  504. const partListNames = Array.from(partList).map(
  505. item =>
  506. item.getElementsByTagName('part-name')?.[0]?.textContent?.trim() || ''
  507. );
  508. // const parts: any = xmlParse.getElementsByTagName('part');
  509. /** 第一分谱如果是约定的配置分谱则跳过 */
  510. if (partListNames[0]?.toLocaleUpperCase?.() === 'COMMON') {
  511. partListNames.shift();
  512. }
  513. // 根据后台已选择的分轨筛选出能切换的声轨
  514. const multiTracksSelection: any =
  515. data.list[data.listActive]?.multiTracksSelection;
  516. const canSelectTracks = multiTracksSelection
  517. ? multiTracksSelection?.split(',')
  518. : [];
  519. const arr = partListNames
  520. .map((item: any, index: number) => {
  521. // 该声轨能否被选
  522. const canselect =
  523. canSelectTracks.length == 0 || canSelectTracks.includes(item)
  524. ? true
  525. : false;
  526. // console.log(canselect,index)
  527. const instrumentName = getInstrumentName(item);
  528. const sortId = sortMusical(instrumentName, index);
  529. return {
  530. label: item + (instrumentName ? `(${instrumentName})` : ''),
  531. value: index,
  532. sortId,
  533. canselect,
  534. track: item
  535. };
  536. })
  537. .filter((item: any) => item.canselect)
  538. .sort((a: any, b: any) => a.sortId - b.sortId);
  539. data.trackList = arr;
  540. // 是否显示总谱
  541. const selectMusic = data.list[data.listActive];
  542. if (selectMusic) {
  543. selectMusic.isScoreRender &&
  544. data.trackList.unshift({
  545. label: '总谱',
  546. value: 999,
  547. sortId: 0,
  548. canselect: true,
  549. track: 999
  550. });
  551. }
  552. // let track = arr.find(
  553. // (item: any) => item.value === data.musicInstrumentIndex
  554. // )?.track;
  555. // track = track
  556. // .replace(/[0-9]+/g, '')
  557. // .replace(/\s/g, '')
  558. // .toLocaleLowerCase();
  559. // track = trackToCode(track);
  560. // let musicRenderType: 'staff' | 'first' | 'fixed' = 'staff';
  561. // let canTrans = true;
  562. // data.list[data.listActive]?.musicalInstruments.forEach((item: any) => {
  563. // if (item.code.toLocaleLowerCase() === track.toLocaleLowerCase()) {
  564. // musicRenderType =
  565. // item.defaultScore === 'STAVE'
  566. // ? 'staff'
  567. // : item.defaultScore === 'JIAN'
  568. // ? 'fixed'
  569. // : item.defaultScore === 'FIRST'
  570. // ? 'first'
  571. // : 'staff';
  572. // canTrans = item.transferFlag;
  573. // }
  574. // });
  575. // data.showTransBtn = canTrans;
  576. // data.showMusicImg = musicRenderType;
  577. const details = data.list[data.listActive];
  578. const { scoreType, isConvertibleScore } = details || {};
  579. let musicImgType: 'staff' | 'first' | 'fixed' = 'first';
  580. musicImgType =
  581. scoreType === 'STAVE'
  582. ? 'staff'
  583. : scoreType === 'JIAN'
  584. ? 'fixed'
  585. : scoreType === 'FIRST'
  586. ? 'first'
  587. : 'first';
  588. data.showMusicImg = musicImgType;
  589. data.showTransBtn = checkConverTible(isConvertibleScore, scoreType);
  590. };
  591. watch(
  592. () => data.listActive,
  593. async () => {
  594. data.musicInstrumentIndex = 0;
  595. analyzeXml();
  596. }
  597. );
  598. // watch(
  599. // () => data.musicInstrumentIndex,
  600. // async () => {
  601. // data.trackName =
  602. // data.trackList.find(
  603. // (item: any) => item.value === data.musicInstrumentIndex
  604. // )?.label || '切换声部';
  605. // musicIframeLoad();
  606. // }
  607. // );
  608. // 合奏曲谱转换时,更新曲谱信息
  609. // watch(
  610. // () => data.showMusicImg,
  611. // () => {
  612. // if (isEnsemble.value) {
  613. // musicIframeLoad();
  614. // }
  615. // }
  616. // );
  617. const musicImg = computed(() => {
  618. let imgs: any = [];
  619. if (data.showMusicImg === 'first') {
  620. const img = activeItem.value?.musicFirstImg;
  621. imgs = img ? img.split(',') : [];
  622. } else if (data.showMusicImg === 'fixed') {
  623. const img = activeItem.value?.musicJianImg;
  624. imgs = img ? img.split(',') : [];
  625. } else if (data.showMusicImg === 'staff') {
  626. const img = activeItem.value?.musicImg || activeItem.value?.musicSvg;
  627. imgs = img ? img.split(',') : [];
  628. }
  629. return imgs;
  630. });
  631. return () => (
  632. <div class={styles.container}>
  633. <NSpace align="center" wrapItem={false} size={16}>
  634. <img
  635. style={{ cursor: 'pointer' }}
  636. src={icon_back}
  637. class={styles.iconBack}
  638. onClick={() => router.push({ path: '/xiaoku-ai' })}
  639. />
  640. <NBreadcrumb separator="">
  641. <NBreadcrumbItem
  642. onClick={() => router.push({ path: '/xiaoku-ai' })}>
  643. 全部列表
  644. </NBreadcrumbItem>
  645. <img class={styles.separator} src={icon_separator} />
  646. <NBreadcrumbItem>{route.query.name}</NBreadcrumbItem>
  647. </NBreadcrumb>
  648. </NSpace>
  649. <div class={[styles.wrap, data.showPlayer ? styles.wrapBottom : '']}>
  650. <div class={styles.content}>
  651. <div class={styles.tools}>
  652. <NSpace style={{ width: '100%' }} size={[12, 6]} wrapItem={false}>
  653. {data.audioPlayTypeList.map((item: any) => (
  654. <NButton
  655. round
  656. textColor={
  657. forms.audioPlayTypes === item.value ? '#fff' : '#000'
  658. }
  659. color={
  660. forms.audioPlayTypes === item.value ? '#198CFE' : '#fff'
  661. }
  662. type={
  663. forms.audioPlayTypes === item.value
  664. ? 'primary'
  665. : 'default'
  666. }
  667. onClick={() => {
  668. forms.audioPlayTypes = item.value || '';
  669. if (item.value === 'SING') {
  670. data.musicalInstrumentId = '';
  671. data.musicSubject = '';
  672. }
  673. data.reshing = true;
  674. document
  675. .querySelector('.musicList-container')
  676. ?.scroll(0, 0);
  677. handleGetList();
  678. }}>
  679. {item.label}
  680. </NButton>
  681. ))}
  682. {/* <div
  683. {...{
  684. id: 'music-0'
  685. }}>
  686. <NSpace
  687. style={{ width: '100%' }}
  688. size={[24, 12]}
  689. wrapItem={false}>
  690. {data.tags.map(item =>
  691. item.instruments && item.instruments.length > 1 ? (
  692. <NPopselect
  693. options={item.instruments}
  694. trigger="hover"
  695. v-model:value={data.tagIndex}
  696. scrollable
  697. onUpdate:value={() => {
  698. // onSearch();
  699. data.reshing = true;
  700. document
  701. .querySelector('.musicList-container')
  702. ?.scroll(0, 0);
  703. handleGetList();
  704. }}
  705. key={item.value}
  706. class={[styles.popSelect1]}>
  707. <NButton
  708. round
  709. textColor={
  710. selectChildObj(item.instruments).selected
  711. ? '#fff'
  712. : '#000'
  713. }
  714. color={
  715. selectChildObj(item.instruments).selected
  716. ? '#198CFE'
  717. : '#fff'
  718. }
  719. type={
  720. selectChildObj(item.instruments).selected
  721. ? 'primary'
  722. : 'default'
  723. }
  724. class={[
  725. styles.textBtn,
  726. selectChildObj(item.instruments).selected &&
  727. styles.textBtnActive
  728. ]}>
  729. {selectChildObj(item.instruments).name || item.name}
  730. <i class={styles.iconArrow}></i>
  731. </NButton>
  732. </NPopselect>
  733. ) : (
  734. <NButton
  735. round
  736. textColor={
  737. data.tagIndex === item.value ? '#fff' : '#000'
  738. }
  739. color={
  740. data.tagIndex === item.value ? '#198CFE' : '#fff'
  741. }
  742. type={
  743. data.tagIndex === item.value ? 'primary' : 'default'
  744. }
  745. onClick={() => {
  746. data.tagIndex = item.value || 0;
  747. data.reshing = true;
  748. document
  749. .querySelector('.musicList-container')
  750. ?.scroll(0, 0);
  751. handleGetList();
  752. }}>
  753. {item.name}
  754. </NButton>
  755. )
  756. )}
  757. </NSpace>
  758. </div> */}
  759. </NSpace>
  760. </div>
  761. <div class={styles.contentWrap}>
  762. <div class={[styles.musicList, 'musicList-container']}>
  763. <div class={styles.searchSection}>
  764. {forms.audioPlayTypes !== 'SING' && (
  765. <CCascader
  766. placeholder="全部乐器"
  767. arrowType="small"
  768. childShowAllCheck={false}
  769. class={styles.instrumentSection}
  770. v-model:value={subjects.value}
  771. options={data.tags}
  772. onMoreId={(val: any) => {
  773. if (data.loading) return;
  774. data.musicalInstrumentId = val.childId;
  775. data.musicSubject = val.parentId;
  776. data.reshing = true;
  777. document
  778. .querySelector('.musicList-container')
  779. ?.scroll(0, 0);
  780. handleGetList();
  781. }}
  782. />
  783. )}
  784. <TheSearch
  785. style={{ marginLeft: 'auto' }}
  786. round
  787. border={false}
  788. onSearch={val => {
  789. if (data.loading) return;
  790. forms.name = val;
  791. data.reshing = true;
  792. handleGetList();
  793. }}
  794. />
  795. </div>
  796. <div class={[styles.wrapList, 'music-wrap-list']}>
  797. {data.list.map((item: IMusicItem, index) => {
  798. return (
  799. <div class={styles.itemContainer}>
  800. <div
  801. class={[
  802. styles.item,
  803. data.listActive === index && styles.active
  804. ]}
  805. onClick={async () => {
  806. handleChange(item);
  807. await analyzeXml();
  808. // 是否显示总谱
  809. const selectMusic = data.list[data.listActive];
  810. console.log(selectMusic, 'selected music');
  811. if (selectMusic && selectMusic.isScoreRender) {
  812. data.musicInstrumentIndex = 999;
  813. } else {
  814. data.musicInstrumentIndex = 0;
  815. }
  816. musicIframeLoad();
  817. }}>
  818. <div class={styles.img}>
  819. <NImage
  820. lazy
  821. objectFit="cover"
  822. previewDisabled={true}
  823. src={item.titleImg || icon_default}
  824. onLoad={e => {
  825. (e.target as any).dataset.loaded = 'true';
  826. }}
  827. />
  828. <PlayLoading
  829. class={[
  830. data.listActive === index &&
  831. data.playState === 'play'
  832. ? ''
  833. : styles.showPlayLoading
  834. ]}
  835. />
  836. </div>
  837. <div class={styles.title}>
  838. <div class={styles.titleName}>
  839. <TheNoticeBar text={item.musicSheetName} />
  840. </div>
  841. <div class={styles.titleDes}>
  842. {item.audioPlayTypeArray?.includes('PLAY') && (
  843. <span
  844. class={[styles.iconType, styles.iconPlay]}>
  845. 演奏
  846. </span>
  847. )}
  848. {item.audioPlayTypeArray?.includes('SING') && (
  849. <span
  850. class={[styles.iconType, styles.iconSing]}>
  851. 演唱
  852. </span>
  853. )}
  854. {item.composer}
  855. </div>
  856. </div>
  857. {/* {index == 0 ? (
  858. <NButton
  859. color="#259CFE"
  860. textColor="#fff"
  861. {...{ id: 'music-1' }}
  862. round
  863. class={styles.btn}
  864. type="primary"
  865. onClick={(e: Event) => {
  866. e.stopPropagation();
  867. handlePlay(item);
  868. if (
  869. data.listActive === index &&
  870. data.playState === 'play' &&
  871. isEnsemble.value
  872. ) {
  873. musicIframeLoad();
  874. }
  875. }}>
  876. 试听
  877. <img
  878. src={
  879. data.listActive === index &&
  880. data.playState === 'play'
  881. ? icon_pause
  882. : icon_play
  883. }
  884. />
  885. </NButton>
  886. ) : (
  887. <NButton
  888. color="#259CFE"
  889. textColor="#fff"
  890. round
  891. class={styles.btn}
  892. type="primary"
  893. onClick={(e: Event) => {
  894. e.stopPropagation();
  895. handlePlay(item);
  896. if (
  897. data.listActive === index &&
  898. data.playState === 'play' &&
  899. isEnsemble.value
  900. ) {
  901. musicIframeLoad();
  902. }
  903. }}>
  904. 试听
  905. <img
  906. src={
  907. data.listActive === index &&
  908. data.playState === 'play'
  909. ? icon_pause
  910. : icon_play
  911. }
  912. />
  913. </NButton>
  914. )} */}
  915. <img class={styles.arrow} src={icon_arrow} />
  916. </div>
  917. </div>
  918. );
  919. })}
  920. <div
  921. ref={spinRef}
  922. class={[
  923. styles.loadingWrap,
  924. data.finshed && styles.showLoading
  925. ]}>
  926. <NSpin show={true}></NSpin>
  927. </div>
  928. {!data.loading && data.list.length === 0 && (
  929. <div class={styles.empty}>
  930. <TheEmpty></TheEmpty>
  931. </div>
  932. )}
  933. </div>
  934. </div>
  935. <div class={styles.musicStaff}>
  936. <div class={styles.musicName}>
  937. {activeItem.value.musicSheetName}
  938. </div>
  939. <img
  940. id="music-2"
  941. style={{
  942. display: activeItem.value.id ? '' : 'none'
  943. }}
  944. class={[styles.goBtn]}
  945. src={icon_goXiaoku}
  946. onClick={() => {
  947. handleChangeAudio('pause');
  948. // const origin = /(localhost|192)/.test(location.host)
  949. // ? 'https://test.lexiaoya.cn'
  950. // : location.origin;
  951. // 默认进页面显示对应的曲谱
  952. let lineType = 'staff';
  953. if (data.showMusicImg === 'first') {
  954. lineType = 'firstTone';
  955. } else if (data.showMusicImg === 'fixed') {
  956. lineType = 'fixedTone';
  957. } else if (data.showMusicImg === 'staff') {
  958. lineType = 'staff';
  959. }
  960. let src = `${vaildMusicScoreUrl()}/instrument?v=${+new Date()}&platform=pc&id=${
  961. activeItem.value.id
  962. }&Authorization=${
  963. user.getToken
  964. }&musicRenderType=${lineType}&showGuide=true&showWebGuide=false&part-index=${
  965. data.musicInstrumentIndex
  966. }`;
  967. if (data.musicalInstrumentId) {
  968. src += '&instrumentId=' + data.musicalInstrumentId;
  969. }
  970. if (
  971. window.matchMedia('(display-mode: standalone)').matches
  972. ) {
  973. state.application = window.matchMedia(
  974. '(display-mode: standalone)'
  975. ).matches;
  976. data.previewModal = true;
  977. data.previewUrl = src;
  978. data.showPreivew = false;
  979. } else {
  980. window.open(src);
  981. }
  982. }}
  983. />
  984. <div
  985. class={styles.rightBtns}
  986. style={{ display: activeItem.value.id ? '' : 'none' }}>
  987. {isEnsemble.value && (
  988. <NPopselect
  989. options={data.trackList}
  990. trigger="hover"
  991. v-model:value={data.musicInstrumentIndex}
  992. onUpdate:value={async (val: any) => {
  993. await analyzeXml();
  994. //
  995. data.trackName =
  996. data.trackList.find(
  997. (item: any) =>
  998. item.value === data.musicInstrumentIndex
  999. )?.label || '切换声部';
  1000. musicIframeLoad();
  1001. }}
  1002. // key={item.id}
  1003. class={[styles.popSelect]}>
  1004. <NButton round class={[styles.textBtn]}>
  1005. {data.trackName}
  1006. <i class={styles.iconArrow}></i>
  1007. </NButton>
  1008. </NPopselect>
  1009. )}
  1010. {/* 转谱按钮 */}
  1011. {data.showTransBtn && (
  1012. <NPopselect
  1013. options={_actions.value}
  1014. trigger="hover"
  1015. v-model:value={data.showMusicImg}
  1016. onUpdate:value={async (val: any) => {
  1017. data.showMusicImg = val;
  1018. // musicIframeLoad();
  1019. if (isEnsemble.value) {
  1020. musicIframeLoad();
  1021. }
  1022. }}
  1023. // key={item.id}
  1024. class={[styles.popTrans]}>
  1025. <img class={[styles.transBtn]} src={icon_trans} />
  1026. </NPopselect>
  1027. )}
  1028. <div class={styles.favitor} onClick={() => handleFavitor()}>
  1029. <Transition name="favitor" mode="out-in">
  1030. {activeItem.value.favitor ? (
  1031. <img src={icon_favitorActive} key="1" />
  1032. ) : (
  1033. <img src={icon_favitor} key="2" />
  1034. )}
  1035. </Transition>
  1036. </div>
  1037. </div>
  1038. <div class={styles.staffImgs}>
  1039. {isEnsemble.value ? (
  1040. <iframe
  1041. id="staffIframeRef"
  1042. style={{
  1043. width: '100%',
  1044. height: '100%',
  1045. paddingTop: '20px'
  1046. // opacity: loading.value ? 0 : 1
  1047. }}
  1048. src={data.iframeSrc}
  1049. onLoad={() => {
  1050. // musicIframeLoad();
  1051. }}></iframe>
  1052. ) : (
  1053. <>
  1054. {/* <TransitionGroup name="van-fade"> */}
  1055. {musicImg.value.length > 0 ? (
  1056. musicImg.value.map((item: string) => {
  1057. return <img src={item} key={item} />;
  1058. })
  1059. ) : (
  1060. <TheEmpty></TheEmpty>
  1061. )}
  1062. {/* </TransitionGroup> */}
  1063. </>
  1064. )}
  1065. </div>
  1066. </div>
  1067. </div>
  1068. </div>
  1069. </div>
  1070. {data.list.length !== 0 && (
  1071. <PlayItem
  1072. show={data.showPlayer}
  1073. playState={data.playState}
  1074. item={activeItem.value}
  1075. onChange={value => handleChangeAudio(value)}
  1076. />
  1077. )}
  1078. {showGuide.value ? <Musicguide></Musicguide> : null}
  1079. <NModal
  1080. maskClosable={modalClickMask}
  1081. v-model:show={data.previewModal}
  1082. onUpdate:show={(val: any) => {
  1083. if (!val) {
  1084. data.previewUrl = '';
  1085. }
  1086. }}
  1087. class={styles.previewWindow}
  1088. showIcon={false}
  1089. displayDirective="show">
  1090. <NSpin show={data.showPreivew} style="--n-opacity-spinning: 1;">
  1091. <img
  1092. style={{ display: data.showCloseBtn ? '' : 'none' }}
  1093. src={icon_close}
  1094. class={styles.previewClose}
  1095. onClick={() => {
  1096. data.previewModal = false;
  1097. data.previewUrl = '';
  1098. }}
  1099. />
  1100. <iframe
  1101. class={styles.previewIframe}
  1102. onLoad={() => {
  1103. data.showPreivew = false;
  1104. }}
  1105. frameborder="0"
  1106. src={data.previewUrl}></iframe>
  1107. </NSpin>
  1108. </NModal>
  1109. </div>
  1110. );
  1111. }
  1112. });