addMusic.tsx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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 { musicSheetSourceType, musicSheetType } from '@/utils/constant'
  24. import {musicSheetApplicationExtendCategoryList, musicSheetApplicationExtendSaveBatch, 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. export default defineComponent({
  29. name: 'kt-addMusic',
  30. props: {
  31. appId: {
  32. type: String,
  33. required: true
  34. },
  35. subjectList: {
  36. type: Array,
  37. default: () => []
  38. },
  39. musicSheetCategories: {
  40. type: Array,
  41. default: () => []
  42. }
  43. },
  44. emits: ['close', 'getList'],
  45. setup(props, { slots, attrs, emit }) {
  46. const dialogs = useDialog()
  47. const message = useMessage()
  48. const btnLoading = ref(false)
  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. },
  67. subjectList: [] as any,
  68. showAdd: false,
  69. currentStep: 1,
  70. dataList: [],
  71. selectRowData: [] as any, // 选择的数据列表
  72. musicSheetCategories: [] as any,
  73. startSortNum: null as any, // 排序起始值
  74. projectMusicCategoryId: null as any // 曲目分类ID
  75. })
  76. onMounted(async () => {
  77. state.loading = true
  78. state.subjectList = props.subjectList
  79. // state.musicSheetCategories = props.musicSheetCategories
  80. //加载曲目分类列表
  81. try {
  82. const {data} = await musicSheetApplicationExtendCategoryList({
  83. applicationIds: props.appId
  84. })
  85. if (data && data.length > 0) {
  86. state.musicSheetCategories = data[0].musicSheetCategories
  87. }
  88. } catch {
  89. }
  90. await getList()
  91. })
  92. const getList = async () => {
  93. try {
  94. state.loading = true
  95. const { data } = await musicSheetPage({
  96. ...state.pagination,
  97. ...state.searchForm,
  98. addAppId: props.appId
  99. })
  100. state.pagination.pageTotal = Number(data.total)
  101. state.dataList = data.rows || []
  102. } catch {}
  103. state.loading = false
  104. }
  105. const saveForm = ref()
  106. const onSearch = () => {
  107. saveForm.value?.submit()
  108. }
  109. const onBtnReset = () => {
  110. saveForm.value?.reset()
  111. }
  112. const onSubmit = () => {
  113. state.pagination.page = 1
  114. getList()
  115. }
  116. const onSave = async () => {
  117. if (state.selectRowData.length == 0) {
  118. message.error('未选择曲目')
  119. return
  120. }
  121. const params = [] as any[]
  122. for (let i = 0; i < state.selectRowData.length; i++) {
  123. const item = state.selectRowData[i]
  124. if (!item.projectMusicCategoryId) {
  125. message.error('乐谱教材不能为空')
  126. return
  127. }
  128. if (!item.sortNo) {
  129. item.sortNo = 0
  130. }
  131. params.push({
  132. ...item,
  133. musicSheetId: item.id,
  134. musicSheetCategoryId: item.projectMusicCategoryId,
  135. applicationId: props.appId,
  136. id: null
  137. })
  138. }
  139. btnLoading.value = true
  140. try {
  141. const res = (await musicSheetApplicationExtendSaveBatch(params)) as any
  142. if (res && res.code == '200') {
  143. message.success(`添加成功`)
  144. emit('getList')
  145. emit('close')
  146. }
  147. } catch (err) {}
  148. btnLoading.value = false
  149. }
  150. const columnsField = [
  151. {
  152. type: 'selection'
  153. },
  154. {
  155. title: '曲目编号',
  156. key: 'id'
  157. },
  158. {
  159. title: '封面图',
  160. key: 'titleImg',
  161. render(row: any) {
  162. return <NImage width={40} height={40} src={row.musicCover} />
  163. }
  164. },
  165. {
  166. title: '声部',
  167. key: 'subjectNames',
  168. render: (row: any) => {
  169. return <TheTooltip content={row.subjectNames}/>
  170. }
  171. },
  172. {
  173. title: '曲目名称',
  174. key: 'name'
  175. },
  176. {
  177. title: '音乐人',
  178. key: 'composer'
  179. },
  180. {
  181. title: '曲目类型',
  182. key: 'musicSheetType',
  183. render: (row: any) => {
  184. return (
  185. <div>
  186. {getMapValueByKey(row.musicSheetType, new Map(Object.entries(musicSheetType)))}
  187. </div>
  188. )
  189. }
  190. },
  191. {
  192. title: '作者属性',
  193. key: 'sourceType',
  194. render(row: any) {
  195. return getMapValueByKey(row.sourceType, new Map(Object.entries(musicSheetSourceType)))
  196. }
  197. },
  198. {
  199. title: '所属人',
  200. key: 'userName',
  201. render: (row: any) => {
  202. return <TheTooltip content={getOwnerName(row.musicSheetExtend, row.sourceType)} />
  203. }
  204. }
  205. ]
  206. const columns = (): any => {
  207. return columnsField
  208. }
  209. const stepColumns = (): DataTableColumns => {
  210. const field = deepClone(columnsField)
  211. field.splice(0, 1)
  212. field.push({
  213. title(column: any) {
  214. return (
  215. <NSpace>
  216. 乐谱教材
  217. <NButton
  218. type="primary"
  219. size="small"
  220. text
  221. onClick={() => {
  222. dialogs.create({
  223. title: '请选择乐谱教材',
  224. showIcon: false,
  225. content: () => {
  226. return h(
  227. 'div',
  228. {
  229. class: 'flex flex-col justify-center items-center text-14px'
  230. },
  231. [
  232. // icon
  233. h(NCascader, {
  234. onUpdateValue(v) {
  235. state.projectMusicCategoryId = v
  236. },
  237. valueField: 'id',
  238. labelField: 'name',
  239. childrenField: 'children',
  240. placeholderField: '请选择乐谱教材',
  241. options: state.musicSheetCategories
  242. })
  243. ]
  244. )
  245. },
  246. positiveText: '确定',
  247. negativeText: '取消',
  248. onPositiveClick: () => {
  249. for (let i = 0; i < state.selectRowData.length; i++) {
  250. const item = state.selectRowData[i]
  251. item.projectMusicCategoryId = state.projectMusicCategoryId
  252. }
  253. }
  254. })
  255. }}
  256. >
  257. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  258. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  259. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  260. <path
  261. 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"
  262. fill="currentColor"
  263. ></path>
  264. </svg>
  265. </NIcon>
  266. </NButton>
  267. </NSpace>
  268. )
  269. },
  270. key: 'projectMusicCategoryId',
  271. fixed: 'right',
  272. width: 200,
  273. render: (row: any) => {
  274. // })
  275. return (
  276. <NCascader
  277. valueField="id"
  278. labelField="name"
  279. children-field="children"
  280. placeholder="请选择曲目分类"
  281. value={row.projectMusicCategoryId}
  282. options={state.musicSheetCategories}
  283. onUpdateValue={(value: any) => {
  284. row.projectMusicCategoryId = value
  285. }}
  286. clearable
  287. />
  288. )
  289. }
  290. })
  291. field.push({
  292. title(column: any) {
  293. return (
  294. <NSpace>
  295. 排序
  296. <NButton
  297. type="primary"
  298. size="small"
  299. text
  300. onClick={() => {
  301. dialogs.create({
  302. title: '请输入排序起始值',
  303. showIcon: false,
  304. content: () => {
  305. return h(
  306. 'div',
  307. {
  308. class: 'flex flex-col justify-center items-center text-14px'
  309. },
  310. [
  311. // icon
  312. h(NInputNumber, {
  313. onUpdateValue(v) {
  314. state.startSortNum = v
  315. },
  316. min: 0,
  317. max: 9999
  318. })
  319. ]
  320. )
  321. },
  322. positiveText: '确定',
  323. negativeText: '取消',
  324. onPositiveClick: () => {
  325. if (state.startSortNum) {
  326. for (let i = 0; i < state.selectRowData.length; i++) {
  327. const item = state.selectRowData[i]
  328. item.sortNo = state.startSortNum + i
  329. }
  330. }
  331. }
  332. })
  333. }}
  334. >
  335. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  336. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  337. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  338. <path
  339. 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"
  340. fill="currentColor"
  341. ></path>
  342. </svg>
  343. </NIcon>
  344. </NButton>
  345. </NSpace>
  346. )
  347. },
  348. key: 'sortNo',
  349. fixed: 'right',
  350. width: 150,
  351. render: (row: any) => {
  352. return h(NInputNumber, {
  353. value: row.sortNo,
  354. min: 0,
  355. max: 9999,
  356. defaultValue: 0,
  357. onUpdateValue(value: any) {
  358. row.sortNo = value
  359. }
  360. })
  361. }
  362. })
  363. field.push({
  364. title: '操作',
  365. key: 'operation',
  366. fixed: 'right',
  367. render(row: any) {
  368. return (
  369. <NSpace>
  370. <NButton
  371. type="primary"
  372. size="small"
  373. text
  374. //v-auth="musicSheet/update1602302618558099458"
  375. onClick={() => {
  376. dialogs.warning({
  377. title: '警告',
  378. content: `是否删除该数据?`,
  379. positiveText: '确定',
  380. negativeText: '取消',
  381. onPositiveClick: async () => {
  382. try {
  383. const index = state.selectRowData.findIndex((item: any) => {
  384. if (item.id == row.id) {
  385. return true
  386. }
  387. })
  388. if (index > -1) {
  389. state.selectRowData.splice(index, 1)
  390. }
  391. const index1 = checkedRowKeysRef.value.findIndex((item: any) => {
  392. if (item == row.id) {
  393. return true
  394. }
  395. })
  396. if (index1 > -1) {
  397. checkedRowKeysRef.value.splice(index, 1)
  398. }
  399. } catch {}
  400. }
  401. })
  402. }}
  403. >
  404. 移除
  405. </NButton>
  406. </NSpace>
  407. )
  408. }
  409. })
  410. return field
  411. }
  412. const checkedRowKeysRef = ref<DataTableRowKey[]>([])
  413. const handleCheck = (rowKeys: DataTableRowKey[]) => {
  414. checkedRowKeysRef.value = rowKeys
  415. // 添加行更新值
  416. state.dataList.forEach((next: any) => {
  417. if (checkedRowKeysRef.value.includes(next.id)) {
  418. const find = state.selectRowData.find((row: any) => {
  419. return row.id === next.id
  420. })
  421. if (!find) {
  422. state.selectRowData.push(next)
  423. }
  424. }
  425. })
  426. // 去掉行更新值
  427. state.selectRowData = state.selectRowData.filter((next: any) => {
  428. return checkedRowKeysRef.value.includes(next.id)
  429. })
  430. }
  431. return () => {
  432. return (
  433. <div class="system-menu-container">
  434. <NSpace vertical size="medium">
  435. <NSteps
  436. current={state.currentStep}
  437. // onUpdateCurrent={()=>{
  438. // state.currentStep = val
  439. // }}
  440. style={'margin-bottom: 10px;margin-top: 10px'}
  441. >
  442. <NStep title="选择曲目" description=""></NStep>
  443. <NStep title="设置曲目信息" description=""></NStep>
  444. </NSteps>
  445. </NSpace>
  446. {state.currentStep === 1 && (
  447. <div class="system-menu-container">
  448. <SaveForm
  449. ref={saveForm}
  450. model={state.searchForm}
  451. onSubmit={onSubmit}
  452. // saveKey="cooleshow-edu-addMusic"
  453. onSetModel={(val: any) => (state.searchForm = val)}
  454. >
  455. <NFormItem label="关键词" path="keyword">
  456. <NInput
  457. v-model:value={state.searchForm.keyword}
  458. placeholder="请输入曲目名称/编号"
  459. clearable
  460. />
  461. </NFormItem>
  462. <NFormItem label="曲目类型" path="musicSheetType">
  463. <NSelect
  464. placeholder="请选择曲目类型"
  465. v-model:value={state.searchForm.musicSheetType}
  466. options={getSelectDataFromObj(musicSheetType)}
  467. clearable
  468. />
  469. </NFormItem>
  470. <NFormItem label="声部" path="musicSubject">
  471. <NSelect
  472. placeholder="请选择声部"
  473. v-model:value={state.searchForm.subjectId}
  474. options={state.subjectList}
  475. clearable
  476. />
  477. </NFormItem>
  478. <NFormItem label="曲目来源" path="sourceType">
  479. <NSelect
  480. placeholder="请选择曲目来源"
  481. v-model:value={state.searchForm.sourceType}
  482. options={getSelectDataFromObj(musicSheetSourceType)}
  483. // onUpdateValue={async (value: any) => {
  484. // }}
  485. clearable
  486. />
  487. </NFormItem>
  488. <NFormItem>
  489. <NSpace>
  490. <NButton type="primary" onClick={onSearch}>
  491. 搜索
  492. </NButton>
  493. <NButton type="default" onClick={onBtnReset}>
  494. 重置
  495. </NButton>
  496. </NSpace>
  497. </NFormItem>
  498. </SaveForm>
  499. <p style={{ paddingBottom: '12px' }}>
  500. 你选择了<span style={'color:red;padding:0 8px'}>{state.selectRowData.length}</span>
  501. 条曲目
  502. </p>
  503. <NDataTable
  504. loading={state.loading}
  505. columns={columns()}
  506. data={state.dataList}
  507. rowKey={(row: any) => row.id}
  508. onUpdateCheckedRowKeys={handleCheck}
  509. ></NDataTable>
  510. <Pagination
  511. v-model:page={state.pagination.page}
  512. v-model:pageSize={state.pagination.rows}
  513. v-model:pageTotal={state.pagination.pageTotal}
  514. onList={getList}
  515. sync
  516. // saveKey="cooleshow-edu-addMusic"
  517. ></Pagination>
  518. </div>
  519. )}
  520. {state.currentStep === 2 && (
  521. <div class="system-menu-container" style={'margin-top: 15px;'}>
  522. <NDataTable
  523. loading={state.loading}
  524. columns={stepColumns()}
  525. data={state.selectRowData}
  526. rowKey={(row: any) => row.id}
  527. maxHeight={500}
  528. ></NDataTable>
  529. </div>
  530. )}
  531. <NSpace justify="end" style={'margin-top:10px'}>
  532. <NButton
  533. type="default"
  534. onClick={() => {
  535. if (state.currentStep > 1) {
  536. state.currentStep = state.currentStep - 1
  537. } else {
  538. emit('close')
  539. }
  540. }}
  541. >
  542. {state.currentStep === 1 ? '取消' : '上一步'}
  543. </NButton>
  544. <NButton
  545. type="primary"
  546. onClick={() => {
  547. if (state.currentStep < 2) {
  548. if (state.selectRowData.length == 0) {
  549. message.warning('请选择曲目')
  550. return
  551. }
  552. state.currentStep = state.currentStep + 1
  553. } else {
  554. onSave()
  555. }
  556. }}
  557. loading={btnLoading.value}
  558. disabled={btnLoading.value}
  559. >
  560. {state.currentStep === 2 ? '确定' : '下一步'}
  561. </NButton>
  562. </NSpace>
  563. </div>
  564. )
  565. }
  566. }
  567. })