import { defineComponent, onMounted, onUnmounted, reactive, Ref, ref, watch, nextTick, Transition } from 'vue' import MusicSheet from '/src/music-sheet' import store from 'store' import runtime, * as RuntimeUtils from '/src/pages/detail/runtime' import { typeById, ITypeContentItem } from '/src/constant/fingering-colexiu' import detailState from '/src/pages/detail/state' import { getAllNodes, getDuration } from '/src/pages/detail/helpers' import SettingState from '/src/pages/detail/setting-state' import { useMidi, useOriginSearch, useFee, useCamera, useUser, useFingering, useDetail, useSpecialShapedScreen, useSuspendPlay, useXml, useActivity, useConfigMusicSheetFreeRate, } from './uses' import Buttons, { followRef, IModelType, modelType, onChangeModelType } from './buttons' import ButtonsPlayer from './buttons/player' import Permission from './popups/permission' import MusicList from './music-list' import TickPopup from '/src/pages/detail/tick-popup' import SoundEffect, { soundEffectShow } from './popups/sound-effect' import HelperPopup from './popups/helper' import { OpenSheetMusicDisplay, PageFormat } from '/osmd-extended/src' import Fingering from './fingering' import { Popup, Skeleton, Toast } from 'vant' import Empty from '/src/components/empty' import formatId from './fingering/format-id' import { browser } from '/src/helpers/utils' import { postMessage } from '/src/helpers/native-message' import { svgtopng } from './helpers' import { restPromptMain } from '/src/helpers/restPrompt' import ProductJson, { getHasCache } from './popups/productJson' import { useRoute } from 'vue-router' import styles from './index.module.less' import Tips from './tips' import AfterClassTraining from './afterClassTraining' import ModelWraper from './buttons/model-wraper' import Follow from './popups/follow' import UnitTest from './unitTest' import { renderError } from './App' import { musicInfo } from './state' import ToggleMusicSheet from './plugins/toggleMusicSheet' import request from '/src/helpers/request' // json化曲谱的note信息和svg export const musicJSON = reactive({ json: '', svg: '', rended: false, // 渲染完成 }) /** 暴露曲谱实例方便其他地方重新绘制曲谱 */ export const MusicSheetRef = ref() export default defineComponent({ name: 'Colexiu', setup() { const search = useOriginSearch() const browserInfo = browser() const tipShow = ref(false) // console.log("🚀 ~ 查询字符串", search) detailState.midiPlayIniting = true const renderLoading = ref(true) const compulsionEvaluating = ref(false) const score = ref('') const fingeringStatus: Ref = ref('init') const fingeringWidth = ref('') const activeType = ref({}) const fingeringDetail = ref({}) const [detailStatus, detail] = useDetail(search.id as string) /** 监听详情的获取状态,设置指法等信息 */ watch(detailStatus, async () => { if (detailStatus.value === 'success' && detail.value.xmlFileUrl) { fingeringDetail.value = typeById[formatId(detail.value.code || '')] || {} const { showFingering, frozenMode, compulsionEvaluating: compulsion } = useActivity() const [status, width, atype] = await useFingering(showFingering.value ? detail.value.code : undefined) fingeringStatus.value = status.value as string fingeringWidth.value = width.value as string activeType.value = atype.value as object detailState.frozenMode = frozenMode.value compulsionEvaluating.value = compulsion.value const xml = await useXml(detail.value.xmlFileUrl, detail.value) if (!xml.value) { renderLoading.value = false renderError.value = true return } else { score.value = xml.value } } if (detailStatus.value === 'error') { renderError.value = true } }) onMounted(() => { ;(window as any).appName = 'colexiu' RuntimeUtils.event.on('settingFingeringChange', settingFingeringChange) postMessage({ api: 'setEventTracking', content: { type: 'klx_xiaokuAI', }, }) if (search.chenkuang) { detailState.chenkuang = true; } }) onUnmounted(() => { RuntimeUtils.event.off('settingFingeringChange', settingFingeringChange) if (typeof runtime?.audiosInstance?.destroy === 'function') { runtime.audiosInstance?.destroy() } }) function throttle(fn: any, delay: number) { let valid = true return function () { if (!valid) { return false } valid = false setTimeout(() => { fn() valid = true }, delay) } } const settingFingeringChange = throttle(() => { const { direction } = fingeringDetail.value as ITypeContentItem if (direction === 'vertical') { Toast('加载中,请稍后...') // Toast({ // type: 'loading', // message: '加载中...' // }) setTimeout(() => { MusicSheetRef.value.reRender() }, 16) } }, 300) // // useUser() useSpecialShapedScreen() useSuspendPlay() /**结束全屏动画 */ const endFullLoading = () => { // @ts-ignore window.isLoading = false postMessage({ api: 'cloudLoading', content: { show: false, type: 'fullscreen', }, }) } // 查询类目信息 const queryCategroyInfo = async (id: any) => { return new Promise((resolve) => { let categoryList: any = [] request .get(`/musicSheetCategories/queryTree?page=1&rows=999&parentId=${id}`) .then((res) => { if (res?.code == 200) { categoryList = res.data.map((item: any) => item.id) resolve(categoryList) } else { resolve([]) } }).catch((err) => { resolve([]) }) }) } const productRef = ref() /** 当渲染完成后的回调 */ const onRerender = async (osmd: OpenSheetMusicDisplay) => { endFullLoading() detailState.initRendered = true console.time('获取数据') runtime.osmd = osmd // 设置速度 //@ts-ignore const saveSpeed = (store.get('speeds') || {})[search.id] const bpm = (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM detailState.activeSpeed = saveSpeed || detail.value.playSpeed || bpm || 100 detailState.baseSpeed = detail.value.playSpeed || bpm || 100 detailState.code = detail.value?.code || '' detailState.activeDetail.originalSpeed = detailState.baseSpeed const categoryList: any = await queryCategroyInfo(49) const { musicSheetCategoriesId } = detailState.activeDetail detailState.skipTick = categoryList.includes(musicSheetCategoriesId) console.log('😯~', osmd, detailState) if (detailState.renderType === 'native') { detailState.times = getAllNodes(osmd) } if (search.modeType === 'json' || getHasCache()) { // const { numerator, denominator } = getDuration(osmd) // try { // musicJSON.json = JSON.stringify({ // musicId: musicInfo.musicId, // musicSheetName: encodeURIComponent(detailState.activeDetail.musicSheetName), // osmd: { // product: true, // bpm: osmd?.Sheet?.userStartTempoInBPM || (osmd as any)?.bpm, // numerator, // denominator, // scoreSize: SettingState.sett.scoreSize || 'middle', // }, // times: detailState.times, // }) // console.log('生成缓存数据', musicJSON) // musicJSON.svg = document.getElementById('osmdSvgPage1')?.outerHTML || '' // nextTick(() => { // musicJSON.svg = document.getElementById('osmdSvgPage1')?.outerHTML || '' // musicJSON.rended = true // productRef.value?.autoProduct() // }) // } catch (error) { // console.log(error) // } } console.timeEnd('获取数据') console.log('🚀 ~👀~ detailState.times', detailState.times) const songEndTime = detailState.times[detailState.times.length - 1 || 0]?.endtime || 0 if (detailState.isAppPlay) { const durationNum = songEndTime useMidi(durationNum, detail.value.midiUrl) } if (!runtime.durationNum) { runtime.durationNum = songEndTime } // const freeRate = await useConfigMusicSheetFreeRate() // detailState.freeRate = freeRate.value useCamera() RuntimeUtils.changeSpeed(detailState.activeSpeed) if (((detailState.setting?.resets || []) as string[]).includes('SPEED')) { if (detailState.activeDetail) { RuntimeUtils.changeSpeed(detailState.activeDetail?.originalSpeed) } } RuntimeUtils.setAudioInit() const _modelType: IModelType = search.modelType as IModelType if (_modelType) { modelType.value = _modelType } renderLoading.value = false try { restPromptMain(detailState.times) } catch (error) {} // 如果进来为评测模式,直接设置成评测模式 if (_modelType && _modelType == 'evaluation') { runtime.evaluatingStatus = true nextTick(() => { onChangeModelType(_modelType) }) } nextTick(() => { useFee() // 给app传伴奏URL // postMessage({ // api: 'cloudAccompanyMessage', // content: { // accompanyUrl: runtime.songs.background, // }, // }) if (search.chenkuang) { RuntimeUtils.refreshView();`` } }) } const onStartRender = async () => { renderLoading.value = true } const onRenderError = () => { endFullLoading() renderError.value = true renderLoading.value = false } /** 是否评测模式,并且有指法监听变化 */ watch( () => runtime.evaluatingStatus, () => { // 指法开启的时候 if (SettingState.sett.fingering && (fingeringDetail.value as any)?.direction === 'vertical') { nextTick(() => { MusicSheetRef.value.reRender() }) } } ) return () => { const loading = renderLoading.value || detailStatus.value === 'loading' const error = renderError.value || detailStatus.value === 'error' // console.log('fingeringStatus', fingeringStatus.value, fingeringWidth.value, fingeringDetail.value) const { width, paddingRight, paddingLeft, direction } = fingeringDetail.value as ITypeContentItem const fingeringInited = fingeringStatus.value !== 'init' const calcWidh = width || '0px' const calcRight = paddingRight || '0px' const calcLeft = paddingLeft || '0px' const isVertical = direction === 'vertical' const calcRightWidth = direction === 'vertical' ? '20px' : '0px' const needFingering = fingeringStatus.value === 'show' && SettingState.sett.fingering && !runtime.evaluatingStatus const needFingeringWidth = direction === 'vertical' && needFingering const musicSheetStyle = { ...(isVertical && { margin: 'auto', marginRight: 0 }), width: fingeringDetail.value && needFingeringWidth ? `calc(100% - ${calcWidh} - ${calcRight} - ${calcLeft} - ${calcRightWidth})` : '', } return ( <>
{!renderLoading.value && }
{!!detail.value.musicSheetName && (
{detail.value.musicSheetName}
)} {detailState.partName ?
{detailState.partName}
: null} {score.value && fingeringInited && ( <> {needFingering && } )} {modelType.value === 'follow' && } {detailState.chenkuang &&
}
{!renderLoading.value && } {/* 节拍器弹窗 */} {/* 投屏帮助 */} {/** 曲目列表 */} {/* 保存json */} {/* */} {/* 后台课后训练小节选择 */} {/* 模式选择 */} { tipShow.value = true }} > {!renderLoading.value && modelType.value == 'init' && ( )} {/* 引导 */} {tipShow.value && !error && }
{/* 效音 */} {soundEffectShow.value && } {/* 单元测验选段 */} {!renderLoading.value && } {/* 切换曲谱 */} {!search.lessonTrainingId && !search.questionId && detail.value.musicSheetType == 'CONCERT' && ( )} ) } }, })