|
@@ -1,5 +1,5 @@
|
|
|
import { Skeleton } from "vant";
|
|
|
-import { defineComponent, onBeforeMount, onBeforeUnmount, onMounted, reactive, Transition } from "vue";
|
|
|
+import { defineComponent, onBeforeMount, onBeforeUnmount, onMounted, reactive, Transition, watch, ref } from "vue";
|
|
|
import { formateTimes } from "../../helpers/formateMusic";
|
|
|
import state, { isRhythmicExercises, getMusicDetail, EnumMusicRenderType } from "../../state";
|
|
|
import { setGlobalData } from "../../utils";
|
|
@@ -18,18 +18,53 @@ import ShareTop from "./component/share-top";
|
|
|
import { addMeasureScore } from "/src/view/evaluating";
|
|
|
|
|
|
const colorsClass: any = {
|
|
|
- RIGHT: styles.right,
|
|
|
- WRONG: styles.wrong,
|
|
|
- NOT_PLAY: styles.notPlay,
|
|
|
- CADENCE_WRONG: styles.cadence_wrong, // 节奏(快慢)
|
|
|
- INTONATION_WRONG: styles.intonation_wrong, // 音准(高低)
|
|
|
- INTEGRITY_WRONG: styles.integrity_wrong, // 完成度
|
|
|
-};
|
|
|
+ RIGHT: styles.right, // 正确
|
|
|
+ WRONG: styles.wrong, // 错误
|
|
|
+ NOT_PLAYED: styles.notPlay, // 未演奏
|
|
|
+ EARLY: styles.cadence_fast, // 节奏快
|
|
|
+ LATE: styles.cadence_slow, // 节奏慢
|
|
|
+ HIGH: styles.intonation_high, // 音准高
|
|
|
+ LOW: styles.intonation_low, // 音准低
|
|
|
+ DURATION_INSUFFICIENT: styles.integrity_wrong // 完整性(时值)不足
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// const colorsClass: any = {
|
|
|
+// /** 音准 */
|
|
|
+// pitch: {
|
|
|
+// /** 高了 */
|
|
|
+// HIGH: styles.intonation_high,
|
|
|
+// /** 正常 */
|
|
|
+// RIGHT: styles.intonation_right,
|
|
|
+// /** 低了 */
|
|
|
+// LOW: styles.intonation_low,
|
|
|
+// /** 未演奏 */
|
|
|
+// NOT_PLAYED: styles.notPlay,
|
|
|
+// /** 错误 */
|
|
|
+// WRONG: styles.intonation_wrong,
|
|
|
+// /** 时值不足 */
|
|
|
+// DURATION_INSUFFICIENT: styles.integrity_wrong
|
|
|
+// },
|
|
|
+// /** 节奏 */
|
|
|
+// rhythmic: {
|
|
|
+// /** 过早 */
|
|
|
+// EARLY: styles.cadence_fast,
|
|
|
+// /** 正常 */
|
|
|
+// RIGHT: styles.cadence_right,
|
|
|
+// /** 过迟 */
|
|
|
+// LATE: styles.cadence_slow,
|
|
|
+// /** 未演奏 */
|
|
|
+// NOT_PLAYED: styles.notPlay,
|
|
|
+// /** 错误 */
|
|
|
+// WRONG: styles.cadence_wrong
|
|
|
+// }
|
|
|
+// }
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: "music-list",
|
|
|
setup() {
|
|
|
const query: any = getQuery();
|
|
|
+ const useedid = ref<string[]>([])
|
|
|
const scoreData = reactive({
|
|
|
videoFilePath: "", // 回放视频路径
|
|
|
cadence: 0,
|
|
@@ -37,6 +72,7 @@ export default defineComponent({
|
|
|
intonation: 0,
|
|
|
score: 0,
|
|
|
heardLevel: "",
|
|
|
+ itemType: "intonation",
|
|
|
});
|
|
|
|
|
|
const detailData = reactive({
|
|
@@ -161,11 +197,121 @@ export default defineComponent({
|
|
|
// });
|
|
|
});
|
|
|
|
|
|
+
|
|
|
+ const getOffsetPosition = (type: keyof typeof colorsClass): string => {
|
|
|
+ switch (type) {
|
|
|
+ case 'EARLY':
|
|
|
+ return 'translateX(-2px)'
|
|
|
+ case 'LATE':
|
|
|
+ return 'translateX(2px)'
|
|
|
+ case 'HIGH':
|
|
|
+ return 'translateY(-2px)'
|
|
|
+ case 'LOW':
|
|
|
+ return 'translateY(2px)'
|
|
|
+ default:
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const filterNotes = () => {
|
|
|
+ const include = ['RIGHT', 'WRONG', 'NOT_PLAYED']
|
|
|
+ if (scoreData.itemType === 'intonation') { // 音准
|
|
|
+ include.push(...['HIGH', 'LOW'])
|
|
|
+ } else if (scoreData.itemType === 'cadence') { // 节奏
|
|
|
+ include.push(...['EARLY', 'LATE'])
|
|
|
+ } else if (scoreData.itemType === 'integrity') { // 完整性
|
|
|
+ include.push(...['DURATION_INSUFFICIENT'])
|
|
|
+ }
|
|
|
+ if (scoreData.itemType === 'cadence') {
|
|
|
+ return detailData.musicalNotesPlayStats.filter((item: any) => include.includes(item.rhythmicAssessment.result))
|
|
|
+ } else {
|
|
|
+ return detailData.musicalNotesPlayStats.filter((item: any) => include.includes(item.pitchAssessment.result))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const setViewColor = () => {
|
|
|
+ clearViewColor()
|
|
|
+ const notes = filterNotes()
|
|
|
+ //console.log(1111,notes)
|
|
|
+ for (const note of notes) {
|
|
|
+ const active = state.times[note.index]
|
|
|
+ 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 = scoreData.itemType === 'cadence' ? note.rhythmicAssessment.result : note.pitchAssessment.result
|
|
|
+ //console.log(1111222,errType)
|
|
|
+ const isNeedCopyElement = ['HIGH', 'LOW', 'EARLY', 'LATE'].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
|
|
|
+ runtime.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 setPathColor = () => {
|
|
|
+ console.log(11111,detailData.musicalNotesPlayStats,scoreData.itemType)
|
|
|
for (const note of detailData.musicalNotesPlayStats) {
|
|
|
- const active = state.times[note.musicalNotesIndex];
|
|
|
+ const active = state.times[note.index];
|
|
|
const svgEl = active?.id ? document.getElementById("vf-" + active?.id) : null;
|
|
|
- svgEl?.classList.add(colorsClass[note.musicalErrorType]);
|
|
|
+ switch (scoreData.itemType) {
|
|
|
+ case "intonation":
|
|
|
+ svgEl?.classList.add(colorsClass.pitch[note.pitchAssessment.result]);
|
|
|
+ break;
|
|
|
+ case "cadence":
|
|
|
+ svgEl?.classList.add(colorsClass.rhythmic[note.rhythmicAssessment.result]);
|
|
|
+ break;
|
|
|
+ case "integrity":
|
|
|
+ svgEl?.classList.add(colorsClass.pitch[note.pitchAssessment.result]);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
const setMearureColor = () => {
|
|
@@ -180,7 +326,8 @@ export default defineComponent({
|
|
|
state.osmd = osmd;
|
|
|
state.times = formateTimes(osmd);
|
|
|
console.log("🚀 ~ state.times:", state.times);
|
|
|
- setPathColor();
|
|
|
+ //setPathColor();
|
|
|
+ setViewColor();
|
|
|
setMearureColor();
|
|
|
api_cloudLoading();
|
|
|
};
|
|
@@ -190,7 +337,12 @@ export default defineComponent({
|
|
|
onBeforeUnmount(() => {
|
|
|
window.removeEventListener("resize", resetMusicScore);
|
|
|
});
|
|
|
-
|
|
|
+ watch(
|
|
|
+ () => scoreData.itemType,
|
|
|
+ () => {
|
|
|
+ setViewColor();
|
|
|
+ }
|
|
|
+ );
|
|
|
return () => (
|
|
|
<div
|
|
|
class={[styles.detail, state.setting.eyeProtection && "eyeProtection", styles.shareBox]}
|