123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- import { defineComponent, onMounted, Ref, ref, Transition, watch } from 'vue'
- import request from '/src/helpers/request'
- import originRequest from 'umi-request'
- import MusicSheet from '/src/music-sheet'
- import runtime from '/src/pages/detail/runtime'
- import {
- formatXML,
- onlyVisible,
- getAllNodes,
- getCustomInfo,
- getBoundingBoxByverticalNote,
- getParentNote,
- } from '/src/pages/detail/helpers'
- import SettingState from '/src/pages/detail/setting-state'
- import detailState from '/src/pages/detail/state'
- import { useOriginSearch } from '../colexiu/uses'
- import styles from '../colexiu/index.module.less'
- import detailStyles from './index.module.less'
- import { OpenSheetMusicDisplay } from '/osmd-extended/src'
- import { MusicSheelDetail, ShaeetStatusType } from '../colexiu/index.d'
- import Header, { active } from './header'
- import { colorsClass } from '/src/pages/report'
- import { getLeveByScoreMeasure } from '/src/pages/detail/evaluating/helper'
- import { Button, Skeleton } from 'vant'
- import Empty from '/src/components/empty'
- import { useSpecialShapedScreen } from '../colexiu/uses/use-app'
- import { postMessage, promisefiyPostMessage } from '/src/helpers/native-message'
- const search = useOriginSearch()
- const useXml = async (url: string, detail: MusicSheelDetail) => {
- const xml = await originRequest(url)
- let score = ref<string>('')
- const parseXmlInfo = getCustomInfo(xml)
- score.value = formatXML(parseXmlInfo.parsedXML, {
- title: detail.musicSheetName,
- })
- const partIndex = Number(search['part-index']) || 0
- score.value = onlyVisible(score.value, partIndex)
- return score
- }
- const useDetail = (id: number | string): [Ref<ShaeetStatusType>, Ref<MusicSheelDetail>, Ref<any>] => {
- const status = ref<ShaeetStatusType>('loading')
- const data = ref<MusicSheelDetail>({})
- const record = ref<any>({})
- onMounted(async () => {
- // 没有token
- const token = sessionStorage.getItem('Authorization')
- console.log('第一次请求', token)
- if (!token) {
- // 获取token
- const res = await promisefiyPostMessage({ api: 'getToken' })
- if (res?.content?.accessToken) {
- sessionStorage.setItem('Authorization', res.content.tokenType + ' ' + res.content.accessToken)
- }
- }
- status.value = 'loading'
- try {
- const recordRes = await request.get('/musicPracticeRecord/getLastEvaluationMusicalNotesPlayStats', {
- params: {
- recordId: search.id,
- },
- })
- if (!recordRes.data) {
- status.value = 'error'
- return
- }
- record.value = recordRes.data
- const res = await request.get(`/musicSheet/detail/${record.value?.musicalNotesPlayStats.examSongId}`)
- data.value = res.data
- detailState.partIndex = recordRes.data.partIndex || 0
- detailState.isPercussion = res.data?.background?.[detailState.partIndex]?.musicSubject == 1
- status.value = 'success'
- } catch (error) {
- status.value = 'error'
- console.log(error)
- }
- })
- return [status, data, record]
- }
- export default defineComponent({
- name: 'Colexiu',
- setup() {
- const headerRef = ref()
- const renderLoading = ref(true)
- const renderError = ref(false)
- const score = ref<string>('')
- const useedid = ref<string[]>([])
- const allNote = ref<any[]>([])
- const [detailStatus, detail, record] = useDetail(search.id as string)
- watch(detailStatus, async () => {
- if (detailStatus.value === 'success' && detail.value.xmlFileUrl) {
- const xml = await useXml(detail.value.xmlFileUrl, detail.value)
- // console.log(runtime.songs, detailState.partListNames)
- score.value = xml.value
- }
- })
- // useUser()
- useSpecialShapedScreen()
-
- const getOffsetPosition = (type: keyof typeof colorsClass): string => {
- switch (type) {
- case 'CADENCE_FAST':
- return 'translateX(2px)'
- case 'CADENCE_SLOW':
- return 'translateX(-2px)'
- case 'INTONATION_HIGH':
- return 'translateY(-2px)'
- case 'INTONATION_LOW':
- return 'translateY(2px)'
- default:
- return ''
- }
- }
- const filterNotes = () => {
- const include = ['RIGHT', 'WRONG', 'CADENCE_WRONG']
- console.log(active.value)
- if (active.value === 'pitch') {
- include.push(...['CADENCE_FAST', 'CADENCE_SLOW'])
- } else if (active.value === 'rhythm') {
- include.push(...['INTONATION_HIGH', 'INTONATION_LOW'])
- } else if (active.value === 'completion') {
- include.push(...['INTEGRITY_WRONG'])
- }
- return record.value.musicalNotesPlayStats.notesData.filter((item: any) => include.includes(item.musicalErrorType))
- }
- const setViewColor = () => {
- clearViewColor()
- for (const note of filterNotes()) {
- const active = allNote.value[note.musicalNotesIndex]
- setTimeout(() => {
- if (useedid.value.includes(active.id)) {
- return
- }
- useedid.value.push(active.id)
- const svgEl = document.getElementById('vf-' + active.id)
- const stemEl = document.getElementById('vf-' + active.id + '-stem')
- const errType = note.musicalErrorType as keyof typeof colorsClass
- const isNeedCopyElement = ['INTONATION_HIGH', 'INTONATION_LOW', 'CADENCE_FAST', 'CADENCE_SLOW'].includes(
- errType
- )
- stemEl?.classList.add(colorsClass[errType])
- svgEl?.classList.add(colorsClass[errType])
- if (svgEl && isNeedCopyElement) {
- stemEl?.classList.remove(colorsClass[errType])
- stemEl?.classList.add(colorsClass.RIGHT)
- svgEl?.classList.remove(colorsClass[errType])
- svgEl?.classList.add(colorsClass.RIGHT)
- const copySvg = svgEl.querySelector('.vf-notehead')!.cloneNode(true) as SVGSVGElement
- copySvg.style.transform = getOffsetPosition(errType)
- svgEl.style.opacity = '.7'
- if (stemEl) {
- stemEl.style.opacity = '.7'
- }
- copySvg.id = 'vf-' + active.id + '-copy'
- copySvg?.classList.add(colorsClass[errType])
- // stemEl?.classList.add(colorsClass.RIGHT)
- // @ts-ignore
- osmd?.container.querySelector('svg')!.insertAdjacentElement('afterbegin', copySvg)
- // svgEl?.parentElement?.appendChild(copySvg)
- }
- }, 300)
- }
- }
- const removeClass = (el?: HTMLElement | null) => {
- if (!el) return
- const classList = el.classList.values()
- for (const val of classList) {
- if (val?.indexOf('vf-') !== 0) {
- el.classList.remove(val)
- }
- }
- }
- const clearViewColor = () => {
- for (const id of useedid.value) {
- removeClass(document.getElementById('vf-' + id))
- removeClass(document.getElementById('vf-' + id + '-stem'))
- const qid = 'vf-' + id + '-copy'
- const copyEl = document.getElementById(qid)
- if (copyEl) {
- copyEl.remove()
- }
- }
- useedid.value = []
- }
- const onRerender = (osmd: OpenSheetMusicDisplay) => {
- renderLoading.value = false
- headerRef.value?.autoShow()
- setTimeout(() => {
- for (const item of Array.from(document.querySelectorAll('.vf-beam'))) {
- ;(item as SVGAElement).querySelector('path')?.setAttribute('fill', '#aeaeae')
- }
- })
- runtime.osmd = osmd
- allNote.value = getAllNodes(runtime.osmd)
- setViewColor()
- const setEvaluatings = (note: any, data: any, dontTransition = true) => {
- const startNote = getBoundingBoxByverticalNote(note)
- detailState.evaluatings = {
- ...detailState.evaluatings,
- [startNote.measureIndex]: {
- ...startNote,
- ...getLeveByScoreMeasure(data.score),
- score: data.score,
- dontTransition,
- },
- }
- }
- if (record.value.userMeasureScore) {
- for (const key in record.value.userMeasureScore) {
- if (Object.prototype.hasOwnProperty.call(record.value.userMeasureScore, key)) {
- const data = record.value.userMeasureScore[key]
- for (const time of allNote.value) {
- if (data.measureRenderIndex == time.noteElement.sourceMeasure.MeasureNumberXML - 1) {
- if (!time.noteElement.tie) {
- setEvaluatings(time, data)
- } else {
- for (const item of time.noteElement.tie.notes) {
- const note = getParentNote(item)
- if (!note) continue
- setEvaluatings(note, data, item !== time.noteElement.tie.StartNote)
- }
- }
- }
- }
- }
- }
- }
- // console.log(detailState.evaluatings, record.value.userMeasureScore)
- // detailState.activeDetail.originalSpeed = osmd.Sheet.userStartTempoInBPM
- // RuntimeUtils.setAudioInit()
- }
- const onRenderError = () => {
- renderError.value = true
- renderLoading.value = false
- }
- return () => {
- const loading = renderLoading.value || detailStatus.value === 'loading'
- const error = renderError.value || detailStatus.value === 'error'
- // console.log('ColexiuRender', detail.value.musicSubject, score.value)
- return (
- <div
- class={[
- styles.container,
- SettingState.sett.eyeProtection && 'eyeProtection',
- ]}
- >
- {!renderLoading.value && (
- <Header
- className={styles.header}
- detail={detail.value}
- record={record}
- ref={headerRef}
- style={{
- paddingLeft: detailState.isSpecialShapedScreen ? detailState.notchHeight / 2 + 'px' : 'auto',
- }}
- onActiveChange={(active: string) => setViewColor()}
- />
- )}
- <div
- id="colexiu-detail-music-sheet"
- class={[styles.musicSheet, detailStyles.musicSheet]}
- style={{
- paddingLeft: detailState.isSpecialShapedScreen ? detailState.notchHeight / 2 + 'px' : 'auto',
- }}
- >
- {loading && !error && <Skeleton class={styles.skeleton} rowWidth="80%" title row={3} />}
- {error && <Empty />}
- {score.value && (
- <>
- <div class={styles.headTitle}>{detail.value.musicSheetName}</div>
- <MusicSheet
- score={score.value}
- showSection
- opotions={{
- drawTitle: false,
- drawComposer: false,
- drawLyricist: false,
- drawMetronomeMarks: true,
- drawMeasureNumbers: true,
- autoResize: false,
- }}
- EngravingRules={{
- DefaultColorNotehead: '#aeaeae',
- DefaultColorRest: '#aeaeae',
- DefaultColorMusic: '#aeaeae',
- DefaultColorStem: '#aeaeae',
- DefaultColorChordSymbol: '#aeaeae',
- DefaultColorLabel: '#aeaeae',
- DYMusicScoreType: SettingState.sett.type,
- }}
- onRerender={onRerender}
- onRenderError={onRenderError}
- />
- </>
- )}
- </div>
- </div>
- )
- }
- },
- })
|