feat: 作业记录改为分页

This commit is contained in:
阿梦 2026-05-30 10:18:36 +08:00
parent 19839f03f3
commit 2a3c7f4871
5 changed files with 104 additions and 79 deletions

2
.env
View File

@ -2,6 +2,6 @@ VITE_WS_URL = wss://ai.lingxixue.com/ws/device
VITE_OSS_URL = https://lxx-web-1313840333.cos.ap-chengdu.myqcloud.com VITE_OSS_URL = https://lxx-web-1313840333.cos.ap-chengdu.myqcloud.com
VITE_CDN_URL = https://dmgcdn-1313840333.cos.ap-guangzhou.myqcloud.com VITE_CDN_URL = https://dmgcdn-1313840333.cos.ap-guangzhou.myqcloud.com
VITE_SERVER_URL = https://ai.lingxixue.com/api/main VITE_SERVER_URL = https://ai.lingxixue.com/api/main
VITE_XXL_VERSION=2.13.7 VITE_XXL_VERSION=2.13.8
VITE_INIT_VCONSOLE = 0 VITE_INIT_VCONSOLE = 0
VITE_TEACHER_ADMIN_URL = https://edu.lingxixue.com VITE_TEACHER_ADMIN_URL = https://edu.lingxixue.com

View File

@ -4,6 +4,6 @@ VITE_OSS_URL = https://lxx-web-1313840333.cos.ap-chengdu.myqcloud.com
VITE_CDN_URL = https://dmgcdn-1313840333.cos.ap-guangzhou.myqcloud.com VITE_CDN_URL = https://dmgcdn-1313840333.cos.ap-guangzhou.myqcloud.com
VITE_SERVER_URL = http://127.0.0.1:9053/api/main VITE_SERVER_URL = http://127.0.0.1:9053/api/main
# VITE_SERVER_URL = http://test.web.xuexiaole.com/api/main # VITE_SERVER_URL = http://test.web.xuexiaole.com/api/main
VITE_XXL_VERSION=2.13.7 VITE_XXL_VERSION=2.13.8
VITE_INIT_VCONSOLE = 0 VITE_INIT_VCONSOLE = 0
VITE_TEACHER_ADMIN_URL = https://test.edu.xuexiaole.com VITE_TEACHER_ADMIN_URL = https://test.edu.xuexiaole.com

View File

