index.tsx 26 KB

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