addMusic.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. import { defineComponent, h, onMounted, reactive, ref } from 'vue'
  2. import SaveForm from '@components/save-form'
  3. import {
  4. DataTableColumns,
  5. DataTableRowKey,
  6. NButton,
  7. NCascader,
  8. NDataTable,
  9. NFormItem,
  10. NIcon,
  11. NImage,
  12. NInput,
  13. NInputNumber,
  14. NSelect,
  15. NSpace,
  16. NStep,
  17. NSteps,
  18. useDialog,
  19. useMessage
  20. } from 'naive-ui'
  21. import Pagination from '@components/pagination'
  22. import { getMapValueByKey, getSelectDataFromObj } from '@/utils/objectUtil'
  23. import {appKey, musicSheetPaymentType, musicSheetSourceType, musicSheetType} from '@/utils/constant'
  24. import {musicSheetApplicationExtendCategoryList, musicSheetApplicationExtendSaveBatch, musicSheetApplicationOwnerList, musicSheetPage} from '@views/music-library/api'
  25. import deepClone from '@/utils/deep.clone'
  26. import { getOwnerName } from '@views/music-library/musicUtil'
  27. import TheTooltip from '@/components/TheTooltip'
  28. import {sysApplicationPage} from "@views/menu-manage/api";
  29. export default defineComponent({
  30. name: 'gym-addMusic',
  31. props: {
  32. appId: {
  33. type: String,
  34. required: true
  35. },
  36. subjectList: {
  37. type: Array,
  38. default: () => []
  39. },
  40. musicSheetCategories: {
  41. type: Array,
  42. default: () => []
  43. }
  44. },
  45. emits: ['close', 'getList'],
  46. setup(props, { slots, attrs, emit }) {
  47. const dialogs = useDialog()
  48. const message = useMessage()
  49. const state = reactive({
  50. loading: false,
  51. pagination: {
  52. page: 1,
  53. rows: 5,
  54. pageTotal: 0
  55. },
  56. stepPagination: {
  57. page: 1,
  58. rows: 5,
  59. pageTotal: 0
  60. },
  61. searchForm: {
  62. keyword: null,
  63. musicSheetType: null,
  64. subjectId: null,
  65. sourceType: null,
  66. composer : null,
  67. userId : null,
  68. applicationId : null,
  69. },
  70. subjectList: [] as any,
  71. showAdd: false,
  72. currentStep: 1,
  73. dataList: [],
  74. selectRowData: [] as any, // 选择的数据列表
  75. musicSheetCategories: [] as any,
  76. startSortNum: null as any, // 排序起始值
  77. projectMusicCategoryId: null as any, // 曲目分类ID
  78. globalPaymentType: null as any, //收费方式
  79. userIdDisable: true,
  80. userIdData: [] as any,
  81. useProjectData: [] as any, // 适用项目行数据
  82. })
  83. onMounted(async () => {
  84. state.searchForm.keyword = null
  85. state.searchForm.musicSheetType = null
  86. state.searchForm.subjectId = null
  87. state.searchForm.sourceType = null
  88. state.searchForm.composer = null
  89. state.searchForm.userId = null
  90. state.searchForm.applicationId = null
  91. state.loading = true
  92. state.subjectList = props.subjectList
  93. // state.musicSheetCategories = props.musicSheetCategories
  94. //加载曲目分类列表
  95. try {
  96. const {data} = await musicSheetApplicationExtendCategoryList({
  97. applicationIds: props.appId
  98. })
  99. if (data && data.length > 0) {
  100. state.musicSheetCategories = data[0].musicSheetCategories
  101. }
  102. } catch {
  103. }
  104. await initUseAppList()
  105. await getList()
  106. })
  107. const initUseAppList = async () => {
  108. try {
  109. const appKeys = Object.keys(appKey)
  110. const { data } = await sysApplicationPage({ page: 1, rows: 999 })
  111. const tempList = data.rows || []
  112. state.useProjectData = []
  113. const filter = tempList.filter((next: any) => {
  114. return appKeys.includes(next.appKey)
  115. })
  116. filter.forEach((item: any) => {
  117. state.useProjectData.push({
  118. ...item,
  119. label: item.appName,
  120. value: item.id
  121. })
  122. })
  123. } catch {}
  124. }
  125. const updateUserIdData = async (sourceType: any) => {
  126. if (!state.searchForm.applicationId) {
  127. return
  128. }
  129. state.userIdData = []
  130. state.searchForm.userId = null
  131. if (sourceType && sourceType !== 'PLATFORM') {
  132. const { data } = await musicSheetApplicationOwnerList({
  133. page: 1,
  134. rows: 9999,
  135. sourceType: sourceType,
  136. applicationId: state.searchForm.applicationId
  137. })
  138. const temp = data.rows || []
  139. temp.forEach((next: any) => {
  140. state.userIdData.push({
  141. ...next,
  142. label: sourceType === 'PERSON' ? next.userName : next.organizationRole,
  143. value: sourceType === 'PERSON' ? next.userId : next.organizationRoleId
  144. })
  145. })
  146. }
  147. }
  148. const getList = async () => {
  149. try {
  150. state.loading = true
  151. const sourceType = state.searchForm.sourceType
  152. const { data } = await musicSheetPage({
  153. ...state.pagination,
  154. ...state.searchForm,
  155. userId: (sourceType && sourceType === 'PERSON') ? state.searchForm.userId : null,
  156. organizationRoleId: (sourceType && sourceType === 'ORG') ? state.searchForm.userId : null,
  157. addAppId: props.appId
  158. })
  159. state.pagination.pageTotal = Number(data.total)
  160. state.dataList = data.rows || []
  161. } catch {}
  162. state.loading = false
  163. }
  164. const saveForm = ref()
  165. const onSearch = () => {
  166. saveForm.value?.submit()
  167. }
  168. const onBtnReset = () => {
  169. saveForm.value?.reset()
  170. }
  171. const onSubmit = () => {
  172. state.pagination.page = 1
  173. getList()
  174. }
  175. const onSave = async () => {
  176. if (state.selectRowData.length == 0) {
  177. message.error('未选择曲目')
  178. return
  179. }
  180. const params = [] as any[]
  181. for (let i = 0; i < state.selectRowData.length; i++) {
  182. const item = state.selectRowData[i]
  183. if (!item.projectMusicCategoryId) {
  184. message.error('曲目分类不能为空')
  185. return
  186. }
  187. if (item.sortNo === null || item.sortNo === undefined || item.sortNo === '') {
  188. message.error('排序号不能为空')
  189. return
  190. }
  191. params.push({
  192. ...item,
  193. musicSheetId: item.id,
  194. musicSheetCategoryId: item.projectMusicCategoryId,
  195. applicationId: props.appId,
  196. id: null
  197. })
  198. }
  199. const res = (await musicSheetApplicationExtendSaveBatch(params)) as any
  200. if (res && res.code == '200') {
  201. message.success(`添加成功`)
  202. emit('getList')
  203. emit('close')
  204. }
  205. }
  206. const columnsField = [
  207. {
  208. type: 'selection'
  209. },
  210. {
  211. title: '曲目编号',
  212. key: 'id'
  213. },
  214. {
  215. title: '封面图',
  216. key: 'titleImg',
  217. render(row: any) {
  218. return <NImage width={40} height={40} src={row.musicCover} />
  219. }
  220. },
  221. {
  222. title: '声部',
  223. key: 'subjectNames',
  224. render: (row: any) => {
  225. return <TheTooltip content={row.subjectNames}/>
  226. }
  227. },
  228. {
  229. title: '曲目名称',
  230. key: 'name'
  231. },
  232. {
  233. title: '音乐人',
  234. key: 'composer'
  235. },
  236. {
  237. title: '多声轨渲染',
  238. key: 'musicSheetType',
  239. render: (row: any) => {
  240. return (
  241. <div>
  242. {getMapValueByKey(row.musicSheetType, new Map(Object.entries(musicSheetType)))}
  243. </div>
  244. )
  245. }
  246. },
  247. {
  248. title: '作者属性',
  249. key: 'sourceType',
  250. render(row: any) {
  251. return getMapValueByKey(row.sourceType, new Map(Object.entries(musicSheetSourceType)))
  252. }
  253. },
  254. {
  255. title: '所属人',
  256. key: 'userName',
  257. width: 200,
  258. render: (row: any) => {
  259. return <TheTooltip content={getOwnerName(row.musicSheetExtend, row.sourceType)} />
  260. }
  261. }
  262. ]
  263. const columns = (): any => {
  264. return columnsField
  265. }
  266. const stepColumns = (): DataTableColumns => {
  267. const field = deepClone(columnsField)
  268. field.splice(0, 1)
  269. field.push({
  270. title(column: any) {
  271. return (
  272. <NSpace>
  273. 曲目分类
  274. <NButton
  275. type="primary"
  276. size="small"
  277. text
  278. onClick={() => {
  279. dialogs.create({
  280. title: '请选择曲目分类',
  281. showIcon: false,
  282. content: () => {
  283. return h(
  284. 'div',
  285. {
  286. class: 'flex flex-col justify-center items-center text-14px'
  287. },
  288. [
  289. // icon
  290. h(NCascader, {
  291. onUpdateValue(v) {
  292. state.projectMusicCategoryId = v
  293. },
  294. valueField: 'id',
  295. labelField: 'name',
  296. childrenField: 'children',
  297. placeholderField: '请选择曲目分类',
  298. options: state.musicSheetCategories
  299. })
  300. ]
  301. )
  302. },
  303. positiveText: '确定',
  304. negativeText: '取消',
  305. onPositiveClick: () => {
  306. for (let i = 0; i < state.selectRowData.length; i++) {
  307. const item = state.selectRowData[i]
  308. item.projectMusicCategoryId = state.projectMusicCategoryId
  309. }
  310. }
  311. })
  312. }}
  313. >
  314. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  315. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  316. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  317. <path
  318. d="M25.4 9c.8-.8.8-2 0-2.8l-3.6-3.6c-.8-.8-2-.8-2.8 0l-15 15V24h6.4l15-15zm-5-5L24 7.6l-3 3L17.4 7l3-3zM6 22v-3.6l10-10l3.6 3.6l-10 10H6z"
  319. fill="currentColor"
  320. ></path>
  321. </svg>
  322. </NIcon>
  323. </NButton>
  324. </NSpace>
  325. )
  326. },
  327. key: 'projectMusicCategoryId',
  328. width: 200,
  329. render: (row: any) => {
  330. // })
  331. return (
  332. <NCascader
  333. valueField="id"
  334. labelField="name"
  335. children-field="children"
  336. placeholder="请选择曲目分类"
  337. value={row.projectMusicCategoryId}
  338. options={state.musicSheetCategories}
  339. onUpdateValue={(value: any) => {
  340. row.projectMusicCategoryId = value
  341. }}
  342. clearable
  343. />
  344. )
  345. }
  346. })
  347. field.push({
  348. title(column: any) {
  349. return (
  350. <NSpace>
  351. 收费方式
  352. <NButton
  353. type="primary"
  354. size="small"
  355. text
  356. onClick={() => {
  357. dialogs.create({
  358. title: '请选择收费方式',
  359. showIcon: false,
  360. content: () => {
  361. return h(
  362. 'div',
  363. {
  364. class: 'flex flex-col justify-center items-center text-14px'
  365. },
  366. [
  367. h(NSelect, {
  368. onUpdateValue(v) {
  369. state.globalPaymentType = v
  370. },
  371. clearable: true,
  372. options: [
  373. {
  374. label:'免费',
  375. value:'FREE'
  376. },
  377. {
  378. label:'收费',
  379. value:'CHARGE'
  380. }
  381. ]
  382. })
  383. ]
  384. )
  385. },
  386. positiveText: '确定',
  387. negativeText: '取消',
  388. onPositiveClick: () => {
  389. for (let i = 0; i < state.selectRowData.length; i++) {
  390. const item = state.selectRowData[i]
  391. item.paymentType = state.globalPaymentType
  392. }
  393. }
  394. })
  395. }}
  396. >
  397. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  398. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  399. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  400. <path
  401. d="M25.4 9c.8-.8.8-2 0-2.8l-3.6-3.6c-.8-.8-2-.8-2.8 0l-15 15V24h6.4l15-15zm-5-5L24 7.6l-3 3L17.4 7l3-3zM6 22v-3.6l10-10l3.6 3.6l-10 10H6z"
  402. fill="currentColor"
  403. ></path>
  404. </svg>
  405. </NIcon>
  406. </NButton>
  407. </NSpace>
  408. )
  409. },
  410. key: 'paymentType',
  411. width: 200,
  412. render: (row: any) => {
  413. return (
  414. <NSelect
  415. placeholder="请选择收费方式"
  416. value={row.paymentType}
  417. options={[
  418. {
  419. label:'免费',
  420. value:'FREE'
  421. },
  422. {
  423. label:'收费',
  424. value:'CHARGE'
  425. }
  426. ]}
  427. clearable
  428. onUpdateValue={(value) => {
  429. row['paymentType'] = value
  430. }}
  431. />
  432. )
  433. }
  434. })
  435. field.push({
  436. title(column: any) {
  437. return (
  438. <NSpace>
  439. 排序
  440. <NButton
  441. type="primary"
  442. size="small"
  443. text
  444. onClick={() => {
  445. dialogs.create({
  446. title: '请输入排序起始值',
  447. showIcon: false,
  448. content: () => {
  449. return h(
  450. 'div',
  451. {
  452. class: 'flex flex-col justify-center items-center text-14px'
  453. },
  454. [
  455. // icon
  456. h(NInputNumber, {
  457. onUpdateValue(v) {
  458. state.startSortNum = v
  459. },
  460. min: 0,
  461. max: 9999
  462. })
  463. ]
  464. )
  465. },
  466. positiveText: '确定',
  467. negativeText: '取消',
  468. onPositiveClick: () => {
  469. if (state.startSortNum) {
  470. for (let i = 0; i < state.selectRowData.length; i++) {
  471. const item = state.selectRowData[i]
  472. item.sortNo = state.startSortNum + i
  473. }
  474. }
  475. }
  476. })
  477. }}
  478. >
  479. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  480. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  481. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  482. <path
  483. d="M25.4 9c.8-.8.8-2 0-2.8l-3.6-3.6c-.8-.8-2-.8-2.8 0l-15 15V24h6.4l15-15zm-5-5L24 7.6l-3 3L17.4 7l3-3zM6 22v-3.6l10-10l3.6 3.6l-10 10H6z"
  484. fill="currentColor"
  485. ></path>
  486. </svg>
  487. </NIcon>
  488. </NButton>
  489. </NSpace>
  490. )
  491. },
  492. key: 'sortNo',
  493. width: 150,
  494. render: (row: any) => {
  495. return h(NInputNumber, {
  496. value: row.sortNo,
  497. min: 0,
  498. max: 9999,
  499. onUpdateValue(value: any) {
  500. row.sortNo = value
  501. }
  502. })
  503. }
  504. })
  505. field.push({
  506. title: '操作',
  507. key: 'operation',
  508. fixed: 'right',
  509. render(row: any) {
  510. return (
  511. <NSpace>
  512. <NButton
  513. type="primary"
  514. size="small"
  515. text
  516. //v-auth="musicSheet/update1602302618558099458"
  517. onClick={() => {
  518. dialogs.warning({
  519. title: '提示',
  520. content: `是否删除该数据?`,
  521. positiveText: '确定',
  522. negativeText: '取消',
  523. onPositiveClick: async () => {
  524. try {
  525. const index = state.selectRowData.findIndex((item: any) => {
  526. if (item.id == row.id) {
  527. return true
  528. }
  529. })
  530. if (index > -1) {
  531. state.selectRowData.splice(index, 1)
  532. }
  533. const index1 = checkedRowKeysRef.value.findIndex((item: any) => {
  534. if (item == row.id) {
  535. return true
  536. }
  537. })
  538. if (index1 > -1) {
  539. checkedRowKeysRef.value.splice(index, 1)
  540. }
  541. } catch {}
  542. }
  543. })
  544. }}
  545. >
  546. 移除
  547. </NButton>
  548. </NSpace>
  549. )
  550. }
  551. })
  552. return field
  553. }
  554. const checkedRowKeysRef = ref<DataTableRowKey[]>([])
  555. const handleCheck = (rowKeys: DataTableRowKey[]) => {
  556. checkedRowKeysRef.value = rowKeys
  557. // 添加行更新值
  558. state.dataList.forEach((next: any) => {
  559. if (checkedRowKeysRef.value.includes(next.id)) {
  560. const find = state.selectRowData.find((row: any) => {
  561. return row.id === next.id
  562. })
  563. if (!find) {
  564. state.selectRowData.push(next)
  565. }
  566. }
  567. })
  568. // 去掉行更新值
  569. state.selectRowData = state.selectRowData.filter((next: any) => {
  570. return checkedRowKeysRef.value.includes(next.id)
  571. })
  572. }
  573. return () => {
  574. return (
  575. <div class="system-menu-container">
  576. <NSpace vertical size="medium">
  577. <NSteps
  578. current={state.currentStep}
  579. // onUpdateCurrent={()=>{
  580. // state.currentStep = val
  581. // }}
  582. style={'margin-bottom: 10px;margin-top: 10px'}
  583. >
  584. <NStep title="选择曲目" description=""></NStep>
  585. <NStep title="设置曲目信息" description=""></NStep>
  586. </NSteps>
  587. </NSpace>
  588. {state.currentStep === 1 && (
  589. <div class="system-menu-container">
  590. <SaveForm
  591. ref={saveForm}
  592. model={state.searchForm}
  593. onSubmit={onSubmit}
  594. // saveKey="cooleshow-edu-addMusic"
  595. onSetModel={(val: any) => (state.searchForm = val)}
  596. >
  597. <NFormItem label="关键词" path="keyword">
  598. <NInput
  599. v-model:value={state.searchForm.keyword}
  600. placeholder="请输入曲目名称/编号"
  601. clearable
  602. />
  603. </NFormItem>
  604. <NFormItem label="多声轨渲染" path="musicSheetType">
  605. <NSelect
  606. placeholder="请选择多声轨渲染"
  607. v-model:value={state.searchForm.musicSheetType}
  608. options={getSelectDataFromObj(musicSheetType)}
  609. clearable
  610. />
  611. </NFormItem>
  612. <NFormItem label="可用声部" path="musicSubject">
  613. <NSelect
  614. placeholder="请选择可用声部"
  615. v-model:value={state.searchForm.subjectId}
  616. options={state.subjectList}
  617. clearable
  618. />
  619. </NFormItem>
  620. <NFormItem label="音乐人" path="composer">
  621. <NInput
  622. placeholder="请选择音乐人"
  623. v-model:value={state.searchForm.composer}
  624. clearable
  625. />
  626. </NFormItem>
  627. <NFormItem label="曲目来源" path="sourceType">
  628. <NSelect
  629. placeholder="请选择曲目来源"
  630. v-model:value={state.searchForm.sourceType}
  631. options={getSelectDataFromObj(musicSheetSourceType)}
  632. onUpdateValue={async (value: any) => {
  633. state.userIdData = []
  634. state.searchForm.userId = null
  635. if (value && value !== 'PLATFORM') {
  636. await updateUserIdData(value)
  637. state.userIdDisable = false
  638. } else {
  639. state.userIdDisable = true
  640. }
  641. }}
  642. clearable
  643. />
  644. </NFormItem>
  645. <NFormItem label="项目" path="applicationId">
  646. <NSelect
  647. placeholder="请选择项目"
  648. v-model:value={state.searchForm.applicationId}
  649. options={state.useProjectData}
  650. clearable
  651. onUpdateValue={async (value: any) => {
  652. state.searchForm.applicationId = value
  653. if (value) {
  654. await updateUserIdData(state.searchForm.sourceType)
  655. state.userIdDisable = !(
  656. state.searchForm.sourceType && state.searchForm.sourceType !== 'PLATFORM'
  657. )
  658. } else {
  659. state.searchForm.userId = null
  660. state.userIdDisable = true
  661. state.userIdData = []
  662. }
  663. }}
  664. />
  665. </NFormItem>
  666. <NFormItem label="所属人" path="author">
  667. <NSelect
  668. filterable
  669. placeholder="请选择所属人"
  670. disabled={state.userIdDisable || (!state.searchForm.applicationId && !state.searchForm.sourceType)}
  671. v-model:value={state.searchForm.userId}
  672. options={state.userIdData}
  673. clearable
  674. ></NSelect>
  675. </NFormItem>
  676. <NFormItem>
  677. <NSpace>
  678. <NButton type="primary" onClick={onSearch}>
  679. 搜索
  680. </NButton>
  681. <NButton type="default" onClick={onBtnReset}>
  682. 重置
  683. </NButton>
  684. </NSpace>
  685. </NFormItem>
  686. </SaveForm>
  687. <p style={{ paddingBottom: '12px' }}>
  688. 你选择了<span style={'color:red;padding:0 8px'}>{state.selectRowData.length}</span>
  689. 条曲目
  690. </p>
  691. <NDataTable
  692. loading={state.loading}
  693. columns={columns()}
  694. data={state.dataList}
  695. rowKey={(row: any) => row.id}
  696. onUpdateCheckedRowKeys={handleCheck}
  697. ></NDataTable>
  698. <Pagination
  699. v-model:page={state.pagination.page}
  700. v-model:pageSize={state.pagination.rows}
  701. v-model:pageTotal={state.pagination.pageTotal}
  702. onList={getList}
  703. sync
  704. // saveKey="cooleshow-edu-addMusic"
  705. ></Pagination>
  706. </div>
  707. )}
  708. {state.currentStep === 2 && (
  709. <div class="system-menu-container" style={'margin-top: 15px;'}>
  710. <NDataTable
  711. loading={state.loading}
  712. columns={stepColumns()}
  713. data={state.selectRowData}
  714. rowKey={(row: any) => row.id}
  715. maxHeight={500}
  716. scrollX={1800}
  717. ></NDataTable>
  718. </div>
  719. )}
  720. <NSpace justify="end" style={'margin-top:10px'}>
  721. <NButton
  722. type="default"
  723. onClick={() => {
  724. if (state.currentStep > 1) {
  725. state.currentStep = state.currentStep - 1
  726. } else {
  727. emit('close')
  728. }
  729. }}
  730. >
  731. {state.currentStep === 1 ? '取消' : '上一步'}
  732. </NButton>
  733. <NButton
  734. type="primary"
  735. onClick={() => {
  736. if (state.currentStep < 2) {
  737. if (state.selectRowData.length == 0) {
  738. message.warning('请选择曲目')
  739. return
  740. }
  741. state.currentStep = state.currentStep + 1
  742. } else {
  743. onSave()
  744. }
  745. }}
  746. // loading={btnLoading.value}
  747. // disabled={btnLoading.value}
  748. >
  749. {state.currentStep === 2 ? '确定' : '下一步'}
  750. </NButton>
  751. </NSpace>
  752. </div>
  753. )
  754. }
  755. }
  756. })