index.tsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. import { defineComponent, reactive, onMounted, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. NButton,
  5. NCascader,
  6. NDataTable,
  7. NForm,
  8. NFormItem,
  9. NImage,
  10. NModal,
  11. NSpace,
  12. useMessage
  13. } from 'naive-ui';
  14. import SearchInput from '@/components/searchInput';
  15. import CSelect from '@/components/CSelect';
  16. import Pagination from '@/components/pagination';
  17. import { classGroupList, deleteClass, getSubject, addGroup } from './api';
  18. import CreateClass from './modals/createClass';
  19. import RestStudentBox from './modals/restStudentBox';
  20. import { getgradeNumList, classArray } from './contants';
  21. import add from '@/views/studentList/images/add.png';
  22. import ClassGuide from '@/custom-plugins/guide-page/class-guide';
  23. import { useRoute, useRouter } from 'vue-router';
  24. import TheEmpty from '/src/components/TheEmpty';
  25. import TheTooltip from '/src/components/TheTooltip';
  26. import PreviewWindow from '../preview-window';
  27. import ResetSubject from './modals/resetSubject';
  28. import UpdateSubject from './modals/updateSubject';
  29. import { getGradeLevelList, getGradeYearList } from '../home/api';
  30. import { initCache, setCache } from '/src/hooks/use-async';
  31. import AddStudentModel from '../studentList/modals/addStudentModel';
  32. import { useUserStore } from '/src/store/modules/users';
  33. import { useCatchStore } from '/src/store/modules/catchData';
  34. export default defineComponent({
  35. name: 'class-classList',
  36. setup() {
  37. const catchData = useCatchStore();
  38. const users = useUserStore();
  39. const state = reactive({
  40. searchForm: {
  41. keyword: null as any,
  42. currentClass: '',
  43. currentGradeNum: '',
  44. instrumentId: '',
  45. gradeYear: '',
  46. gradeLevel: ''
  47. },
  48. orchestraType: null,
  49. courseTypeCode: null,
  50. loading: false,
  51. pagination: {
  52. page: 1,
  53. rows: 10,
  54. pageTotal: 6
  55. },
  56. gradeNumList: [] as any,
  57. tableList: [] as any,
  58. studentVisible: false,
  59. activeRow: null as any,
  60. showaddClass: false,
  61. goCourseVisiable: false,
  62. removeVisiable: false,
  63. removeRow: {} as any,
  64. previewModal: false,
  65. previewParams: {} as any,
  66. lastCourse: null as any,
  67. groupBtnLoading: false, // 按钮是否在请求中
  68. // subjectList: [] as any,
  69. showResetClass: false,
  70. showSubjectClass: false,
  71. groupVisiable: false,
  72. popSelectYearList: [] as any,
  73. popSelectLevelList: [] as any,
  74. addStudentVisible: false
  75. });
  76. const formRef = ref();
  77. const message = useMessage();
  78. const router = useRouter();
  79. const route = useRoute();
  80. const search = () => {
  81. state.pagination.page = 1;
  82. getList();
  83. setCache({ current: state.searchForm, saveKey: route.path });
  84. };
  85. const showGuide = ref(false);
  86. state.gradeNumList = getgradeNumList();
  87. const onReset = () => {
  88. state.searchForm = {
  89. keyword: null as any,
  90. currentClass: '' as any,
  91. currentGradeNum: '' as any,
  92. instrumentId: '' as any,
  93. gradeYear: '' as any,
  94. gradeLevel: ''
  95. };
  96. if (state.popSelectYearList.length > 1) {
  97. state.searchForm.gradeYear = state.popSelectYearList[1].id;
  98. }
  99. getList();
  100. setCache({ current: state.searchForm, saveKey: route.path });
  101. };
  102. const removeClass = async () => {
  103. try {
  104. await deleteClass({ ids: state.removeRow.id });
  105. getList();
  106. message.success(`删除成功`);
  107. state.removeVisiable = false;
  108. } catch (e) {
  109. console.log(e);
  110. }
  111. };
  112. const getList = async () => {
  113. // classGroupList
  114. state.loading = true;
  115. try {
  116. const res = await classGroupList({
  117. ...state.searchForm,
  118. ...state.pagination
  119. });
  120. state.tableList = res.data.rows;
  121. state.pagination.pageTotal = res.data.total;
  122. state.loading = false;
  123. setTimeout(() => {
  124. if (state.tableList.length > 0) {
  125. showGuide.value = true;
  126. }
  127. }, 500);
  128. } catch (e) {
  129. state.loading = false;
  130. console.log(e);
  131. }
  132. };
  133. // const getSubjectList = async () => {
  134. // const res = await getSubject({ page: 1, rows: 9999 });
  135. // state.subjectList = res.data.rows.map((item: any) => {
  136. // return {
  137. // value: item.id,
  138. // label: item.name
  139. // };
  140. // });
  141. // state.subjectList.unshift({ value: '', label: '全部声部' });
  142. // };
  143. const columns = () => {
  144. return [
  145. {
  146. title: '班级名称',
  147. key: 'name'
  148. },
  149. {
  150. title: '学年',
  151. key: 'gradeYear'
  152. },
  153. {
  154. title: '学级',
  155. key: 'gradeLevel',
  156. render(row: any) {
  157. return row.gradeLevel ? `${row.gradeLevel}级` : '';
  158. }
  159. },
  160. {
  161. title: '班级乐器',
  162. key: 'instrumentName'
  163. },
  164. {
  165. title: '学生人数',
  166. key: 'preStudentNum'
  167. },
  168. {
  169. title: '上次学习',
  170. key: 'lastStudy',
  171. width: '20%',
  172. render(row: any) {
  173. return row.lastStudy ? (
  174. <TheTooltip
  175. maxWidth={300}
  176. showContentWidth={300}
  177. content={row.lastStudy}
  178. />
  179. ) : (
  180. '--'
  181. );
  182. }
  183. },
  184. {
  185. title: '操作',
  186. key: 'id',
  187. render(row: any, index: number) {
  188. return (
  189. <div>
  190. <NSpace>
  191. {index == 0 ? (
  192. <div id="class-0">
  193. <NButton
  194. type="primary"
  195. text
  196. onClick={() => {
  197. router.push({
  198. path: '/classDetail',
  199. query: {
  200. name: row.name,
  201. id: row.id,
  202. gradeYear: row.gradeYear,
  203. upgradeFlag: row.upgradeFlag ? 1 : 0 // 是否为历史班
  204. }
  205. });
  206. }}>
  207. 详情
  208. </NButton>
  209. </div>
  210. ) : (
  211. <NButton
  212. type="primary"
  213. text
  214. onClick={() => {
  215. router.push({
  216. path: '/classDetail',
  217. query: {
  218. name: row.name,
  219. id: row.id,
  220. gradeYear: row.gradeYear,
  221. upgradeFlag: row.upgradeFlag ? 1 : 0 // 是否为历史班
  222. }
  223. });
  224. }}>
  225. 详情
  226. </NButton>
  227. )}
  228. <NButton
  229. type="primary"
  230. disabled={!row.upgradeFlag || row.instrumentId}
  231. text
  232. onClick={() => resetClassSubject(row)}>
  233. 修改乐器
  234. </NButton>
  235. {index == 0 ? (
  236. <NButton
  237. type="primary"
  238. disabled={!row.upgradeFlag}
  239. {...{ id: 'class-1' }}
  240. text
  241. onClick={() => {
  242. startResetStudent(row);
  243. }}>
  244. 学生调整
  245. </NButton>
  246. ) : (
  247. <NButton
  248. type="primary"
  249. disabled={!row.upgradeFlag}
  250. text
  251. onClick={() => {
  252. startResetStudent(row);
  253. }}>
  254. 学生调整
  255. </NButton>
  256. )}
  257. {index == 0 ? (
  258. <NButton
  259. {...{ id: 'class-2' }}
  260. disabled={!row.upgradeFlag}
  261. type="primary"
  262. text
  263. onClick={() => classesBegin(row)}>
  264. 开始上课
  265. </NButton>
  266. ) : (
  267. <NButton
  268. disabled={!row.upgradeFlag}
  269. type="primary"
  270. text
  271. onClick={() => classesBegin(row)}>
  272. 开始上课
  273. </NButton>
  274. )}
  275. {/* <p
  276. style={{ color: '#EA4132', cursor: 'pointer' }}
  277. onClick={() => {
  278. state.removeVisiable = true;
  279. state.removeRow = row;
  280. }}>
  281. 删除
  282. </p> */}
  283. {!(row.preStudentNum > 0) ? (
  284. <NButton
  285. type="error"
  286. color="#EA4132"
  287. textColor="#EA4132"
  288. text
  289. onClick={() => {
  290. state.removeVisiable = true;
  291. state.removeRow = row;
  292. }}>
  293. 删除
  294. </NButton>
  295. ) : null}
  296. {row.imGroupId ? null : (
  297. <NButton
  298. type="primary"
  299. disabled={!row.upgradeFlag}
  300. text
  301. onClick={() => {
  302. createImgroup(row);
  303. }}>
  304. 创建群聊
  305. </NButton>
  306. )}
  307. <NButton
  308. type="primary"
  309. disabled={!row.upgradeFlag}
  310. text
  311. onClick={() => {
  312. const { schoolInfos } = users.getUserInfo;
  313. const schoolId =
  314. schoolInfos.length > 0 ? schoolInfos[0].id : null;
  315. if (schoolId) {
  316. state.addStudentVisible = true;
  317. state.activeRow = {
  318. id: schoolId,
  319. classId: row.id,
  320. currentGradeNum: row.currentGradeNum,
  321. currentClass: row.currentClass,
  322. gradeYear: row.gradeYear
  323. };
  324. }
  325. }}>
  326. 邀请学生
  327. </NButton>
  328. </NSpace>
  329. </div>
  330. );
  331. }
  332. }
  333. ];
  334. };
  335. const startResetStudent = (row: any) => {
  336. state.activeRow = row;
  337. state.studentVisible = true;
  338. };
  339. const classesBegin = async (row: any) => {
  340. try {
  341. // 判断是否有声部
  342. if (row.instrumentId) {
  343. //
  344. // 声部先取上次上课的声部,如果没有则取班级上面的声部
  345. router.push({
  346. path: '/prepare-lessons',
  347. query: {
  348. lastUseCoursewareId: row.lessonCoursewareId,
  349. unit: row.lessonCoursewareKnowledgeDetailId,
  350. instrumentId: row.instrumentId,
  351. courseScheduleSubjectId: row.courseScheduleSubjectId,
  352. preStudentNum: row.preStudentNum,
  353. name: row.name, // 班级名称
  354. classGroupId: row.id // 班级编号
  355. }
  356. });
  357. } else {
  358. state.showSubjectClass = true;
  359. state.activeRow = row;
  360. }
  361. } catch (e) {
  362. console.log(e);
  363. }
  364. };
  365. const resetClassSubject = (row: any) => {
  366. state.activeRow = row;
  367. state.showResetClass = true;
  368. };
  369. const createImgroup = async (row: any) => {
  370. state.activeRow = row;
  371. state.groupVisiable = true;
  372. };
  373. const submitGroup = async () => {
  374. console.log(state.activeRow, 'row');
  375. state.groupBtnLoading = true;
  376. try {
  377. await addGroup({ classGroupId: state.activeRow.id });
  378. message.success('创建成功');
  379. state.groupVisiable = false;
  380. await getList();
  381. } catch (e) {
  382. console.log(e);
  383. }
  384. state.groupBtnLoading = false;
  385. };
  386. // 获取学年
  387. const getYearList = async () => {
  388. try {
  389. const { data } = await getGradeYearList();
  390. const temp = data || [];
  391. temp.forEach((i: any) => {
  392. i.name = i.name + '学年';
  393. });
  394. // temp.unshift({
  395. // id: '',
  396. // name: '全部学年'
  397. // });
  398. state.popSelectYearList = temp || [];
  399. if (temp.length > 1 && !state.searchForm.gradeYear) {
  400. state.searchForm.gradeYear = temp[1].id;
  401. }
  402. } catch {
  403. //
  404. }
  405. };
  406. // 获取学级
  407. const getLevelList = async () => {
  408. try {
  409. const { data } = await getGradeLevelList();
  410. const temp = data || [];
  411. temp.forEach((i: any) => {
  412. i.name = i.name + '级';
  413. });
  414. temp.unshift({
  415. id: '',
  416. name: '全部学级'
  417. });
  418. state.popSelectLevelList = temp || [];
  419. if (temp.length > 0 && !state.searchForm.gradeLevel) {
  420. state.searchForm.gradeLevel = temp[0].id;
  421. }
  422. } catch {
  423. //
  424. }
  425. };
  426. initCache({
  427. current: state.searchForm,
  428. callBack: (active: any) => {
  429. state.searchForm = active;
  430. }
  431. });
  432. onMounted(async () => {
  433. state.loading = true;
  434. await catchData.getSubjects();
  435. // getSubjectList();
  436. await getYearList();
  437. await getLevelList();
  438. await getList();
  439. state.loading = false;
  440. });
  441. return () => (
  442. <div class={styles.listWrap}>
  443. <div class={styles.searchList}>
  444. <NForm label-placement="left" inline ref={formRef}>
  445. <NFormItem>
  446. <SearchInput
  447. {...{ placeholder: '请输入班级名称' }}
  448. class={styles.searchInput}
  449. searchWord={state.searchForm.keyword}
  450. onChangeValue={(val: string) =>
  451. (state.searchForm.keyword = val)
  452. }></SearchInput>
  453. </NFormItem>
  454. <NFormItem>
  455. <CSelect
  456. {...({
  457. options: state.popSelectYearList,
  458. placeholder: '选择学年',
  459. clearable: false,
  460. inline: true,
  461. labelField: 'name',
  462. valueField: 'id'
  463. } as any)}
  464. v-model:value={state.searchForm.gradeYear}></CSelect>
  465. </NFormItem>
  466. <NFormItem>
  467. <CSelect
  468. {...({
  469. options: state.popSelectLevelList,
  470. placeholder: '选择学级',
  471. clearable: true,
  472. inline: true,
  473. labelField: 'name',
  474. valueField: 'id'
  475. } as any)}
  476. v-model:value={state.searchForm.gradeLevel}></CSelect>
  477. </NFormItem>
  478. <NFormItem>
  479. <CSelect
  480. {...({
  481. options: state.gradeNumList,
  482. placeholder: '选择年级',
  483. clearable: true,
  484. inline: true
  485. } as any)}
  486. v-model:value={state.searchForm.currentGradeNum}></CSelect>
  487. </NFormItem>
  488. <NFormItem>
  489. <CSelect
  490. {...({
  491. options: classArray,
  492. placeholder: '选择班级',
  493. clearable: true,
  494. inline: true
  495. } as any)}
  496. v-model:value={state.searchForm.currentClass}></CSelect>
  497. </NFormItem>
  498. <NFormItem>
  499. {/* <CSelect
  500. {...({
  501. options: [
  502. { value: '', label: '全部声部' },
  503. ...catchData.getSubjectList
  504. ],
  505. placeholder: '选择乐器',
  506. clearable: true,
  507. inline: true
  508. } as any)}
  509. v-model:value={state.searchForm.instrumentId}></CSelect> */}
  510. <NCascader
  511. to="body"
  512. placeholder="选择乐器"
  513. options={[
  514. { value: '', label: '全部乐器' },
  515. ...catchData.getSubjectList
  516. ]}
  517. childrenField="instruments"
  518. checkStrategy="child"
  519. expandTrigger="hover"
  520. showPath={true}
  521. v-model:value={state.searchForm.instrumentId}
  522. onUpdate:value={(val: any, option: any, pathValues: any) => {
  523. console.log(val, option, pathValues);
  524. }}
  525. />
  526. </NFormItem>
  527. <NFormItem>
  528. <NSpace justify="end">
  529. <NButton type="primary" class="searchBtn" onClick={search}>
  530. 搜索
  531. </NButton>
  532. <NButton
  533. type="primary"
  534. ghost
  535. class="resetBtn"
  536. onClick={onReset}>
  537. 重置
  538. </NButton>
  539. </NSpace>
  540. </NFormItem>
  541. </NForm>
  542. </div>
  543. <NButton
  544. class={styles.addBtn}
  545. type="primary"
  546. onClick={() => (state.showaddClass = true)}
  547. v-slots={{
  548. icon: () => (
  549. <>
  550. <NImage
  551. class={styles.addBtnIcon}
  552. previewDisabled
  553. src={add}></NImage>
  554. </>
  555. )
  556. }}>
  557. 创建班级
  558. </NButton>
  559. <div class={styles.tableWrap}>
  560. <NDataTable
  561. v-slots={{
  562. empty: () => <TheEmpty></TheEmpty>
  563. }}
  564. class={styles.classTable}
  565. loading={state.loading}
  566. columns={columns()}
  567. data={state.tableList}></NDataTable>
  568. <Pagination
  569. v-model:page={state.pagination.page}
  570. v-model:pageSize={state.pagination.rows}
  571. v-model:pageTotal={state.pagination.pageTotal}
  572. onList={getList}
  573. sync
  574. />
  575. </div>
  576. <NModal
  577. v-model:show={state.studentVisible}
  578. preset="card"
  579. class={['modalTitle background', styles.studentVisible]}
  580. title={'学生调整'}>
  581. <RestStudentBox
  582. activeRow={state.activeRow}
  583. onClose={() => (state.studentVisible = false)}
  584. onGetList={() => getList()}></RestStudentBox>
  585. </NModal>
  586. <NModal
  587. v-model:show={state.showaddClass}
  588. style={{ width: '500px' }}
  589. display-directive="if"
  590. preset="card"
  591. class={['modalTitle background']}
  592. title={'创建班级'}>
  593. <CreateClass
  594. gradeYearList={state.popSelectYearList}
  595. gradeNumList={state.gradeNumList}
  596. classArray={classArray}
  597. onGetList={() => getList()}
  598. onClose={() => (state.showaddClass = false)}
  599. />
  600. </NModal>
  601. <NModal
  602. v-model:show={state.showResetClass}
  603. style={{ width: '500px' }}
  604. display-directive="if"
  605. preset="card"
  606. class={['modalTitle background']}
  607. title={'修改乐器'}>
  608. <ResetSubject
  609. activeRow={state.activeRow}
  610. onGetList={() => getList()}
  611. onClose={() => (state.showResetClass = false)}
  612. />
  613. </NModal>
  614. <NModal
  615. v-model:show={state.showSubjectClass}
  616. style={{ width: '500px' }}
  617. preset="card"
  618. class={['modalTitle background']}
  619. title={'修改乐器'}>
  620. {state.showSubjectClass ? (
  621. <UpdateSubject
  622. activeRow={state.activeRow}
  623. onGetList={() => getList()}
  624. onConfirm={(item: any) => {
  625. //
  626. router.push({
  627. path: '/prepare-lessons',
  628. query: {
  629. ...item
  630. }
  631. });
  632. }}
  633. onClose={() => (state.showSubjectClass = false)}
  634. />
  635. ) : null}
  636. </NModal>
  637. {/* 上课弹窗 */}
  638. <PreviewWindow
  639. v-model:show={state.previewModal}
  640. type="attend"
  641. params={state.previewParams}
  642. />
  643. <NModal
  644. v-model:show={state.removeVisiable}
  645. preset="card"
  646. class={['modalTitle', styles.removeVisiable]}
  647. title={'删除班级'}>
  648. <div class={styles.studentRemove}>
  649. <p>
  650. 确定要删除班级么?
  651. <span>删除班级信息将会清空</span>。
  652. </p>
  653. <NSpace class={styles.btnGroup} justify="center">
  654. <NButton round type="primary" onClick={removeClass}>
  655. 确定
  656. </NButton>
  657. <NButton round onClick={() => (state.removeVisiable = false)}>
  658. 取消
  659. </NButton>
  660. </NSpace>
  661. </div>
  662. </NModal>
  663. <NModal
  664. v-model:show={state.groupVisiable}
  665. preset="card"
  666. class={['modalTitle', styles.removeVisiable]}
  667. title={'创建群聊'}>
  668. <div class={styles.studentRemove}>
  669. <p style={{ textAlign: 'center' }}>是否创建班级群聊</p>
  670. <NSpace class={styles.btnGroup} justify="center">
  671. <NButton
  672. round
  673. type="primary"
  674. onClick={submitGroup}
  675. loading={state.groupBtnLoading}
  676. disabled={state.groupBtnLoading}>
  677. 确定
  678. </NButton>
  679. <NButton round onClick={() => (state.groupVisiable = false)}>
  680. 取消
  681. </NButton>
  682. </NSpace>
  683. </div>
  684. </NModal>
  685. {showGuide.value ? <ClassGuide></ClassGuide> : null}
  686. {state.addStudentVisible ? (
  687. <div
  688. v-model:show={state.addStudentVisible}
  689. class={['n-modal-mask', styles.popBox]}>
  690. <AddStudentModel
  691. activeRow={state.activeRow}
  692. onClose={() => {
  693. state.addStudentVisible = false;
  694. }}></AddStudentModel>
  695. </div>
  696. ) : null}
  697. </div>
  698. );
  699. }
  700. });