|
@@ -1,25 +1,61 @@
|
|
|
import { defineComponent } from 'vue'
|
|
|
-import { Button, Field, Sticky, Form, Tag, Radio, RadioGroup } from 'vant'
|
|
|
+import {
|
|
|
+ Button,
|
|
|
+ Field,
|
|
|
+ Sticky,
|
|
|
+ Form,
|
|
|
+ Tag,
|
|
|
+ Radio,
|
|
|
+ RadioGroup,
|
|
|
+ Popup,
|
|
|
+ Icon,
|
|
|
+ Empty,
|
|
|
+ Picker
|
|
|
+} 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 { teacherChargeType } from '@/constant/music'
|
|
|
+import {
|
|
|
+ teachercanEvaluateType,
|
|
|
+ teacherChargeType,
|
|
|
+ teachershowFingeringType
|
|
|
+} from '@/constant/music'
|
|
|
import { getXmlInfo, FormatXMLInfo } from '@/helpers/music-xml'
|
|
|
import Upload from './upload'
|
|
|
import styles from './index.module.less'
|
|
|
+import SelectTag from '@/student/music/search/select-tag'
|
|
|
+import { browser } from '@/helpers/utils'
|
|
|
+import { postMessage } from '@/helpers/native-message'
|
|
|
+import classNames from 'classnames'
|
|
|
+import { teacherState } from '@/teacher/teacher-cert/teacherState'
|
|
|
+import request from '@/helpers/request'
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'MusicUpload',
|
|
|
data() {
|
|
|
return {
|
|
|
+ xmlFileUrl: '',
|
|
|
+ midiUrl: '',
|
|
|
musicSheetName: '',
|
|
|
composer: '',
|
|
|
speed: '',
|
|
|
chargeType: '0',
|
|
|
+ showFingering: 1,
|
|
|
+ canEvaluate: 1,
|
|
|
musicPrice: '',
|
|
|
selectTagVisible: false,
|
|
|
- tags: ['12312'] as string[],
|
|
|
- formated: {} as FormatXMLInfo
|
|
|
+ subJectVisible: false,
|
|
|
+ tags: [] as string[],
|
|
|
+ tagsNames: [] as Array<{ [id in string]: string }>,
|
|
|
+ formated: {} as FormatXMLInfo,
|
|
|
+ tagVisibility: false,
|
|
|
+ subjectListNames: {} as any,
|
|
|
+ selectedSubjectList: null as any,
|
|
|
+ vlewSubjectList: null as any,
|
|
|
+ submitLoading: false,
|
|
|
+ showPicker: false,
|
|
|
+ music_sheet_service_fee: 0
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
@@ -32,10 +68,85 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ computed: {
|
|
|
+ choiceSubjectIds() {
|
|
|
+ // 选择的科目编号
|
|
|
+ let ids = teacherState.teacherCert.subjectId
|
|
|
+ ? teacherState.teacherCert.subjectId.split(',')
|
|
|
+ : []
|
|
|
+ ids = ids.map((item: any) => Number(item))
|
|
|
+ return ids
|
|
|
+ },
|
|
|
+ subjectList() {
|
|
|
+ // 学科列表
|
|
|
+ return teacherState.subjectList || []
|
|
|
+ },
|
|
|
+ choiceSubject() {
|
|
|
+ // 选择的科目
|
|
|
+ let 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/queryByParamName', {
|
|
|
+ params: {
|
|
|
+ paramName: 'music_sheet_service_fee'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(res => (this.music_sheet_service_fee = res.data.paramValue))
|
|
|
+ // if (teacherState.subjectList.length <= 0) {
|
|
|
+ request.get('/api-teacher/subject/subjectSelect').then(res => {
|
|
|
+ teacherState.subjectList = res.data || []
|
|
|
+ this.subjectListNames = this.getSubjectListNames(teacherState.subjectList)
|
|
|
+ })
|
|
|
+
|
|
|
+ // }
|
|
|
+ },
|
|
|
methods: {
|
|
|
- submit(vals: any) {
|
|
|
+ async submit(vals: any) {
|
|
|
+ this.submitLoading = true
|
|
|
+ try {
|
|
|
+ await request.post('/api-teacher/music/sheet/create', {
|
|
|
+ data: {
|
|
|
+ audioType: 'MIDI',
|
|
|
+ sourceType: 'TEACHER',
|
|
|
+ showFingering: this.showFingering,
|
|
|
+ musicTag: this.tags.join(','),
|
|
|
+ musicSubject: this.selectedSubjectList?.label,
|
|
|
+ musicSheetName: this.musicSheetName,
|
|
|
+ midiUrl: this.midiUrl,
|
|
|
+ xmlFileUrl: this.xmlFileUrl,
|
|
|
+ canEvaluate: this.canEvaluate,
|
|
|
+ chargeType: this.chargeType === '0' ? 'FREE' : 'CHARGE',
|
|
|
+ composer: this.composer,
|
|
|
+ musicPrice: this.musicPrice
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } catch (error) {}
|
|
|
+ this.submitLoading = false
|
|
|
console.log(vals)
|
|
|
},
|
|
|
+ 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.musicSheetName)
|
|
|
},
|
|
@@ -58,18 +169,115 @@ export default defineComponent({
|
|
|
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() {
|
|
|
+ postMessage({ api: 'chooseFile', content: { type: 'xml' } }, path => {})
|
|
|
+ },
|
|
|
+ naiveMidFile() {
|
|
|
+ postMessage({ api: 'chooseFile', content: { type: 'midi' } }, path => {})
|
|
|
+ },
|
|
|
+ fileName(name = '') {
|
|
|
+ return name.split('/').pop()
|
|
|
}
|
|
|
},
|
|
|
render() {
|
|
|
+ const browserInfo = browser()
|
|
|
return (
|
|
|
<Form onSubmit={this.submit} onFailed={this.failed}>
|
|
|
<div class={styles.container}>
|
|
|
<ColFieldGroup class={styles.area}>
|
|
|
- <ColField required title="MusicXML文件">
|
|
|
- <Upload
|
|
|
- onUpdate:modelValue={val => console.log(val)}
|
|
|
- accept=".xml"
|
|
|
- formatFile={this.readerFile}
|
|
|
+ <ColField border={false} required title="MusicXML文件">
|
|
|
+ <Field
|
|
|
+ name="xmlFileUrl"
|
|
|
+ modelValue={this.xmlFileUrl}
|
|
|
+ rules={[{ required: true, message: '请选择MusicXML文件' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <>
|
|
|
+ {this.xmlFileUrl ? (
|
|
|
+ <>
|
|
|
+ <div
|
|
|
+ class={classNames(styles.file, 'van-ellipsis')}
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <Icon name="music-o" />
|
|
|
+ <span>{this.fileName(this.xmlFileUrl)}</span>
|
|
|
+ </div>
|
|
|
+ <Button
|
|
|
+ class={styles.delbtn}
|
|
|
+ icon="delete-o"
|
|
|
+ onClick={() => (this.xmlFileUrl = '')}
|
|
|
+ ></Button>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <Button icon="upgrade" onClick={this.naiveXMLFile}>
|
|
|
+ 上传文件
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.xmlFileUrl = val)}
|
|
|
+ accept=".xml"
|
|
|
+ formatFile={this.readerFile}
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </ColField>
|
|
|
+ <ColField border={false} required title="MIDI文件">
|
|
|
+ <Field
|
|
|
+ name="midiUrl"
|
|
|
+ modelValue={this.midiUrl}
|
|
|
+ rules={[{ required: true, message: '请选择MIDI文件' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ browserInfo.isApp ? (
|
|
|
+ <>
|
|
|
+ {this.midiUrl ? (
|
|
|
+ <>
|
|
|
+ <div
|
|
|
+ class={classNames(styles.file, 'van-ellipsis')}
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <Icon name="music-o" />
|
|
|
+ <span>{this.fileName(this.midiUrl)}</span>
|
|
|
+ </div>
|
|
|
+ <Button
|
|
|
+ class={styles.delbtn}
|
|
|
+ onClick={() => (this.midiUrl = '')}
|
|
|
+ icon="delete-o"
|
|
|
+ ></Button>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <Button icon="upgrade" onClick={this.naiveMidFile}>
|
|
|
+ 上传文件
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+ ) : (
|
|
|
+ <Upload
|
|
|
+ onUpdate:modelValue={val => (this.midiUrl = val)}
|
|
|
+ accept=".mid"
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }}
|
|
|
/>
|
|
|
</ColField>
|
|
|
</ColFieldGroup>
|
|
@@ -96,9 +304,23 @@ export default defineComponent({
|
|
|
onUpdate:modelValue={val => (this.composer = val)}
|
|
|
/>
|
|
|
</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>
|
|
|
<ColFieldGroup class={styles.area}>
|
|
|
<ColField
|
|
|
+ border={false}
|
|
|
required
|
|
|
title="曲目标签"
|
|
|
v-slots={{
|
|
@@ -108,26 +330,80 @@ export default defineComponent({
|
|
|
round
|
|
|
type="primary"
|
|
|
size="small"
|
|
|
- onClick={() => (this.selectTagVisible = true)}
|
|
|
+ onClick={() => (this.tagVisibility = true)}
|
|
|
>
|
|
|
选择
|
|
|
</Button>
|
|
|
)
|
|
|
}}
|
|
|
>
|
|
|
- {this.tags.length > 0 &&
|
|
|
- this.tags.map((item: any) => (
|
|
|
- <Tag
|
|
|
+ <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
|
|
|
+ border={false}
|
|
|
+ title="曲目声部"
|
|
|
+ v-slots={{
|
|
|
+ right: () => (
|
|
|
+ <Button
|
|
|
+ class={styles.select}
|
|
|
+ round
|
|
|
type="primary"
|
|
|
- size="large"
|
|
|
- closeable
|
|
|
- onClose={() => console.log(item)}
|
|
|
+ size="small"
|
|
|
+ onClick={() => (this.subJectVisible = true)}
|
|
|
>
|
|
|
- {item}
|
|
|
- </Tag>
|
|
|
- ))}
|
|
|
+ 选择
|
|
|
+ </Button>
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Field
|
|
|
+ name="tags"
|
|
|
+ modelValue={this.selectedSubjectList.length ? 1 : undefined}
|
|
|
+ rules={[{ required: true, message: '请选择曲目声部' }]}
|
|
|
+ // @ts-ignore
|
|
|
+ vSlots={{
|
|
|
+ input: () =>
|
|
|
+ this.selectedSubjectList.length > 0 ? (
|
|
|
+ this.selectedSubjectList.map((item: any) => (
|
|
|
+ <Tag type="primary" size="large" class={styles.tags}>
|
|
|
+ {this.subjectListNames[item]}
|
|
|
+ </Tag>
|
|
|
+ ))
|
|
|
+ ) : (
|
|
|
+ <Empty
|
|
|
+ style={{ width: '100%' }}
|
|
|
+ description="请选择曲目声部"
|
|
|
+ imageSize={0}
|
|
|
+ />
|
|
|
+ )
|
|
|
+ }}
|
|
|
+ />
|
|
|
</ColField>
|
|
|
- </ColFieldGroup>
|
|
|
+ </ColFieldGroup> */}
|
|
|
<ColFieldGroup class={styles.area}>
|
|
|
<ColField required title="默认速度">
|
|
|
<Field
|
|
@@ -140,6 +416,44 @@ export default defineComponent({
|
|
|
placeholder="请输入默认速度"
|
|
|
/>
|
|
|
</ColField>
|
|
|
+ <ColField required title="是否评测">
|
|
|
+ <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="指法展示">
|
|
|
+ <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>
|
|
|
<ColField required title="是否收费">
|
|
|
<RadioGroup
|
|
|
class={styles['radio-group']}
|
|
@@ -177,7 +491,13 @@ export default defineComponent({
|
|
|
<div class={styles.rule}>
|
|
|
<p>扣除手续费后该曲目预计收入为:</p>
|
|
|
<p>
|
|
|
- 单课时:<span>5.8</span>元/人
|
|
|
+ 单课时:
|
|
|
+ <span>
|
|
|
+ {((parseFloat(this.musicPrice || '0') || 0) *
|
|
|
+ (100 - this.music_sheet_service_fee)) /
|
|
|
+ 100}
|
|
|
+ </span>
|
|
|
+ 元/人
|
|
|
</p>
|
|
|
<p>您的乐谱收入将在学员购买后结算到您的账户中</p>
|
|
|
</div>
|
|
@@ -185,11 +505,67 @@ export default defineComponent({
|
|
|
</div>
|
|
|
<Sticky offsetBottom={0} position="bottom">
|
|
|
<div class={styles['button-area']}>
|
|
|
- <Button type="primary" block round native-type="submit">
|
|
|
+ <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
|
|
|
+ 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 onComfirm={this.onComfirm} onCancel={() => {}} />
|
|
|
+ </Popup>
|
|
|
</Form>
|
|
|
)
|
|
|
}
|