index.tsx 23 KB

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