index.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import { NScrollbar, NSpin, NTabPane, NTabs } from 'naive-ui';
  2. import { PropType, defineComponent, onMounted, reactive, watch } from 'vue';
  3. import styles from './index.module.less';
  4. import CardType from '@/components/card-type';
  5. import SearchGroup from './search-group';
  6. import TheEmpty from '/src/components/TheEmpty';
  7. import { useDebounceFn, useThrottleFn, useResizeObserver } from '@vueuse/core';
  8. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  9. import { musicSheetPage } from '../../../api';
  10. import CardPreview from '/src/components/card-preview';
  11. import { favorite, materialQueryPage } from '/src/views/natural-resources/api';
  12. const formatType = (type: string) => {
  13. if (type === 'shareResources') {
  14. return 2;
  15. } else if (type === 'myResources') {
  16. return 3;
  17. } else if (type === 'myCollect') {
  18. return 4;
  19. }
  20. };
  21. export default defineComponent({
  22. name: 'select-music',
  23. props: {
  24. /** 类型 */
  25. cardType: {
  26. type: String as PropType<'' | 'homerowk-record' | 'prepare'>,
  27. default: ''
  28. },
  29. type: {
  30. type: String,
  31. default: ''
  32. },
  33. from: {
  34. type: String,
  35. default: ''
  36. }
  37. },
  38. emits: ['add'],
  39. setup(props, { emit }) {
  40. const prepareStore = usePrepareStore();
  41. const state = reactive({
  42. searchHeight: '0px',
  43. loading: false,
  44. finshed: false, // 是否加载完
  45. pagination: {
  46. page: 1,
  47. rows: 20
  48. },
  49. searchGroup: {
  50. name: '',
  51. type: 'MUSIC', //
  52. musicSheetCategoriesId: '',
  53. musicalInstrumentId: '',
  54. audioPlayTypes:
  55. props.cardType === 'homerowk-record' || props.cardType === 'prepare'
  56. ? ['PLAY']
  57. : [],
  58. sourceType: formatType(props.type),
  59. status: 1,
  60. versionFlag: false,
  61. subjectId: null
  62. },
  63. tableList: [] as any,
  64. show: false,
  65. item: {} as any,
  66. isShowAddDisabled: !prepareStore.getIsEditTrain
  67. });
  68. const className = 'musicSearchGroup' + +new Date();
  69. const getList = async () => {
  70. try {
  71. if (state.pagination.page === 1) {
  72. state.loading = true;
  73. }
  74. const { data } = await materialQueryPage({
  75. ...state.searchGroup,
  76. ...state.pagination
  77. });
  78. state.loading = false;
  79. if (data.current === 1 && state.tableList.length > 0) return;
  80. const tempRows = data.rows || [];
  81. const temp: any = [];
  82. tempRows.forEach((row: any) => {
  83. // const index = prepareStore.getTrainList.findIndex(
  84. // (course: any) => course.musicId === row.id
  85. // );
  86. temp.push({
  87. id: row.id,
  88. coverImg: row.coverImg || row.musicSvg,
  89. type: 'MUSIC',
  90. title: row.name,
  91. isCollect: !!row.favoriteFlag,
  92. isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
  93. refFlag: row.refFlag,
  94. content: row.id,
  95. xmlFileUrl: row.xmlFileUrl,
  96. audioPlayTypeArray: row.audioPlayTypes
  97. ? row.audioPlayTypes.split(',')
  98. : [],
  99. containAccompaniment: row.containAccompaniment
  100. // exist: index !== -1 ? true : false // 是否存在
  101. });
  102. });
  103. state.tableList.push(...temp);
  104. state.finshed = data.pages <= data.current ? true : false;
  105. } catch {
  106. state.loading = false;
  107. }
  108. };
  109. // watch(
  110. // () => prepareStore.trainList,
  111. // () => {
  112. // state.tableList.forEach((item: any) => {
  113. // const index = prepareStore.getTrainList.findIndex(
  114. // (course: any) => course.musicId === item.id
  115. // );
  116. // item.exist = index !== -1 ? true : false; // 是否存在
  117. // });
  118. // },
  119. // {
  120. // deep: true,
  121. // immediate: true
  122. // }
  123. // );
  124. const onSearch = (item: any) => {
  125. state.pagination.page = 1;
  126. state.tableList = [];
  127. state.searchGroup = Object.assign(state.searchGroup, item);
  128. getList();
  129. };
  130. const throttledFnSearch = useDebounceFn(item => {
  131. onSearch(item);
  132. }, 300);
  133. const throttledFn = useThrottleFn(() => {
  134. state.pagination.page = state.pagination.page + 1;
  135. getList();
  136. }, 300);
  137. // 收藏
  138. const onCollect = async (item: any) => {
  139. try {
  140. await favorite({
  141. materialId: item.id,
  142. favoriteFlag: item.isCollect ? 0 : 1,
  143. type: item.type
  144. });
  145. item.isCollect = !item.isCollect;
  146. } catch {
  147. //
  148. }
  149. };
  150. onMounted(() => {
  151. useResizeObserver(
  152. document.querySelector('.' + className) as HTMLElement,
  153. (entries: any) => {
  154. const entry = entries[0];
  155. const { height } = entry.contentRect;
  156. state.searchHeight = height + 'px';
  157. }
  158. );
  159. if (props.type === 'homework') {
  160. state.isShowAddDisabled = false;
  161. }
  162. // getList();
  163. });
  164. return () => (
  165. <div class={styles.selectMusic}>
  166. <NScrollbar
  167. class={styles.listContainer}
  168. style={{
  169. 'max-height': `calc(85vh - var(--modal-lesson-tab-height) - 12px) `
  170. }}
  171. onScroll={(e: any) => {
  172. const clientHeight = e.target?.clientHeight;
  173. const scrollTop = e.target?.scrollTop;
  174. const scrollHeight = e.target?.scrollHeight;
  175. // 是否到底,是否加载完
  176. if (
  177. clientHeight + scrollTop + 20 >= scrollHeight &&
  178. !state.finshed &&
  179. !state.loading
  180. ) {
  181. throttledFn();
  182. }
  183. }}>
  184. <div class={className}>
  185. <SearchGroup
  186. type={props.type}
  187. onSearch={(item: any, type: any) => {
  188. if (type) {
  189. onSearch(item);
  190. } else {
  191. throttledFnSearch(item);
  192. }
  193. }}
  194. />
  195. </div>
  196. <NSpin show={state.loading} size={'small'}>
  197. <div
  198. style={{
  199. 'min-height': `calc(85vh - var(--modal-lesson-tab-height) - ${state.searchHeight} - 12px)`
  200. }}
  201. class={[
  202. styles.listSection,
  203. !state.loading && state.tableList.length <= 0
  204. ? styles.emptySection
  205. : ''
  206. ]}>
  207. {state.tableList.length > 0 && (
  208. <div class={styles.list}>
  209. {state.tableList.map((item: any) => (
  210. <CardType
  211. isShowAdd
  212. isShowCollect
  213. item={item}
  214. // isShowAddDisabled={state.isShowAddDisabled}
  215. onAdd={() => emit('add', item)}
  216. disabledMouseHover={false}
  217. onClick={() => {
  218. if (item.type === 'IMG') return;
  219. state.show = true;
  220. state.item = {
  221. instrumentId:
  222. state.searchGroup.musicalInstrumentId || null,
  223. ...item
  224. };
  225. }}
  226. onCollect={(item: any) => onCollect(item)}
  227. />
  228. ))}
  229. </div>
  230. )}
  231. {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
  232. </div>
  233. </NSpin>
  234. </NScrollbar>
  235. {/* 弹窗查看 */}
  236. <CardPreview
  237. from={props.from}
  238. v-model:show={state.show}
  239. item={state.item}
  240. isDownload={false}
  241. />
  242. </div>
  243. );
  244. }
  245. });