use-project.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. import { computed, defineComponent, nextTick, onMounted, reactive, ref } from 'vue'
  2. import styles from '@views/music-library/music-sheet/modal/index.module.less'
  3. import {
  4. NButton,
  5. NCascader,
  6. NCheckbox,
  7. NCheckboxGroup,
  8. NForm,
  9. NFormItem,
  10. NInputNumber,
  11. NSelect,
  12. NSpace,
  13. NTabPane,
  14. NTabs,
  15. useMessage
  16. } from 'naive-ui'
  17. import { appKey, musicSheetAvailableType, musicSheetPaymentType } from '@/utils/constant'
  18. import {
  19. musicSheetApplicationExtendCategoryApplicationExtendInfo,
  20. musicSheetApplicationExtendCategoryList,
  21. musicSheetApplicationExtendSave,
  22. musicSheetDetail
  23. } from '@views/music-library/api'
  24. import { getSelectDataFromObj } from '@/utils/objectUtil'
  25. export default defineComponent({
  26. name: 'use-project',
  27. props: {
  28. useProject: {
  29. type: Array,
  30. required: true,
  31. default: []
  32. },
  33. id: {
  34. type: String,
  35. required: true,
  36. default: null
  37. }
  38. },
  39. emits: ['close', 'getList'],
  40. setup(props, { emit }) {
  41. const tabsRef = ref()
  42. const forms = reactive({
  43. musicSheetId: null,
  44. useApplicationIds: [] as any,
  45. useProjectParamConfig: {
  46. //各个项目配置的参数
  47. GYM: {
  48. musicSheetCategoryId: null as any,
  49. sortNo: null as any,
  50. paymentType: null as any // 是否收费
  51. },
  52. GYT: {
  53. musicSheetCategoryId: null as any,
  54. sortNo: null as any
  55. },
  56. KLX: {
  57. availableType: null as any, //可用途径 ORG 机构 PLATFORM 平台
  58. musicSheetCategoryId: null as any,
  59. paymentType: null as any, // 是否收费
  60. musicPrice: null as any, // 曲目价格
  61. topFlag: null as any, // 是否置顶(0:否;1:是)
  62. exquisiteFlag: null as any, // 精品标志
  63. sortNo: null as any
  64. },
  65. KT: {
  66. musicSheetCategoryId: null as any,
  67. sortNo: null as any
  68. }
  69. } as any
  70. })
  71. // 除了排序号,其他字段有一个有值,其他字段都必填
  72. const gymFileRequire = computed(() => {
  73. const app = forms.useProjectParamConfig.GYM
  74. const fieldList = ['musicSheetCategoryId', 'paymentType']
  75. for (let i = 0; i < fieldList.length; i++) {
  76. const fieldValue = app[fieldList[i]]
  77. if (fieldValue) {
  78. return true
  79. }
  80. }
  81. return false
  82. })
  83. const klxFileRequire = computed(() => {
  84. const app = forms.useProjectParamConfig['KLX']
  85. const fieldList = [
  86. 'availableType',
  87. 'musicSheetCategoryId',
  88. 'paymentType',
  89. 'musicPrice',
  90. 'topFlag',
  91. 'exquisiteFlag'
  92. ]
  93. for (let i = 0; i < fieldList.length; i++) {
  94. const fieldValue = app[fieldList[i]]
  95. if (fieldValue) {
  96. return true
  97. }
  98. }
  99. return false
  100. })
  101. const ktFileRequire = computed(() => {
  102. const app = forms.useProjectParamConfig['KT']
  103. const fieldList = ['musicSheetCategoryId']
  104. for (let i = 0; i < fieldList.length; i++) {
  105. const fieldValue = app[fieldList[i]]
  106. if (fieldValue) {
  107. return true
  108. }
  109. }
  110. return false
  111. })
  112. const gytFileRequire = computed(() => {
  113. const app = forms.useProjectParamConfig['GYT']
  114. const fieldList = ['musicSheetCategoryId']
  115. for (let i = 0; i < fieldList.length; i++) {
  116. const fieldValue = app[fieldList[i]]
  117. if (fieldValue) {
  118. return true
  119. }
  120. }
  121. return false
  122. })
  123. const state = reactive({
  124. loading: false,
  125. musicSheetData: null as any,
  126. tabName: null as any,
  127. selectAppKey: [] as any, //选择的APP
  128. selectAppName: [] as any, //app key name映射
  129. appKeyNameMap: null as any, //
  130. userProjectList: [] as any, // 适用项目列表
  131. musicSheetCategoryOptions: {} as any, //项目曲目分类选择
  132. musicSheetCanBeUsedProjectKey: [] as any // 曲目可以使用在哪些项目,通过声部配置过滤
  133. })
  134. const btnLoading = ref(false)
  135. const message = useMessage()
  136. onMounted(async () => {
  137. state.loading = true
  138. // 加载已经配置的APP
  139. const { data } = await musicSheetDetail({ id: props.id })
  140. state.musicSheetData = data
  141. if (data && data.musicSheetExtend) {
  142. forms.useApplicationIds = data.musicSheetExtend.useApplicationIds?.split(',') || []
  143. }
  144. // 查询该曲目可以使用的app
  145. // {
  146. // try {
  147. // const {data} = await musicSheetApplicationApplicationInfo(state.musicSheetData.id)
  148. // data.forEach((next: any) => {
  149. // state.musicSheetCanBeUsedProjectKey.push(next.appKey)
  150. // })
  151. // } catch (e) {
  152. // }
  153. // }
  154. // 加载所有的APP
  155. const keys = Object.keys(appKey)
  156. // state.userProjectList = props.useProject.filter((next: any) => {
  157. // const indexOf = keys.indexOf(next.appKey);
  158. // return indexOf > -1;
  159. // })
  160. props.useProject.forEach((next: any) => {
  161. const indexOf = keys.indexOf(next.appKey)
  162. let disabled = false
  163. if (indexOf > -1) {
  164. // disabled = !state.musicSheetCanBeUsedProjectKey.includes(next.appKey);
  165. state.userProjectList.push({
  166. ...next,
  167. disabled: disabled
  168. })
  169. }
  170. })
  171. state.appKeyNameMap = new Map<String, String>()
  172. state.userProjectList.forEach((next: any) => {
  173. if (forms.useApplicationIds.includes(next.id)) {
  174. state.selectAppKey.push(next.appKey)
  175. }
  176. state.appKeyNameMap.set(next.appKey, next.appName)
  177. })
  178. if (state.selectAppKey.length > 0) {
  179. state.tabName = state.selectAppKey[0]
  180. }
  181. // 加载不同项目的曲目分类列表
  182. const projectIdArr = [] as any
  183. const appIdCodeMap = new Map<number, string>()
  184. props.useProject.forEach((project: any) => {
  185. projectIdArr.push(project.id)
  186. appIdCodeMap.set(project.id, project.appKey)
  187. })
  188. if (projectIdArr.length > 0) {
  189. const { data } = await musicSheetApplicationExtendCategoryList({
  190. applicationIds: projectIdArr.join(',')
  191. })
  192. data.forEach((next: any) => {
  193. const appCode = appIdCodeMap.get(next.applicationId)
  194. if (appCode) {
  195. state.musicSheetCategoryOptions[appCode] = next.musicSheetCategories
  196. }
  197. })
  198. }
  199. {
  200. const { data } = (await musicSheetApplicationExtendCategoryApplicationExtendInfo({
  201. musicSheetId: props.id
  202. })) as any
  203. data.forEach((next: any) => {
  204. const key = next.appKey
  205. if (key === 'GYM') {
  206. forms.useProjectParamConfig[key]['musicSheetCategoryId'] = next.musicSheetCategories
  207. forms.useProjectParamConfig[key]['sortNo'] = next.sortNo
  208. forms.useProjectParamConfig[key]['paymentType'] = next.paymentType
  209. } else if (key === 'GYT') {
  210. forms.useProjectParamConfig[key]['musicSheetCategoryId'] = next.musicSheetCategoryId
  211. forms.useProjectParamConfig[key]['sortNo'] = next.sortNo
  212. } else if (key === 'KLX') {
  213. forms.useProjectParamConfig[key]['availableType'] = next.availableType
  214. forms.useProjectParamConfig[key]['musicSheetCategoryId'] = next.musicSheetCategoryId
  215. forms.useProjectParamConfig[key]['paymentType'] = next.paymentType
  216. forms.useProjectParamConfig[key]['musicPrice'] = next.musicPrice
  217. forms.useProjectParamConfig[key]['topFlag'] = next.topFlag
  218. forms.useProjectParamConfig[key]['exquisiteFlag'] = next.exquisiteFlag
  219. forms.useProjectParamConfig[key]['sortNo'] = next.sortNo
  220. } else if (key === 'KT') {
  221. forms.useProjectParamConfig[key]['musicSheetCategoryId'] = next.musicSheetCategoryId
  222. forms.useProjectParamConfig[key]['sortNo'] = next.sortNo
  223. }
  224. // forms.useProjectParamConfig[key] = next
  225. })
  226. }
  227. state.loading = false
  228. })
  229. const formsRef = ref()
  230. const onSubmit = async () => {
  231. formsRef.value.validate(async (error: any) => {
  232. if (error) {
  233. if (Array.isArray(error) && error.length > 0) {
  234. const app = error[0][0].field?.split('.')[1]
  235. if (app && state.selectAppKey.includes(app)) {
  236. state.tabName = app
  237. }
  238. }
  239. return
  240. }
  241. btnLoading.value = true
  242. try {
  243. const appKeyIdMap = new Map<string, string>()
  244. props.useProject.forEach((project: any) => {
  245. appKeyIdMap.set(project.appKey, project.id)
  246. })
  247. // 获取选择的应用项目
  248. const applicationExtends = [] as any
  249. state.selectAppKey.forEach((appKey: any) => {
  250. Object.keys(forms.useProjectParamConfig).forEach((key) => {
  251. if (appKey === key) {
  252. const value = forms.useProjectParamConfig[key]
  253. if (!value['sortNo']) {
  254. value['sortNo'] = 0
  255. }
  256. //除了排序号,其他字段都不为空时才保存数据
  257. const every = Object.values(value).every((val: any) => {
  258. return !(val === null || val === undefined || val === '')
  259. })
  260. if (every) {
  261. applicationExtends.push({
  262. ...value,
  263. musicSheetId: props.id,
  264. applicationId: appKeyIdMap.get(key)
  265. })
  266. }
  267. }
  268. })
  269. })
  270. const params = {
  271. musicSheetId: props.id,
  272. useApplicationIds: forms.useApplicationIds.join(','),
  273. applicationExtends: applicationExtends
  274. }
  275. await musicSheetApplicationExtendSave(params)
  276. message.success('修改成功')
  277. emit('getList')
  278. emit('close')
  279. } catch (e) {
  280. console.log(e)
  281. }
  282. btnLoading.value = false
  283. })
  284. }
  285. return () => (
  286. <div>
  287. <NForm
  288. class={styles.formContainer}
  289. model={forms}
  290. ref={formsRef}
  291. label-placement="left"
  292. label-width="85"
  293. >
  294. {/*<NText style={'color:red'}>*/}
  295. {/* 注:应用无曲目声部时,适用应用不可选择*/}
  296. {/*</NText>*/}
  297. <NFormItem
  298. label="适用应用"
  299. path="useApplicationIds"
  300. rule={[
  301. {
  302. required: true,
  303. message: '请选择适用应用'
  304. }
  305. ]}
  306. >
  307. <NCheckboxGroup
  308. v-model:value={forms.useApplicationIds}
  309. onUpdateValue={(value) => {
  310. state.selectAppKey = []
  311. state.userProjectList.forEach((next: any) => {
  312. if (value.includes(next.id)) {
  313. state.selectAppKey.push(next.appKey)
  314. }
  315. })
  316. // 反勾选时,更新选中的tab
  317. if (state.selectAppKey.length == 0) {
  318. state.tabName = ''
  319. } else {
  320. state.tabName = state.selectAppKey[0]
  321. }
  322. nextTick(() => tabsRef.value?.syncBarPosition())
  323. }}
  324. >
  325. {state.userProjectList.map((item: any) => (
  326. <NCheckbox value={item.value}>{item.label}</NCheckbox>
  327. // <NCheckbox value={item.value} disabled={item.disabled}>{item.label}</NCheckbox>
  328. ))}
  329. </NCheckboxGroup>
  330. </NFormItem>
  331. {state.selectAppKey.length > 0 && (
  332. <NTabs
  333. ref={tabsRef}
  334. type="line"
  335. v-model:value={state.tabName}
  336. onUpdate:value={(val: any) => {
  337. state.tabName = val
  338. }}
  339. >
  340. {state.selectAppKey.map((item: any, index: number) => {
  341. return (
  342. <NTabPane
  343. tab={state.appKeyNameMap.get(item)}
  344. name={item}
  345. displayDirective={'show'}
  346. >
  347. {item === 'GYM' && (
  348. <div>
  349. <NFormItem
  350. label="曲目分类"
  351. path="useProjectParamConfig.GYM.musicSheetCategoryId"
  352. rule={[
  353. {
  354. required: gymFileRequire.value,
  355. message: '请选择曲目分类',
  356. trigger:'change',
  357. }
  358. ]}
  359. >
  360. <NCascader
  361. valueField="id"
  362. labelField="name"
  363. children-field="children"
  364. placeholder="请选择分类"
  365. v-model:value={forms.useProjectParamConfig.GYM.musicSheetCategoryId}
  366. options={state.musicSheetCategoryOptions.GYM}
  367. onChange={() => {}}
  368. clearable
  369. />
  370. </NFormItem>
  371. <NFormItem
  372. label="是否收费"
  373. path="useProjectParamConfig.GYM.paymentType"
  374. rule={[
  375. {
  376. required: gymFileRequire.value,
  377. message: '请选择收费类型',
  378. trigger:'change'
  379. }
  380. ]}
  381. >
  382. <NSelect
  383. placeholder="请选择收费类型"
  384. clearable
  385. v-model:value={forms.useProjectParamConfig.GYM.paymentType}
  386. options={[
  387. {
  388. label:'免费',
  389. value:'FREE'
  390. },
  391. {
  392. label:'收费',
  393. value:'CHARGE'
  394. }
  395. ]}
  396. ></NSelect>
  397. </NFormItem>
  398. <NFormItem label="排序值" path="useProjectParamConfig.GYM.sortNo">
  399. <NInputNumber
  400. v-model:value={forms.useProjectParamConfig.GYM.sortNo}
  401. placeholder="请输入排序值"
  402. clearable
  403. min={0}
  404. max={9999}
  405. style={{ width: '100%' }}
  406. />
  407. </NFormItem>
  408. </div>
  409. )}
  410. {item === 'GYT' && (
  411. <div>
  412. <NFormItem
  413. label="分类"
  414. path="useProjectParamConfig.GYT.musicSheetCategoryId"
  415. rule={[
  416. {
  417. required: gytFileRequire.value,
  418. message: '请选择分类',
  419. trigger:'change'
  420. }
  421. ]}
  422. >
  423. <NCascader
  424. valueField="id"
  425. labelField="name"
  426. children-field="children"
  427. placeholder="请选择分类"
  428. v-model:value={forms.useProjectParamConfig.GYT.musicSheetCategoryId}
  429. options={state.musicSheetCategoryOptions.GYT}
  430. clearable
  431. />
  432. </NFormItem>
  433. <NFormItem label="排序值" path="useProjectParamConfig.GYT.sortNo">
  434. <NInputNumber
  435. v-model:value={forms.useProjectParamConfig.GYT.sortNo}
  436. placeholder="请输入排序值"
  437. clearable
  438. min={0}
  439. max={9999}
  440. style={{ width: '100%' }}
  441. />
  442. </NFormItem>
  443. </div>
  444. )}
  445. {item === 'KLX' && (
  446. <div>
  447. <NFormItem
  448. label="可用途径"
  449. path="useProjectParamConfig.KLX.availableType"
  450. rule={[
  451. {
  452. required: klxFileRequire.value,
  453. message: '请选择可用途径',
  454. trigger:'change'
  455. }
  456. ]}
  457. >
  458. <NSelect
  459. placeholder="请选择可用途径"
  460. clearable
  461. v-model:value={forms.useProjectParamConfig.KLX.availableType}
  462. options={getSelectDataFromObj(musicSheetAvailableType)}
  463. ></NSelect>
  464. </NFormItem>
  465. <NFormItem
  466. label="曲目标签"
  467. path="useProjectParamConfig.KLX.musicSheetCategoryId"
  468. rule={[
  469. {
  470. required: klxFileRequire.value,
  471. message: '请选择曲目标签',
  472. trigger:'change',
  473. type:'array'
  474. }
  475. ]}
  476. >
  477. <NSelect
  478. placeholder="请选择曲目标签"
  479. clearable
  480. multiple
  481. labelField={'name'}
  482. valueField={'id'}
  483. v-model:value={forms.useProjectParamConfig.KLX.musicSheetCategoryId}
  484. options={state.musicSheetCategoryOptions.KLX}
  485. maxTagCount={3}
  486. ></NSelect>
  487. </NFormItem>
  488. <NFormItem
  489. label="是否收费"
  490. path="useProjectParamConfig.KLX.paymentType"
  491. rule={[
  492. {
  493. required: klxFileRequire.value,
  494. message: '请选择是否收费',
  495. trigger:'change',
  496. type:'number'
  497. }
  498. ]}
  499. >
  500. <NSelect
  501. placeholder="请选择是否收费"
  502. clearable
  503. v-model:value={forms.useProjectParamConfig.KLX.paymentType}
  504. options={[
  505. {
  506. label: '是',
  507. value: 1
  508. },
  509. {
  510. label: '否',
  511. value: 0
  512. }
  513. ]}
  514. ></NSelect>
  515. </NFormItem>
  516. <NFormItem
  517. label="曲目价格"
  518. path="useProjectParamConfig.KLX.musicPrice"
  519. rule={[
  520. {
  521. required: klxFileRequire.value,
  522. message: '请输入曲目价格',
  523. trigger:['input','blur'],
  524. type:'number'
  525. }
  526. ]}
  527. >
  528. <NInputNumber
  529. style={'width:100%'}
  530. placeholder="请输入曲目价格"
  531. v-model:value={forms.useProjectParamConfig.KLX.musicPrice}
  532. />
  533. </NFormItem>
  534. <NFormItem
  535. label="是否置顶"
  536. path="useProjectParamConfig.KLX.topFlag"
  537. rule={[
  538. {
  539. required: klxFileRequire.value,
  540. message: '请选择是否置顶',
  541. trigger:'change',
  542. type:'number'
  543. }
  544. ]}
  545. >
  546. <NSelect
  547. placeholder="请选择是否置顶"
  548. clearable
  549. v-model:value={forms.useProjectParamConfig.KLX.topFlag}
  550. options={[
  551. {
  552. label: '是',
  553. value: 1
  554. },
  555. {
  556. label: '否',
  557. value: 0
  558. }
  559. ]}
  560. ></NSelect>
  561. </NFormItem>
  562. <NFormItem
  563. label="精品乐谱"
  564. path="useProjectParamConfig.KLX.exquisiteFlag"
  565. rule={[
  566. {
  567. required: klxFileRequire.value,
  568. message: '请选择是否精品乐谱',
  569. trigger:'change',
  570. type:'number'
  571. }
  572. ]}
  573. >
  574. <NSelect
  575. placeholder="请选择是否精品乐谱"
  576. clearable
  577. v-model:value={forms.useProjectParamConfig.KLX.exquisiteFlag}
  578. options={[
  579. {
  580. label: '是',
  581. value: 1
  582. },
  583. {
  584. label: '否',
  585. value: 0
  586. }
  587. ]}
  588. ></NSelect>
  589. </NFormItem>
  590. <NFormItem label="排序值" path="useProjectParamConfig.KLX.sortNo">
  591. <NInputNumber
  592. v-model:value={forms.useProjectParamConfig.KLX.sortNo}
  593. placeholder="请输入排序值"
  594. clearable
  595. min={0}
  596. max={9999}
  597. style={{ width: '100%' }}
  598. />
  599. </NFormItem>
  600. </div>
  601. )}
  602. {item === 'KT' && (
  603. <div>
  604. <NFormItem
  605. label="乐谱教材"
  606. path="useProjectParamConfig.KT.musicSheetCategoryId"
  607. rule={[
  608. {
  609. required: ktFileRequire.value,
  610. message: '请选择乐谱教材'
  611. }
  612. ]}
  613. >
  614. <NCascader
  615. valueField="id"
  616. labelField="name"
  617. children-field="children"
  618. placeholder="请选择乐谱教材"
  619. v-model:value={forms.useProjectParamConfig.KT.musicSheetCategoryId}
  620. options={state.musicSheetCategoryOptions.KT}
  621. clearable
  622. />
  623. </NFormItem>
  624. <NFormItem label="排序值" path="useProjectParamConfig.KT.sortNo">
  625. <NInputNumber
  626. v-model:value={forms.useProjectParamConfig.KT.sortNo}
  627. placeholder="请输入排序值"
  628. clearable
  629. min={0}
  630. max={9999}
  631. style={{ width: '100%' }}
  632. />
  633. </NFormItem>
  634. </div>
  635. )}
  636. </NTabPane>
  637. )
  638. })}
  639. </NTabs>
  640. )}
  641. </NForm>
  642. <NSpace justify="end" style={'margin-top: 10px'}>
  643. <NButton type="default" onClick={() => emit('close')}>
  644. 取消
  645. </NButton>
  646. <NButton
  647. type="primary"
  648. onClick={() => onSubmit()}
  649. loading={btnLoading.value}
  650. disabled={btnLoading.value}
  651. >
  652. 确认
  653. </NButton>
  654. </NSpace>
  655. </div>
  656. )
  657. }
  658. })