|
|
@ -1,12 +1,14 @@ |
|
|
<template> |
|
|
<template> |
|
|
<el-card class="box-card !border-none" shadow="never"> |
|
|
<el-card class="box-card !border-none" shadow="never"> |
|
|
<div class="mb-4 flex items-center justify-between"> |
|
|
<div class="header-control-panel mb-4"> |
|
|
<div class="flex items-center" style="width: 50%;"> |
|
|
<div class="flex items-center flex-wrap"> |
|
|
<el-select |
|
|
<el-select |
|
|
v-model="selectedCampus" |
|
|
v-model="selectedCampus" |
|
|
placeholder="请选择校区" |
|
|
placeholder="请选择校区" |
|
|
clearable |
|
|
clearable |
|
|
class="mr-2" |
|
|
size="default" |
|
|
|
|
|
class="mr-2 mb-2" |
|
|
|
|
|
style="width: 160px;" |
|
|
@change="handleCampusChange" |
|
|
@change="handleCampusChange" |
|
|
> |
|
|
> |
|
|
<el-option |
|
|
<el-option |
|
|
@ -16,21 +18,24 @@ |
|
|
:value="item.id" |
|
|
:value="item.id" |
|
|
/> |
|
|
/> |
|
|
</el-select> |
|
|
</el-select> |
|
|
<el-button @click="prevWeek" icon="el-icon-arrow-left">上一周</el-button> |
|
|
<el-button size="default" @click="prevWeek" icon="el-icon-arrow-left" class="mb-2">上一周</el-button> |
|
|
<div class="ml-2 mr-2"> |
|
|
<div class="mx-2 mb-2"> |
|
|
<el-date-picker |
|
|
<el-date-picker |
|
|
v-model="weekDate" |
|
|
v-model="weekDate" |
|
|
type="week" |
|
|
type="week" |
|
|
format="YYYY 第 ww 周" |
|
|
format="YYYY 第 ww 周" |
|
|
placeholder="选择周" |
|
|
placeholder="选择周" |
|
|
|
|
|
size="default" |
|
|
style="width: 180px;" |
|
|
style="width: 180px;" |
|
|
@change="handleWeekChange" |
|
|
@change="handleWeekChange" |
|
|
/> |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
<el-button @click="nextWeek" icon="el-icon-arrow-right">下一周</el-button> |
|
|
<el-button size="default" @click="nextWeek" icon="el-icon-arrow-right" class="mb-2">下一周</el-button> |
|
|
<el-button type="primary" class="ml-2" @click="fetchData">查询</el-button> |
|
|
<el-button type="primary" size="default" class="ml-2 mb-2" @click="fetchData">查询</el-button> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div> |
|
|
|
|
|
<el-button size="default" type="primary" plain @click="addSchedule">添加课程</el-button> |
|
|
</div> |
|
|
</div> |
|
|
<el-button @click="addSchedule">添加课程</el-button> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="schedule-container"> |
|
|
<div class="schedule-container"> |
|
|
@ -41,7 +46,10 @@ |
|
|
:data="day.timeSlots" |
|
|
:data="day.timeSlots" |
|
|
border |
|
|
border |
|
|
:span-method="(data) => objectSpanMethod(day.timeSlots, data)" |
|
|
:span-method="(data) => objectSpanMethod(day.timeSlots, data)" |
|
|
style="width: 100%" |
|
|
style="width: 100%; height: 100%;" |
|
|
|
|
|
max-height="100%" |
|
|
|
|
|
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }" |
|
|
|
|
|
:cell-style="{ padding: '4px' }" |
|
|
@cell-click="handleCellClick" |
|
|
@cell-click="handleCellClick" |
|
|
> |
|
|
> |
|
|
<!-- 时间列 --> |
|
|
<!-- 时间列 --> |
|
|
@ -60,23 +68,31 @@ |
|
|
:label="`${classroom.venue_name}`" |
|
|
:label="`${classroom.venue_name}`" |
|
|
:prop="`classroom${classroom.id}`" |
|
|
:prop="`classroom${classroom.id}`" |
|
|
align="center" |
|
|
align="center" |
|
|
|
|
|
width="280" |
|
|
> |
|
|
> |
|
|
<template #default="{ row }"> |
|
|
<template #default="{ row }"> |
|
|
<div v-if="row.course && row.course.classroom.id == classroom.id"> |
|
|
<div v-if="row.course && row.course.classroom[0].id == classroom.id" class="course-cell" :style="{ backgroundColor: row.backgroundColor || '#f0f9eb', color: row.color ? '#fff' : '#000' }"> |
|
|
<div class="teacher-name"> |
|
|
<div class="teacher-name"> |
|
|
{{ getTeacherName(row.course.teacher) }} |
|
|
{{ row.course.teacher[0].name }} |
|
|
</div> |
|
|
</div> |
|
|
<div class="student-list"> |
|
|
<div class="student-list" :style="{ backgroundColor: row.backgroundColor || '#f0f9eb', color: row.color ? '#fff' : '#000' }"> |
|
|
<el-tag |
|
|
<div |
|
|
v-for="student in row.course.students" |
|
|
v-for="student in row.course.students" |
|
|
:key="student" |
|
|
:key="student.id" |
|
|
size="small" |
|
|
class="custom-student-tag" |
|
|
effect="plain" |
|
|
|
|
|
> |
|
|
> |
|
|
{{ getStudentName(student) }} |
|
|
<div class="tag-content"> |
|
|
</el-tag> |
|
|
<span class="tag-label">家长:</span> |
|
|
|
|
|
<span class="tag-value">{{ student.resources?.name || '未知' }}</span> |
|
|
|
|
|
<template v-if="student.student && student.student?.name"> |
|
|
|
|
|
<span class="tag-divider">|</span> |
|
|
|
|
|
<span class="tag-label">学员:</span> |
|
|
|
|
|
<span class="tag-value">{{ student.student?.name }}</span> |
|
|
|
|
|
</template> |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="classroom-name"> |
|
|
<div class="classroom-name" :style="{ backgroundColor: row.backgroundColor || '#f0f9eb', color: row.color ? '#fff' : '#000' }"> |
|
|
剩余空位:{{ row.course.hasnumber }} |
|
|
剩余空位:{{ row.course.hasnumber }} |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
@ -86,16 +102,61 @@ |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- 详情弹窗 --> |
|
|
<!-- 详情弹窗 --> |
|
|
<el-dialog v-model="dialogVisible" title="课程详情"> |
|
|
<el-dialog v-model="dialogVisible" title="课程安排" width="600px" @open="handleDialogOpen"> |
|
|
<p> |
|
|
<!-- 人员类型选择 --> |
|
|
<strong>教师:</strong> {{ getTeacherName(selectedCourse?.teacher) }} |
|
|
<div class="my-3"> |
|
|
</p> |
|
|
<el-radio-group v-model="personType" @change="handlePersonTypeChange"> |
|
|
<p> |
|
|
<el-radio :label="'course'">课程人员</el-radio> |
|
|
<strong>学员:</strong> |
|
|
<el-radio :label="'trial'">试课人员</el-radio> |
|
|
{{ |
|
|
</el-radio-group> |
|
|
selectedCourse?.students.map((id) => getStudentName(id)).join(', ') |
|
|
</div> |
|
|
}} |
|
|
|
|
|
</p> |
|
|
<!-- 试课人员搜索框 --> |
|
|
|
|
|
<div v-if="personType === 'trial'" class="search-box mb-3"> |
|
|
|
|
|
<el-input |
|
|
|
|
|
v-model="searchKeyword" |
|
|
|
|
|
placeholder="请输入姓名或手机号" |
|
|
|
|
|
class="mr-2" |
|
|
|
|
|
style="width: 220px;" |
|
|
|
|
|
> |
|
|
|
|
|
<template #append> |
|
|
|
|
|
<el-button @click="searchPerson"> |
|
|
|
|
|
<el-icon><Search /></el-icon> |
|
|
|
|
|
</el-button> |
|
|
|
|
|
</template> |
|
|
|
|
|
</el-input> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 人员列表多选区域 --> |
|
|
|
|
|
<div class="student-checkbox-container"> |
|
|
|
|
|
<el-checkbox-group v-model="selectedStudentIds"> |
|
|
|
|
|
<el-checkbox |
|
|
|
|
|
v-for="student in students" |
|
|
|
|
|
:key="student.id" |
|
|
|
|
|
:label="student.id" |
|
|
|
|
|
class="student-checkbox-item" |
|
|
|
|
|
:checked="student.checked === true" |
|
|
|
|
|
@change="(val) => handleStudentCheck(student, val)" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="student-info"> |
|
|
|
|
|
<span class="student-name">{{ student.name }}</span> |
|
|
|
|
|
<span v-if="student.student_name" class="student-school"> |
|
|
|
|
|
({{ student.student_name }}) |
|
|
|
|
|
</span> |
|
|
|
|
|
</div> |
|
|
|
|
|
</el-checkbox> |
|
|
|
|
|
</el-checkbox-group> |
|
|
|
|
|
<div v-if="students.length === 0" class="text-center py-3 text-gray-500"> |
|
|
|
|
|
暂无人员数据 |
|
|
|
|
|
</div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<template #footer> |
|
|
|
|
|
<span class="dialog-footer"> |
|
|
|
|
|
<el-button @click="dialogVisible = false">取消</el-button> |
|
|
|
|
|
<el-button type="primary" @click="saveStudents">保存</el-button> |
|
|
|
|
|
</span> |
|
|
|
|
|
</template> |
|
|
</el-dialog> |
|
|
</el-dialog> |
|
|
|
|
|
|
|
|
<!-- 添加课程弹窗组件 --> |
|
|
<!-- 添加课程弹窗组件 --> |
|
|
@ -110,9 +171,12 @@ |
|
|
|
|
|
|
|
|
<script setup> |
|
|
<script setup> |
|
|
import { ref, onMounted, computed } from 'vue' |
|
|
import { ref, onMounted, computed } from 'vue' |
|
|
import { getTimetables } from '@/app/api/course_schedule' |
|
|
import { getTimetables, getCourseStudents, getResourceByNameOrPhone } from '@/app/api/course_schedule' |
|
|
|
|
|
import { addPersonCourseSchedule,getTryCoursePerson } from '@/app/api/person_course_schedule' |
|
|
import { getWithCampusList } from '@/app/api/venue' |
|
|
import { getWithCampusList } from '@/app/api/venue' |
|
|
import ScheduleAdd from './components/schedule-add.vue' |
|
|
import ScheduleAdd from './components/schedule-add.vue' |
|
|
|
|
|
import { ElMessage } from 'element-plus' |
|
|
|
|
|
import { Search } from '@element-plus/icons-vue' |
|
|
|
|
|
|
|
|
// 校区列表 |
|
|
// 校区列表 |
|
|
const campusList = ref([]) |
|
|
const campusList = ref([]) |
|
|
@ -148,6 +212,15 @@ const days = ref([]) |
|
|
const dialogVisible = ref(false) |
|
|
const dialogVisible = ref(false) |
|
|
const selectedCourse = ref(null) |
|
|
const selectedCourse = ref(null) |
|
|
|
|
|
|
|
|
|
|
|
// 人员相关 |
|
|
|
|
|
const personType = ref('course') // 默认课程人员 |
|
|
|
|
|
const searchKeyword = ref('') // 搜索关键词 |
|
|
|
|
|
const students = ref([]) // 人员列表 |
|
|
|
|
|
const selectedStudentIds = ref([]) // 已选择的人员ID列表 |
|
|
|
|
|
const selectedStudents = ref([]) // 已选择的人员完整信息列表 |
|
|
|
|
|
const courseStudents = ref([]) // 课程人员列表缓存 |
|
|
|
|
|
const trialStudents = ref([]) // 试课人员列表缓存 |
|
|
|
|
|
|
|
|
// 上一周 |
|
|
// 上一周 |
|
|
const prevWeek = () => { |
|
|
const prevWeek = () => { |
|
|
const date = new Date(weekDate.value) |
|
|
const date = new Date(weekDate.value) |
|
|
@ -185,8 +258,10 @@ const fetchCampusList = async () => { |
|
|
selectedCampus.value = campusList.value[0].id |
|
|
selectedCampus.value = campusList.value[0].id |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return Promise.resolve() |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
console.error('获取校区列表失败:', error) |
|
|
console.error('获取校区列表失败:', error) |
|
|
|
|
|
return Promise.reject(error) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -212,18 +287,6 @@ const fetchData = async () => { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 获取教师名称(实际应用中应该从教师列表中获取) |
|
|
|
|
|
const getTeacherName = (teacherId) => { |
|
|
|
|
|
// 这里应该根据teacherId获取教师名称 |
|
|
|
|
|
return teacherId ? `教师${teacherId}` : '' |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取学生名称(实际应用中应该从学生列表中获取) |
|
|
|
|
|
const getStudentName = (studentId) => { |
|
|
|
|
|
// 这里应该根据studentId获取学生名称 |
|
|
|
|
|
return studentId ? `学生${studentId}` : '' |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 添加课程 |
|
|
// 添加课程 |
|
|
const addSchedule = () => { |
|
|
const addSchedule = () => { |
|
|
addDialogVisible.value = true |
|
|
addDialogVisible.value = true |
|
|
@ -263,44 +326,286 @@ const objectSpanMethod = (timeSlots, { row, column, rowIndex }) => { |
|
|
// 单元格点击事件 |
|
|
// 单元格点击事件 |
|
|
const handleCellClick = (row, column, cell, event) => { |
|
|
const handleCellClick = (row, column, cell, event) => { |
|
|
if (column.property.startsWith('classroom') && row.course) { |
|
|
if (column.property.startsWith('classroom') && row.course) { |
|
|
selectedCourse.value = row.course |
|
|
console.log(row.course.schedule) |
|
|
|
|
|
selectedCourse.value = row.course.schedule.id |
|
|
dialogVisible.value = true |
|
|
dialogVisible.value = true |
|
|
|
|
|
} else { |
|
|
|
|
|
ElMessage.warning('当天该时间段没有课程') |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 弹窗打开事件 |
|
|
|
|
|
const handleDialogOpen = async () => { |
|
|
|
|
|
if (!selectedCourse.value) { |
|
|
|
|
|
ElMessage.warning('未选择有效课程') |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重置状态 |
|
|
|
|
|
personType.value = 'course' |
|
|
|
|
|
searchKeyword.value = '' |
|
|
|
|
|
courseStudents.value = [] |
|
|
|
|
|
trialStudents.value = [] |
|
|
|
|
|
students.value = [] |
|
|
|
|
|
selectedStudentIds.value = [] |
|
|
|
|
|
selectedStudents.value = [] |
|
|
|
|
|
|
|
|
|
|
|
// 加载课程人员列表 |
|
|
|
|
|
await fetchCourseStudents() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取课程人员列表 |
|
|
|
|
|
const fetchCourseStudents = async () => { |
|
|
|
|
|
try { |
|
|
|
|
|
if (!selectedCourse.value) return |
|
|
|
|
|
|
|
|
|
|
|
const response = await getCourseStudents(selectedCourse.value) |
|
|
|
|
|
|
|
|
|
|
|
if (response.data) { |
|
|
|
|
|
courseStudents.value = response.data || [] |
|
|
|
|
|
students.value = courseStudents.value |
|
|
|
|
|
|
|
|
|
|
|
// 设置默认选中的学员 - 根据checked属性 |
|
|
|
|
|
const checkedStudents = students.value.filter(student => student.checked === true) |
|
|
|
|
|
selectedStudentIds.value = checkedStudents.map(student => student.id) |
|
|
|
|
|
|
|
|
|
|
|
// 同时记录完整的学员信息 |
|
|
|
|
|
selectedStudents.value = checkedStudents.map(student => ({ |
|
|
|
|
|
id: student.id, |
|
|
|
|
|
student_id: student.student_id || null, |
|
|
|
|
|
name: student.name, |
|
|
|
|
|
student_name: student.student_name || null |
|
|
|
|
|
})) |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('获取课程人员列表失败:', error) |
|
|
|
|
|
ElMessage.error('获取课程人员列表失败') |
|
|
|
|
|
courseStudents.value = [] |
|
|
|
|
|
students.value = [] |
|
|
|
|
|
selectedStudentIds.value = [] |
|
|
|
|
|
selectedStudents.value = [] |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理学员选择变更 |
|
|
|
|
|
const handleStudentCheck = (student, checked) => { |
|
|
|
|
|
if (checked) { |
|
|
|
|
|
// 添加到已选学员列表 |
|
|
|
|
|
if (!selectedStudents.value.some(item => item.id === student.id)) { |
|
|
|
|
|
selectedStudents.value.push({ |
|
|
|
|
|
id: student.id, |
|
|
|
|
|
student_id: student.student_id || null, |
|
|
|
|
|
name: student.name, |
|
|
|
|
|
student_name: student.student_name || null |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 从已选学员列表移除 |
|
|
|
|
|
const index = selectedStudents.value.findIndex(item => item.id === student.id) |
|
|
|
|
|
if (index !== -1) { |
|
|
|
|
|
selectedStudents.value.splice(index, 1) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 人员类型变更 |
|
|
|
|
|
const handlePersonTypeChange = async () => { |
|
|
|
|
|
// 清空搜索框 |
|
|
|
|
|
searchKeyword.value = '' |
|
|
|
|
|
|
|
|
|
|
|
if (personType.value === 'course') { |
|
|
|
|
|
// 切换到课程人员时,显示已缓存的课程人员列表 |
|
|
|
|
|
students.value = courseStudents.value |
|
|
|
|
|
} else { |
|
|
|
|
|
// 切换到试课人员时,调用getTryCoursePerson获取已选中的人员 |
|
|
|
|
|
try { |
|
|
|
|
|
if (selectedCourse.value) { |
|
|
|
|
|
const response = await getTryCoursePerson(selectedCourse.value) |
|
|
|
|
|
|
|
|
|
|
|
if (response.data) { |
|
|
|
|
|
trialStudents.value = response.data || [] |
|
|
|
|
|
students.value = trialStudents.value |
|
|
|
|
|
|
|
|
|
|
|
// 根据返回数据标记已选中的人员 |
|
|
|
|
|
const checkedStudents = students.value.filter(student => student.checked === true) |
|
|
|
|
|
if (checkedStudents.length > 0) { |
|
|
|
|
|
checkedStudents.forEach(student => { |
|
|
|
|
|
if (!selectedStudentIds.value.includes(student.id)) { |
|
|
|
|
|
selectedStudentIds.value.push(student.id) |
|
|
|
|
|
|
|
|
|
|
|
// 同时添加到完整信息列表 |
|
|
|
|
|
if (!selectedStudents.value.some(item => item.id === student.id)) { |
|
|
|
|
|
selectedStudents.value.push({ |
|
|
|
|
|
id: student.id, |
|
|
|
|
|
student_id: student.student_id || null, |
|
|
|
|
|
name: student.name, |
|
|
|
|
|
student_name: student.student_name || null |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
// 如果没有选中课程,显示空列表 |
|
|
|
|
|
trialStudents.value = [] |
|
|
|
|
|
students.value = trialStudents.value |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('获取试课人员失败:', error) |
|
|
|
|
|
ElMessage.error('获取试课人员失败') |
|
|
|
|
|
trialStudents.value = [] |
|
|
|
|
|
students.value = trialStudents.value |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 搜索人员 |
|
|
|
|
|
const searchPerson = async () => { |
|
|
|
|
|
if (!searchKeyword.value.trim()) { |
|
|
|
|
|
ElMessage.warning('请输入搜索关键词') |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const response = await getResourceByNameOrPhone({ |
|
|
|
|
|
name: searchKeyword.value.trim() |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
if (response.data) { |
|
|
|
|
|
// 保存当前已选学员ID列表 |
|
|
|
|
|
const currentSelectedIds = [...selectedStudentIds.value] |
|
|
|
|
|
|
|
|
|
|
|
trialStudents.value = response.data || [] |
|
|
|
|
|
students.value = trialStudents.value |
|
|
|
|
|
|
|
|
|
|
|
// 只有当学员的checked属性明确为true时才添加到已选列表中 |
|
|
|
|
|
// 不再默认选中第一个学员 |
|
|
|
|
|
const checkedStudents = students.value.filter(student => student.checked === true) |
|
|
|
|
|
|
|
|
|
|
|
// 重置选中列表,使用之前保存的选择 |
|
|
|
|
|
selectedStudentIds.value = currentSelectedIds |
|
|
|
|
|
|
|
|
|
|
|
// 添加有checked标记但未选中的项 |
|
|
|
|
|
if (checkedStudents.length > 0) { |
|
|
|
|
|
checkedStudents.forEach(student => { |
|
|
|
|
|
if (!selectedStudentIds.value.includes(student.id)) { |
|
|
|
|
|
selectedStudentIds.value.push(student.id) |
|
|
|
|
|
|
|
|
|
|
|
// 同时添加到完整信息列表 |
|
|
|
|
|
if (!selectedStudents.value.some(item => item.id === student.id)) { |
|
|
|
|
|
selectedStudents.value.push({ |
|
|
|
|
|
id: student.id, |
|
|
|
|
|
student_id: student.student_id || null, |
|
|
|
|
|
name: student.name, |
|
|
|
|
|
student_name: student.student_name || null |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('搜索人员失败:', error) |
|
|
|
|
|
ElMessage.error('搜索人员失败') |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 保存选择的人员 |
|
|
|
|
|
const saveStudents = async () => { |
|
|
|
|
|
if (selectedStudentIds.value.length === 0) { |
|
|
|
|
|
ElMessage.warning('请至少选择一名人员') |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 调用添加人员接口 |
|
|
|
|
|
await addPersonCourseSchedule({ |
|
|
|
|
|
schedule_id: selectedCourse.value, |
|
|
|
|
|
resources_id: selectedStudentIds.value, |
|
|
|
|
|
// 添加student_id数据 |
|
|
|
|
|
student_ids: selectedStudents.value |
|
|
|
|
|
.filter(student => student.student_id) |
|
|
|
|
|
.map(student => student.student_id) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success('保存成功') |
|
|
|
|
|
dialogVisible.value = false |
|
|
|
|
|
|
|
|
|
|
|
// 刷新课程表数据 |
|
|
|
|
|
fetchData() |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('保存人员失败:', error) |
|
|
|
|
|
ElMessage.error('保存人员失败') |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 页面加载时获取数据 |
|
|
// 页面加载时获取数据 |
|
|
onMounted(() => { |
|
|
onMounted(() => { |
|
|
fetchCampusList() |
|
|
fetchCampusList().then(() => { |
|
|
fetchData() |
|
|
fetchData() |
|
|
|
|
|
}) |
|
|
}) |
|
|
}) |
|
|
</script> |
|
|
</script> |
|
|
|
|
|
|
|
|
<style scoped> |
|
|
<style scoped> |
|
|
|
|
|
.header-control-panel { |
|
|
|
|
|
display: flex; |
|
|
|
|
|
justify-content: space-between; |
|
|
|
|
|
align-items: flex-start; |
|
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
.schedule-container { |
|
|
.schedule-container { |
|
|
display: flex; |
|
|
display: flex; |
|
|
gap: 10px; |
|
|
gap: 5px; |
|
|
overflow-x: auto; |
|
|
overflow-x: auto; |
|
|
|
|
|
background-color: #fff; |
|
|
|
|
|
padding: 0; |
|
|
|
|
|
border-radius: 4px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.day-column { |
|
|
.day-column { |
|
|
flex: 1; |
|
|
flex: 1; |
|
|
min-width: 200px; |
|
|
min-width: 180px; |
|
|
|
|
|
display: flex; |
|
|
|
|
|
flex-direction: column; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.day-header { |
|
|
.day-header { |
|
|
text-align: center; |
|
|
text-align: center; |
|
|
font-weight: bold; |
|
|
font-weight: bold; |
|
|
padding: 8px; |
|
|
padding: 8px 0; |
|
|
background-color: #f0f0f0; |
|
|
background-color: #f5f7fa; |
|
|
|
|
|
border-top: 1px solid #ebeef5; |
|
|
|
|
|
border-left: 1px solid #ebeef5; |
|
|
|
|
|
border-right: 1px solid #ebeef5; |
|
|
|
|
|
color: #606266; |
|
|
|
|
|
font-size: 14px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.teacher-name { |
|
|
.teacher-name { |
|
|
font-weight: bold; |
|
|
font-weight: bold; |
|
|
margin-bottom: 5px; |
|
|
margin-bottom: 3px; |
|
|
|
|
|
font-size: 13px; |
|
|
|
|
|
white-space: nowrap; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.student-list { |
|
|
.student-list { |
|
|
margin-top: 5px; |
|
|
margin: 3px 0; |
|
|
|
|
|
max-height: 60px; |
|
|
|
|
|
overflow-y: auto; |
|
|
|
|
|
display: flex; |
|
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.el-table { |
|
|
|
|
|
height: calc(100vh - 220px); |
|
|
|
|
|
overflow-y: auto; |
|
|
|
|
|
font-size: 13px; |
|
|
|
|
|
border-collapse: collapse; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.el-table__cell { |
|
|
.el-table__cell { |
|
|
@ -309,6 +614,129 @@ onMounted(() => { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.classroom-name { |
|
|
.classroom-name { |
|
|
margin-bottom: 5px; |
|
|
margin-top: 3px; |
|
|
|
|
|
font-size: 12px; |
|
|
|
|
|
color: #606266; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.course-cell { |
|
|
|
|
|
padding: 4px; |
|
|
|
|
|
height: 100%; |
|
|
|
|
|
width: 100%; |
|
|
|
|
|
display: flex; |
|
|
|
|
|
flex-direction: column; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
border-radius: 3px; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.custom-student-tag { |
|
|
|
|
|
background-color: #ecf5ff; |
|
|
|
|
|
color: #409eff; |
|
|
|
|
|
border: 1px solid #d9ecff; |
|
|
|
|
|
border-radius: 4px; |
|
|
|
|
|
padding: 0 8px; |
|
|
|
|
|
margin: 2px; |
|
|
|
|
|
font-size: 12px; |
|
|
|
|
|
display: inline-block; |
|
|
|
|
|
max-width: 260px; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
white-space: nowrap; |
|
|
|
|
|
text-overflow: ellipsis; |
|
|
|
|
|
box-sizing: border-box; |
|
|
|
|
|
height: 24px; |
|
|
|
|
|
line-height: 22px; |
|
|
|
|
|
transition: all .2s; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.custom-student-tag:hover { |
|
|
|
|
|
background-color: #d9ecff; |
|
|
|
|
|
color: #3a8ee6; |
|
|
|
|
|
cursor: default; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.tag-content { |
|
|
|
|
|
display: flex; |
|
|
|
|
|
flex-wrap: nowrap; |
|
|
|
|
|
align-items: center; |
|
|
|
|
|
max-width: 100%; |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.tag-label { |
|
|
|
|
|
font-weight: bold; |
|
|
|
|
|
font-size: 11px; |
|
|
|
|
|
flex-shrink: 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.tag-value { |
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
text-overflow: ellipsis; |
|
|
|
|
|
white-space: nowrap; |
|
|
|
|
|
flex: 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.tag-divider { |
|
|
|
|
|
margin: 0 2px; |
|
|
|
|
|
color: #99c2ff; |
|
|
|
|
|
flex-shrink: 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__body-wrapper) { |
|
|
|
|
|
overflow-y: auto; |
|
|
|
|
|
height: 100%; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table__header-wrapper) { |
|
|
|
|
|
position: sticky; |
|
|
|
|
|
top: 0; |
|
|
|
|
|
z-index: 2; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table--border) { |
|
|
|
|
|
border-color: #ebeef5; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table td), :deep(.el-table th) { |
|
|
|
|
|
padding: 4px 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table--enable-row-hover .el-table__body tr:hover > td) { |
|
|
|
|
|
background-color: #f5f7fa; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.student-checkbox-container { |
|
|
|
|
|
max-height: 300px; |
|
|
|
|
|
overflow-y: auto; |
|
|
|
|
|
border: 1px solid #ebeef5; |
|
|
|
|
|
border-radius: 4px; |
|
|
|
|
|
padding: 10px; |
|
|
|
|
|
margin-bottom: 15px; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.student-checkbox-item { |
|
|
|
|
|
margin-right: 10px; |
|
|
|
|
|
margin-bottom: 8px; |
|
|
|
|
|
display: inline-block; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.student-info { |
|
|
|
|
|
display: inline-flex; |
|
|
|
|
|
align-items: center; |
|
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.student-name { |
|
|
|
|
|
font-weight: 500; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.student-school { |
|
|
|
|
|
color: #666; |
|
|
|
|
|
margin-left: 4px; |
|
|
|
|
|
font-size: 0.9em; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.search-box { |
|
|
|
|
|
display: flex; |
|
|
|
|
|
align-items: center; |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</style> |
|
|
|