feat(position): 岗位课程分配增加全选功能和checkbox样式优化
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
- 添加表格多选功能,支持全选/取消全选 - 增加批量设为必修/选修操作 - 优化 checkbox 样式(渐变色、圆角、动画) - 新增批量操作栏UI
This commit is contained in:
@@ -338,40 +338,76 @@
|
|||||||
<div class="course-section">
|
<div class="course-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h4>可用课程列表</h4>
|
<h4>可用课程列表</h4>
|
||||||
<el-input
|
<div class="header-actions">
|
||||||
v-model="courseSearchText"
|
<el-input
|
||||||
placeholder="搜索课程名称"
|
v-model="courseSearchText"
|
||||||
style="width: 200px"
|
placeholder="搜索课程名称"
|
||||||
clearable
|
style="width: 200px"
|
||||||
>
|
clearable
|
||||||
<template #prefix>
|
>
|
||||||
<el-icon><Search /></el-icon>
|
<template #prefix>
|
||||||
</template>
|
<el-icon><Search /></el-icon>
|
||||||
</el-input>
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="filteredAllCourses" style="width: 100%" max-height="300">
|
|
||||||
<el-table-column prop="name" label="课程名称" min-width="200" />
|
<!-- 批量操作栏 -->
|
||||||
<el-table-column prop="category" label="分类" width="120">
|
<div class="batch-actions" v-if="selectedCourses.length > 0">
|
||||||
|
<span class="selected-count">已选择 {{ selectedCourses.length }} 门课程</span>
|
||||||
|
<el-button type="danger" size="small" @click="batchAssignCourse('required')">
|
||||||
|
<el-icon><Star /></el-icon>
|
||||||
|
批量设为必修
|
||||||
|
</el-button>
|
||||||
|
<el-button type="warning" size="small" @click="batchAssignCourse('optional')">
|
||||||
|
<el-icon><CollectionTag /></el-icon>
|
||||||
|
批量设为选修
|
||||||
|
</el-button>
|
||||||
|
<el-button size="small" @click="clearSelection">
|
||||||
|
取消选择
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
ref="courseTableRef"
|
||||||
|
:data="filteredAllCourses"
|
||||||
|
style="width: 100%"
|
||||||
|
max-height="300"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
class="course-table"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55">
|
||||||
|
<template #header>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="isAllSelected"
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
@change="handleSelectAll"
|
||||||
|
class="custom-checkbox"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="name" label="课程名称" min-width="180" />
|
||||||
|
<el-table-column prop="category" label="分类" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag size="small">{{ scope.row.category }}</el-tag>
|
<el-tag size="small">{{ scope.row.category }}</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="duration" label="学时" width="80" />
|
<el-table-column prop="duration" label="学时" width="70" />
|
||||||
<el-table-column prop="difficulty" label="难度" width="100">
|
<el-table-column prop="difficulty" label="难度" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag :type="getDifficultyTagType(scope.row.difficulty)" size="small">
|
<el-tag :type="getDifficultyTagType(scope.row.difficulty)" size="small">
|
||||||
{{ getDifficultyText(scope.row.difficulty) }}
|
{{ getDifficultyText(scope.row.difficulty) }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="当前状态" width="120">
|
<el-table-column label="当前状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="isCourseRequired(scope.row.id)" type="danger" size="small">必修</el-tag>
|
<el-tag v-if="isCourseRequired(scope.row.id)" type="danger" size="small">必修</el-tag>
|
||||||
<el-tag v-else-if="isCourseOptional(scope.row.id)" type="warning" size="small">选修</el-tag>
|
<el-tag v-else-if="isCourseOptional(scope.row.id)" type="warning" size="small">选修</el-tag>
|
||||||
<span v-else class="text-muted">未分配</span>
|
<span v-else class="text-muted">未分配</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="200">
|
<el-table-column label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!isCourseRequired(scope.row.id)"
|
v-if="!isCourseRequired(scope.row.id)"
|
||||||
@@ -452,6 +488,12 @@ const requiredCourses = ref<any[]>([])
|
|||||||
const optionalCourses = ref<any[]>([])
|
const optionalCourses = ref<any[]>([])
|
||||||
const allCourses = ref<any[]>([])
|
const allCourses = ref<any[]>([])
|
||||||
|
|
||||||
|
// 全选相关
|
||||||
|
const courseTableRef = ref<any>(null)
|
||||||
|
const selectedCourses = ref<any[]>([])
|
||||||
|
const isAllSelected = ref(false)
|
||||||
|
const isIndeterminate = ref(false)
|
||||||
|
|
||||||
// 岗位表单
|
// 岗位表单
|
||||||
const positionForm = reactive({
|
const positionForm = reactive({
|
||||||
id: '',
|
id: '',
|
||||||
@@ -941,6 +983,67 @@ const filteredAllCourses = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理表格选择变化
|
||||||
|
*/
|
||||||
|
const handleSelectionChange = (selection: any[]) => {
|
||||||
|
selectedCourses.value = selection
|
||||||
|
const total = filteredAllCourses.value.length
|
||||||
|
isAllSelected.value = selection.length === total && total > 0
|
||||||
|
isIndeterminate.value = selection.length > 0 && selection.length < total
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全选/取消全选
|
||||||
|
*/
|
||||||
|
const handleSelectAll = (val: boolean) => {
|
||||||
|
if (courseTableRef.value) {
|
||||||
|
if (val) {
|
||||||
|
filteredAllCourses.value.forEach(row => {
|
||||||
|
courseTableRef.value.toggleRowSelection(row, true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
courseTableRef.value.clearSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除选择
|
||||||
|
*/
|
||||||
|
const clearSelection = () => {
|
||||||
|
if (courseTableRef.value) {
|
||||||
|
courseTableRef.value.clearSelection()
|
||||||
|
}
|
||||||
|
selectedCourses.value = []
|
||||||
|
isAllSelected.value = false
|
||||||
|
isIndeterminate.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量分配课程
|
||||||
|
*/
|
||||||
|
const batchAssignCourse = async (type: 'required' | 'optional') => {
|
||||||
|
if (!currentPosition.value || selectedCourses.value.length === 0) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const courseIds = selectedCourses.value.map(c => c.id)
|
||||||
|
const response = await request.post(`/api/v1/admin/positions/${currentPosition.value.id}/courses`, {
|
||||||
|
course_ids: courseIds,
|
||||||
|
course_type: type
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response && response.code === 200) {
|
||||||
|
await loadPositionCourses(currentPosition.value.id)
|
||||||
|
clearSelection()
|
||||||
|
ElMessage.success(`已将 ${courseIds.length} 门课程设为${type === 'required' ? '必修' : '选修'}`)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('批量分配课程失败:', error)
|
||||||
|
ElMessage.error('批量分配课程失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查课程是否为必修
|
* 检查课程是否为必修
|
||||||
*/
|
*/
|
||||||
@@ -1326,11 +1429,120 @@ onMounted(() => {
|
|||||||
color: #333;
|
color: #333;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量操作栏样式
|
||||||
|
.batch-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
background: linear-gradient(135deg, #e8f4fd 0%, #f0f7ff 100%);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #d4e8fc;
|
||||||
|
|
||||||
|
.selected-count {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #409eff;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
&.el-button--danger {
|
||||||
|
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #ff5252 0%, #d63031 100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-button--warning {
|
||||||
|
background: linear-gradient(135deg, #ffa726 0%, #ff9800 100%);
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-muted {
|
.text-muted {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 课程表格样式优化
|
||||||
|
.course-table {
|
||||||
|
// Checkbox 样式优化
|
||||||
|
:deep(.el-checkbox) {
|
||||||
|
.el-checkbox__inner {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 2px solid #dcdfe6;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
width: 4px;
|
||||||
|
height: 8px;
|
||||||
|
left: 5px;
|
||||||
|
top: 1px;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .el-checkbox__inner {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked .el-checkbox__inner {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-indeterminate .el-checkbox__inner {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border-color: #667eea;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
height: 3px;
|
||||||
|
top: 6px;
|
||||||
|
left: 3px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格行选中效果
|
||||||
|
:deep(.el-table__row) {
|
||||||
|
&.current-row,
|
||||||
|
&:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selection-row {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表头样式
|
||||||
|
:deep(.el-table__header-wrapper) {
|
||||||
|
th {
|
||||||
|
background-color: #fafafa;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user