index.tsx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import {
  4. NButton,
  5. NDataTable,
  6. NForm,
  7. NFormItem,
  8. NImage,
  9. NModal,
  10. NSelect,
  11. NSpace,
  12. NTooltip,
  13. useMessage
  14. } from 'naive-ui';
  15. import SearchInput from '@/components/searchInput';
  16. import CSelect from '@/components/CSelect';
  17. import Pagination from '@/components/pagination';
  18. import add from './images/add.png';
  19. import { useRoute, useRouter } from 'vue-router';
  20. import { getStudentList, schoolDetail } from './api';
  21. import { classGroupList } from '@/views/classList/api';
  22. import AddStudentModel from './modals/addStudentModel';
  23. import Studentguide from '@/custom-plugins/guide-page/student-guide';
  24. import TheEmpty from '/src/components/TheEmpty';
  25. // import NoticeModal from './modals/noticeModal';
  26. import { useUserStore } from '/src/store/modules/users';
  27. import UpdateStudent from './modals/update-student';
  28. import { initCache, setCache } from '/src/hooks/use-async';
  29. import { classArray, getgradeNumList } from '../classList/contants';
  30. import { getGradeLevelList, getGradeYearList } from '../home/api';
  31. export default defineComponent({
  32. name: 'student-studentList',
  33. setup(props, { emit }) {
  34. const userStore = useUserStore();
  35. const state = reactive({
  36. searchForm: {
  37. keyword: '',
  38. gender: '' as any,
  39. classGroupId: '' as any,
  40. membership: '' as any,
  41. currentClass: '' as any,
  42. currentGradeNum: '' as any,
  43. gradeYear: '' as any,
  44. gradeLevel: ''
  45. },
  46. gradeNumList: [] as any,
  47. searchWord: '',
  48. orchestraType: null,
  49. courseTypeCode: null,
  50. subjectId: null,
  51. classId: null,
  52. studentType: null,
  53. loading: false,
  54. pagination: {
  55. page: 1,
  56. rows: 10,
  57. pageTotal: 4
  58. },
  59. tableList: [] as any,
  60. classList: [],
  61. addStudentVisible: false,
  62. editStatus: false,
  63. activeRow: {} as any,
  64. popSelectYearList: [] as any,
  65. popSelectLevelList: [] as any
  66. });
  67. state.gradeNumList = getgradeNumList();
  68. const route = useRoute();
  69. const router = useRouter();
  70. const showGuide = ref(false);
  71. const message = useMessage();
  72. const search = () => {
  73. state.pagination.page = 1;
  74. getList();
  75. setCache({ current: state.searchForm, saveKey: route.path });
  76. };
  77. const getClasslist = async () => {
  78. try {
  79. const res = await classGroupList({ page: 1, rows: 999 });
  80. state.classList = res.data.rows.map((item: any) => {
  81. return {
  82. label: item.name,
  83. value: item.id
  84. };
  85. });
  86. } catch (e) {
  87. console.log(e);
  88. }
  89. };
  90. const copyTo = (text: string) => {
  91. const input = document.createElement('input');
  92. input.value = text;
  93. document.body.appendChild(input);
  94. input.select();
  95. input.setSelectionRange(0, input.value.length);
  96. document.execCommand('Copy');
  97. document.body.removeChild(input);
  98. message.success('复制成功');
  99. };
  100. const onReset = () => {
  101. state.searchForm = {
  102. keyword: '',
  103. gender: '' as any,
  104. classGroupId: '' as any,
  105. membership: '' as any,
  106. currentClass: '' as any,
  107. currentGradeNum: '' as any,
  108. gradeYear: '' as any,
  109. gradeLevel: ''
  110. };
  111. if (state.popSelectYearList.length > 0) {
  112. state.searchForm.gradeYear = state.popSelectYearList[0].id;
  113. }
  114. search();
  115. setCache({ current: state.searchForm, saveKey: route.path });
  116. };
  117. initCache({
  118. current: state.searchForm,
  119. callBack: (active: any) => {
  120. state.searchForm = active;
  121. }
  122. });
  123. const getList = async () => {
  124. try {
  125. const res = await getStudentList({
  126. ...state.searchForm,
  127. ...state.pagination
  128. });
  129. state.tableList = res.data.rows;
  130. state.pagination.pageTotal = res.data.total;
  131. if (state.tableList.length > 0) {
  132. setTimeout(() => {
  133. showGuide.value = true;
  134. }, 500);
  135. }
  136. } catch (e) {
  137. console.log(e);
  138. }
  139. console.log('getList');
  140. };
  141. // 获取学年
  142. const getYearList = async () => {
  143. try {
  144. const { data } = await getGradeYearList();
  145. const temp = data || [];
  146. temp.forEach((i: any) => {
  147. i.name = i.name + '学年';
  148. });
  149. // temp.unshift({
  150. // id: '',
  151. // name: '全部学年'
  152. // });
  153. state.popSelectYearList = temp || [];
  154. if (temp.length > 0 && !state.searchForm.gradeYear) {
  155. state.searchForm.gradeYear = temp[0].id;
  156. }
  157. } catch {
  158. //
  159. }
  160. };
  161. // 获取学级
  162. const getLevelList = async () => {
  163. try {
  164. const { data } = await getGradeLevelList();
  165. const temp = data || [];
  166. temp.forEach((i: any) => {
  167. i.name = i.name + '级';
  168. });
  169. temp.unshift({
  170. id: '',
  171. name: '全部学级'
  172. });
  173. state.popSelectLevelList = temp || [];
  174. if (temp.length > 0 && !state.searchForm.gradeLevel) {
  175. state.searchForm.gradeLevel = temp[0].id;
  176. }
  177. } catch {
  178. //
  179. }
  180. };
  181. onMounted(async () => {
  182. state.loading = true;
  183. await getYearList();
  184. await getLevelList();
  185. await getList();
  186. await getClasslist();
  187. state.loading = false;
  188. });
  189. const columns = () => {
  190. return [
  191. {
  192. title: '学生姓名',
  193. key: 'nickname',
  194. render: (row: any) => {
  195. return (
  196. <NTooltip showArrow={false} placement="top-start">
  197. {{
  198. trigger: () => (
  199. <div
  200. style={{ userSelect: 'all', cursor: 'pointer' }}
  201. onClick={() => copyTo(row.nickname)}>
  202. {row.nickname}
  203. </div>
  204. ),
  205. default: '点击复制'
  206. }}
  207. </NTooltip>
  208. );
  209. }
  210. },
  211. {
  212. title: '手机号',
  213. key: 'phone',
  214. render: (row: any) => {
  215. return (
  216. <NTooltip showArrow={false} placement="top-start">
  217. {{
  218. trigger: () => (
  219. <div
  220. style={{ userSelect: 'all', cursor: 'pointer' }}
  221. onClick={() => copyTo(row.phone)}>
  222. {row.phone}
  223. </div>
  224. ),
  225. default: '点击复制'
  226. }}
  227. </NTooltip>
  228. );
  229. }
  230. },
  231. {
  232. title: '性别',
  233. key: 'gender',
  234. render(row: any) {
  235. return (
  236. <>
  237. {row.gender + '' != 'null'
  238. ? row.gender == '0'
  239. ? '女'
  240. : '男'
  241. : '--'}
  242. </>
  243. );
  244. }
  245. },
  246. {
  247. title: '年级班级',
  248. key: 'classGroupName'
  249. },
  250. {
  251. title: '学生类型',
  252. key: 'vipMember',
  253. render(row: any) {
  254. return <>{row.vipMember ? '会员' : '普通'}</>;
  255. }
  256. },
  257. {
  258. title: '操作',
  259. key: 'id',
  260. width: 300,
  261. render(row: any, index: number) {
  262. return (
  263. <NSpace>
  264. {index == 0 ? (
  265. <NButton
  266. {...{ id: 'student-1' }}
  267. text
  268. type="primary"
  269. onClick={() => gotoDetail(row)}>
  270. 详情
  271. </NButton>
  272. ) : (
  273. <NButton text type="primary" onClick={() => gotoDetail(row)}>
  274. 详情
  275. </NButton>
  276. )}
  277. <NButton
  278. text
  279. type="primary"
  280. onClick={() => onUpdate(row)}
  281. disabled={row.historyClassStudent}>
  282. 修改
  283. </NButton>
  284. </NSpace>
  285. );
  286. }
  287. }
  288. ];
  289. };
  290. const gotoDetail = (row: any) => {
  291. router.push({
  292. path: '/studentDetail',
  293. query: { ...route.query, studentId: row.id, studentName: row.nickname }
  294. });
  295. };
  296. // 修改
  297. const onUpdate = (row: any) => {
  298. state.editStatus = true;
  299. state.activeRow = row;
  300. };
  301. return () => (
  302. <div class={styles.listWrap}>
  303. <div class={styles.searchList}>
  304. <NForm label-placement="left" inline>
  305. <NFormItem>
  306. <SearchInput
  307. {...{ placeholder: '请输入学生姓名' }}
  308. class={styles.searchInput}
  309. style={{ width: '160px' }}
  310. searchWord={state.searchForm.keyword}
  311. onChangeValue={(val: string) =>
  312. (state.searchForm.keyword = val)
  313. }></SearchInput>
  314. </NFormItem>
  315. <NFormItem>
  316. <CSelect
  317. {...({
  318. options: [
  319. {
  320. label: '全部性别',
  321. value: ''
  322. },
  323. {
  324. label: '男',
  325. value: 1
  326. },
  327. {
  328. label: '女',
  329. value: 0
  330. }
  331. ],
  332. placeholder: '性别',
  333. clearable: true,
  334. inline: true
  335. } as any)}
  336. v-model:value={state.searchForm.gender}></CSelect>
  337. </NFormItem>
  338. <NFormItem>
  339. <CSelect
  340. {...({
  341. options: state.popSelectYearList,
  342. placeholder: '选择学年',
  343. clearable: false,
  344. inline: true,
  345. labelField: 'name',
  346. valueField: 'id'
  347. } as any)}
  348. v-model:value={state.searchForm.gradeYear}></CSelect>
  349. </NFormItem>
  350. <NFormItem>
  351. <CSelect
  352. {...({
  353. options: state.popSelectLevelList,
  354. placeholder: '选择学级',
  355. clearable: true,
  356. inline: true,
  357. labelField: 'name',
  358. valueField: 'id'
  359. } as any)}
  360. v-model:value={state.searchForm.gradeLevel}></CSelect>
  361. </NFormItem>
  362. <NFormItem>
  363. <CSelect
  364. {...({
  365. options: state.gradeNumList,
  366. placeholder: '选择年级',
  367. clearable: true,
  368. inline: true
  369. } as any)}
  370. v-model:value={state.searchForm.currentGradeNum}></CSelect>
  371. </NFormItem>
  372. <NFormItem>
  373. <CSelect
  374. {...({
  375. options: classArray,
  376. placeholder: '选择班级',
  377. clearable: true,
  378. inline: true
  379. } as any)}
  380. v-model:value={state.searchForm.currentClass}></CSelect>
  381. </NFormItem>
  382. {/* <NFormItem>
  383. <CSelect
  384. {...({
  385. options: [
  386. { label: '全部年级班级', value: '' },
  387. ...state.classList
  388. ],
  389. placeholder: '年级班级',
  390. clearable: true,
  391. inline: true
  392. } as any)}
  393. v-model:value={state.searchForm.classGroupId}></CSelect>
  394. </NFormItem> */}
  395. <NFormItem>
  396. <CSelect
  397. {...({
  398. options: [
  399. {
  400. label: '全部类型',
  401. value: ''
  402. },
  403. {
  404. label: '会员',
  405. value: true
  406. },
  407. {
  408. label: '普通',
  409. value: false
  410. }
  411. ],
  412. placeholder: '学生类型',
  413. clearable: true,
  414. inline: true
  415. } as any)}
  416. v-model:value={state.searchForm.membership}></CSelect>
  417. </NFormItem>
  418. <NFormItem>
  419. <NSpace justify="end">
  420. <NButton type="primary" class="searchBtn" onClick={search}>
  421. 搜索
  422. </NButton>
  423. <NButton
  424. type="primary"
  425. ghost
  426. class="resetBtn"
  427. onClick={onReset}>
  428. 重置
  429. </NButton>
  430. </NSpace>
  431. </NFormItem>
  432. </NForm>
  433. </div>
  434. {/* <NButton
  435. {...{ id: 'student-0' }}
  436. onClick={async () => {
  437. // state.addStudentVisible = true;
  438. try {
  439. const { schoolInfos } = userStore.getUserInfo;
  440. const schoolId =
  441. schoolInfos.length > 0 ? schoolInfos[0].id : null;
  442. if (schoolId) {
  443. const { data } = await schoolDetail({ id: schoolId });
  444. state.activeRow = data;
  445. state.addStudentVisible = true;
  446. }
  447. } catch {
  448. //
  449. }
  450. }}
  451. class={styles.addBtn}
  452. type="primary"
  453. v-slots={{
  454. icon: () => (
  455. <>
  456. <NImage
  457. class={styles.addBtnIcon}
  458. previewDisabled
  459. src={add}></NImage>
  460. </>
  461. )
  462. }}>
  463. 邀请学生
  464. </NButton> */}
  465. <div class={styles.tableWrap}>
  466. <NDataTable
  467. v-slots={{
  468. empty: () => <TheEmpty></TheEmpty>
  469. }}
  470. class={styles.classTable}
  471. loading={state.loading}
  472. columns={columns()}
  473. data={state.tableList}></NDataTable>
  474. <Pagination
  475. v-model:page={state.pagination.page}
  476. v-model:pageSize={state.pagination.rows}
  477. v-model:pageTotal={state.pagination.pageTotal}
  478. onList={getList}
  479. sync
  480. />
  481. </div>
  482. {state.addStudentVisible ? (
  483. <div v-model:show={state.addStudentVisible} class="n-modal-mask">
  484. <AddStudentModel
  485. activeRow={state.activeRow}
  486. onClose={() => {
  487. state.addStudentVisible = false;
  488. }}></AddStudentModel>
  489. </div>
  490. ) : null}
  491. {/* <NModal
  492. v-model:show={state.addStudentVisible}
  493. showIcon={false}
  494. style={{ width: '400px' }}>
  495. <NoticeModal
  496. data={state.activeRow}
  497. onClose={() => (state.addStudentVisible = false)}
  498. />
  499. </NModal> */}
  500. <NModal
  501. v-model:show={state.editStatus}
  502. class={['modalTitle background', styles.updateStudent]}
  503. preset="card"
  504. title="修改信息">
  505. <UpdateStudent
  506. onClose={() => (state.editStatus = false)}
  507. onConfirm={() => getList()}
  508. row={state.activeRow}
  509. />
  510. </NModal>
  511. {showGuide.value ? <Studentguide></Studentguide> : null}
  512. </div>
  513. );
  514. }
  515. });