index.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import {
  2. PropType,
  3. defineComponent,
  4. onMounted,
  5. onUnmounted,
  6. reactive,
  7. watch
  8. } from 'vue';
  9. import ResourceSearchGroup from './resource-search-group';
  10. import { NScrollbar, NSpin, useDialog, useMessage } from 'naive-ui';
  11. import styles from './index.module.less';
  12. import CardType from '/src/components/card-type';
  13. import { favorite, materialQueryPage } from '/src/views/natural-resources/api';
  14. import TheEmpty from '/src/components/TheEmpty';
  15. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  16. import { useDebounceFn, useThrottleFn, useThrottle } from '@vueuse/core';
  17. import { saveCourseware } from '/src/views/prepare-lessons/api';
  18. import CardPreview from '/src/components/card-preview';
  19. import { eventGlobal } from '/src/utils';
  20. import Draggable from 'vuedraggable';
  21. const formatType = (type: string) => {
  22. if (type === 'shareResources') {
  23. return 2;
  24. } else if (type === 'myResources') {
  25. return 3;
  26. } else if (type === 'myCollect') {
  27. return 4;
  28. } else if (type === 'relateResources') {
  29. return 5;
  30. }
  31. };
  32. export default defineComponent({
  33. name: 'share-resources',
  34. props: {
  35. type: {
  36. type: String as PropType<
  37. 'shareResources' | 'myResources' | 'myCollect' | 'relateResources'
  38. >,
  39. default: 'relateResources'
  40. }
  41. },
  42. setup(props, { expose }) {
  43. const prepareStore = usePrepareStore();
  44. const message = useMessage();
  45. const dialog = useDialog();
  46. const state = reactive({
  47. loading: false,
  48. finshed: false, // 是否加载完
  49. pagination: {
  50. page: 1,
  51. rows: 20
  52. },
  53. searchGroup: {
  54. type: 'MUSIC', //
  55. name: '',
  56. bookVersionId: null,
  57. musicalInstrumentId: null,
  58. subjectId: null,
  59. audioPlayTypes: [], // 场景
  60. sourceType: formatType(props.type),
  61. enableFlag: true
  62. },
  63. tableList: [] as any,
  64. show: false,
  65. item: {} as any
  66. });
  67. const getList = async () => {
  68. try {
  69. // if (!prepareStore.getSubjectId) return;
  70. if (state.pagination.page === 1) {
  71. state.loading = true;
  72. }
  73. const { data } = await materialQueryPage({
  74. ...state.searchGroup,
  75. ...state.pagination,
  76. lessonCoursewareKnowledgeId:
  77. props.type === 'relateResources' || props.type === 'shareResources'
  78. ? prepareStore.getSelectKey
  79. : null,
  80. relateLessonCoursewareKnowledgeMaterialIds: getIds()
  81. // subjectId: prepareStore.getSubjectId
  82. });
  83. state.loading = false;
  84. const tempRows = data.rows || [];
  85. const temp: any = [];
  86. tempRows.forEach((row: any) => {
  87. // const index = prepareStore.getCoursewareList.findIndex(
  88. // (course: any) => course.materialId === row.id
  89. // );
  90. temp.push({
  91. id: row.id,
  92. coverImg: row.coverImg,
  93. type: row.type,
  94. title: row.name,
  95. isCollect: !!row.favoriteFlag,
  96. refFlag: row.refFlag,
  97. isSelected: row.sourceFrom === 'PLATFORM' ? true : false,
  98. containAccompaniment: row.containAccompaniment,
  99. content: row.content,
  100. instrumentIds: row.instrumentIds,
  101. hasNotCheck: row.hasNotCheck,
  102. sourceForm: 'resource-item',
  103. audioPlayTypeArray: row.audioPlayTypes
  104. ? row.audioPlayTypes.split(',')
  105. : []
  106. // exist: index !== -1 ? true : false // 是否存在
  107. });
  108. });
  109. if (state.pagination.page === 1) {
  110. state.tableList = temp;
  111. } else {
  112. state.tableList.push(...temp);
  113. }
  114. state.finshed = data.pages <= data.current ? true : false;
  115. } catch {
  116. state.loading = false;
  117. }
  118. };
  119. const onSearch = async (item: any) => {
  120. state.pagination.page = 1;
  121. state.tableList = [];
  122. state.searchGroup = Object.assign(state.searchGroup, item);
  123. getList();
  124. };
  125. const throttledFnSearch = useDebounceFn(item => {
  126. state.pagination.page = state.pagination.page + 1;
  127. state.pagination.page = 1;
  128. state.tableList = [];
  129. state.searchGroup = Object.assign(state.searchGroup, item);
  130. getList();
  131. }, 300);
  132. // 声部变化时
  133. watch(
  134. () => prepareStore.getInstrumentId,
  135. () => {
  136. onSearch(state.searchGroup);
  137. }
  138. );
  139. const throttledFn = useThrottleFn(() => {
  140. state.pagination.page = state.pagination.page + 1;
  141. getList();
  142. }, 500);
  143. // 添加资源
  144. const onAdd = async (item: any) => {
  145. try {
  146. eventGlobal.emit('onPrepareAddItem', {
  147. materialId: item.id,
  148. coverImg: item.coverImg,
  149. refFlag: item.refFlag,
  150. type: item.type,
  151. title: item.title,
  152. isCollect: item.isCollect,
  153. isSelected: item.isSelected,
  154. audioPlayTypeArray: item.audioPlayTypeArray,
  155. instrumentIds: item.instrumentIds,
  156. hasNotCheck: item.hasNotCheck,
  157. content: item.content,
  158. removeFlag: false
  159. });
  160. } catch {
  161. //
  162. }
  163. };
  164. // 收藏
  165. const onCollect = async (item: any) => {
  166. try {
  167. await favorite({
  168. materialId: item.id,
  169. favoriteFlag: item.isCollect ? 0 : 1,
  170. type: item.type
  171. });
  172. item.isCollect = !item.isCollect;
  173. } catch {
  174. //
  175. }
  176. };
  177. const getIds = () => {
  178. let noRepeatIds: any = [];
  179. if (props.type === 'relateResources') {
  180. const materialIds: any = [];
  181. prepareStore.getCoursewareList.forEach((course: any) => {
  182. course.list?.forEach((item: any) => {
  183. materialIds.push(item.materialId);
  184. });
  185. });
  186. noRepeatIds = Array(...new Set(materialIds));
  187. }
  188. return noRepeatIds.join(',');
  189. };
  190. const onUpdate = () => {
  191. state.pagination.page = 1;
  192. state.tableList = [];
  193. getList();
  194. };
  195. onMounted(() => {
  196. // 加载的时候判断是否有资源数据
  197. onUpdate();
  198. if (props.type === 'relateResources') {
  199. eventGlobal.on('onCoursewareUpdate', onUpdate);
  200. }
  201. });
  202. onUnmounted(() => {
  203. eventGlobal.off('onCoursewareUpdate', onUpdate);
  204. });
  205. const getParams = () => {
  206. return state.searchGroup;
  207. };
  208. expose({
  209. getParams
  210. });
  211. return () => (
  212. <div>
  213. <ResourceSearchGroup
  214. type={props.type}
  215. onSearch={(item: any) => {
  216. state.searchGroup = Object.assign(state.searchGroup, item);
  217. throttledFnSearch(item);
  218. }}
  219. />
  220. <NScrollbar
  221. class={[
  222. styles.listContainer,
  223. 'listContainerResource',
  224. state.searchGroup.type !== 'MUSIC' ||
  225. ['myResources', 'myCollect', 'relateResources'].includes(props.type)
  226. ? [styles.listNoMusic, 'listNoMusicResource']
  227. : ''
  228. ]}
  229. onScroll={(e: any) => {
  230. const clientHeight = e.target?.clientHeight;
  231. const scrollTop = e.target?.scrollTop;
  232. const scrollHeight = e.target?.scrollHeight;
  233. // 是否到底,是否加载完
  234. if (
  235. clientHeight + scrollTop + 20 >= scrollHeight &&
  236. !state.finshed &&
  237. !state.loading
  238. ) {
  239. throttledFn();
  240. }
  241. }}>
  242. <NSpin show={state.loading} size={'small'}>
  243. <div
  244. class={[
  245. styles.listSection,
  246. 'listSectionResource',
  247. !state.loading && state.tableList.length <= 0
  248. ? [styles.emptySection, 'emptySectionResource']
  249. : ''
  250. ]}>
  251. {state.tableList.length > 0 && (
  252. <Draggable
  253. v-model:modelValue={state.tableList}
  254. itemKey="id"
  255. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  256. // @ts-ignore
  257. // group="description"
  258. group={{ name: 'description', pull: 'clone', put: false }}
  259. animation={200}
  260. sort={false}
  261. onMove={(evt: any) => {
  262. // console.log(evt, 'evt', evt.from !== evt.to);
  263. return evt.from !== evt.to;
  264. }}
  265. componentData={{
  266. draggable: 'row-nav',
  267. itemKey: 'id',
  268. tag: 'div',
  269. pull: 'clone',
  270. put: false,
  271. animation: 200,
  272. group: 'description'
  273. }}
  274. class={styles.list}>
  275. {{
  276. item: (element: any) => {
  277. const item = element.element;
  278. return (
  279. <div
  280. data-id={item.id}
  281. class={['itemWrap', 'itemBlock', 'row-nav']}>
  282. <div class={'itemWrapBox'}>
  283. <CardType
  284. isShowAdd
  285. item={item}
  286. isShowCollect={true}
  287. draggable={false}
  288. disabledMouseHover={false}
  289. onClick={() => {
  290. if (item.type === 'IMG') return;
  291. state.show = true;
  292. state.item = {
  293. instrumentId:
  294. state.searchGroup.musicalInstrumentId ||
  295. null,
  296. ...item
  297. };
  298. }}
  299. onCollect={(item: any) => onCollect(item)}
  300. // isShowAddDisabled={!prepareStore.getIsEditResource}
  301. onAdd={(item: any) => onAdd(item)}
  302. />
  303. </div>
  304. </div>
  305. // <div
  306. // data-id={item.id}
  307. // class={[
  308. // styles.itemWrap,
  309. // styles.itemBlock,
  310. // 'row-nav'
  311. // ]}>
  312. // <div class={styles.itemWrapBox}>
  313. // <CardType
  314. // class={[styles.itemContent]}
  315. // isShowCollect={false}
  316. // offShelf={item.removeFlag ? true : false}
  317. // // onOffShelf={() => onRemove(item)}
  318. // item={item}
  319. // disabledMouseHover={false}
  320. // onClick={() => {
  321. // if (item.type === 'IMG') return;
  322. // forms.show = true;
  323. // forms.item = item;
  324. // }}
  325. // />
  326. // <div class={styles.itemOperation}>
  327. // <img
  328. // src={iconDelete}
  329. // class={styles.iconDelete}
  330. // onClick={(e: MouseEvent) => {
  331. // e.stopPropagation();
  332. // onDelete(element.index, index);
  333. // }}
  334. // />
  335. // </div>
  336. // </div>
  337. // </div>
  338. );
  339. }
  340. }}
  341. </Draggable>
  342. // <div class={styles.list}>
  343. // {state.tableList.map((item: any) => (
  344. // <CardType
  345. // isShowAdd
  346. // item={item}
  347. // isShowCollect={true}
  348. // draggable
  349. // disabledMouseHover={false}
  350. // onClick={() => {
  351. // if (item.type === 'IMG') return;
  352. // state.show = true;
  353. // state.item = item;
  354. // }}
  355. // onCollect={(item: any) => onCollect(item)}
  356. // // isShowAddDisabled={!prepareStore.getIsEditResource}
  357. // onAdd={(item: any) => onAdd(item)}
  358. // />
  359. // ))}
  360. // </div>
  361. )}
  362. {!state.loading && state.tableList.length <= 0 && <TheEmpty />}
  363. </div>
  364. </NSpin>
  365. </NScrollbar>
  366. {/* 弹窗查看 */}
  367. <CardPreview
  368. v-model:show={state.show}
  369. item={state.item}
  370. isDownload={false}
  371. />
  372. </div>
  373. );
  374. }
  375. });