import { defineComponent, onMounted, onUnmounted, reactive, Ref, ref, watch,nextTick } from 'vue' import MusicSheet from '/src/music-sheet' import store from 'store' // import { throttle } from 'lodash' 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 EvaluatingTips from '/src/pages/detail/evaluating-tips' 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, { modelType } 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 from './popups/sound-effect' import HelperPopup from './popups/helper' import { OpenSheetMusicDisplay, PageFormat } from '/osmd-extended/src' import Fingering from './fingering' import { 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 from './popups/productJson' import { useRoute } from 'vue-router' import styles from './index.module.less' import Tips from './tips' const search = useOriginSearch() const browserInfo = browser() // json化曲谱的note信息和svg export const musicJSON = reactive({ json: '', svg: '', rended: false, // 渲染完成 }) /** 暴露曲谱实例方便其他地方重新绘制曲谱 */ export const MusicSheetRef = ref() export default defineComponent({ name: 'Colexiu', setup() { const route = useRoute() // console.log("🚀 ~ route", route.query, search) detailState.midiPlayIniting = true const renderLoading = ref(true) const renderError = ref(false) 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) const pages = new PageFormat(650, 884) /** 监听详情的获取状态,设置指法等信息 */ watch(detailStatus, async () => { if (detailStatus.value === 'success' && detail.value.xmlFileUrl) { pushAppMusic(detail.value) 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 } if (detailStatus.value === 'success' && detail.value.xmlFileUrl) { const xml = await useXml(detail.value.xmlFileUrl, detail.value) if (!xml.value) { renderLoading.value = false renderError.value = true return } else { score.value = xml.value } } }) 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(() => { // console.log('settingFingeringChange') const { direction } = fingeringDetail.value as ITypeContentItem if (direction === 'vertical') { Toast('加载中,请稍后...') setTimeout(() => { MusicSheetRef.value.reRender() }, 16) } }, 300) onMounted(() => { ;(window as any).appName = 'colexiu' RuntimeUtils.event.on('settingFingeringChange', settingFingeringChange) postMessage({ api: 'setEventTracking', content: { type: 'klx_xiaokuAI', }, }) }) onUnmounted(() => { RuntimeUtils.event.off('settingFingeringChange', settingFingeringChange) if (typeof runtime?.audiosInstance?.destroy === 'function') { runtime.audiosInstance?.destroy() } }) useUser() useSpecialShapedScreen() useSuspendPlay() //需要生成缓存数据的条件 const isProductJson = ref(false) const productRef = ref() /** 当渲染完成后的回调 */ const onRerender = async (osmd: OpenSheetMusicDisplay) => { // @ts-ignore window.isLoading = false console.log('onRerender', '渲染结束') postMessage({ api: 'cloudLoading', content: { show: false, type: 'fullscreen', }, }) console.log('cloudLoading', false) detailState.initRendered = true // console.log('onRerender', osmd) console.log(search) console.time('获取数据') runtime.osmd = osmd detailState.isSpecialBookCategory = true if (detailState.renderType === 'native') { detailState.times = getAllNodes(osmd) } isProductJson.value = search.modeType === 'json' || !detailState.activeDetail?.musicSvg || !detailState.activeDetail?.musicJianSvg || !detailState.activeDetail?.musicFirstSvg if (isProductJson.value) { const { numerator, denominator } = getDuration(osmd) try { musicJSON.json = JSON.stringify({ musicId: detailState.activeDetail.id, 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() }) // console.log("🚀 ~ detailState.times", document.getElementById('osmdSvgPage1')) } catch (error) { console.log(error) } } console.timeEnd('获取数据') // console.time('循环引用') // if (detailState.times.length) { // for(let i = 0; i < detailState.times.length;i++){ // let item = detailState.times[i] // item.measures = item.measures.map((n: any) => detailState.times.find((m: any) => m.NoteToGraphicalNoteObjectId === n.NoteToGraphicalNoteObjectId)) // } // } // console.timeEnd('循环引用') console.log('🚀 ~ detailState.times', detailState.times) const saveSpeed = (store.get('speeds') || {})[search.id as string] const bpm = (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM detailState.activeSpeed = saveSpeed || bpm || 100 detailState.baseSpeed = bpm || 100 detailState.code = detail.value?.code || '' detailState.activeDetail.originalSpeed = detailState.baseSpeed 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 useFee(detail.value.paymentType || detail.value.chargeType, detail.value.orderStatus) useCamera() RuntimeUtils.changeSpeed(detailState.activeSpeed) if (((detailState.setting?.resets || []) as string[]).includes('SPEED')) { if (detailState.activeDetail) { RuntimeUtils.changeSpeed(detailState.activeDetail?.originalSpeed) } } RuntimeUtils.setAudioInit() renderLoading.value = false try { restPromptMain(detailState.times) } catch (error) {} if (compulsionEvaluating.value) { runtime.evaluatingStatus = true modelType.value = 'evaluation' } } const onStartRender = async () => { renderLoading.value = true postMessage({ api: 'cloudLoading', content: { show: true, type: 'fullscreen', }, }) } const onRenderError = () => { // @ts-ignore window.isLoading = false postMessage({ api: 'cloudLoading', content: { show: false, type: 'fullscreen', }, }) renderError.value = true renderLoading.value = false } //给app传伴奏 const pushAppMusic = (detail: any) => { postMessage({ api: 'cloudAccompanyMessage', content: { accompanyUrl: detail.audioFileUrl || detail.metronomeUrl || detail.url || '', }, }) } 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 (
{loading && !error && } {error && } {score.value && fingeringInited && ( <>

{detail.value.musicSheetName}

{ renderLoading.value = false ;(window as any).isLoading = false postMessage({ api: 'cloudLoading', content: { show: false, type: 'fullscreen', }, }) }} /> {needFingering && ( )} )}
{!loading && !error && } {/* 节拍器弹窗 */} {/* 效音 */} {/* 投屏帮助 */} {/** 曲目列表 */} {/* 保存json */} {/* 引导 */}
) } }, })