use-project.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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, NSpin,
  13. NTabPane,
  14. NTabs,
  15. useMessage
  16. } from 'naive-ui'
  17. import {appKey, musicSheetAvailableType, musicSheetPaymentType, musicSheetType} 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. musicTagIds: null as any,
  59. paymentType: [] 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.musicSheetCategoryId
  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]['musicTagIds'] = next.musicTagIds?.split(',')||[]
  215. forms.useProjectParamConfig[key]['paymentType'] = next.paymentType?.split(',')||[]
  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. let appData = value as any;
  262. if (appKey === 'KLX') {
  263. appData['musicTagIds'] = appData['musicTagIds'].join(',')
  264. appData['paymentType'] = appData['paymentType'].join(',')
  265. }
  266. applicationExtends.push({
  267. ...appData,
  268. musicSheetId: props.id,
  269. applicationId: appKeyIdMap.get(key)
  270. })
  271. }
  272. }
  273. })
  274. })
  275. const params = {
  276. musicSheetId: props.id,
  277. useApplicationIds: forms.useApplicationIds.join(','),
  278. applicationExtends: applicationExtends
  279. }
  280. await musicSheetApplicationExtendSave(params)
  281. message.success('修改成功')
  282. emit('getList')
  283. emit('close')
  284. } catch (e) {
  285. console.log(e)
  286. }
  287. btnLoading.value = false
  288. })
  289. }
  290. return () => (
  291. <NSpin show={state.loading}>
  292. <NForm
  293. class={styles.formContainer}
  294. model={forms}
  295. ref={formsRef}
  296. label-placement="left"
  297. label-width="85"
  298. >
  299. {/*<NText style={'color:red'}>*/}
  300. {/* 注:应用无曲目声部时,适用应用不可选择*/}
  301. {/*</NText>*/}
  302. <NFormItem
  303. label="适用应用"
  304. path="useApplicationIds"
  305. rule={[
  306. {
  307. required: false,
  308. message: '请选择适用应用'
  309. }
  310. ]}
  311. >
  312. <NCheckboxGroup
  313. v-model:value={forms.useApplicationIds}
  314. onUpdateValue={(value) => {
  315. state.selectAppKey = []
  316. state.userProjectList.forEach((next: any) => {
  317. if (value.includes(next.id)) {
  318. state.selectAppKey.push(next.appKey)
  319. }
  320. })
  321. // 反勾选时,更新选中的tab
  322. if (state.selectAppKey.length == 0) {
  323. state.tabName = ''
  324. } else {
  325. state.tabName = state.selectAppKey[0]
  326. }
  327. nextTick(() => tabsRef.value?.syncBarPosition())
  328. }}
  329. >
  330. {state.userProjectList.map((item: any) => (
  331. <NCheckbox value={item.value}>{item.label}</NCheckbox>
  332. // <NCheckbox value={item.value} disabled={item.disabled}>{item.label}</NCheckbox>
  333. ))}
  334. </NCheckboxGroup>
  335. </NFormItem>
  336. {state.selectAppKey.length > 0 && (
  337. <NTabs
  338. ref={tabsRef}
  339. type="line"
  340. v-model:value={state.tabName}
  341. onUpdate:value={(val: any) => {
  342. state.tabName = val
  343. }}
  344. >
  345. {state.selectAppKey.map((item: any, index: number) => {
  346. return (
  347. <NTabPane
  348. tab={state.appKeyNameMap.get(item)}
  349. name={item}
  350. displayDirective={'show'}
  351. >
  352. {item === 'GYM' && (
  353. <div>
  354. <NFormItem
  355. label="曲目分类"
  356. path="useProjectParamConfig.GYM.musicSheetCategoryId"
  357. rule={[
  358. {
  359. required: gymFileRequire.value,
  360. message: '请选择曲目分类',
  361. trigger:'change',
  362. }
  363. ]}
  364. >
  365. <NCascader
  366. valueField="id"
  367. labelField="name"
  368. children-field="children"
  369. placeholder="请选择分类"
  370. v-model:value={forms.useProjectParamConfig.GYM.musicSheetCategoryId}
  371. options={state.musicSheetCategoryOptions.GYM}
  372. onChange={() => {}}
  373. clearable
  374. />
  375. </NFormItem>
  376. <NFormItem
  377. label="是否收费"
  378. path="useProjectParamConfig.GYM.paymentType"
  379. rule={[
  380. {
  381. required: gymFileRequire.value,
  382. message: '请选择收费类型',
  383. trigger:'change'
  384. }
  385. ]}
  386. >
  387. <NSelect
  388. placeholder="请选择收费类型"
  389. clearable
  390. v-model:value={forms.useProjectParamConfig.GYM.paymentType}
  391. options={[
  392. {
  393. label:'免费',
  394. value:'FREE'
  395. },
  396. {
  397. label:'收费',
  398. value:'CHARGE'
  399. }
  400. ]}
  401. ></NSelect>
  402. </NFormItem>
  403. <NFormItem label="排序值" path="useProjectParamConfig.GYM.sortNo">
  404. <NInputNumber
  405. v-model:value={forms.useProjectParamConfig.GYM.sortNo}
  406. placeholder="请输入排序值"
  407. clearable
  408. min={0}
  409. max={9999}
  410. style={{ width: '100%' }}
  411. />
  412. </NFormItem>
  413. </div>
  414. )}
  415. {item === 'GYT' && (
  416. <div>
  417. <NFormItem
  418. label="分类"
  419. path="useProjectParamConfig.GYT.musicSheetCategoryId"
  420. rule={[
  421. {
  422. required: gytFileRequire.value,
  423. message: '请选择分类',
  424. trigger:'change'
  425. }
  426. ]}
  427. >
  428. <NCascader
  429. valueField="id"
  430. labelField="name"
  431. children-field="children"
  432. placeholder="请选择分类"
  433. v-model:value={forms.useProjectParamConfig.GYT.musicSheetCategoryId}
  434. options={state.musicSheetCategoryOptions.GYT}
  435. clearable
  436. />
  437. </NFormItem>
  438. <NFormItem label="排序值" path="useProjectParamConfig.GYT.sortNo">
  439. <NInputNumber
  440. v-model:value={forms.useProjectParamConfig.GYT.sortNo}
  441. placeholder="请输入排序值"
  442. clearable
  443. min={0}
  444. max={9999}
  445. style={{ width: '100%' }}
  446. />
  447. </NFormItem>
  448. </div>
  449. )}
  450. {item === 'KLX' && (
  451. <div>
  452. <NFormItem
  453. label="可用途径"
  454. path="useProjectParamConfig.KLX.availableType"
  455. rule={[
  456. {
  457. required: klxFileRequire.value,
  458. message: '请选择可用途径',
  459. trigger:'change'
  460. }
  461. ]}
  462. >
  463. <NSelect
  464. placeholder="请选择可用途径"
  465. clearable
  466. v-model:value={forms.useProjectParamConfig.KLX.availableType}
  467. options={getSelectDataFromObj(musicSheetAvailableType)}
  468. ></NSelect>
  469. </NFormItem>
  470. <NFormItem
  471. label="曲目标签"
  472. path="useProjectParamConfig.KLX.musicTagIds"
  473. rule={[
  474. {
  475. required: klxFileRequire.value,
  476. message: '请选择曲目标签',
  477. trigger:'change',
  478. type:'array'
  479. }
  480. ]}
  481. >
  482. <NSelect
  483. placeholder="请选择曲目标签"
  484. clearable
  485. multiple
  486. labelField={'name'}
  487. valueField={'id'}
  488. v-model:value={forms.useProjectParamConfig.KLX.musicTagIds}
  489. options={state.musicSheetCategoryOptions.KLX}
  490. maxTagCount={3}
  491. ></NSelect>
  492. </NFormItem>
  493. <NFormItem
  494. label="是否收费"
  495. path="useProjectParamConfig.KLX.paymentType"
  496. rule={[
  497. {
  498. required: klxFileRequire.value,
  499. message: '请选择是否收费',
  500. trigger:'change',
  501. type:'array'
  502. }
  503. ]}
  504. >
  505. <NSelect
  506. placeholder="请选择是否收费"
  507. clearable
  508. v-model:value={forms.useProjectParamConfig.KLX.paymentType}
  509. options={getSelectDataFromObj(musicSheetPaymentType)}
  510. multiple
  511. onUpdate:value={() => {
  512. const free = 'FREE'
  513. if(forms.useProjectParamConfig.KLX.paymentType[forms.useProjectParamConfig.KLX.paymentType.length - 1] == free) {
  514. forms.useProjectParamConfig.KLX.paymentType = [free]
  515. } else if (forms.useProjectParamConfig.KLX.paymentType.length > 1 && forms.useProjectParamConfig.KLX.paymentType.includes(free)) {
  516. forms.useProjectParamConfig.KLX.paymentType.splice(forms.useProjectParamConfig.KLX.paymentType.indexOf(free), 1)
  517. }
  518. if (!forms.useProjectParamConfig.KLX.paymentType.includes('CHARGE')) {
  519. forms.useProjectParamConfig.KLX.musicPrice = 0
  520. }
  521. }}
  522. ></NSelect>
  523. </NFormItem>
  524. {forms.useProjectParamConfig.KLX.paymentType?.includes('CHARGE') && (
  525. <NFormItem
  526. label="曲目价格"
  527. path="useProjectParamConfig.KLX.musicPrice"
  528. rule={[
  529. {
  530. required: klxFileRequire.value,
  531. message: '请输入曲目价格',
  532. trigger: ['input', 'blur'],
  533. type: 'number'
  534. }
  535. ]}
  536. >
  537. <NInputNumber
  538. style={'width:100%'}
  539. placeholder="请输入曲目价格"
  540. v-model:value={forms.useProjectParamConfig.KLX.musicPrice}
  541. />
  542. </NFormItem>
  543. )
  544. }
  545. <NFormItem
  546. label="是否置顶"
  547. path="useProjectParamConfig.KLX.topFlag"
  548. rule={[
  549. {
  550. required: klxFileRequire.value,
  551. message: '请选择是否置顶',
  552. trigger:'change',
  553. type:'boolean'
  554. }
  555. ]}
  556. >
  557. <NSelect
  558. placeholder="请选择是否置顶"
  559. clearable
  560. v-model:value={forms.useProjectParamConfig.KLX.topFlag}
  561. options={[
  562. {
  563. label: '是',
  564. value: true
  565. },
  566. {
  567. label: '否',
  568. value: false
  569. }
  570. ] as any}
  571. ></NSelect>
  572. </NFormItem>
  573. <NFormItem
  574. label="精品乐谱"
  575. path="useProjectParamConfig.KLX.exquisiteFlag"
  576. rule={[
  577. {
  578. required: klxFileRequire.value,
  579. message: '请选择是否精品乐谱',
  580. trigger:'change',
  581. type:'boolean'
  582. }
  583. ]}
  584. >
  585. <NSelect
  586. placeholder="请选择是否精品乐谱"
  587. clearable
  588. v-model:value={forms.useProjectParamConfig.KLX.exquisiteFlag}
  589. options={[
  590. {
  591. label: '是',
  592. value: true
  593. },
  594. {
  595. label: '否',
  596. value: false
  597. }
  598. ] as any}
  599. ></NSelect>
  600. </NFormItem>
  601. <NFormItem label="排序值" path="useProjectParamConfig.KLX.sortNo">
  602. <NInputNumber
  603. v-model:value={forms.useProjectParamConfig.KLX.sortNo}
  604. placeholder="请输入排序值"
  605. clearable
  606. min={0}
  607. max={9999}
  608. style={{ width: '100%' }}
  609. />
  610. </NFormItem>
  611. </div>
  612. )}
  613. {item === 'KT' && (
  614. <div>
  615. <NFormItem
  616. label="乐谱教材"
  617. path="useProjectParamConfig.KT.musicSheetCategoryId"
  618. rule={[
  619. {
  620. required: ktFileRequire.value,
  621. message: '请选择乐谱教材'
  622. }
  623. ]}
  624. >
  625. <NCascader
  626. valueField="id"
  627. labelField="name"
  628. children-field="children"
  629. placeholder="请选择乐谱教材"
  630. v-model:value={forms.useProjectParamConfig.KT.musicSheetCategoryId}
  631. options={state.musicSheetCategoryOptions.KT}
  632. clearable
  633. />
  634. </NFormItem>
  635. <NFormItem label="排序值" path="useProjectParamConfig.KT.sortNo">
  636. <NInputNumber
  637. v-model:value={forms.useProjectParamConfig.KT.sortNo}
  638. placeholder="请输入排序值"
  639. clearable
  640. min={0}
  641. max={9999}
  642. style={{ width: '100%' }}
  643. />
  644. </NFormItem>
  645. </div>
  646. )}
  647. </NTabPane>
  648. )
  649. })}
  650. </NTabs>
  651. )}
  652. </NForm>
  653. <NSpace justify="end" style={'margin-top: 10px'}>
  654. <NButton type="default" onClick={() => emit('close')}>
  655. 取消
  656. </NButton>
  657. <NButton
  658. type="primary"
  659. onClick={() => onSubmit()}
  660. loading={btnLoading.value}
  661. disabled={btnLoading.value}
  662. >
  663. 确认
  664. </NButton>
  665. </NSpace>
  666. </NSpin>
  667. )
  668. }
  669. })