index.tsx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. NImage,
  5. NButton,
  6. NPopselect,
  7. NModal,
  8. useMessage,
  9. NSpin
  10. } from 'naive-ui';
  11. import headerD from './images/headerD.png';
  12. import defultHeade from '@/components/layout/images/teacherIcon.png';
  13. import blackBoardBg from './images/blackboard_bg.png';
  14. import teacherMan from './images/teacher_man.png';
  15. import teacherWoman from './images/teacher_woman.png';
  16. import homeText1 from './images/home/home-text-1.png';
  17. import homeText2 from './images/home/home-text-2.png';
  18. import iconTo from './images/icon-to.png';
  19. import t1 from './images/t1.png';
  20. import t2 from './images/t2.png';
  21. import t3 from './images/t3.png';
  22. import { useRouter } from 'vue-router';
  23. import { useUserStore } from '/src/store/modules/users';
  24. import SelectClass from './modals/selectClass';
  25. import dayjs from 'dayjs';
  26. import { gradeToCN, weekToCN } from '/src/utils/contants';
  27. import { useCatchStore } from '/src/store/modules/catchData';
  28. import TeachGroup from './modals/teachGroup';
  29. import { classGroupList, courseSchedulePage } from './api';
  30. import TheEmpty from '/src/components/TheEmpty';
  31. import HomeGuide from '/src/custom-plugins/guide-page/home-guide';
  32. import TimerMeter from '/src/components/timerMeter';
  33. import { vaildUrl } from '/src/utils/urlUtils';
  34. import { px2vw } from '/src/utils';
  35. import PlaceholderTone from '@/components/layout/modals/placeholderTone';
  36. import PreviewWindow from '../preview-window';
  37. import UpdatePassword from '/src/components/layout/modals/update-password';
  38. import AttendClass from '../prepare-lessons/model/attend-class';
  39. import { state } from '/src/state';
  40. export const formatDateToDay = () => {
  41. const hours = dayjs().hour();
  42. if (hours < 12) {
  43. return '早上好'; //如果小时数小于12则输出“早上好!”
  44. } else if (hours > 12 && hours < 18) {
  45. return '下午好'; //如果小时数大于12并且小于18,输入“下午好!”
  46. } else {
  47. return '晚上好'; //如果上面两个条件都不符合,则输出“晚上好!”
  48. }
  49. };
  50. export default defineComponent({
  51. name: 'home-page',
  52. setup() {
  53. const catchStore = useCatchStore();
  54. const message = useMessage();
  55. const router = useRouter();
  56. const userStore = useUserStore();
  57. const showUpdatePassword = ref(false);
  58. const showModalBeat = ref(false);
  59. const showModalTone = ref(false);
  60. const showModalTime = ref(false);
  61. const forms = reactive({
  62. showAttendClass: false,
  63. useStatus: false,
  64. studentList: [] as any,
  65. bookVersionId: null,
  66. classGroupId: null,
  67. category: null,
  68. subjectId: null,
  69. musicTagList: [] as any,
  70. loading: false,
  71. list: [] as any,
  72. unit: null,
  73. unitList: [],
  74. subjectList: [] as any,
  75. gradeList: [] as any,
  76. classLoading: false,
  77. total: 0, // 上课数量
  78. classSelect: {
  79. currentGradeNum: null,
  80. currentClass: null,
  81. name: ''
  82. } as any,
  83. popSelectOptions: [] as any,
  84. showGuide: false,
  85. showPreview: false,
  86. itemPreview: {} as any
  87. });
  88. const teachList = ref({} as any);
  89. // 学生列表
  90. // getStdentList
  91. const onUseConfirm = (item: any) => {
  92. forms.classSelect = {
  93. currentGradeNum: item.currentGradeNum,
  94. currentClass: item.classGroupId,
  95. name: item.name
  96. };
  97. getCourseSchedulePage();
  98. };
  99. // 获取年级班级
  100. const getClassList = async () => {
  101. try {
  102. const { data } = await classGroupList({ removeZeroClass: true });
  103. const cList = data || [];
  104. const gradeList: any = [];
  105. const popSelectOptions: any = [];
  106. // getLastClassRecode()
  107. cList.forEach((item: any, index: number) => {
  108. // if (index === 0) {
  109. // const temp = item.classGroupList[0];
  110. // if(forms.classSelect.currentClass){
  111. // return
  112. // }else{
  113. // forms.classSelect = {
  114. // currentGradeNum: item.currentGradeNum,
  115. // currentClass: temp.id,
  116. // name: temp.name
  117. // };
  118. // console.log(forms.classSelect.currentClass,'getClassList')
  119. // }
  120. // }
  121. const classList: any = [];
  122. item.classGroupList.forEach((i: any) => {
  123. classList.push({
  124. label: i.currentClass + '班',
  125. value: i.id,
  126. lastStudy: i.lastStudy
  127. });
  128. popSelectOptions.push({
  129. label: i.name,
  130. value: i.id,
  131. currentGradeNum: item.currentGradeNum,
  132. lastStudy: i.lastStudy
  133. });
  134. });
  135. gradeList.push({
  136. label: gradeToCN[item.currentGradeNum],
  137. value: item.currentGradeNum,
  138. childrens: classList
  139. });
  140. });
  141. forms.popSelectOptions = popSelectOptions;
  142. forms.gradeList = gradeList;
  143. } catch {
  144. //
  145. }
  146. };
  147. const getLastClassRecode = async ()=>{
  148. const { data } = await courseSchedulePage({
  149. page: 1,
  150. rows: 1,
  151. teacherId: userStore.getUserInfo.id
  152. });
  153. if(data.rows.length >0 && data.rows[0]){
  154. forms.classSelect.currentClass = data.rows[0].classGroupId;
  155. forms.classSelect.name = data.rows[0].classGroupName;
  156. }
  157. }
  158. const getCourseSchedulePage = async () => {
  159. forms.classLoading = true;
  160. try {
  161. const { data } = await courseSchedulePage({
  162. classGroupId: forms.classSelect.currentClass,
  163. page: 1,
  164. rows: 4,
  165. teacherId: userStore.getUserInfo.id
  166. });
  167. const result = data.rows || [];
  168. forms.total = data.total || 0;
  169. const dateTime: any = {};
  170. result.forEach((item: any) => {
  171. const tempTime = dayjs(item.classDate).format('MM-DD');
  172. if (!dateTime[tempTime]) {
  173. dateTime[tempTime] = [];
  174. }
  175. const lessonCourseware = item.lessonCoursewareJson
  176. ? JSON.parse(item.lessonCoursewareJson)
  177. : {};
  178. dateTime[tempTime].push({
  179. classGroup: forms.classSelect.name,
  180. teacherName: item.teacherName,
  181. conent:
  182. lessonCourseware.lessonCoursewareName +
  183. ' | ' +
  184. lessonCourseware.lessonCoursewareDetailName +
  185. ' | ' +
  186. lessonCourseware.lessonCoursewareKnowledgeDetailName,
  187. image: item.teacherAvatar
  188. });
  189. });
  190. teachList.value = dateTime;
  191. } catch (e: any) {
  192. //
  193. console.log(e);
  194. }
  195. forms.classLoading = false;
  196. };
  197. onMounted(async () => {
  198. await getClassList();
  199. await getLastClassRecode()
  200. await catchStore.getSubjects();
  201. await getCourseSchedulePage();
  202. forms.subjectList = catchStore.getSubjectList.map((item: any) => {
  203. return {
  204. label: item.name,
  205. value: item.id
  206. };
  207. });
  208. if (!userStore.getUserInfo.account.updatePasswordFlag) {
  209. showUpdatePassword.value = true;
  210. } else {
  211. forms.showGuide = true;
  212. }
  213. });
  214. // const formsRef = ref();
  215. // const gotoClassPage = () => {
  216. // formsRef.value.validate(async (error: any) => {
  217. // if (error) return;
  218. // try {
  219. // const { data } = await queryCourseware({
  220. // coursewareDetailKnowledgeId: forms.unit,
  221. // subjectId: forms.subjectId,
  222. // page: 1,
  223. // rows: 99
  224. // });
  225. // if (data.rows && data.rows.length > 0) {
  226. // await courseScheduleStart({
  227. // lessonCoursewareKnowledgeDetailId: forms.unit,
  228. // classGroupId: forms.applyClassItem?.classGroupId
  229. // });
  230. // if (window.matchMedia('(display-mode: standalone)').matches) {
  231. // forms.showPreview = true;
  232. // forms.itemPreview = {
  233. // type: 'class',
  234. // classGroupId: forms.applyClassItem?.classGroupId,
  235. // subjectId: forms.subjectId,
  236. // detailId: forms.unit
  237. // };
  238. // globalState.application = window.matchMedia(
  239. // '(display-mode: standalone)'
  240. // ).matches;
  241. // // 加全屏
  242. // fscreen();
  243. // } else {
  244. // const { href } = router.resolve({
  245. // path: '/attend-class',
  246. // query: {
  247. // type: 'class',
  248. // classGroupId: forms.applyClassItem?.classGroupId,
  249. // subjectId: forms.subjectId,
  250. // detailId: forms.unit
  251. // }
  252. // });
  253. // window.open(href, +new Date() + '');
  254. // }
  255. // } else {
  256. // message.error('当前章节暂无课件,请重新选择');
  257. // }
  258. // } catch {
  259. // //
  260. // }
  261. // });
  262. // };
  263. const clearStorng = () => {
  264. localStorage.removeItem('teacher-guideInfo');
  265. forms.showGuide = false;
  266. setTimeout(() => {
  267. forms.showGuide = true;
  268. }, 500);
  269. };
  270. return () => (
  271. <div class={styles.homeWrap}>
  272. <div class={styles.homeInfoLeft}>
  273. <div class={styles.homeBanner}>
  274. <div class={styles.applyInfo} id="home-1">
  275. <div class={styles.centerInfo} id="home-0"></div>
  276. <div class={styles.userInfo}>
  277. <div class={styles.userName}>
  278. Hi,{userStore.getUserInfo?.nickname} {formatDateToDay()}~
  279. </div>
  280. </div>
  281. {userStore.getUserInfo.gender === 1 ? (
  282. <img src={teacherMan} class={styles.teacherMan} />
  283. ) : (
  284. <img src={teacherWoman} class={styles.teacherWoman} />
  285. )}
  286. <div class={styles.blackborad}>
  287. <img src={blackBoardBg} class={styles.blackBoardBg} />
  288. </div>
  289. <div class={styles.applyContainer}>
  290. <div class={[styles.applyItem, styles.applyItem1]}>
  291. <p>可根据声部进行备课,更好的规划教学</p>
  292. <div
  293. class={[styles.applyBtn, styles.applyBtn1]}
  294. onClick={() => {
  295. // 备课
  296. router.push({
  297. path: '/prepare-lessons'
  298. });
  299. }}>
  300. <img src={homeText1} />
  301. </div>
  302. </div>
  303. <div class={[styles.applyItem, styles.applyItem2]}>
  304. <p>点击这里,选择班级快速进入备课区域</p>
  305. <div
  306. class={[styles.applyBtn, styles.applyBtn2]}
  307. onClick={() => {
  308. forms.showAttendClass = true;
  309. }}>
  310. <img src={homeText2} />
  311. </div>
  312. </div>
  313. </div>
  314. </div>
  315. </div>
  316. <div class={styles.toolContainer}>
  317. <div class={styles.toolTips}>
  318. <div class={styles.toolTitle}>工具箱</div>
  319. <div class={styles.toolContent}>
  320. 这里是常用的教学辅助工具,可帮助学生集中注意力、提高演奏效率,使演奏更完整平稳。让您在课堂上完成更好的教学。
  321. </div>
  322. </div>
  323. <img src={iconTo} class={styles.iconTo} />
  324. <div class={styles.toolFunction} id="home-3">
  325. <div class={[styles.toolItem, styles.item1]}>
  326. <img src={t1} />
  327. {/* <p class={styles.toolMemo}>提升效率,练习好节奏</p> */}
  328. <NButton
  329. class={styles.btn1}
  330. onClick={() => {
  331. showModalBeat.value = true;
  332. }}>
  333. 节拍器
  334. </NButton>
  335. </div>
  336. <div class={[styles.toolItem, styles.item2]}>
  337. <img src={t2} />
  338. {/* <p class={styles.toolMemo}>精准调音,一劳永逸</p> */}
  339. <NButton
  340. class={styles.btn2}
  341. onClick={() => {
  342. showModalTone.value = true;
  343. }}>
  344. 调音器
  345. </NButton>
  346. </div>
  347. <div class={[styles.toolItem, styles.item3]}>
  348. <img src={t3} />
  349. {/* <p class={styles.toolMemo}>创造时间,集中注意力</p> */}
  350. <NButton
  351. class={styles.btn3}
  352. onClick={() => {
  353. showModalTime.value = true;
  354. }}>
  355. 计时器
  356. </NButton>
  357. </div>
  358. </div>
  359. </div>
  360. </div>
  361. <div class={styles.homeInfoRight}>
  362. <div class={styles.rightTeachingWrap}>
  363. <div class={styles.headerContainer}>
  364. <div
  365. class={styles.HeaderWrap}
  366. onClick={() => router.push('/setting')}>
  367. <NImage
  368. previewDisabled
  369. class={styles.headerD}
  370. src={headerD}></NImage>
  371. <NImage
  372. previewDisabled
  373. class={styles.defultHeade}
  374. src={userStore.getUserInfo.avatar || defultHeade}></NImage>
  375. </div>
  376. </div>
  377. <div class={styles.headerInfo}>
  378. <p class={styles.headerTitle}>{userStore.getUserInfo.nickname}</p>
  379. {userStore.getUserInfo.schoolInfos &&
  380. userStore.getUserInfo.schoolInfos.length > 0 && (
  381. <p class={styles.headerSubTitle}>
  382. {userStore.getUserInfo.schoolInfos[0].name}
  383. {/* | 音乐老师 */}
  384. </p>
  385. )}
  386. </div>
  387. <div class={styles.rightTeachingWrapTitle}>
  388. <h3 class={styles.rightTitle}>
  389. <div class={styles.titleDot}></div>上课记录
  390. </h3>
  391. {forms.classSelect.name && (
  392. <NPopselect
  393. v-model:value={forms.classSelect.currentClass}
  394. options={forms.popSelectOptions}
  395. trigger="click"
  396. onUpdate:value={(val: any) => {
  397. forms.popSelectOptions.forEach((item: any) => {
  398. if (item.value === val) {
  399. forms.classSelect = {
  400. currentGradeNum: item.currentGradeNum,
  401. currentClass: item.value,
  402. name: item.label
  403. };
  404. getCourseSchedulePage();
  405. }
  406. });
  407. }}>
  408. <div
  409. class={styles.lookMore}
  410. // onClick={() => (forms.useStatus = true)}
  411. >
  412. {forms.classSelect.name}
  413. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  414. <path
  415. d="M6 9l6 6l6-6"
  416. fill="none"
  417. stroke="currentColor"
  418. stroke-width="2"
  419. stroke-linecap="round"
  420. stroke-linejoin="round"></path>
  421. </svg>
  422. </div>
  423. </NPopselect>
  424. )}
  425. </div>
  426. <NSpin show={forms.classLoading} style={{ minHeight: '40vh' }}>
  427. {Object.keys(teachList.value).length > 0 && (
  428. <div class={styles.teachListWrap}>
  429. {Object.keys(teachList.value).map(key => (
  430. <TeachGroup
  431. list={teachList.value[key]}
  432. keys={key}></TeachGroup>
  433. ))}
  434. {forms.total > 4 && (
  435. <div class={styles.teachListWrapWall}>
  436. <span
  437. onClick={() => {
  438. // setTabsCaches('attendclass', 'tabName', {
  439. // path: '/classDetail'
  440. // });
  441. sessionStorage.setItem(
  442. 'classDetailTabs',
  443. 'attendclass'
  444. );
  445. router.push({
  446. path: '/classDetail',
  447. query: {
  448. name: forms.classSelect.name,
  449. id: forms.classSelect.currentClass
  450. }
  451. });
  452. }}>
  453. 查看全部
  454. </span>
  455. </div>
  456. )}
  457. </div>
  458. )}
  459. {Object.keys(teachList.value).length <= 0 &&
  460. !forms.classLoading && <TheEmpty />}
  461. </NSpin>
  462. </div>
  463. </div>
  464. <NModal
  465. v-model:show={forms.useStatus}
  466. preset="card"
  467. showIcon={false}
  468. class={['modalTitle background', styles.assignHomework]}
  469. title={'选择班级'}
  470. blockScroll={false}>
  471. <SelectClass
  472. useDetail={{
  473. currentGradeNum: forms.classSelect.currentGradeNum,
  474. classGroupId: forms.classSelect.currentClass
  475. }}
  476. gradeList={forms.gradeList}
  477. onConfirm={(item: any) => onUseConfirm(item)}
  478. onClose={() => (forms.useStatus = false)}
  479. />
  480. </NModal>
  481. <NModal
  482. class={['modalTitle background']}
  483. title={'节拍器'}
  484. preset="card"
  485. v-model:show={showModalBeat.value}
  486. style={{ width: '687px' }}>
  487. <div class={styles.modeWrap}>
  488. <iframe
  489. src={`${vaildUrl()}/metronome/?id=${new Date().getTime()}`}
  490. scrolling="no"
  491. frameborder="0"
  492. width="100%"
  493. height={'650px'}></iframe>
  494. </div>
  495. </NModal>
  496. <NModal
  497. v-model:show={showModalTime.value}
  498. class={['modalTitle background']}
  499. title={'计时器'}
  500. preset="card"
  501. style={{ width: px2vw(772) }}>
  502. <div>
  503. <TimerMeter></TimerMeter>
  504. </div>
  505. </NModal>
  506. <NModal class={['background']} v-model:show={showModalTone.value}>
  507. <div>
  508. <PlaceholderTone
  509. onClose={() => {
  510. showModalTone.value = false;
  511. }}></PlaceholderTone>
  512. </div>
  513. </NModal>
  514. {/* 弹窗查看 */}
  515. <PreviewWindow
  516. v-model:show={forms.showPreview}
  517. type="attend"
  518. params={forms.itemPreview}
  519. />
  520. {forms.showGuide ? <HomeGuide></HomeGuide> : null}
  521. <NModal
  522. v-model:show={showUpdatePassword.value}
  523. class={['modalTitle', styles.showUpdatePassword]}
  524. style="--n-title-font-weight: 600;"
  525. preset="card"
  526. title={'修改密码'}
  527. closable={false}
  528. maskClosable={false}
  529. closeOnEsc={false}>
  530. <UpdatePassword
  531. onSubmit={() => {
  532. // 密码更新成功
  533. showUpdatePassword.value = true;
  534. forms.showGuide = true;
  535. userStore.logout().then(() => {
  536. // 移除标签页
  537. router
  538. .replace({
  539. name: 'login'
  540. })
  541. .finally(() => location.reload());
  542. });
  543. }}
  544. />
  545. </NModal>
  546. <NModal
  547. v-model:show={forms.showAttendClass}
  548. preset="card"
  549. showIcon={false}
  550. class={['modalTitle background', styles.attendClassModal]}
  551. title={'选择班级'}
  552. blockScroll={false}>
  553. <AttendClass
  554. onClose={() => (forms.showAttendClass = false)}
  555. type="change"
  556. onConfirm={(item: any) => {
  557. router.push({
  558. path: '/prepare-lessons',
  559. query: {
  560. ...item
  561. }
  562. });
  563. }}
  564. />
  565. </NModal>
  566. </div>
  567. );
  568. }
  569. });