import { onBeforeUnmount, onMounted, Ref, ref, watch } from 'vue' import { useClientType, useOriginSearch } from '.' import request from '/src/helpers/request' import originRequest from 'umi-request' import store from 'store' import runtime, * as RuntimeUtils from '/src/pages/detail/runtime' import detailState, { GradualTimes, isRhythmicExercises } from '/src/pages/detail/state' import SettingState from '/src/pages/detail/setting-state' import { listenerMessage, postMessage } from '/src/helpers/native-message' import audiosInstance from '/src/helpers/multiple-audio' import { formatXML, onlyVisible, getCustomInfo } from '/src/pages/detail/helpers' import { MusicSheelDetail, ShaeetStatusType } from '../index.d' import { browser, getRequestHostname, isEncoded, setGlobalData } from '/src/helpers/utils' import formatId, { formatdata, getSubjectIdCode } from '../fingering/format-id' import { evaluatStopPlay } from '../buttons/evaluating' import state from '/src/pages/detail/state' import { getGradualLengthByXml } from '/src/pages/detail/calcSpeed' import { musicInfo } from '../state' import { getInstrumentName } from '../helpers/instruments' const search = useOriginSearch() const skpList = ['Ukulele'] /** * 特殊教材分类id */ export const classids = [1, 2, 6, 7, 8, 9, 3, 10, 11, 12, 13, 4, 14, 15, 16, 17, 30, 31, 35, 36, 108]; // 大雅金唐, 竖笛教程, 声部训练展开的分类ID // export const classids = [1, 30, 97]; // [大雅金唐, 竖笛教程, 声部训练] /** * 大雅金唐类目 */ const daYaClassids = [1, 2, 6, 7, 8, 9, 3, 10, 11, 12, 13, 4, 14, 15, 16, 17] /** * 获取xml并前置格式化 * @param url xml地址 * @param detail 音乐详情 * @returns Ref */ export const useXml = async (url: string, detail: MusicSheelDetail) => { const partIndex = Number(search['part-index']) || 0 let score = ref('') try { const xml = await originRequest(url) const parseXmlInfo = getCustomInfo(xml) if (skpList.includes(parseXmlInfo.code)) { score.value = xml } else { score.value = formatXML(parseXmlInfo.parsedXML, { title: detail.musicSheetName, }) // 多种乐器分轨合并显示 if (state.isCombineRender) { const customNoduleInfo = JSON.parse(localStorage.getItem('customNoduleInfo')) || [] const matchMusic = customNoduleInfo.find((n: any) => n.id === id) const xjNum = matchMusic ? matchMusic.customNum : 4 setGlobalData('wrapNum', xjNum) } else { score.value = onlyVisible(score.value, partIndex) } state.partIndex = partIndex } state.gradual = getGradualLengthByXml(xml) } catch (error) {} return score } /** * 设置音频信息 * @param detail 音乐详情 */ export const useMp3s = async (detail: MusicSheelDetail) => { const search = useOriginSearch() const partIndex = ((search['part-index'] as string) || 0) as unknown as number const activebg = detail.background?.[partIndex] Object.assign(musicInfo, activebg) if (musicInfo.musicSvg) { try { musicInfo.musicSvg = typeof musicInfo.musicSvg === 'string' && musicInfo.musicSvg ? JSON.parse(musicInfo.musicSvg) : '' } catch (error) {} } // 伴奏 const backgroundSong = isEncoded(detail.metronomeUrl || '') ? detail.metronomeUrl || '' : encodeURI(detail.metronomeUrl || '') // 原音 const musicSong = isEncoded(activebg?.audioFileUrl|| '') ? activebg?.audioFileUrl || '' : encodeURI(activebg?.audioFileUrl|| '') console.log('伴奏:',backgroundSong,'原音:',musicSong) // 兼容未修改之前 runtime.songs = { background: backgroundSong ? backgroundSong + '?t=background' : '', music: musicSong ? musicSong + '?t=music' : '', } detailState.isAppPlay = detail.audioType === 'MIDI' // 如果后台有速度 const isSpecialSong= !classids.includes(detail.musicSheetCategoriesId) if (!isSpecialSong) { detailState.playSpeed = detail.playSpeed ? parseFloat(String(detail.playSpeed)) : 100; detailState.baseSpeed = detailState.playSpeed } else if (detail.playSpeed && detail.playSpeed !== "") { // detailState.playSpeed = detail.playSpeed ? parseFloat(String(detail.playSpeed)) : 100; // detailState.baseSpeed = detailState.playSpeed detailState.temporarySpeed = detail.playSpeed ? parseFloat(String(detail.playSpeed)) : 90; } let defaultExtConfigJson = { skipTick: false, repeatedBeats: false, scoreSize: 'middle', } let extConfigJson = {} detailState.activeDetail = { ...detail, examSongId: detail.id, originalSpeed: 90, isAppPlay: detail.audioType === 'MIDI', extConfigJson: { ...defaultExtConfigJson, }, } detailState.isPercussion = musicInfo.musicSubject == '1' || isRhythmicExercises(); try { extConfigJson = JSON.parse(detail?.extConfigJson || '') } catch (error) {} detailState.activeDetail.extConfigJson = { ...detailState.activeDetail.extConfigJson, ...extConfigJson, } const setZoom = detailState.activeDetail.extConfigJson.scoreSize const zooms = store.get('zooms') || {} if (setZoom && !zooms['' + detail.id]) { store.set('zooms', { ...zooms, ['' + detail.id]: setZoom }) SettingState.sett.scoreSize = setZoom } detailState.needTick = (detail.audioType === 'MP3' && detail.mp3Type === 'MP3' && detail.musicSheetType != 'CONCERT' ) || detail.audioType === 'MIDI' detailState.skipTick = detailState.activeDetail.extConfigJson.skipTick detailState.repeatedBeats = detailState.activeDetail.extConfigJson.repeatedBeats if (!runtime.songs['music']) { RuntimeUtils.changeMode('background') } // console.log({ ...detailState.activeDetail }) if (!runtime.audiosInstance) { runtime.audiosInstance = new audiosInstance(Object.values(runtime.songs) as string[]) } } /** * 获取异形屏信息 * @returns {Promise} */ export const useSpecialShapedScreen = () => { const heightRef = ref(0) postMessage( { api: 'isSpecialShapedScreen', }, (evt) => { const height = evt?.content.notchHeight detailState.notchHeight = (browser().ios ? height * 2 : height) || (evt?.content.isSpecialShapedScreen && browser().ios ? 100 : 0) heightRef.value = detailState.notchHeight detailState.isSpecialShapedScreen = evt?.content.isSpecialShapedScreen document.documentElement.style.setProperty('--popup-loading', detailState.notchHeight / 4 + 'px') } ) return [heightRef] } /** * 获取当前曲目信息 * @param id 歌曲id */ export const useDetail = (id: number | string): [Ref, Ref] => { const prefix = getRequestHostname() const status = ref('loading') const data = ref({}) status.value = 'loading' request .get(`/musicSheet/detail/${id}`, { prefix: prefix, }) .then((res) => { useMp3s(res.data) data.value = { ...res.data, code: Array.isArray(res?.data?.background) && res.data.background.length ? getSubjectIdCode(res.data.background[0].musicSubject) : '', } // notation: 是能转简谱 0: 不可以,需要设置成五线谱模式, 是否是切换简谱 if (data.value.notation == 0 || !sessionStorage.getItem('notation')) { SettingState.sett.type = 'staff' } // 设置是否特殊曲谱, 是特殊曲谱取反(不理解之前的思考逻辑), 使用后台设置的速度 detailState.isSpecialBookCategory = !classids.includes(res.data.musicSheetCategoriesId) // 大雅金唐类目,#9248 优化 detailState.isDaYaCategory = daYaClassids.includes(res.data.musicSheetCategoriesId) if (detailState.isDaYaCategory) { ;(window as any).customSectionAmount = SettingState.sett.openCustomNodule const customNoduleInfo = JSON.parse(localStorage.getItem('customNoduleInfo')) || [] const matchMusic = customNoduleInfo.find((n: any) => n.id === id) const xjNum = matchMusic ? matchMusic.customNum : 4 setGlobalData('wrapNum', xjNum) } detailState.subjectId = Number(musicInfo.musicSubject) // 打击乐声部下的曲目,需要合并展示所有分轨 if (Number(res.data.musicSubject) === 1 && res.data.background?.length > 1) { state.isCombineRender = true // 开启自定义每行显示的小节数 ;(window as any).customSectionAmount = true setGlobalData('multitrack', res.data.background?.length) } ;(window as any).DYSubjectId = formatId(data.value.code as any) /** * 长笛教程2-5-2,符杆全部朝下 * DYMusicalOrientation,0:朝上;1:朝下 */ if (id == 904) { ;(window as any).DYMusicalOrientation = 1 } if (id == 829) { ;(window as any).DYMusicalOrientation = 0 } status.value = 'success' // 额外配置 let extConfigJson = { gradualTimes: {}, } try { if (data.value?.extConfigJson) { extConfigJson = { ...extConfigJson, ...JSON.parse(data.value.extConfigJson), } } } catch (error) {} state.gradualTimes = extConfigJson.gradualTimes as GradualTimes // 合奏设置 if (res?.data?.musicSheetType == 'CONCERT') { const backgrounds = res?.data?.background || []; const partIndex = Number(search['part-index']) || 0 let track = backgrounds[partIndex]?.track if (backgrounds[0]?.track?.toLocaleUpperCase() == 'COMMON'){ track = backgrounds[partIndex + 1]?.track } const instrumentName = getInstrumentName(track) console.log("🚀 ~ track:", track) detailState.partName = track + (instrumentName ? `(${instrumentName})` : '') const _track = Object.keys(formatdata).filter((key) => key.includes(track) || track.includes(key))[0] data.value.code = _track } }) .catch(() => (status.value = 'error')) return [status, data] } /** * 监听后台切换状态,暂停播放与评测 */ export const useSuspendPlay = () => { listenerMessage('suspendPlay', () => { if (detailState.activeTick > -1) { RuntimeUtils.stopTick() } console.log(runtime.playState) if (runtime.playState === 'play') { RuntimeUtils.resetPlayStatus() if (runtime.evaluatingStatus) { // postMessage( // { // api: 'pauseRecording', // }, // () => { // detailState.isPauseRecording = true // } // ) evaluatStopPlay() } } }) }