123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- 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<string>
- */
- export const useXml = async (url: string, detail: MusicSheelDetail) => {
- const partIndex = Number(search['part-index']) || 0
- let score = ref<string>('')
- 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'
- 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<void>}
- */
- export const useSpecialShapedScreen = () => {
- const heightRef = ref<number>(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<ShaeetStatusType>, Ref<MusicSheelDetail>] => {
- const prefix = getRequestHostname()
- const status = ref<ShaeetStatusType>('loading')
- const data = ref<MusicSheelDetail>({})
- 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()
- }
- }
- })
- }
|