index.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. import OHeader from '@/components/o-header'
  2. import OSearch from '@/components/o-search'
  3. import OSticky from '@/components/o-sticky'
  4. import OEmpty from '@/components/o-empty'
  5. import dayjs from 'dayjs'
  6. import isBetween from 'dayjs/plugin/isBetween'
  7. dayjs.extend(isBetween)
  8. import { Icon, List, showToast, DropdownMenu, DropdownItem, Button, Calendar } from 'vant'
  9. import OFullRefresh from '@/components/o-full-refresh'
  10. import StudentItem from './modals/student-item'
  11. import { defineComponent, reactive, ref, onMounted } from 'vue'
  12. import { state as globalState } from '@/state'
  13. import { useRoute, useRouter } from 'vue-router'
  14. import styles from './index.module.less'
  15. import request from '@/helpers/request'
  16. export default defineComponent({
  17. name: 'exercise-record',
  18. setup() {
  19. const platformApi = ref(globalState.platformApi)
  20. const router = useRouter()
  21. const route = useRoute()
  22. const state = reactive({
  23. showSearchStatus: true,
  24. showPopoverTime: false,
  25. actions: [] as any,
  26. subjects: [] as any
  27. })
  28. const forms = reactive({
  29. startTime: dayjs().day(1).format('YYYY-MM-DD'),
  30. endTime: dayjs().day(7).format('YYYY-MM-DD'),
  31. orchestraId: '',
  32. orchestraName: '',
  33. subjectId: '',
  34. subjectName: '',
  35. sortType: '',
  36. sortTypeName: '',
  37. keyword: '',
  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(true)
  45. const list = ref([])
  46. const getList = async () => {
  47. loading.value = true
  48. try {
  49. if (refreshing.value) {
  50. forms.page = 1
  51. list.value = []
  52. refreshing.value = false
  53. }
  54. const { endTime, startTime, ...re } = forms
  55. // , endTime: endTime + ' 23:59:59', startTime: endTime + ' 00:00:00'
  56. const res = await request.post(
  57. `${platformApi.value}/musicPracticeRecord/school/studentPracticeThisWeek`,
  58. {
  59. data: { ...re }
  60. }
  61. )
  62. if (list.value.length > 0 && res.data.pages === 1) {
  63. return
  64. }
  65. forms.page = res.data.current + 1
  66. list.value = list.value.concat(res.data.rows || [])
  67. showContact.value = list.value.length > 0
  68. console.log(showContact.value, ' showContact.value ')
  69. loading.value = false
  70. finished.value = res.data.current >= res.data.pages
  71. } catch (e: any) {
  72. // console.log(e, 'e')
  73. const message = e.message
  74. showToast(message)
  75. showContact.value = false
  76. finished.value = true
  77. }
  78. }
  79. onMounted(async () => {
  80. await getSubjects()
  81. await getOrchestraList()
  82. await getList()
  83. })
  84. const onBack = () => {
  85. router.go(-1)
  86. }
  87. const checkSort = (val: any) => {
  88. forms.sortType = val.value
  89. forms.sortTypeName = val.name
  90. }
  91. const checkOrchestra = (val: any) => {
  92. forms.orchestraId = val.value
  93. forms.orchestraName = val.name
  94. }
  95. const checkSubject = (val: any) => {
  96. forms.subjectId = val.value
  97. forms.subjectName = val.name
  98. }
  99. const getOrchestraList = async () => {
  100. try {
  101. const res = await request.post(`${platformApi.value}/orchestra/page`, {
  102. data: { page: 1, rows: 9999, status: 'DONE' }
  103. })
  104. state.actions = res.data.rows.map((item) => {
  105. return {
  106. name: item.name,
  107. value: item.id as string
  108. }
  109. })
  110. } catch (e: any) {
  111. const message = e.message
  112. showToast(message)
  113. }
  114. }
  115. const getSubjects = async () => {
  116. try {
  117. const res = await request.post(`${platformApi.value}/subjectBasicConfig/page`, {
  118. data: { page: 1, rows: 9999 }
  119. })
  120. state.subjects = res.data.rows.map((item) => {
  121. if (route.query.subjectId == item.subjectId) {
  122. forms.subjectId = item.subjectId
  123. forms.subjectName = item.subjectName
  124. }
  125. return {
  126. name: item.subjectName,
  127. value: item.subjectId as string
  128. }
  129. })
  130. } catch (e: any) {
  131. const message = e.message
  132. showToast(message)
  133. }
  134. }
  135. const onRefresh = () => {
  136. finished.value = false
  137. // 重新加载数据
  138. // 将 loading 设置为 true,表示处于加载状态
  139. loading.value = true
  140. getList()
  141. }
  142. // 名称
  143. const formatLength = (name: string) => {
  144. if (name.length > 11) {
  145. const fristName = name.substring(0, 6)
  146. const lastName = name.substring(name.length - 5, name.length)
  147. return fristName + '...' + lastName
  148. } else {
  149. return name
  150. }
  151. }
  152. const dropdownMenuRef = ref()
  153. const dropdownItemRef = ref()
  154. // 重置
  155. const onSearchReset = () => {
  156. forms.startTime = dayjs().day(1).format('YYYY-MM-DD')
  157. forms.endTime = dayjs().day(7).format('YYYY-MM-DD')
  158. forms.orchestraId = ''
  159. forms.orchestraName = ''
  160. forms.subjectId = ''
  161. forms.subjectName = ''
  162. forms.sortType = ''
  163. forms.sortTypeName = ''
  164. dropdownItemRef.value?.toggle()
  165. refreshing.value = true
  166. getList()
  167. }
  168. // 搜索
  169. const onSearchConfirm = () => {
  170. dropdownItemRef.value?.toggle()
  171. refreshing.value = true
  172. getList()
  173. }
  174. return () => (
  175. <div class={[!showContact.value ? 'emptyRootContainer' : '', styles.exerciseRecord]}>
  176. <OSticky
  177. position="top"
  178. background="#F8F8F8"
  179. onGetHeight={(height: any) => {
  180. document.documentElement.style.setProperty('--header-height', height + 'px')
  181. }}
  182. >
  183. <OHeader border={false}>
  184. {{
  185. right: () => (
  186. <DropdownMenu
  187. class={styles.searchMore}
  188. closeOnClickOverlay={false}
  189. closeOnClickOutside={false}
  190. ref={dropdownMenuRef}
  191. >
  192. <DropdownItem title="筛选" v-model={state.showSearchStatus} ref={dropdownItemRef}>
  193. <div class={styles.searchContainer}>
  194. {state.actions.length > 0 && (
  195. <>
  196. <div class={styles.searchTitle}>乐团</div>
  197. <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
  198. {state.actions.map((item: any) => (
  199. <div
  200. class={[
  201. styles.searchTypeItem,
  202. item.value === forms.orchestraId && styles['is-active']
  203. ]}
  204. onClick={() => checkOrchestra(item)}
  205. >
  206. {formatLength(item.name)}
  207. </div>
  208. ))}
  209. </div>
  210. </>
  211. )}
  212. <div class={styles.searchTitle}>时间段</div>
  213. <div class={[styles.searchTypeGroup, styles.searchTypeFlex2]}>
  214. <div
  215. class={styles.searchTypeItem}
  216. onClick={() => (state.showPopoverTime = true)}
  217. >
  218. {forms.startTime}
  219. </div>
  220. <div
  221. class={styles.searchTypeItemLine}
  222. onClick={() => (state.showPopoverTime = true)}
  223. ></div>
  224. <div
  225. class={styles.searchTypeItem}
  226. onClick={() => (state.showPopoverTime = true)}
  227. >
  228. {forms.endTime}
  229. </div>
  230. </div>
  231. <div class={styles.searchTitle}>声部</div>
  232. <div class={[styles.searchTypeGroup, styles.searchTypeFlex1]}>
  233. {state.subjects.map((subject: any) => (
  234. <div
  235. class={[
  236. styles.searchTypeItem,
  237. subject.value === forms.subjectId && styles['is-active']
  238. ]}
  239. onClick={() => checkSubject(subject)}
  240. >
  241. {subject.name}
  242. </div>
  243. ))}
  244. </div>
  245. <div class={styles.searchTitle}>排序方式</div>
  246. <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
  247. {[
  248. {
  249. name: '按时长',
  250. value: 'PRACTICE_TIMES'
  251. },
  252. {
  253. name: '按天数',
  254. value: 'PRACTICE_DAY'
  255. }
  256. ].map((item: any) => (
  257. <div
  258. class={[
  259. styles.searchTypeItem,
  260. forms.sortType === item.value && styles['is-active']
  261. ]}
  262. onClick={() => checkSort(item)}
  263. >
  264. {item.name}
  265. </div>
  266. ))}
  267. </div>
  268. </div>
  269. <div class={[styles.searchMoreGroup, 'van-hairline--top']}>
  270. <Button type="default" block round size="large" onClick={onSearchReset}>
  271. 重置
  272. </Button>
  273. <Button type="primary" block round size="large" onClick={onSearchConfirm}>
  274. 查询
  275. </Button>
  276. </div>
  277. </DropdownItem>
  278. </DropdownMenu>
  279. )
  280. }}
  281. </OHeader>
  282. <div
  283. style={{
  284. backgroundColor: '#fff'
  285. }}
  286. >
  287. <OSearch
  288. placeholder="请输入学员姓名"
  289. class={styles.recordSearch}
  290. onSearch={(val: any) => {
  291. forms.keyword = val
  292. refreshing.value = true
  293. getList()
  294. }}
  295. ></OSearch>
  296. <div class={styles.searchPreview}>
  297. <div
  298. class={styles.searchPreviewItem}
  299. onClick={() => {
  300. // console.log(dropdownItemRef.value, dropdownMenuRef.value)
  301. // dropdownItemRef.value?.toggle()
  302. // dropdownMenuRef.value?.click()
  303. }}
  304. >
  305. {forms.startTime}~{forms.endTime}
  306. </div>
  307. {forms.orchestraId && (
  308. <div class={styles.searchPreviewItem}>
  309. {formatLength(forms.orchestraName)}
  310. <Icon
  311. name="cross"
  312. class={styles.cross}
  313. onClick={(e: any) => {
  314. forms.orchestraId = ''
  315. forms.orchestraName = ''
  316. e.stopPropagation()
  317. refreshing.value = true
  318. getList()
  319. }}
  320. />
  321. </div>
  322. )}
  323. {forms.subjectId && (
  324. <div class={styles.searchPreviewItem}>
  325. {forms.subjectName}
  326. <Icon
  327. name="cross"
  328. class={styles.cross}
  329. onClick={(e: any) => {
  330. forms.subjectId = ''
  331. forms.subjectName = ''
  332. e.stopPropagation()
  333. refreshing.value = true
  334. getList()
  335. }}
  336. />
  337. </div>
  338. )}
  339. {forms.sortType && (
  340. <div class={styles.searchPreviewItem}>
  341. {forms.sortTypeName}
  342. <Icon
  343. name="cross"
  344. class={styles.cross}
  345. onClick={(e: any) => {
  346. forms.sortType = ''
  347. forms.sortTypeName = ''
  348. e.stopPropagation()
  349. refreshing.value = true
  350. getList()
  351. }}
  352. />
  353. </div>
  354. )}
  355. </div>
  356. </div>
  357. </OSticky>
  358. {showContact.value ? (
  359. <OFullRefresh
  360. v-model:modelValue={refreshing.value}
  361. onRefresh={onRefresh}
  362. style="min-height: calc(100vh - var(--header-height))"
  363. >
  364. <List
  365. loading-text=" "
  366. // v-model:loading={loading.value}
  367. finished={finished.value}
  368. style={{
  369. paddingTop: '12px'
  370. }}
  371. finished-text=" "
  372. onLoad={getList}
  373. immediateCheck={false}
  374. >
  375. {list.value.map((item: any) => (
  376. <StudentItem item={item} forms={forms} />
  377. ))}
  378. </List>
  379. </OFullRefresh>
  380. ) : (
  381. <OEmpty tips="暂无练习记录" />
  382. )}
  383. <Calendar
  384. v-model:show={state.showPopoverTime}
  385. firstDayOfWeek={1}
  386. showConfirm={false}
  387. type="range"
  388. maxRange={7}
  389. minDate={new Date('2023-02-27')}
  390. defaultDate={[dayjs(forms.startTime).toDate(), dayjs(forms.endTime).toDate()]}
  391. style={{
  392. height: '70%'
  393. }}
  394. onSelect={(item: any) => {
  395. forms.startTime = ''
  396. forms.endTime = ''
  397. if (!dayjs(item[0]).isBetween(dayjs(forms.startTime), dayjs(forms.endTime))) {
  398. forms.startTime = dayjs(item[0]).day(1).format('YYYY-MM-DD')
  399. forms.endTime = dayjs(item[0]).day(7).format('YYYY-MM-DD')
  400. }
  401. state.showPopoverTime = false
  402. }}
  403. />
  404. </div>
  405. )
  406. }
  407. })