Files
education/frontend/src/views/teachOffice/shiftSemester/index.vue
T
2026-08-21 18:42:51 +08:00

487 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container shift-semester-page">
<!-- ==================== 1. 学年学期标题 ==================== -->
<div class="list-title">{{ semesterName }}</div>
<!-- ==================== 2. 校历 / 预设日期信息区 ==================== -->
<el-card shadow="never" class="search-card">
<el-form class="search-form">
<div class="date-group">
<span class="date-group-label">校历</span>
<el-form-item label="开学日期">
<el-date-picker v-model="semester.kxrq" type="date" format="yyyy年M月d日" value-format="yyyy-MM-dd" style="width: 160px" />
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker v-model="semester.jsrq" type="date" format="yyyy年M月d日" value-format="yyyy-MM-dd" style="width: 160px" />
</el-form-item>
<el-form-item label="学期周数">
<el-input-number v-model="semester.weeks" :min="1" controls-position="right" style="width: 90px" />
</el-form-item>
</div>
<div class="date-group">
<span class="date-group-label">预设</span>
<el-form-item label="开学日期">
<el-date-picker v-model="preset.kxrq" type="date" format="yyyy年M月d日" value-format="yyyy-MM-dd" style="width: 160px" />
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker v-model="preset.jsrq" type="date" format="yyyy年M月d日" value-format="yyyy-MM-dd" style="width: 160px" />
</el-form-item>
<el-form-item label="学期周数">
<el-input-number v-model="preset.weeks" :min="1" controls-position="right" style="width: 90px" />
</el-form-item>
<el-button class="absorb-btn" type="primary" plain @click="handleAbsorbDate">吸取日期</el-button>
</div>
</el-form>
</el-card>
<!-- ==================== 3. 工具栏按钮区 ==================== -->
<div class="list-toolbar">
<div class="left-group">
<!-- 新添下拉列出可新建学期信息的班次 -->
<el-dropdown trigger="click" @command="handleNewCommand">
<el-button type="primary">
<i class="el-icon-plus"></i>
<span>新添</span>
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown" class="new-class-menu">
<el-dropdown-item v-for="item in newableClasses" :key="item.bc" :command="item">
{{ item.bc }}{{ item.xkzy }}{{ item.nj }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button type="primary" plain @click="handleAction('编辑')">编辑</el-button>
<el-button type="primary" plain @click="handleQuickSetDates">快速设定学期日期</el-button>
<el-button type="danger" @click="handleAction('删除')">删除</el-button>
<el-button type="primary" plain @click="handleEditCalendar">编辑班历</el-button>
<el-button type="primary" plain @click="handleAction('自动生成教学计划')">自动生成教学计划</el-button>
<el-button type="primary" plain @click="handleAction('教学计划管理')">教学计划管理</el-button>
<!-- 序号排序带下拉箭头点击弹出排序方式 -->
<el-dropdown trigger="click" @command="handleSortCommand">
<el-button type="primary" plain>
<span>{{ sortLabel }}</span>
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="xh">序号排序</el-dropdown-item>
<el-dropdown-item command="bw">波次排序</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button type="primary" plain @click="handleMerge">预设合班</el-button>
<el-button type="primary" plain @click="handleAction('预设拆班')">预设拆班</el-button>
<el-button type="primary" plain @click="handlePeidangEdit">配档编辑</el-button>
</div>
</div>
<!-- ==================== 4. 班次学期信息列表 ==================== -->
<el-card shadow="never" class="table-card">
<el-table
ref="tableRef"
:data="displayData"
border
stripe
highlight-current-row
:span-method="spanMethod"
:row-class-name="rowClassName"
:header-cell-class-name="headerCellClassName"
max-height="480"
class="class-table"
@current-change="handleCurrentChange"
>
<el-table-column prop="xzdw" label="行政队别" width="90" align="center" show-overflow-tooltip />
<el-table-column prop="xh" label="班次序号" width="70" align="center" />
<el-table-column prop="bc" label="班级" width="70" align="center" show-overflow-tooltip />
<el-table-column prop="rs" label="人数" width="55" align="center" show-overflow-tooltip />
<el-table-column prop="nj" label="年级" width="85" align="center" show-overflow-tooltip />
<el-table-column prop="xkzy" label="学科专业" width="85" align="center" show-overflow-tooltip />
<el-table-column prop="kxrq" label="开学日期" width="90" align="center" show-overflow-tooltip />
<el-table-column prop="jsrq" label="结束日期" width="90" align="center" show-overflow-tooltip />
<el-table-column prop="xqcc" label="学期第次" width="80" align="center" show-overflow-tooltip />
<el-table-column prop="zyjs" label="专用教室" width="80" align="center" show-overflow-tooltip />
<el-table-column prop="jxrw" label="教学任务" min-width="160" align="left" show-overflow-tooltip />
<el-table-column prop="zs" label="周数" width="55" align="center" show-overflow-tooltip />
<el-table-column prop="kcrws" label="总课程数" width="80" align="center" show-overflow-tooltip />
<el-table-column prop="kczs" label="总课时数" width="80" align="center" show-overflow-tooltip />
<el-table-column label="周学时" width="80" align="center">
<template slot-scope="{ row }">{{ row.zxs.toFixed(2) }}</template>
</el-table-column>
<el-table-column prop="zxf" label="总学分" width="70" align="center" show-overflow-tooltip />
</el-table>
</el-card>
<!-- ==================== 教学班次学期信息明细弹窗新添 ==================== -->
<ClassSemesterDetailDialog
:visible="detailVisible"
:class-info="selectedNewClass"
:semester-name="semesterName"
@update:visible="val => detailVisible = val"
@confirm="handleDetailConfirm"
/>
<!-- ==================== 班历设置弹窗编辑班历 ==================== -->
<ClassCalendarDialog
:visible="calendarVisible"
:bc="currentRow ? currentRow.bc : ''"
:semester-name="semesterName"
@update:visible="val => calendarVisible = val"
/>
<!-- ==================== 预设合班弹窗 ==================== -->
<ClassTeamSelectDialog
:visible="teamVisible"
@update:visible="val => teamVisible = val"
@confirm="handleTeamConfirm"
/>
<!-- ==================== 班次学期配档编辑弹窗 ==================== -->
<PeidangEditDialog
:visible="peidangVisible"
:semester-name="semesterName"
:class-label="peidangClassLabel"
@update:visible="val => peidangVisible = val"
@confirm="handleAction('配档编辑')"
/>
</div>
</template>
<script>
import ClassSemesterDetailDialog from './ClassSemesterDetailDialog.vue'
import ClassCalendarDialog from './ClassCalendarDialog.vue'
import ClassTeamSelectDialog from './ClassTeamSelectDialog.vue'
import PeidangEditDialog from './PeidangEditDialog.vue'
export default {
name: 'ShiftSemester',
components: {
ClassSemesterDetailDialog,
ClassCalendarDialog,
ClassTeamSelectDialog,
PeidangEditDialog
},
data() {
return {
// ==================== 1. 学年学期标题区 ====================
semesterName: '2017-2018学年第一学期',
// ==================== 2. 校历 / 预设日期信息区 ====================
/** 校历日期 */
semester: {
kxrq: '2017-07-08', // 校历开学日期
jsrq: '2018-02-11', // 校历结束日期
weeks: 32 // 学期周数
},
/** 预设(班次)日期 */
preset: {
kxrq: '2017-07-08', // 预设开学日期
jsrq: '2018-02-11', // 预设结束日期
weeks: 32 // 预设学期周数
},
// ==================== 3. 工具栏按钮区 ====================
/** 可新建学期信息的班次 */
newableClasses: [
{ bc: '班次0633', xkzy: '专业209', nj: '2017级' },
{ bc: '班次0634', xkzy: '专业209', nj: '2017级' },
{ bc: '班次0709', xkzy: '专业205', nj: '2017级' },
{ bc: '班次0710', xkzy: '专业205', nj: '2017级' },
{ bc: '班次0901', xkzy: '专业301', nj: '2017级' }
],
/** 教学班次学期信息明细弹窗(新添) */
detailVisible: false,
selectedNewClass: null,
/** 班历设置弹窗(编辑班历) */
calendarVisible: false,
currentRow: null,
/** 预设合班弹窗 */
teamVisible: false,
/** 配档编辑弹窗(班次学期配档)显示状态 */
peidangVisible: false,
/** 配档编辑弹窗标题(班次学期配档——...——班次) */
peidangClassLabel: '',
/** 排序方式:xh=序号排序 / bw=波次排序 */
sortType: 'xh',
/** 波次背景色(同一波次使用同一颜色连在一起显示) */
bwColors: [
'#e3f2fd', // 浅蓝
'#e8f5e9', // 浅绿
'#fff8e1', // 浅黄
'#f3e5f5', // 浅紫
'#e0f2f1' // 浅青
],
// ==================== 4. 班次学期信息列表 ====================
tableData: [
// ---- 学员1队(跨 10 行) ----
{ xzdw: '学员1队', xh: 1, bw: 1, bc: '0150', rs: 40, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-307', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
{ xzdw: '学员1队', xh: 2, bw: 1, bc: '0151', rs: 40, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-307', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
{ xzdw: '学员1队', xh: 3, bw: 1, bc: '0152', rs: 40, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-308', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
{ xzdw: '学员1队', xh: 4, bw: 1, bc: '0153', rs: 40, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-308', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
{ xzdw: '学员1队', xh: 5, bw: 1, bc: '0154', rs: 42, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-309', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 528, zxs: 22.0, zxf: 42 },
{ xzdw: '学员1队', xh: 6, bw: 1, bc: '0155', rs: 42, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-309', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 528, zxs: 22.0, zxf: 42 },
{ xzdw: '学员1队', xh: 7, bw: 1, bc: '0156', rs: 42, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-310', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 15, kczs: 540, zxs: 22.5, zxf: 43 },
{ xzdw: '学员1队', xh: 8, bw: 1, bc: '0157', rs: 38, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-310', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 15, kczs: 540, zxs: 22.5, zxf: 43 },
{ xzdw: '学员1队', xh: 9, bw: 1, bc: '0158', rs: 38, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-311', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
{ xzdw: '学员1队', xh: 10, bw: 1, bc: '0159', rs: 38, nj: '2017级秋', xkzy: '专业5', kxrq: '2017-09-03', jsrq: '2018-02-05', xqcc: '第1学期', zyjs: '1-311', jxrw: '2017年下半年教学任务', zs: 24, kcrws: 14, kczs: 512, zxs: 21.33, zxf: 40 },
// ---- 教学五系(跨 2 行) ----
{ xzdw: '教学五系', xh: 11, bw: 2, bc: '0201', rs: 30, nj: '2016级', xkzy: '专业113', kxrq: '2017-08-24', jsrq: '2018-02-05', xqcc: '第3学期', zyjs: '6-202', jxrw: '2017年下半年教学任务', zs: 25, kcrws: 12, kczs: 480, zxs: 19.2, zxf: 36 },
{ xzdw: '教学五系', xh: 12, bw: 2, bc: '0202', rs: 30, nj: '2016级', xkzy: '专业113', kxrq: '2017-08-24', jsrq: '2018-02-05', xqcc: '第3学期', zyjs: '6-202', jxrw: '2017年下半年教学任务', zs: 25, kcrws: 12, kczs: 480, zxs: 19.2, zxf: 36 },
// ---- 教学七系(跨 3 行) ----
{ xzdw: '教学七系', xh: 13, bw: 3, bc: '0203', rs: 36, nj: '2016级', xkzy: '专业115', kxrq: '2017-08-24', jsrq: '2018-02-05', xqcc: '第3学期', zyjs: '8-007', jxrw: '2017年下半年教学任务', zs: 25, kcrws: 13, kczs: 520, zxs: 20.8, zxf: 38 },
{ xzdw: '教学七系', xh: 14, bw: 3, bc: '0204', rs: 36, nj: '2016级', xkzy: '专业115', kxrq: '2017-08-24', jsrq: '2018-02-05', xqcc: '第3学期', zyjs: '8-007', jxrw: '2017年下半年教学任务', zs: 25, kcrws: 13, kczs: 520, zxs: 20.8, zxf: 38 },
{ xzdw: '教学七系', xh: 15, bw: 3, bc: '0205', rs: 36, nj: '2016级', xkzy: '专业115', kxrq: '2017-08-24', jsrq: '2018-02-05', xqcc: '第3学期', zyjs: '8-008', jxrw: '2017年下半年教学任务', zs: 25, kcrws: 13, kczs: 520, zxs: 20.8, zxf: 38 }
]
}
},
computed: {
/** 排序方式标签 */
sortLabel() {
return this.sortType === 'bw' ? '波次排序' : '序号排序'
},
/** 根据排序方式展示列表:波次排序时按波次分组连排 */
displayData() {
if (this.sortType === 'bw') {
return [...this.tableData].sort((a, b) => a.bw - b.bw || a.xh - b.xh)
}
return this.tableData
}
},
mounted() {
// 默认选中第一行 班次0150(高亮)
this.$nextTick(() => {
if (this.tableData.length && this.$refs.tableRef) {
this.$refs.tableRef.setCurrentRow(this.tableData[0])
}
})
},
methods: {
// ==================== 2. 校历 / 预设日期 ====================
/** 吸取日期:将校历日期复制到预设日期 */
handleAbsorbDate() {
this.preset.kxrq = this.semester.kxrq
this.preset.jsrq = this.semester.jsrq
this.preset.weeks = this.semester.weeks
this.$message.success('已吸取校历日期到预设日期')
},
/** 快速设定学期日期 */
handleQuickSetDates() {
this.$message.success('快速设定学期日期(前端演示)')
},
// ==================== 3. 工具栏按钮区 ====================
/** 通用操作(前端演示) */
handleAction(name) {
this.$message.success(`${name}(前端演示)`)
},
/** 新添:从下拉选择班次后打开明细弹窗 */
handleNewCommand(item) {
if (typeof item === 'string') return
this.selectedNewClass = item
this.detailVisible = true
},
handleDetailConfirm() {
this.$message.success('已创建班次学期信息(前端演示)')
},
/** 编辑班历 */
handleEditCalendar() {
if (!this.currentRow) {
this.$message.warning('请先在列表中选择一条班次学期信息')
return
}
this.calendarVisible = true
},
/** 预设合班 */
handleMerge() {
this.teamVisible = true
},
handleTeamConfirm(teams) {
this.$message.success(`预设合班已应用于 ${teams.length} 个班次(前端演示)`)
},
/** 配档编辑:选择班次后打开班次学期配档窗口 */
handlePeidangEdit() {
if (!this.currentRow) {
this.$message.warning('请先在列表中选择一个班次')
return
}
const row = this.currentRow
this.peidangClassLabel = `${row.xzdw}${row.nj}${row.xkzy}班次${row.bc}`
this.peidangVisible = true
},
handleSortCommand(command) {
this.sortType = command
},
/** 行样式:波次排序时同一波次使用同一背景色 */
rowClassName({ row }) {
if (this.sortType !== 'bw') return ''
const colorIndex = (row.bw - 1) % this.bwColors.length
return `bw-row bw-row-${colorIndex}`
},
// ==================== 4. 班次学期信息列表 ====================
handleCurrentChange(row) {
this.currentRow = row
},
/** 合并单元格:行政队别列(第一列)纵向合并相同值 */
spanMethod({ rowIndex, columnIndex }) {
if (columnIndex === 0) {
const list = this.displayData
const current = list[rowIndex]
// 非分组首行,隐藏
if (rowIndex > 0 && list[rowIndex - 1].xzdw === current.xzdw) {
return { rowspan: 0, colspan: 0 }
}
// 统计连续相同行政队别的行数
let rowspan = 1
for (let i = rowIndex + 1; i < list.length; i++) {
if (list[i].xzdw === current.xzdw) rowspan++
else break
}
return { rowspan, colspan: 1 }
}
return { rowspan: 1, colspan: 1 }
},
/** 表头特殊样式:总课程数 / 总课时数列红色框标注 */
headerCellClassName({ column }) {
if (column.property === 'kcrws' || column.property === 'kczs') {
return 'red-header-cell'
}
return ''
}
}
}
</script>
<style scoped lang="scss">
.app-container {
padding: 20px;
}
.shift-semester-page {
// ========== 1. 学年学期标题 ==========
.list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-left: 10px;
border-left: 4px solid var(--edu-green-primary);
}
// ========== 2. 校历 / 预设日期信息区 ==========
.search-card {
margin-bottom: 16px;
.search-form {
.date-group {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 12px;
&:last-child {
margin-bottom: 0;
}
.date-group-label {
flex-shrink: 0;
font-size: 14px;
font-weight: 600;
color: #303133;
margin-right: 8px;
}
.absorb-btn {
margin-left: auto;
align-self: center;
}
.el-form-item {
margin-bottom: 0;
margin-right: 16px;
}
}
}
}
// ========== 3. 工具栏按钮区 ==========
.list-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
.left-group,
.right-group {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
}
// ========== 新建下拉菜单 ==========
.new-class-menu {
max-height: 320px;
overflow-y: auto;
}
// ========== 4. 数据表格区 ==========
$bwColors: (#e3f2fd, #e8f5e9, #fff8e1, #f3e5f5, #e0f2f1);
.table-card {
flex: 1;
.class-table {
width: 100%;
// 波次背景色(同一合班波次使用同一背景颜色连在一起显示)
@for $i from 0 through length($bwColors) - 1 {
::v-deep(.el-table__body tr.bw-row-#{$i} > td.el-table__cell) {
background-color: nth($bwColors, $i + 1);
}
::v-deep(.el-table__body tr.bw-row-#{$i}:hover > td.el-table__cell) {
background-color: nth($bwColors, $i + 1);
}
}
// 当前行高亮(优先于波次背景色)
::v-deep(.el-table__body tr.current-row > td.el-table__cell) {
background-color: #e1f5ec;
}
::v-deep(.el-table__body tr.current-row:hover > td.el-table__cell) {
background-color: #e1f5ec;
}
// 表头红色框标注列(总课程数 / 总课时数)
::v-deep(th.red-header-cell) {
border: 2px solid #f56c6c !important;
background: #fdeaea !important;
}
}
}
}
</style>