|
@@ -1,5 +1,5 @@
|
|
|
import { Button, Toast } from 'vant'
|
|
|
-import { defineComponent, Directive, onBeforeUnmount, onMounted, Ref, ref, Teleport } from 'vue'
|
|
|
+import { defineComponent, onBeforeUnmount, onMounted, Ref, ref, Teleport, Transition } from 'vue'
|
|
|
import '@dotlottie/player-component'
|
|
|
import detailState from '/src/pages/detail/state'
|
|
|
import SettingState from '/src/pages/detail/setting-state'
|
|
@@ -10,21 +10,20 @@ import {
|
|
|
promisefiyPostMessage,
|
|
|
removeListenerMessage,
|
|
|
} from '/src/helpers/native-message'
|
|
|
-import { browser, getRequestHostname } from '/src/helpers/utils'
|
|
|
+import { browser } from '/src/helpers/utils'
|
|
|
import runtime, * as RuntimeUtils from '/src/pages/detail/runtime'
|
|
|
import { getBoundingBoxByverticalNote, getNoteByMeasuresSlursStart, getParentNote } from '/src/pages/detail/helpers'
|
|
|
-import { useClientType, useOriginSearch } from '../uses'
|
|
|
+import { handleCheckEvaluatStatus, useClientType, useOriginSearch } from '../uses'
|
|
|
import { startButtonShow } from './index'
|
|
|
import { getLeveByScoreMeasure } from '/src/pages/detail/evaluating/helper'
|
|
|
import Evaluating, { evaluatingShow } from '../popups/evaluating'
|
|
|
// @ts-ignore
|
|
|
-import iconStartEvaluating from './dotlotties/StartEvaluating.png'
|
|
|
-import iconRecord from './dotlotties/iconRecord.png'
|
|
|
-// @ts-ignore
|
|
|
import styles from './index.module.less'
|
|
|
import { Vue3Lottie } from 'vue3-lottie'
|
|
|
import startData from './data/start.json'
|
|
|
import startingData from './data/starting.json'
|
|
|
+import { unitTestData } from '../unitTest'
|
|
|
+import iconEvaluatingStart from './icons/icon-evaluatingStart.png'
|
|
|
|
|
|
let backtime = 0
|
|
|
|
|
@@ -34,22 +33,7 @@ const playStatus: Ref<'connecting' | 'play' | 'stop'> = ref('stop')
|
|
|
const endloading = ref(false)
|
|
|
const connentLoading = ref(false)
|
|
|
const playUrl: Ref<string> = ref('')
|
|
|
-
|
|
|
const endResult = ref(null)
|
|
|
-
|
|
|
-export const animate: Directive = {
|
|
|
- mounted: (el: HTMLElement) => {
|
|
|
- el.addEventListener('click', (evt: Event) => {
|
|
|
- let element = evt.target as HTMLElement
|
|
|
- element.classList.add(...['animate__animated', 'animate__tada'])
|
|
|
- })
|
|
|
- el.addEventListener('animationend', (evt: Event) => {
|
|
|
- let element = evt.target as HTMLElement
|
|
|
- element.classList.remove(...['animate__animated', 'animate__tada'])
|
|
|
- })
|
|
|
- },
|
|
|
-}
|
|
|
-
|
|
|
const browserInfo = browser()
|
|
|
|
|
|
/**
|
|
@@ -73,12 +57,24 @@ const formatTimes = () => {
|
|
|
let dontEvaluatingMode = false
|
|
|
let skip = false
|
|
|
const datas = []
|
|
|
- for (let index = 0; index < detailState.times.length; index++) {
|
|
|
- const item = detailState.times[index]
|
|
|
+ let times = detailState.times
|
|
|
+ if (unitTestData.isSelectMeasureMode) {
|
|
|
+ const startIndex = detailState.times.findIndex(
|
|
|
+ (n: any) => n.NoteToGraphicalNoteObjectId == detailState.section[0].NoteToGraphicalNoteObjectId
|
|
|
+ )
|
|
|
+ const endIndex = detailState.times.findIndex(
|
|
|
+ (n: any) => n.NoteToGraphicalNoteObjectId == detailState.section[1].NoteToGraphicalNoteObjectId
|
|
|
+ )
|
|
|
+ times = detailState.times.filter((n: any, index: number) => {
|
|
|
+ return index >= startIndex && index <= endIndex
|
|
|
+ })
|
|
|
+ console.log("🚀 ~ times", times)
|
|
|
+ }
|
|
|
+ // let measureIndex = -1
|
|
|
+ for (let index = 0; index < times.length; index++) {
|
|
|
+ const item = times[index]
|
|
|
const note = getNoteByMeasuresSlursStart(item)
|
|
|
- // console.log(item.nodeElement)
|
|
|
const rate = runtime.speed / detailState.baseSpeed //1
|
|
|
- // const fixtime = 0
|
|
|
const start = difftime + (item.sourceRelativeTime || item.relativeTime)
|
|
|
const end = difftime + (item.sourceRelaEndtime || item.relaEndtime)
|
|
|
const isStaccato =
|
|
@@ -97,15 +93,15 @@ const formatTimes = () => {
|
|
|
dontEvaluatingMode = true
|
|
|
}
|
|
|
const nextNote = detailState.times[index + 1]
|
|
|
- // console.log("noteinfo", note.noteElement.isRestFlag && !!note.stave && !!nextNote)
|
|
|
if (skip && (note.stave || !note.noteElement.isRestFlag || (nextNote && !nextNote.noteElement.isRestFlag))) {
|
|
|
skip = false
|
|
|
}
|
|
|
if (note.noteElement.isRestFlag && !!note.stave && !!nextNote && nextNote.noteElement.isRestFlag) {
|
|
|
skip = true
|
|
|
}
|
|
|
- // console.log(note.measureOpenIndex, item.measureOpenIndex, note)
|
|
|
- // console.log("skip", skip)
|
|
|
+ // if (note.measureOpenIndex != measureIndex){
|
|
|
+ // measureIndex++
|
|
|
+ // }
|
|
|
const data = {
|
|
|
timeStamp: (start * 1000) / rate,
|
|
|
duration: ((end * 1000) / rate - (start * 1000) / rate) * noteRate,
|
|
@@ -113,17 +109,16 @@ const formatTimes = () => {
|
|
|
nextFrequency: formatPitch(item.noteElement?.pitch?.nextFrequency),
|
|
|
prevFrequency: formatPitch(item.noteElement?.pitch?.prevFrequency),
|
|
|
// 重复的情况index会自然累加,render的index是谱面渲染的index
|
|
|
- measureIndex: note.measureOpenIndex,
|
|
|
+ measureIndex: note.measureOpenIndex, //note.measureOpenIndex,
|
|
|
measureRenderIndex: note.noteElement.sourceMeasure.measureListIndex,
|
|
|
- // dontEvaluating: ListenMode,
|
|
|
dontEvaluating: ListenMode || dontEvaluatingMode || item.skipMode,
|
|
|
- musicalNotesIndex: item.i,
|
|
|
+ musicalNotesIndex: index,//item.i,
|
|
|
denominator: note.noteElement?.Length.denominator,
|
|
|
isOrnament: !!note?.voiceEntry?.ornamentContainer,
|
|
|
}
|
|
|
datas.push(data)
|
|
|
}
|
|
|
- // console.log("🚀 ~ datas", datas)
|
|
|
+ console.log("🚀 ~ datas", datas)
|
|
|
return datas
|
|
|
}
|
|
|
const connect = async () => {
|
|
@@ -134,7 +129,6 @@ const connect = async () => {
|
|
|
|
|
|
const content = {
|
|
|
musicXmlInfos: formatTimes(),
|
|
|
- // id: search.id,
|
|
|
subjectId: detailState.subjectId,
|
|
|
detailId: detailState.activeDetail?.id,
|
|
|
examSongId: search.id,
|
|
@@ -204,64 +198,48 @@ const sendOffsetTime = (offsetTime: number) => {
|
|
|
|
|
|
const cancelTheEvaluation = () => {
|
|
|
const search = useOriginSearch()
|
|
|
+ postMessage({ api: 'endEvaluating', content: { musicScoreId: search.id } })
|
|
|
+ playStatus.value = 'stop'
|
|
|
+ RuntimeUtils.pause()
|
|
|
RuntimeUtils.resetPlayStatus()
|
|
|
RuntimeUtils.clearIntervalTimeline()
|
|
|
RuntimeUtils.setCurrentTime(0)
|
|
|
- playStatus.value = 'stop'
|
|
|
- postMessage(
|
|
|
- {
|
|
|
- api: 'endEvaluating',
|
|
|
- content: {
|
|
|
- musicScoreId: search.id,
|
|
|
- },
|
|
|
- },
|
|
|
- (evt) => {
|
|
|
- evaluating.value = false
|
|
|
- // RuntimeUtils.setCaptureMode()
|
|
|
- Toast.clear()
|
|
|
- }
|
|
|
- )
|
|
|
+ Toast.clear()
|
|
|
}
|
|
|
|
|
|
-const stopPlay = (show: boolean = true) => {
|
|
|
+const stopPlay = () => {
|
|
|
console.log('调用stopPlay')
|
|
|
- if (show) {
|
|
|
- // Toast({
|
|
|
- // duration: 0,
|
|
|
- // message: '评分中...',
|
|
|
- // type: 'loading',
|
|
|
- // })
|
|
|
+ if (!connentLoading.value) {
|
|
|
+ cancelTheEvaluation()
|
|
|
}
|
|
|
startButtonShow.value = true
|
|
|
- cancelTheEvaluation()
|
|
|
+ connentLoading.value = false
|
|
|
+ evaluating.value = false
|
|
|
}
|
|
|
export const evaluatStopPlay = stopPlay
|
|
|
|
|
|
const startPlay = () => {
|
|
|
console.log('连接服务成功,开始播放', new Date().getTime() - runtime.clickTime)
|
|
|
- // synced = false
|
|
|
if (!SettingState.eva.mute) {
|
|
|
RuntimeUtils.changeAllMode()
|
|
|
} else {
|
|
|
RuntimeUtils.changeMode('background')
|
|
|
}
|
|
|
startButtonShow.value = false
|
|
|
- // RuntimeUtils.changeSpeed(90)
|
|
|
RuntimeUtils.setPlayState()
|
|
|
}
|
|
|
|
|
|
const setPlayer = async () => {
|
|
|
- console.log('调用setPlayer')
|
|
|
+ // 连接中,禁止重复连接
|
|
|
+ if (connentLoading.value) return
|
|
|
runtime.clickTime = new Date().getTime()
|
|
|
RuntimeUtils.resetPlayStatus()
|
|
|
- runtime.evaluatingTips = false
|
|
|
if (detailState.isPauseRecording) {
|
|
|
evaluating.value = false
|
|
|
startPlay()
|
|
|
return
|
|
|
}
|
|
|
detailState.evaluatings = {}
|
|
|
- RuntimeUtils.setCurrentTime(0)
|
|
|
const hint = Toast({
|
|
|
duration: 0,
|
|
|
message: '服务连接中...',
|
|
@@ -294,16 +272,6 @@ const togglePlay = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const cancelEvaluating = (data?: IPostMessage) => {
|
|
|
- // this.starting = false
|
|
|
- if (data?.content.reson) {
|
|
|
- // Toast.fail({
|
|
|
- // message: data?.content?.reson,
|
|
|
- // })
|
|
|
- stopPlay()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
const timeupdate = () => {
|
|
|
console.log('播放事件被触发', playUrl.value, evaluating.value)
|
|
|
if (playUrl.value) {
|
|
@@ -361,6 +329,12 @@ const playerStop = () => {
|
|
|
export const evaluatPlayerStop = playerStop
|
|
|
|
|
|
const endevent = (evt: Event) => {
|
|
|
+ // 如果是单元测验和课后训练 播放结束
|
|
|
+ if (unitTestData.isSelectMeasureMode && playStatus.value === 'play') {
|
|
|
+ playerStop()
|
|
|
+ canSubmit.value = true
|
|
|
+ return
|
|
|
+ }
|
|
|
if ((evt.target as HTMLAudioElement)?.src === playUrl.value && playStatus.value === 'play') {
|
|
|
playerStop()
|
|
|
canSubmit.value = true
|
|
@@ -371,7 +345,8 @@ const endevent = (evt: Event) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const start = () => {
|
|
|
+/**正式开始评测 */
|
|
|
+const evaluatStart = () => {
|
|
|
playStatus.value = 'play'
|
|
|
if (detailState.isPauseRecording) {
|
|
|
postMessage(
|
|
@@ -425,7 +400,7 @@ const submitEvaluationScore = async (data: any) => {
|
|
|
musicId: search.id || '',
|
|
|
unitId: search.unitId || '',
|
|
|
questionId: search.questionId || '',
|
|
|
- score: canSubmit.value ? ((endResult.value as any)?.score || 0) : 0,
|
|
|
+ score: canSubmit.value ? (endResult.value as any)?.score || 0 : 0,
|
|
|
}),
|
|
|
},
|
|
|
})
|
|
@@ -436,10 +411,11 @@ const submitEvaluationScore = async (data: any) => {
|
|
|
/** 活动使用,只有在全部评测完成后才能提交,避免只是一小节就高分的情况 */
|
|
|
const canSubmit = ref(false)
|
|
|
|
|
|
-
|
|
|
+/**接受websocket返回的信息 */
|
|
|
const sendResult = (evt?: IPostMessage) => {
|
|
|
- console.log('评测返回', evt?.content)
|
|
|
- if (evt?.content) {
|
|
|
+ const { body, header } = evt?.content || {}
|
|
|
+ console.log('评测返回', { body, header })
|
|
|
+ if (body && header) {
|
|
|
const data = evt?.content?.body
|
|
|
if (evt?.content.header.commond === 'overall') {
|
|
|
// console.log(evt)
|
|
@@ -518,37 +494,38 @@ const cloudMetronome = (evt: any) => {
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'ColexiuButtonEvaluating',
|
|
|
- directives: { animate },
|
|
|
setup(props, { expose }) {
|
|
|
onMounted(async () => {
|
|
|
- runtime.evaluatingTips = true
|
|
|
- detailState.section = []
|
|
|
- detailState.sectionStatus = false
|
|
|
+ console.log('进入评测模块')
|
|
|
+ handleCheckEvaluatStatus()
|
|
|
+ // 如果为单元测验和课后训练,不清楚选段数据
|
|
|
+ if (!unitTestData.isSelectMeasureMode) {
|
|
|
+ detailState.section = []
|
|
|
+ detailState.sectionStatus = false
|
|
|
+ }
|
|
|
RuntimeUtils.changeAllMode()
|
|
|
playUrl.value = runtime.songs.background || (runtime.songs.music as string)
|
|
|
runtime.audiosInstance?.audios[playUrl.value]?.addEventListener('play', timeupdate)
|
|
|
runtime.audiosInstance?.audios[playUrl.value]?.addEventListener('timeupdate', onProgress)
|
|
|
- RuntimeUtils.event.on('next-click', playerStop)
|
|
|
+ // RuntimeUtils.event.on('next-click', playerStop)
|
|
|
RuntimeUtils.event.on('ended', endevent)
|
|
|
listenerMessage('sendResult', sendResult)
|
|
|
- listenerMessage('cancelEvaluating', cancelEvaluating)
|
|
|
+ // listenerMessage('cancelEvaluating', cancelTheEvaluation)
|
|
|
listenerMessage('cloudTimeUpdae', onProgress)
|
|
|
RuntimeUtils.event.on('tickDestroy', cloudMetronome)
|
|
|
- RuntimeUtils.event.on('tickEnd', start)
|
|
|
- await RuntimeUtils.pause()
|
|
|
- RuntimeUtils.setCurrentTime(0)
|
|
|
+ RuntimeUtils.event.on('tickEnd', evaluatStart)
|
|
|
})
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
runtime.audiosInstance?.audios[playUrl.value]?.removeEventListener('play', timeupdate)
|
|
|
runtime.audiosInstance?.audios[playUrl.value]?.removeEventListener('timeupdate', onProgress)
|
|
|
- RuntimeUtils.event.off('next-click', playerStop)
|
|
|
+ // RuntimeUtils.event.off('next-click', playerStop)
|
|
|
RuntimeUtils.event.off('ended', endevent)
|
|
|
RuntimeUtils.event.off('tickDestroy', cloudMetronome)
|
|
|
removeListenerMessage('sendResult', sendResult)
|
|
|
- removeListenerMessage('cancelEvaluating', cancelEvaluating)
|
|
|
+ // removeListenerMessage('cancelEvaluating', cancelTheEvaluation)
|
|
|
removeListenerMessage('cloudTimeUpdae', onProgress)
|
|
|
- RuntimeUtils.event.off('tickEnd', start)
|
|
|
+ RuntimeUtils.event.off('tickEnd', evaluatStart)
|
|
|
})
|
|
|
|
|
|
expose({
|
|
@@ -565,30 +542,38 @@ export default defineComponent({
|
|
|
|
|
|
return () => {
|
|
|
return (
|
|
|
- <>
|
|
|
- {/* 评测 */}
|
|
|
+ <Teleport to="body" key="StartEvaluating">
|
|
|
+ {/* 评测完成结果显示 */}
|
|
|
<Evaluating data={endResult.value} />
|
|
|
|
|
|
+ <Transition name="finish">
|
|
|
+ {startButtonShow.value && (
|
|
|
+ <div
|
|
|
+ style={{ backgroundImage: `url(${iconEvaluatingStart})` }}
|
|
|
+ class={[styles.evaluatStartBtn]}
|
|
|
+ onClick={() => {
|
|
|
+ setPlayer()
|
|
|
+ }}
|
|
|
+ ></div>
|
|
|
+ )}
|
|
|
+ </Transition>
|
|
|
+
|
|
|
{!evaluating.value ? (
|
|
|
- <Teleport to="body" key="StartEvaluating">
|
|
|
- <div class={styles.dialogueBox}>
|
|
|
- <div class={styles.dialogue}>
|
|
|
- <div>
|
|
|
- 演奏前请调整好乐器,保证最佳演奏状态。<span class={styles.triangle}></span>
|
|
|
- </div>
|
|
|
+ <div class={styles.dialogueBox}>
|
|
|
+ <div class={styles.dialogue}>
|
|
|
+ <div>
|
|
|
+ 演奏前请调整好乐器,保证最佳演奏状态。<span class={styles.triangle}></span>
|
|
|
</div>
|
|
|
- <Vue3Lottie class={styles.dialogueIcon} animationData={startData}></Vue3Lottie>
|
|
|
</div>
|
|
|
- </Teleport>
|
|
|
+ <Vue3Lottie class={styles.dialogueIcon} animationData={startData}></Vue3Lottie>
|
|
|
+ </div>
|
|
|
) : (
|
|
|
- <Teleport to="body" key="Recording">
|
|
|
- <div class={styles.dialogueBox}>
|
|
|
- <div class={styles.inRadio}>收音中...</div>
|
|
|
- <Vue3Lottie class={styles.inRadioIcon} animationData={startingData}></Vue3Lottie>
|
|
|
- </div>
|
|
|
- </Teleport>
|
|
|
+ <div class={styles.dialogueBox}>
|
|
|
+ <div class={styles.inRadio}>收音中...</div>
|
|
|
+ <Vue3Lottie class={styles.inRadioIcon} animationData={startingData}></Vue3Lottie>
|
|
|
+ </div>
|
|
|
)}
|
|
|
- </>
|
|
|
+ </Teleport>
|
|
|
)
|
|
|
}
|
|
|
},
|