123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- import ColCropper from '@/components/col-cropper'
- import ColUpload from '@/components/col-upload'
- import request from '@/helpers/request'
- import { verifyNumberIntegerAndFloat } from '@/helpers/toolsValidate'
- import { getCodeBaseUrl } from '@/helpers/utils'
- import {
- ElButton,
- ElForm,
- ElFormItem,
- ElInput,
- ElOption,
- ElOptionGroup,
- ElRadioButton,
- ElRadioGroup,
- ElSelect,
- ElDialog,
- ElMessage
- } from 'element-plus'
- import { defineComponent } from 'vue'
- import styles from './index.module.less'
- export type BackgroundMp3 = {
- url?: string
- track?: string
- }
- export const validator = (rule, value, callback) => {
- console.log(value)
- if (value == '') {
- callback(new Error('请输入收费价格'))
- } else if (Number(value) <= 0) {
- callback(new Error('收费金额必须大于0'))
- } else {
- callback()
- }
- }
- export default defineComponent({
- name: 'music-operation',
- data() {
- const query = this.$route.query
- return {
- type: query.type || 'create',
- subjectList: [],
- tagList: [],
- submitLoading: false,
- reason: '',
- form: {
- titleImg: '',
- accompanimentType: 'HOMEMODE',
- audioType: 'MP3',
- xmlFileUrl: '',
- hasBeat: 0,
- mp3Url: '',
- bgmp3Url: '',
- midiUrl: '',
- musicSheetName: '',
- composer: '',
- musicSubject: null as any,
- tags: [] as string[],
- notation: 0,
- canEvaluate: 1,
- showFingering: 1,
- chargeType: 0,
- musicPrice: '',
- backgroundMp3s: [
- {
- url: '',
- track: ''
- }
- ] as BackgroundMp3[]
- },
- radioList: [], // 选中的人数
- tagStatus: false,
- music_sheet_service_fee: 0
- }
- },
- async mounted() {
- document.title = this.type === 'create' ? '新建曲谱' : '编辑曲谱'
- try {
- await request
- .get('/api-website/sysConfig/queryByParamName', {
- params: {
- paramName: 'music_sheet_service_fee'
- }
- })
- .then(res => (this.music_sheet_service_fee = res.data.paramValue))
- await request.get('/api-website/open/subject/subjectSelect').then(res => {
- this.subjectList = res.data || []
- })
- await request.get('/api-website/open/MusicTag/tree').then(res => {
- this.tagList = res.data || []
- })
- if (this.$route.query.id) {
- this.setDetail(this.$route.query.id as string)
- }
- } catch {}
- },
- methods: {
- async setDetail(id: string) {
- try {
- const res = await request.get(
- '/api-website/open/music/sheet/detail/' + id
- )
- this.form.chargeType = res.data.chargeType === 'FREE' ? 0 : 2
- this.form.showFingering = res.data.showFingering
- this.form.notation = res.data.notation
- this.form.canEvaluate = res.data.canEvaluate
- if (this.form.chargeType) {
- this.form.musicPrice = res.data.musicPrice
- }
- this.form.composer = res.data.composer
- this.form.musicSheetName = res.data.musicSheetName
- this.form.audioType = res.data.audioType
- this.form.musicSubject = Number(res.data.musicSubject)
- const musicTag = res.data.musicTag.split(',')
- this.form.tags = musicTag.map((item: any) => {
- return Number(item)
- })
- this.radioList = this.form.tags as any
- this.form.xmlFileUrl = res.data.xmlFileUrl
- this.form.accompanimentType = res.data.accompanimentType
- this.form.titleImg = res.data.titleImg
- // this.form.audioType = res.data.mp3Type
- if (this.form.audioType === 'MP3') {
- this.form.hasBeat = res.data.hasBeat || 0
- this.form.mp3Url = res.data.metronomeUrl || res.data.url
- } else {
- this.form.midiUrl = res.data.midiUrl
- }
- this.form.backgroundMp3s = (res.data.background || []).map(
- (item: any, index: any) => {
- if (index === 0) {
- this.form.bgmp3Url = item.metronomeUrl || item.audioFileUrl
- }
- return {
- url: this.form.hasBeat ? item.metronomeUrl : item.audioFileUrl,
- track: item.track
- }
- }
- )
- this.reason = res.data.reason
- console.log(this.form.bgmp3Url)
- } catch (error) {
- console.log(error)
- }
- },
- createSubmitData() {
- const { form } = this
- const beatType = form.hasBeat ? 'MP3_METRONOME' : 'MP3'
- const mp3Type = form.audioType === 'MP3' ? beatType : 'MIDI'
- return {
- audioType: form.audioType,
- sourceType: 'TEACHER',
- mp3Type,
- accompanimentType: form.accompanimentType,
- titleImg: form.titleImg,
- hasBeat: form.hasBeat,
- url: form.hasBeat ? '' : form.mp3Url,
- metronomeUrl: form.hasBeat ? form.mp3Url : '',
- showFingering: Number(form.showFingering),
- notation: Number(form.notation),
- musicTag: form.tags.join(','),
- musicSubject: form.musicSubject || undefined,
- musicSheetName: form.musicSheetName,
- midiUrl: form.midiUrl,
- xmlFileUrl: form.xmlFileUrl,
- canEvaluate: Number(form.canEvaluate),
- chargeType: form.chargeType === 0 ? 'FREE' : 'CHARGE',
- composer: form.composer,
- musicPrice: form.musicPrice,
- background: form.backgroundMp3s.map(item => ({
- audioFileUrl: form.hasBeat ? '' : form.bgmp3Url,
- track: item.track,
- metronomeUrl: form.hasBeat ? form.bgmp3Url : ''
- }))
- }
- },
- onFormatter(e: any) {
- e.target.value = verifyNumberIntegerAndFloat(e.target.value)
- },
- onSubmit() {
- ;(this as any).$refs.form.validate(async (valid: any) => {
- if (valid) {
- this.submitLoading = true
- console.log(this.createSubmitData(), 'createSubmitData')
- try {
- if (this.$route.query.id) {
- await request.post('/api-website/music/sheet/update', {
- data: {
- ...this.createSubmitData(),
- id: this.$route.query.id
- }
- })
- } else {
- await request.post('/api-website/music/sheet/create', {
- data: this.createSubmitData()
- })
- }
- this.submitLoading = false
- ElMessage.success('上传成功')
- sessionStorage.setItem('musicActiveName', 'DOING')
- this.$router.back()
- } catch (error) {
- this.submitLoading = false
- }
- } else {
- this.$nextTick(() => {
- const isError = document.getElementsByClassName('is-error')
- isError[0].scrollIntoView({
- block: 'center',
- behavior: 'smooth'
- })
- })
- return false
- }
- })
- },
- onDetail(type: string) {
- let url = `${getCodeBaseUrl('/teacher')}/#/registerProtocol`
- if (type === 'question') {
- url = `${getCodeBaseUrl('/teacher')}/muic-standard/question.html`
- } else if (type === 'music') {
- url = `${getCodeBaseUrl('/teacher')}/muic-standard/index.html`
- }
- window.open(url)
- }
- },
- render() {
- return (
- <div class={styles.form}>
- <div class="text-2xl font-semibold text-black leading-none px-6 py-5 ">
- {this.type === 'create' ? '新建曲谱' : '编辑曲谱'}
- </div>
- <ElForm
- size="large"
- labelPosition="left"
- labelWidth={'150px'}
- model={this.form}
- ref="form"
- class="px-7 py-5"
- >
- <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>
- <ElFormItem
- label="上传XML"
- prop="xmlFileUrl"
- rules={[{ required: true, message: '请选择MusicXML文件' }]}
- >
- <ColUpload
- v-model:modelValue={this.form.xmlFileUrl}
- bucket={'cloud-coach'}
- accept={'application/xml'}
- uploadType={'file'}
- extraTips="文件最大不能超过5MB"
- />
- </ElFormItem>
- <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>
- <ElFormItem
- label="播放类型"
- prop="audioType"
- rules={[{ required: true, message: '请选择播放类型' }]}
- >
- <ElRadioGroup v-model={this.form.audioType}>
- <ElRadioButton label={'MIDI'} class="mr-3 w-24">
- MIDI
- </ElRadioButton>
- <ElRadioButton label={'MP3'} class="w-24">
- MP3
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- {this.form.audioType === 'MP3' ? (
- <>
- <ElFormItem
- label="是否带节拍器"
- prop="hasBeat"
- rules={[{ required: true, message: '请选择是否带节拍器' }]}
- >
- <ElRadioGroup v-model={this.form.hasBeat}>
- <ElRadioButton label={0} class="mr-3 w-24">
- 否
- </ElRadioButton>
- <ElRadioButton label={1} class="w-24">
- 是
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem
- label="伴奏类型"
- prop="accompanimentType"
- rules={[{ required: true, message: '请选择伴奏类型' }]}
- >
- <ElRadioGroup v-model={this.form.accompanimentType}>
- <ElRadioButton label={'HOMEMODE'} class="mr-3 w-24">
- 自制伴奏
- </ElRadioButton>
- <ElRadioButton label={'COMMON'} class="w-24">
- 普通伴奏
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem label="伴奏文件" prop="mp3Url">
- <ColUpload
- v-model:modelValue={this.form.mp3Url}
- bucket={'cloud-coach'}
- accept={'.mp3'}
- uploadType={'file'}
- size={8}
- extraTips="文件最大不能超过8MB"
- />
- </ElFormItem>
- </>
- ) : (
- <>
- <ElFormItem
- label="伴奏类型"
- prop="accompanimentType"
- rules={[{ required: true, message: '请选择伴奏类型' }]}
- >
- <ElRadioGroup v-model={this.form.accompanimentType}>
- <ElRadioButton label={'HOMEMODE'} class="mr-3 w-24">
- 自制伴奏
- </ElRadioButton>
- <ElRadioButton label={'COMMON'} class="w-24">
- 普通伴奏
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem
- label="MIDI文件"
- prop="midiUrl"
- rules={[{ required: true, message: '请选择MIDI文件' }]}
- >
- <ColUpload
- v-model:modelValue={this.form.midiUrl}
- bucket={'cloud-coach'}
- accept={'.midi'}
- uploadType={'file'}
- size={8}
- extraTips="文件最大不能超过8MB"
- />
- </ElFormItem>
- </>
- )}
- <div class={styles.tips}>
- <div class={styles.tipsContent}>
- 1、推荐上传自制伴奏,伴奏和谱面必须对齐。自制伴奏可以设置更高的收费标准。
- <br />
- 2、普通伴奏如果涉及到版权纠纷,根据
- <span onClick={() => this.onDetail('protocol')}>
- 《用户注册协议》
- </span>
- 平台有权进行下架处理。
- </div>
- </div>
- {this.form.audioType === 'MP3' && (
- <ElFormItem
- label="原音文件"
- prop="bgmp3Url"
- rules={[{ required: true, message: '请选择原音文件' }]}
- >
- <ColUpload
- v-model:modelValue={this.form.bgmp3Url}
- bucket={'cloud-coach'}
- accept={'.mp3'}
- uploadType={'file'}
- extraTips="文件最大不能超过8MB"
- />
- </ElFormItem>
- )}
- <ElFormItem
- label="曲目名称"
- prop="musicSheetName"
- rules={[{ required: true, message: '请输入曲目名称' }]}
- >
- <ElInput
- v-model={this.form.musicSheetName}
- placeholder="请选择曲目名称"
- />
- </ElFormItem>
- <div class={styles.tips}>
- <div class={styles.tipsContent}>
- 1、同一首曲目不可重复上传,如有不同版本统一用“()”补充。举例:人生的旋转木马(长笛二重奏版)。
- <br />
- 2、曲目名后可添加曲目信息备注,包含但不限于曲目类型等。曲目名《xxxx》,举例:人生的旋转木马《哈尔的移动城堡》(长笛二重奏版)
- <br />
- 3、其他信息不要写在曲目名里,如歌手、上传人员昵称等。
- </div>
- </div>
- <ElFormItem
- label="曲谱封面"
- prop="titleImg"
- rules={[
- {
- required: true,
- message: '请上传曲谱封面'
- }
- ]}
- >
- <ColCropper
- modelValue={this.form.titleImg}
- bucket={'cloud-coach'}
- cropUploadSuccess={(data: any) => {
- this.form.titleImg = data
- }}
- domSize={{ height: '150px' }}
- options={{
- title: '曲谱封面',
- enlarge: 2,
- autoCropWidth: 300,
- autoCropHeight: 300
- }}
- />
- </ElFormItem>
- <ElFormItem
- label="艺术家"
- prop="composer"
- rules={[{ required: true, message: '请输入艺术家' }]}
- >
- <ElInput v-model={this.form.composer} placeholder="请输入艺术家" />
- </ElFormItem>
- <ElFormItem
- label="曲目声部"
- prop="musicSubject"
- rules={[
- { required: true, message: '请选择曲目声部', trigger: 'change' }
- ]}
- >
- <ElSelect
- filterable
- v-model={this.form.musicSubject}
- placeholder="请选择曲目声部"
- class="w-full"
- >
- {this.subjectList.map((group: any) => (
- <ElOptionGroup key={group.id} label={group.name}>
- {group.subjects &&
- group.subjects.map((item: any) => (
- <ElOption
- key={item.id}
- value={item.id}
- label={item.name}
- />
- ))}
- </ElOptionGroup>
- ))}
- </ElSelect>
- </ElFormItem>
- <div class={styles.tips}>
- <div class={styles.tipsContent}>
- XML文件中,选择的曲目声部需要在总谱的置顶位置。
- </div>
- </div>
- <ElFormItem
- label="曲目标签"
- prop="tags"
- rules={[{ required: true, message: '请选择曲目标签' }]}
- >
- <div class="w-full relative">
- <div
- class=" w-full block h-[42px] absolute top-0 left-0 z-10"
- onClick={() => {
- console.log(111)
- this.tagStatus = true
- }}
- ></div>
- <ElSelect
- multiple
- v-model={this.form.tags}
- placeholder="请选择曲目标签"
- class="w-full"
- >
- {this.tagList.map((group: any) => (
- <ElOptionGroup key={group.id} label={group.name}>
- {group.children &&
- group.children.map((item: any) => (
- <ElOption
- key={item.id}
- value={item.id}
- label={item.name}
- />
- ))}
- </ElOptionGroup>
- ))}
- </ElSelect>
- </div>
- </ElFormItem>
- <ElFormItem
- label="支持简谱"
- prop="notation"
- rules={[{ required: true, message: '请选择是否支持简谱' }]}
- >
- <ElRadioGroup v-model={this.form.notation}>
- <ElRadioButton label={0} class="mr-3 w-24">
- 否
- </ElRadioButton>
- <ElRadioButton label={1} class="w-24">
- 是
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem
- label="是否评测"
- prop="canEvaluate"
- rules={[{ required: true, message: '请选择是否评测' }]}
- >
- <ElRadioGroup v-model={this.form.canEvaluate}>
- <ElRadioButton label={0} class="mr-3 w-24">
- 否
- </ElRadioButton>
- <ElRadioButton label={1} class="w-24">
- 是
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem
- label="指法展示"
- prop="showFingering"
- rules={[{ required: true, message: '请选择指法展示' }]}
- >
- <ElRadioGroup v-model={this.form.showFingering}>
- <ElRadioButton label={0} class="mr-3 w-24">
- 否
- </ElRadioButton>
- <ElRadioButton label={1} class="w-24">
- 是
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- <ElFormItem
- label="是否收费"
- prop="chargeType"
- rules={[{ required: true, message: '请选择是否收费' }]}
- >
- <ElRadioGroup v-model={this.form.chargeType}>
- <ElRadioButton label={0} class="mr-3 w-24">
- 否
- </ElRadioButton>
- <ElRadioButton label={2} class="w-24">
- 是
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- {this.form.chargeType === 2 && (
- <>
- <ElFormItem
- label="收费价格"
- prop="musicPrice"
- rules={[{ required: true, validator }]}
- >
- <ElInput
- v-model={this.form.musicPrice}
- placeholder="请输入收费价格"
- // @ts-ignore
- maxlength={5}
- onKeyup={this.onFormatter}
- v-slots={{
- suffix: () => <span class="text-base text-[#999]">元</span>
- }}
- />
- </ElFormItem>
- <ElFormItem>
- <div class={styles.rule}>
- <p>扣除手续费后该曲目预计收入为:</p>
- <p>
- 每人:
- <span>
- {((parseFloat(this.form.musicPrice || '0') || 0) *
- (100 - this.music_sheet_service_fee)) /
- 100}
- </span>
- 元/人
- </p>
- <p>您的乐谱收入将在学员购买后结算到您的账户中</p>
- </div>
- </ElFormItem>
- </>
- )}
- </ElForm>
- <div class="text-center pt-6 pb-7">
- <ElButton
- class="!w-44 !h-[48px]"
- round
- onClick={() => {
- this.$router.back()
- }}
- >
- 取消
- </ElButton>
- <ElButton
- type="primary"
- class="!w-44 !h-[48px]"
- round
- onClick={this.onSubmit}
- loading={this.submitLoading}
- >
- 提交审核
- </ElButton>
- </div>
- <ElDialog
- modelValue={this.tagStatus}
- onUpdate:modelValue={val => (this.tagStatus = val)}
- width="35%"
- title="全部标签"
- >
- {this.tagList.map((item: any, index: number) => (
- <div class={[styles.tags, 'py-2']}>
- <div class="text-sm pb-2">{item.name}</div>
- {item.children.map((child: any) => (
- <ElRadioGroup v-model={this.radioList[index]} class="pb-2">
- <ElRadioButton label={child.id} class="mr-3">
- {child.name}
- </ElRadioButton>
- </ElRadioGroup>
- ))}
- </div>
- ))}
- <div class="text-center pt-2">
- <ElButton
- class="!w-36 !h-[48px]"
- round
- size="large"
- onClick={() => {
- this.radioList = []
- }}
- >
- 重置
- </ElButton>
- <ElButton
- class="!w-36 !h-[48px]"
- round
- size="large"
- type="primary"
- onClick={() => {
- this.form.tags = this.radioList
- this.tagStatus = false
- ;(this as any).$refs.form.clearValidate('tags')
- }}
- >
- 确认
- </ElButton>
- </div>
- </ElDialog>
- </div>
- )
- }
- })
|