feat: 教师团队管理接入接口
This commit is contained in:
parent
978713b316
commit
17ed40fc23
@ -1,32 +1,34 @@
|
||||
<template>
|
||||
<div class="team-management">
|
||||
<div class="toolbar">
|
||||
<n-select v-model:value="selectedDepartment" :options="departmentOptions" placeholder="班级名称"
|
||||
style="width: 200px" />
|
||||
<!-- 班级选择器已注释,保留布局空间 -->
|
||||
<div style="width: 200px; height: 34px;"></div>
|
||||
<NSpace>
|
||||
<n-button type="primary" @click="showAddModal = true">
|
||||
<n-button type="primary" @click="handleAddTeacher">
|
||||
添加老师
|
||||
</n-button>
|
||||
<n-input v-model:value="searchKeyword" placeholder="请输入关键词" style="width: 200px" />
|
||||
<n-button type="primary">
|
||||
<n-input v-model:value="searchKeyword" placeholder="请输入关键词" style="width: 200px"
|
||||
@keyup.enter="handleSearch" />
|
||||
<n-button type="primary" @click="handleSearch">
|
||||
搜索
|
||||
</n-button>
|
||||
<n-button @click="handleClearSearch" v-if="searchKeyword">
|
||||
清空
|
||||
</n-button>
|
||||
</NSpace>
|
||||
</div>
|
||||
|
||||
<n-data-table :columns="columns" :data="data" :pagination="pagination" :loading="loading"
|
||||
:row-key="(row: TeacherItem) => row.id" striped size="small" />
|
||||
<n-data-table :columns="columns" :data="filteredData" :pagination="pagination" :loading="loading"
|
||||
:row-key="(row) => row.id" striped size="small" />
|
||||
|
||||
<!-- 添加教师弹窗 -->
|
||||
<n-modal v-model:show="showAddModal" title="添加老师">
|
||||
<n-card style="width: 600px" title="添加老师" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-form ref="formRef" :model="formData" :rules="rules" label-placement="left" label-width="auto"
|
||||
require-mark-placement="right-hanging">
|
||||
<n-form-item label="姓名" path="teacherName">
|
||||
<n-input v-model:value="formData.teacherName" placeholder="请输入老师姓名" />
|
||||
</n-form-item>
|
||||
<n-form-item label="工号" path="teacherId">
|
||||
<n-input v-model:value="formData.teacherId" placeholder="请输入老师工号" />
|
||||
<n-form-item label="选择教师" path="teacherId">
|
||||
<n-select v-model:value="formData.teacherId" :options="allTeachers" placeholder="请选择要添加的教师"
|
||||
filterable clearable />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<template #footer>
|
||||
@ -46,17 +48,19 @@ import {
|
||||
NDataTable,
|
||||
NButton,
|
||||
NSpace,
|
||||
NSelect,
|
||||
NInput,
|
||||
NSelect,
|
||||
NModal,
|
||||
NCard,
|
||||
NForm,
|
||||
NFormItem,
|
||||
useMessage,
|
||||
useDialog,
|
||||
type FormInst,
|
||||
type FormRules
|
||||
} from 'naive-ui'
|
||||
import type { DataTableColumns } from 'naive-ui'
|
||||
import { TeachCourseApi } from '@/api/modules/teachCourse'
|
||||
|
||||
// 定义数据类型
|
||||
interface TeacherItem {
|
||||
@ -72,41 +76,44 @@ interface TeacherItem {
|
||||
|
||||
// 表单数据类型
|
||||
interface FormData {
|
||||
teacherName: string
|
||||
teacherId: string
|
||||
}
|
||||
|
||||
// 组件属性
|
||||
interface Props {
|
||||
courseId: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const message = useMessage()
|
||||
const dialog = useDialog()
|
||||
|
||||
// 响应式数据
|
||||
const selectedDepartment = ref('')
|
||||
const searchKeyword = ref('')
|
||||
const showAddModal = ref(false)
|
||||
const formRef = ref<FormInst | null>(null)
|
||||
const allTeachers = ref<Array<{ label: string, value: string }>>([])
|
||||
|
||||
// 表单数据
|
||||
const formData = ref<FormData>({
|
||||
teacherName: '',
|
||||
teacherId: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const rules: FormRules = {
|
||||
teacherName: [
|
||||
{ required: true, message: '请输入教师姓名', trigger: 'blur' }
|
||||
],
|
||||
teacherId: [
|
||||
{ required: true, message: '请输入工号', trigger: 'blur' }
|
||||
{ required: true, message: '请选择教师', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 部门选项
|
||||
const departmentOptions = ref([
|
||||
{ label: '全部班级', value: '' },
|
||||
{ label: '软件工程1班', value: 'software1' },
|
||||
{ label: '软件工程2班', value: 'software2' },
|
||||
{ label: '计算机科学1班', value: 'cs1' }
|
||||
])
|
||||
// 部门选项(已注释班级选择器,保留备用)
|
||||
// const departmentOptions = ref([
|
||||
// { label: '全部班级', value: '' },
|
||||
// { label: '软件工程1班', value: 'software1' },
|
||||
// { label: '软件工程2班', value: 'software2' },
|
||||
// { label: '计算机科学1班', value: 'cs1' }
|
||||
// ])
|
||||
|
||||
// 表格列定义
|
||||
const columns: DataTableColumns<TeacherItem> = [
|
||||
@ -151,7 +158,7 @@ const columns: DataTableColumns<TeacherItem> = [
|
||||
key: 'actions',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (row) => {
|
||||
render: (row: TeacherItem) => {
|
||||
return h(
|
||||
NButton,
|
||||
{
|
||||
@ -168,6 +175,7 @@ const columns: DataTableColumns<TeacherItem> = [
|
||||
|
||||
// 表格数据
|
||||
const data = ref<TeacherItem[]>([])
|
||||
const filteredData = ref<TeacherItem[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页配置
|
||||
@ -187,51 +195,192 @@ const pagination = ref({
|
||||
}
|
||||
})
|
||||
|
||||
// 搜索功能
|
||||
const handleSearch = () => {
|
||||
if (!searchKeyword.value.trim()) {
|
||||
// 如果搜索关键词为空,显示所有数据
|
||||
filteredData.value = [...data.value]
|
||||
} else {
|
||||
// 根据关键词过滤数据
|
||||
const keyword = searchKeyword.value.toLowerCase().trim()
|
||||
filteredData.value = data.value.filter((teacher: TeacherItem) =>
|
||||
teacher.teacherName.toLowerCase().includes(keyword) ||
|
||||
teacher.role.toLowerCase().includes(keyword) ||
|
||||
teacher.department.toLowerCase().includes(keyword) ||
|
||||
teacher.teachingClass.toLowerCase().includes(keyword)
|
||||
)
|
||||
}
|
||||
|
||||
// 重置分页到第一页
|
||||
pagination.value.page = 1
|
||||
|
||||
console.log('🔍 搜索完成,关键词:', searchKeyword.value, '结果数量:', filteredData.value.length)
|
||||
}
|
||||
|
||||
// 清空搜索
|
||||
const handleClearSearch = () => {
|
||||
searchKeyword.value = ''
|
||||
filteredData.value = [...data.value]
|
||||
pagination.value.page = 1
|
||||
console.log('🧹 搜索已清空,显示所有数据')
|
||||
}
|
||||
|
||||
// 处理添加教师按钮点击
|
||||
const handleAddTeacher = async () => {
|
||||
// 先加载教师列表
|
||||
await loadAllTeachers()
|
||||
// 然后打开弹窗
|
||||
showAddModal.value = true
|
||||
}
|
||||
|
||||
// 获取所有教师列表
|
||||
const loadAllTeachers = async () => {
|
||||
try {
|
||||
console.log('🔍 开始加载所有教师列表...')
|
||||
const response = await TeachCourseApi.getTeacherList()
|
||||
console.log('📊 教师列表响应:', response)
|
||||
|
||||
if (response.data && response.data.result) {
|
||||
// 获取当前课程已绑定的教师ID列表
|
||||
const currentTeacherIds = data.value.map(teacher => teacher.id)
|
||||
console.log('🔍 当前课程已绑定的教师ID:', currentTeacherIds)
|
||||
|
||||
// 过滤掉已绑定的教师
|
||||
allTeachers.value = response.data.result
|
||||
.filter((teacher: any) => !currentTeacherIds.includes(teacher.id))
|
||||
.map((teacher: any) => ({
|
||||
label: teacher.realname || teacher.name || '未知教师',
|
||||
value: teacher.id
|
||||
}))
|
||||
|
||||
console.log('✅ 教师列表加载成功,共', allTeachers.value.length, '位可选教师')
|
||||
|
||||
// 如果没有可选教师,显示提示
|
||||
if (allTeachers.value.length === 0) {
|
||||
message.info('所有教师都已绑定到此课程')
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ 教师列表数据为空')
|
||||
allTeachers.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 加载教师列表失败:', error)
|
||||
message.error('加载教师列表失败')
|
||||
allTeachers.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 操作处理函数
|
||||
const handleDelete = (row: TeacherItem) => {
|
||||
message.warning(`移除教师:${row.teacherName}`)
|
||||
dialog.warning({
|
||||
title: '确认移除',
|
||||
content: `确定要移除教师"${row.teacherName}"吗?此操作不可撤销。`,
|
||||
positiveText: '确定移除',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: async () => {
|
||||
await performDelete(row)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 执行移除操作
|
||||
const performDelete = async (row: TeacherItem) => {
|
||||
try {
|
||||
console.log('🚀 开始移除教师:', row.teacherName, 'ID:', row.id)
|
||||
|
||||
// 使用API移除教师
|
||||
await TeachCourseApi.unbindTeacher({ courseId: props.courseId, userId: row.id })
|
||||
message.success(`成功移除教师:${row.teacherName}`)
|
||||
|
||||
// 重新加载数据
|
||||
await loadData()
|
||||
} catch (error) {
|
||||
console.error('❌ 移除教师失败:', error)
|
||||
|
||||
// 检查具体的错误信息
|
||||
const errorMessage = (error as Error).message
|
||||
if (errorMessage.includes('该教师未绑定到此课程')) {
|
||||
message.warning('该教师未绑定到此课程')
|
||||
} else if (errorMessage.includes('无法移除')) {
|
||||
message.error('无法移除该教师,可能存在依赖关系')
|
||||
} else {
|
||||
message.error('移除教师失败: ' + errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await formRef.value?.validate()
|
||||
// 这里处理添加教师的逻辑
|
||||
|
||||
console.log('🚀 开始添加教师:', formData.value)
|
||||
|
||||
// 使用API添加教师
|
||||
await TeachCourseApi.addTeacher({ courseId: props.courseId, userId: formData.value.teacherId })
|
||||
|
||||
message.success('添加教师成功')
|
||||
showAddModal.value = false
|
||||
|
||||
// 重置表单
|
||||
formData.value = {
|
||||
teacherName: '',
|
||||
teacherId: ''
|
||||
}
|
||||
|
||||
// 重新加载数据
|
||||
loadData()
|
||||
await loadData()
|
||||
} catch (error) {
|
||||
message.error('请检查表单信息')
|
||||
console.error('❌ 添加教师失败:', error)
|
||||
|
||||
// 检查是否是教师已绑定的错误
|
||||
const errorMessage = (error as Error).message
|
||||
if (errorMessage.includes('该教师已绑定到此课程')) {
|
||||
message.warning('该教师已绑定到此课程,请选择其他教师')
|
||||
} else {
|
||||
message.error('添加教师失败: ' + errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟数据加载
|
||||
// 加载课程教师数据
|
||||
const loadData = async () => {
|
||||
console.log('🔍 TeamManagement 接收到的 courseId:', props.courseId)
|
||||
if (!props.courseId) {
|
||||
console.warn('❌ 课程ID不存在,无法加载教师数据')
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
console.log('🚀 开始加载课程教师数据,课程ID:', props.courseId)
|
||||
|
||||
const roles = ['刘桂人']
|
||||
const departments = ['北京大学经济学理学院']
|
||||
const mockData: TeacherItem[] = Array.from({ length: 1 }, (_, index) => ({
|
||||
id: `teacher_${index + 1}`,
|
||||
teacherName: roles[0],
|
||||
teacherId: `56566652`,
|
||||
role: '刘桂人',
|
||||
studentId: '56566652',
|
||||
teachingClass: '北京大学经济学理学院',
|
||||
department: departments[0],
|
||||
joinTime: '2025.08.02 07:30'
|
||||
}))
|
||||
const response = await TeachCourseApi.getTeacherListInCourse(props.courseId)
|
||||
console.log('📊 API响应:', response)
|
||||
|
||||
data.value = mockData
|
||||
if (response.data && response.data.result) {
|
||||
data.value = response.data.result.map((teacher: any) => ({
|
||||
id: teacher.id,
|
||||
teacherName: teacher.name || '未知教师',
|
||||
teacherId: teacher.id,
|
||||
role: teacher.title || '教师',
|
||||
studentId: teacher.id,
|
||||
teachingClass: '当前课程',
|
||||
department: '教学团队',
|
||||
joinTime: new Date().toLocaleString()
|
||||
}))
|
||||
// 初始化过滤数据
|
||||
filteredData.value = [...data.value]
|
||||
console.log('✅ 教师数据加载成功,共', data.value.length, '位教师')
|
||||
} else {
|
||||
console.log('⚠️ API返回数据为空或失败')
|
||||
data.value = []
|
||||
filteredData.value = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
console.error('❌ 加载课程教师失败:', error)
|
||||
message.error('加载教师数据失败: ' + (error as Error).message)
|
||||
// 清空数据
|
||||
data.value = []
|
||||
filteredData.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<ClassManagement type="course" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="team" tab="教师团队管理">
|
||||
<TeamManagement />
|
||||
<TeamManagement :course-id="courseId" />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="log" tab="操作日志">
|
||||
<OperationLog />
|
||||
@ -21,7 +21,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { NTabs, NTabPane } from 'naive-ui'
|
||||
import ClassManagement from '@/components/teacher/ClassManagement.vue'
|
||||
import TeamManagement from '@/components/teacher/TeamManagement.vue'
|
||||
@ -29,6 +30,15 @@ import OperationLog from '@/components/teacher/OperationLog.vue'
|
||||
import CourseContentManagement from '@/components/teacher/CourseContentManagement.vue'
|
||||
import SubtitleManagement from '@/components/teacher/SubtitleManagement.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 从路由参数中获取课程ID
|
||||
const courseId = computed(() => {
|
||||
console.log('🔍 路由参数:', route.params)
|
||||
console.log('🔍 路由路径:', route.path)
|
||||
return route.params.id as string || ''
|
||||
})
|
||||
|
||||
// 当前激活的tab
|
||||
const activeTab = ref('class')
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user