feat(unit): 新增单元管理功能及相关接口

- 新增单元的请求和响应VO类,实现分页查询单元列表
- 新增UnitController,提供单元列表查询、添加和删除API接口
- 实现UnitService及其实现类,完成单元相关数据库操作和业务逻辑
- 扩展UnitDOMapper及对应XML,实现单元列表和数量查询功能
- 扩展GradeUnitDOMapper,支持单元与年级关联的插入与删除
- 在enlish-vue中新增单元列表展示、分页、删除及新增对话框功能
- 编写AddUnitDialog组件,实现新增单元UI及逻辑
- 新增unit.js接口封装单元相关的API请求
- 注释掉LessonPlansServiceImpl中的导出Word文档相关代码逻辑调整
- 调整class.vue页面样式和布局,集成单元管理模块并优化查询交互
This commit is contained in:
lbw
2025-12-17 11:20:04 +08:00
parent 7f41036193
commit 07b9b56e8a
15 changed files with 472 additions and 30 deletions

View File

@@ -0,0 +1,21 @@
import axios from "@/axios";
export function getUnitList(page, size) {
return axios.post('/unit/list', {
page: page,
size: size
})
}
export function addUnit(name, gradeId) {
return axios.post('/unit/add', {
title: name,
gradeId: gradeId
})
}
export function deleteUnit(id) {
return axios.post('/unit/delete', {
id: id
})
}

View File

@@ -0,0 +1,86 @@
<template>
<el-dialog v-model="visible" title="新增单元" width="480px" :close-on-click-modal="false">
<div class="space-y-4" v-loading="loading">
<el-form label-width="80px">
<el-form-item label="单元名称">
<el-input v-model="name" placeholder="请输入单元名称Unit 1" clearable />
</el-form-item>
<el-form-item label="年级">
<el-select v-model="gradeId" placeholder="请选择年级" style="width: 260px">
<el-option v-for="g in gradeOptions" :key="g.id" :label="g.title" :value="g.id" />
</el-select>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" :disabled="!canSubmit" @click="handleSubmit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { getGradeList } from '@/api/grade'
import { addUnit } from '@/api/unit'
const props = defineProps({
modelValue: { type: Boolean, default: false },
defaultGradeId: { type: [Number, String], default: null }
})
const emit = defineEmits(['update:modelValue', 'success'])
const visible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const loading = ref(false)
const name = ref('')
const gradeId = ref(null)
const gradeOptions = ref([])
const canSubmit = computed(() => name.value.trim().length > 0 && !!gradeId.value)
async function fetchGrades() {
loading.value = true
try {
const res = await getGradeList(1, 100)
const d = res?.data
gradeOptions.value = Array.isArray(d?.data) ? d.data : []
if (props.defaultGradeId && !gradeId.value) {
gradeId.value = Number(props.defaultGradeId)
}
} finally {
loading.value = false
}
}
async function handleSubmit() {
if (!canSubmit.value) return
loading.value = true
try {
await addUnit(name.value.trim(), Number(gradeId.value))
ElMessage.success('新增单元成功')
emit('success')
visible.value = false
} finally {
loading.value = false
}
}
watch(
() => props.modelValue,
(v) => {
if (v) {
name.value = ''
gradeId.value = props.defaultGradeId ? Number(props.defaultGradeId) : null
fetchGrades()
}
}
)
</script>
<style scoped></style>

View File

@@ -35,7 +35,7 @@
</div>
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 lg:col-span-1 lg:row-span-2">
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 lg:col-span-1 lg:row-span-1">
<div class="text-lg font-semibold mb-4">学生查询</div>
<div class="flex flex-wrap items-center gap-3 mb-4">
<el-input v-model="studentName" placeholder="按姓名查询" clearable style="max-width: 220px" />
@@ -105,6 +105,40 @@
<AddGradeDialog v-model="showAddGradeDialog" @success="fetchGrades" />
</div>
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6" v-loading="unitLoading">
<div class="text-lg font-semibold mb-4">单元列表</div>
<el-table ref="unitTableRef" :data="units" border class="w-full">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="title" label="单元名称" min-width="200" />
<el-table-column prop="version" label="版本" min-width="120" />
<el-table-column prop="createAt" label="创建时间" min-width="160" />
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button type="danger" size="small" @click.stop="onDeleteUnit(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-4 flex justify-end">
<el-pagination
background
layout="prev, pager, next, sizes, total"
:total="unitTotalCount"
:page-size="unitPageSize"
:current-page="unitPageNo"
@current-change="handleUnitPageChange"
@size-change="handleUnitSizeChange"
/>
</div>
<div class="mt-3 flex justify-end">
<el-button type="primary" :disabled="!selectedGradeId" @click="showAddUnitDialog = true">新增单元</el-button>
</div>
<AddUnitDialog
v-model="showAddUnitDialog"
:default-grade-id="selectedGradeId"
@success="fetchUnits"
/>
</div>
</div>
</el-main>
@@ -116,12 +150,14 @@
import Header from '@/layouts/components/Header.vue'
import { ref, onMounted } from 'vue'
import { getClassList, deleteClass } from '@/api/class'
import { getGradeList } from '@/api/grade'
import { getGradeList, deleteGrade } from '@/api/grade'
import { getStudentList, deleteStudent } from '@/api/student'
import ExamGenerateDialog from '@/layouts/components/ExamGenerateDialog.vue'
import AddClassDialog from '@/layouts/components/AddClassDialog.vue'
import AddGradeDialog from '@/layouts/components/AddGradeDialog.vue'
import AddStudentDialog from '@/layouts/components/AddStudentDialog.vue'
import { getUnitList, deleteUnit } from '@/api/unit'
import AddUnitDialog from '@/layouts/components/AddUnitDialog.vue'
const classes = ref([])
const pageNo = ref(1)
@@ -154,6 +190,14 @@ const selectedStudentIds = ref([])
const showGenerateDialog = ref(false)
const showAddStudentDialog = ref(false)
const units = ref([])
const unitPageNo = ref(1)
const unitPageSize = ref(10)
const unitTotalCount = ref(0)
const unitLoading = ref(false)
const unitTableRef = ref(null)
const showAddUnitDialog = ref(false)
async function fetchClasses() {
loading.value = true
try {
@@ -303,9 +347,48 @@ async function onDeleteGrade(row) {
}
}
async function fetchUnits() {
unitLoading.value = true
try {
const res = await getUnitList(unitPageNo.value, unitPageSize.value)
const d = res.data
units.value = Array.isArray(d.data) ? d.data : []
unitTotalCount.value = d.totalCount || 0
unitPageNo.value = d.pageNo || unitPageNo.value
unitPageSize.value = d.pageSize || unitPageSize.value
} finally {
unitLoading.value = false
}
}
function handleUnitPageChange(p) {
unitPageNo.value = p
fetchUnits()
}
function handleUnitSizeChange(s) {
unitPageSize.value = s
unitPageNo.value = 1
fetchUnits()
}
async function onDeleteUnit(row) {
try {
const res = await deleteUnit(row.id)
const data = res.data
console.log(data)
if (data.success) {
ElMessage.success('删除成功')
} else {
ElMessage.error(data.message || '删除失败')
}
await fetchUnits()
} catch (e) {
ElMessage.error('删除失败')
}
}
onMounted(() => {
fetchClasses()
fetchGrades()
fetchStudents()
fetchUnits()
})
</script>