@ -1,6 +1,12 @@
import { get, post } from '../../request' import { get, post, type PageResponse } from '../../request'
import { PaperRecord, HomeworkExam, SubjectPaperRecord } from './type' import {
PaperRecord,
HomeworkExam,
SubjectPaperRecord,
CompleteRecord,
ListCompleteRecordParams,
} from './type'
export * from './type' export * from './type'
const getUnfinishedHomework = async () => { const getUnfinishedHomework = async () => {
@ -42,7 +48,7 @@ const submitExam = async (data: any) => {
export { submitExam } export { submitExam }
// 作业记录列表 // 作业记录列表
const getListCompleteRecord = async (data: any) => { const getListCompleteRecord = async (data: ListCompleteRecordParams) => {
return get<HomeworkExam>(`/school/paper/userRecord/listCompleteRecord`, data) return get<PageResponse<CompleteRecord>>(`/school/paper/userRecord/listCompleteRecord`, data)
} }
export { getListCompleteRecord } export { getListCompleteRecord }

View File

@ -253,6 +253,46 @@ export interface SubjectTitleVo {
answerSqs: string | null answerSqs: string | null
} }
/** 批改状态0-未批改 1-已批改 */
export type GradingStatus = 0 | 1
/** 来源类型0-作业 1-错题本 2-举一反三 */
export type CompleteRecordResourceType = 0 | 1 | 2
/** 已完成答题记录 */
export interface CompleteRecord {
id: number
userId: number
userName: string
schoolId: number
courseId: number
subjectId: number
subjectName: string
textBookId: number
paperId: number
paperName: string
publisherId: number
publisherName: string
resourceType: CompleteRecordResourceType
type: string
status: number
gradingStatus: GradingStatus
score: number
totalScore: number
costTime: number
createTime: string
endTime: string
submitTime: string
}
export interface ListCompleteRecordParams {
current: number
size: number
gradingStatus?: GradingStatus
subjectId?: number
resourceType?: CompleteRecordResourceType
}
/** /**
* *
*/ */

View File

@ -1,21 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { rateType, XMessage } from '@/hooks' import { rateType, XMessage } from '@/hooks'
import homeWorkApi from '@/api/system/homeWork'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { userStore } from '@/stores' import { userStore } from '@/stores'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { getListCompleteRecord } from '@/api/subject/homework' import {
getListCompleteRecord,
type CompleteRecord,
type GradingStatus,
} from '@/api/subject/homework'
import { getSubjectsByGrade } from '@/api/subject/config' import { getSubjectsByGrade } from '@/api/subject/config'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const resourceType = computed(() => (route.query.resourceType as string) || '0') const resourceType = computed(() => Number(route.query.resourceType ?? 0) as 0 | 1 | 2)
const titleMap: Record<string, string> = { const titleMap: Record<number, string> = {
'0': '作业记录', 0: '作业记录',
'1': '错题重练记录', 1: '错题本记录',
'2': '举一反三记录', 2: '举一反三记录',
} }
const pageTitle = computed(() => titleMap[resourceType.value] || '作业记录') const pageTitle = computed(() => titleMap[resourceType.value] || '作业记录')
@ -44,11 +47,15 @@ const rateConfig = computed(() => {
}) })
// //
const activeStatus = ref('') const activeStatus = ref<GradingStatus | ''>('')
function handleChangeStatus() { function handleChangeStatus() {
refreshJobList() refreshJobList()
} }
function isGraded(item: CompleteRecord) {
return item.gradingStatus === 1
}
// //
// const classList = ref<any[]>([]) // const classList = ref<any[]>([])
// async function getClassList() { // async function getClassList() {
@ -86,35 +93,37 @@ function handleSelectClass(_item: any) {
} }
// //
const jobList = ref<any[]>([]) const jobList = ref<CompleteRecord[]>([])
const page = reactive({ const page = reactive({
pageSize: 4, size: 4,
pageNum: 1, current: 1,
total: -1, total: 0,
totalPage: 0,
}) })
const listLoading = ref(false) const listLoading = ref(false)
async function getJobList() { async function getJobList() {
const res = await getListCompleteRecord({ const res = await getListCompleteRecord({
gradingStatus: activeStatus.value || undefined, current: page.current,
size: page.size,
gradingStatus: activeStatus.value === '' ? undefined : activeStatus.value,
subjectId: activeClass.value || undefined, subjectId: activeClass.value || undefined,
resourceType: resourceType.value, resourceType: resourceType.value,
}) })
if (res) { jobList.value = res.rows
jobList.value = res
page.total = res.totalRows page.total = res.totalRows
} page.totalPage = res.totalPage
} }
const pageError = ref(false) const pageError = ref(false)
async function changePage(type: 0 | 1) { async function changePage(type: 0 | 1) {
pageError.value = false pageError.value = false
const { total, pageNum, pageSize } = page const { total, current, size } = page
if (type) { if (type) {
if (pageNum * pageSize >= total) return if (current * size >= total) return
page.pageNum++ page.current++
} else { } else {
if (pageNum <= 1) return if (current <= 1) return
page.pageNum-- page.current--
} }
try { try {
listLoading.value = true listLoading.value = true
@ -130,7 +139,7 @@ async function refreshJobList() {
pageError.value = false pageError.value = false
listLoading.value = true listLoading.value = true
jobList.value = [] jobList.value = []
page.pageNum = 1 page.current = 1
try { try {
await getJobList() await getJobList()
} catch { } catch {
@ -144,7 +153,7 @@ onActivated(async () => {
pageLoading.value = true pageLoading.value = true
listLoading.value = true listLoading.value = true
jobList.value = [] jobList.value = []
page.pageNum = 1 page.current = 1
try { try {
await initSubject() await initSubject()
if (subjectData.value.length) { if (subjectData.value.length) {
@ -158,9 +167,9 @@ onActivated(async () => {
pageLoading.value = false pageLoading.value = false
}) })
function toReports(item: any) { function toReports(item: CompleteRecord) {
if (resourceType.value === '1' || resourceType.value === '2') { if (resourceType.value === 1 || resourceType.value === 2) {
const doWorkResourceType = resourceType.value === '1' ? '10' : '11' const doWorkResourceType = resourceType.value === 1 ? '10' : '11'
router.push({ router.push({
path: `/subject/doWork/${item.id}`, path: `/subject/doWork/${item.id}`,
query: { query: {
@ -170,15 +179,13 @@ function toReports(item: any) {
}) })
return return
} }
if (item.gradingStatus !== 1) { if (!isGraded(item)) {
XMessage.error('作业未批改,请耐心等待老师批改') XMessage.error('作业未批改,请耐心等待老师批改')
return return
} }
router.push(`/system/homeWork/reports/${item.id}`) router.push(`/system/homeWork/reports/${item.id}`)
} }
//
const isDeadline = computed(() => (time: string) => dayjs().isAfter(time))
const activeSubjectName = computed(() => { const activeSubjectName = computed(() => {
return subjectData.value.find(i => i.id === activeClass.value)?.name || '' return subjectData.value.find(i => i.id === activeClass.value)?.name || ''
}) })
@ -191,8 +198,8 @@ const activeSubjectName = computed(() => {
v-model="activeStatus" v-model="activeStatus"
:selectList="[ :selectList="[
{ label: '全部', value: '' }, { label: '全部', value: '' },
{ label: '已批改', value: '1' }, { label: '已批改', value: 1 },
{ label: '未批改', value: '0' }, { label: '未批改', value: 0 },
]" ]"
@selectChange="handleChangeStatus" @selectChange="handleChangeStatus"
></Select> ></Select>
@ -219,15 +226,14 @@ const activeSubjectName = computed(() => {
i.createTime && `发布时间:${dayjs(i.createTime).format('YYYY/MM/DD HH:mm')}` i.createTime && `发布时间:${dayjs(i.createTime).format('YYYY/MM/DD HH:mm')}`
}} }}
&nbsp;&nbsp; &nbsp;&nbsp;
{{ {{ i.endTime && `截止时间:${dayjs(i.endTime).format('YYYY/MM/DD HH:mm')}` }}
i.submitEndTime &&
`截止时间:${dayjs(i.submitEndTime).format('YYYY/MM/DD HH:mm')}`
}}
&nbsp;&nbsp; &nbsp;&nbsp;
{{ i.markTime && `批改时间:${dayjs(i.markTime).format('YYYY/MM/DD HH:mm')}` }} {{
i.submitTime && `提交时间:${dayjs(i.submitTime).format('YYYY/MM/DD HH:mm')}`
}}
</div> </div>
<div <div
v-if="i.gradingStatus === 1" v-if="isGraded(i)"
class="list-item-rate" class="list-item-rate"
:style="{ color: rateConfig((i.score / i.totalScore) * 100).color }" :style="{ color: rateConfig((i.score / i.totalScore) * 100).color }"
> >
@ -237,55 +243,28 @@ const activeSubjectName = computed(() => {
width="196" width="196"
v-bind="rateConfig(i.score / i.totalScore)" v-bind="rateConfig(i.score / i.totalScore)"
></ProgressBar> ></ProgressBar>
<div class="reward-list">
<div v-if="i.addDiamond" class="reward-list-item">
<ItemPopover
:data="{
iconName: 'reward_diamond',
rewardName: '钻石',
personalCount: userInfo.diamond,
}"
>
<Icon name="diamond_nobg" width="48" @click.stop="false"></Icon>
</ItemPopover>
<span class="text">+{{ i.addDiamond }}</span>
</div>
<div v-if="i.addExp" class="reward-list-item">
<ItemPopover
:data="{
iconName: 'reward_exp',
rewardName: '经验值',
personalCount: userInfo.experience,
}"
>
<Icon name="exp_nobg" width="48" @click.stop="false"></Icon>
</ItemPopover>
<span class="text">+{{ i.addExp }}</span>
</div>
</div>
</div> </div>
</div> </div>
<div <div
:class="{ 'list-item-status': true, active: i.gradingStatus === 1 }" :class="{ 'list-item-status': true, active: isGraded(i) }"
:style="{ :style="{
'background-image': 'background-image': isGraded(i)
i.gradingStatus === 1
? `url(${OSS_URL}/urm/homeWork/corrected.svg)` ? `url(${OSS_URL}/urm/homeWork/corrected.svg)`
: `url(${OSS_URL}/urm/homeWork/uncorrected.svg)`, : `url(${OSS_URL}/urm/homeWork/uncorrected.svg)`,
}" }"
> >
{{ i.gradingStatus === 1 ? '已批改' : '未批改' }} {{ isGraded(i) ? '已批改' : '未批改' }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="page"> <div class="page">
<Btn v-if="page.pageNum > 1" width="162" height="80" tilt @click="changePage(0)"> <Btn v-if="page.current > 1" width="162" height="80" tilt @click="changePage(0)">
上一页 上一页
</Btn> </Btn>
<div>{{ page.pageNum }}/{{ Math.ceil(page.total / page.pageSize) }}</div> <div>{{ page.current }}/{{ page.totalPage || Math.ceil(page.total / page.size) }}</div>
<Btn <Btn
v-if="page.pageNum * page.pageSize < page.total" v-if="page.current * page.size < page.total"
type="success" type="success"
width="162" width="162"
height="80" height="80"