index.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. import OHeader from '@/components/o-header'
  2. import OSticky from '@/components/o-sticky'
  3. import OEmpty from '@/components/o-empty'
  4. import dayjs from 'dayjs'
  5. import isBetween from 'dayjs/plugin/isBetween'
  6. dayjs.extend(isBetween)
  7. import {
  8. Cell,
  9. Icon,
  10. List,
  11. showToast,
  12. Image,
  13. DropdownMenu,
  14. DropdownItem,
  15. Button,
  16. Calendar,
  17. CellGroup
  18. } from 'vant'
  19. import OFullRefresh from '@/components/o-full-refresh'
  20. import { defineComponent, reactive, ref, onMounted } from 'vue'
  21. import { state as globalState } from '@/state'
  22. import { useRouter } from 'vue-router'
  23. import styles from './index.module.less'
  24. import request from '@/helpers/request'
  25. import iconTeacher from '@common/images/icon_teacher.png'
  26. import { courseEmnu } from '@/constant'
  27. export default defineComponent({
  28. name: 'exercise-record',
  29. setup() {
  30. const platformApi = ref(globalState.platformApi)
  31. const router = useRouter()
  32. const state = reactive({
  33. showSearchStatus: true,
  34. showPopoverTime: false,
  35. actions: [] as any,
  36. subjects: [] as any
  37. })
  38. const forms = reactive({
  39. startTime: dayjs().day(1).format('YYYY-MM-DD'),
  40. endTime: dayjs().day(7).format('YYYY-MM-DD'),
  41. orchestraId: '',
  42. orchestraName: '',
  43. courseType: '',
  44. courseTypeName: '',
  45. coursewareErr: null,
  46. coursewareErrName: '',
  47. keyword: '',
  48. page: 1,
  49. rows: 20
  50. })
  51. const refreshing = ref(false)
  52. const loading = ref(false)
  53. const finished = ref(false)
  54. const showContact = ref(true)
  55. const list = ref([])
  56. const getList = async () => {
  57. loading.value = true
  58. try {
  59. if (refreshing.value) {
  60. forms.page = 1
  61. list.value = []
  62. refreshing.value = false
  63. }
  64. const { endTime, startTime, ...re } = forms
  65. const res = await request.post(`${platformApi.value}/courseSchedule/coursewareErrPage`, {
  66. data: { ...re, endTime: endTime + ' 23:59:59', startTime: startTime + ' 00:00:00' }
  67. })
  68. if (list.value.length > 0 && res.data.pages === 1) {
  69. return
  70. }
  71. forms.page = res.data.current + 1
  72. list.value = list.value.concat(res.data.rows || [])
  73. showContact.value = list.value.length > 0
  74. // console.log(showContact.value, ' showContact.value ')
  75. loading.value = false
  76. finished.value = res.data.current >= res.data.pages
  77. } catch (e: any) {
  78. // console.log(e, 'e')
  79. const message = e.message
  80. showToast(message)
  81. showContact.value = false
  82. finished.value = true
  83. }
  84. }
  85. onMounted(() => {
  86. getList()
  87. getOrchestraList()
  88. // getSubjects()
  89. })
  90. const onBack = () => {
  91. router.go(-1)
  92. }
  93. const checkSort = (val: any) => {
  94. console.log(val, 'val')
  95. forms.coursewareErr = val.value
  96. forms.coursewareErrName = val.name
  97. }
  98. const checkOrchestra = (val: any) => {
  99. forms.orchestraId = val.value
  100. forms.orchestraName = val.name
  101. }
  102. const checkSubject = (val: any) => {
  103. forms.courseType = val.value
  104. forms.courseTypeName = val.name
  105. }
  106. const getOrchestraList = async () => {
  107. try {
  108. const res = await request.post(`${platformApi.value}/orchestra/page`, {
  109. data: { page: 1, rows: 9999, status: 'DONE' }
  110. })
  111. state.actions = res.data.rows.map((item: any) => {
  112. return {
  113. name: item.name,
  114. value: item.id as string
  115. }
  116. })
  117. } catch (e: any) {
  118. const message = e.message
  119. showToast(message)
  120. }
  121. }
  122. // const getSubjects = async () => {
  123. // try {
  124. // const res = await request.post(`${platformApi.value}/subjectBasicConfig/page`, {
  125. // data: { page: 1, rows: 9999 }
  126. // })
  127. // state.subjects = res.data.rows.map((item) => {
  128. // return {
  129. // name: item.courseTypeName,
  130. // value: item.courseType as string
  131. // }
  132. // })
  133. // } catch (e: any) {
  134. // const message = e.message
  135. // showToast(message)
  136. // }
  137. // }
  138. const onRefresh = () => {
  139. finished.value = false
  140. // 重新加载数据
  141. // 将 loading 设置为 true,表示处于加载状态
  142. loading.value = true
  143. getList()
  144. }
  145. // 名称
  146. const formatLength = (name: string) => {
  147. if (name.length > 11) {
  148. const fristName = name.substring(0, 6)
  149. const lastName = name.substring(name.length - 5, name.length)
  150. return fristName + '...' + lastName
  151. } else {
  152. return name
  153. }
  154. }
  155. const formatTime2Mins = (second: number) => {
  156. if (second) {
  157. const first = Math.floor(second / 60)
  158. const last = second % 60
  159. return (first >= 10 ? first : '0' + first) + ':' + (last >= 10 ? last : '0' + last)
  160. } else {
  161. return '00:00'
  162. }
  163. }
  164. const dropdownMenuRef = ref()
  165. const dropdownItemRef = ref()
  166. // 重置
  167. const onSearchReset = () => {
  168. forms.startTime = dayjs().day(1).format('YYYY-MM-DD')
  169. forms.endTime = dayjs().day(7).format('YYYY-MM-DD')
  170. forms.orchestraId = ''
  171. forms.orchestraName = ''
  172. forms.courseType = ''
  173. forms.courseTypeName = ''
  174. forms.coursewareErr = null
  175. forms.coursewareErrName = ''
  176. dropdownItemRef.value?.toggle()
  177. refreshing.value = true
  178. getList()
  179. }
  180. // 搜索
  181. const onSearchConfirm = () => {
  182. dropdownItemRef.value?.toggle()
  183. refreshing.value = true
  184. getList()
  185. }
  186. return () => (
  187. <div class={[!showContact.value ? 'emptyRootContainer' : '', styles.exerciseRecord]}>
  188. <OSticky position="top" background="#F8F8F8">
  189. <OHeader border={false}>
  190. {{
  191. right: () => (
  192. <DropdownMenu
  193. class={styles.searchMore}
  194. closeOnClickOverlay={false}
  195. closeOnClickOutside={false}
  196. ref={dropdownMenuRef}
  197. >
  198. <DropdownItem title="筛选" v-model={state.showSearchStatus} ref={dropdownItemRef}>
  199. <div class={styles.searchContainer}>
  200. {state.actions.length > 0 && (
  201. <>
  202. <div class={styles.searchTitle}>乐团</div>
  203. <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
  204. {state.actions.map((item: any) => (
  205. <div
  206. class={[
  207. styles.searchTypeItem,
  208. item.value === forms.orchestraId && styles['is-active']
  209. ]}
  210. onClick={() => checkOrchestra(item)}
  211. >
  212. {formatLength(item.name)}
  213. </div>
  214. ))}
  215. </div>
  216. </>
  217. )}
  218. <div class={styles.searchTitle}>时间段</div>
  219. <div class={[styles.searchTypeGroup, styles.searchTypeFlex2]}>
  220. <div
  221. class={styles.searchTypeItem}
  222. onClick={() => (state.showPopoverTime = true)}
  223. >
  224. {forms.startTime}
  225. </div>
  226. <div
  227. class={styles.searchTypeItemLine}
  228. onClick={() => (state.showPopoverTime = true)}
  229. ></div>
  230. <div
  231. class={styles.searchTypeItem}
  232. onClick={() => (state.showPopoverTime = true)}
  233. >
  234. {forms.endTime}
  235. </div>
  236. </div>
  237. <div class={styles.searchTitle}>课程类型</div>
  238. <div class={[styles.searchTypeGroup, styles.searchTypeFlex1]}>
  239. {Object.keys(courseEmnu).map((subject: any) => (
  240. <div
  241. class={[
  242. styles.searchTypeItem,
  243. subject === forms.courseType && styles['is-active']
  244. ]}
  245. onClick={() => {
  246. checkSubject({
  247. name: courseEmnu[subject],
  248. value: subject
  249. })
  250. }}
  251. >
  252. {courseEmnu[subject]}
  253. </div>
  254. ))}
  255. </div>
  256. <div class={styles.searchTitle}>课件使用状态</div>
  257. <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
  258. {[
  259. {
  260. name: '正常',
  261. value: false
  262. },
  263. {
  264. name: '异常',
  265. value: true
  266. }
  267. ].map((item: any) => (
  268. <div
  269. class={[
  270. styles.searchTypeItem,
  271. forms.coursewareErr === item.value && styles['is-active']
  272. ]}
  273. onClick={() => checkSort(item)}
  274. >
  275. {item.name}
  276. </div>
  277. ))}
  278. </div>
  279. </div>
  280. <div class={[styles.searchMoreGroup, 'van-hairline--top']}>
  281. <Button type="default" block round size="large" onClick={onSearchReset}>
  282. 重置
  283. </Button>
  284. <Button type="primary" block round size="large" onClick={onSearchConfirm}>
  285. 查询
  286. </Button>
  287. </div>
  288. </DropdownItem>
  289. </DropdownMenu>
  290. )
  291. }}
  292. </OHeader>
  293. <div
  294. style={{
  295. backgroundColor: '#fff'
  296. }}
  297. >
  298. <div class={styles.searchPreview}>
  299. <div
  300. class={styles.searchPreviewItem}
  301. onClick={() => {
  302. // console.log(dropdownItemRef.value, dropdownMenuRef.value)
  303. //
  304. // dropdownItemRef.value?.toggle()
  305. // dropdownMenuRef.value?.click()
  306. // const dropDown = document.querySelector('.van-dropdown-item--down')
  307. // console.log(dropDown.style.top, '1')
  308. // document.querySelector('.van-dropdown-item--down').style.top =
  309. // 'var(--van-nav-bar-height) !important'
  310. }}
  311. >
  312. {forms.startTime}~{forms.endTime}
  313. </div>
  314. {forms.orchestraId && (
  315. <div class={styles.searchPreviewItem}>
  316. {formatLength(forms.orchestraName)}
  317. <Icon
  318. name="cross"
  319. class={styles.cross}
  320. onClick={(e: any) => {
  321. forms.orchestraId = ''
  322. forms.orchestraName = ''
  323. e.stopPropagation()
  324. refreshing.value = true
  325. getList()
  326. }}
  327. />
  328. </div>
  329. )}
  330. {forms.courseType && (
  331. <div class={styles.searchPreviewItem}>
  332. {forms.courseTypeName}
  333. <Icon
  334. name="cross"
  335. class={styles.cross}
  336. onClick={(e: any) => {
  337. forms.courseType = ''
  338. forms.courseTypeName = ''
  339. e.stopPropagation()
  340. refreshing.value = true
  341. getList()
  342. }}
  343. />
  344. </div>
  345. )}
  346. {forms.coursewareErr != null && (
  347. <div class={styles.searchPreviewItem}>
  348. {forms.coursewareErrName}
  349. <Icon
  350. name="cross"
  351. class={styles.cross}
  352. onClick={(e: any) => {
  353. forms.coursewareErr = null
  354. forms.coursewareErrName = ''
  355. e.stopPropagation()
  356. refreshing.value = true
  357. getList()
  358. }}
  359. />
  360. </div>
  361. )}
  362. </div>
  363. </div>
  364. </OSticky>
  365. {showContact.value ? (
  366. <OFullRefresh
  367. v-model:modelValue={refreshing.value}
  368. onRefresh={onRefresh}
  369. style="min-height: 100vh;"
  370. >
  371. <List
  372. loading-text=" "
  373. // v-model:loading={loading.value}
  374. finished={finished.value}
  375. style={{
  376. paddingTop: '12px'
  377. }}
  378. finished-text=" "
  379. immediateCheck={false}
  380. onLoad={getList}
  381. >
  382. {list.value.map((item: any) => (
  383. <CellGroup inset class={styles.coursewareGroup}>
  384. <Cell class={styles.top1}>
  385. {{
  386. title: () => (
  387. <>
  388. {dayjs(item.startTime).format('YYYY-MM-DD HH:mm')}~
  389. {dayjs(item.endTime).format('HH:mm')}
  390. </>
  391. ),
  392. value: () => <>{formatLength(item.orchestraName)}</>
  393. }}
  394. </Cell>
  395. <Cell class={styles.top2}>
  396. {{
  397. icon: () => (
  398. <Image class={styles.userLogo} src={item.teacherAvatar || iconTeacher} />
  399. ),
  400. title: () => (
  401. <div class={styles.userInfo}>
  402. <p class={[styles.userName, 'van-ellipsis']}>{item.teacherName}</p>
  403. <p class={[styles.courseName, 'van-ellipsis']}>{item.className}</p>
  404. </div>
  405. ),
  406. value: () => (
  407. <div class={styles.courseCount}>
  408. <p class={styles.courseRange}>
  409. <span>{formatTime2Mins(item.coursewarePlayTime)}</span>/
  410. {formatTime2Mins(item.adviseStudyTimeSecond)}
  411. </p>
  412. <p class={styles.courseRangeTips}>使用时长/标准时长</p>
  413. </div>
  414. )
  415. }}
  416. </Cell>
  417. </CellGroup>
  418. ))}
  419. </List>
  420. </OFullRefresh>
  421. ) : (
  422. <OEmpty tips="暂无课件记录" />
  423. )}
  424. <Calendar
  425. v-model:show={state.showPopoverTime}
  426. firstDayOfWeek={1}
  427. showConfirm={false}
  428. type="range"
  429. maxRange={7}
  430. minDate={new Date('2023-02-27')}
  431. defaultDate={[dayjs(forms.startTime).toDate(), dayjs(forms.endTime).toDate()]}
  432. style={{
  433. height: '70%'
  434. }}
  435. onSelect={(item: any) => {
  436. forms.startTime = ''
  437. forms.endTime = ''
  438. // console.log(
  439. // item,
  440. // dayjs(item[0]).format('YYYY-MM-DD'),
  441. // 'item',
  442. // dayjs(item[0]).day(0).format('YYYY-MM-DD'),
  443. // dayjs(item[0]).day(),
  444. // dayjs(item[0]).subtract(6, 'day').format('YYYY-MM-DD')
  445. // )
  446. if (!dayjs(item[0]).isBetween(dayjs(forms.startTime), dayjs(forms.endTime))) {
  447. const week = dayjs(item[0]).day()
  448. if (week === 0) {
  449. // 星期天
  450. forms.startTime = dayjs(item[0]).subtract(6, 'day').format('YYYY-MM-DD')
  451. forms.endTime = dayjs(item[0]).format('YYYY-MM-DD')
  452. } else if (week === 1) {
  453. // 星期一
  454. forms.startTime = dayjs(item[0]).format('YYYY-MM-DD')
  455. forms.endTime = dayjs(item[0]).add(6, 'day').format('YYYY-MM-DD')
  456. } else {
  457. forms.startTime = dayjs(item[0])
  458. .subtract(week - 1, 'day')
  459. .format('YYYY-MM-DD')
  460. forms.endTime = dayjs(item[0])
  461. .add(7 - week, 'day')
  462. .format('YYYY-MM-DD')
  463. }
  464. }
  465. state.showPopoverTime = false
  466. }}
  467. />
  468. </div>
  469. )
  470. }
  471. })