feat(student-plan): 实现学生学案查询功能

- 新增FindStudentPlansReqVO和FindStudentPlansRspVO定义请求和响应数据结构
- 新增LessonPlanItem用于描述单个学案项
- StudentLessonPlansDO模型新增isFinished属性
- 扩展StudentLessonPlansDOMapper,添加分页及按姓名查询学生学案列表方法及统计总数方法
- 扩展LessonPlansDOMapper,新增按学案ID列表批量查询方法
- 实现StudentLessonPlansService及LessonPlansService接口对应查询方法
- 新增StudentLessonPlansController,提供学生学案分页查询接口
- 在前端LearningPlan.vue添加学案查询界面及分页、搜索功能
- 封装studentLessonPlans接口axios方法,支持分页按姓名查询学生学案数据
- 添加单元测试更新验证数据库查询正确性
This commit is contained in:
lbw
2025-12-17 15:23:40 +08:00
parent 49cd146bc3
commit dbe7312633
16 changed files with 335 additions and 6 deletions

View File

@@ -0,0 +1,9 @@
import axios from "@/axios";
export function findStudentLessonPlans(page, size, name) {
return axios.post('/studentLessonPlans/list', {
page: page,
size: size,
name: name ?? ''
})
}

View File

@@ -6,10 +6,44 @@
</el-header>
<el-main class="p-4">
<el-tabs v-model="activeTab" type="border-card" class="demo-tabs">
<el-tab-pane label="学习计划" name="first">习计划</el-tab-pane>
<el-tab-pane label="学习记录" name="second">学习记录</el-tab-pane>
</el-tabs>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
<div class="text-lg font-semibold mb-4">案查询</div>
<div class="flex flex-wrap items-center gap-3 mb-4">
<el-input v-model="searchName" placeholder="按姓名查询" clearable style="max-width: 220px" />
<el-button type="primary" @click="onSearch">查询</el-button>
<el-button @click="onReset">重置</el-button>
</div>
<el-table ref="tableRef" :data="rows" border class="w-full" v-loading="loading" row-key="id">
<el-table-column type="expand">
<template #default="{ row }">
<div class="p-3">
<div class="text-sm font-semibold mb-2">学案</div>
<el-table :data="row.plans || []" size="small" border>
<el-table-column prop="id" label="学案ID" width="100" />
<el-table-column prop="title" label="标题" min-width="280" />
<el-table-column label="状态" width="120">
<template #default="{ row: plan }">
<el-tag :type="plan.isFinished === 1 ? 'success' : 'info'"
effect="plain">
{{ plan.isFinished === 1 ? '已完成' : '未完成' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column prop="id" label="学生ID" width="100" />
<el-table-column prop="name" label="姓名" min-width="120" />
<el-table-column prop="className" label="班级" min-width="120" />
<el-table-column prop="gradeName" label="年级" min-width="120" />
</el-table>
<div class="mt-4 flex justify-end">
<el-pagination background layout="prev, pager, next, sizes, total" :total="totalCount"
:page-size="pageSize" :current-page="pageNo" @current-change="handlePageChange"
@size-change="handleSizeChange" />
</div>
</div>
</el-main>
</el-container>
@@ -18,5 +52,52 @@
<script setup>
import Header from '@/layouts/components/Header.vue'
import { ref, onMounted } from 'vue'
import { findStudentLessonPlans } from '@/api/studentLessonPlans'
const rows = ref([])
const loading = ref(false)
const pageNo = ref(1)
const pageSize = ref(10)
const totalCount = ref(0)
const searchName = ref('')
const tableRef = ref(null)
async function fetchLessonPlans() {
loading.value = true
try {
const res = await findStudentLessonPlans(pageNo.value, pageSize.value, searchName.value || '')
const d = res.data
rows.value = Array.isArray(d.data) ? d.data : []
totalCount.value = d.totalCount || 0
pageNo.value = d.pageNo || pageNo.value
pageSize.value = d.pageSize || pageSize.value
} finally {
loading.value = false
}
}
function handlePageChange(p) {
pageNo.value = p
fetchLessonPlans()
}
function handleSizeChange(s) {
pageSize.value = s
pageNo.value = 1
fetchLessonPlans()
}
function onSearch() {
pageNo.value = 1
fetchLessonPlans()
}
function onReset() {
searchName.value = ''
pageNo.value = 1
fetchLessonPlans()
}
onMounted(() => {
fetchLessonPlans()
})
</script>