feat(student): 实现学生的新增与删除功能
- 新增AddStudentReqVO和DeleteStudentReqVO请求对象 - 在StudentController中添加新增和删除学生接口 - StudentService及其实现类增加新增和删除学生方法 - 通过StudentDOMapper新增插入和逻辑删除方法 - 新增AddStudentDialog组件,实现学生添加的表单及交互 - 在class.vue页面添加新增学生按钮及删除学生操作列 - API层新增addStudent和deleteStudent接口调用 - 删除学生时更新选中状态及重新加载学生列表 - 初始化新增学生时词汇掌握记录相关数据
This commit is contained in:
134
enlish-vue/src/layouts/components/AddStudentDialog.vue
Normal file
134
enlish-vue/src/layouts/components/AddStudentDialog.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="新增学生" width="560px" :close-on-click-modal="false">
|
||||
<div class="space-y-4" v-loading="loading">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="name" placeholder="请输入学生姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="年级">
|
||||
<el-select v-model="gradeId" placeholder="请选择年级" style="width: 260px" @change="handleGradeChange">
|
||||
<el-option v-for="g in gradeOptions" :key="g.id" :label="g.title" :value="g.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级">
|
||||
<el-select v-model="classId" placeholder="请选择班级" style="width: 260px">
|
||||
<el-option v-for="c in filteredClassOptions" :key="c.id" :label="c.title" :value="c.id" />
|
||||
</el-select>
|
||||
<div v-if="gradeId && filteredClassOptions.length === 0" class="mt-2 flex items-center gap-2">
|
||||
<span class="text-xs text-gray-500">当前年级暂无班级</span>
|
||||
<el-button type="primary" size="small" @click="showAddClassDialog = true">新增班级</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="入学时间">
|
||||
<el-date-picker v-model="startDate" type="datetime" placeholder="选择日期时间"
|
||||
format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||
</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>
|
||||
<AddClassDialog v-model="showAddClassDialog" :default-grade-id="gradeId" @success="onAddClassSuccess" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { getGradeList } from '@/api/grade'
|
||||
import { getClassList } from '@/api/class'
|
||||
import { addStudent } from '@/api/student'
|
||||
import AddClassDialog from '@/layouts/components/AddClassDialog.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
defaultClassId: { type: [Number, String], default: null },
|
||||
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 classId = ref(null)
|
||||
const startDate = ref('')
|
||||
const gradeOptions = ref([])
|
||||
const classOptions = ref([])
|
||||
|
||||
const filteredClassOptions = computed(() => {
|
||||
if (!gradeId.value) return []
|
||||
return classOptions.value.filter(c => String(c.gradeId) === String(gradeId.value))
|
||||
})
|
||||
const showAddClassDialog = ref(false)
|
||||
function onAddClassSuccess() {
|
||||
fetchBaseOptions().then(() => {
|
||||
handleGradeChange()
|
||||
})
|
||||
}
|
||||
|
||||
const canSubmit = computed(() =>
|
||||
name.value.trim().length > 0 &&
|
||||
!!gradeId.value &&
|
||||
!!classId.value &&
|
||||
!!startDate.value
|
||||
)
|
||||
|
||||
async function fetchBaseOptions() {
|
||||
loading.value = true
|
||||
try {
|
||||
const [gr, cl] = await Promise.all([
|
||||
getGradeList(1, 100),
|
||||
getClassList(1, 100)
|
||||
])
|
||||
const gd = gr?.data
|
||||
const cd = cl?.data
|
||||
gradeOptions.value = Array.isArray(gd?.data) ? gd.data : []
|
||||
classOptions.value = Array.isArray(cd?.data) ? cd.data : []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleGradeChange() {
|
||||
if (classId.value) {
|
||||
const match = filteredClassOptions.value.some(c => String(c.id) === String(classId.value))
|
||||
if (!match) classId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!canSubmit.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
await addStudent(name.value.trim(), Number(classId.value), Number(gradeId.value), startDate.value)
|
||||
ElMessage.success('新增学生成功')
|
||||
emit('success')
|
||||
visible.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (v) => {
|
||||
if (v) {
|
||||
name.value = ''
|
||||
gradeId.value = props.defaultGradeId ? Number(props.defaultGradeId) : null
|
||||
classId.value = props.defaultClassId ? Number(props.defaultClassId) : null
|
||||
startDate.value = ''
|
||||
await fetchBaseOptions()
|
||||
if (gradeId.value) handleGradeChange()
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
Reference in New Issue
Block a user