addMusic.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  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, 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: 'gyt-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. useProjectData: [] as any, // 适用项目行数据
  79. userIdDisable: true,
  80. userIdData: [] as any,
  81. })
  82. onMounted(async () => {
  83. state.searchForm.keyword = null
  84. state.searchForm.musicSheetType = null
  85. state.searchForm.subjectId = null
  86. state.searchForm.sourceType = null
  87. state.searchForm.composer = null
  88. state.searchForm.userId = null
  89. state.searchForm.applicationId = null
  90. state.loading = true
  91. state.subjectList = props.subjectList
  92. // state.musicSheetCategories = props.musicSheetCategories
  93. //加载曲目分类列表
  94. try {
  95. const {data} = await musicSheetApplicationExtendCategoryList({
  96. applicationIds: props.appId
  97. })
  98. if (data && data.length > 0) {
  99. state.musicSheetCategories = data[0].musicSheetCategories
  100. }
  101. } catch {
  102. }
  103. await initUseAppList()
  104. await getList()
  105. })
  106. const initUseAppList = async () => {
  107. try {
  108. const appKeys = Object.keys(appKey)
  109. const { data } = await sysApplicationPage({ page: 1, rows: 999 })
  110. const tempList = data.rows || []
  111. state.useProjectData = []
  112. const filter = tempList.filter((next: any) => {
  113. return appKeys.includes(next.appKey)
  114. })
  115. filter.forEach((item: any) => {
  116. state.useProjectData.push({
  117. ...item,
  118. label: item.appName,
  119. value: item.id
  120. })
  121. })
  122. } catch {}
  123. }
  124. const getList = async () => {
  125. try {
  126. state.loading = true
  127. const search = {
  128. ...state.searchForm,
  129. userId: (state.searchForm.sourceType && state.searchForm.sourceType == 'PERSON') ? state.searchForm.userId : null,
  130. organizationRoleId: (state.searchForm.sourceType && state.searchForm.sourceType == 'ORG') ? state.searchForm.userId : null,
  131. }
  132. const { data } = await musicSheetPage({
  133. ...state.pagination,
  134. ...search,
  135. addAppId: props.appId
  136. })
  137. state.pagination.pageTotal = Number(data.total)
  138. state.dataList = data.rows || []
  139. } catch {}
  140. state.loading = false
  141. }
  142. const saveForm = ref()
  143. const onSearch = () => {
  144. saveForm.value?.submit()
  145. }
  146. const onBtnReset = () => {
  147. saveForm.value?.reset()
  148. }
  149. const onSubmit = () => {
  150. state.pagination.page = 1
  151. getList()
  152. }
  153. const updateUserIdData = async (sourceType: any) => {
  154. if (!state.searchForm.applicationId) {
  155. return
  156. }
  157. state.userIdData = []
  158. state.searchForm.userId = null
  159. if (sourceType && sourceType !== 'PLATFORM') {
  160. const { data } = await musicSheetApplicationOwnerList({
  161. page: 1,
  162. rows: 9999,
  163. sourceType: sourceType,
  164. applicationId: state.searchForm.applicationId
  165. })
  166. const temp = data.rows || []
  167. temp.forEach((next: any) => {
  168. state.userIdData.push({
  169. ...next,
  170. label: sourceType === 'PERSON' ? next.userName : next.organizationRole,
  171. value: sourceType === 'PERSON' ? next.userId : next.organizationRoleId
  172. })
  173. })
  174. }
  175. }
  176. const onSave = async () => {
  177. if (state.selectRowData.length == 0) {
  178. message.error('未选择曲目')
  179. return
  180. }
  181. const params = [] as any[]
  182. for (let i = 0; i < state.selectRowData.length; i++) {
  183. const item = state.selectRowData[i]
  184. if (!item.projectMusicCategoryId) {
  185. message.error('曲目分类不能为空')
  186. return
  187. }
  188. if (item.sortNo === null || item.sortNo === undefined || item.sortNo === '') {
  189. message.error('排序号不能为空')
  190. return
  191. }
  192. params.push({
  193. ...item,
  194. musicSheetId: item.id,
  195. musicSheetCategoryId: item.projectMusicCategoryId,
  196. applicationId: props.appId,
  197. id: null
  198. })
  199. }
  200. const res = (await musicSheetApplicationExtendSaveBatch(params)) as any
  201. if (res && res.code == '200') {
  202. message.success(`添加成功`)
  203. emit('getList')
  204. emit('close')
  205. }
  206. }
  207. const columnsField = [
  208. {
  209. type: 'selection'
  210. },
  211. {
  212. title: '曲目编号',
  213. key: 'id'
  214. },
  215. {
  216. title: '封面图',
  217. key: 'titleImg',
  218. render(row: any) {
  219. return <NImage width={40} height={40} src={row.musicCover} />
  220. }
  221. },
  222. {
  223. title: '可用声部',
  224. key: 'subjectNames',
  225. render: (row: any) => {
  226. return <TheTooltip content={row.subjectNames}/>
  227. }
  228. },
  229. {
  230. title: '曲目名称',
  231. key: 'name'
  232. },
  233. {
  234. title: '音乐人',
  235. key: 'composer'
  236. },
  237. {
  238. title: '多声轨渲染',
  239. key: 'musicSheetType',
  240. render: (row: any) => {
  241. return (
  242. <div>
  243. {getMapValueByKey(row.musicSheetType, new Map(Object.entries(musicSheetType)))}
  244. </div>
  245. )
  246. }
  247. },
  248. {
  249. title: '曲目来源',
  250. key: 'sourceType',
  251. render(row: any) {
  252. return getMapValueByKey(row.sourceType, new Map(Object.entries(musicSheetSourceType)))
  253. }
  254. },
  255. {
  256. title: '所属人',
  257. key: 'userName',
  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. fixed: 'right',
  329. width: 200,
  330. render: (row: any) => {
  331. // })
  332. return (
  333. <NCascader
  334. valueField="id"
  335. labelField="name"
  336. children-field="children"
  337. placeholder="请选择曲目分类"
  338. value={row.projectMusicCategoryId}
  339. options={state.musicSheetCategories}
  340. onUpdateValue={(value: any) => {
  341. row.projectMusicCategoryId = value
  342. }}
  343. clearable
  344. />
  345. )
  346. }
  347. })
  348. field.push({
  349. title(column: any) {
  350. return (
  351. <NSpace>
  352. 排序
  353. <NButton
  354. type="primary"
  355. size="small"
  356. text
  357. onClick={() => {
  358. dialogs.create({
  359. title: '请输入排序起始值',
  360. showIcon: false,
  361. content: () => {
  362. return h(
  363. 'div',
  364. {
  365. class: 'flex flex-col justify-center items-center text-14px'
  366. },
  367. [
  368. // icon
  369. h(NInputNumber, {
  370. onUpdateValue(v) {
  371. state.startSortNum = v
  372. },
  373. min: 0,
  374. max: 9999
  375. })
  376. ]
  377. )
  378. },
  379. positiveText: '确定',
  380. negativeText: '取消',
  381. onPositiveClick: () => {
  382. if (state.startSortNum) {
  383. for (let i = 0; i < state.selectRowData.length; i++) {
  384. const item = state.selectRowData[i]
  385. item.sortNo = state.startSortNum + i
  386. }
  387. }
  388. }
  389. })
  390. }}
  391. >
  392. <NIcon size={15} style="padding-left: 5px;margin-top:4px">
  393. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
  394. <path d="M2 26h28v2H2z" fill="currentColor"></path>
  395. <path
  396. 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"
  397. fill="currentColor"
  398. ></path>
  399. </svg>
  400. </NIcon>
  401. </NButton>
  402. </NSpace>
  403. )
  404. },
  405. key: 'sortNo',
  406. fixed: 'right',
  407. width: 150,
  408. render: (row: any) => {
  409. return h(NInputNumber, {
  410. value: row.sortNo,
  411. min: 0,
  412. max: 9999,
  413. onUpdateValue(value: any) {
  414. row.sortNo = value
  415. }
  416. })
  417. }
  418. })
  419. field.push({
  420. title: '操作',
  421. key: 'operation',
  422. fixed: 'right',
  423. render(row: any) {
  424. return (
  425. <NSpace>
  426. <NButton
  427. type="primary"
  428. size="small"
  429. text
  430. //v-auth="musicSheet/update1602302618558099458"
  431. onClick={() => {
  432. dialogs.warning({
  433. title: '提示',
  434. content: `是否删除该数据?`,
  435. positiveText: '确定',
  436. negativeText: '取消',
  437. onPositiveClick: async () => {
  438. try {
  439. const index = state.selectRowData.findIndex((item: any) => {
  440. if (item.id == row.id) {
  441. return true
  442. }
  443. })
  444. if (index > -1) {
  445. state.selectRowData.splice(index, 1)
  446. }
  447. const index1 = checkedRowKeysRef.value.findIndex((item: any) => {
  448. if (item == row.id) {
  449. return true
  450. }
  451. })
  452. if (index1 > -1) {
  453. checkedRowKeysRef.value.splice(index, 1)
  454. }
  455. } catch {}
  456. }
  457. })
  458. }}
  459. >
  460. 移除
  461. </NButton>
  462. </NSpace>
  463. )
  464. }
  465. })
  466. return field
  467. }
  468. const checkedRowKeysRef = ref<DataTableRowKey[]>([])
  469. const handleCheck = (rowKeys: DataTableRowKey[]) => {
  470. checkedRowKeysRef.value = rowKeys
  471. // 添加行更新值
  472. state.dataList.forEach((next: any) => {
  473. if (checkedRowKeysRef.value.includes(next.id)) {
  474. const find = state.selectRowData.find((row: any) => {
  475. return row.id === next.id
  476. })
  477. if (!find) {
  478. state.selectRowData.push(next)
  479. }
  480. }
  481. })
  482. // 去掉行更新值
  483. state.selectRowData = state.selectRowData.filter((next: any) => {
  484. return checkedRowKeysRef.value.includes(next.id)
  485. })
  486. }
  487. return () => {
  488. return (
  489. <div class="system-menu-container">
  490. <NSpace vertical size="medium">
  491. <NSteps
  492. current={state.currentStep}
  493. // onUpdateCurrent={()=>{
  494. // state.currentStep = val
  495. // }}
  496. style={'margin-bottom: 10px;margin-top: 10px'}
  497. >
  498. <NStep title="选择曲目" description=""></NStep>
  499. <NStep title="设置曲目信息" description=""></NStep>
  500. </NSteps>
  501. </NSpace>
  502. {state.currentStep === 1 && (
  503. <div class="system-menu-container">
  504. <SaveForm
  505. ref={saveForm}
  506. model={state.searchForm}
  507. onSubmit={onSubmit}
  508. // saveKey="cooleshow-edu-addMusic"
  509. onSetModel={(val: any) => (state.searchForm = val)}
  510. >
  511. <NFormItem label="关键词" path="keyword">
  512. <NInput
  513. v-model:value={state.searchForm.keyword}
  514. placeholder="请输入曲目名称/编号"
  515. clearable
  516. />
  517. </NFormItem>
  518. <NFormItem label="多声轨渲染" path="musicSheetType">
  519. <NSelect
  520. placeholder="请选择多声轨渲染"
  521. v-model:value={state.searchForm.musicSheetType}
  522. options={getSelectDataFromObj(musicSheetType)}
  523. clearable
  524. />
  525. </NFormItem>
  526. <NFormItem label="可用声部" path="musicSubject">
  527. <NSelect
  528. placeholder="请选择可用声部"
  529. v-model:value={state.searchForm.subjectId}
  530. options={state.subjectList}
  531. clearable
  532. />
  533. </NFormItem>
  534. <NFormItem label="音乐人" path="composer">
  535. <NInput
  536. placeholder="请选择音乐人"
  537. v-model:value={state.searchForm.composer}
  538. clearable
  539. />
  540. </NFormItem>
  541. <NFormItem label="曲目来源" path="sourceType">
  542. <NSelect
  543. placeholder="请选择曲目来源"
  544. v-model:value={state.searchForm.sourceType}
  545. options={getSelectDataFromObj(musicSheetSourceType)}
  546. onUpdateValue={async (value: any) => {
  547. state.userIdData = []
  548. state.searchForm.userId = null
  549. if (value && value !== 'PLATFORM') {
  550. await updateUserIdData(value)
  551. state.userIdDisable = false
  552. } else {
  553. state.userIdDisable = true
  554. }
  555. }}
  556. clearable
  557. />
  558. </NFormItem>
  559. <NFormItem label="项目" path="applicationId">
  560. <NSelect
  561. placeholder="请选择项目"
  562. v-model:value={state.searchForm.applicationId}
  563. options={state.useProjectData}
  564. clearable
  565. onUpdateValue={async (value: any) => {
  566. state.searchForm.applicationId = value
  567. if (value) {
  568. await updateUserIdData(state.searchForm.sourceType)
  569. state.userIdDisable = !(
  570. state.searchForm.sourceType && state.searchForm.sourceType !== 'PLATFORM'
  571. )
  572. } else {
  573. state.searchForm.userId = null
  574. state.userIdDisable = true
  575. state.userIdData = []
  576. }
  577. }}
  578. />
  579. </NFormItem>
  580. <NFormItem label="所属人" path="author">
  581. <NSelect
  582. filterable
  583. placeholder="请选择所属人"
  584. disabled={state.userIdDisable || (!state.searchForm.applicationId && !state.searchForm.sourceType)}
  585. v-model:value={state.searchForm.userId}
  586. options={state.userIdData}
  587. clearable
  588. ></NSelect>
  589. </NFormItem>
  590. <NFormItem>
  591. <NSpace>
  592. <NButton type="primary" onClick={onSearch}>
  593. 搜索
  594. </NButton>
  595. <NButton type="default" onClick={onBtnReset}>
  596. 重置
  597. </NButton>
  598. </NSpace>
  599. </NFormItem>
  600. </SaveForm>
  601. <p style={{ paddingBottom: '12px' }}>
  602. 你选择了<span style={'color:red;padding:0 8px'}>{state.selectRowData.length}</span>
  603. 条曲目
  604. </p>
  605. <NDataTable
  606. loading={state.loading}
  607. columns={columns()}
  608. data={state.dataList}
  609. rowKey={(row: any) => row.id}
  610. onUpdateCheckedRowKeys={handleCheck}
  611. ></NDataTable>
  612. <Pagination
  613. v-model:page={state.pagination.page}
  614. v-model:pageSize={state.pagination.rows}
  615. v-model:pageTotal={state.pagination.pageTotal}
  616. onList={getList}
  617. sync
  618. // saveKey="cooleshow-edu-addMusic"
  619. ></Pagination>
  620. </div>
  621. )}
  622. {state.currentStep === 2 && (
  623. <div class="system-menu-container" style={'margin-top: 15px;'}>
  624. <NDataTable
  625. loading={state.loading}
  626. columns={stepColumns()}
  627. data={state.selectRowData}
  628. rowKey={(row: any) => row.id}
  629. maxHeight={500}
  630. ></NDataTable>
  631. </div>
  632. )}
  633. <NSpace justify="end" style={'margin-top:10px'}>
  634. <NButton
  635. type="default"
  636. onClick={() => {
  637. if (state.currentStep > 1) {
  638. state.currentStep = state.currentStep - 1
  639. } else {
  640. emit('close')
  641. }
  642. }}
  643. >
  644. {state.currentStep === 1 ? '取消' : '上一步'}
  645. </NButton>
  646. <NButton
  647. type="primary"
  648. onClick={() => {
  649. if (state.currentStep < 2) {
  650. if (state.selectRowData.length == 0) {
  651. message.warning('请选择曲目')
  652. return
  653. }
  654. state.currentStep = state.currentStep + 1
  655. } else {
  656. onSave()
  657. }
  658. }}
  659. // loading={btnLoading.value}
  660. // disabled={btnLoading.value}
  661. >
  662. {state.currentStep === 2 ? '确定' : '下一步'}
  663. </NButton>
  664. </NSpace>
  665. </div>
  666. )
  667. }
  668. }
  669. })