index.tsx 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import { defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from './index.module.less';
  3. import MSticky from '@/components/m-sticky';
  4. import MHeader from '@/components/m-header';
  5. import MSearch from '@/components/m-search';
  6. import SkeletonModal from './skeleton-modal';
  7. import { Cell, CellGroup, DropdownItem, DropdownMenu, Image, List } from 'vant';
  8. import { useRouter } from 'vue-router';
  9. import MFullRefresh from '@/components/m-full-refresh';
  10. import request from '@/helpers/request';
  11. import iconTeacher from '@/common/images/icon-student-default.png';
  12. import MEmpty from '@/components/m-empty';
  13. import { coursesType } from '@/helpers/constant';
  14. import DropDownModal from './drop-down-modal';
  15. import dayjs from 'dayjs';
  16. import DropDownMoreModal from './drop-down-more-modal';
  17. export default defineComponent({
  18. name: 'student-leave-record',
  19. setup() {
  20. const dropDownItemRef = ref();
  21. const dropDownItemRef1 = ref();
  22. const router = useRouter();
  23. const forms = reactive({
  24. listState: {
  25. loading: true,
  26. dataShow: true,
  27. finished: false,
  28. refreshing: false
  29. },
  30. isClick: false,
  31. params: {
  32. createTime: [dayjs().format('YYYY'), dayjs().format('MM')],
  33. musicGroupIds: '',
  34. classGroupType: '',
  35. courseScheduleType: '',
  36. search: '',
  37. page: 1,
  38. rows: 20
  39. },
  40. orchestraColumns: [] as any,
  41. list: []
  42. });
  43. const onDropDownClose = (item: any) => {
  44. item.value && item.value.toggle();
  45. };
  46. const getList = async () => {
  47. try {
  48. if (forms.isClick) return;
  49. forms.isClick = true;
  50. const { createTime, ...res } = forms.params;
  51. const startTime = createTime.join('-') + '-01';
  52. const endTime = dayjs(startTime).endOf('month').format('YYYY-MM-DD');
  53. const { data } = await request.post(
  54. '/api-web/schoolStudentHomework/queryStudentLeave',
  55. {
  56. data: {
  57. ...res,
  58. startTime,
  59. endTime
  60. }
  61. }
  62. );
  63. const result = data || {};
  64. // 判断是否有数据
  65. if (forms.listState.refreshing) {
  66. forms.list = result.rows || [];
  67. } else {
  68. forms.list = forms.list.concat(result.rows || []);
  69. }
  70. forms.listState.finished = result.pageNo >= result.totalPage;
  71. forms.params.page = result.pageNo + 1;
  72. } catch {
  73. // forms.listState.finished = true;
  74. } finally {
  75. forms.listState.dataShow = forms.list.length > 0;
  76. forms.listState.refreshing = false;
  77. forms.listState.loading = false;
  78. forms.isClick = false;
  79. }
  80. };
  81. const formatTime = (time: string) => {
  82. if (!time) {
  83. return '';
  84. }
  85. return time.substring(0, 5);
  86. };
  87. const onRefresh = () => {
  88. forms.params.page = 1;
  89. getList();
  90. };
  91. // 乐团列表
  92. const musicGroupPage = async () => {
  93. try {
  94. const { data } = await request.get(
  95. '/api-web/cooperationOrgan/musicGroupPage'
  96. );
  97. (data || []).forEach((item: any) => {
  98. forms.orchestraColumns.push({
  99. text: item.name,
  100. value: item.id
  101. });
  102. });
  103. } catch {
  104. //
  105. }
  106. };
  107. onMounted(() => {
  108. musicGroupPage();
  109. getList();
  110. });
  111. return () => (
  112. <div class={styles.studentLeaveRecord}>
  113. <MSticky position="top">
  114. <MHeader />
  115. <MSearch
  116. placeholder="请输入学员姓名/手机号"
  117. onSearch={(val: string) => {
  118. forms.params.search = val;
  119. forms.listState.dataShow = true;
  120. forms.listState.refreshing = true;
  121. forms.list = [];
  122. onRefresh();
  123. }}
  124. />
  125. <DropdownMenu>
  126. <DropdownItem
  127. ref={dropDownItemRef}
  128. title={forms.params.createTime.join('-')}>
  129. <DropDownModal
  130. selectValues={forms.params.createTime}
  131. open={dropDownItemRef.value.state.showPopup}
  132. onDropDownClose={() => onDropDownClose(dropDownItemRef)}
  133. onDropDownConfirm={(values: any) => {
  134. forms.params.createTime = values;
  135. onDropDownClose(dropDownItemRef);
  136. forms.listState.dataShow = true;
  137. forms.listState.refreshing = true;
  138. forms.list = [];
  139. onRefresh();
  140. }}
  141. />
  142. </DropdownItem>
  143. <DropdownItem ref={dropDownItemRef1} title={'筛选'}>
  144. <DropDownMoreModal
  145. selectValues={{
  146. musicGroupIds: forms.params.musicGroupIds,
  147. classGroupType: forms.params.classGroupType,
  148. courseScheduleType: forms.params.courseScheduleType
  149. }}
  150. columns={forms.orchestraColumns}
  151. open={dropDownItemRef1.value.state.showPopup}
  152. onDropDownClose={() => onDropDownClose(dropDownItemRef1)}
  153. onDropDownConfirm={(values: any) => {
  154. forms.params.musicGroupIds = values.musicGroupIds;
  155. forms.params.classGroupType = values.classGroupType;
  156. forms.params.courseScheduleType = values.courseScheduleType;
  157. onDropDownClose(dropDownItemRef1);
  158. forms.listState.refreshing = true;
  159. forms.listState.dataShow = true;
  160. forms.list = [];
  161. onRefresh();
  162. }}
  163. />
  164. </DropdownItem>
  165. </DropdownMenu>
  166. </MSticky>
  167. <SkeletonModal v-model:show={forms.listState.loading}>
  168. <MFullRefresh
  169. v-model:modelValue={forms.listState.refreshing}
  170. onRefresh={() => onRefresh()}
  171. style={{
  172. minHeight: `calc(100vh - var(--header-height))`
  173. }}>
  174. <List
  175. finished={forms.listState.finished}
  176. finishedText=" "
  177. style={{ overflow: 'hidden' }}
  178. onLoad={getList}
  179. immediateCheck={false}>
  180. <div class={styles.cellGroup}>
  181. {forms.listState.dataShow ? (
  182. forms.list.map((item: any) => (
  183. <CellGroup class={styles.cellGroupIn}>
  184. <Cell center clickable={false} class={styles.cell}>
  185. {{
  186. icon: () => (
  187. <Image
  188. src={item.avatar || iconTeacher}
  189. fit="cover"
  190. class={styles.iconTeacher}
  191. />
  192. ),
  193. title: () => (
  194. <div class={styles.username}>
  195. <p class={styles.name}>
  196. {coursesType[item.courseScheduleType]}·
  197. {item.classGroupName}
  198. </p>
  199. <p class={styles.class}>
  200. <span class={styles.userName}>
  201. {item.username}
  202. </span>
  203. {item.phone && <span>{item.phone}</span>}
  204. </p>
  205. </div>
  206. )
  207. }}
  208. </Cell>
  209. <Cell
  210. center
  211. clickable={false}
  212. class={styles.cell}
  213. titleClass={styles.cellInfo}>
  214. {{
  215. title: () => (
  216. <div class={styles.info}>
  217. <div class={[styles.times, styles.time1]}>
  218. <span class={styles.title}>课程时间</span>
  219. <span>
  220. {item.classDate}{' '}
  221. {formatTime(item.endClassTime)}-
  222. {formatTime(item.startClassTime)}
  223. </span>
  224. </div>
  225. <div class={[styles.times]}>
  226. <span class={styles.title}>提交时间</span>
  227. <span>{item.leaveTime}</span>
  228. </div>
  229. {item.remark && (
  230. <div class={styles.remark}>
  231. <div class={styles.remarkTitle}>请假事由</div>
  232. <p>{item.remark}</p>
  233. </div>
  234. )}
  235. </div>
  236. )
  237. }}
  238. </Cell>
  239. </CellGroup>
  240. ))
  241. ) : (
  242. <MEmpty
  243. style={{
  244. minHeight: `calc(100vh - var(--header-height))`
  245. }}
  246. description="暂无学员请假统计"
  247. />
  248. )}
  249. </div>
  250. </List>
  251. </MFullRefresh>
  252. </SkeletonModal>
  253. </div>
  254. );
  255. }
  256. });