|
@@ -0,0 +1,1076 @@
|
|
|
+import { defineComponent } from 'vue'
|
|
|
+import {
|
|
|
+ Button,
|
|
|
+ Field,
|
|
|
+ Sticky,
|
|
|
+ Form,
|
|
|
+ Tag,
|
|
|
+ Radio,
|
|
|
+ RadioGroup,
|
|
|
+ Popup,
|
|
|
+ Icon,
|
|
|
+ Empty,
|
|
|
+ Picker,
|
|
|
+ Toast,
|
|
|
+ NoticeBar
|
|
|
+} from 'vant'
|
|
|
+import ColFieldGroup from '@/components/col-field-group'
|
|
|
+// import { MusicType } from 'src/teacher/music/list/item.d'
|
|
|
+import SubjectModel from '@/business-components/subject-list'
|
|
|
+import ColField from '@/components/col-field'
|
|
|
+
|
|
|
+import {
|
|
|
+ teachercanEvaluateType,
|
|
|
+ teacherChargeType,
|
|
|
+ teachershowAudiType,
|
|
|
+ teachershowFingeringType,
|
|
|
+ teachershowHasBeatType,
|
|
|
+ teacherNotationType,
|
|
|
+ teacherStyleType,
|
|
|
+ teacherExquisiteType
|
|
|
+} from '@/constant/music'
|
|
|
+import { getXmlInfo, FormatXMLInfo } from '@/helpers/music-xml'
|
|
|
+import Upload from './upload'
|
|
|
+import styles from './index.module.less'
|
|
|
+import SelectTag from '@/views/music/search/select-tag'
|
|
|
+import { browser } from '@/helpers/utils'
|
|
|
+import { postMessage } from '@/helpers/native-message'
|
|
|
+import { teacherState } from '@/teacher/teacher-cert/teacherState'
|
|
|
+import request from '@/helpers/request'
|
|
|
+import requestOrigin from 'umi-request'
|
|
|
+import UploadIcon from './upload.svg'
|
|
|
+import ColUpload from '@/components/col-upload'
|
|
|
+import { verifyNumberIntegerAndFloat } from '@/helpers/toolsValidate'
|
|
|
+import { state } from '@/state'
|
|
|
+import ColHeader from '@/components/col-header'
|
|
|
+
|
|
|
+export type BackgroundMp3 = {
|
|
|
+ url?: string
|
|
|
+ track?: string
|
|
|
+}
|
|
|
+
|
|
|
+// 校验函数返回 true 表示校验通过,false 表示不通过
|
|
|
+export const validator = val => {
|
|
|
+ console.log(val)
|
|
|
+ if (Number(val) <= 0) {
|
|
|
+ return '收费金额必须大于0'
|
|
|
+ } else {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'MusicUpload',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ reason: '',
|
|
|
+ audioType: 'MP3',
|
|
|
+ xmlFileUrl: '',
|
|
|
+ xmlFileLoading: false,
|
|
|
+ midiUrl: '',
|
|
|
+ midiLoading: false,
|
|
|
+ mp3Url: '',
|
|
|
+ bgmp3Url: '',
|
|
|
+ mp3Loading: false,
|
|
|
+ bgmp3Loading: false,
|
|
|
+ musicSheetName: '',
|
|
|
+ composer: '',
|
|
|
+ speed: '',
|
|
|
+ hasBeat: 0,
|
|
|
+ titleImg: '',
|
|
|
+ accompanimentType: 'HOMEMODE',
|
|
|
+ chargeType: 0,
|
|
|
+ paymentType: '',
|
|
|
+ showFingering: 1,
|
|
|
+ canEvaluate: 1,
|
|
|
+ notation: 1,
|
|
|
+ musicPrice: '',
|
|
|
+ subJectIndex: 0,
|
|
|
+ selectTagVisible: false,
|
|
|
+ subJectVisible: false,
|
|
|
+ tags: [] as string[],
|
|
|
+ tagsNames: [] as Array<{ [id in string]: string }>,
|
|
|
+ formated: {} as FormatXMLInfo,
|
|
|
+ tagVisibility: false,
|
|
|
+ subjectListres: [] as any[],
|
|
|
+ subjectListNames: {} as any,
|
|
|
+ selectedSubjectList: null as any,
|
|
|
+ vlewSubjectList: null as any,
|
|
|
+ submitLoading: false,
|
|
|
+ showPicker: false,
|
|
|
+ music_sheet_service_fee: 0,
|
|
|
+ music_account_period: 0,
|
|
|
+ exquisiteFlag: 0,
|
|
|
+ backgroundMp3s: [
|
|
|
+ {
|
|
|
+ url: '',
|
|
|
+ track: ''
|
|
|
+ }
|
|
|
+ ] as BackgroundMp3[],
|
|
|
+ checked: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ formated() {
|
|
|
+ this.mergeXmlData(this.formated)
|
|
|
+ },
|
|
|
+ chargeType() {
|
|
|
+ if (this.chargeType === 0) {
|
|
|
+ this.musicPrice = ''
|
|
|
+ this.paymentType = ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ choiceSubjectIds() {
|
|
|
+ // 选择的科目编号
|
|
|
+ let ids = teacherState.teacherCert.subjectId
|
|
|
+ ? teacherState.teacherCert.subjectId.split(',')
|
|
|
+ : []
|
|
|
+ ids = ids.map((item: any) => Number(item))
|
|
|
+ return ids
|
|
|
+ },
|
|
|
+ subjectList() {
|
|
|
+ // 学科列表
|
|
|
+ const subjects: any = this.subjectListres || []
|
|
|
+ return subjects
|
|
|
+ },
|
|
|
+ choiceSubject() {
|
|
|
+ // 选择的科目
|
|
|
+ const tempArr: any[] = []
|
|
|
+ this.subjectList.forEach((parent: any) => {
|
|
|
+ parent.subjects &&
|
|
|
+ parent.subjects.forEach((sub: any) => {
|
|
|
+ if (this.choiceSubjectIds.includes(sub.id)) {
|
|
|
+ tempArr.push(sub as never)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return tempArr
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async mounted() {
|
|
|
+ // 获取基础数据
|
|
|
+ request
|
|
|
+ .get('/api-teacher/sysConfig/queryByParamNameList', {
|
|
|
+ params: {
|
|
|
+ paramNames: 'music_sheet_service_fee,music_account_period'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then((res: any) => {
|
|
|
+ console.log(res, 'res')
|
|
|
+ const data = res.data || []
|
|
|
+ data.forEach((item: any) => {
|
|
|
+ if (item.paramName === 'music_sheet_service_fee') {
|
|
|
+ this.music_sheet_service_fee = item.paramValue
|
|
|
+ } else if (item.paramName === 'music_account_period') {
|
|
|
+ this.music_account_period = item.paramValue
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // console.log(config, 'config')
|
|
|
+ // request
|
|
|
+ // .get('/api-teacher/sysConfig/queryByParamName', {
|
|
|
+ // params: {
|
|
|
+ // paramName: 'music_sheet_service_fee'
|
|
|
+ // }
|
|
|
+ // })
|
|
|
+ // .then(res => (this.music_sheet_service_fee = res.data.paramValue))
|
|
|
+ // if (teacherState.subjectList.length <= 0) {
|
|
|
+ await request.get('/api-teacher/subject/subjectSelect').then(res => {
|
|
|
+ const list: any[] = []
|
|
|
+ for (const item of res.data || []) {
|
|
|
+ const slist: any[] = (item as any).subjects || []
|
|
|
+ list.push(...slist)
|
|
|
+ }
|
|
|
+ this.subjectListres = list
|
|
|
+ this.subjectListNames = this.getSubjectListNames(list)
|
|
|
+ })
|
|
|
+
|
|
|
+ if (this.$route.params.id) {
|
|
|
+ this.setDetail(this.$route.params.id as string)
|
|
|
+ }
|
|
|
+
|
|
|
+ const resVersion = await request.post('/api-teacher/open/appVersion', {
|
|
|
+ data: {
|
|
|
+ platform:
|
|
|
+ state.platformType === 'STUDENT' ? 'ios-student' : 'ios-teacher',
|
|
|
+ version: state.version
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.checked = resVersion.data.check ? true : false
|
|
|
+ // 审核版本金额默认为0
|
|
|
+ if (this.checked) {
|
|
|
+ this.chargeType = 0
|
|
|
+ }
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async setDetail(id: string) {
|
|
|
+ try {
|
|
|
+ const res = await request.get('/api-teacher/music/sheet/detail/' + id)
|
|
|
+ this.chargeType = res.data.paymentType === 'FREE' ? 0 : 2
|
|
|
+ this.paymentType = res.data.paymentType
|
|
|
+ this.showFingering = res.data.showFingering
|
|
|
+ this.canEvaluate = res.data.canEvaluate
|
|
|
+ if (this.chargeType) {
|
|
|
+ this.musicPrice = res.data.musicPrice
|
|
|
+ }
|
|
|
+
|
|
|
+ this.composer = res.data.composer
|
|
|
+ this.musicSheetName = res.data.musicSheetName
|
|
|
+ this.audioType = res.data.audioType
|
|
|
+ this.notation = res.data.notation
|
|
|
+ this.selectedSubjectList = {
|
|
|
+ label: res.data.musicSubject,
|
|
|
+ value: res.data.subjectNames
|
|
|
+ }
|
|
|
+ this.vlewSubjectList = {
|
|
|
+ label: res.data.musicSubject,
|
|
|
+ value: res.data.subjectNames
|
|
|
+ }
|
|
|
+ this.subJectIndex = Object.keys(this.subjectListNames).findIndex(
|
|
|
+ key => key === res.data.musicSubject
|
|
|
+ )
|
|
|
+ const names = res.data.musicTagNames.split(',')
|
|
|
+ this.tags = res.data.musicTag.split(',')
|
|
|
+ this.tags = this.tags.filter((el: any) => {
|
|
|
+ return el != ''
|
|
|
+ })
|
|
|
+
|
|
|
+ for (let i = 0; i < names.length; i++) {
|
|
|
+ this.tagsNames[this.tags[i]] = names[i]
|
|
|
+ }
|
|
|
+ this.exquisiteFlag = res.data.exquisiteFlag
|
|
|
+ this.xmlFileUrl = res.data.xmlFileUrl
|
|
|
+ this.accompanimentType = res.data.accompanimentType
|
|
|
+ this.titleImg = res.data.titleImg
|
|
|
+
|
|
|
+ // this.audioType = res.data.mp3Type
|
|
|
+
|
|
|
+ if (this.audioType === 'MP3') {
|
|
|
+ this.hasBeat =
|
|
|
+ (res.data.audioType === 'MP3' &&
|
|
|
+ res.data.mp3Type === 'MP3_METRONOME') ||
|
|
|
+ res.data.audioType === 'MIDI'
|
|
|
+ ? 1
|
|
|
+ : 0
|
|
|
+ this.mp3Url = res.data.audioFileUrl || res.data.url //res.data.metronomeUrl || res.data.url
|
|
|
+ } else {
|
|
|
+ this.midiUrl = res.data.midiUrl
|
|
|
+ }
|
|
|
+
|
|
|
+ this.backgroundMp3s = (res.data.background || []).map((item, index) => {
|
|
|
+ if (index === 0) {
|
|
|
+ this.bgmp3Url = item.audioFileUrl
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ url: item.audioFileUrl,
|
|
|
+ track: item.track
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.reason = res.data.reason
|
|
|
+
|
|
|
+ console.log(this.bgmp3Url)
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ createSubmitData() {
|
|
|
+ const beatType = this.hasBeat ? 'MP3_METRONOME' : 'MP3'
|
|
|
+ const mp3Type = this.audioType === 'MP3' ? beatType : 'MIDI'
|
|
|
+ return {
|
|
|
+ audioType: this.audioType,
|
|
|
+ sourceType: 'TEACHER',
|
|
|
+ mp3Type,
|
|
|
+ hasBeat: Number(this.hasBeat),
|
|
|
+ accompanimentType: this.accompanimentType,
|
|
|
+ titleImg: this.titleImg,
|
|
|
+ url: this.hasBeat ? '' : this.mp3Url,
|
|
|
+ metronomeUrl: this.hasBeat ? this.mp3Url : '',
|
|
|
+ audioFileUrl: this.mp3Url,
|
|
|
+ showFingering: Number(this.showFingering),
|
|
|
+ musicTag: this.tags.join(','),
|
|
|
+ musicSubject: Number(this.selectedSubjectList?.label) || undefined,
|
|
|
+ musicSheetName: this.musicSheetName,
|
|
|
+ midiUrl: this.midiUrl,
|
|
|
+ notation: Number(this.notation),
|
|
|
+ xmlFileUrl: this.xmlFileUrl,
|
|
|
+ canEvaluate: Number(this.canEvaluate),
|
|
|
+ chargeType: this.chargeType === 0 ? 'FREE' : 'CHARGE',
|
|
|
+ paymentType: this.chargeType === 0 ? 'FREE' : 'CHARGE',
|
|
|
+ exquisiteFlag: this.exquisiteFlag,
|
|
|
+ composer: this.composer,
|
|
|
+ musicPrice: this.chargeType === 0 ? 0 : this.musicPrice, // 当选择免费时,重置金额为0
|
|
|
+ background: this.backgroundMp3s.map(item => ({
|
|
|
+ audioFileUrl: this.bgmp3Url,
|
|
|
+ track: item.track
|
|
|
+ // metronomeUrl: this.hasBeat ? this.bgmp3Url : ''
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async submit(vals: any) {
|
|
|
+ console.log(vals)
|
|
|
+ this.submitLoading = true
|
|
|
+ try {
|
|
|
+ if (this.$route.params.id) {
|
|
|
+ await request.post('/api-teacher/music/sheet/update', {
|
|
|
+ data: {
|
|
|
+ ...this.createSubmitData(),
|
|
|
+ id: this.$route.params.id
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ await request.post('/api-teacher/music/sheet/create', {
|
|
|
+ data: this.createSubmitData()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {}
|
|
|
+
|
|
|
+ Toast('上传成功')
|
|
|
+ setTimeout(() => {
|
|
|
+ postMessage({
|
|
|
+ api: 'back'
|
|
|
+ })
|
|
|
+ this.submitLoading = false
|
|
|
+ }, 800)
|
|
|
+ console.log(vals)
|
|
|
+ },
|
|
|
+ onFormatter(val: any) {
|
|
|
+ return verifyNumberIntegerAndFloat(val)
|
|
|
+ },
|
|
|
+ getSubjectListNames(list) {
|
|
|
+ const data = {}
|
|
|
+ for (const item of list) {
|
|
|
+ data[item.id] = item.name
|
|
|
+ if (item.subjects) {
|
|
|
+ for (const sub of item.subjects) {
|
|
|
+ data[sub.id] = sub.name
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return data
|
|
|
+ },
|
|
|
+ failed() {
|
|
|
+ console.log('failed', this.backgroundMp3s)
|
|
|
+ },
|
|
|
+ mergeXmlData(data: FormatXMLInfo) {
|
|
|
+ this.formated = data
|
|
|
+ // this.backgroundMp3s = data.partNames.map((partName: string) => ({
|
|
|
+ // track: partName
|
|
|
+ // }))
|
|
|
+ if (!this.musicSheetName) {
|
|
|
+ this.musicSheetName = data.title
|
|
|
+ }
|
|
|
+ if (!this.composer) {
|
|
|
+ this.composer = data.composer
|
|
|
+ }
|
|
|
+ // if (!this.speed && data.speed) {
|
|
|
+ // this.speed = '' + data.speed
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ readerFile(file: File) {
|
|
|
+ const reader = new FileReader()
|
|
|
+ reader.onload = () => {
|
|
|
+ const xml = reader.result as string
|
|
|
+ this.formated = getXmlInfo(xml)
|
|
|
+ }
|
|
|
+ reader.readAsText(file)
|
|
|
+ },
|
|
|
+ onChoice(val: any) {
|
|
|
+ this.subJectVisible = false
|
|
|
+ this.selectedSubjectList = [val]
|
|
|
+ },
|
|
|
+ onComfirm(tags: any, names: any) {
|
|
|
+ this.tagsNames = names
|
|
|
+ this.tagVisibility = false
|
|
|
+ const data = Object.values(tags).flat().filter(Boolean) as string[]
|
|
|
+ console.log(data)
|
|
|
+ this.tags = data
|
|
|
+ },
|
|
|
+ naiveXMLFile() {
|
|
|
+ this.xmlFileLoading = true
|
|
|
+ postMessage(
|
|
|
+ { api: 'chooseFile', content: { type: 'xml', bucket: 'cloud-coach' } },
|
|
|
+ evt => {
|
|
|
+ // @ts-ignore
|
|
|
+ this.xmlFileUrl = evt?.fileUrl || this.xmlFileUrl || ''
|
|
|
+ this.xmlFileLoading = false
|
|
|
+ if (this.xmlFileUrl) {
|
|
|
+ requestOrigin(this.xmlFileUrl).then(
|
|
|
+ res => (this.formated = getXmlInfo(res))
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ naiveMidFile() {
|
|
|
+ this.midiLoading = true
|
|
|
+ postMessage(
|
|
|
+ { api: 'chooseFile', content: { type: 'midi', bucket: 'cloud-coach' } },
|
|
|
+ evt => {
|
|
|
+ // @ts-ignore
|
|
|
+ this.midiUrl = evt?.fileUrl || this.midiUrl || ''
|
|
|
+ this.midiLoading = false
|
|
|
+ // this.midiUrl = path
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ naiveMp3File() {
|
|
|
+ this.mp3Loading = true
|
|
|
+ postMessage(
|
|
|
+ { api: 'chooseFile', content: { type: 'mp3', bucket: 'cloud-coach' } },
|
|
|
+ evt => {
|
|
|
+ // @ts-ignore
|
|
|
+ this.mp3Url = evt?.fileUrl || this.mp3Url || ''
|
|
|
+ this.mp3Loading = false
|
|
|
+ // this.midiUrl = path
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ naiveBGMp3File() {
|
|
|
+ this.bgmp3Loading = true
|
|
|
+ postMessage(
|
|
|
+ { api: 'chooseFile', content: { type: 'mp3', bucket: 'cloud-coach' } },
|
|
|
+ evt => {
|
|
|
+ this.bgmp3Url
|
|
|
+ // @ts-ignore
|
|
|
+ this.bgmp3Url = evt?.fileUrl || this.bgmp3Url || ''
|
|
|
+ this.bgmp3Loading = false
|
|
|
+ // this.midiUrl = path
|
|
|
+ }
|
|
|
+ )
|
|
|
+ },
|
|
|
+ fileName(name = '') {
|
|
|
+ return name.split('/').pop()
|
|
|
+ },
|
|
|
+ removeBackground(index: number) {
|
|
|
+ this.backgroundMp3s.splice(index, 1)
|
|
|
+ },
|
|
|
+ onDetail(type: string) {
|
|
|
+ let url = `${location.origin}/teacher/#/registerProtocol`
|
|
|
+
|
|
|
+ if (type === 'question') {
|
|
|
+ url = `${location.origin}/teacher/muic-standard/question.html`
|
|
|
+ } else if (type === 'music') {
|
|
|
+ url = `${location.origin}/teacher/muic-standard/index.html`
|
|
|
+ }
|
|
|
+
|
|
|
+ postMessage({
|
|
|
+ api: 'openWebView',
|
|
|
+ content: {
|
|
|
+ url,
|
|
|
+ orientation: 1,
|
|
|
+ isHideTitle: false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render() {
|
|
|
+ console.log(this.formated)
|
|
|
+ const browserInfo = browser()
|
|
|
+ return (
|
|
|
+ <Form class={styles.form} onSubmit={this.submit} onFailed={this.failed}>
|
|
|
+ <ColHeader />
|
|
|
+ {this.reason && (
|
|
|
+ <NoticeBar wrapable scrollable={false} text={this.reason} />
|
|
|
+ )}
|
|
|
+ <div class={styles.container}>
|
|
|
+ <div class={styles.tips}>
|
|
|
+ <div class={styles.tipsTitle}>注意事项:</div>
|
|
|
+ <div class={styles.tipsContent}>
|
|
|
+ 1、必须是上传人自己参与制作的作品。
|
|
|
+ <br />
|
|
|
+ 2、歌曲及歌曲信息中请勿涉及政治、宗教、广告、涉毒、犯罪、色情、低俗、暴力、血腥、消极等违规内容,违反者直接删除内容。多次违反将封号。
|
|
|
+ <br />
|
|
|
+ 3、点击查看
|
|
|
+ <span onClick={() => this.onDetail('protocol')}>
|
|
|
+ 《用户注册协议》
|
|
|
+ </span>
|
|
|
+ ,如果您上传了文件,即认为您完全同意并遵守该协议的内容;
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ <ColField border={false} required title="MusicXML文件">
|
|
|
+ <Field
|
|
|
+ name="xmlFileUrl"
|
|
|
+ modelValue={this.xmlFileUrl}
|
|
|
+ rules={[{ required: true, message: '请选择MusicXML文件' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <Button
|
|
|
+ icon={UploadIcon}
|
|
|
+ class={styles.upbtn}
|
|
|
+ onClick={this.naiveXMLFile}
|
|
|
+ loading={this.xmlFileLoading}
|
|
|
+ >
|
|
|
+ {this.xmlFileUrl
|
|
|
+ ? this.fileName(this.xmlFileUrl)
|
|
|
+ : '上传文件'}
|
|
|
+ </Button>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.xmlFileUrl = val)}
|
|
|
+ accept=".xml"
|
|
|
+ formatFile={this.readerFile}
|
|
|
+ />
|
|
|
+ <div style={{ marginLeft: '8px' }}>
|
|
|
+ {this.fileName(this.xmlFileUrl)}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ <div class={styles.tips}>
|
|
|
+ <div class={styles.tipsTitle}>曲谱审核标准:</div>
|
|
|
+ <div class={styles.tipsContent}>
|
|
|
+ 1、文件大小不要超过5MB,不符合版面规范的乐谱,审核未通过的不予上架,详情参考
|
|
|
+ <span onClick={() => this.onDetail('music')}>
|
|
|
+ 《曲谱排版规范》
|
|
|
+ </span>
|
|
|
+ ; 1、必须是上传人自己参与制作的作品。
|
|
|
+ <br />
|
|
|
+ 2、XML与MIDI文件内容必须一致,推荐使用Sibelius打谱软件。导出设置:导出XML-未压缩(*.xml)/导出MIDI:音色-其他回放设备General
|
|
|
+ MIDI、MIDI、MIDI文件类型-类型0、不要勾选“将弱拍小节导出为具有休止符的完整小节”。点击查看
|
|
|
+ <span onClick={() => this.onDetail('question')}>
|
|
|
+ 《常见问题》
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ <ColField required title="播放类型" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.audioType}
|
|
|
+ onUpdate:modelValue={val => (this.audioType = val)}
|
|
|
+ >
|
|
|
+ {Object.keys(teachershowAudiType).map((item: string) => {
|
|
|
+ const isActive = item === this.audioType
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teachershowAudiType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField>
|
|
|
+ {this.audioType === 'MP3' ? (
|
|
|
+ <>
|
|
|
+ {/* <ColField required title="是否带节拍器" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.hasBeat}
|
|
|
+ onUpdate:modelValue={val => (this.hasBeat = val)}
|
|
|
+ >
|
|
|
+ {Object.keys(teachershowHasBeatType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.hasBeat)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teachershowHasBeatType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField> */}
|
|
|
+ <ColField required title="伴奏类型" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.accompanimentType}
|
|
|
+ onUpdate:modelValue={val => (this.accompanimentType = val)}
|
|
|
+ >
|
|
|
+ {Object.keys(teacherStyleType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.accompanimentType)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teacherStyleType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField>
|
|
|
+ <ColField border={false} title="伴奏文件">
|
|
|
+ <Field
|
|
|
+ name="mp3Url"
|
|
|
+ modelValue={this.mp3Url}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <Button
|
|
|
+ icon={UploadIcon}
|
|
|
+ class={styles.upbtn}
|
|
|
+ onClick={this.naiveMp3File}
|
|
|
+ loading={this.mp3Loading}
|
|
|
+ >
|
|
|
+ {this.mp3Url
|
|
|
+ ? this.fileName(this.mp3Url)
|
|
|
+ : '上传文件'}
|
|
|
+ </Button>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.mp3Url = val)}
|
|
|
+ accept=".mp3"
|
|
|
+ />
|
|
|
+ <div style={{ marginLeft: '8px' }}>
|
|
|
+ {this.fileName(this.mp3Url)}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <ColField border={false} required title="MIDI文件">
|
|
|
+ <Field
|
|
|
+ name="midiUrl"
|
|
|
+ modelValue={this.midiUrl}
|
|
|
+ rules={[{ required: true, message: '请选择MIDI文件' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <Button
|
|
|
+ icon={UploadIcon}
|
|
|
+ class={styles.upbtn}
|
|
|
+ onClick={this.naiveMidFile}
|
|
|
+ loading={this.midiLoading}
|
|
|
+ >
|
|
|
+ {this.midiUrl
|
|
|
+ ? this.fileName(this.midiUrl)
|
|
|
+ : '上传文件'}
|
|
|
+ </Button>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.midiUrl = val)}
|
|
|
+ accept=".mid,.midi"
|
|
|
+ />
|
|
|
+ <div style={{ marginLeft: '8px' }}>
|
|
|
+ {this.fileName(this.midiUrl)}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ )}
|
|
|
+ </ColFieldGroup>
|
|
|
+ <div class={styles.tips}>
|
|
|
+ <div class={styles.tipsContent}>
|
|
|
+ 1、推荐上传自制伴奏,伴奏和谱面必须对齐。自制伴奏可以设置更高的收费标准。
|
|
|
+ <br />
|
|
|
+ 2、普通伴奏如果涉及到版权纠纷,根据
|
|
|
+ <span onClick={() => this.onDetail('protocol')}>
|
|
|
+ 《用户注册协议》
|
|
|
+ </span>
|
|
|
+ 平台有权进行下架处理。
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ {this.audioType === 'MP3' &&
|
|
|
+ this.backgroundMp3s.map((item, index) => (
|
|
|
+ <ColField
|
|
|
+ required
|
|
|
+ border={false}
|
|
|
+ title={(item.track || '') + '原音文件'}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ right: () =>
|
|
|
+ this.backgroundMp3s.length > 1 ? (
|
|
|
+ <Button
|
|
|
+ onClick={() => this.removeBackground(index)}
|
|
|
+ style={{ border: 'none' }}
|
|
|
+ icon="cross"
|
|
|
+ ></Button>
|
|
|
+ ) : null
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Field
|
|
|
+ name="url"
|
|
|
+ modelValue={this.bgmp3Url}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <Button
|
|
|
+ icon={UploadIcon}
|
|
|
+ class={styles.upbtn}
|
|
|
+ onClick={this.naiveBGMp3File}
|
|
|
+ loading={this.bgmp3Loading}
|
|
|
+ >
|
|
|
+ {this.bgmp3Url
|
|
|
+ ? this.fileName(this.bgmp3Url)
|
|
|
+ : '上传文件'}
|
|
|
+ </Button>
|
|
|
+ ) : (
|
|
|
+ <>
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.bgmp3Url = val)}
|
|
|
+ accept=".mp3"
|
|
|
+ />
|
|
|
+ <div style={{ marginLeft: '8px' }}>
|
|
|
+ {this.fileName(this.bgmp3Url)}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ ))}
|
|
|
+ <ColField required title="曲目名称">
|
|
|
+ <Field
|
|
|
+ clearable
|
|
|
+ name="musicSheetName"
|
|
|
+ modelValue={this.musicSheetName}
|
|
|
+ rules={[{ required: true, message: '请输入曲目名称' }]}
|
|
|
+ class={styles['clear-px']}
|
|
|
+ placeholder="请输入曲目名称"
|
|
|
+ onUpdate:modelValue={val => (this.musicSheetName = val)}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ <div class={styles.tips}>
|
|
|
+ <div class={styles.tipsContent}>
|
|
|
+ 1、同一首曲目不可重复上传,如有不同版本统一用“()”补充。举例:人生的旋转木马(长笛二重奏版)。
|
|
|
+ <br />
|
|
|
+ 2、曲目名后可添加曲目信息备注,包含但不限于曲目类型等。曲目名《xxxx》,举例:人生的旋转木马《哈尔的移动城堡》(长笛二重奏版)
|
|
|
+ <br />
|
|
|
+ 3、其他信息不要写在曲目名里,如歌手、上传人员昵称等。
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ <ColField border={false} required title="曲谱封面">
|
|
|
+ <ColUpload
|
|
|
+ cropper
|
|
|
+ bucket="cloud-coach"
|
|
|
+ options={{
|
|
|
+ autoCropWidth: 600,
|
|
|
+ autoCropHeight: 600
|
|
|
+ }}
|
|
|
+ v-model={this.titleImg}
|
|
|
+ class={styles.imgContainer}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ <ColField required title="艺术家">
|
|
|
+ <Field
|
|
|
+ clearable
|
|
|
+ class={styles['clear-px']}
|
|
|
+ placeholder="请输入艺术家姓名"
|
|
|
+ name="composer"
|
|
|
+ modelValue={this.composer}
|
|
|
+ rules={[{ required: true, message: '请输入艺术家姓名' }]}
|
|
|
+ onUpdate:modelValue={val => (this.composer = val)}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ {/* <ColField required title="默认速度">
|
|
|
+ <Field
|
|
|
+ clearable
|
|
|
+ name="playSpeed"
|
|
|
+ modelValue={this.speed}
|
|
|
+ rules={[{ required: true, message: '请输入默认速度' }]}
|
|
|
+ onUpdate:modelValue={val => (this.speed = val)}
|
|
|
+ class={styles['clear-px']}
|
|
|
+ placeholder="请输入默认速度"
|
|
|
+ />
|
|
|
+ </ColField> */}
|
|
|
+ <ColField required title="曲目声部">
|
|
|
+ <Field
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ class={styles['clear-px']}
|
|
|
+ placeholder="请选择曲目声部"
|
|
|
+ name="vlewSubjectList"
|
|
|
+ modelValue={this.vlewSubjectList?.value}
|
|
|
+ rules={[{ required: true, message: '请选择曲目声部' }]}
|
|
|
+ // onUpdate:modelValue={val => (this.selectedSubjectList = )}
|
|
|
+ onClick={() => (this.showPicker = true)}
|
|
|
+ ></Field>
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ <div class={styles.tips}>
|
|
|
+ <div class={styles.tipsContent}>
|
|
|
+ XML文件中,选择的曲目声部需要在总谱的置顶位置。
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ <ColField
|
|
|
+ border={false}
|
|
|
+ required
|
|
|
+ title="曲目标签"
|
|
|
+ v-slots={{
|
|
|
+ right: () => (
|
|
|
+ <Button
|
|
|
+ class={styles.select}
|
|
|
+ round
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ onClick={() => (this.tagVisibility = true)}
|
|
|
+ >
|
|
|
+ 选择
|
|
|
+ </Button>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Field
|
|
|
+ name="tags"
|
|
|
+ modelValue={this.tags.length ? 1 : undefined}
|
|
|
+ rules={[{ required: true, message: '请选择曲目标签' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ this.tags.length > 0 ? (
|
|
|
+ this.tags.map((item: any) => (
|
|
|
+ <Tag type="primary" size="large" class={styles.tags}>
|
|
|
+ {this.tagsNames[item]}
|
|
|
+ </Tag>
|
|
|
+ ))
|
|
|
+ ) : (
|
|
|
+ <Empty
|
|
|
+ style={{ width: '100%' }}
|
|
|
+ description="请选择曲目标签"
|
|
|
+ imageSize={0}
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ <ColFieldGroup class={styles.area}>
|
|
|
+ {/* <ColField required title="是否评测" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.canEvaluate}
|
|
|
+ onUpdate:modelValue={val => (this.canEvaluate = val)}
|
|
|
+ >
|
|
|
+ {Object.keys(teachercanEvaluateType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.canEvaluate)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teachercanEvaluateType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField> */}
|
|
|
+ {/* <ColField required title="指法展示" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.showFingering}
|
|
|
+ onUpdate:modelValue={val => (this.showFingering = val)}
|
|
|
+ >
|
|
|
+ {Object.keys(teachershowFingeringType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.showFingering)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teachershowFingeringType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField> */}
|
|
|
+
|
|
|
+ {/* 判断是否是审核版本 */}
|
|
|
+ {!this.checked && (
|
|
|
+ <ColField required title="是否收费" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.chargeType}
|
|
|
+ onUpdate:modelValue={val => {
|
|
|
+ this.chargeType = Number(val)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {Object.keys(teacherChargeType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.chargeType)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teacherChargeType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {this.chargeType === 2 && (
|
|
|
+ <ColField required title="收费价格">
|
|
|
+ <Field
|
|
|
+ clearable
|
|
|
+ class={styles['clear-px']}
|
|
|
+ placeholder="请输入收费价格"
|
|
|
+ formatter={this.onFormatter}
|
|
|
+ v-slots={{ button: () => '元' }}
|
|
|
+ modelValue={this.musicPrice}
|
|
|
+ rules={[
|
|
|
+ { required: true, validator, message: '请输入收费价格' }
|
|
|
+ ]}
|
|
|
+ onUpdate:modelValue={val => (this.musicPrice = val)}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ )}
|
|
|
+ {/* <ColField required title="支持简谱" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.notation}
|
|
|
+ onUpdate:modelValue={val => {
|
|
|
+ this.notation = Number(val)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {Object.keys(teacherNotationType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.notation)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teacherNotationType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField> */}
|
|
|
+ <ColField required title="是否精品乐谱" border={false}>
|
|
|
+ <RadioGroup
|
|
|
+ class={styles['radio-group']}
|
|
|
+ modelValue={this.exquisiteFlag}
|
|
|
+ onUpdate:modelValue={val => {
|
|
|
+ this.exquisiteFlag = Number(val)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {Object.keys(teacherExquisiteType).map((item: string) => {
|
|
|
+ const isActive = item === String(this.exquisiteFlag)
|
|
|
+ const type = isActive ? 'primary' : 'default'
|
|
|
+ return (
|
|
|
+ <Radio class={styles.radio} name={item}>
|
|
|
+ <Tag size="large" plain={isActive} type={type}>
|
|
|
+ {teacherExquisiteType[item]}
|
|
|
+ </Tag>
|
|
|
+ </Radio>
|
|
|
+ )
|
|
|
+ })}
|
|
|
+ </RadioGroup>
|
|
|
+ </ColField>
|
|
|
+ </ColFieldGroup>
|
|
|
+ {this.chargeType === 2 && (
|
|
|
+ <div class={styles.rule}>
|
|
|
+ <p>扣除手续费后该曲目预计收入为:</p>
|
|
|
+ <p>
|
|
|
+ 每人:
|
|
|
+ <span>
|
|
|
+ {(
|
|
|
+ ((parseFloat(this.musicPrice || '0') || 0) *
|
|
|
+ (100 - this.music_sheet_service_fee)) /
|
|
|
+ 100
|
|
|
+ ).toFixed(2)}
|
|
|
+ </span>
|
|
|
+ 元/人
|
|
|
+ </p>
|
|
|
+
|
|
|
+ <p>
|
|
|
+ 您的乐谱收入在学员购买后{this.music_account_period}
|
|
|
+ 天结算到您的账户中
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ <Sticky offsetBottom={0} position="bottom">
|
|
|
+ <div class={styles['button-area']}>
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ block
|
|
|
+ round
|
|
|
+ native-type="submit"
|
|
|
+ loading={this.submitLoading}
|
|
|
+ >
|
|
|
+ 确认
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </Sticky>
|
|
|
+ <Popup
|
|
|
+ show={this.showPicker}
|
|
|
+ round
|
|
|
+ position="bottom"
|
|
|
+ teleport="body"
|
|
|
+ onUpdate:show={val => (this.showPicker = val)}
|
|
|
+ >
|
|
|
+ <Picker
|
|
|
+ defaultIndex={this.subJectIndex}
|
|
|
+ columnsFieldNames={{
|
|
|
+ text: 'value'
|
|
|
+ }}
|
|
|
+ columns={Object.entries(this.subjectListNames).map(
|
|
|
+ ([key, value]) => ({ label: key, value })
|
|
|
+ )}
|
|
|
+ onCancel={() => (this.showPicker = false)}
|
|
|
+ onConfirm={val => {
|
|
|
+ this.selectedSubjectList = val
|
|
|
+ this.vlewSubjectList = val
|
|
|
+ this.showPicker = false
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+
|
|
|
+ <Popup
|
|
|
+ show={this.subJectVisible}
|
|
|
+ round
|
|
|
+ closeable
|
|
|
+ position="bottom"
|
|
|
+ style={{ height: '60%' }}
|
|
|
+ teleport="body"
|
|
|
+ onUpdate:show={val => (this.subJectVisible = val)}
|
|
|
+ >
|
|
|
+ <SubjectModel
|
|
|
+ subjectList={this.subjectList}
|
|
|
+ choiceSubjectIds={this.choiceSubjectIds}
|
|
|
+ onChoice={this.onChoice}
|
|
|
+ selectType="Radio"
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+ <Popup
|
|
|
+ show={this.tagVisibility}
|
|
|
+ round
|
|
|
+ closeable
|
|
|
+ position="bottom"
|
|
|
+ style={{ height: '60%' }}
|
|
|
+ teleport="body"
|
|
|
+ onUpdate:show={val => (this.tagVisibility = val)}
|
|
|
+ >
|
|
|
+ <SelectTag
|
|
|
+ onConfirm={this.onComfirm}
|
|
|
+ onCancel={() => {}}
|
|
|
+ rowSingle
|
|
|
+ defaultValue={this.tags.join(',')}
|
|
|
+ needAllButton={false}
|
|
|
+ />
|
|
|
+ </Popup>
|
|
|
+ </Form>
|
|
|
+ )
|
|
|
+ }
|
|
|
+})
|