| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- 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,
- ElInputNumber,
- ElTooltip
- } from 'element-plus'
- import { defineComponent } from 'vue'
- import styles from './index.module.less'
- import requestOrigin from 'umi-request'
- import { FormatXMLInfo, getXmlInfo } from './music-xml'
- import MessageTip from './message-tip'
- import ListenAudio from './listen-audio'
- export type BackgroundMp3 = {
- url?: string
- id?: string
- trackName?: string
- track?: string
- loading?: boolean
- }
- 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: '',
- formated: {} as FormatXMLInfo,
- musicSheetAuthRecordId: null as any,
- auditStatus: '' as any,
- form: {
- musicCover: '',
- accompanimentType: 'HOMEMODE',
- playMode: 'MP3',
- xmlFileUrl: '',
- playSpeed: '100',
- mp3Url: '',
- // bgmp3Url: '',
- midiFileUrl: '',
- name: '',
- composer: '',
- remark: '',
- tags: [] as any[],
- paymentType: 'FREE',
- musicPrice: '',
- backgroundMp3s: [] as BackgroundMp3[]
- },
- radioList: [], // 选中的人数
- tagStatus: false,
- music_sheet_service_fee: 0,
- music_account_period: 0,
- visibleShow: false,
- visibleShow2: false,
- visibleAudio: false,
- fileInfo: {} as any,
- messageTipTitle: '上传须知',
- messageTipType: 'upload' as 'upload' | 'error' | 'origin',
- cbsInstrumentList: [] as any
- }
- },
- async mounted() {
- const isCatchTip = localStorage.getItem('isCatchTip')
- if (!isCatchTip) {
- this.visibleShow = true
- }
- document.title = this.type === 'create' ? '新建曲谱' : '编辑曲谱'
- try {
- await request
- .get('/api-website/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
- }
- })
- })
- // 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 || []
- })
- await request
- .post('/api-teacher/musicalInstrument/list')
- .then((response: any) => {
- const data = response.data || []
- data.forEach((item: any) => {
- this.cbsInstrumentList.push({
- id: item.id,
- name: item.name,
- code: item.code,
- loading: false
- })
- })
- })
- if (this.$route.query.id) {
- this.setDetail(this.$route.query.id as string)
- }
- } catch {
- //
- }
- },
- watch: {
- formated() {
- this.mergeXmlData(this.formated)
- }
- },
- computed: {
- auditDisabled(): boolean {
- return this.auditStatus === 'DOING'
- }
- },
- methods: {
- mergeXmlData(data: FormatXMLInfo) {
- this.formated = data
- // this.backgroundMp3s = data.partNames.map((partName: string) => ({
- // track: partName
- // }))
- if (!this.form.name) {
- this.form.name = data.title
- }
- if (!this.form.composer) {
- this.form.composer = data.composer
- }
- if (data.speed) {
- this.form.playSpeed = '' + data.speed
- }
- },
- async setDetail(id: string) {
- try {
- const { data } = await request.get(
- '/api-website/open/music/sheet/detail/' + id
- )
- this.musicSheetAuthRecordId = data.musicSheetAuthRecordId // 审核编号
- this.auditStatus = data.auditStatus // 状态
- this.form.playMode = data.audioType || 'MP3'
- this.form.xmlFileUrl = data.xmlFileUrl
- this.form.name = data.musicSheetName
- this.form.composer = data.composer
- this.form.playSpeed = data.playSpeed
- // this.form.tags = data.musicTag?.split(',')
- // const names = data.musicTagNames.split(',')
- this.form.tags = data.musicTag.split(',')
- this.form.tags = this.form.tags
- .filter((el: any) => {
- return el != ''
- })
- .map(e => Number(e))
- // for (let i = 0; i < names.length; i++) {
- // this.form.tagsNames[this.form.tags[i]] = names[i]
- // }
- this.form.musicCover = data.titleImg
- this.form.midiFileUrl = data.midiUrl
- this.form.mp3Url = data.metronomeUrl
- this.form.remark = data.remark
- this.form.paymentType = data.paymentType
- this.form.musicPrice = data.musicPrice || 0
- // this.form.extConfigJson = data.extConfigJson
- this.form.backgroundMp3s = data.background.map((item: any) => {
- return {
- url: item.audioFileUrl,
- trackName: item.musicalInstrumentName,
- id: item.musicalInstrumentId,
- track: item.track,
- loading: false
- }
- })
- } catch (error) {
- console.log(error)
- }
- },
- createSubmitData() {
- const { form } = this
- return {
- musicSheetJson: {
- playMode: form.playMode, // 播放模式
- xmlFileUrl: form.xmlFileUrl, // XML
- name: form.name, // 曲目名称
- composer: form.composer, // 音乐人
- playSpeed: form.playSpeed, // 曲目速度
- musicTagIds: form.tags?.join(','),
- remark: form.remark,
- musicCover: form.musicCover, // 曲目封面
- multiTracksSelection: form.backgroundMp3s
- .map(item => item.track)
- ?.join(','), // 声轨名
- midiFileUrl: form.midiFileUrl, // MID文件
- musicPrice: form.musicPrice,
- paymentType: form.paymentType,
- musicSheetAccompanimentList: [
- {
- audioFileUrl: form.mp3Url,
- sortNumber: 1,
- audioPlayType: 'PLAY'
- }
- ], // 伴奏
- // playMode: 'HOMEMODE', // HOMEMODE 默认自制
- musicSheetSoundList: form.backgroundMp3s.map(item => ({
- musicalInstrumentId: item.id,
- musicalInstrumentName: item.trackName,
- audioFileUrl: item.url,
- track: item.track,
- audioPlayType: 'PLAY' // SING
- })), // 原音
- musicalInstrumentIds: form.backgroundMp3s
- .map(item => item.id)
- ?.join(','), // 乐器编号
- extConfigJson: '{"repeatedBeats":0,"gradualTimes":{},"isEvxml":0}'
- }
- }
- },
- onFormatter(e: any) {
- e.target.value = verifyNumberIntegerAndFloat(e.target.value)
- },
- readerFile(file: string) {
- requestOrigin(file).then(res => {
- // this.formated = getXmlInfo(res)
- const formated = getXmlInfo(res)
- let resultIndexStatus = false
- const partNames = formated.partNames || []
- const tempMp3s: BackgroundMp3[] = []
- for (const i of partNames) {
- let index = -1
- this.cbsInstrumentList.forEach((item: any, j: number) => {
- const code = item.code ? item.code.split(',') : ''
- for (const p of code) {
- if (i.indexOf(p) > -1) {
- index = j
- }
- }
- })
- if (index === -1) {
- resultIndexStatus = true
- break
- }
- const currentItem = this.cbsInstrumentList[index]
- if (currentItem) {
- tempMp3s.push({
- url: '',
- id: currentItem.id,
- trackName: currentItem.name,
- track: i,
- loading: currentItem.loading
- })
- }
- }
- if (partNames.length <= 0 || resultIndexStatus) {
- this.visibleShow2 = true
- this.form.xmlFileUrl = ''
- return
- }
- this.formated = formated
- this.form.backgroundMp3s = tempMp3s
- console.log(this.form.backgroundMp3s, '121212', tempMp3s)
- })
- },
- onSubmit() {
- ;(this as any).$refs.form.validate(async (valid: any) => {
- if (valid) {
- this.submitLoading = true
- try {
- if (this.$route.query.id) {
- await request.post('/api-teacher/musicSheetAuthRecord/update', {
- data: {
- ...this.createSubmitData(),
- id: this.musicSheetAuthRecordId
- }
- })
- } else {
- await request.post('/api-teacher/musicSheetAuthRecord/save', {
- 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 flex justify-between">
- {this.type === 'create' ? '新建曲谱' : '编辑曲谱'}
- <div
- class={styles.uploadTips}
- onClick={() => (this.visibleShow = true)}
- >
- 上传须知
- </div>
- </div>
- <ElForm
- size="large"
- labelPosition="left"
- labelWidth={'150px'}
- model={this.form}
- ref="form"
- class="px-7 py-5"
- disabled={this.auditDisabled}
- >
- <div class={styles.fAlert}>曲目上传</div>
- <ElFormItem
- label="播放类型"
- prop="playMode"
- rules={[{ required: true, message: '请选择播放类型' }]}
- >
- <ElRadioGroup v-model={this.form.playMode}>
- <ElRadioButton label={'MP3'} class="mr-3 w-24">
- MP3
- </ElRadioButton>
- <ElRadioButton label={'MIDI'} class="w-24">
- MIDI
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- {this.form.playMode === 'MP3' ? (
- <ElFormItem
- label="上传伴奏"
- prop="mp3Url"
- rules={[{ required: true, message: '请选择伴奏' }]}
- >
- <ColUpload
- isPreview={this.form.mp3Url ? true : false}
- v-model:modelValue={this.form.mp3Url}
- bucket={'cloud-coach'}
- accept={'.mp3'}
- uploadType={'file'}
- disabled={this.auditDisabled}
- type="music"
- btnText="上传伴奏文件"
- size={50}
- onPreview={(fileInfo: any) => {
- this.visibleAudio = true;
- this.fileInfo = fileInfo
- }}
- extraTips="仅支持MP3格式文件,文件最大不能超过50MB"
- />
- </ElFormItem>
- ) : (
- <ElFormItem
- label="MIDI文件"
- prop="midiFileUrl"
- rules={[{ required: true, message: '请选择MIDI文件' }]}
- >
- <ColUpload
- isPreview={this.form.midiFileUrl ? true : false}
- v-model:modelValue={this.form.midiFileUrl}
- bucket={'cloud-coach'}
- accept={'.midi,.mid'}
- disabled={this.auditDisabled}
- uploadType={'file'}
- type="music"
- btnText="上传MIDI文件"
- size={8}
- extraTips="仅支持MID格式文件,文件最大不能超过8MB"
- />
- </ElFormItem>
- )}
- <ElFormItem
- label="上传XML"
- prop="xmlFileUrl"
- rules={[{ required: true, message: '请选择XML文件' }]}
- >
- <ColUpload
- v-model:modelValue={this.form.xmlFileUrl}
- bucket={'cloud-coach'}
- accept={'application/xml'}
- uploadType={'file'}
- isOnlyUpload={this.form.xmlFileUrl ? true : false}
- disabled={this.auditDisabled}
- type="music"
- btnText="上传XML文件"
- extraTips="仅支持XML格式文件,文件最大不能超过8MB"
- onChange={this.readerFile}
- onRemove={() => {
- this.form.backgroundMp3s = []
- }}
- />
- </ElFormItem>
- {this.form.backgroundMp3s.length > 0 && this.form.playMode === 'MP3' && (
- <ElFormItem>
- {{
- label: () => (
- <div class="flex items-center">
- <i style="color: var(--el-color-danger);margin-right: 4px;">
- *
- </i>
- 上传原音
- <ElTooltip effect="dark" placement="top">
- {{
- content: () => (
- <div class="w-[445px]">
- 1、同一首曲目不可重复上传,如有不同版本统一用“()”补充。举例:人生的旋转木马(长笛二重奏版)
- <br />
- 2、曲目名后可添加曲目信息备注,包含但不限于曲目类型等。曲目名《XXX》,举例:人声的旋转木马《哈尔的移动城堡》(长笛二重奏版)
- <br />
- 3、其他信息不要写在曲目名里,如歌手、上传人员昵称等。
- </div>
- ),
- default: () => <i class={styles.iconQesution}></i>
- }}
- </ElTooltip>
- </div>
- ),
- default: () => (
- <>
- {this.form.backgroundMp3s.map((mp3, index) => (
- <ElFormItem
- prop={`backgroundMp3s.${index}.url`}
- rules={[
- {
- required: true,
- message: '请选择原音文件',
- trigger: 'blur,change'
- }
- ]}
- class={styles.formItem}
- >
- <div style="line-height: 1; font-weight: 500;font-size: 16px;color: #131415; padding-bottom: 12px;">
- 所属轨道:{mp3.trackName}
- </div>
- <ColUpload
- isPreview={mp3.url ? true : false}
- onPreview={(fileInfo: any) => {
- this.visibleAudio = true;
- this.fileInfo = fileInfo
- }}
- v-model:modelValue={mp3.url}
- bucket={'cloud-coach'}
- accept={'.mp3'}
- uploadType={'file'}
- disabled={this.auditDisabled}
- class={styles.uploadCon}
- size={50}
- type="music"
- btnText="上传原音文件"
- extraTips="仅支持MP3格式文件,文件最大不能超过50MB"
- />
- </ElFormItem>
- ))}
- </>
- )
- }}
- </ElFormItem>
- )}
- <div class={styles.fAlert}>曲目信息</div>
- <ElFormItem
- label="曲目名称"
- prop="name"
- rules={[{ required: true, message: '请输入曲目名称' }]}
- >
- <ElInput
- v-model={this.form.name}
- placeholder="请选择曲目名称"
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- maxlength={50}
- showWordLimit
- />
- </ElFormItem>
- <ElFormItem
- label="音乐人"
- prop="composer"
- rules={[{ required: true, message: '请输入音乐人' }]}
- >
- <ElInput
- v-model={this.form.composer}
- placeholder="请输入音乐人"
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- maxlength={14}
- showWordLimit
- />
- </ElFormItem>
- <ElFormItem label="曲目描述" prop="remark">
- <ElInput
- v-model={this.form.remark}
- placeholder="请输入曲目描述"
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- maxlength={200}
- showWordLimit
- type="textarea"
- />
- </ElFormItem>
- <ElFormItem
- label="曲谱封面"
- prop="musicCover"
- rules={[
- {
- required: true,
- message: '请上传曲谱封面'
- }
- ]}
- >
- <ColCropper
- modelValue={this.form.musicCover}
- bucket={'cloud-coach'}
- cropUploadSuccess={(data: any) => {
- this.form.musicCover = data
- }}
- onRemove={() => {
- this.form.musicCover = ''
- }}
- delete={!this.auditDisabled}
- disabled={this.auditDisabled}
- domSize={{ height: '150px' }}
- options={{
- title: '曲谱封面',
- enlarge: 2,
- autoCropWidth: 300,
- autoCropHeight: 300
- }}
- />
- </ElFormItem>
- <ElFormItem
- label="曲目速度"
- prop="playSpeed"
- rules={[{ required: true, message: '请输入曲目速度' }]}
- >
- <ElInputNumber
- controls={false}
- v-model={this.form.playSpeed}
- placeholder="请输入曲目速度"
- min={45}
- max={270}
- />
- </ElFormItem>
- <ElFormItem
- label="曲目标签"
- prop="tags"
- rules={[{ required: true, message: '请选择曲目标签' }]}
- >
- <ElSelect
- multiple
- v-model={this.form.tags}
- placeholder="请选择曲目标签"
- multipleLimit={3}
- class="w-full"
- >
- {this.tagList.map((item: any) => (
- <ElOption key={item.id} value={item.id} label={item.name} />
- ))}
- </ElSelect>
- {/* </div> */}
- </ElFormItem>
- <ElFormItem
- label="是否收费"
- prop="paymentType"
- rules={[{ required: true, message: '请选择是否收费' }]}
- >
- <ElRadioGroup v-model={this.form.paymentType}>
- <ElRadioButton label={'CHARGE'} class="mr-3 w-24">
- 是
- </ElRadioButton>
- <ElRadioButton label={'FREE'} class="w-24">
- 否
- </ElRadioButton>
- </ElRadioGroup>
- </ElFormItem>
- {this.form.paymentType === 'CHARGE' && (
- <>
- <ElFormItem
- label="收费价格"
- prop="musicPrice"
- rules={[{ required: true, validator }]}
- >
- <ElInput
- v-model={this.form.musicPrice}
- placeholder="请输入收费价格"
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- maxlength={5}
- onKeyup={this.onFormatter}
- v-slots={{
- suffix: () => <span class="text-base text-[#999]">元</span>
- }}
- />
- </ElFormItem>
- <ElFormItem>
- <div class={styles.rule}>
- <p>
- 扣除手续费后该曲目预计收入为:
- <span>
- {((parseFloat(this.form.musicPrice || '0') || 0) *
- (100 - this.music_sheet_service_fee)) /
- 100}
- <span>元/人</span>
- </span>
- </p>
- <p>
- 您的乐谱收入在学员购买后{this.music_account_period}
- 天结算到您的账户中
- </p>
- </div>
- </ElFormItem>
- </>
- )}
- </ElForm>
- {!this.auditDisabled && (
- <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.filter((el: any) => {
- return el != ''
- })
- this.tagStatus = false
- ;(this as any).$refs.form.clearValidate('tags')
- }}
- >
- 确认
- </ElButton>
- </div>
- </ElDialog> */}
- <ElDialog
- modelValue={this.visibleShow}
- onUpdate:modelValue={val => (this.visibleShow = val)}
- destroyOnClose={true}
- customClass={styles.messageDialog}
- >
- <MessageTip
- type={'upload'}
- title={'上传须知'}
- onConfirm={() => {
- localStorage.setItem('isCatchTip', '1')
- this.visibleShow = false
- }}
- />
- </ElDialog>
- <ElDialog
- modelValue={this.visibleShow2}
- onUpdate:modelValue={val => (this.visibleShow2 = val)}
- destroyOnClose={true}
- customClass={styles.messageDialog2}
- >
- <MessageTip
- type={'error'}
- title={'解析失败'}
- onConfirm={() => (this.visibleShow2 = false)}
- />
- </ElDialog>
- <ElDialog
- modelValue={this.visibleAudio}
- onUpdate:modelValue={val => (this.visibleAudio = val)}
- destroyOnClose={true}
- customClass={styles.messageDialog3}
- appendToBody
- >
- {this.visibleAudio && <ListenAudio fileInfo={this.fileInfo} />}
- </ElDialog>
- </div>
- )
- }
- })
|