|
@@ -0,0 +1,463 @@
|
|
|
|
+import OHeader from '@/components/o-header'
|
|
|
|
+import OSticky from '@/components/o-sticky'
|
|
|
|
+import OEmpty from '@/components/o-empty'
|
|
|
|
+import dayjs from 'dayjs'
|
|
|
|
+import isBetween from 'dayjs/plugin/isBetween'
|
|
|
|
+dayjs.extend(isBetween)
|
|
|
|
+import {
|
|
|
|
+ Cell,
|
|
|
|
+ Icon,
|
|
|
|
+ List,
|
|
|
|
+ showToast,
|
|
|
|
+ Image,
|
|
|
|
+ DropdownMenu,
|
|
|
|
+ DropdownItem,
|
|
|
|
+ Button,
|
|
|
|
+ Calendar,
|
|
|
|
+ CellGroup
|
|
|
|
+} from 'vant'
|
|
|
|
+import OFullRefresh from '@/components/o-full-refresh'
|
|
|
|
+import { defineComponent, reactive, ref, onMounted } from 'vue'
|
|
|
|
+import { state as globalState } from '@/state'
|
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
|
+import styles from './index.module.less'
|
|
|
|
+import request from '@/helpers/request'
|
|
|
|
+import iconTeacher from '@common/images/icon_teacher.png'
|
|
|
|
+import { courseEmnu } from '@/constant'
|
|
|
|
+export default defineComponent({
|
|
|
|
+ name: 'exercise-record',
|
|
|
|
+ setup() {
|
|
|
|
+ const platformApi = ref(globalState.platformApi)
|
|
|
|
+ const router = useRouter()
|
|
|
|
+ const state = reactive({
|
|
|
|
+ showSearchStatus: true,
|
|
|
|
+ showPopoverTime: false,
|
|
|
|
+ actions: [] as any,
|
|
|
|
+ subjects: [] as any
|
|
|
|
+ })
|
|
|
|
+ const forms = reactive({
|
|
|
|
+ startTime: dayjs().day(1).format('YYYY-MM-DD'),
|
|
|
|
+ endTime: dayjs().day(7).format('YYYY-MM-DD'),
|
|
|
|
+ orchestraId: '',
|
|
|
|
+ orchestraName: '',
|
|
|
|
+ courseType: '',
|
|
|
|
+ courseTypeName: '',
|
|
|
|
+ coursewareErr: null,
|
|
|
|
+ coursewareErrName: '',
|
|
|
|
+ keyword: '',
|
|
|
|
+ page: 1,
|
|
|
|
+ rows: 20
|
|
|
|
+ })
|
|
|
|
+ const refreshing = ref(false)
|
|
|
|
+ const loading = ref(false)
|
|
|
|
+ const finished = ref(false)
|
|
|
|
+ const showContact = ref(true)
|
|
|
|
+ const list = ref([])
|
|
|
|
+ const getList = async () => {
|
|
|
|
+ loading.value = true
|
|
|
|
+ try {
|
|
|
|
+ if (refreshing.value) {
|
|
|
|
+ forms.page = 1
|
|
|
|
+ list.value = []
|
|
|
|
+ refreshing.value = false
|
|
|
|
+ }
|
|
|
|
+ const { endTime, startTime, ...re } = forms
|
|
|
|
+ const res = await request.post(`${platformApi.value}/courseSchedule/coursewareErrPage`, {
|
|
|
|
+ data: { ...re, endTime: endTime + ' 23:59:59', startTime: startTime + ' 00:00:00' }
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ if (list.value.length > 0 && res.data.pages === 1) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ forms.page = res.data.current + 1
|
|
|
|
+ list.value = list.value.concat(res.data.rows || [])
|
|
|
|
+ showContact.value = list.value.length > 0
|
|
|
|
+ // console.log(showContact.value, ' showContact.value ')
|
|
|
|
+ loading.value = false
|
|
|
|
+
|
|
|
|
+ finished.value = res.data.current >= res.data.pages
|
|
|
|
+ } catch (e: any) {
|
|
|
|
+ // console.log(e, 'e')
|
|
|
|
+ const message = e.message
|
|
|
|
+ showToast(message)
|
|
|
|
+ showContact.value = false
|
|
|
|
+ finished.value = true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ onMounted(() => {
|
|
|
|
+ getList()
|
|
|
|
+ getOrchestraList()
|
|
|
|
+ getSubjects()
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ const onBack = () => {
|
|
|
|
+ router.go(-1)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const checkSort = (val: any) => {
|
|
|
|
+ console.log(val, 'val')
|
|
|
|
+ forms.coursewareErr = val.value
|
|
|
|
+ forms.coursewareErrName = val.name
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const checkOrchestra = (val: any) => {
|
|
|
|
+ forms.orchestraId = val.value
|
|
|
|
+ forms.orchestraName = val.name
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const checkSubject = (val: any) => {
|
|
|
|
+ forms.courseType = val.value
|
|
|
|
+ forms.courseTypeName = val.name
|
|
|
|
+ }
|
|
|
|
+ const getOrchestraList = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const res = await request.post(`${platformApi.value}/orchestra/page`, {
|
|
|
|
+ data: { page: 1, rows: 9999, status: 'DONE' }
|
|
|
|
+ })
|
|
|
|
+ state.actions = res.data.rows.map((item: any) => {
|
|
|
|
+ return {
|
|
|
|
+ name: item.name,
|
|
|
|
+ value: item.id as string
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } catch (e: any) {
|
|
|
|
+ const message = e.message
|
|
|
|
+ showToast(message)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const getSubjects = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const res = await request.post(`${platformApi.value}/subjectBasicConfig/page`, {
|
|
|
|
+ data: { page: 1, rows: 9999 }
|
|
|
|
+ })
|
|
|
|
+ state.subjects = res.data.rows.map((item) => {
|
|
|
|
+ return {
|
|
|
|
+ name: item.courseTypeName,
|
|
|
|
+ value: item.courseType as string
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } catch (e: any) {
|
|
|
|
+ const message = e.message
|
|
|
|
+ showToast(message)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ const onRefresh = () => {
|
|
|
|
+ finished.value = false
|
|
|
|
+ // 重新加载数据
|
|
|
|
+ // 将 loading 设置为 true,表示处于加载状态
|
|
|
|
+ loading.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 名称
|
|
|
|
+ const formatLength = (name: string) => {
|
|
|
|
+ if (name.length > 11) {
|
|
|
|
+ const fristName = name.substring(0, 6)
|
|
|
|
+ const lastName = name.substring(name.length - 5, name.length)
|
|
|
|
+ return fristName + '...' + lastName
|
|
|
|
+ } else {
|
|
|
|
+ return name
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const formatTime2Mins = (second: number) => {
|
|
|
|
+ if (second) {
|
|
|
|
+ const first = Math.floor(1098 / 60)
|
|
|
|
+ const last = second % 60
|
|
|
|
+ return (first >= 10 ? first : '0' + first) + ':' + (last >= 10 ? last : '0' + last)
|
|
|
|
+ } else {
|
|
|
|
+ return '00:00'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const dropdownMenuRef = ref()
|
|
|
|
+ const dropdownItemRef = ref()
|
|
|
|
+ // 重置
|
|
|
|
+ const onSearchReset = () => {
|
|
|
|
+ forms.startTime = dayjs().day(1).format('YYYY-MM-DD')
|
|
|
|
+ forms.endTime = dayjs().day(7).format('YYYY-MM-DD')
|
|
|
|
+ forms.orchestraId = ''
|
|
|
|
+ forms.orchestraName = ''
|
|
|
|
+ forms.courseType = ''
|
|
|
|
+ forms.courseTypeName = ''
|
|
|
|
+ forms.coursewareErr = null
|
|
|
|
+ forms.coursewareErrName = ''
|
|
|
|
+ dropdownItemRef.value?.toggle()
|
|
|
|
+ refreshing.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 搜索
|
|
|
|
+ const onSearchConfirm = () => {
|
|
|
|
+ dropdownItemRef.value?.toggle()
|
|
|
|
+ refreshing.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return () => (
|
|
|
|
+ <div class={[!showContact.value ? 'emptyRootContainer' : '', styles.exerciseRecord]}>
|
|
|
|
+ <OSticky position="top" background="#F8F8F8">
|
|
|
|
+ <OHeader border={false}>
|
|
|
|
+ {{
|
|
|
|
+ right: () => (
|
|
|
|
+ <DropdownMenu
|
|
|
|
+ class={styles.searchMore}
|
|
|
|
+ closeOnClickOverlay={false}
|
|
|
|
+ closeOnClickOutside={false}
|
|
|
|
+ ref={dropdownMenuRef}
|
|
|
|
+ >
|
|
|
|
+ <DropdownItem title="筛选" v-model={state.showSearchStatus} ref={dropdownItemRef}>
|
|
|
|
+ <div class={styles.searchContainer}>
|
|
|
|
+ {state.actions.length > 0 && (
|
|
|
|
+ <>
|
|
|
|
+ <div class={styles.searchTitle}>乐团</div>
|
|
|
|
+ <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
|
|
|
|
+ {state.actions.map((item: any) => (
|
|
|
|
+ <div
|
|
|
|
+ class={[
|
|
|
|
+ styles.searchTypeItem,
|
|
|
|
+ item.value === forms.orchestraId && styles['is-active']
|
|
|
|
+ ]}
|
|
|
|
+ onClick={() => checkOrchestra(item)}
|
|
|
|
+ >
|
|
|
|
+ {formatLength(item.name)}
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ </>
|
|
|
|
+ )}
|
|
|
|
+
|
|
|
|
+ <div class={styles.searchTitle}>时间段</div>
|
|
|
|
+ <div class={[styles.searchTypeGroup, styles.searchTypeFlex2]}>
|
|
|
|
+ <div
|
|
|
|
+ class={styles.searchTypeItem}
|
|
|
|
+ onClick={() => (state.showPopoverTime = true)}
|
|
|
|
+ >
|
|
|
|
+ {forms.startTime}
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ class={styles.searchTypeItemLine}
|
|
|
|
+ onClick={() => (state.showPopoverTime = true)}
|
|
|
|
+ ></div>
|
|
|
|
+ <div
|
|
|
|
+ class={styles.searchTypeItem}
|
|
|
|
+ onClick={() => (state.showPopoverTime = true)}
|
|
|
|
+ >
|
|
|
|
+ {forms.endTime}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class={styles.searchTitle}>课程类型</div>
|
|
|
|
+ <div class={[styles.searchTypeGroup, styles.searchTypeFlex1]}>
|
|
|
|
+ {Object.keys(courseEmnu).map((subject: any) => (
|
|
|
|
+ <div
|
|
|
|
+ class={[
|
|
|
|
+ styles.searchTypeItem,
|
|
|
|
+ subject === forms.courseType && styles['is-active']
|
|
|
|
+ ]}
|
|
|
|
+ onClick={() => {
|
|
|
|
+ checkSubject({
|
|
|
|
+ name: courseEmnu[subject],
|
|
|
|
+ value: subject
|
|
|
|
+ })
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {courseEmnu[subject]}
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ <div class={styles.searchTitle}>课件使用状态</div>
|
|
|
|
+ <div class={[styles.searchTypeGroup, styles.searchTypeFlex]}>
|
|
|
|
+ {[
|
|
|
|
+ {
|
|
|
|
+ name: '正常',
|
|
|
|
+ value: false
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ name: '异常',
|
|
|
|
+ value: true
|
|
|
|
+ }
|
|
|
|
+ ].map((item: any) => (
|
|
|
|
+ <div
|
|
|
|
+ class={[
|
|
|
|
+ styles.searchTypeItem,
|
|
|
|
+ forms.coursewareErr === item.value && styles['is-active']
|
|
|
|
+ ]}
|
|
|
|
+ onClick={() => checkSort(item)}
|
|
|
|
+ >
|
|
|
|
+ {item.name}
|
|
|
|
+ </div>
|
|
|
|
+ ))}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class={[styles.searchMoreGroup, 'van-hairline--top']}>
|
|
|
|
+ <Button type="default" block round size="large" onClick={onSearchReset}>
|
|
|
|
+ 重置
|
|
|
|
+ </Button>
|
|
|
|
+ <Button type="primary" block round size="large" onClick={onSearchConfirm}>
|
|
|
|
+ 查询
|
|
|
|
+ </Button>
|
|
|
|
+ </div>
|
|
|
|
+ </DropdownItem>
|
|
|
|
+ </DropdownMenu>
|
|
|
|
+ )
|
|
|
|
+ }}
|
|
|
|
+ </OHeader>
|
|
|
|
+ <div
|
|
|
|
+ style={{
|
|
|
|
+ backgroundColor: '#fff'
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ <div class={styles.searchPreview}>
|
|
|
|
+ <div
|
|
|
|
+ class={styles.searchPreviewItem}
|
|
|
|
+ onClick={() => {
|
|
|
|
+ // console.log(dropdownItemRef.value, dropdownMenuRef.value)
|
|
|
|
+ //
|
|
|
|
+ // dropdownItemRef.value?.toggle()
|
|
|
|
+ // dropdownMenuRef.value?.click()
|
|
|
|
+ // const dropDown = document.querySelector('.van-dropdown-item--down')
|
|
|
|
+ // console.log(dropDown.style.top, '1')
|
|
|
|
+ // document.querySelector('.van-dropdown-item--down').style.top =
|
|
|
|
+ // 'var(--van-nav-bar-height) !important'
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {forms.startTime}~{forms.endTime}
|
|
|
|
+ </div>
|
|
|
|
+ {forms.orchestraId && (
|
|
|
|
+ <div class={styles.searchPreviewItem}>
|
|
|
|
+ {formatLength(forms.orchestraName)}
|
|
|
|
+ <Icon
|
|
|
|
+ name="cross"
|
|
|
|
+ class={styles.cross}
|
|
|
|
+ onClick={(e: any) => {
|
|
|
|
+ forms.orchestraId = ''
|
|
|
|
+ forms.orchestraName = ''
|
|
|
|
+ e.stopPropagation()
|
|
|
|
+ refreshing.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ {forms.courseType && (
|
|
|
|
+ <div class={styles.searchPreviewItem}>
|
|
|
|
+ {forms.courseTypeName}
|
|
|
|
+ <Icon
|
|
|
|
+ name="cross"
|
|
|
|
+ class={styles.cross}
|
|
|
|
+ onClick={(e: any) => {
|
|
|
|
+ forms.courseType = ''
|
|
|
|
+ forms.courseTypeName = ''
|
|
|
|
+ e.stopPropagation()
|
|
|
|
+ refreshing.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ {forms.coursewareErr != null && (
|
|
|
|
+ <div class={styles.searchPreviewItem}>
|
|
|
|
+ {forms.coursewareErrName}
|
|
|
|
+ <Icon
|
|
|
|
+ name="cross"
|
|
|
|
+ class={styles.cross}
|
|
|
|
+ onClick={(e: any) => {
|
|
|
|
+ forms.coursewareErr = null
|
|
|
|
+ forms.coursewareErrName = ''
|
|
|
|
+ e.stopPropagation()
|
|
|
|
+ refreshing.value = true
|
|
|
|
+ getList()
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </OSticky>
|
|
|
|
+ {showContact.value ? (
|
|
|
|
+ <OFullRefresh
|
|
|
|
+ v-model:modelValue={refreshing.value}
|
|
|
|
+ onRefresh={onRefresh}
|
|
|
|
+ style="min-height: 100vh;"
|
|
|
|
+ >
|
|
|
|
+ <List
|
|
|
|
+ loading-text=" "
|
|
|
|
+ // v-model:loading={loading.value}
|
|
|
|
+ finished={finished.value}
|
|
|
|
+ style={{
|
|
|
|
+ paddingTop: '12px'
|
|
|
|
+ }}
|
|
|
|
+ finished-text=" "
|
|
|
|
+ immediateCheck={false}
|
|
|
|
+ onLoad={getList}
|
|
|
|
+ >
|
|
|
|
+ {list.value.map((item: any) => (
|
|
|
|
+ <CellGroup inset class={styles.coursewareGroup}>
|
|
|
|
+ <Cell class={styles.top1}>
|
|
|
|
+ {{
|
|
|
|
+ title: () => (
|
|
|
|
+ <>
|
|
|
|
+ {dayjs(item.startTime).format('YYYY-MM-DD HH:mm')}~
|
|
|
|
+ {dayjs(item.endTime).format('HH:mm')}
|
|
|
|
+ </>
|
|
|
|
+ ),
|
|
|
|
+ value: () => <>{formatLength(item.orchestraName)}</>
|
|
|
|
+ }}
|
|
|
|
+ </Cell>
|
|
|
|
+ <Cell class={styles.top2}>
|
|
|
|
+ {{
|
|
|
|
+ icon: () => (
|
|
|
|
+ <Image class={styles.userLogo} src={item.teacherAvatar || iconTeacher} />
|
|
|
|
+ ),
|
|
|
|
+ title: () => (
|
|
|
|
+ <div class={styles.userInfo}>
|
|
|
|
+ <p class={[styles.userName, 'van-ellipsis']}>{item.teacherName}</p>
|
|
|
|
+ <p class={[styles.courseName, 'van-ellipsis']}>{item.className}</p>
|
|
|
|
+ </div>
|
|
|
|
+ ),
|
|
|
|
+ value: () => (
|
|
|
|
+ <div class={styles.courseCount}>
|
|
|
|
+ <p class={styles.courseRange}>
|
|
|
|
+ <span>{formatTime2Mins(item.coursewarePlayTime)}</span>/
|
|
|
|
+ {formatTime2Mins(item.adviseStudyTimeSecond)}
|
|
|
|
+ </p>
|
|
|
|
+ <p class={styles.courseRangeTips}>使用时长/标准时长</p>
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+ }}
|
|
|
|
+ </Cell>
|
|
|
|
+ </CellGroup>
|
|
|
|
+ ))}
|
|
|
|
+ </List>
|
|
|
|
+ </OFullRefresh>
|
|
|
|
+ ) : (
|
|
|
|
+ <OEmpty tips="暂无课件记录" />
|
|
|
|
+ )}
|
|
|
|
+
|
|
|
|
+ <Calendar
|
|
|
|
+ v-model:show={state.showPopoverTime}
|
|
|
|
+ firstDayOfWeek={1}
|
|
|
|
+ showConfirm={false}
|
|
|
|
+ type="range"
|
|
|
|
+ maxRange={7}
|
|
|
|
+ minDate={new Date('2023-02-27')}
|
|
|
|
+ defaultDate={[dayjs(forms.startTime).toDate(), dayjs(forms.endTime).toDate()]}
|
|
|
|
+ style={{
|
|
|
|
+ height: '70%'
|
|
|
|
+ }}
|
|
|
|
+ onSelect={(item: any) => {
|
|
|
|
+ forms.startTime = ''
|
|
|
|
+ forms.endTime = ''
|
|
|
|
+ if (!dayjs(item[0]).isBetween(dayjs(forms.startTime), dayjs(forms.endTime))) {
|
|
|
|
+ forms.startTime = dayjs(item[0]).day(1).format('YYYY-MM-DD')
|
|
|
|
+ forms.endTime = dayjs(item[0]).day(7).format('YYYY-MM-DD')
|
|
|
|
+ }
|
|
|
|
+ state.showPopoverTime = false
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+})
|