|
@@ -54,15 +54,13 @@
|
|
|
<el-form-item
|
|
|
prop="sysMusicScore.isOpenMetronome"
|
|
|
label="节拍器"
|
|
|
- :rules="[{required: true, message: '请选择节拍器'}]"
|
|
|
+ :rules="[{ required: true, message: '请选择节拍器' }]"
|
|
|
>
|
|
|
<template slot="label">
|
|
|
<span>
|
|
|
节拍器
|
|
|
<el-tooltip placement="top" popper-class="mTooltip">
|
|
|
- <div slot="content">
|
|
|
- 是否播放系统自带节拍器
|
|
|
- </div>
|
|
|
+ <div slot="content">是否播放系统自带节拍器</div>
|
|
|
<i
|
|
|
class="el-icon-question"
|
|
|
style="font-size: 18px; color: #f56c6c"
|
|
@@ -81,26 +79,16 @@
|
|
|
v-for="item in memberRankList"
|
|
|
:key="item.id"
|
|
|
></el-option> -->
|
|
|
- <el-option
|
|
|
- :value="0"
|
|
|
- label="不播放"
|
|
|
- ></el-option>
|
|
|
- <el-option
|
|
|
- :value="1"
|
|
|
- label="播放"
|
|
|
- ></el-option>
|
|
|
+ <el-option :value="0" label="不播放"></el-option>
|
|
|
+ <el-option :value="1" label="播放"></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
- <el-form-item
|
|
|
- label="重复节拍时长"
|
|
|
- >
|
|
|
+ <el-form-item label="重复节拍时长">
|
|
|
<template slot="label">
|
|
|
<span>
|
|
|
重复节拍时长
|
|
|
<el-tooltip placement="top" popper-class="mTooltip">
|
|
|
- <div slot="content">
|
|
|
- 2/4拍类似的节拍器是否重复时长
|
|
|
- </div>
|
|
|
+ <div slot="content">2/4拍类似的节拍器是否重复时长</div>
|
|
|
<i
|
|
|
class="el-icon-question"
|
|
|
style="font-size: 18px; color: #f56c6c"
|
|
@@ -113,14 +101,8 @@
|
|
|
v-model="form.repeatedBeats"
|
|
|
placeholder="请选择是否重复节拍器时长"
|
|
|
>
|
|
|
- <el-option
|
|
|
- :value="0"
|
|
|
- label="不重复"
|
|
|
- ></el-option>
|
|
|
- <el-option
|
|
|
- :value="1"
|
|
|
- label="重复"
|
|
|
- ></el-option>
|
|
|
+ <el-option :value="0" label="不重复"></el-option>
|
|
|
+ <el-option :value="1" label="重复"></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<!-- <el-form-item
|
|
@@ -175,19 +157,77 @@
|
|
|
<el-radio :label="0">否</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
+ <el-form-item :prop="`sysMusicScore.subjectId`" label="声部">
|
|
|
+ <!-- :rules="[{required: true, message: '请选择声部'}]" -->
|
|
|
+ <el-select
|
|
|
+ style="width: 100% !important"
|
|
|
+ v-model="form.sysMusicScore.subjectId"
|
|
|
+ clearable
|
|
|
+ placeholder="请选择声部"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in selects.subjects"
|
|
|
+ :value="item.id"
|
|
|
+ :label="item.name"
|
|
|
+ :key="item.id"
|
|
|
+ :disabled="hasSubjectId(item.id)"
|
|
|
+ ></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item
|
|
|
+ :prop="`sysMusicScore.isShowFingering`"
|
|
|
+ label="指法展示"
|
|
|
+ :rules="[{ required: true, message: '请选择是否展示指法' }]"
|
|
|
+ >
|
|
|
+ <el-select
|
|
|
+ style="width: 100% !important"
|
|
|
+ v-model="form.sysMusicScore.isShowFingering"
|
|
|
+ placeholder="请选择是否展示指法"
|
|
|
+ >
|
|
|
+ <el-option :value="true" label="是"></el-option>
|
|
|
+ <el-option :value="false" label="否"></el-option>
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
<el-form-item
|
|
|
prop="sysMusicScore.order"
|
|
|
label="排序"
|
|
|
- :rules="[{ required: true, message: '请输入排序' }, {
|
|
|
- pattern: /^([1-9]\d*|[0]{1,1})$/,
|
|
|
- message: '请输入正确的排序',
|
|
|
- trigger: 'blur',
|
|
|
- },]"
|
|
|
+ :rules="[
|
|
|
+ { required: true, message: '请输入排序' },
|
|
|
+ {
|
|
|
+ pattern: /^([1-9]\d*|[0]{1,1})$/,
|
|
|
+ message: '请输入正确的排序',
|
|
|
+ trigger: 'blur',
|
|
|
+ },
|
|
|
+ ]"
|
|
|
>
|
|
|
<el-input placeholder="请输入排序" v-model="form.sysMusicScore.order" />
|
|
|
</el-form-item>
|
|
|
<el-form-item
|
|
|
- v-if="form.sysMusicScore.isOpenMetronome ===1"
|
|
|
+ label="MusicXML"
|
|
|
+ :prop="`sysMusicScore.xmlUrl`"
|
|
|
+ :rules="[{ required: true, message: '请选择MusicXML文件' }]"
|
|
|
+ >
|
|
|
+ <singe-file-upload
|
|
|
+ tips="仅支持上传 xml 格式文件"
|
|
|
+ accept=".xml"
|
|
|
+ v-model="form.sysMusicScore.xmlUrl"
|
|
|
+ @inputFile="inputFile"
|
|
|
+ bucket_name="cloud-coach"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ prop="sysMusicScore.speed"
|
|
|
+ label="速度"
|
|
|
+ :rules="[{ required: true, message: '请输入速度' }]"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ placeholder="请输入速度"
|
|
|
+ v-model="form.sysMusicScore.speed"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ v-if="form.sysMusicScore.isOpenMetronome === 1"
|
|
|
label="伴奏(不含节拍器)"
|
|
|
prop="sysMusicScore.url"
|
|
|
>
|
|
@@ -199,7 +239,7 @@
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
<el-form-item
|
|
|
- v-else
|
|
|
+ v-else
|
|
|
label="伴奏(含节拍器)"
|
|
|
prop="sysMusicScore.metronomeUrl"
|
|
|
>
|
|
@@ -207,45 +247,58 @@
|
|
|
tips="仅支持上传 mp3/aac 格式音频文件"
|
|
|
accept=".mp3, .aac"
|
|
|
v-model="form.sysMusicScore.metronomeUrl"
|
|
|
- bucket_name="cloud-coach"
|
|
|
+ bucket_name="cloud-coach"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
- <el-form-item
|
|
|
- label="MIDI"
|
|
|
- prop="sysMusicScore.midiUrl"
|
|
|
- >
|
|
|
+ <el-form-item label="MIDI" prop="sysMusicScore.midiUrl">
|
|
|
<singe-file-upload
|
|
|
tips="仅支持上传 mid 格式音频文件"
|
|
|
accept=".mid"
|
|
|
v-model="form.sysMusicScore.midiUrl"
|
|
|
- bucket_name="cloud-coach"
|
|
|
+ bucket_name="cloud-coach"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
|
|
|
<div v-if="gradual && gradual.length">
|
|
|
- <el-alert :closable="false" style="margin-bottom: 20px;">识别到共{{gradual.length}}处渐变速度,请输入Dorico对应小节时间信息</el-alert>
|
|
|
- <div v-for="item in gradual">
|
|
|
+ <el-alert :closable="false" style="margin-bottom: 20px"
|
|
|
+ >识别到共{{
|
|
|
+ gradual.length
|
|
|
+ }}处渐变速度,请输入Dorico对应小节时间信息</el-alert
|
|
|
+ >
|
|
|
+ <div v-for="(item,index) in gradual" :key="index">
|
|
|
<el-form-item
|
|
|
:label="item[0].measureIndex + 2 + ' 小节'"
|
|
|
- :rules="[{required: true, message: '请输入合奏曲目时间'}, {
|
|
|
- pattern: /^((\d{2}):?){2,3}$/,
|
|
|
- message: '请输入正确的曲目时间',
|
|
|
- trigger: 'blur',
|
|
|
- }]"
|
|
|
+ :rules="[
|
|
|
+ { required: true, message: '请输入合奏曲目时间' },
|
|
|
+ {
|
|
|
+ pattern: /^((\d{2}):?){2,3}$/,
|
|
|
+ message: '请输入正确的曲目时间',
|
|
|
+ trigger: 'blur',
|
|
|
+ },
|
|
|
+ ]"
|
|
|
:prop="`graduals.${item[0].measureIndex}`"
|
|
|
>
|
|
|
- <el-input placeholder="00:00:00" v-model="form.graduals[item[0].measureIndex]"></el-input>
|
|
|
+ <el-input
|
|
|
+ placeholder="00:00:00"
|
|
|
+ v-model="form.graduals[item[0].measureIndex]"
|
|
|
+ ></el-input>
|
|
|
</el-form-item>
|
|
|
<el-form-item
|
|
|
:label="item[1].measureIndex + 2 + ' 小节'"
|
|
|
- :rules="[{required: true, message: '请输入合奏曲目时间'}, {
|
|
|
- pattern: /^((\d{2}):?){2,3}$/,
|
|
|
- message: '请输入正确的曲目时间',
|
|
|
- trigger: 'blur',
|
|
|
- }]"
|
|
|
+ :rules="[
|
|
|
+ { required: true, message: '请输入合奏曲目时间' },
|
|
|
+ {
|
|
|
+ pattern: /^((\d{2}):?){2,3}$/,
|
|
|
+ message: '请输入正确的曲目时间',
|
|
|
+ trigger: 'blur',
|
|
|
+ },
|
|
|
+ ]"
|
|
|
:prop="`graduals.${item[1].measureIndex}`"
|
|
|
>
|
|
|
- <el-input placeholder="00:00:00" v-model="form.graduals[item[1].measureIndex]"></el-input>
|
|
|
+ <el-input
|
|
|
+ placeholder="00:00:00"
|
|
|
+ v-model="form.graduals[item[1].measureIndex]"
|
|
|
+ ></el-input>
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -256,73 +309,44 @@
|
|
|
:key="index"
|
|
|
>
|
|
|
<el-row>
|
|
|
- <el-col :span="12">
|
|
|
+ <!-- <el-col :span="12">
|
|
|
+
|
|
|
+ </el-col> -->
|
|
|
+ <!-- <el-col :span="12">
|
|
|
+
|
|
|
+ </el-col> -->
|
|
|
+ <el-col :span="12" v-if="partListNames.length > 1">
|
|
|
<el-form-item
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.subjectId`"
|
|
|
- label="声部"
|
|
|
+ label="所属轨道"
|
|
|
+ :prop="`sysMusicScoreAccompaniments.${index}.track`"
|
|
|
+ :rules="[{ required: true, message: '请选择所属轨道' }]"
|
|
|
>
|
|
|
- <!-- :rules="[{required: true, message: '请选择声部'}]" -->
|
|
|
<el-select
|
|
|
style="width: 100% !important"
|
|
|
- v-model="song.subjectId"
|
|
|
+ v-model="song.track"
|
|
|
clearable
|
|
|
- placeholder="请选择声部"
|
|
|
+ placeholder="请选择轨道"
|
|
|
>
|
|
|
<el-option
|
|
|
- v-for="item in selects.subjects"
|
|
|
- :value="item.id"
|
|
|
- :label="item.name"
|
|
|
- :key="item.id"
|
|
|
- :disabled="hasSubjectId(item.id)"
|
|
|
+ v-for="item in partListNames"
|
|
|
+ :value="item"
|
|
|
+ :label="item"
|
|
|
+ :key="item"
|
|
|
+ :disabled="hasPartName(item)"
|
|
|
></el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.speed`"
|
|
|
- label="速度"
|
|
|
- :rules="[{ required: true, message: '请输入速度' }]"
|
|
|
- >
|
|
|
- <el-input
|
|
|
- type="number"
|
|
|
- placeholder="请输入速度"
|
|
|
- v-model="song.speed"
|
|
|
- />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.isShowFingering`"
|
|
|
- label="指法展示"
|
|
|
- :rules="[{ required: true, message: '请选择是否展示指法' }]"
|
|
|
- >
|
|
|
- <el-select
|
|
|
- style="width: 100% !important"
|
|
|
- v-model="song.isShowFingering"
|
|
|
- placeholder="请选择是否展示指法"
|
|
|
- >
|
|
|
- <el-option :value="true" label="是"></el-option>
|
|
|
- <el-option :value="false" label="否"></el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.memo`"
|
|
|
- label="描述"
|
|
|
- >
|
|
|
- <el-input placeholder="请输入描述" v-model="song.memo" />
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12" v-if="form.sysMusicScore.isOpenMetronome ===1">
|
|
|
- <el-form-item
|
|
|
|
|
|
+ <el-col :span="12" v-if="form.sysMusicScore.isOpenMetronome === 1">
|
|
|
+ <el-form-item
|
|
|
label="原音(不含节拍器)"
|
|
|
:prop="`sysMusicScoreAccompaniments.${index}.mp3Url`"
|
|
|
:rules="[
|
|
|
{
|
|
|
- required: form.sysMusicScore.isOpenMetronome ? form.sysMusicScore.playMode === 'MP3' : false,
|
|
|
+ required: form.sysMusicScore.isOpenMetronome
|
|
|
+ ? form.sysMusicScore.playMode === 'MP3'
|
|
|
+ : false,
|
|
|
message: '请上传原音(不含节拍器)',
|
|
|
},
|
|
|
]"
|
|
@@ -331,7 +355,7 @@
|
|
|
tips="仅支持上传 mp3/aac 格式音频文件"
|
|
|
accept=".mp3, .aac"
|
|
|
v-model="song.mp3Url"
|
|
|
- bucket_name="cloud-coach"
|
|
|
+ bucket_name="cloud-coach"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
@@ -341,7 +365,9 @@
|
|
|
:prop="`sysMusicScoreAccompaniments.${index}.metronomeMp3Url`"
|
|
|
:rules="[
|
|
|
{
|
|
|
- required: form.sysMusicScore.isOpenMetronome ? false : form.sysMusicScore.playMode === 'MP3',
|
|
|
+ required: form.sysMusicScore.isOpenMetronome
|
|
|
+ ? false
|
|
|
+ : form.sysMusicScore.playMode === 'MP3',
|
|
|
message: '原音(含节拍器)',
|
|
|
},
|
|
|
]"
|
|
@@ -350,49 +376,28 @@
|
|
|
tips="仅支持上传 mp3/aac 格式音频文件"
|
|
|
accept=".mp3, .aac"
|
|
|
v-model="song.metronomeMp3Url"
|
|
|
- bucket_name="cloud-coach"
|
|
|
+ bucket_name="cloud-coach"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
<el-row>
|
|
|
- <el-col :span="12">
|
|
|
+ <el-col :span="24">
|
|
|
<el-form-item
|
|
|
- label="MusicXML"
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.xmlUrl`"
|
|
|
- :rules="[{ required: true, message: '请选择MusicXML文件' }]"
|
|
|
+ :prop="`sysMusicScoreAccompaniments.${index}.memo`"
|
|
|
+ label="描述"
|
|
|
>
|
|
|
- <singe-file-upload
|
|
|
- tips="仅支持上传 xml 格式文件"
|
|
|
- accept=".xml"
|
|
|
- v-model="song.xmlUrl"
|
|
|
- @inputFile="inputFile"
|
|
|
- bucket_name="cloud-coach"
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ :rows="2"
|
|
|
+ placeholder="请输入描述"
|
|
|
+ v-model="song.memo"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12" v-if="partListNames.length > 1">
|
|
|
- <el-form-item
|
|
|
- label="所属轨道"
|
|
|
- :prop="`sysMusicScoreAccompaniments.${index}.track`"
|
|
|
- :rules="[{ required: true, message: '请选择所属轨道' }]"
|
|
|
- >
|
|
|
- <el-select
|
|
|
- style="width: 100% !important"
|
|
|
- v-model="song.track"
|
|
|
- clearable
|
|
|
- placeholder="请选择轨道"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="item in partListNames"
|
|
|
- :value="item"
|
|
|
- :label="item"
|
|
|
- :key="item"
|
|
|
- :disabled="hasPartName(item)"
|
|
|
- ></el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
+ <!-- <el-col :span="12">
|
|
|
+
|
|
|
+ </el-col> -->
|
|
|
</el-row>
|
|
|
<el-button
|
|
|
class="file-remove"
|
|
@@ -417,18 +422,18 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
<script>
|
|
|
-import axios from 'axios'
|
|
|
+import axios from "axios";
|
|
|
import { Add, Update, queryPageSysExam, queryTree } from "../api";
|
|
|
import { getAllmemberRank } from "@/views/resetTeaming/api";
|
|
|
const initailExtConfigJson = {
|
|
|
- repeatedBeats: 0
|
|
|
-}
|
|
|
+ repeatedBeats: 0,
|
|
|
+};
|
|
|
export default {
|
|
|
props: ["detail", "type"],
|
|
|
data() {
|
|
|
return {
|
|
|
gradual: null,
|
|
|
- xmlFirstSpeed: '',
|
|
|
+ xmlFirstSpeed: "",
|
|
|
partListNames: [],
|
|
|
tree: [],
|
|
|
extConfigJson: {},
|
|
@@ -451,7 +456,11 @@ export default {
|
|
|
renderFrom: "",
|
|
|
playMode: "MP3",
|
|
|
enableEvaluation: 1,
|
|
|
- extConfigJson: "{}"
|
|
|
+ extConfigJson: "{}",
|
|
|
+ subjectId:null,
|
|
|
+ speed:'',
|
|
|
+ xmlUrl:null,
|
|
|
+ isShowFingering:null,
|
|
|
},
|
|
|
sysMusicScoreAccompaniments: [
|
|
|
{
|
|
@@ -461,7 +470,7 @@ export default {
|
|
|
xmlUrl: "",
|
|
|
isShowFingering: true,
|
|
|
mome: "",
|
|
|
- track: ""
|
|
|
+ track: "",
|
|
|
},
|
|
|
],
|
|
|
delExamSongAccompanimentIds: [],
|
|
@@ -481,12 +490,12 @@ export default {
|
|
|
try {
|
|
|
this.extConfigJson = JSON.parse(this.detail.extConfigJson);
|
|
|
} catch (error) {
|
|
|
- this.extConfigJson = {...initailExtConfigJson}
|
|
|
+ this.extConfigJson = { ...initailExtConfigJson };
|
|
|
}
|
|
|
this.form.repeatedBeats = this.extConfigJson.repeatedBeats;
|
|
|
this.form.graduals = this.extConfigJson.gradualTimes || {};
|
|
|
this.$set(this.form, "sysMusicScore", {
|
|
|
- isOpenMetronome:Number(this.detail.isOpenMetronome),
|
|
|
+ isOpenMetronome: Number(this.detail.isOpenMetronome),
|
|
|
name: this.detail.name,
|
|
|
url: this.detail.url,
|
|
|
midiUrl: this.detail.midiUrl,
|
|
@@ -506,9 +515,11 @@ export default {
|
|
|
} else {
|
|
|
this.form.rankIdType = 0;
|
|
|
}
|
|
|
- const xmlres = await axios(this.detail.xmlUrl)
|
|
|
- this.gradual = getGradualLengthByXml(xmlres.data).filter(item => item.length === 2)
|
|
|
- this.partListNames = this.getPartListNames(xmlres.data)
|
|
|
+ const xmlres = await axios(this.detail.xmlUrl);
|
|
|
+ this.gradual = getGradualLengthByXml(xmlres.data).filter(
|
|
|
+ (item) => item.length === 2
|
|
|
+ );
|
|
|
+ this.partListNames = this.getPartListNames(xmlres.data);
|
|
|
this.FeatchDetailList();
|
|
|
} else {
|
|
|
// 新增条件下默认设置为收费
|
|
@@ -518,40 +529,65 @@ export default {
|
|
|
},
|
|
|
methods: {
|
|
|
getPartListNames(xml) {
|
|
|
- if (!xml) return []
|
|
|
- const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
|
|
|
- const partList = xmlParse.getElementsByTagName('part-list')?.[0]?.getElementsByTagName('score-part') || []
|
|
|
- const partListNames = Array.from(partList).map(item => item.getElementsByTagName('part-name')?.[0].textContent || '')
|
|
|
- this.xmlFirstSpeed = xmlParse.getElementsByTagName('per-minute')?.[0]?.textContent || ''
|
|
|
- return partListNames.filter(text => text.toLocaleUpperCase() !== 'COMMON')
|
|
|
+ if (!xml) return [];
|
|
|
+ const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
|
|
|
+ const partList =
|
|
|
+ xmlParse
|
|
|
+ .getElementsByTagName("part-list")?.[0]
|
|
|
+ ?.getElementsByTagName("score-part") || [];
|
|
|
+ const partListNames = Array.from(partList).map(
|
|
|
+ (item) => item.getElementsByTagName("part-name")?.[0].textContent || ""
|
|
|
+ );
|
|
|
+
|
|
|
+ this.xmlFirstSpeed =
|
|
|
+ xmlParse.getElementsByTagName("per-minute")?.[0]?.textContent || "";
|
|
|
+
|
|
|
+ // this.form.sysMusicScore.speed = this.xmlFirstSpeed;
|
|
|
+ this.$set(this.form.sysMusicScore,'speed',this.xmlFirstSpeed)
|
|
|
+ return partListNames.filter(
|
|
|
+ (text) => text.toLocaleUpperCase() !== "COMMON"
|
|
|
+ );
|
|
|
},
|
|
|
inputFile(file) {
|
|
|
- const xmlRead = new FileReader()
|
|
|
- xmlRead.onload = res => {
|
|
|
- this.partListNames = this.getPartListNames(res.target.result)
|
|
|
- this.gradual = getGradualLengthByXml(res.target.result).filter(item => item.length === 2)
|
|
|
+ const xmlRead = new FileReader();
|
|
|
+ xmlRead.onload = (res) => {
|
|
|
+ this.partListNames = this.getPartListNames(res.target.result);
|
|
|
+ this.gradual = getGradualLengthByXml(res.target.result).filter(
|
|
|
+ (item) => item.length === 2
|
|
|
+ );
|
|
|
+
|
|
|
+
|
|
|
for (let j = 0; j < this.form.sysMusicScoreAccompaniments.length; j++) {
|
|
|
- this.form.sysMusicScoreAccompaniments[j].track = this.partListNames[j]
|
|
|
+ this.form.sysMusicScoreAccompaniments[j].track =
|
|
|
+ this.partListNames[j];
|
|
|
if (!this.form.sysMusicScoreAccompaniments[j].speed) {
|
|
|
- this.form.sysMusicScoreAccompaniments[j].speed = this.xmlFirstSpeed
|
|
|
+ this.form.sysMusicScoreAccompaniments[j].speed = this.xmlFirstSpeed;
|
|
|
}
|
|
|
- this.$set(this.form, 'sysMusicScoreAccompaniments', this.form.sysMusicScoreAccompaniments)
|
|
|
+ this.$set(
|
|
|
+ this.form,
|
|
|
+ "sysMusicScoreAccompaniments",
|
|
|
+ this.form.sysMusicScoreAccompaniments
|
|
|
+ );
|
|
|
}
|
|
|
- for (let index = this.form.sysMusicScoreAccompaniments.length; index < this.partListNames.length; index++) {
|
|
|
- const part = this.partListNames[index]
|
|
|
+ for (
|
|
|
+ let index = this.form.sysMusicScoreAccompaniments.length;
|
|
|
+ index < this.partListNames.length;
|
|
|
+ index++
|
|
|
+ ) {
|
|
|
+ const part = this.partListNames[index];
|
|
|
const sysData = {
|
|
|
...this.form.sysMusicScoreAccompaniments[0],
|
|
|
metronomeMp3Url: "",
|
|
|
mp3Url: "",
|
|
|
track: part,
|
|
|
- }
|
|
|
+ };
|
|
|
if (!sysData.speed) {
|
|
|
- sysData.speed = this.xmlFirstSpeed
|
|
|
+ sysData.speed = this.xmlFirstSpeed;
|
|
|
}
|
|
|
- this.createSys(sysData)
|
|
|
+ this.createSys(sysData);
|
|
|
}
|
|
|
- }
|
|
|
- xmlRead.readAsText(file.raw)
|
|
|
+ };
|
|
|
+ xmlRead.readAsText(file.raw);
|
|
|
},
|
|
|
rankChange(value) {
|
|
|
if (value) {
|
|
@@ -595,15 +631,18 @@ export default {
|
|
|
try {
|
|
|
const res = await queryTree();
|
|
|
this.tree = res.data;
|
|
|
- this.formatTree(this.tree)
|
|
|
+ this.formatTree(this.tree);
|
|
|
} catch (error) {}
|
|
|
},
|
|
|
- formatTree(data){
|
|
|
- for(let i of data) {
|
|
|
- if(i.sysMusicScoreCategoriesList && i.sysMusicScoreCategoriesList.length > 0) {
|
|
|
- this.formatTree(i.sysMusicScoreCategoriesList, i)
|
|
|
+ formatTree(data) {
|
|
|
+ for (let i of data) {
|
|
|
+ if (
|
|
|
+ i.sysMusicScoreCategoriesList &&
|
|
|
+ i.sysMusicScoreCategoriesList.length > 0
|
|
|
+ ) {
|
|
|
+ this.formatTree(i.sysMusicScoreCategoriesList, i);
|
|
|
} else {
|
|
|
- i.sysMusicScoreCategoriesList = null
|
|
|
+ i.sysMusicScoreCategoriesList = null;
|
|
|
}
|
|
|
}
|
|
|
},
|
|
@@ -618,17 +657,29 @@ export default {
|
|
|
item.subjectId = null;
|
|
|
}
|
|
|
});
|
|
|
+ if(result.length >0){
|
|
|
+ console.log(result[0].speed)
|
|
|
+ this.$set(this.form.sysMusicScore, "subjectId", result[0].subjectId);
|
|
|
+ this.$set(this.form.sysMusicScore, "speed", result[0].speed);
|
|
|
+ this.$set(this.form.sysMusicScore, "xmlUrl", result[0].xmlUrl);
|
|
|
+ this.$set(this.form.sysMusicScore, "isShowFingering", result[0].isShowFingering);
|
|
|
+ }
|
|
|
this.$set(this.form, "sysMusicScoreAccompaniments", result);
|
|
|
} catch (error) {}
|
|
|
},
|
|
|
createSys(initData) {
|
|
|
- this.form.sysMusicScoreAccompaniments.push(Object.assign({
|
|
|
- subjectId: "",
|
|
|
- speed: "",
|
|
|
- mp3Url: "",
|
|
|
- xmlUrl: "",
|
|
|
- track: "",
|
|
|
- }, (initData || {})));
|
|
|
+ this.form.sysMusicScoreAccompaniments.push(
|
|
|
+ Object.assign(
|
|
|
+ {
|
|
|
+ subjectId: "",
|
|
|
+ speed: "",
|
|
|
+ mp3Url: "",
|
|
|
+ xmlUrl: "",
|
|
|
+ track: "",
|
|
|
+ },
|
|
|
+ initData || {}
|
|
|
+ )
|
|
|
+ );
|
|
|
},
|
|
|
async removeSys(index) {
|
|
|
try {
|
|
@@ -661,6 +712,13 @@ export default {
|
|
|
async submit() {
|
|
|
this.$refs.form.validate(async (valid) => {
|
|
|
if (valid) {
|
|
|
+ // 提交前平铺 速度,声部,XML,isShowFingering
|
|
|
+ this.form.sysMusicScoreAccompaniments.forEach(item=>{
|
|
|
+ item.speed = this.form.sysMusicScore.speed
|
|
|
+ item.subjectId = this.form.sysMusicScore.subjectId
|
|
|
+ item.spexmlUrled = this.form.sysMusicScore.spexmlUrled
|
|
|
+ item.isShowFingering = this.form.sysMusicScore.isShowFingering
|
|
|
+ })
|
|
|
if (!this.detail) {
|
|
|
await Add({
|
|
|
...this.form,
|
|
@@ -710,43 +768,46 @@ export default {
|
|
|
* @param ele 指定元素
|
|
|
* @param selectors 选择器
|
|
|
*/
|
|
|
- const getNextNote = (ele, selectors) => {
|
|
|
- let index = 0
|
|
|
- const parentEle = ele.closest(selectors)
|
|
|
- let pointer = parentEle
|
|
|
- const measure = parentEle?.closest('measure')
|
|
|
- let siblingNote = null
|
|
|
+const getNextNote = (ele, selectors) => {
|
|
|
+ let index = 0;
|
|
|
+ const parentEle = ele.closest(selectors);
|
|
|
+ let pointer = parentEle;
|
|
|
+ const measure = parentEle?.closest("measure");
|
|
|
+ let siblingNote = null;
|
|
|
// 查找到相邻的第一个note元素
|
|
|
while (!siblingNote && index < (measure?.childNodes.length || 50)) {
|
|
|
- index++
|
|
|
- if (pointer?.nextElementSibling?.tagName === 'note') {
|
|
|
- siblingNote = pointer?.nextElementSibling
|
|
|
+ index++;
|
|
|
+ if (pointer?.nextElementSibling?.tagName === "note") {
|
|
|
+ siblingNote = pointer?.nextElementSibling;
|
|
|
}
|
|
|
- pointer = pointer?.nextElementSibling
|
|
|
+ pointer = pointer?.nextElementSibling;
|
|
|
}
|
|
|
- return siblingNote
|
|
|
-}
|
|
|
+ return siblingNote;
|
|
|
+};
|
|
|
|
|
|
export const onlyVisible = (xml, partIndex) => {
|
|
|
- if (!xml) return ''
|
|
|
- const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
|
|
|
- const partList = xmlParse.getElementsByTagName('part-list')?.[0]?.getElementsByTagName('score-part') || []
|
|
|
+ if (!xml) return "";
|
|
|
+ const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
|
|
|
+ const partList =
|
|
|
+ xmlParse
|
|
|
+ .getElementsByTagName("part-list")?.[0]
|
|
|
+ ?.getElementsByTagName("score-part") || [];
|
|
|
// const partListNames = Array.from(partList).map(item => item.getElementsByTagName('part-name')?.[0].textContent || '')
|
|
|
- const parts = xmlParse.getElementsByTagName('part')
|
|
|
+ const parts = xmlParse.getElementsByTagName("part");
|
|
|
// const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true)
|
|
|
// const firstMeasures = [...Array.from(parts[0]?.getElementsByTagName('measure') || [])]
|
|
|
// const metronomes = [...Array.from(parts[0]?.getElementsByTagName('metronome') || [])]
|
|
|
// const words = [...Array.from(parts[0]?.getElementsByTagName('words') || [])]
|
|
|
// const codas = [...Array.from(parts[0]?.getElementsByTagName('coda') || [])]
|
|
|
// const rehearsals = [...Array.from(parts[0]?.getElementsByTagName('rehearsal') || [])]
|
|
|
- const visiblePartInfo = partList[partIndex]
|
|
|
+ const visiblePartInfo = partList[partIndex];
|
|
|
// console.log(visiblePartInfo, partIndex)
|
|
|
// state.partListNames = partListNames
|
|
|
if (visiblePartInfo) {
|
|
|
- const id = visiblePartInfo.getAttribute('id')
|
|
|
- Array.from(parts).forEach(part => {
|
|
|
- if (part && part.getAttribute('id') !== id) {
|
|
|
- part.parentNode?.removeChild(part)
|
|
|
+ const id = visiblePartInfo.getAttribute("id");
|
|
|
+ Array.from(parts).forEach((part) => {
|
|
|
+ if (part && part.getAttribute("id") !== id) {
|
|
|
+ part.parentNode?.removeChild(part);
|
|
|
// 不等于第一行才添加避免重复添加
|
|
|
} else {
|
|
|
// words.forEach(word => {
|
|
@@ -763,101 +824,101 @@ export const onlyVisible = (xml, partIndex) => {
|
|
|
}
|
|
|
|
|
|
// 最后一个小节的结束线元素不在最后 调整
|
|
|
- if (part && part.getAttribute('id') === id) {
|
|
|
- const barlines = part.getElementsByTagName('barline')
|
|
|
- const lastParent = barlines[barlines.length - 1]?.parentElement
|
|
|
- if (lastParent?.lastElementChild?.tagName !== 'barline') {
|
|
|
- const children = lastParent?.children || []
|
|
|
+ if (part && part.getAttribute("id") === id) {
|
|
|
+ const barlines = part.getElementsByTagName("barline");
|
|
|
+ const lastParent = barlines[barlines.length - 1]?.parentElement;
|
|
|
+ if (lastParent?.lastElementChild?.tagName !== "barline") {
|
|
|
+ const children = lastParent?.children || [];
|
|
|
for (let el of children) {
|
|
|
- if (el.tagName === 'barline') {
|
|
|
+ if (el.tagName === "barline") {
|
|
|
// 将结束线元素放到最后
|
|
|
- lastParent?.appendChild(el)
|
|
|
- break
|
|
|
+ lastParent?.appendChild(el);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- })
|
|
|
- Array.from(partList).forEach(part => {
|
|
|
- if (part && part.getAttribute('id') !== id) {
|
|
|
- part.parentNode?.removeChild(part)
|
|
|
+ });
|
|
|
+ Array.from(partList).forEach((part) => {
|
|
|
+ if (part && part.getAttribute("id") !== id) {
|
|
|
+ part.parentNode?.removeChild(part);
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
// 处理装饰音问题
|
|
|
- const notes = xmlParse.getElementsByTagName('note')
|
|
|
+ const notes = xmlParse.getElementsByTagName("note");
|
|
|
const getNextvNoteDuration = (i) => {
|
|
|
- let nextNote = notes[i + 1]
|
|
|
+ let nextNote = notes[i + 1];
|
|
|
// 可能存在多个装饰音问题,取下一个非装饰音时值
|
|
|
for (let index = i; index < notes.length; index++) {
|
|
|
const note = notes[index];
|
|
|
- if (!note.getElementsByTagName('grace')?.length) {
|
|
|
- nextNote = note
|
|
|
- break
|
|
|
+ if (!note.getElementsByTagName("grace")?.length) {
|
|
|
+ nextNote = note;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- const nextNoteDuration = nextNote?.getElementsByTagName('duration')[0]
|
|
|
- return nextNoteDuration
|
|
|
- }
|
|
|
+ const nextNoteDuration = nextNote?.getElementsByTagName("duration")[0];
|
|
|
+ return nextNoteDuration;
|
|
|
+ };
|
|
|
Array.from(notes).forEach((note, i) => {
|
|
|
- const graces = note.getElementsByTagName('grace')
|
|
|
+ const graces = note.getElementsByTagName("grace");
|
|
|
if (graces && graces.length) {
|
|
|
// if (i !== 0) {
|
|
|
- note.appendChild(getNextvNoteDuration(i)?.cloneNode(true))
|
|
|
+ note.appendChild(getNextvNoteDuration(i)?.cloneNode(true));
|
|
|
// }
|
|
|
}
|
|
|
- })
|
|
|
+ });
|
|
|
}
|
|
|
// console.log(new XMLSerializer().serializeToString(xmlParse))
|
|
|
- return new XMLSerializer().serializeToString(xmlParse)
|
|
|
-}
|
|
|
+ return new XMLSerializer().serializeToString(xmlParse);
|
|
|
+};
|
|
|
|
|
|
const speedInfo = {
|
|
|
- 'rall.': 1.333333333,
|
|
|
- 'poco rit.': 1.333333333,
|
|
|
- 'rit.': 1.333333333,
|
|
|
- 'molto rit.': 1.333333333,
|
|
|
- 'molto rall': 1.333333333,
|
|
|
+ "rall.": 1.333333333,
|
|
|
+ "poco rit.": 1.333333333,
|
|
|
+ "rit.": 1.333333333,
|
|
|
+ "molto rit.": 1.333333333,
|
|
|
+ "molto rall": 1.333333333,
|
|
|
lentando: 1.333333333,
|
|
|
allargando: 1.333333333,
|
|
|
morendo: 1.333333333,
|
|
|
- 'accel.': 0.8,
|
|
|
+ "accel.": 0.8,
|
|
|
calando: 2,
|
|
|
- 'poco accel.': 0.8,
|
|
|
-}
|
|
|
+ "poco accel.": 0.8,
|
|
|
+};
|
|
|
|
|
|
/**
|
|
|
* 按照xml进行减慢速度的计算
|
|
|
* @param xml 始终按照第一分谱进行减慢速度的计算
|
|
|
*/
|
|
|
- export function getGradualLengthByXml (xml) {
|
|
|
- const firstPartXml = onlyVisible(xml, 0)
|
|
|
- const xmlParse = new DOMParser().parseFromString(firstPartXml, 'text/xml')
|
|
|
- const measures = Array.from(xmlParse.querySelectorAll('measure'))
|
|
|
- const notes = Array.from(xmlParse.querySelectorAll('note'))
|
|
|
- const words = Array.from(xmlParse.querySelectorAll('words'))
|
|
|
- const metronomes = Array.from(xmlParse.querySelectorAll('metronome'))
|
|
|
+export function getGradualLengthByXml(xml) {
|
|
|
+ const firstPartXml = onlyVisible(xml, 0);
|
|
|
+ const xmlParse = new DOMParser().parseFromString(firstPartXml, "text/xml");
|
|
|
+ const measures = Array.from(xmlParse.querySelectorAll("measure"));
|
|
|
+ const notes = Array.from(xmlParse.querySelectorAll("note"));
|
|
|
+ const words = Array.from(xmlParse.querySelectorAll("words"));
|
|
|
+ const metronomes = Array.from(xmlParse.querySelectorAll("metronome"));
|
|
|
|
|
|
- const eles = []
|
|
|
+ const eles = [];
|
|
|
|
|
|
for (const ele of [...words, ...metronomes]) {
|
|
|
- const note = getNextNote(ele, 'direction')
|
|
|
+ const note = getNextNote(ele, "direction");
|
|
|
// console.log(ele, note)
|
|
|
if (note) {
|
|
|
- const measure = note?.closest('measure')
|
|
|
- const measureNotes = Array.from(measure.querySelectorAll('note'))
|
|
|
+ const measure = note?.closest("measure");
|
|
|
+ const measureNotes = Array.from(measure.querySelectorAll("note"));
|
|
|
|
|
|
const noteInMeasureIndex = Array.from(measure.childNodes)
|
|
|
- .filter((item) => item.nodeName === 'note')
|
|
|
- .findIndex((item) => item === note)
|
|
|
+ .filter((item) => item.nodeName === "note")
|
|
|
+ .findIndex((item) => item === note);
|
|
|
|
|
|
- let allDuration = 0
|
|
|
- let leftDuration = 0
|
|
|
+ let allDuration = 0;
|
|
|
+ let leftDuration = 0;
|
|
|
for (let i = 0; i < measureNotes.length; i++) {
|
|
|
- const n = measureNotes[i]
|
|
|
- const duration = +(n.querySelector('duration')?.textContent || '0')
|
|
|
- allDuration += duration
|
|
|
+ const n = measureNotes[i];
|
|
|
+ const duration = +(n.querySelector("duration")?.textContent || "0");
|
|
|
+ allDuration += duration;
|
|
|
if (i < noteInMeasureIndex) {
|
|
|
- leftDuration = allDuration
|
|
|
+ leftDuration = allDuration;
|
|
|
}
|
|
|
}
|
|
|
eles.push({
|
|
@@ -869,16 +930,16 @@ const speedInfo = {
|
|
|
type: ele.tagName,
|
|
|
allDuration,
|
|
|
leftDuration,
|
|
|
- })
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const gradualNotes = []
|
|
|
- eles.sort((a, b) => a.index - b.index)
|
|
|
- const keys = Object.keys(speedInfo).map(w => w.toLocaleLowerCase())
|
|
|
+ const gradualNotes = [];
|
|
|
+ eles.sort((a, b) => a.index - b.index);
|
|
|
+ const keys = Object.keys(speedInfo).map((w) => w.toLocaleLowerCase());
|
|
|
for (const ele of eles) {
|
|
|
- const textContent = ele.textContent?.toLocaleLowerCase().trim()
|
|
|
- if (ele.type === 'words' && keys.includes(textContent)) {
|
|
|
+ const textContent = ele.textContent?.toLocaleLowerCase().trim();
|
|
|
+ if (ele.type === "words" && keys.includes(textContent)) {
|
|
|
gradualNotes.push([
|
|
|
{
|
|
|
start: ele.index,
|
|
@@ -888,13 +949,13 @@ const speedInfo = {
|
|
|
leftDuration: ele.leftDuration,
|
|
|
type: textContent,
|
|
|
},
|
|
|
- ])
|
|
|
+ ]);
|
|
|
}
|
|
|
if (
|
|
|
- ele.type === 'metronome' ||
|
|
|
- (ele.type === 'words' && textContent === 'a tempo')
|
|
|
+ ele.type === "metronome" ||
|
|
|
+ (ele.type === "words" && textContent === "a tempo")
|
|
|
) {
|
|
|
- const indexOf = gradualNotes.findIndex((item) => item.length === 1)
|
|
|
+ const indexOf = gradualNotes.findIndex((item) => item.length === 1);
|
|
|
if (indexOf > -1 && ele.index > gradualNotes[indexOf]?.[0].start) {
|
|
|
gradualNotes[indexOf][1] = {
|
|
|
start: ele.index,
|
|
@@ -903,11 +964,11 @@ const speedInfo = {
|
|
|
allDuration: ele.allDuration,
|
|
|
leftDuration: ele.leftDuration,
|
|
|
type: textContent,
|
|
|
- }
|
|
|
+ };
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- return gradualNotes
|
|
|
+ return gradualNotes;
|
|
|
}
|
|
|
</script>
|
|
|
<style lang="less" scoped>
|