use-project.tsx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. }
  357. ]}
  358. >
  359. <NCascader
  360. valueField="id"
  361. labelField="name"
  362. children-field="children"
  363. placeholder="请选择分类"
  364. v-model:value={forms.useProjectParamConfig.GYM.musicSheetCategoryId}
  365. options={state.musicSheetCategoryOptions.GYM}
  366. onChange={() => {}}
  367. clearable
  368. />
  369. </NFormItem>
  370. <NFormItem
  371. label="是否收费"
  372. path="useProjectParamConfig.GYM.paymentType"
  373. rule={[
  374. {
  375. required: gymFileRequire.value,
  376. message: '请选择收费类型'
  377. }
  378. ]}
  379. >
  380. <NSelect
  381. placeholder="请选择收费类型"
  382. clearable
  383. v-model:value={forms.useProjectParamConfig.GYM.paymentType}
  384. options={getSelectDataFromObj(musicSheetPaymentType)}
  385. ></NSelect>
  386. </NFormItem>
  387. <NFormItem label="排序值" path="useProjectParamConfig.GYM.sortNo">
  388. <NInputNumber
  389. v-model:value={forms.useProjectParamConfig.GYM.sortNo}
  390. placeholder="请输入排序值"
  391. clearable
  392. min={0}
  393. max={9999}
  394. style={{ width: '100%' }}
  395. />
  396. </NFormItem>
  397. </div>
  398. )}
  399. {item === 'GYT' && (
  400. <div>
  401. <NFormItem
  402. label="分类"
  403. path="useProjectParamConfig.GYT.musicSheetCategoryId"
  404. rule={[
  405. {
  406. required: gytFileRequire.value,
  407. message: '请选择分类'
  408. }
  409. ]}
  410. >
  411. <NCascader
  412. valueField="id"
  413. labelField="name"
  414. children-field="children"
  415. placeholder="请选择分类"
  416. v-model:value={forms.useProjectParamConfig.GYT.musicSheetCategoryId}
  417. options={state.musicSheetCategoryOptions.GYT}
  418. clearable
  419. />
  420. </NFormItem>
  421. <NFormItem label="排序值" path="useProjectParamConfig.GYT.sortNo">
  422. <NInputNumber
  423. v-model:value={forms.useProjectParamConfig.GYT.sortNo}
  424. placeholder="请输入排序值"
  425. clearable
  426. min={0}
  427. max={9999}
  428. style={{ width: '100%' }}
  429. />
  430. </NFormItem>
  431. </div>
  432. )}
  433. {item === 'KLX' && (
  434. <div>
  435. <NFormItem
  436. label="可用途径"
  437. path="useProjectParamConfig.KLX.availableType"
  438. rule={[
  439. {
  440. required: klxFileRequire.value,
  441. message: '请选择可用途径'
  442. }
  443. ]}
  444. >
  445. <NSelect
  446. placeholder="请选择可用途径"
  447. clearable
  448. v-model:value={forms.useProjectParamConfig.KLX.availableType}
  449. options={getSelectDataFromObj(musicSheetAvailableType)}
  450. ></NSelect>
  451. </NFormItem>
  452. <NFormItem
  453. label="曲目标签"
  454. path="useProjectParamConfig.KLX.musicSheetCategoryId"
  455. rule={[
  456. {
  457. required: klxFileRequire.value,
  458. message: '请选择曲目标签'
  459. }
  460. ]}
  461. >
  462. <NSelect
  463. placeholder="请选择曲目标签"
  464. clearable
  465. v-model:value={forms.useProjectParamConfig.KLX.musicSheetCategoryId}
  466. options={[]}
  467. ></NSelect>
  468. </NFormItem>
  469. <NFormItem
  470. label="是否收费"
  471. path="useProjectParamConfig.KLX.paymentType"
  472. rule={[
  473. {
  474. required: klxFileRequire.value,
  475. message: '请选择是否收费'
  476. }
  477. ]}
  478. >
  479. <NSelect
  480. placeholder="请选择是否收费"
  481. clearable
  482. v-model:value={forms.useProjectParamConfig.KLX.paymentType}
  483. options={[
  484. {
  485. label: '是',
  486. value: 1
  487. },
  488. {
  489. label: '否',
  490. value: 0
  491. }
  492. ]}
  493. ></NSelect>
  494. </NFormItem>
  495. <NFormItem
  496. label="曲目价格"
  497. path="useProjectParamConfig.KLX.musicPrice"
  498. rule={[
  499. {
  500. required: klxFileRequire.value,
  501. message: '请输入曲目价格'
  502. }
  503. ]}
  504. >
  505. <NInputNumber
  506. style={'width:100%'}
  507. placeholder="请输入曲目价格"
  508. v-model:value={forms.useProjectParamConfig.KLX.musicPrice}
  509. />
  510. </NFormItem>
  511. <NFormItem
  512. label="是否置顶"
  513. path="useProjectParamConfig.KLX.topFlag"
  514. rule={[
  515. {
  516. required: klxFileRequire.value,
  517. message: '请选择是否置顶'
  518. }
  519. ]}
  520. >
  521. <NSelect
  522. placeholder="请选择是否置顶"
  523. clearable
  524. v-model:value={forms.useProjectParamConfig.KLX.topFlag}
  525. options={[
  526. {
  527. label: '是',
  528. value: 1
  529. },
  530. {
  531. label: '否',
  532. value: 0
  533. }
  534. ]}
  535. ></NSelect>
  536. </NFormItem>
  537. <NFormItem
  538. label="精品乐谱"
  539. path="useProjectParamConfig.KLX.exquisiteFlag"
  540. rule={[
  541. {
  542. required: klxFileRequire.value,
  543. message: '请选择是否精品乐谱'
  544. }
  545. ]}
  546. >
  547. <NSelect
  548. placeholder="请选择是否精品乐谱"
  549. clearable
  550. v-model:value={forms.useProjectParamConfig.KLX.exquisiteFlag}
  551. options={[
  552. {
  553. label: '是',
  554. value: 1
  555. },
  556. {
  557. label: '否',
  558. value: 0
  559. }
  560. ]}
  561. ></NSelect>
  562. </NFormItem>
  563. <NFormItem label="排序值" path="useProjectParamConfig.KLX.sortNo">
  564. <NInputNumber
  565. v-model:value={forms.useProjectParamConfig.KLX.sortNo}
  566. placeholder="请输入排序值"
  567. clearable
  568. min={0}
  569. max={9999}
  570. style={{ width: '100%' }}
  571. />
  572. </NFormItem>
  573. </div>
  574. )}
  575. {item === 'KT' && (
  576. <div>
  577. <NFormItem
  578. label="乐谱教材"
  579. path="useProjectParamConfig.KT.musicSheetCategoryId"
  580. rule={[
  581. {
  582. required: ktFileRequire.value,
  583. message: '请选择乐谱教材'
  584. }
  585. ]}
  586. >
  587. <NCascader
  588. valueField="id"
  589. labelField="name"
  590. children-field="children"
  591. placeholder="请选择乐谱教材"
  592. v-model:value={forms.useProjectParamConfig.KT.musicSheetCategoryId}
  593. options={state.musicSheetCategoryOptions.KT}
  594. clearable
  595. />
  596. </NFormItem>
  597. <NFormItem label="排序值" path="useProjectParamConfig.KT.sortNo">
  598. <NInputNumber
  599. v-model:value={forms.useProjectParamConfig.KT.sortNo}
  600. placeholder="请输入排序值"
  601. clearable
  602. min={0}
  603. max={9999}
  604. style={{ width: '100%' }}
  605. />
  606. </NFormItem>
  607. </div>
  608. )}
  609. </NTabPane>
  610. )
  611. })}
  612. </NTabs>
  613. )}
  614. </NForm>
  615. <NSpace justify="end" style={'margin-top: 10px'}>
  616. <NButton type="default" onClick={() => emit('close')}>
  617. 取消
  618. </NButton>
  619. <NButton
  620. type="primary"
  621. onClick={() => onSubmit()}
  622. loading={btnLoading.value}
  623. disabled={btnLoading.value}
  624. >
  625. 确认
  626. </NButton>
  627. </NSpace>
  628. </div>
  629. )
  630. }
  631. })