exercis-detail.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import OHeader from '@/components/m-header';
  2. import OSticky from '@/components/m-sticky';
  3. import OEmpty from '@/components/m-empty';
  4. import dayjs from 'dayjs';
  5. import { DatePicker, Popup, List, Image, CellGroup, Cell } from 'vant';
  6. import OFullRefresh from '@/components/m-full-refresh';
  7. import DetailItem from './modals/detail-item';
  8. import { defineComponent, onMounted, reactive, ref, nextTick } from 'vue';
  9. import { useRoute } from 'vue-router';
  10. import styles from './exercis-detail.module.less';
  11. import request from '@/helpers/request';
  12. import iconStudent from '@common/images/icon-student.png';
  13. import iconData from './images/icon-data.png';
  14. import { useRect } from '@vant/use';
  15. import { formatterDatePicker } from '@/helpers/utils';
  16. import { useEventListener, useWindowScroll } from '@vueuse/core';
  17. import { state as baseState } from '@/state';
  18. import iconClock from './images/icon-clock.png';
  19. import iconDays from './images/icon-days.png';
  20. export default defineComponent({
  21. name: 'exercis-detail',
  22. setup() {
  23. const route = useRoute();
  24. const state = reactive({
  25. showPopoverTime: false,
  26. currentDate: [dayjs().format('YYYY'), dayjs().format('MM')],
  27. isClick: false,
  28. background: 'transparent',
  29. practiceMonthName: route.query.practiceMonthName
  30. ? route.query.practiceMonthName
  31. : dayjs().format('YYYY') + '年' + dayjs().format('MM') + '月'
  32. });
  33. const forms = reactive({
  34. practiceMonth: route.query.practiceMonth
  35. ? route.query.practiceMonth
  36. : state.currentDate[0] + '' + state.currentDate[1],
  37. page: 1,
  38. rows: 20
  39. });
  40. const refreshing = ref(false);
  41. const loading = ref(false);
  42. const finished = ref(false);
  43. const showContact = ref(false);
  44. const infoDetail = ref({} as any);
  45. const list = ref([]);
  46. const getList = async () => {
  47. if (state.isClick) {
  48. return;
  49. }
  50. state.isClick = true;
  51. if (refreshing.value) {
  52. list.value = [];
  53. forms.page = 1;
  54. refreshing.value = false;
  55. }
  56. try {
  57. const res = await request.post(`/edu-app/musicPracticeRecord/page`, {
  58. data: { ...forms, feature: 'EVALUATION' }
  59. });
  60. if (list.value.length > 0 && res.data.current === 1) {
  61. return;
  62. }
  63. list.value = list.value.concat(res.data.rows || []);
  64. forms.page = res.data.current + 1;
  65. showContact.value = list.value.length > 0;
  66. loading.value = false;
  67. finished.value = res.data.current >= res.data.pages;
  68. } catch {
  69. showContact.value = false;
  70. finished.value = true;
  71. }
  72. state.isClick = false;
  73. };
  74. const getDetail = async () => {
  75. try {
  76. const res = await request.get(`/edu-app/student/detail`, {
  77. params: {
  78. id: baseState.user.data?.id
  79. }
  80. });
  81. infoDetail.value = { ...res.data };
  82. } catch (e: any) {}
  83. };
  84. const topWrap = ref();
  85. const topWrapHeight = ref(0);
  86. onMounted(async () => {
  87. useEventListener(document, 'scroll', () => {
  88. const { y } = useWindowScroll();
  89. if (y.value > 52) {
  90. state.background = '#fff';
  91. // state.color = '#323333';
  92. } else {
  93. state.background = 'transparent';
  94. // state.color = '#fff';
  95. }
  96. });
  97. await getList();
  98. await getDetail();
  99. nextTick(() => {
  100. const { height } = useRect(topWrap.value);
  101. topWrapHeight.value = height;
  102. });
  103. });
  104. const checkTimer = (val: any) => {
  105. forms.practiceMonth = val.selectedValues[0] + val.selectedValues[1];
  106. state.practiceMonthName =
  107. val.selectedValues[0] + '年' + val.selectedValues[1] + '月';
  108. state.showPopoverTime = false;
  109. refreshing.value = true;
  110. getList();
  111. };
  112. const onRefresh = () => {
  113. finished.value = false;
  114. // 重新加载数据
  115. // 将 loading 设置为 true,表示处于加载状态
  116. loading.value = true;
  117. getList();
  118. };
  119. return () => (
  120. <>
  121. <div class={[styles.exercisContainer]}>
  122. <div class={styles.topWrap} ref={topWrap}>
  123. <OSticky position="top">
  124. <OHeader
  125. border={false}
  126. background={state.background}
  127. // color={state.color}
  128. />
  129. </OSticky>
  130. <div class={styles.topInfo}>
  131. <div class={styles.topInfoLeft}>
  132. <div class={styles.headWrap}>
  133. <Image
  134. src={
  135. infoDetail.value.avatar
  136. ? infoDetail.value.avatar
  137. : iconStudent
  138. }
  139. fit="cover"
  140. class={styles.headerImg}
  141. />
  142. </div>
  143. <div class={styles.infoMsg}>
  144. <p>{infoDetail.value.nickname}</p>
  145. <div class={styles.tag}>
  146. {infoDetail.value.instrumentName
  147. ? infoDetail.value.instrumentName
  148. : // + infoDetail.value.classGroupName
  149. '暂无乐器'}
  150. </div>
  151. </div>
  152. </div>
  153. </div>
  154. <div class={styles.topInfoRight}>
  155. <div class={styles.infoDay}>
  156. <p class={styles.infoDayMain}>
  157. {infoDetail.value.practiceDays
  158. ? infoDetail.value.practiceDays
  159. : 0}
  160. {/* <span>天</span> */}
  161. </p>
  162. <p class={styles.infoDaysub}>
  163. <img src={iconDays} />
  164. 练习天数(天)
  165. </p>
  166. </div>
  167. <div class={styles.infoTime}>
  168. <p class={styles.infoDayMain}>
  169. {infoDetail.value.practiceTimes
  170. ? Math.floor(infoDetail.value.practiceTimes / 60)
  171. : 0}
  172. {/* <span>分钟</span> */}
  173. </p>
  174. <p class={styles.infoDaysub}>
  175. <img src={iconClock} />
  176. 练习时长(分钟)
  177. </p>
  178. </div>
  179. </div>
  180. <CellGroup inset>
  181. <Cell
  182. class={styles.select}
  183. center
  184. isLink
  185. onClick={() => (state.showPopoverTime = true)}>
  186. {{
  187. // icon: () => <img class={styles.icon} src={iconData} />,
  188. title: () => (
  189. <div class="van-ellipsis">{state.practiceMonthName}</div>
  190. )
  191. }}
  192. </Cell>
  193. </CellGroup>
  194. </div>
  195. {showContact.value ? (
  196. <OFullRefresh
  197. v-model:modelValue={refreshing.value}
  198. onRefresh={onRefresh}
  199. style={{ minHeight: `calc(100vh - ${topWrapHeight.value}px)` }}>
  200. <List
  201. loading-text=" "
  202. finished={finished.value}
  203. finished-text=" "
  204. onLoad={getList}>
  205. {list.value.map((item: any) => (
  206. <DetailItem item={item} />
  207. ))}
  208. </List>
  209. </OFullRefresh>
  210. ) : (
  211. <OEmpty
  212. description="暂无学练统计"
  213. style={{ height: `calc(100vh - ${topWrapHeight.value}px)` }}
  214. />
  215. )}
  216. </div>
  217. <Popup
  218. v-model:show={state.showPopoverTime}
  219. position="bottom"
  220. round
  221. class={'popupBottomSearch'}>
  222. <DatePicker
  223. onCancel={() => {
  224. state.showPopoverTime = false;
  225. }}
  226. onConfirm={checkTimer}
  227. v-model={state.currentDate}
  228. formatter={formatterDatePicker}
  229. columnsType={['year', 'month']}
  230. />
  231. </Popup>
  232. </>
  233. );
  234. }
  235. });