index.tsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. import { defineComponent, onMounted, reactive, ref, watch } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. NButton,
  5. NTooltip,
  6. NCarousel,
  7. NIcon,
  8. NImage,
  9. NInput,
  10. NModal,
  11. NScrollbar,
  12. NSelect,
  13. NSpace,
  14. NSpin,
  15. NTabPane,
  16. NTabs,
  17. useMessage
  18. } from 'naive-ui';
  19. import { usePrepareStore } from '/src/store/modules/prepareLessons';
  20. import add from '@/views/studentList/images/add.png';
  21. import iconSlideRight from '../../../images/icon-slide-right.png';
  22. import CoursewareType from '../../../model/courseware-type';
  23. import TheEmpty from '/src/components/TheEmpty';
  24. import RelatedClass from '../../../model/related-class';
  25. import { state } from '/src/state';
  26. import { useResizeObserver } from '@vueuse/core';
  27. import AttendClass from '/src/views/prepare-lessons/model/attend-class';
  28. import {
  29. api_addByOpenCourseware,
  30. api_teacherChapterLessonCoursewareRemove,
  31. api_queryOpenCoursewareByPage,
  32. api_updateCoursewareInfo,
  33. teacherChapterLessonCoursewareList,
  34. courseScheduleStart
  35. } from '../../../api';
  36. import { useRoute, useRouter } from 'vue-router';
  37. import TheMessageDialog from '/src/components/TheMessageDialog';
  38. import { eventGlobal, fscreen } from '/src/utils';
  39. import PreviewWindow from '/src/views/preview-window';
  40. import Related from './related';
  41. export default defineComponent({
  42. name: 'courseware-presets',
  43. emits: ['change'],
  44. setup(props, { emit }) {
  45. const prepareStore = usePrepareStore();
  46. const message = useMessage();
  47. const route = useRoute();
  48. const router = useRouter();
  49. const localStorageSubjectId = localStorage.getItem(
  50. 'prepareLessonSubjectId'
  51. );
  52. const forms = reactive({
  53. // 选取参数带的,后取缓存
  54. leftWidth: '100%',
  55. rightWidth: '0',
  56. messageLoading: false,
  57. subjectId: route.query.subjectId
  58. ? Number(route.query.subjectId)
  59. : localStorageSubjectId
  60. ? Number(localStorageSubjectId)
  61. : '',
  62. courseScheduleSubjectId: route.query.courseScheduleSubjectId,
  63. classGroupId: route.query.classGroupId,
  64. preStudentNum: route.query.preStudentNum,
  65. bodyWidth: '100%',
  66. loading: false,
  67. openLoading: false,
  68. showRelatedClass: false,
  69. tableList: [] as any,
  70. openTableShow: true, // 是否显示
  71. openTableList: [] as any,
  72. selectItem: {} as any,
  73. editTitleVisiable: false,
  74. editTitle: null,
  75. editBtnLoading: false,
  76. preRemoveVisiable: false,
  77. carouselIndex: 0,
  78. showAttendClass: false,
  79. attendClassType: 'change', //
  80. attendClassItem: {} as any,
  81. previewModal: false,
  82. previewParams: {
  83. type: '',
  84. courseId: '',
  85. subjectId: '',
  86. detailId: ''
  87. } as any
  88. });
  89. const getCoursewareList = async () => {
  90. forms.loading = true;
  91. try {
  92. // 判断是否有选择对应的课件 或声部
  93. if (!prepareStore.getSelectKey) return (forms.loading = false);
  94. const { data } = await teacherChapterLessonCoursewareList({
  95. subjectId: prepareStore.getSubjectId,
  96. coursewareDetailKnowledgeId: prepareStore.getSelectKey
  97. });
  98. if (!Array.isArray(data)) {
  99. return;
  100. }
  101. const tempList: any = [];
  102. data.forEach((item: any) => {
  103. const firstItem: any =
  104. item.chapterKnowledgeList[0]?.chapterKnowledgeMaterialList[0];
  105. tempList.push({
  106. id: item.id,
  107. openFlag: item.openFlag,
  108. openFlagEnable: item.openFlagEnable,
  109. subjectNames: item.subjectNames,
  110. fromChapterLessonCoursewareId: item.fromChapterLessonCoursewareId,
  111. name: item.name,
  112. coverImg: firstItem?.bizInfo.coverImg,
  113. type: firstItem?.bizInfo.type
  114. });
  115. });
  116. forms.tableList = tempList;
  117. } catch {
  118. //
  119. }
  120. forms.loading = false;
  121. };
  122. const getOpenCoursewareList = async () => {
  123. // 查询公开课件列表
  124. forms.openLoading = true;
  125. try {
  126. // 判断是否有选择对应的课件 或声部
  127. if (!prepareStore.getSelectKey) return (forms.openLoading = false);
  128. const { data } = await api_queryOpenCoursewareByPage({
  129. subjectId: prepareStore.getSubjectId,
  130. coursewareDetailKnowledgeId: prepareStore.getSelectKey,
  131. page: 1,
  132. rows: 20
  133. });
  134. const result = data.rows || [];
  135. const tempList: any = [];
  136. result.forEach((item: any) => {
  137. // const index = forms.tableList.findIndex(
  138. // (i: any) => i.fromChapterLessonCoursewareId === item.id
  139. // );
  140. const firstItem: any =
  141. item.chapterKnowledgeList[0]?.chapterKnowledgeMaterialList[0];
  142. tempList.push({
  143. id: item.id,
  144. openFlag: item.openFlag,
  145. openFlagEnable: item.openFlagEnable,
  146. subjectNames: item.subjectNames,
  147. fromChapterLessonCoursewareId: item.fromChapterLessonCoursewareId,
  148. name: item.name,
  149. coverImg: firstItem?.bizInfo.coverImg,
  150. type: firstItem?.bizInfo.type,
  151. isAdd: item.addFlag
  152. });
  153. });
  154. forms.openTableList = tempList || [];
  155. } catch {
  156. //
  157. }
  158. forms.openLoading = false;
  159. };
  160. // const chunkArray = (array: any, size: number) => {
  161. // const result = [];
  162. // for (let i = 0; i < array.length; i += size) {
  163. // result.push(array.slice(i, i + size));
  164. // }
  165. // return result;
  166. // };
  167. // 监听选择的key 左侧选择了其它的课
  168. watch(
  169. () => [prepareStore.getSelectKey, prepareStore.getSubjectId],
  170. async () => {
  171. await getCoursewareList();
  172. // await getOpenCoursewareList();
  173. eventGlobal.emit('openCoursewareChanged');
  174. subjectRef.value?.syncBarPosition();
  175. }
  176. );
  177. watch(
  178. () => prepareStore.getSubjectList,
  179. () => {
  180. checkSubjectIds();
  181. }
  182. );
  183. const checkSubjectIds = () => {
  184. const subjectList = prepareStore.getSubjectList;
  185. // 并且没有声部时才会更新
  186. if (subjectList.length > 0) {
  187. const prepareLessonCourseWareSubjectIsNull = sessionStorage.getItem(
  188. 'prepareLessonCourseWareSubjectIsNull'
  189. );
  190. if (prepareLessonCourseWareSubjectIsNull === 'true') {
  191. prepareStore.setSubjectId('');
  192. return;
  193. }
  194. // 并且声部在列表中
  195. const localStorageSubjectId = localStorage.getItem(
  196. 'prepareLessonSubjectId'
  197. );
  198. // // 先取 上次上课声部,在取班级声部 最后取缓存
  199. let subjectId = null;
  200. let index = -1;
  201. if (forms.courseScheduleSubjectId) {
  202. // 判断浏览器上面是否有
  203. index = subjectList.findIndex(
  204. (subject: any) => subject.id == forms.courseScheduleSubjectId
  205. );
  206. if (index >= 0) {
  207. subjectId = Number(forms.courseScheduleSubjectId);
  208. }
  209. }
  210. // 判断班级上面声部 & 还没有声部
  211. if (forms.subjectId && !subjectId) {
  212. // 判断浏览器上面是否有
  213. index = subjectList.findIndex(
  214. (subject: any) => subject.id == forms.subjectId
  215. );
  216. if (index >= 0) {
  217. subjectId = Number(forms.subjectId);
  218. }
  219. }
  220. // 缓存声部 & 还没有声部
  221. if (localStorageSubjectId && !subjectId) {
  222. // 判断浏览器上面是否有
  223. index = subjectList.findIndex(
  224. (subject: any) => subject.id == localStorageSubjectId
  225. );
  226. if (index >= 0) {
  227. subjectId = Number(localStorageSubjectId);
  228. }
  229. }
  230. // 判断是否选择为空
  231. if (subjectId && index >= 0) {
  232. prepareStore.setSubjectId(subjectId);
  233. // forms.subjectId = subjectId;
  234. } else {
  235. // 判断是否有缓存
  236. // prepareStore.setSubjectId(subjectList[0].id);
  237. // forms.subjectId = subjectList[0].id;
  238. }
  239. // 保存
  240. localStorage.setItem(
  241. 'prepareLessonSubjectId',
  242. prepareStore.getSubjectId as any
  243. );
  244. subjectRef.value?.syncBarPosition();
  245. }
  246. };
  247. const subjectRef = ref();
  248. onMounted(async () => {
  249. useResizeObserver(
  250. document.querySelector('#presetsLeftRef') as HTMLElement,
  251. (entries: any) => {
  252. const entry = entries[0];
  253. const { width } = entry.contentRect;
  254. forms.leftWidth = width + 'px';
  255. }
  256. );
  257. useResizeObserver(
  258. document.querySelector('#presetsRightRef') as HTMLElement,
  259. (entries: any) => {
  260. const entry = entries[0];
  261. const { width } = entry.contentRect;
  262. forms.rightWidth = width + 'px';
  263. }
  264. );
  265. prepareStore.setClassGroupId(route.query.classGroupId as any);
  266. if (!prepareStore.getSubjectId) {
  267. // 获取教材分类列表
  268. checkSubjectIds();
  269. }
  270. // useResizeObserver(
  271. // document.querySelector('#coursewarePresets') as HTMLElement,
  272. // (entries: any) => {
  273. // const entry = entries[0];
  274. // const { width } = entry.contentRect;
  275. // forms.bodyWidth = width + 'px';
  276. // }
  277. // );
  278. await getCoursewareList();
  279. // await getOpenCoursewareList();
  280. });
  281. // 重命名
  282. const onEditTitleSubmit = async () => {
  283. try {
  284. await api_updateCoursewareInfo({
  285. id: forms.selectItem.id,
  286. name: forms.editTitle
  287. });
  288. message.success('修改成功');
  289. getCoursewareList();
  290. // getOpenCoursewareList()
  291. forms.editTitleVisiable = false;
  292. } catch {
  293. //
  294. }
  295. };
  296. // 删除
  297. const onRemove = async () => {
  298. forms.messageLoading = true;
  299. try {
  300. await api_teacherChapterLessonCoursewareRemove({
  301. id: forms.selectItem.id
  302. });
  303. message.success('删除成功');
  304. getCoursewareList();
  305. // getOpenCoursewareList();
  306. eventGlobal.emit('openCoursewareChanged');
  307. forms.preRemoveVisiable = false;
  308. } catch {
  309. //
  310. }
  311. setTimeout(() => {
  312. forms.messageLoading = false;
  313. }, 100);
  314. };
  315. // 添加课件
  316. const onAddCourseware = async (item: any) => {
  317. if (forms.messageLoading) return;
  318. forms.messageLoading = true;
  319. try {
  320. await api_addByOpenCourseware({ id: item.id });
  321. message.success('添加成功');
  322. getCoursewareList();
  323. // getOpenCoursewareList();
  324. eventGlobal.emit('openCoursewareChanged');
  325. } catch {
  326. //
  327. }
  328. setTimeout(() => {
  329. forms.messageLoading = false;
  330. }, 100);
  331. };
  332. // 预览上课
  333. const onPreviewAttend = (id: string) => {
  334. // 判断是否在应用里面
  335. if (window.matchMedia('(display-mode: standalone)').matches) {
  336. state.application = window.matchMedia(
  337. '(display-mode: standalone)'
  338. ).matches;
  339. forms.previewModal = true;
  340. fscreen();
  341. forms.previewParams = {
  342. type: 'preview',
  343. courseId: id,
  344. subjectId: prepareStore.getSubjectId,
  345. detailId: prepareStore.getSelectKey,
  346. lessonCourseId: prepareStore.getBaseCourseware.id
  347. };
  348. } else {
  349. const { href } = router.resolve({
  350. path: '/attend-class',
  351. query: {
  352. type: 'preview',
  353. courseId: id,
  354. subjectId: prepareStore.getSubjectId,
  355. detailId: prepareStore.getSelectKey,
  356. lessonCourseId: prepareStore.getBaseCourseware.id
  357. }
  358. });
  359. window.open(href, +new Date() + '');
  360. }
  361. };
  362. const onStartClass = async (item: any, classGroupId: any) => {
  363. if (classGroupId) {
  364. // 开始上课
  365. const res = await courseScheduleStart({
  366. lessonCoursewareKnowledgeDetailId: prepareStore.selectKey,
  367. classGroupId: classGroupId,
  368. useChapterLessonCoursewareId: item.id,
  369. subjectId: prepareStore.getSubjectId
  370. });
  371. if (window.matchMedia('(display-mode: standalone)').matches) {
  372. state.application = window.matchMedia(
  373. '(display-mode: standalone)'
  374. ).matches;
  375. forms.previewModal = true;
  376. fscreen();
  377. forms.previewParams = {
  378. type: 'class',
  379. classGroupId: classGroupId,
  380. courseId: item.id,
  381. subjectId: prepareStore.getSubjectId,
  382. detailId: prepareStore.getSelectKey,
  383. classId: res.data,
  384. lessonCourseId: prepareStore.getBaseCourseware.id,
  385. preStudentNum: forms.preStudentNum
  386. };
  387. } else {
  388. const { href } = router.resolve({
  389. path: '/attend-class',
  390. query: {
  391. type: 'class',
  392. classGroupId: classGroupId,
  393. courseId: item.id,
  394. subjectId: prepareStore.getSubjectId,
  395. detailId: prepareStore.getSelectKey,
  396. classId: res.data,
  397. lessonCourseId: prepareStore.getBaseCourseware.id,
  398. preStudentNum: forms.preStudentNum
  399. }
  400. });
  401. window.open(href, +new Date() + '');
  402. }
  403. } else {
  404. forms.showAttendClass = true;
  405. forms.attendClassType = 'change';
  406. forms.attendClassItem = item;
  407. }
  408. };
  409. const carouselRef = ref();
  410. const onChangeSlide = (type: 'left' | 'right') => {
  411. if (type === 'left') {
  412. carouselRef.value?.prev();
  413. } else if (type === 'right') {
  414. carouselRef.value?.next();
  415. }
  416. };
  417. return () => (
  418. <div
  419. class={[
  420. styles.coursewarePresetsContainer,
  421. forms.openTableShow && styles.rightLineShow
  422. ]}>
  423. <div
  424. class={styles.presetsLeft}
  425. id="presetsLeftRef"
  426. style={{ width: `calc(${forms.leftWidth} - ${forms.rightWidth})` }}>
  427. <NTabs
  428. ref={subjectRef}
  429. defaultValue="subject"
  430. paneClass={styles.paneTitle}
  431. justifyContent="start"
  432. paneWrapperClass={styles.paneWrapperContainer}
  433. value={prepareStore.getSubjectId?.toString()}
  434. onUpdate:value={val => {
  435. prepareStore.setSubjectId(val);
  436. // 保存
  437. forms.subjectId = val;
  438. if (!val) {
  439. sessionStorage.setItem(
  440. 'prepareLessonCourseWareSubjectIsNull',
  441. val ? 'false' : 'true'
  442. );
  443. }
  444. }}
  445. v-slots={{
  446. suffix: () => (
  447. <NButton
  448. class={styles.addBtn}
  449. type="primary"
  450. bordered={false}
  451. onClick={() => {
  452. eventGlobal.emit('teacher-slideshow', true);
  453. emit('change', {
  454. status: true,
  455. type: 'create'
  456. });
  457. }}>
  458. <NImage
  459. class={styles.addBtnIcon}
  460. previewDisabled
  461. src={add}></NImage>
  462. 创建课件
  463. </NButton>
  464. )
  465. }}>
  466. {[{ name: '全部声部', id: '' }, ...prepareStore.getSubjectList].map(
  467. (item: any) => (
  468. <NTabPane
  469. name={`${item.id}`}
  470. tab={item.name}
  471. displayDirective="if"></NTabPane>
  472. )
  473. )}
  474. </NTabs>
  475. <NScrollbar class={styles.coursewarePresets}>
  476. <div style={{ overflow: 'hidden' }}>
  477. <NSpin show={forms.loading}>
  478. <div class={styles.list}>
  479. {forms.tableList.map((item: any) => (
  480. <div class={[styles.itemWrap, styles.itemBlock, 'row-nav']}>
  481. <div class={styles.itemWrapBox}>
  482. <CoursewareType
  483. operate
  484. isEditName
  485. item={item}
  486. onClick={() => onPreviewAttend(item.id)}
  487. onEditName={() => {
  488. forms.selectItem = item;
  489. forms.editTitle = item.name;
  490. forms.editTitleVisiable = true;
  491. }}
  492. onEdit={() => {
  493. //
  494. eventGlobal.emit('teacher-slideshow', true);
  495. emit('change', {
  496. status: true,
  497. type: 'update',
  498. groupItem: { id: item.id }
  499. });
  500. }}
  501. onStartClass={() =>
  502. onStartClass(item, forms.classGroupId)
  503. }
  504. onDelete={() => {
  505. forms.selectItem = item;
  506. forms.preRemoveVisiable = true;
  507. }}
  508. />
  509. </div>
  510. </div>
  511. ))}
  512. {!forms.loading && forms.tableList.length <= 0 && (
  513. <TheEmpty class={styles.empty1} description="暂无课件" />
  514. )}
  515. </div>
  516. </NSpin>
  517. </div>
  518. </NScrollbar>
  519. </div>
  520. {/* {forms.openTableList.length > 0 && ( */}
  521. <div class={styles.presetsRight} id="presetsRightRef">
  522. <NTooltip showArrow={false}>
  523. {{
  524. trigger: () => (
  525. // <i
  526. // class={[
  527. // styles.presetsArrar,
  528. // !forms.openTableShow && styles.presetsArrarActive
  529. // ]}
  530. // onClick={() =>
  531. // (forms.openTableShow = !forms.openTableShow)
  532. // }></i>
  533. <div
  534. class={[
  535. styles.presetsArrar,
  536. !forms.openTableShow && styles.presetsArrarActive
  537. ]}
  538. onClick={() => (forms.openTableShow = !forms.openTableShow)}>
  539. <NIcon>
  540. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  541. <path
  542. d="M16.62 2.99a1.25 1.25 0 0 0-1.77 0L6.54 11.3a.996.996 0 0 0 0 1.41l8.31 8.31c.49.49 1.28.49 1.77 0s.49-1.28 0-1.77L9.38 12l7.25-7.25c.48-.48.48-1.28-.01-1.76z"
  543. fill="currentColor"></path>
  544. </svg>
  545. </NIcon>
  546. </div>
  547. ),
  548. default: () => <div>{forms.openTableShow ? '收起' : '展开'}</div>
  549. }}
  550. </NTooltip>
  551. <Related
  552. onMore={() => (forms.showRelatedClass = true)}
  553. onAdd={(item: any) => {
  554. onAddCourseware(item);
  555. }}
  556. onLook={(item: any) => {
  557. onPreviewAttend(item.id);
  558. }}
  559. />
  560. </div>
  561. {/* )} */}
  562. <NModal
  563. v-model:show={forms.showRelatedClass}
  564. preset="card"
  565. showIcon={false}
  566. class={['modalTitle background', styles.attendClassModal1]}
  567. title={'相关课件'}
  568. blockScroll={false}>
  569. <RelatedClass
  570. tableList={forms.tableList}
  571. subjectList={prepareStore.getSubjectList}
  572. subjectId={prepareStore.getSubjectId as any}
  573. coursewareDetailKnowledgeId={prepareStore.getSelectKey}
  574. onClose={() => (forms.showRelatedClass = false)}
  575. onAdd={(item: any) => onAddCourseware(item)}
  576. onClick={(item: any) => {
  577. onPreviewAttend(item.id);
  578. forms.showRelatedClass = false;
  579. }}
  580. />
  581. </NModal>
  582. <NModal
  583. v-model:show={forms.editTitleVisiable}
  584. preset="card"
  585. class={['modalTitle', styles.removeVisiable1]}
  586. title={'课件重命名'}>
  587. <div class={styles.studentRemove}>
  588. <NInput
  589. placeholder="请输入课件名称"
  590. v-model:value={forms.editTitle}
  591. maxlength={15}
  592. onKeyup={(e: any) => {
  593. if (e.code === 'ArrowLeft' || e.code === 'ArrowRight') {
  594. e.stopPropagation();
  595. }
  596. }}
  597. />
  598. <NSpace class={styles.btnGroupModal} justify="center">
  599. <NButton round onClick={() => (forms.editTitleVisiable = false)}>
  600. 取消
  601. </NButton>
  602. <NButton
  603. round
  604. type="primary"
  605. onClick={onEditTitleSubmit}
  606. loading={forms.editBtnLoading}>
  607. 确定
  608. </NButton>
  609. </NSpace>
  610. </div>
  611. </NModal>
  612. <NModal
  613. v-model:show={forms.preRemoveVisiable}
  614. preset="card"
  615. class={['modalTitle', styles.removeVisiable1]}
  616. title={'删除课件'}>
  617. <TheMessageDialog
  618. content={`<p style="text-align: left;">请确认是否删除【${forms.selectItem.name}】,删除后不可恢复</p>`}
  619. cancelButtonText="取消"
  620. confirmButtonText="确认"
  621. loading={forms.messageLoading}
  622. onClose={() => (forms.preRemoveVisiable = false)}
  623. onConfirm={() => onRemove()}
  624. />
  625. </NModal>
  626. {/* 应用内预览或上课 */}
  627. <PreviewWindow
  628. v-model:show={forms.previewModal}
  629. type="attend"
  630. params={forms.previewParams}
  631. />
  632. <NModal
  633. v-model:show={forms.showAttendClass}
  634. preset="card"
  635. showIcon={false}
  636. class={['modalTitle background', styles.attendClassModal]}
  637. title={'选择班级'}
  638. blockScroll={false}>
  639. <AttendClass
  640. onClose={() => (forms.showAttendClass = false)}
  641. type={forms.attendClassType}
  642. onPreview={(item: any) => {
  643. if (window.matchMedia('(display-mode: standalone)').matches) {
  644. state.application = window.matchMedia(
  645. '(display-mode: standalone)'
  646. ).matches;
  647. forms.previewModal = true;
  648. forms.previewParams = {
  649. ...item
  650. };
  651. } else {
  652. const { href } = router.resolve({
  653. path: '/attend-class',
  654. query: {
  655. ...item
  656. }
  657. });
  658. window.open(href, +new Date() + '');
  659. }
  660. }}
  661. onConfirm={async (item: any) => {
  662. onStartClass(forms.attendClassItem, item.classGroupId);
  663. }}
  664. />
  665. </NModal>
  666. </div>
  667. );
  668. }
  669. });