index.tsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. NImage,
  5. NButton,
  6. NAvatarGroup,
  7. NForm,
  8. NFormItem,
  9. NSelect,
  10. NPopselect,
  11. NSpace,
  12. NModal,
  13. NCascader,
  14. useMessage,
  15. NSpin
  16. } from 'naive-ui';
  17. import headerD from './images/headerD.png';
  18. import defultHeade from '@/components/layout/images/teacherIcon.png';
  19. import blackBoardBg from './images/blackboard_bg.png';
  20. import teacherMan from './images/teacher_man.png';
  21. import teacherWoman from './images/teacher_woman.png';
  22. import iconLession from './images/icon-lession.png';
  23. import iconBook from './images/icon-book.png';
  24. import iconDetail from './images/icon-detail.png';
  25. import iconSubject from './images/icon-subject.png';
  26. import iconTo from './images/icon-to.png';
  27. import t1 from './images/t1.png';
  28. import t2 from './images/t2.png';
  29. import t3 from './images/t3.png';
  30. import { useRouter } from 'vue-router';
  31. import { useUserStore } from '/src/store/modules/users';
  32. import SelectClass from './modals/selectClass';
  33. import dayjs from 'dayjs';
  34. import { gradeToCN, weekToCN } from '/src/utils/contants';
  35. import { getCLassStudent, getCourseChapter } from '../classList/api';
  36. import { useCatchStore } from '/src/store/modules/catchData';
  37. import { useThrottleFn } from '@vueuse/core';
  38. import {
  39. bookVersionPage,
  40. courseScheduleStart,
  41. lessonCoursewarePage,
  42. queryCourseware
  43. } from '../prepare-lessons/api';
  44. import TheNoticeBar from '/src/components/TheNoticeBar';
  45. import TeachGroup from './modals/teachGroup';
  46. import { classGroupList, courseSchedulePage } from './api';
  47. import TheEmpty from '/src/components/TheEmpty';
  48. import { setTabsCaches } from '/src/hooks/use-async';
  49. import HomeGuide from '/src/custom-plugins/guide-page/home-guide';
  50. export const formatDateToDay = () => {
  51. const hours = dayjs().hour();
  52. if (hours < 12) {
  53. return '早上好'; //如果小时数小于12则输出“早上好!”
  54. } else if (hours > 12 && hours < 18) {
  55. return '下午好'; //如果小时数大于12并且小于18,输入“下午好!”
  56. } else {
  57. return '晚上好'; //如果上面两个条件都不符合,则输出“晚上好!”
  58. }
  59. };
  60. export default defineComponent({
  61. name: 'home-page',
  62. setup() {
  63. const catchStore = useCatchStore();
  64. const message = useMessage();
  65. const router = useRouter();
  66. const userStore = useUserStore();
  67. const forms = reactive({
  68. applyClassItem: {} as any, // 选择的内容
  69. applyStatus: false,
  70. useStatus: false,
  71. studentList: [] as any,
  72. bookVersionId: null,
  73. classGroupId: null,
  74. category: null,
  75. subjectId: null,
  76. musicTagList: [] as any,
  77. loading: false,
  78. list: [] as any,
  79. unit: null,
  80. unitList: [],
  81. subjectList: [] as any,
  82. gradeList: [] as any,
  83. classLoading: false,
  84. total: 0, // 上课数量
  85. classSelect: {
  86. currentGradeNum: null,
  87. currentClass: null,
  88. name: ''
  89. } as any,
  90. popSelectOptions: [] as any,
  91. showGuide: false
  92. });
  93. const teachList = ref({} as any);
  94. // 学生列表
  95. // getStdentList
  96. // 应用选择年级班级
  97. const onApplyConfirm = async (item: any) => {
  98. try {
  99. //
  100. const { data } = await getCLassStudent({
  101. page: 1,
  102. rows: 999,
  103. classGroupId: item.classGroupId
  104. });
  105. const temps = data.rows || [];
  106. temps.forEach((row: any) => {
  107. forms.studentList.push({
  108. name: row.nickname,
  109. src: row.avatar
  110. });
  111. });
  112. forms.applyClassItem = item;
  113. } catch {
  114. //
  115. }
  116. };
  117. const onUseConfirm = (item: any) => {
  118. forms.classSelect = {
  119. currentGradeNum: item.currentGradeNum,
  120. currentClass: item.classGroupId,
  121. name: item.name
  122. };
  123. getCourseSchedulePage();
  124. };
  125. const throttledFn = useThrottleFn(() => getLessonCourseware(), 500);
  126. const getLessonCourseware = async () => {
  127. forms.category = null;
  128. forms.unit = null;
  129. forms.category = null;
  130. forms.loading = true;
  131. try {
  132. const { data } = await lessonCoursewarePage({
  133. bookVersionId: forms.bookVersionId,
  134. enableFlag: 1,
  135. page: 1,
  136. rows: 99,
  137. type: 'COURSEWARE'
  138. // currentGradeNum: forms.applyClassItem.currentGradeNum
  139. });
  140. forms.list = data.rows.map((item: any) => {
  141. return {
  142. label: item.name,
  143. value: item.id
  144. };
  145. });
  146. } catch {
  147. //
  148. }
  149. forms.loading = false;
  150. };
  151. const getunitList = async () => {
  152. forms.unit = null;
  153. try {
  154. if (forms.category) {
  155. const res = await getCourseChapter(forms.category);
  156. forms.unitList = res.data.lessonList.map((item: any) => {
  157. return { ...item, label: item.name, value: item.id };
  158. });
  159. } else {
  160. forms.unitList = [];
  161. }
  162. } catch (e) {
  163. console.log(e);
  164. }
  165. };
  166. const getVersion = async () => {
  167. forms.unit = null;
  168. try {
  169. const { data } = await bookVersionPage({
  170. page: 1,
  171. rows: 99,
  172. type: 'COURSEWARE'
  173. });
  174. const temp = data.rows || [];
  175. temp.forEach((item: any) => {
  176. forms.musicTagList.push({
  177. id: item.id,
  178. name: item.name
  179. });
  180. });
  181. } catch {
  182. //
  183. }
  184. };
  185. // 获取年级班级
  186. const getClassList = async () => {
  187. try {
  188. const { data } = await classGroupList({ removeZeroClass: true });
  189. const cList = data || [];
  190. const gradeList: any = [];
  191. const popSelectOptions: any = [];
  192. cList.forEach((item: any, index: number) => {
  193. if (index === 0) {
  194. const temp = item.classGroupList[0];
  195. forms.classSelect = {
  196. currentGradeNum: item.currentGradeNum,
  197. currentClass: temp.id,
  198. name: temp.name
  199. };
  200. }
  201. const classList: any = [];
  202. item.classGroupList.forEach((i: any) => {
  203. classList.push({
  204. label: i.currentClass + '班',
  205. value: i.id,
  206. lastStudy: i.lastStudy
  207. });
  208. popSelectOptions.push({
  209. label: i.name,
  210. value: i.id,
  211. currentGradeNum: item.currentGradeNum,
  212. lastStudy: i.lastStudy
  213. });
  214. });
  215. gradeList.push({
  216. label: gradeToCN[item.currentGradeNum],
  217. value: item.currentGradeNum,
  218. childrens: classList
  219. });
  220. });
  221. forms.popSelectOptions = popSelectOptions;
  222. forms.gradeList = gradeList;
  223. } catch {
  224. //
  225. }
  226. };
  227. const getCourseSchedulePage = async () => {
  228. forms.classLoading = true;
  229. try {
  230. const { data } = await courseSchedulePage({
  231. classGroupId: forms.classSelect.currentClass,
  232. page: 1,
  233. rows: 6,
  234. teacherId: userStore.getUserInfo.id
  235. });
  236. const result = data.rows || [];
  237. forms.total = data.total || 0;
  238. const dateTime: any = {};
  239. result.forEach((item: any) => {
  240. const tempTime = dayjs(item.classDate).format('MM-DD');
  241. if (!dateTime[tempTime]) {
  242. dateTime[tempTime] = [];
  243. }
  244. const lessonCourseware = item.lessonCoursewareJson
  245. ? JSON.parse(item.lessonCoursewareJson)
  246. : {};
  247. dateTime[tempTime].push({
  248. classGroup: forms.classSelect.name,
  249. teacherName: item.teacherName,
  250. conent:
  251. lessonCourseware.lessonCoursewareName +
  252. ' | ' +
  253. lessonCourseware.lessonCoursewareDetailName +
  254. ' | ' +
  255. lessonCourseware.lessonCoursewareKnowledgeDetailName,
  256. image: item.teacherAvatar
  257. });
  258. });
  259. teachList.value = dateTime;
  260. } catch (e: any) {
  261. //
  262. console.log(e);
  263. }
  264. forms.classLoading = false;
  265. };
  266. onMounted(async () => {
  267. await getClassList();
  268. await catchStore.getSubjects();
  269. await getCourseSchedulePage();
  270. forms.subjectList = catchStore.getSubjectList.map((item: any) => {
  271. return {
  272. label: item.name,
  273. value: item.id
  274. };
  275. });
  276. getVersion();
  277. forms.showGuide = true;
  278. });
  279. const formsRef = ref();
  280. const gotoClassPage = () => {
  281. formsRef.value.validate(async (error: any) => {
  282. if (error) return;
  283. try {
  284. const { data } = await queryCourseware({
  285. coursewareDetailKnowledgeId: forms.unit,
  286. subjectId: forms.subjectId,
  287. page: 1,
  288. rows: 99
  289. });
  290. if (data.rows && data.rows.length > 0) {
  291. await courseScheduleStart({
  292. lessonCoursewareKnowledgeDetailId: forms.unit,
  293. classGroupId: forms.applyClassItem?.classGroupId
  294. });
  295. const { href } = router.resolve({
  296. path: '/attend-class',
  297. query: {
  298. type: 'class',
  299. classGroupId: forms.applyClassItem?.classGroupId,
  300. subjectId: forms.subjectId,
  301. detailId: forms.unit
  302. }
  303. });
  304. window.open(href, +new Date() + '');
  305. } else {
  306. message.error('当前章节暂无课件,请重新选择');
  307. }
  308. } catch {
  309. //
  310. }
  311. });
  312. };
  313. return () => (
  314. <div class={styles.homeWrap}>
  315. <div class={styles.homeInfoLeft}>
  316. <div class={styles.homeBanner}>
  317. <div class={styles.welcomeInfo}>
  318. <div class={styles.userInfo}>
  319. <div class={styles.userName}>
  320. Hi,{userStore.getUserInfo?.nickname} {formatDateToDay()}~
  321. </div>
  322. <div class={styles.userTime}>
  323. {dayjs().format('MM月DD日')},{weekToCN[dayjs().day()]}
  324. </div>
  325. </div>
  326. <div class={styles.userTips}>
  327. <span>欢迎您使用酷乐秀课堂乐器数字化教学平台!</span>
  328. <NButton
  329. color="#40A1FF"
  330. round
  331. class={styles.guide_btn}
  332. {...{ id: 'home-1' }}>
  333. 功能引导
  334. <i></i>
  335. </NButton>
  336. </div>
  337. </div>
  338. {/* <div class={styles.centerInfo}>11111</div> */}
  339. <div class={styles.applyInfo}>
  340. <div class={styles.centerInfo} id="home-0"></div>
  341. <div class={styles.applyInfo} id="home-2"></div>
  342. {userStore.getUserInfo.gender === 1 ? (
  343. <img src={teacherMan} class={styles.teacherMan} />
  344. ) : (
  345. <img src={teacherWoman} class={styles.teacherWoman} />
  346. )}
  347. <div class={styles.blackborad}>
  348. <img src={blackBoardBg} class={styles.blackBoardBg} />
  349. </div>
  350. <div class={styles.applyContainer}>
  351. <div class={styles.applyTitle}>
  352. <span
  353. class={styles.className}
  354. onClick={() => (forms.applyStatus = true)}>
  355. {forms.applyClassItem.name || '请选择班级'}
  356. </span>
  357. <NAvatarGroup options={forms.studentList} max={5} />
  358. </div>
  359. <div class={styles.informations}>
  360. {forms.applyClassItem.lastStudy ? (
  361. <>
  362. 上次课程:
  363. <TheNoticeBar text={forms.applyClassItem.lastStudy} />
  364. </>
  365. ) : (
  366. ''
  367. )}
  368. </div>
  369. <NForm showLabel={false} ref={formsRef} model={forms}>
  370. <NFormItem
  371. path="bookVersionId"
  372. rule={[
  373. {
  374. required: true,
  375. message: '',
  376. trigger: ['blur', 'change']
  377. }
  378. ]}>
  379. <div class={styles.selectContainer}>
  380. <img src={iconLession} />
  381. <NSelect
  382. placeholder="请选择教材版本"
  383. disabled={
  384. forms.applyClassItem?.currentGradeNum ? false : true
  385. }
  386. clearable
  387. options={[...forms.musicTagList]}
  388. labelField="name"
  389. valueField="id"
  390. v-model:value={forms.bookVersionId}
  391. onUpdate:value={() => throttledFn()}
  392. />
  393. </div>
  394. </NFormItem>
  395. <NFormItem
  396. path="category"
  397. rule={[
  398. {
  399. required: true,
  400. message: '',
  401. trigger: ['blur', 'change']
  402. }
  403. ]}>
  404. <div class={styles.selectContainer}>
  405. <img src={iconBook} />
  406. <NSelect
  407. placeholder="请选择册别"
  408. options={[...forms.list]}
  409. clearable
  410. disabled={!forms.bookVersionId}
  411. v-model:value={forms.category}
  412. onUpdate:value={() => getunitList()}
  413. />
  414. </div>
  415. </NFormItem>
  416. <NFormItem
  417. path="unit"
  418. rule={[
  419. {
  420. required: true,
  421. message: '',
  422. trigger: ['blur', 'change']
  423. }
  424. ]}>
  425. <div class={styles.selectContainer}>
  426. <img src={iconDetail} />
  427. <NCascader
  428. disabled={!forms.category}
  429. {...({
  430. options: [...forms.unitList],
  431. placeholder: '选择章节',
  432. clearable: true
  433. } as any)}
  434. childrenField="knowledgeList"
  435. valueField="id"
  436. labelField="name"
  437. v-model:value={forms.unit}
  438. checkStrategy="child"
  439. expandTrigger="hover"
  440. />
  441. </div>
  442. </NFormItem>
  443. <NFormItem
  444. path="subjectId"
  445. rule={[
  446. {
  447. required: true,
  448. message: '',
  449. trigger: ['blur', 'change'],
  450. type: 'number'
  451. }
  452. ]}>
  453. <div class={styles.selectContainer}>
  454. <img src={iconSubject} />
  455. <NSelect
  456. {...({
  457. options: [...forms.subjectList],
  458. placeholder: '选择乐器',
  459. clearable: true
  460. } as any)}
  461. v-model:value={forms.subjectId}
  462. />
  463. </div>
  464. </NFormItem>
  465. <NSpace class={styles.btnGroup} justify="center">
  466. <NButton
  467. round
  468. block
  469. class={styles.startClass}
  470. color="#FF6E4C"
  471. onClick={gotoClassPage}>
  472. 开始上课
  473. </NButton>
  474. <NButton
  475. round
  476. block
  477. class={styles.beforClass}
  478. color="#5B64D1"
  479. onClick={() => router.push('/prepare-lessons')}>
  480. 去备课
  481. </NButton>
  482. </NSpace>
  483. </NForm>
  484. </div>
  485. </div>
  486. </div>
  487. <div class={styles.toolContainer}>
  488. <div class={styles.toolTips}>
  489. <div class={styles.toolTitle}>工具箱</div>
  490. <div class={styles.toolContent}>
  491. 这里是常用的教学辅助工具,可帮助学生集中注意力、提高演奏效率,使演奏更完整平稳。让您在课堂上完成更好的教学。
  492. </div>
  493. </div>
  494. <img src={iconTo} class={styles.iconTo} />
  495. <div class={styles.toolFunction} id="home-4">
  496. <div class={[styles.toolItem, styles.item1]}>
  497. <img src={t1} />
  498. <p class={styles.toolMemo}>提升效率,练习好节奏</p>
  499. <NButton class={styles.btn1}>节拍器</NButton>
  500. </div>
  501. <div class={[styles.toolItem, styles.item2]}>
  502. <img src={t2} />
  503. <p class={styles.toolMemo}>精准调音,一劳永逸</p>
  504. <NButton class={styles.btn2}>调音器</NButton>
  505. </div>
  506. <div class={[styles.toolItem, styles.item3]}>
  507. <img src={t3} />
  508. <p class={styles.toolMemo}>创造时间,集中注意力</p>
  509. <NButton class={styles.btn3}>计时器</NButton>
  510. </div>
  511. </div>
  512. </div>
  513. </div>
  514. <div class={styles.homeInfoRight}>
  515. <div class={styles.rightTeachingWrap}>
  516. <div class={styles.headerContainer}>
  517. <div
  518. class={styles.HeaderWrap}
  519. onClick={() => router.push('/setting')}>
  520. <NImage
  521. previewDisabled
  522. class={styles.headerD}
  523. src={headerD}></NImage>
  524. <NImage
  525. previewDisabled
  526. class={styles.defultHeade}
  527. src={userStore.getUserInfo.avatar || defultHeade}></NImage>
  528. </div>
  529. </div>
  530. <div class={styles.headerInfo}>
  531. <p class={styles.headerTitle}>{userStore.getUserInfo.nickname}</p>
  532. {userStore.getUserInfo.schoolInfos &&
  533. userStore.getUserInfo.schoolInfos.length > 0 && (
  534. <p class={styles.headerSubTitle}>
  535. {userStore.getUserInfo.schoolInfos[0].name}
  536. {/* | 音乐老师 */}
  537. </p>
  538. )}
  539. </div>
  540. <div class={styles.rightTeachingWrapTitle}>
  541. <h3 class={styles.rightTitle}>
  542. <div class={styles.titleDot}></div>上课记录
  543. </h3>
  544. {forms.classSelect.name && (
  545. <NPopselect
  546. v-model:value={forms.classSelect.currentClass}
  547. options={forms.popSelectOptions}
  548. trigger="click"
  549. onUpdate:value={(val: any) => {
  550. console.log(val, '1212');
  551. forms.popSelectOptions.forEach((item: any) => {
  552. if (item.value === val) {
  553. forms.classSelect = {
  554. currentGradeNum: item.currentGradeNum,
  555. currentClass: item.value,
  556. name: item.label
  557. };
  558. getCourseSchedulePage();
  559. }
  560. });
  561. }}>
  562. <div
  563. class={styles.lookMore}
  564. // onClick={() => (forms.useStatus = true)}
  565. >
  566. {forms.classSelect.name}
  567. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  568. <path
  569. d="M6 9l6 6l6-6"
  570. fill="none"
  571. stroke="currentColor"
  572. stroke-width="2"
  573. stroke-linecap="round"
  574. stroke-linejoin="round"></path>
  575. </svg>
  576. </div>
  577. </NPopselect>
  578. )}
  579. </div>
  580. <NSpin show={forms.classLoading} style={{ minHeight: '40vh' }}>
  581. {Object.keys(teachList.value).length > 0 && (
  582. <div class={styles.teachListWrap}>
  583. {Object.keys(teachList.value).map(key => (
  584. <TeachGroup
  585. list={teachList.value[key]}
  586. keys={key}></TeachGroup>
  587. ))}
  588. {forms.total > 6 && (
  589. <div class={styles.teachListWrapWall}>
  590. <span
  591. onClick={() => {
  592. setTabsCaches('attendclass', 'tabName', {
  593. path: '/classDetail'
  594. });
  595. router.push({
  596. path: '/classDetail',
  597. query: {
  598. name: forms.classSelect.name,
  599. id: forms.classSelect.currentClass
  600. }
  601. });
  602. }}>
  603. 查看全部
  604. </span>
  605. </div>
  606. )}
  607. </div>
  608. )}
  609. {Object.keys(teachList.value).length <= 0 &&
  610. !forms.classLoading && <TheEmpty />}
  611. </NSpin>
  612. </div>
  613. </div>
  614. {/* 添加自定义教材 */}
  615. <NModal
  616. v-model:show={forms.applyStatus}
  617. preset="card"
  618. showIcon={false}
  619. class={['modalTitle background', styles.assignHomework]}
  620. title={'选择班级'}
  621. blockScroll={false}>
  622. <SelectClass
  623. useDetail={{
  624. currentGradeNum: forms.applyClassItem.currentGradeNum,
  625. classGroupId: forms.applyClassItem.classGroupId
  626. }}
  627. gradeList={forms.gradeList}
  628. onConfirm={(item: any) => onApplyConfirm(item)}
  629. onClose={() => (forms.applyStatus = false)}
  630. />
  631. </NModal>
  632. <NModal
  633. v-model:show={forms.useStatus}
  634. preset="card"
  635. showIcon={false}
  636. class={['modalTitle background', styles.assignHomework]}
  637. title={'选择班级'}
  638. blockScroll={false}>
  639. <SelectClass
  640. useDetail={{
  641. currentGradeNum: forms.classSelect.currentGradeNum,
  642. classGroupId: forms.classSelect.currentClass
  643. }}
  644. gradeList={forms.gradeList}
  645. onConfirm={(item: any) => onUseConfirm(item)}
  646. onClose={() => (forms.useStatus = false)}
  647. />
  648. </NModal>
  649. {forms.showGuide ? <HomeGuide></HomeGuide> : null}
  650. </div>
  651. );
  652. }
  653. });