exercis-detail.tsx 7.8 KB

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