index.tsx 20 KB

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