index.tsx 21 KB

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