music-operationV2.tsx 93 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593
  1. import type { SelectOption } from 'naive-ui'
  2. import {
  3. NAlert,
  4. NButton,
  5. NCascader,
  6. NCheckbox,
  7. NCheckboxGroup,
  8. NDivider,
  9. NForm,
  10. NFormItem,
  11. NFormItemGi,
  12. NGi,
  13. NGrid,
  14. NInput,
  15. NInputGroup,
  16. NInputGroupLabel,
  17. NInputNumber,
  18. NModal,
  19. NRadio,
  20. NRadioGroup,
  21. NSelect,
  22. NSpace,
  23. NSpin,
  24. useDialog,
  25. useMessage
  26. } from 'naive-ui'
  27. import { defineComponent, onMounted, PropType, reactive, ref, watch } from 'vue'
  28. import { musicSheetCategoriesQueryTree, musicSheetDetail, musicSheetSave } from '../../api'
  29. import UploadFile from '@/components/upload-file'
  30. import styles from './index.module.less'
  31. import deepClone from '@/utils/deep.clone'
  32. import axios from 'axios'
  33. import { appKey, clientType, musicSheetSourceType } from '@/utils/constant'
  34. import { getMapValueByKey, getSelectDataFromObj } from '@/utils/objectUtil'
  35. import { musicalInstrumentPage } from '@views/system-manage/subject-manage/api'
  36. import { subjectPage } from '@views/system-manage/api'
  37. import MusicSheetOwnerDialog from '@views/music-library/music-sheet/modal/musicSheetOwnerDialog'
  38. import { sysApplicationPage } from '@views/menu-manage/api'
  39. import { filterPointCategory } from '@views/teaching-manage/unit-test'
  40. import MusicCreateImg from './music-create-img'
  41. import MusiceBeatTime from './musiceBeatTime'
  42. /**
  43. * 获取指定元素下一个Note元素
  44. * @param ele 指定元素
  45. * @param selectors 选择器
  46. */
  47. const getNextNote = (ele: any, selectors: any) => {
  48. let index = 0
  49. const parentEle = ele.closest(selectors)
  50. let pointer = parentEle
  51. const measure = parentEle?.closest('measure')
  52. let siblingNote = null
  53. // 查找到相邻的第一个note元素
  54. while (!siblingNote && index < (measure?.childNodes.length || 50)) {
  55. index++
  56. if (pointer?.nextElementSibling?.tagName === 'note') {
  57. siblingNote = pointer?.nextElementSibling
  58. }
  59. pointer = pointer?.nextElementSibling
  60. }
  61. return siblingNote
  62. }
  63. export const onlyVisible = (xml: any, partIndex: any) => {
  64. if (!xml) return ''
  65. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  66. const partList =
  67. xmlParse.getElementsByTagName('part-list')?.[0]?.getElementsByTagName('score-part') || []
  68. const parts = xmlParse.getElementsByTagName('part')
  69. const visiblePartInfo = partList[partIndex]
  70. if (visiblePartInfo) {
  71. const id = visiblePartInfo.getAttribute('id')
  72. Array.from(parts).forEach((part) => {
  73. if (part && part.getAttribute('id') !== id) {
  74. part.parentNode?.removeChild(part)
  75. // 不等于第一行才添加避免重复添加
  76. }
  77. // 最后一个小节的结束线元素不在最后 调整
  78. if (part && part.getAttribute('id') === id) {
  79. const barlines = part.getElementsByTagName('barline')
  80. const lastParent = barlines[barlines.length - 1]?.parentElement
  81. if (lastParent?.lastElementChild?.tagName !== 'barline') {
  82. const children: any[] = (lastParent?.children as any) || []
  83. for (let el of children) {
  84. if (el.tagName === 'barline') {
  85. // 将结束线元素放到最后
  86. lastParent?.appendChild(el)
  87. break
  88. }
  89. }
  90. }
  91. }
  92. })
  93. Array.from(partList).forEach((part) => {
  94. if (part && part.getAttribute('id') !== id) {
  95. part.parentNode?.removeChild(part)
  96. }
  97. })
  98. // 处理装饰音问题
  99. const notes = xmlParse.getElementsByTagName('note')
  100. const getNextvNoteDuration = (i: any) => {
  101. let nextNote = notes[i + 1]
  102. // 可能存在多个装饰音问题,取下一个非装饰音时值
  103. for (let index = i; index < notes.length; index++) {
  104. const note = notes[index]
  105. if (!note.getElementsByTagName('grace')?.length) {
  106. nextNote = note
  107. break
  108. }
  109. }
  110. return nextNote?.getElementsByTagName('duration')[0]
  111. }
  112. Array.from(notes).forEach((note, i) => {
  113. const graces = note.getElementsByTagName('grace')
  114. if (graces && graces.length) {
  115. note.appendChild(getNextvNoteDuration(i)?.cloneNode(true))
  116. }
  117. })
  118. }
  119. return new XMLSerializer().serializeToString(xmlParse)
  120. }
  121. const speedInfo = {
  122. 'rall.': 1.333333333,
  123. 'poco rit.': 1.333333333,
  124. 'rit.': 1.333333333,
  125. 'molto rit.': 1.333333333,
  126. 'molto rall': 1.333333333,
  127. molto: 1.333333333,
  128. lentando: 1.333333333,
  129. allargando: 1.333333333,
  130. morendo: 1.333333333,
  131. 'accel.': 0.8,
  132. calando: 2,
  133. 'poco accel.': 0.8,
  134. 'gradually slowing': 1.333333333,
  135. slowing: 1.333333333,
  136. slow: 1.333333333,
  137. slowly: 1.333333333,
  138. faster: 1.333333333
  139. }
  140. /**
  141. * 按照xml进行减慢速度的计算
  142. * @param xml 始终按照第一分谱进行减慢速度的计算
  143. */
  144. export function getGradualLengthByXml(xml: string) {
  145. const firstPartXml = onlyVisible(xml, 0)
  146. const xmlParse = new DOMParser().parseFromString(firstPartXml, 'text/xml')
  147. const measures = Array.from(xmlParse.querySelectorAll('measure'))
  148. const notes = Array.from(xmlParse.querySelectorAll('note'))
  149. const words = Array.from(xmlParse.querySelectorAll('words'))
  150. const metronomes = Array.from(xmlParse.querySelectorAll('metronome'))
  151. const eles = []
  152. for (const ele of [...words, ...metronomes]) {
  153. const note = getNextNote(ele, 'direction')
  154. // console.log(ele, note)
  155. if (note) {
  156. const measure = note?.closest('measure')
  157. const measureNotes = Array.from(measure.querySelectorAll('note'))
  158. const noteInMeasureIndex = Array.from(measure.childNodes)
  159. .filter((item: any) => item.nodeName === 'note')
  160. .findIndex((item) => item === note)
  161. let allDuration = 0
  162. let leftDuration = 0
  163. for (let i = 0; i < measureNotes.length; i++) {
  164. const n: any = measureNotes[i]
  165. const duration = +(n.querySelector('duration')?.textContent || '0')
  166. allDuration += duration
  167. if (i < noteInMeasureIndex) {
  168. leftDuration = allDuration
  169. }
  170. }
  171. eles.push({
  172. ele,
  173. index: notes.indexOf(note),
  174. noteInMeasureIndex,
  175. textContent: ele.textContent,
  176. // measureIndex: measures.indexOf(measure), //,measure?.getAttribute('number')
  177. measureIndex: measure?.getAttribute('number') ? Number(measure?.getAttribute('number')) : measures.indexOf(measure),
  178. type: ele.tagName,
  179. allDuration,
  180. leftDuration
  181. })
  182. }
  183. }
  184. // 结尾处手动插入一个音符节点
  185. eles.push({
  186. ele: notes[notes.length - 1],
  187. index: notes.length,
  188. noteInMeasureIndex: 0,
  189. textContent: '',
  190. type: 'metronome',
  191. allDuration: 1,
  192. leftDuration: 1,
  193. measureIndex: measures.length
  194. })
  195. const gradualNotes: any[] = []
  196. eles.sort((a, b) => a.index - b.index)
  197. const keys = Object.keys(speedInfo).map((w) => w.toLocaleLowerCase())
  198. let isLastNoteAndNotClosed = false
  199. for (const ele of eles) {
  200. const textContent: any = ele.textContent?.toLocaleLowerCase().trim()
  201. if (ele === eles[eles.length - 1]) {
  202. if (gradualNotes[gradualNotes.length - 1]?.length === 1) {
  203. isLastNoteAndNotClosed = true
  204. }
  205. }
  206. const isKeyWork = keys.find((k) => {
  207. const ks = k.split(' ')
  208. return textContent && ks.includes(textContent)
  209. })
  210. if (
  211. ele.type === 'metronome' ||
  212. (ele.type === 'words' && (textContent.startsWith('a tempo') || isKeyWork)) ||
  213. isLastNoteAndNotClosed
  214. ) {
  215. const indexOf = gradualNotes.findIndex((item) => item.length === 1)
  216. if (indexOf > -1 && ele.index > gradualNotes[indexOf]?.[0].start) {
  217. gradualNotes[indexOf][1] = {
  218. start: ele.index,
  219. measureIndex: ele.measureIndex,
  220. noteInMeasureIndex: ele.noteInMeasureIndex,
  221. allDuration: ele.allDuration,
  222. leftDuration: ele.leftDuration,
  223. type: textContent
  224. }
  225. }
  226. }
  227. if (ele.type === 'words' && isKeyWork) {
  228. gradualNotes.push([
  229. {
  230. start: ele.index,
  231. measureIndex: ele.measureIndex,
  232. noteInMeasureIndex: ele.noteInMeasureIndex,
  233. allDuration: ele.allDuration,
  234. leftDuration: ele.leftDuration,
  235. type: textContent
  236. }
  237. ])
  238. }
  239. }
  240. return gradualNotes
  241. }
  242. export type FormatXMLInfo = {
  243. speed: number
  244. title: string
  245. composer: string
  246. partNames: string[]
  247. }
  248. /** 获取xml基本信息,标题,速度等信息 */
  249. export const getXmlInfo = (xml: string): FormatXMLInfo => {
  250. const data: FormatXMLInfo = {
  251. /** 速度 */
  252. speed: 0,
  253. /** 标题 */
  254. title: '',
  255. /** 作曲人 */
  256. composer: '',
  257. /** 声部列表 */
  258. partNames: []
  259. }
  260. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  261. data.title = xmlParse.getElementsByTagName('work-title')[0]?.textContent || ''
  262. data.composer = xmlParse.getElementsByTagName('creator')[0]?.textContent || ''
  263. const measures = xmlParse.getElementsByTagName('measure')
  264. for (const item of Array.from(xmlParse.getElementsByTagName('part-name'))) {
  265. if (item.textContent) {
  266. data.partNames.push(item.textContent)
  267. }
  268. }
  269. for (const measure of Array.from(measures)) {
  270. const perMinute = measure.getElementsByTagName('per-minute')
  271. if (perMinute.length && perMinute[perMinute.length - 1]) {
  272. data.speed = parseFloat(perMinute[perMinute.length - 1].textContent || '0')
  273. break
  274. }
  275. }
  276. return data
  277. }
  278. export default defineComponent({
  279. name: 'music-operation',
  280. props: {
  281. type: {
  282. type: String,
  283. default: 'add'
  284. },
  285. data: {
  286. type: Object as PropType<any>,
  287. default: () => {}
  288. },
  289. tagList: {
  290. type: Array as PropType<Array<SelectOption>>,
  291. default: () => []
  292. },
  293. subjectList: {
  294. type: Array as PropType<Array<SelectOption>>,
  295. default: () => []
  296. }
  297. // musicSheetCategories: {
  298. // type: Array as PropType<Array<SelectOption>>,
  299. // default: () => []
  300. // }
  301. },
  302. emits: ['close', 'getList'],
  303. setup(props, { slots, attrs, emit }) {
  304. const forms = reactive({
  305. details: {} as any, // 曲目详情
  306. graduals: {} as any, // 渐变速度
  307. playMode: 'MP3', // 播放类型
  308. xmlFileUrl: null, // XML
  309. midiUrl: null, // mid
  310. name: null, // 曲目名称
  311. // musicTag: [] as any, // 曲目标签
  312. composer: null as any, // 音乐人
  313. playSpeed: null as any, // 曲谱速度
  314. // showFingering: null as any, // 是否显示指法
  315. // canEvaluate: null as any, // 是否评测
  316. // notation: null as any, // 能否转和简谱
  317. // auditVersion: null as any, // 审核版本
  318. // sortNumber: null, // 排序
  319. musicCover: null, // 曲谱封面
  320. remark: null, // 曲谱描述
  321. // musicSheetSoundList: [] as any, // 原音
  322. musicSheetSoundList_YY: [] as any, // 演唱原音
  323. musicSheetSoundList_YZ: [] as any, // 演奏演奏
  324. musicSheetSoundList_all_subject: null, // 全部声部原音
  325. // musicSheetCategoriesId: null,
  326. status: false,
  327. musicSheetType: 'CONCERT', // 曲目类型
  328. sourceType: 'PLATFORM' as any, //来源类型/作者属性(PLATFORM: 平台; ORG: 机构; PERSON: 个人)
  329. // userId: null, // 所属人
  330. appAuditFlag: 0, // 是否审核版本
  331. midiFileUrl: null, // 伴奏文件 MIDI文件(保留字段)
  332. subjectIds: [] as any, // 可用声部
  333. musicalInstrumentIdList: [] as any, //可用乐器
  334. musicCategoryId: null, //曲目分类
  335. musicSheetAccompanimentList: [] as any, //曲目伴奏
  336. audioType: 'HOMEMODE', // 伴奏类型
  337. isPlayBeat: true, // 是否播放节拍器
  338. isUseSystemBeat: true, // 是否使用系统节拍器(0:否;1:是)
  339. isUseSingSystemBeat: true, //演唱是否使用系统节拍器(0:否;1:是)
  340. repeatedBeats: false, // 是否重复节拍时长
  341. repeatedBeatsToSing: false, //演唱是否重复节拍时长
  342. isPlaySingBeat: true, //是否播入演唱节拍器(0: 否 1:是)
  343. evaluationStandard: 'FREQUENCY', // 评分标准 节奏 AMPLITUDE 音准 FREQUENCY 分贝 DECIBELS
  344. multiTracksSelection: [] as any, // 声轨
  345. musicSheetExtend: {} as any, //所属人信息
  346. musicImg: '', // 五线谱图片
  347. musicFirstImg: '', //首调图片
  348. musicJianImg: '', // 简谱固定调
  349. isEvxml: false, // 是否是evxml
  350. isShowFingering: true, // 是否显示指法
  351. solmizationFileUrl: null, // 唱名文件
  352. isAllSubject: false, // 适用声部
  353. fSongList: [] as any, // 范唱列表
  354. isScoreRender: true, // 总谱渲染
  355. defaultScoreRender: true, // 演奏是否默认展示总谱渲染
  356. scoreAudioFileUrl: null as any // 总谱文件
  357. })
  358. const state = reactive({
  359. loading: false,
  360. musicUpdateLoading: false, // 是否在加载 中
  361. previewMode: false, //是否是预览模式
  362. tagList: [...props.tagList] as any, // 标签列表
  363. xmlFirstSpeed: null as any, // 第一个音轨速度
  364. partListNames: [] as any, // 所有音轨声部列表
  365. musicSheetCategories: [] as any,
  366. musicSheetAccompanimentUrl: null as any,
  367. instrumentData: [],
  368. instrumentList: [] as any,
  369. instrumentIdNameMap: new Map() as any,
  370. subjectList: [] as any,
  371. showMusicSheetOwnerDialog: false, //所属人弹框
  372. // musicSheetOwnerData: {}, //所属人信息
  373. multiTracks: null as any,
  374. multiInstruments: null,
  375. appData: [], // 应用列表
  376. ownerName: null as any, // 所属人名称描述
  377. productOpen: false, // 是否打开自动生成图片
  378. productItem: {} as any,
  379. productIfameSrc: '',
  380. isAutoSave: false, // 是否自动保存
  381. bSongFile: null as any, // 伴唱
  382. musicSheetSoundList: [] as any,
  383. subjectDisabled: false, // 声部不可用
  384. instrumentDisabled: false, // 乐器不可用
  385. initFSongMap: new Map() as any //初始化的范唱
  386. })
  387. const gradualData = reactive({
  388. list: [] as any[],
  389. gradualRefs: [] as any[]
  390. })
  391. const beatTimeData = reactive({
  392. beatTimeOpen: false,
  393. musicId: ''
  394. })
  395. watch(
  396. () => forms.multiTracksSelection,
  397. (value) => {
  398. // 在修改的时候不用自动更新
  399. if(state.musicUpdateLoading) return
  400. initInstrumentAndSubjectByTrack(value)
  401. initFSongList()
  402. }
  403. )
  404. const btnLoading = ref(false)
  405. const formsRef = ref()
  406. const message = useMessage()
  407. const dialog = useDialog()
  408. // 提交记录
  409. const onSubmit = async () => {
  410. formsRef.value.validate(async (error: any) => {
  411. if (error) {
  412. return
  413. }
  414. // 校验合奏时声轨与乐器是否存在不匹配情况
  415. if (forms.musicSheetType == 'CONCERT') {
  416. let set = [] as any
  417. const { data } = await musicalInstrumentPage({ page: 1, rows: 9999 })
  418. data.rows.map((row: any) => {
  419. if (row.code) {
  420. row.code.split(',').forEach((code: string) => {
  421. set.push(code.replaceAll(' ', '').toLocaleLowerCase())
  422. })
  423. }
  424. })
  425. let unDefinedTrack = [] as any
  426. forms.multiTracksSelection.forEach((item: any) => {
  427. if (item && !isPtrack(item)) {
  428. let contain = false
  429. let code = item.replace(' ', '').toLocaleLowerCase()
  430. for (let i = 0; i < set.length; i++) {
  431. if (code.startsWith(set[i])) {
  432. contain = true
  433. break
  434. }
  435. }
  436. if (!contain) {
  437. unDefinedTrack.push(item)
  438. }
  439. }
  440. })
  441. if (unDefinedTrack.length > 0) {
  442. dialog.warning({
  443. title: '提示',
  444. content: `声轨未配置:${unDefinedTrack.join(',')}`,
  445. positiveText: '确定',
  446. onPositiveClick: () => {}
  447. })
  448. return
  449. }
  450. }
  451. try {
  452. //extConfigJson: {"repeatedBeats":0,"gradualTimes":{"75":"02:38:60","77":"02:43:39"}}
  453. let audioPlayTypes = new Set() as any
  454. let musicSheetSoundList = []
  455. let musicSheetType = forms.musicSheetType
  456. let existYzFile = false
  457. // console.log({
  458. // musicSheetType,
  459. // fSongList: forms.fSongList,
  460. // isAllSubject: forms.isAllSubject,
  461. // musicSheetSoundList_all_subject: forms.musicSheetSoundList_all_subject,
  462. // musicSheetSoundList_YZ: forms.musicSheetSoundList_YZ,
  463. // playMode: forms.playMode,
  464. // musicalInstrumentIdList: forms.musicalInstrumentIdList
  465. // })
  466. if (musicSheetType == 'SINGLE') {
  467. if (forms.isAllSubject) {
  468. if (forms.musicSheetSoundList_all_subject) {
  469. audioPlayTypes.add('PLAY')
  470. musicSheetSoundList.push({
  471. audioFileUrl: forms.musicSheetSoundList_all_subject,
  472. musicSheetId: props.data.id,
  473. audioPlayType: 'PLAY'
  474. })
  475. existYzFile = true
  476. }
  477. } else {
  478. if (forms.musicSheetSoundList_YZ.length > 0) {
  479. forms.musicSheetSoundList_YZ.forEach((musicSheetSound: any) => {
  480. if (
  481. forms.musicalInstrumentIdList.includes(musicSheetSound.musicalInstrumentId) &&
  482. musicSheetSound.audioFileUrl
  483. ) {
  484. existYzFile = true
  485. musicSheetSoundList.push({
  486. ...musicSheetSound,
  487. musicSheetId: props.data.id
  488. })
  489. // 判断是否显示
  490. if (!audioPlayTypes.has('PLAY')) {
  491. audioPlayTypes.add('PLAY')
  492. }
  493. }
  494. })
  495. }
  496. }
  497. } else if (musicSheetType == 'CONCERT') {
  498. forms.musicSheetSoundList_YY.forEach((musicSheetSound: any) => {
  499. if (
  500. musicSheetSound.audioFileUrl &&
  501. forms.multiTracksSelection.includes(musicSheetSound.track)
  502. ) {
  503. musicSheetSoundList.push({
  504. ...musicSheetSound,
  505. musicalInstrumentId:
  506. musicSheetSound.musicalInstrumentId ||
  507. instrumentCodeToInstrumentId(musicSheetSound.track),
  508. musicSheetId: props.data.id,
  509. audioPlayType: 'PLAY'
  510. })
  511. existYzFile = true
  512. if (!audioPlayTypes.has('PLAY')) {
  513. audioPlayTypes.add('PLAY')
  514. }
  515. }
  516. })
  517. }
  518. // 判断 伴唱 范唱 唱名只有上传一个都可以上传
  519. let existFSFile = false
  520. for (let i = 0; i < forms.fSongList.length; i++) {
  521. let fSong = forms.fSongList[i]
  522. if (fSong.audioFileUrl || fSong.solmizationFileUrl || fSong.femaleSolmizationFileUrl) {
  523. musicSheetSoundList.push(fSong)
  524. audioPlayTypes.add('SING')
  525. existFSFile = true
  526. }
  527. }
  528. // 总谱 伴唱判断
  529. if (forms.scoreAudioFileUrl || state.bSongFile) {
  530. existFSFile = true
  531. }
  532. // 演唱 演奏只要有一个上传都可以
  533. if (!existFSFile && !existYzFile) {
  534. message.warning('请上传音频文件')
  535. return
  536. }
  537. // 生成图片
  538. if (!state.isAutoSave) {
  539. state.isAutoSave = true
  540. state.productOpen = true
  541. return
  542. }
  543. // 判断是否有总谱
  544. if (forms.scoreAudioFileUrl) {
  545. forms.musicSheetAccompanimentList.push({
  546. musicSheetId: props.data.id,
  547. audioFileUrl: state.bSongFile,
  548. scoreAudioFileUrl:
  549. forms.multiTracksSelection.length > 1 &&
  550. forms.isScoreRender &&
  551. forms.scoreAudioFileUrl
  552. ? forms.scoreAudioFileUrl
  553. : null,
  554. audioPlayType: 'SING'
  555. })
  556. }
  557. if (state.musicSheetAccompanimentUrl) {
  558. forms.musicSheetAccompanimentList.push({
  559. musicSheetId: props.data.id,
  560. audioFileUrl: state.musicSheetAccompanimentUrl,
  561. audioPlayType: 'PLAY'
  562. })
  563. }
  564. let isScoreRender
  565. let defaultScoreRender
  566. if (forms.multiTracksSelection.length > 1) {
  567. isScoreRender = forms.isScoreRender
  568. if (forms.isScoreRender) {
  569. defaultScoreRender = forms.defaultScoreRender
  570. }
  571. }
  572. const obj = {
  573. musicCategoryId: forms.musicCategoryId,
  574. musicCover: forms.musicCover,
  575. name: forms.name,
  576. appAuditFlag: forms.appAuditFlag,
  577. subjectIds: forms.isAllSubject ? '' : forms.subjectIds.join(','),
  578. remark: forms.remark,
  579. audioPlayTypes: Array.from(audioPlayTypes).join(','),
  580. musicalInstrumentIds: forms.isAllSubject ? '' : forms.musicalInstrumentIdList.join(','),
  581. composer: forms.composer,
  582. musicSheetType: forms.musicSheetType,
  583. isUseSystemBeat: forms.isUseSystemBeat,
  584. isShowFingering: forms.isShowFingering,
  585. isPlayBeat: forms.isPlayBeat,
  586. multiTracksSelection: forms.multiTracksSelection.join(','),
  587. playSpeed: forms.playSpeed,
  588. playMode: forms.playMode,
  589. xmlFileUrl: forms.xmlFileUrl,
  590. musicImg: forms.musicImg,
  591. musicFirstImg: forms.musicFirstImg,
  592. musicJianImg: forms.musicJianImg,
  593. extConfigJson: JSON.stringify({
  594. repeatedBeats: forms.repeatedBeats ? 1 : 0,
  595. gradualTimes: forms.graduals,
  596. isEvxml: forms.isEvxml ? 1 : 0,
  597. repeatedBeatsToSing: forms.repeatedBeatsToSing ? 1 : 0
  598. }),
  599. // availableType: forms.availableType,
  600. sourceType: forms.sourceType,
  601. audioType: forms.audioType,
  602. status: forms.status,
  603. evaluationStandard: forms.evaluationStandard,
  604. musicSheetAccompanimentList: forms.musicSheetAccompanimentList,
  605. musicSheetSoundList: musicSheetSoundList,
  606. musicTag: '-1',
  607. isUseSingSystemBeat: forms.isUseSingSystemBeat,
  608. isPlaySingBeat: forms.isPlaySingBeat,
  609. isAllSubject: forms.isAllSubject,
  610. musicSheetExtend: forms.sourceType == 'PLATFORM' ? null : forms.musicSheetExtend,
  611. isScoreRender: isScoreRender,
  612. defaultScoreRender: defaultScoreRender
  613. }
  614. if (forms.audioType == 'MIDI') {
  615. obj.musicSheetSoundList = []
  616. }
  617. btnLoading.value = true
  618. let resData: any
  619. if (props.type === 'add') {
  620. resData = await musicSheetSave(obj)
  621. } else if (props.type === 'edit') {
  622. resData = await musicSheetSave({ ...obj, id: props.data.id })
  623. }
  624. beatTimeData.beatTimeOpen = true
  625. beatTimeData.musicId = resData.data
  626. } catch (e) {
  627. console.log(e)
  628. setTimeout(() => {
  629. btnLoading.value = false
  630. state.isAutoSave = false
  631. }, 100)
  632. }
  633. })
  634. }
  635. // 合成节拍器的回调
  636. function handlerMusiceBeatTimeClose() {
  637. if (props.type === 'add') {
  638. message.success('添加成功')
  639. } else if (props.type === 'edit') {
  640. message.success('修改成功')
  641. }
  642. emit('getList')
  643. emit('close')
  644. setTimeout(() => {
  645. btnLoading.value = false
  646. state.isAutoSave = false
  647. }, 100)
  648. }
  649. const isPtrack = async (track: string) => {
  650. if (track && (track == 'P1' || track == 'P2' || track == 'P3' || track == 'P4')) {
  651. return true
  652. }
  653. return false
  654. }
  655. const initFSongList = async () => {
  656. forms.fSongList.forEach((fSong: any) => {
  657. state.initFSongMap.set(fSong.track, fSong)
  658. })
  659. let fSongList = [] as any
  660. forms.multiTracksSelection.forEach((item: any) => {
  661. if (state.initFSongMap.has(item)) {
  662. fSongList.push(state.initFSongMap.get(item))
  663. } else {
  664. fSongList.push({
  665. musicSheetId: props.data.id,
  666. audioFileUrl: null,
  667. audioPlayType: 'SING',
  668. musicalInstrumentId: null,
  669. track: item,
  670. // musicalInstrumentName: state.instrumentIdNameMap.get(item),
  671. musicalInstrumentName: null,
  672. solmizationFileUrl: null, // 唱名男
  673. femaleSolmizationFileUrl: null // 唱名女
  674. })
  675. }
  676. })
  677. forms.fSongList = fSongList
  678. }
  679. // 上传XML,初始化音轨 音轨速度 乐器、声部
  680. const readFileInputEventAsArrayBuffer = (file: any) => {
  681. // 是否是evxml
  682. const xmlRead = new FileReader()
  683. xmlRead.onload = (res) => {
  684. try {
  685. gradualData.list = getGradualLengthByXml(res?.target?.result as any).filter(
  686. (item: any) => item.length === 2
  687. )
  688. // 音乐人中有值,则不做更新
  689. const result = getXmlInfo(res?.target?.result as any)
  690. if (!forms.composer) {
  691. forms.composer = result.composer
  692. }
  693. } catch (error) {}
  694. forms.musicSheetSoundList_YY = forms.musicSheetSoundList_YY.filter((item: any) => {
  695. return (
  696. !item.track ||
  697. !containOther(item.track) ||
  698. (item.track?.toLocaleUpperCase?.() != 'COMMON' &&
  699. forms.multiTracksSelection.includes(item.track))
  700. )
  701. })
  702. state.partListNames = getPartListNames(res?.target?.result as any) as any
  703. // parseInstrumentAndSubject(res?.target?.result as any)
  704. // 这里是如果没有当前音轨就重新写
  705. let map = new Map<String, String>()
  706. for (let i = 0; i < forms.musicSheetSoundList_YY.length; i++) {
  707. let track = forms.musicSheetSoundList_YY[i].track
  708. if (track) {
  709. map.set(track, forms.musicSheetSoundList_YY[i])
  710. }
  711. }
  712. let newMusicSheetSoundList = []
  713. let tracks = [] as any
  714. for (let j = 0; j < state.partListNames.length; j++) {
  715. let track = state.partListNames[j].value
  716. if (map.has(track)) {
  717. newMusicSheetSoundList.push(map.get(track))
  718. } else {
  719. newMusicSheetSoundList.push({
  720. audioFileUrl: null,
  721. track: track,
  722. musicalInstrumentId: null
  723. })
  724. }
  725. tracks.push(track)
  726. if (!forms.multiTracksSelection.includes(track)) {
  727. forms.multiTracksSelection.push(track)
  728. }
  729. }
  730. for (let i = 0; i < forms.musicSheetSoundList_YY.length; i++) {
  731. let track = forms.musicSheetSoundList_YY[i].track
  732. if (!track || !tracks.includes(track)) {
  733. forms.musicSheetSoundList_YY[i].track = null
  734. newMusicSheetSoundList.push(forms.musicSheetSoundList_YY[i])
  735. }
  736. }
  737. forms.musicSheetSoundList_YY = newMusicSheetSoundList
  738. forms.multiTracksSelection = forms.multiTracksSelection.filter((track: any) => {
  739. return tracks.includes(track)
  740. })
  741. // 全选选中
  742. state.multiTracks = 'all'
  743. // 循环添加所在音轨的原音
  744. // for (let index = forms.musicSheetSoundList.length; index < state.partListNames.length; index++) {
  745. // const part = state.partListNames[index].value
  746. // const sysData = {
  747. // ...forms.musicSheetSoundList[0],
  748. // track: part
  749. // }
  750. // if (!sysData.speed) {
  751. // sysData.speed = state.xmlFirstSpeed
  752. // }
  753. // createSys(sysData)
  754. // }
  755. if (forms.musicSheetSoundList_YY.length == 0) {
  756. forms.musicSheetSoundList_YY.push({ audioFileUrl: '', track: '' })
  757. }
  758. }
  759. xmlRead.readAsText(file)
  760. }
  761. const containOther = (track: any) => {
  762. for (let i = 0; i < state.partListNames.length; i++) {
  763. if (state.partListNames[i].value == track) {
  764. return true
  765. }
  766. }
  767. return false
  768. }
  769. const validSoundNum = () => {
  770. return forms.musicSheetSoundList_YY.filter((item: any) => {
  771. return (
  772. !item.track ||
  773. !containOther(item.track) ||
  774. (item.track?.toLocaleUpperCase?.() != 'COMMON' &&
  775. forms.multiTracksSelection.includes(item.track))
  776. )
  777. }).length
  778. }
  779. const parseInstrumentAndSubject = (xml: any) => {
  780. if (!xml) return
  781. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  782. // 乐器
  783. const instrumentCodeList: any = []
  784. const instrumentEle = xmlParse.getElementsByTagName('virtual-instrument')
  785. for (let index = 0; index < instrumentEle.length; index++) {
  786. const note = instrumentEle[index]
  787. let instrumentCode = note.getElementsByTagName('virtual-name')?.[0]?.textContent || ''
  788. instrumentCode = instrumentCode.toLocaleLowerCase().trim()
  789. if (instrumentCode && !instrumentCodeList.includes(instrumentCode)) {
  790. instrumentCodeList.push(instrumentCode)
  791. }
  792. }
  793. // 乐器支持多编码,暂不开放
  794. initInstrumentAndSubjectByTrack(instrumentCodeList)
  795. }
  796. /** 通过声轨反显乐器和声部 */
  797. const initInstrumentAndSubjectByTrack = async (tracks: string[]) => {
  798. // 选择一个声轨,独奏
  799. // 选择了多个声轨,合奏,乐器和声部自动反显,不可修改
  800. if (!tracks || tracks.length <= 1) {
  801. forms.musicSheetType = 'SINGLE'
  802. state.subjectDisabled = false
  803. state.instrumentDisabled = false
  804. return
  805. }
  806. forms.musicSheetType = 'CONCERT'
  807. state.subjectDisabled = true
  808. state.instrumentDisabled = true
  809. await initInstrumentAndSubjectByCode(tracks)
  810. }
  811. /** 获取分轨名称 */
  812. const getInstrumentName = (instruments: any, name = '') => {
  813. name = name.toLocaleLowerCase().replace(/ /g, '').replace(/\d*/gi, '')
  814. if (!name) return ''
  815. for (let key of instruments) {
  816. const _key = key.toLocaleLowerCase().replace(/ /g, '')
  817. // if (_key.includes(name)) {
  818. // return key
  819. // }
  820. if (_key === name) {
  821. return _key
  822. }
  823. }
  824. // for (let key of instruments) {
  825. // const _key = key.toLocaleLowerCase().replace(/ /g, '')
  826. // if (name.includes(_key)) {
  827. // return key
  828. // }
  829. // }
  830. return ''
  831. }
  832. // 通过乐器编码反显乐器和声部
  833. const initInstrumentAndSubjectByCode = async (codes: string[]) => {
  834. // forms.musicalInstrumentIdList = []
  835. forms.subjectIds = []
  836. const codeIdMap = new Map<string, []>() as any
  837. const codeMapKeys: string[] = []
  838. state.instrumentData.forEach((data: any) => {
  839. if (!data.disabled) {
  840. const codes = data.code.split(/[,,]/)
  841. codes.forEach((code: string) => {
  842. let codeTemp = code.replaceAll(' ', '').toLowerCase()
  843. codeMapKeys.push(codeTemp)
  844. if (codeIdMap.has(codeTemp)) {
  845. codeIdMap.get(codeTemp).push(data.id + '')
  846. } else {
  847. const arr = [] as any
  848. arr.push(data.id + '')
  849. codeIdMap.set(codeTemp, arr)
  850. }
  851. })
  852. }
  853. })
  854. for (let i = 0; i < codes.length; i++) {
  855. let code = codes[i].replaceAll(' ', '').toLowerCase()
  856. const tempCode = getInstrumentName(codeMapKeys, code)
  857. if (codeIdMap.has(tempCode)) {
  858. codeIdMap.get(tempCode).forEach((c: any) => {
  859. const index = state.instrumentList.findIndex((item: any) => item.id.toString() === c)
  860. if (!forms.musicalInstrumentIdList.includes(c) && index !== -1) {
  861. forms.musicalInstrumentIdList.push(c)
  862. }
  863. })
  864. }
  865. }
  866. // 声部
  867. if (forms.musicalInstrumentIdList.length > 0) {
  868. await showBackSubject(forms.musicalInstrumentIdList)
  869. // changeSubject(forms.subjectIds)
  870. }
  871. }
  872. // 通过乐器编码返回乐器编号
  873. const instrumentCodeToInstrumentId = (code: string) => {
  874. const codeIdMap = new Map<string, []>() as any
  875. const codeMapKeys: string[] = []
  876. state.instrumentData.forEach((data: any) => {
  877. if (!data.disabled) {
  878. const codes = data.code.split(/[,,]/)
  879. codes.forEach((code: string) => {
  880. let codeTemp = code.replaceAll(' ', '').toLowerCase()
  881. codeMapKeys.push(codeTemp)
  882. if (codeIdMap.has(codeTemp)) {
  883. codeIdMap.get(codeTemp).push(data.id + '')
  884. } else {
  885. const arr = [] as any
  886. arr.push(data.id + '')
  887. codeIdMap.set(codeTemp, arr)
  888. }
  889. })
  890. }
  891. })
  892. if (!code) {
  893. return ''
  894. }
  895. code = code.replaceAll(' ', '').toLowerCase()
  896. const tempCode = getInstrumentName(codeMapKeys, code)
  897. if (codeIdMap.has(tempCode)) {
  898. const result = codeIdMap.get(tempCode)
  899. console.log('result:', result)
  900. return result[0] || ''
  901. }
  902. return ''
  903. }
  904. // 获取xml中所有轨道 乐器
  905. const getPartListNames = (xml: any) => {
  906. if (!xml) return []
  907. const xmlParse = new DOMParser().parseFromString(xml, 'text/xml')
  908. const partList: any =
  909. xmlParse.getElementsByTagName('part-list')?.[0]?.getElementsByTagName('score-part') || []
  910. let partListNames = Array.from(partList).map((item: any) => {
  911. let part = item.getElementsByTagName('part-name')?.[0]
  912. // evxml没有分轨,需要手动设置一个默认的名称,用于上传原音
  913. let track = ''
  914. if (forms.isEvxml) {
  915. // 秒极客曲目,取ID
  916. let id = item.getAttribute('id')
  917. if (id) {
  918. track = id
  919. }
  920. } else {
  921. // 优先解析声轨,没有就取id值
  922. if (part) {
  923. track = part.textContent || ''
  924. } else {
  925. let id = item.getAttribute('id')
  926. if (id) {
  927. track = id
  928. }
  929. }
  930. }
  931. return {
  932. value: track.trim(),
  933. label: track.trim()
  934. }
  935. })
  936. // 处理空数据
  937. // if (partListNames.length === 1 && forms.details.id && !partListNames[0].value) {
  938. // partListNames[0] = {
  939. // value: forms.details.multiTracksSelection,
  940. // label: forms.details.multiTracksSelection
  941. // }
  942. // }
  943. partListNames = partListNames.filter((n: any) => n.value?.toLocaleUpperCase?.() != 'COMMON')
  944. // if (partListNames.length > 0) {
  945. // forms.musicSheetSoundList = forms.musicSheetSoundList.slice(0, partListNames.length)
  946. // }
  947. state.xmlFirstSpeed = xmlParse.getElementsByTagName('per-minute')?.[0]?.textContent || ''
  948. if (!forms.playSpeed) {
  949. if (state.xmlFirstSpeed) {
  950. forms.playSpeed = Number.parseFloat(state.xmlFirstSpeed)
  951. } else {
  952. // 速度默认给100
  953. forms.playSpeed = 100
  954. }
  955. }
  956. // console.log('xml声轨',partListNames,state.xmlFirstSpeed)
  957. return partListNames
  958. }
  959. // 判断选择的音轨是否在选中
  960. const initPartsListStatus = (track: string): any => {
  961. // const _names = state.partListNames.filter(
  962. // (n: any) => n.value?.toLocaleUpperCase?.() != 'COMMON'
  963. // )
  964. const partListNames = deepClone(state.partListNames) || []
  965. const multiTracksSelection = forms.multiTracksSelection
  966. partListNames.forEach((item: any) => {
  967. if (multiTracksSelection.includes(item.value)) {
  968. item.disabled = true
  969. } else {
  970. item.disabled = false
  971. }
  972. // const index = forms.musicSheetSoundList.findIndex(
  973. // (ground: any) => item.value == ground.track
  974. // )
  975. // if (index > -1 && track == item.value) {
  976. // item.disabled = false
  977. // } else {
  978. // item.disabled = true
  979. // }
  980. })
  981. return partListNames || []
  982. }
  983. // 反显声部
  984. const showBackSubject = async (musicalInstrumentIdList: []) => {
  985. if (!musicalInstrumentIdList || musicalInstrumentIdList.length == 0) {
  986. forms.subjectIds = []
  987. return
  988. }
  989. try {
  990. const { data } = await subjectPage({
  991. page: 1,
  992. rows: 999,
  993. musicalInstrumentIdList: musicalInstrumentIdList
  994. })
  995. const tempList = data.rows || []
  996. const tempSubject: any[] = []
  997. tempList.forEach((item: any) => {
  998. tempSubject.push(item.id + '')
  999. })
  1000. forms.subjectIds = tempSubject
  1001. } catch {}
  1002. }
  1003. // 添加原音
  1004. const createSys = (initData?: any) => {
  1005. forms.musicSheetSoundList_YY.push({
  1006. audioFileUrl: null, // 原音
  1007. track: null, // 轨道
  1008. ...initData
  1009. })
  1010. }
  1011. // 删除原音
  1012. const removeSys = (index: number) => {
  1013. dialog.warning({
  1014. title: '提示',
  1015. content: `是否确认删除此原音?`,
  1016. positiveText: '确定',
  1017. negativeText: '取消',
  1018. onPositiveClick: async () => {
  1019. const sound = forms.musicSheetSoundList_YY[index]
  1020. let track = sound.track
  1021. // if (!track) {
  1022. // track = ''
  1023. // }
  1024. // if (track) {
  1025. const selectIndex = forms.multiTracksSelection.indexOf(track)
  1026. if (selectIndex > -1) {
  1027. forms.multiTracksSelection.splice(selectIndex, 1)
  1028. } else {
  1029. forms.musicSheetSoundList_YY.splice(index, 1)
  1030. }
  1031. if (
  1032. state.multiTracks == 'all' &&
  1033. state.partListNames.length != forms.multiTracksSelection.length
  1034. ) {
  1035. state.multiTracks = null
  1036. }
  1037. }
  1038. })
  1039. }
  1040. const checkMultiTracks = (value: string) => {
  1041. if (!value) {
  1042. return
  1043. }
  1044. let tempMultiTracksSelection = [] as any
  1045. if (value === 'all') {
  1046. state.partListNames.forEach((next: any) => {
  1047. tempMultiTracksSelection.push(next.value)
  1048. })
  1049. } else if (value === 'invert') {
  1050. state.partListNames.forEach((next: any) => {
  1051. if (!forms.multiTracksSelection.includes(next.value)) {
  1052. tempMultiTracksSelection.push(next.value)
  1053. }
  1054. })
  1055. }
  1056. forms.multiTracksSelection = tempMultiTracksSelection
  1057. }
  1058. const setOwnerName = () => {
  1059. if (forms.sourceType == 'PLATFORM') {
  1060. state.ownerName = ''
  1061. return
  1062. }
  1063. if (!forms.sourceType || !forms.musicSheetExtend?.userId) {
  1064. return
  1065. }
  1066. const appId = forms.musicSheetExtend.applicationId
  1067. const app = state.appData.filter((next: any) => {
  1068. return next.id == appId
  1069. }) as any
  1070. if (app.length > 0) {
  1071. state.ownerName = app[0].appName
  1072. }
  1073. if (forms.sourceType == 'ORG') {
  1074. state.ownerName = state.ownerName ? state.ownerName + '-' + forms.musicSheetExtend.organizationRole : forms.musicSheetExtend.organizationRole
  1075. } else if (forms.sourceType == 'PERSON') {
  1076. state.ownerName = state.ownerName ? state.ownerName +
  1077. '-' +
  1078. getMapValueByKey(forms.musicSheetExtend.clientType, new Map(Object.entries(clientType))) : getMapValueByKey(forms.musicSheetExtend.clientType, new Map(Object.entries(clientType)))
  1079. if (forms.musicSheetExtend.userName) {
  1080. state.ownerName = state.ownerName ? state.ownerName + '-' + forms.musicSheetExtend.userName : forms.musicSheetExtend.userName
  1081. }
  1082. if (forms.musicSheetExtend.phone) {
  1083. state.ownerName += '(' + forms.musicSheetExtend.phone + ')'
  1084. }
  1085. }
  1086. }
  1087. // 声轨数据兼容
  1088. const formatTrack = (track: string) => {
  1089. if (!track) {
  1090. return ''
  1091. }
  1092. const trim = track.trim().toUpperCase()
  1093. // 导入后的脏数据兼容
  1094. if (trim == 'P1' || trim == 'NULL') {
  1095. return ''
  1096. }
  1097. return track.trim()
  1098. }
  1099. const changeSubject = async (subjectIdList: []) => {
  1100. state.instrumentList = []
  1101. if (!subjectIdList || subjectIdList.length == 0) {
  1102. forms.musicalInstrumentIdList = []
  1103. return
  1104. }
  1105. let enableFlag = null
  1106. if (props.type === 'add') {
  1107. enableFlag = true
  1108. }
  1109. let tempMusicalInstrumentIdList = [] as any
  1110. const { data } = await musicalInstrumentPage({
  1111. page: 1,
  1112. rows: 999,
  1113. subjectIds: subjectIdList,
  1114. enableFlag: enableFlag
  1115. })
  1116. data.rows.map((item: any) => {
  1117. tempMusicalInstrumentIdList.push(item.id + '')
  1118. state.instrumentList.push({
  1119. label: item.name,
  1120. value: item.id + '',
  1121. disabled: !item.enableFlag
  1122. })
  1123. })
  1124. forms.musicalInstrumentIdList = forms.musicalInstrumentIdList.filter((item: any) => {
  1125. return tempMusicalInstrumentIdList.includes(item)
  1126. })
  1127. }
  1128. onMounted(async () => {
  1129. state.loading = true
  1130. if (props.type === 'preview') {
  1131. state.previewMode = true
  1132. }
  1133. // 获取乐器信息
  1134. {
  1135. if (state.instrumentList && state.instrumentList.length > 0) {
  1136. return
  1137. }
  1138. try {
  1139. const { data } = await musicalInstrumentPage({ page: 1, rows: 999 })
  1140. const tempList = data.rows || []
  1141. tempList.forEach((item: any) => {
  1142. item.label = item.name
  1143. item.value = item.id + ''
  1144. // item.disabled = !item.enableFlag
  1145. state.instrumentIdNameMap.set(item.id + '', item.name)
  1146. forms.musicSheetSoundList_YZ.push({
  1147. musicSheetId: props.data.id,
  1148. musicalInstrumentId: item.id + '',
  1149. musicalInstrumentName: item.name,
  1150. audioFileUrl: null,
  1151. audioPlayType: 'PLAY'
  1152. })
  1153. })
  1154. state.instrumentData = tempList
  1155. state.instrumentList = deepClone(tempList)
  1156. } catch {}
  1157. }
  1158. state.subjectList = deepClone(props.subjectList)
  1159. state.subjectList.forEach((subject: any) => {
  1160. subject.disabled = !subject.enableFlag
  1161. })
  1162. // 初始化应用
  1163. {
  1164. const appKeys = Object.keys(appKey)
  1165. const { data } = await sysApplicationPage({ page: 1, rows: 999, parentId: 0 })
  1166. const tempList = data.rows || []
  1167. const filter = tempList.filter((next: any) => {
  1168. return appKeys.includes(next.appKey)
  1169. })
  1170. filter.forEach((item: any) => {
  1171. item.label = item.appName
  1172. item.value = item.id
  1173. })
  1174. state.appData = filter
  1175. }
  1176. // 获取分类信息
  1177. {
  1178. try {
  1179. const { data } = await musicSheetCategoriesQueryTree({ enable: true })
  1180. state.musicSheetCategories = filterPointCategory(data, 'musicSheetCategoriesList')
  1181. } catch (e) {}
  1182. }
  1183. if (props.type === 'edit' || props.type === 'preview') {
  1184. const detail = props.data
  1185. try {
  1186. const { data } = await musicSheetDetail({ id: detail.id })
  1187. forms.details = data
  1188. forms.playMode = data.playMode
  1189. forms.xmlFileUrl = data.xmlFileUrl
  1190. forms.midiUrl = data.midiUrl
  1191. forms.name = data.name
  1192. // forms.musicTag = data.musicTag?.split(',')
  1193. forms.composer = data.composer
  1194. forms.playSpeed = data.playSpeed ? Number.parseFloat(data.playSpeed) : 100
  1195. // forms.showFingering = Number(data.showFingering)
  1196. // forms.canEvaluate = Number(data.canEvaluate)
  1197. // forms.notation = Number(data.notation)
  1198. // forms.auditVersion = Number(data.auditVersion)
  1199. // forms.sortNumber = data.sortNumber
  1200. forms.defaultScoreRender = data.defaultScoreRender
  1201. forms.isScoreRender = data.isScoreRender
  1202. forms.musicCover = data.musicCover
  1203. forms.remark = data.remark
  1204. forms.status = data.status
  1205. // forms.musicSheetType = data.musicSheetType || 'SINGLE'
  1206. forms.sourceType = data.sourceType
  1207. forms.appAuditFlag = data.appAuditFlag ? 1 : 0
  1208. forms.midiFileUrl = data.midiFileUrl
  1209. forms.isShowFingering = data.isShowFingering
  1210. forms.isAllSubject = data.isAllSubject
  1211. forms.isUseSingSystemBeat = data.isUseSingSystemBeat
  1212. forms.isPlaySingBeat = data.isPlaySingBeat
  1213. forms.subjectIds = []
  1214. if (data.subjectIds) {
  1215. const subjectIds = data.subjectIds.split(',') || []
  1216. subjectIds.forEach((subjectId: any) => {
  1217. if (!forms.subjectIds.includes(subjectId)) {
  1218. forms.subjectIds.push(subjectId)
  1219. }
  1220. })
  1221. state.subjectList = state.subjectList.filter((subject: any) => {
  1222. return !subject.disabled || subjectIds.includes(subject.value)
  1223. })
  1224. }
  1225. forms.musicCategoryId = data.musicCategoryId
  1226. forms.audioType = data.audioType
  1227. forms.isPlayBeat = data.isPlayBeat
  1228. forms.isUseSystemBeat = data.isUseSystemBeat
  1229. // 获取渐变 和 是否多声部
  1230. try {
  1231. const extConfigJson = data.extConfigJson ? JSON.parse(data.extConfigJson) : {}
  1232. forms.graduals = extConfigJson.gradualTimes || {}
  1233. forms.repeatedBeats = !!extConfigJson.repeatedBeats
  1234. forms.isEvxml = !!extConfigJson.isEvxml
  1235. forms.repeatedBeatsToSing = !!extConfigJson.repeatedBeatsToSing
  1236. } catch (error) {}
  1237. forms.evaluationStandard = data.evaluationStandard
  1238. forms.musicSheetExtend = data.musicSheetExtend
  1239. state.musicSheetSoundList = data.musicSheetSoundList ? data.musicSheetSoundList : []
  1240. let musicSheetAccompanimentList = data.musicSheetAccompanimentList
  1241. ? data.musicSheetAccompanimentList
  1242. : []
  1243. musicSheetAccompanimentList.forEach((next: any) => {
  1244. let audioPlayType = next.audioPlayType
  1245. if (audioPlayType && audioPlayType == 'SING') {
  1246. state.bSongFile = next.audioFileUrl
  1247. forms.scoreAudioFileUrl = next.scoreAudioFileUrl
  1248. } else {
  1249. state.musicSheetAccompanimentUrl = next.audioFileUrl
  1250. }
  1251. })
  1252. // 初始化演奏
  1253. for (let i = 0; i < state.musicSheetSoundList.length; i++) {
  1254. if (
  1255. state.musicSheetSoundList[i].audioPlayType == 'SING' &&
  1256. state.musicSheetSoundList[i].track != null
  1257. ) {
  1258. // 范唱 唱名
  1259. state.initFSongMap.set(state.musicSheetSoundList[i].track, {
  1260. ...state.musicSheetSoundList[i]
  1261. // musicalInstrumentName: state.instrumentIdNameMap.get(state.musicSheetSoundList[i].musicalInstrumentId),
  1262. })
  1263. } else {
  1264. if (forms.isAllSubject) {
  1265. forms.musicSheetSoundList_all_subject = state.musicSheetSoundList[i].audioFileUrl
  1266. } else {
  1267. // 乐器演奏原音
  1268. for (let j = 0; j < forms.musicSheetSoundList_YZ.length; j++) {
  1269. let musicalInstrumentId = state.musicSheetSoundList[i].musicalInstrumentId
  1270. if (
  1271. musicalInstrumentId &&
  1272. musicalInstrumentId == forms.musicSheetSoundList_YZ[j].musicalInstrumentId
  1273. ) {
  1274. forms.musicSheetSoundList_YZ[j].audioFileUrl =
  1275. state.musicSheetSoundList[i].audioFileUrl
  1276. }
  1277. }
  1278. }
  1279. }
  1280. }
  1281. forms.musicalInstrumentIdList = data.musicalInstrumentIds
  1282. ? data.musicalInstrumentIds.split(',')
  1283. : []
  1284. // 乐器下拉格式化,停用的过滤
  1285. state.instrumentList = state.instrumentList.filter((next: any) => {
  1286. return next.enableFlag || forms.musicalInstrumentIdList.includes(next.id + '')
  1287. })
  1288. setOwnerName()
  1289. axios.get(data.xmlFileUrl).then((res: any) => {
  1290. if (res?.data) {
  1291. state.musicUpdateLoading = true;
  1292. gradualData.list = getGradualLengthByXml(res?.data as any).filter(
  1293. (item: any) => item.length === 2
  1294. )
  1295. state.partListNames = getPartListNames(res?.data as any) as any
  1296. // 初始化音轨和原音
  1297. let multiTracksSelection = [] as any
  1298. if (data.multiTracksSelection) {
  1299. data.multiTracksSelection = data.multiTracksSelection.toLocaleUpperCase()
  1300. }
  1301. if (
  1302. !data.multiTracksSelection ||
  1303. data.multiTracksSelection.trim() == '' ||
  1304. data.multiTracksSelection.trim() == 'NULL'
  1305. ) {
  1306. multiTracksSelection.push('')
  1307. } else {
  1308. data.multiTracksSelection.split(',').forEach((next: any) => {
  1309. multiTracksSelection.push(next.trim())
  1310. })
  1311. }
  1312. let names = state.partListNames.map((next: any) => next.label)
  1313. multiTracksSelection = names.filter((next: any) =>
  1314. multiTracksSelection.includes(next.toLocaleUpperCase())
  1315. )
  1316. forms.multiTracksSelection = multiTracksSelection
  1317. // 根据声轨数量判断独奏合奏
  1318. forms.musicSheetType = forms.multiTracksSelection.length > 1 ? 'CONCERT' : 'SINGLE'
  1319. const existSoundList = data.musicSheetSoundList ? data.musicSheetSoundList : []
  1320. // 如果只有一个原音文件,并且原音没有对应声轨,取xml解析中的第一个声轨绑定当当前原音
  1321. // if (existSoundList.length === 1 && !formatTrack(existSoundList[0].track)) {
  1322. // let track = state.partListNames.length > 0 ? state.partListNames[0].value : null;
  1323. // forms.musicSheetSoundList_YY.push({
  1324. // audioFileUrl: existSoundList[0].audioFileUrl, // 原音
  1325. // musicalInstrumentId: existSoundList[0].musicalInstrumentId,
  1326. // track: track, // 轨道
  1327. // audioPlayType: 'PLAY'
  1328. // })
  1329. // if (track && !forms.multiTracksSelection.includes(track)) {
  1330. // forms.multiTracksSelection.push(track)
  1331. // }
  1332. // } else {
  1333. const tracks = [] as any
  1334. state.partListNames.forEach((item: any) => {
  1335. let audioFileUrl = null
  1336. let musicalInstrumentId = null
  1337. if (forms.musicSheetType == 'CONCERT') {
  1338. existSoundList.forEach((next: any) => {
  1339. if (next.audioPlayType == 'PLAY') {
  1340. let track = ''
  1341. if (next.track) {
  1342. track = next.track.trim()
  1343. }
  1344. if (track == item.value) {
  1345. audioFileUrl = next.audioFileUrl
  1346. musicalInstrumentId = next.musicalInstrumentId
  1347. }
  1348. }
  1349. })
  1350. }
  1351. forms.musicSheetSoundList_YY.push({
  1352. audioFileUrl: audioFileUrl, // 原音
  1353. musicalInstrumentId: musicalInstrumentId, // 乐器
  1354. track: item.value, // 轨道
  1355. audioPlayType: 'PLAY'
  1356. })
  1357. tracks.push(item.value)
  1358. })
  1359. if (tracks.length == forms.multiTracksSelection.length) {
  1360. state.multiTracks = 'all'
  1361. }
  1362. // 处理没有声轨,但有原音
  1363. if (forms.musicSheetType == 'CONCERT') {
  1364. state.musicSheetSoundList.forEach((next: any) => {
  1365. if (next.audioPlayType == 'PLAY') {
  1366. if (
  1367. next.track &&
  1368. !tracks.includes(next.track.trim()) &&
  1369. next.audioPlayType == 'PLAY'
  1370. ) {
  1371. forms.musicSheetSoundList_YY.push({
  1372. audioFileUrl: next.audioFileUrl, // 原音
  1373. musicalInstrumentId: next.musicalInstrumentId,
  1374. track: next.track ? next.track.trim() : '', // 轨道
  1375. audioPlayType: 'PLAY'
  1376. })
  1377. }
  1378. }
  1379. })
  1380. // }
  1381. }
  1382. state.musicUpdateLoading = false
  1383. }
  1384. })
  1385. } catch (error) {}
  1386. } else {
  1387. // 新增只能使用启用状态的数据
  1388. state.subjectList = state.subjectList.filter((next: any) => {
  1389. return next.enableFlag == true
  1390. })
  1391. state.instrumentList = state.instrumentList.filter((next: any) => {
  1392. return next.enableFlag == true
  1393. })
  1394. }
  1395. state.loading = false
  1396. })
  1397. return () => (
  1398. <div style="background: #fff; padding-top: 12px">
  1399. <NSpin show={state.loading}>
  1400. <NForm
  1401. class={styles.formContainer}
  1402. model={forms}
  1403. ref={formsRef}
  1404. label-placement="left"
  1405. label-width="150"
  1406. disabled={state.previewMode}
  1407. >
  1408. <NAlert showIcon={false} style={{ marginBottom: '12px' }}>
  1409. 基本信息
  1410. </NAlert>
  1411. <NGrid cols={2}>
  1412. <NFormItemGi
  1413. label="曲目名称"
  1414. path="name"
  1415. rule={[
  1416. {
  1417. required: true,
  1418. message: '请输入曲目名称',
  1419. trigger: ['input', 'blur']
  1420. }
  1421. ]}
  1422. >
  1423. <NInput
  1424. v-model:value={forms.name}
  1425. placeholder="请输入曲目名称"
  1426. maxlength={50}
  1427. showCount
  1428. />
  1429. </NFormItemGi>
  1430. <NFormItemGi
  1431. label="音乐人"
  1432. path="composer"
  1433. rule={[
  1434. {
  1435. required: false,
  1436. message: '请输入音乐人',
  1437. trigger: ['input', 'blur']
  1438. }
  1439. ]}
  1440. >
  1441. <NInput
  1442. v-model:value={forms.composer}
  1443. placeholder="请输入音乐人名称"
  1444. showCount
  1445. maxlength={14}
  1446. />
  1447. </NFormItemGi>
  1448. </NGrid>
  1449. <NGrid cols={2}>
  1450. <NFormItemGi
  1451. label="曲目封面"
  1452. path="musicCover"
  1453. rule={[
  1454. {
  1455. required: false,
  1456. message: '请上传曲目封面',
  1457. trigger: ['input', 'blur']
  1458. }
  1459. ]}
  1460. >
  1461. <UploadFile
  1462. desc={'封面图'}
  1463. disabled={state.previewMode}
  1464. accept=".jpg,.jpeg,.png"
  1465. tips="请上传大小1M以内的JPG、PNG图片"
  1466. size={1}
  1467. v-model:fileList={forms.musicCover}
  1468. cropper
  1469. bucketName="cbs"
  1470. options={{
  1471. autoCrop: true, //是否默认生成截图框
  1472. enlarge: 2, // 图片放大倍数
  1473. autoCropWidth: 200, //默框高度
  1474. fixedBox: true, //是否固定截图框大认生成截图框宽度
  1475. autoCropHeight: 200, //默认生成截图小 不允许改变
  1476. previewsCircle: false, //预览图是否是原圆形
  1477. title: '曲目封面'
  1478. }}
  1479. />
  1480. </NFormItemGi>
  1481. <NFormItemGi
  1482. label="曲目分类"
  1483. path="musicCategoryId"
  1484. rule={[
  1485. {
  1486. required: true,
  1487. message: '请选择曲目分类',
  1488. trigger: ['change']
  1489. }
  1490. ]}
  1491. >
  1492. <NCascader
  1493. valueField="id"
  1494. labelField="name"
  1495. children-field="musicSheetCategoriesList"
  1496. placeholder="请选择分类"
  1497. v-model:value={forms.musicCategoryId}
  1498. options={state.musicSheetCategories}
  1499. clearable
  1500. />
  1501. </NFormItemGi>
  1502. </NGrid>
  1503. <NGrid cols={2}>
  1504. <NFormItemGi
  1505. label="作者属性"
  1506. path="sourceType"
  1507. rule={[
  1508. {
  1509. required: true,
  1510. message: '请选择作者属性',
  1511. trigger: 'change'
  1512. }
  1513. ]}
  1514. >
  1515. <NSelect
  1516. v-model:value={forms.sourceType}
  1517. options={getSelectDataFromObj(musicSheetSourceType)}
  1518. placeholder="请选择作者属性"
  1519. onUpdateValue={() => {
  1520. // 发送变化,清理选择的所属人信息
  1521. forms.musicSheetExtend = {}
  1522. state.ownerName = null
  1523. // forms.musicSheetExtend.userId = null
  1524. // forms.musicSheetExtend.userName = null
  1525. // forms.musicSheetExtend.applicationId = null
  1526. // forms.musicSheetExtend.organizationRoleId = null
  1527. }}
  1528. />
  1529. </NFormItemGi>
  1530. {forms.sourceType === 'PERSON' && (
  1531. <NFormItemGi
  1532. label="所属人"
  1533. path="musicSheetExtend.userId"
  1534. rule={[
  1535. {
  1536. required: true,
  1537. message: '请选择曲目所属人',
  1538. trigger: ['input', 'change']
  1539. }
  1540. ]}
  1541. >
  1542. <NButton
  1543. disabled={state.previewMode || !forms.sourceType}
  1544. type="primary"
  1545. size="small"
  1546. text
  1547. //v-auth="orchestraSubsidyStandard/update1597887579789053953"
  1548. onClick={() => {
  1549. state.showMusicSheetOwnerDialog = true
  1550. }}
  1551. >
  1552. {state.ownerName ? state.ownerName : '请选择所属人'}
  1553. </NButton>
  1554. </NFormItemGi>
  1555. )}
  1556. {forms.sourceType === 'ORG' && (
  1557. <NFormItemGi
  1558. label="所属人"
  1559. path="musicSheetExtend.organizationRoleId"
  1560. rule={[
  1561. {
  1562. required: true,
  1563. message: '请选择曲目所属机构',
  1564. trigger: ['input', 'change']
  1565. }
  1566. ]}
  1567. >
  1568. <NButton
  1569. disabled={state.previewMode || !forms.sourceType}
  1570. type="primary"
  1571. size="small"
  1572. text
  1573. //v-auth="orchestraSubsidyStandard/update1597887579789053953"
  1574. onClick={() => {
  1575. state.showMusicSheetOwnerDialog = true
  1576. }}
  1577. >
  1578. {state.ownerName ? state.ownerName : '请选择所属机构'}
  1579. </NButton>
  1580. </NFormItemGi>
  1581. )}
  1582. </NGrid>
  1583. <NGrid cols={2}>
  1584. <NFormItemGi
  1585. label="审核版本"
  1586. path="appAuditFlag"
  1587. rule={[
  1588. {
  1589. required: true,
  1590. message: '请选择审核版本',
  1591. trigger: 'change',
  1592. type: 'number'
  1593. }
  1594. ]}
  1595. >
  1596. <NSelect
  1597. options={
  1598. [
  1599. {
  1600. label: '是',
  1601. value: 1
  1602. },
  1603. {
  1604. label: '否',
  1605. value: 0
  1606. }
  1607. ] as any
  1608. }
  1609. v-model:value={forms.appAuditFlag}
  1610. />
  1611. </NFormItemGi>
  1612. </NGrid>
  1613. <NAlert showIcon={false} style={{ marginBottom: '12px' }}>
  1614. 曲目设置
  1615. </NAlert>
  1616. <NGrid cols={2}>
  1617. <NFormItemGi
  1618. label="播放模式"
  1619. path="playMode"
  1620. rule={[
  1621. {
  1622. required: true,
  1623. message: '请选择播放模式'
  1624. }
  1625. ]}
  1626. >
  1627. <NRadioGroup
  1628. v-model:value={forms.playMode}
  1629. onUpdateValue={(value: string | number | boolean) => {
  1630. if (value === 'MP3') {
  1631. forms.playMode = 'MP3'
  1632. } else {
  1633. forms.playMode = 'MIDI'
  1634. }
  1635. }}
  1636. >
  1637. <NRadio value="MP3">MP3</NRadio>
  1638. {forms.playMode == 'MIDI' && props.type === 'preview' && (
  1639. <NRadio value="MIDI">MID</NRadio>
  1640. )}
  1641. </NRadioGroup>
  1642. </NFormItemGi>
  1643. {forms.playMode === 'MP3' && (
  1644. <NFormItemGi
  1645. label="伴奏类型"
  1646. path="audioType"
  1647. rule={[
  1648. {
  1649. required: true,
  1650. message: '请选择伴奏类型'
  1651. }
  1652. ]}
  1653. >
  1654. <NRadioGroup v-model:value={forms.audioType}>
  1655. <NRadio value={'HOMEMODE'}>自制伴奏</NRadio>
  1656. <NRadio value={'COMMON'}>普通伴奏</NRadio>
  1657. </NRadioGroup>
  1658. </NFormItemGi>
  1659. )}
  1660. </NGrid>
  1661. <NGrid cols={2}>
  1662. <NFormItemGi
  1663. label="上传XML"
  1664. path="xmlFileUrl"
  1665. rule={[
  1666. {
  1667. required: true,
  1668. message: '请选择上传XML',
  1669. trigger: ['change', 'input']
  1670. }
  1671. ]}
  1672. >
  1673. <UploadFile
  1674. desc={'XML文件'}
  1675. disabled={state.previewMode}
  1676. size={30}
  1677. key={'xmlFileUrl'}
  1678. v-model:fileList={forms.xmlFileUrl}
  1679. tips="仅支持上传.xml/.mxml格式文件"
  1680. listType="image"
  1681. accept=".xml,.mxml,.evxml"
  1682. bucketName="cloud-coach"
  1683. text="点击上传XML文件"
  1684. onReadFileInputEventAsArrayBuffer={readFileInputEventAsArrayBuffer}
  1685. onRemove={() => {
  1686. // forms.multiTracksSelection = []
  1687. // state.partListNames = []
  1688. // forms.musicSheetSoundList_YY = []
  1689. // forms.musicalInstrumentIdList = []
  1690. // forms.subjectIds = []
  1691. }}
  1692. />
  1693. </NFormItemGi>
  1694. <NFormItemGi
  1695. label="评分标准"
  1696. path="evaluationStandard"
  1697. rule={[
  1698. {
  1699. required: true
  1700. }
  1701. ]}
  1702. >
  1703. <NRadioGroup v-model:value={forms.evaluationStandard}>
  1704. <NRadio value={'FREQUENCY'}>标准评测</NRadio>
  1705. <NRadio value={'AMPLITUDE'}>打击乐(振幅)</NRadio>
  1706. <NRadio value={'DECIBELS'}>节奏(分贝)</NRadio>
  1707. </NRadioGroup>
  1708. </NFormItemGi>
  1709. </NGrid>
  1710. <NGrid cols={2}>
  1711. {/*<NFormItemGi*/}
  1712. {/* label="谱面渲染"*/}
  1713. {/* path="musicSheetType"*/}
  1714. {/* rule={[*/}
  1715. {/* {*/}
  1716. {/* required: true,*/}
  1717. {/* message: '请选择谱面渲染',*/}
  1718. {/* trigger: 'change'*/}
  1719. {/* }*/}
  1720. {/* ]}*/}
  1721. {/*>*/}
  1722. {/* <NRadioGroup v-model:value={forms.musicSheetType}>*/}
  1723. {/* <NRadio value={'SINGLE'}>多声轨</NRadio>*/}
  1724. {/* <NRadio value={'CONCERT'}>单声轨</NRadio>*/}
  1725. {/* </NRadioGroup>*/}
  1726. {/*</NFormItemGi>*/}
  1727. <NFormItemGi
  1728. label="是否全声部"
  1729. path="isAllSubject"
  1730. rule={[
  1731. {
  1732. required: true,
  1733. message: '是否全声部'
  1734. }
  1735. ]}
  1736. >
  1737. <NRadioGroup v-model:value={forms.isAllSubject}>
  1738. <NRadio value={false}>否</NRadio>
  1739. <NRadio value={true}>是</NRadio>
  1740. </NRadioGroup>
  1741. </NFormItemGi>
  1742. <NFormItemGi
  1743. label="速度"
  1744. path="playSpeed"
  1745. rule={[
  1746. {
  1747. required: false,
  1748. message: '请输入速度'
  1749. }
  1750. ]}
  1751. >
  1752. <NInputNumber
  1753. placeholder="请输入速度"
  1754. v-model:value={forms.playSpeed}
  1755. min={0}
  1756. style="width:100%"
  1757. />
  1758. </NFormItemGi>
  1759. </NGrid>
  1760. {!forms.isAllSubject && (
  1761. <NGrid cols={2}>
  1762. <NFormItemGi
  1763. label="可用乐器"
  1764. path="musicalInstrumentIdList"
  1765. rule={[
  1766. {
  1767. required: true,
  1768. message: '请选择可用乐器',
  1769. trigger: 'change',
  1770. type: 'array'
  1771. }
  1772. ]}
  1773. >
  1774. <NSelect
  1775. placeholder="请选择可用乐器"
  1776. options={state.instrumentList}
  1777. v-model:value={forms.musicalInstrumentIdList}
  1778. // disabled = {state.instrumentDisabled}
  1779. clearable
  1780. multiple
  1781. filterable
  1782. maxTagCount={10}
  1783. onUpdateValue={async (value: any) => {
  1784. await showBackSubject(value)
  1785. }}
  1786. />
  1787. </NFormItemGi>
  1788. <NFormItemGi
  1789. label="可用声部"
  1790. path="subjectIds"
  1791. rule={[
  1792. {
  1793. required: true,
  1794. message: '请选择可用声部',
  1795. trigger: 'change',
  1796. type: 'array'
  1797. }
  1798. ]}
  1799. >
  1800. <NSelect
  1801. v-model:value={forms.subjectIds}
  1802. options={state.subjectList}
  1803. // disabled={true}
  1804. multiple
  1805. filterable
  1806. clearable
  1807. placeholder="请选择可用声部"
  1808. maxTagCount={10}
  1809. onUpdateValue={async (val: any) => {
  1810. // await changeSubject(val)
  1811. }}
  1812. />
  1813. </NFormItemGi>
  1814. </NGrid>
  1815. )}
  1816. <NGrid cols={1}>
  1817. <NFormItemGi
  1818. label={'切换声轨'}
  1819. path="multiTracksSelection"
  1820. rule={[
  1821. {
  1822. required: true,
  1823. message: `请选择切换声轨`,
  1824. trigger: 'change',
  1825. type: 'array'
  1826. }
  1827. ]}
  1828. >
  1829. <NGrid style="padding-top: 4px;">
  1830. <NGi span={24}>
  1831. <NRadioGroup
  1832. v-model:value={state.multiTracks}
  1833. onUpdateValue={(value) => {
  1834. checkMultiTracks(value)
  1835. }}
  1836. >
  1837. <NRadio value={'all'}>全选</NRadio>
  1838. <NRadio value={'allUncheck'}>重置</NRadio>
  1839. <NRadio value={'invert'}>反选</NRadio>
  1840. </NRadioGroup>
  1841. </NGi>
  1842. {state.partListNames && state.partListNames.length > 0 && (
  1843. <NGi span={24} style={'margin-top:5px'}>
  1844. <NFormItemGi
  1845. label=""
  1846. path="multiTracksSelection"
  1847. rule={[
  1848. {
  1849. required: false
  1850. }
  1851. ]}
  1852. >
  1853. <NCheckboxGroup
  1854. v-model:value={forms.multiTracksSelection}
  1855. onUpdateValue={(val: any) => {
  1856. if (state.partListNames.length != val.length) {
  1857. state.multiTracks = null
  1858. } else {
  1859. state.multiTracks = 'all'
  1860. }
  1861. }}
  1862. >
  1863. <NGrid yGap={2} cols={4}>
  1864. {state.partListNames.map((item: any) => (
  1865. <NGi>
  1866. <NCheckbox value={item.value} label={item.label} />
  1867. </NGi>
  1868. ))}
  1869. </NGrid>
  1870. </NCheckboxGroup>
  1871. </NFormItemGi>
  1872. </NGi>
  1873. )}
  1874. </NGrid>
  1875. </NFormItemGi>
  1876. </NGrid>
  1877. {forms.multiTracksSelection.length > 1 && (
  1878. <NGrid cols={2}>
  1879. <NFormItemGi
  1880. label="总谱渲染"
  1881. path="isScoreRender"
  1882. rule={[
  1883. {
  1884. required: true,
  1885. message: '请选择总谱渲染'
  1886. }
  1887. ]}
  1888. >
  1889. <NRadioGroup v-model:value={forms.isScoreRender}>
  1890. <NRadio value={true}>支持</NRadio>
  1891. <NRadio value={false}>不支持</NRadio>
  1892. </NRadioGroup>
  1893. </NFormItemGi>
  1894. {/* 支持总谱渲染的时候才显示 */}
  1895. {forms.isScoreRender && (
  1896. <NFormItemGi
  1897. label="默认显示"
  1898. path="defaultScoreRender"
  1899. rule={[
  1900. {
  1901. required: false
  1902. }
  1903. ]}
  1904. >
  1905. <NRadioGroup v-model:value={forms.defaultScoreRender}>
  1906. <NRadio value={true}>总谱</NRadio>
  1907. <NRadio value={false}>分轨</NRadio>
  1908. </NRadioGroup>
  1909. </NFormItemGi>
  1910. )}
  1911. </NGrid>
  1912. )}
  1913. <NAlert showIcon={false} style={{ marginBottom: '12px' }}>
  1914. 演唱文件
  1915. </NAlert>
  1916. <NGrid cols={2}>
  1917. <NFormItemGi
  1918. label="是否播放节拍器"
  1919. path="isPlaySingBeat"
  1920. rule={[
  1921. {
  1922. required: true,
  1923. message: '请选择是否播放节拍器'
  1924. }
  1925. ]}
  1926. >
  1927. <NRadioGroup v-model:value={forms.isPlaySingBeat}>
  1928. <NRadio value={true}>是</NRadio>
  1929. <NRadio value={false}>否</NRadio>
  1930. </NRadioGroup>
  1931. </NFormItemGi>
  1932. {forms.isPlaySingBeat && (
  1933. <NFormItemGi
  1934. label="播放方式"
  1935. path="isUseSingSystemBeat"
  1936. rule={[
  1937. {
  1938. required: true,
  1939. message: '请选择播放方式'
  1940. }
  1941. ]}
  1942. >
  1943. <NRadioGroup v-model:value={forms.isUseSingSystemBeat}>
  1944. <NRadio value={true}>系统节拍器</NRadio>
  1945. <NRadio value={false}>MP3节拍器</NRadio>
  1946. </NRadioGroup>
  1947. </NFormItemGi>
  1948. )}
  1949. </NGrid>
  1950. <NGrid cols={2}>
  1951. <NFormItemGi
  1952. label="重复节拍时长"
  1953. path="repeatedBeatsToSing"
  1954. rule={[
  1955. {
  1956. required: false,
  1957. message: '请选择是否重复节拍时长'
  1958. }
  1959. ]}
  1960. >
  1961. <NRadioGroup v-model:value={forms.repeatedBeatsToSing}>
  1962. <NRadio value={true}>是</NRadio>
  1963. <NRadio value={false}>否</NRadio>
  1964. </NRadioGroup>
  1965. </NFormItemGi>
  1966. </NGrid>
  1967. <NGrid cols={2}>
  1968. <NFormItemGi
  1969. label="上传伴唱"
  1970. path="bSongFile"
  1971. rule={[
  1972. {
  1973. required: false
  1974. }
  1975. ]}
  1976. >
  1977. <UploadFile
  1978. desc={'上传伴唱'}
  1979. disabled={state.previewMode}
  1980. size={30}
  1981. v-model:fileList={state.bSongFile}
  1982. tips="仅支持上传.mp3格式文件"
  1983. listType="image"
  1984. accept=".mp3"
  1985. bucketName="cloud-coach"
  1986. text="点击上传伴唱文件"
  1987. />
  1988. </NFormItemGi>
  1989. </NGrid>
  1990. {forms.fSongList.length > 0 &&
  1991. forms.fSongList.map((item: any) => {
  1992. return (
  1993. <NGrid class={styles.audioSection}>
  1994. <NFormItemGi
  1995. span={12}
  1996. label={item.track + '范唱'}
  1997. path={item.audioFileUrl}
  1998. rule={[
  1999. {
  2000. required: false
  2001. }
  2002. ]}
  2003. >
  2004. <UploadFile
  2005. desc={'上传范唱'}
  2006. disabled={state.previewMode}
  2007. size={100}
  2008. v-model:fileList={item.audioFileUrl}
  2009. tips="仅支持上传.mp3格式文件"
  2010. listType="image"
  2011. accept=".mp3"
  2012. bucketName="cloud-coach"
  2013. text={'点击上传范唱文件'}
  2014. />
  2015. </NFormItemGi>
  2016. </NGrid>
  2017. )
  2018. })}
  2019. {forms.multiTracksSelection.length > 1 && forms.isScoreRender && (
  2020. <NGrid cols={2} class={styles.audioSection}>
  2021. <NFormItemGi
  2022. label="总谱范唱"
  2023. path="scoreRenderFile"
  2024. rule={[
  2025. {
  2026. required: false
  2027. }
  2028. ]}
  2029. >
  2030. <UploadFile
  2031. desc={'上传总谱范唱'}
  2032. disabled={state.previewMode}
  2033. size={30}
  2034. v-model:fileList={forms.scoreAudioFileUrl}
  2035. tips="仅支持上传.mp3格式文件"
  2036. listType="image"
  2037. accept=".mp3"
  2038. bucketName="cloud-coach"
  2039. text="点击上传总谱范唱"
  2040. />
  2041. </NFormItemGi>
  2042. </NGrid>
  2043. )}
  2044. {forms.fSongList.length > 0 &&
  2045. forms.fSongList.map((item: any) => {
  2046. return (
  2047. <NGrid cols={2}>
  2048. <NFormItemGi
  2049. label={item.track + '唱名(男)'}
  2050. path={item.solmizationFileUrl}
  2051. rule={[
  2052. {
  2053. required: false
  2054. }
  2055. ]}
  2056. >
  2057. <UploadFile
  2058. desc={'上传范唱'}
  2059. disabled={state.previewMode}
  2060. size={100}
  2061. v-model:fileList={item.solmizationFileUrl}
  2062. tips="仅支持上传.mp3格式文件"
  2063. listType="image"
  2064. accept=".mp3"
  2065. bucketName="cloud-coach"
  2066. text={'点击上传唱名文件'}
  2067. />
  2068. </NFormItemGi>
  2069. <NFormItemGi
  2070. label={item.track + '唱名(女)'}
  2071. path={item.femaleSolmizationFileUrl}
  2072. rule={[
  2073. {
  2074. required: false
  2075. }
  2076. ]}
  2077. >
  2078. <UploadFile
  2079. desc={'上传范唱'}
  2080. disabled={state.previewMode}
  2081. size={100}
  2082. v-model:fileList={item.femaleSolmizationFileUrl}
  2083. tips="仅支持上传.mp3格式文件"
  2084. listType="image"
  2085. accept=".mp3"
  2086. bucketName="cloud-coach"
  2087. text={'点击上传唱名文件'}
  2088. />
  2089. </NFormItemGi>
  2090. </NGrid>
  2091. )
  2092. })}
  2093. <NAlert showIcon={false} style={{ marginBottom: '12px' }}>
  2094. 演奏文件
  2095. </NAlert>
  2096. <NGrid cols={2}>
  2097. <NFormItemGi
  2098. label="是否播放节拍器"
  2099. path="isPlayBeat"
  2100. rule={[
  2101. {
  2102. required: true,
  2103. message: '请选择是否播放节拍器'
  2104. }
  2105. ]}
  2106. >
  2107. <NRadioGroup v-model:value={forms.isPlayBeat}>
  2108. <NRadio value={true}>是</NRadio>
  2109. <NRadio value={false}>否</NRadio>
  2110. </NRadioGroup>
  2111. </NFormItemGi>
  2112. {forms.isPlayBeat && (
  2113. <NFormItemGi
  2114. label="播放方式"
  2115. path="isUseSystemBeat"
  2116. rule={[
  2117. {
  2118. required: true,
  2119. message: '请选择播放方式'
  2120. }
  2121. ]}
  2122. >
  2123. <NRadioGroup v-model:value={forms.isUseSystemBeat}>
  2124. <NRadio value={true}>系统节拍器</NRadio>
  2125. <NRadio value={false}>MP3节拍器</NRadio>
  2126. </NRadioGroup>
  2127. </NFormItemGi>
  2128. )}
  2129. </NGrid>
  2130. <NGrid cols={2}>
  2131. <NFormItemGi
  2132. label="重复节拍时长"
  2133. path="repeatedBeats"
  2134. rule={[
  2135. {
  2136. required: false,
  2137. message: '请选择是否重复节拍时长'
  2138. }
  2139. ]}
  2140. >
  2141. <NRadioGroup v-model:value={forms.repeatedBeats}>
  2142. <NRadio value={true}>是</NRadio>
  2143. <NRadio value={false}>否</NRadio>
  2144. </NRadioGroup>
  2145. </NFormItemGi>
  2146. <NFormItemGi
  2147. label="是否显示指法"
  2148. path="isShowFingering"
  2149. rule={[
  2150. {
  2151. required: true,
  2152. message: '请选择是否显示指法'
  2153. }
  2154. ]}
  2155. >
  2156. <NRadioGroup v-model:value={forms.isShowFingering}>
  2157. <NRadio value={true}>是</NRadio>
  2158. <NRadio value={false}>否</NRadio>
  2159. </NRadioGroup>
  2160. </NFormItemGi>
  2161. </NGrid>
  2162. <NGrid cols={2}>
  2163. {forms.playMode === 'MP3' && (
  2164. <NFormItemGi
  2165. label="上传伴奏"
  2166. path="musicSheetAccompanimentList"
  2167. rule={[
  2168. {
  2169. required: false,
  2170. message: '请选择上传.mp3'
  2171. }
  2172. ]}
  2173. >
  2174. <UploadFile
  2175. disabled={state.previewMode}
  2176. size={30}
  2177. v-model:fileList={state.musicSheetAccompanimentUrl}
  2178. tips="仅支持上传.mp3格式文件"
  2179. listType="image"
  2180. accept=".mp3"
  2181. bucketName="cloud-coach"
  2182. text="点击上传伴奏文件"
  2183. max={1}
  2184. desc={'上传伴奏文件'}
  2185. // onReadFileInputEventAsArrayBuffer={readFileInputEventAsArrayBuffer}
  2186. />
  2187. </NFormItemGi>
  2188. )}
  2189. {forms.isAllSubject && forms.musicSheetType == 'SINGLE' && (
  2190. <NFormItemGi
  2191. label="上传原音"
  2192. path="musicSheetSoundList_all_subject"
  2193. rule={[
  2194. {
  2195. required: false,
  2196. message: '请选择上传原音',
  2197. trigger: ['change', 'input']
  2198. }
  2199. ]}
  2200. >
  2201. <UploadFile
  2202. desc={'上传原音'}
  2203. disabled={state.previewMode}
  2204. size={30}
  2205. max={1}
  2206. v-model:fileList={forms.musicSheetSoundList_all_subject}
  2207. tips="仅支持上传.mp3格式文件"
  2208. listType="image"
  2209. accept=".mp3"
  2210. bucketName="cloud-coach"
  2211. text="点击上传原音"
  2212. onRemove={() => {}}
  2213. />
  2214. </NFormItemGi>
  2215. )}
  2216. </NGrid>
  2217. {/*渐变速*/}
  2218. {!!gradualData.list.length && (
  2219. <>
  2220. <NAlert showIcon={false} type="info">
  2221. 识别到共1处渐变速度,请输入Dorico对应小节时间信息
  2222. </NAlert>
  2223. <NFormItem label="rit." required style={{ marginTop: '10px' }}>
  2224. <NSpace vertical>
  2225. {gradualData.list.map((n: any, ni: number) => (
  2226. <NInputGroup>
  2227. <NFormItem
  2228. path={`graduals.${n[0].measureIndex}`}
  2229. rule={[
  2230. { required: true, message: '请输入合奏曲目时间' },
  2231. {
  2232. pattern: /^((\d{2}):?){2,3}$/,
  2233. message: '请输入正确的曲目时间',
  2234. trigger: 'blur'
  2235. }
  2236. ]}
  2237. >
  2238. <NInputGroup>
  2239. <NInputGroupLabel>{n[0].measureIndex}小节开始</NInputGroupLabel>
  2240. <NInput
  2241. placeholder="00:00:00"
  2242. v-model:value={forms.graduals[n[0].measureIndex]}
  2243. ></NInput>
  2244. </NInputGroup>
  2245. </NFormItem>
  2246. <div style={{ lineHeight: '30px', padding: '0 4px' }}>~</div>
  2247. <NFormItem
  2248. path={`graduals.${n[1].measureIndex}`}
  2249. rule={[
  2250. { required: true, message: '请输入合奏曲目时间' },
  2251. {
  2252. pattern: /^((\d{2}):?){2,3}$/,
  2253. message: '请输入正确的曲目时间',
  2254. trigger: 'blur'
  2255. }
  2256. ]}
  2257. >
  2258. <NInputGroup>
  2259. <NInput
  2260. placeholder="00:00:00"
  2261. v-model:value={forms.graduals[n[1].measureIndex]}
  2262. ></NInput>
  2263. <NInputGroupLabel>{n[1].measureIndex}小节结束</NInputGroupLabel>
  2264. </NInputGroup>
  2265. </NFormItem>
  2266. </NInputGroup>
  2267. ))}
  2268. </NSpace>
  2269. </NFormItem>
  2270. </>
  2271. )}
  2272. {/*独奏*/}
  2273. {forms.musicSheetType == 'SINGLE' &&
  2274. forms.playMode === 'MP3' &&
  2275. !forms.isAllSubject &&
  2276. forms.musicSheetSoundList_YZ.map((item: any, index: any) => {
  2277. return (
  2278. <>
  2279. {forms.musicalInstrumentIdList.includes(item.musicalInstrumentId) && (
  2280. <NGrid class={styles.audioSection}>
  2281. <NFormItemGi
  2282. span={12}
  2283. label={item.musicalInstrumentName}
  2284. path={`musicSheetSoundList_YZ[${index}].audioFileUrl`}
  2285. rule={[
  2286. {
  2287. required: false,
  2288. message: `请上传乐器演奏文件`
  2289. }
  2290. ]}
  2291. >
  2292. <UploadFile
  2293. desc={'乐器演奏文件'}
  2294. disabled={state.previewMode}
  2295. size={100}
  2296. v-model:fileList={item.audioFileUrl}
  2297. tips="仅支持上传.mp3格式文件"
  2298. listType="image"
  2299. accept=".mp3"
  2300. text={'点击上传MP3文件'}
  2301. bucketName="cloud-coach"
  2302. />
  2303. </NFormItemGi>
  2304. </NGrid>
  2305. )}
  2306. </>
  2307. )
  2308. })}
  2309. {/*合奏*/}
  2310. {forms.musicSheetType == 'CONCERT' &&
  2311. forms.playMode === 'MP3' &&
  2312. forms.musicSheetSoundList_YY.length > 0 && (
  2313. <>
  2314. {forms.musicSheetSoundList_YY.map((item: any, index: number) => {
  2315. return (
  2316. <>
  2317. {(!containOther(item.track) ||
  2318. (item.track?.toLocaleUpperCase?.() != 'COMMON' &&
  2319. forms.multiTracksSelection.includes(item.track))) && (
  2320. <NGrid
  2321. class={styles.audioSection}
  2322. // v-show={forms.multiTracksSelection.indexOf(item.track) > -1}
  2323. >
  2324. <NFormItemGi
  2325. span={12}
  2326. label="原音"
  2327. path={`musicSheetSoundList_YY[${index}].audioFileUrl`}
  2328. rule={[
  2329. {
  2330. // required: forms.multiTracksSelection.indexOf(forms.musicSheetSoundList_YY[index].audioFileUrl) > -1,
  2331. required: false,
  2332. message: `请上传${
  2333. item.track ? item.track + '的' : '第' + (index + 1) + '个'
  2334. }原音`
  2335. }
  2336. ]}
  2337. >
  2338. <UploadFile
  2339. desc={'原音文件'}
  2340. disabled={state.previewMode}
  2341. size={100}
  2342. v-model:fileList={item.audioFileUrl}
  2343. tips="仅支持上传.mp3格式文件"
  2344. listType="image"
  2345. accept=".mp3"
  2346. bucketName="cloud-coach"
  2347. />
  2348. </NFormItemGi>
  2349. {state.partListNames.length > 0 && (
  2350. <NFormItemGi
  2351. span={12}
  2352. label="所属轨道"
  2353. path={`musicSheetSoundList_YY[${index}].track`}
  2354. rule={[
  2355. {
  2356. required: false,
  2357. message: '请选择所属轨道'
  2358. }
  2359. ]}
  2360. >
  2361. <NSelect
  2362. placeholder="请选择所属轨道"
  2363. value={item.track}
  2364. options={initPartsListStatus(item.track)}
  2365. onUpdateValue={(value: any) => {
  2366. const track = item.track
  2367. if (track) {
  2368. // 声轨交换
  2369. forms.musicSheetSoundList_YY.forEach((next: any) => {
  2370. if (next.track == value) {
  2371. next.track = track
  2372. }
  2373. })
  2374. const index = forms.multiTracksSelection.indexOf(item.track)
  2375. forms.multiTracksSelection.splice(index, 1)
  2376. } else {
  2377. forms.musicSheetSoundList_YY =
  2378. forms.musicSheetSoundList_YY.filter((next: any) => {
  2379. return next.track != value
  2380. })
  2381. }
  2382. if (
  2383. value != null &&
  2384. !forms.multiTracksSelection.includes(value)
  2385. ) {
  2386. forms.multiTracksSelection.push(value)
  2387. }
  2388. item.track = value
  2389. if (
  2390. state.partListNames.length ==
  2391. forms.multiTracksSelection.length
  2392. ) {
  2393. state.multiTracks = 'all'
  2394. }
  2395. }}
  2396. />
  2397. </NFormItemGi>
  2398. )}
  2399. <NGi class={styles.btnRemove}>
  2400. <NButton
  2401. type="primary"
  2402. text
  2403. // disabled={forms.musicSheetSoundList_YY.length === 1}
  2404. onClick={() => removeSys(index)}
  2405. >
  2406. 删除
  2407. </NButton>
  2408. </NGi>
  2409. </NGrid>
  2410. )}
  2411. </>
  2412. )
  2413. })}
  2414. </>
  2415. )}
  2416. </NForm>
  2417. </NSpin>
  2418. {props.type !== 'preview' && (
  2419. <NSpace justify="end" style="padding-top:12px">
  2420. <NButton type="default" onClick={() => emit('close')}>
  2421. 取消
  2422. </NButton>
  2423. <NButton
  2424. type="primary"
  2425. onClick={() => onSubmit()}
  2426. loading={btnLoading.value}
  2427. disabled={btnLoading.value}
  2428. >
  2429. 确认
  2430. </NButton>
  2431. </NSpace>
  2432. )}
  2433. <NModal
  2434. v-model:show={state.showMusicSheetOwnerDialog}
  2435. preset="dialog"
  2436. showIcon={false}
  2437. maskClosable={false}
  2438. title="所属人"
  2439. style={{ width: '800px' }}
  2440. >
  2441. <MusicSheetOwnerDialog
  2442. musicSheetExtend={forms.musicSheetExtend}
  2443. sourceType={forms.sourceType}
  2444. appData={state.appData}
  2445. onClose={() => {
  2446. state.showMusicSheetOwnerDialog = false
  2447. }}
  2448. onChoseMusicSheetOwnerData={(musicSheetOwnerData) => {
  2449. forms.musicSheetExtend = {
  2450. ...musicSheetOwnerData
  2451. }
  2452. setOwnerName()
  2453. }}
  2454. />
  2455. </NModal>
  2456. <NModal
  2457. class={styles.productModal}
  2458. title="自动生成曲谱图片"
  2459. v-model:show={state.productOpen}
  2460. preset="dialog"
  2461. closeOnEsc={false}
  2462. maskClosable={false}
  2463. onClose={() => {
  2464. state.isAutoSave = false
  2465. }}
  2466. showIcon={false}
  2467. >
  2468. <MusicCreateImg
  2469. xmlFileUrl={forms.xmlFileUrl || ''}
  2470. onClose={() => (state.productOpen = false)}
  2471. onConfirm={async (item: any) => {
  2472. // 保存
  2473. try {
  2474. forms.musicImg = item.musicImg
  2475. forms.musicFirstImg = item.musicFirstImg
  2476. forms.musicJianImg = item.musicJianImg
  2477. await onSubmit()
  2478. } catch (e: any) {
  2479. //
  2480. console.log(e, 'e')
  2481. }
  2482. // setTimeout(() => {
  2483. // state.isAutoSave = false
  2484. // }, 50)
  2485. }}
  2486. />
  2487. </NModal>
  2488. {beatTimeData.beatTimeOpen && (
  2489. <MusiceBeatTime
  2490. id={beatTimeData.musicId}
  2491. onClose={handlerMusiceBeatTimeClose}
  2492. ></MusiceBeatTime>
  2493. )}
  2494. </div>
  2495. )
  2496. }
  2497. })