1课表模板管理;
2、课表生成; 3、课表的网格视图; 4、导出与打印
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 课表模版管理(KCBMBController /kcbmb,手册一第12章)
|
||||
|
||||
/** 分页查询模版列表 GET /kcbmb/list(pageNum/pageSize/mbmc) */
|
||||
export function listKcbmb(params) {
|
||||
return request({
|
||||
url: '/kcbmb/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
/** 模版详情 GET /kcbmb/get?bh= */
|
||||
export function getKcbmb(bh) {
|
||||
return request({
|
||||
url: '/kcbmb/get',
|
||||
method: 'get',
|
||||
params: { bh }
|
||||
})
|
||||
}
|
||||
|
||||
/** 可用模版下拉 GET /kcbmb/options → [{bh, mbmc}] */
|
||||
export function listKcbmbOptions() {
|
||||
return request({
|
||||
url: '/kcbmb/options',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/** 新增模版 POST /kcbmb/add */
|
||||
export function addKcbmb(data) {
|
||||
return request({
|
||||
url: '/kcbmb/add',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/** 更新模版 POST /kcbmb/update */
|
||||
export function updateKcbmb(data) {
|
||||
return request({
|
||||
url: '/kcbmb/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除模版 POST /kcbmb/delete?bh= */
|
||||
export function deleteKcbmb(bh) {
|
||||
return request({
|
||||
url: '/kcbmb/delete',
|
||||
method: 'post',
|
||||
params: { bh }
|
||||
})
|
||||
}
|
||||
|
||||
/** 启用/停用模版 POST /kcbmb/toggle?bh=&enabled= */
|
||||
export function toggleKcbmb(bh, enabled) {
|
||||
return request({
|
||||
url: '/kcbmb/toggle',
|
||||
method: 'post',
|
||||
params: { bh, enabled }
|
||||
})
|
||||
}
|
||||
@@ -87,3 +87,30 @@ export function exportClassCourses(data) {
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 周次横版课表网格(手册一第12章)
|
||||
* GET /kcb/grid?dim=&id=&nd=&start=&end=&mbbh=
|
||||
* dim: semester 班次学期 | team 学员队 | teacher 教员 | room 教室
|
||||
* 返回 TimetableGridVO:periods / weeks[].days[].cells / remarks
|
||||
*/
|
||||
export function getTimetableGrid(params) {
|
||||
return request({
|
||||
url: '/kcb/grid',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 网格课表矩阵 Excel 导出(每周一个 sheet)
|
||||
* GET /kcb/grid/export(参数同 getTimetableGrid)
|
||||
*/
|
||||
export function exportTimetableGrid(params) {
|
||||
return request({
|
||||
url: '/kcb/grid/export',
|
||||
method: 'get',
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
<template>
|
||||
<div class="tg-view" v-loading="loading">
|
||||
<template v-if="grid && grid.weeks && grid.weeks.length">
|
||||
<div v-for="week in grid.weeks" :key="week.weekNo" class="tg-week">
|
||||
<div class="tg-week-title">
|
||||
第 {{ week.weekNo }} 周({{ week.startDate }} ~ {{ week.endDate }})
|
||||
</div>
|
||||
<table class="tg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tg-col-period">节次</th>
|
||||
<th v-for="d in week.days" :key="d.date" :class="{ 'tg-blocked': d.blocked }">
|
||||
<div>星期{{ weekdayName(d.weekday) }}</div>
|
||||
<div class="tg-date">{{ d.date }}</div>
|
||||
<div v-if="d.blocked && d.blockReason" class="tg-block-reason">{{ d.blockReason }}</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="p in grid.periods" :key="p.jc">
|
||||
<td class="tg-period">
|
||||
<div class="tg-period-name">{{ p.mc }}</div>
|
||||
<div v-if="p.kssj" class="tg-period-time">{{ p.kssj }}-{{ p.jssj }}</div>
|
||||
<div class="tg-period-sd">{{ p.sd }}</div>
|
||||
</td>
|
||||
<td
|
||||
v-for="d in week.days"
|
||||
:key="d.date"
|
||||
class="tg-cell"
|
||||
:class="{ 'tg-blocked': d.blocked }"
|
||||
>
|
||||
<div v-for="(cell, i) in cellsOf(d, p.jc)" :key="i" class="tg-lesson">
|
||||
<div class="tg-course">{{ cell.kcjc || cell.kcmc }}</div>
|
||||
<div v-if="showTeacher && cell.jyxm" class="tg-sub">{{ cell.jyxm }}</div>
|
||||
<div v-if="showRoom && cell.jsmc" class="tg-sub">{{ cell.jsmc }}</div>
|
||||
<div v-if="showTeam && cell.xydmc" class="tg-sub">{{ cell.xydmc }}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-if="grid.remarks && grid.remarks.length" class="tg-remarks">
|
||||
<div class="tg-remarks-title">备注栏</div>
|
||||
<div v-for="(r, i) in grid.remarks" :key="i" class="tg-remark-row">
|
||||
<span class="tg-remark-date">{{ r.date }}</span>
|
||||
<span class="tg-remark-scope">[{{ r.scope }}]</span>
|
||||
<span>{{ r.text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<el-empty v-else-if="!loading" description="请选择维度与日期范围后生成课表" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const WEEKDAY_NAMES = ['', '一', '二', '三', '四', '五', '六', '日']
|
||||
|
||||
/**
|
||||
* 周次横版课表网格(手册一第12章)。
|
||||
* 行=节次、列=星期一~日、纵向按周分块;备注栏事件不落格。
|
||||
* 供「课表生成」页与后续角色化页面(教员端/学员端)复用。
|
||||
*/
|
||||
export default {
|
||||
name: 'TimetableGridView',
|
||||
props: {
|
||||
grid: { type: Object, default: null },
|
||||
loading: { type: Boolean, default: false },
|
||||
showTeacher: { type: Boolean, default: true },
|
||||
showRoom: { type: Boolean, default: true },
|
||||
showTeam: { type: Boolean, default: false }
|
||||
},
|
||||
methods: {
|
||||
weekdayName(wd) {
|
||||
return WEEKDAY_NAMES[wd] || wd
|
||||
},
|
||||
cellsOf(day, jc) {
|
||||
return (day.cells && day.cells[String(jc)]) || []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tg-view {
|
||||
.tg-week {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tg-week-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.tg-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
table-layout: fixed;
|
||||
background: #fff;
|
||||
|
||||
th, td {
|
||||
border: 1px solid #dcdfe6;
|
||||
padding: 6px;
|
||||
vertical-align: top;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #f5f7fa;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tg-col-period {
|
||||
width: 96px;
|
||||
}
|
||||
|
||||
.tg-date {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.tg-block-reason {
|
||||
font-size: 11px;
|
||||
color: #f56c6c;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
th.tg-blocked {
|
||||
background: repeating-linear-gradient(45deg, #f5f7fa, #f5f7fa 6px, #eceff2 6px, #eceff2 12px);
|
||||
}
|
||||
|
||||
td.tg-blocked {
|
||||
background: repeating-linear-gradient(45deg, #fafafa, #fafafa 6px, #f0f1f2 6px, #f0f1f2 12px);
|
||||
}
|
||||
}
|
||||
|
||||
.tg-period {
|
||||
text-align: center;
|
||||
background: #fafbfc;
|
||||
|
||||
.tg-period-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tg-period-time {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.tg-period-sd {
|
||||
font-size: 11px;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
|
||||
.tg-lesson {
|
||||
margin-bottom: 4px;
|
||||
padding: 4px;
|
||||
background: #eef6f2;
|
||||
border-radius: 3px;
|
||||
border-left: 3px solid var(--edu-color-primary, #0b6b55);
|
||||
|
||||
.tg-course {
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.tg-sub {
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.tg-remarks {
|
||||
margin-top: 8px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
background: #fff;
|
||||
|
||||
.tg-remarks-title {
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.tg-remark-row {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
line-height: 1.8;
|
||||
|
||||
.tg-remark-date {
|
||||
color: #909399;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.tg-remark-scope {
|
||||
color: #e6a23c;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.tg-view {
|
||||
.tg-week {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<div class="app-container tg-page">
|
||||
<div class="section-card no-print">
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<div class="section-title">课表生成</div>
|
||||
<div class="section-desc">按 班次学期 / 学员队 / 教员 / 教室 生成周次横版课表,可套用课表模板、导出矩阵 Excel 或直接打印</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button type="success" size="mini" icon="el-icon-download" :loading="exporting" :disabled="!grid" @click="handleExport">导出 Excel</el-button>
|
||||
<el-button type="primary" size="mini" icon="el-icon-printer" :disabled="!grid" @click="handlePrint">打印</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-form inline class="filter-form" @submit.native.prevent>
|
||||
<el-form-item label="维度">
|
||||
<el-select v-model="dim" style="width: 130px" @change="handleDimChange">
|
||||
<el-option label="班次学期" value="semester" />
|
||||
<el-option label="学员队" value="team" />
|
||||
<el-option label="教员" value="teacher" />
|
||||
<el-option label="教室" value="room" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="dimLabel">
|
||||
<el-select v-model="targetId" :placeholder="'请选择' + dimLabel" clearable filterable :loading="optionsLoading" style="width: 240px">
|
||||
<el-option v-for="o in targetOptions" :key="o.value" :label="o.label" :value="o.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="日期范围">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="默认学期/本周"
|
||||
end-placeholder="默认学期/本周"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="width: 250px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="课表模板">
|
||||
<el-select v-model="mbbh" placeholder="默认样式" clearable style="width: 160px">
|
||||
<el-option v-for="t in templateOptions" :key="t.bh" :label="t.mbmc" :value="t.bh" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="mini" icon="el-icon-search" :loading="loading" @click="handleGenerate">生成课表</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="格内显示">
|
||||
<el-checkbox v-model="showTeacher">教员</el-checkbox>
|
||||
<el-checkbox v-model="showRoom">场地</el-checkbox>
|
||||
<el-checkbox v-model="showTeam">班次</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="section-card">
|
||||
<div v-if="grid" class="grid-title">
|
||||
{{ grid.targetName }}({{ grid.startDate }} ~ {{ grid.endDate }})
|
||||
<el-tag v-if="mbbh" size="mini" type="warning" class="plan-tag">计划课表 · {{ templateName }}</el-tag>
|
||||
<el-tag v-else size="mini" type="success" class="plan-tag">运行课表</el-tag>
|
||||
</div>
|
||||
<timetable-grid-view
|
||||
:grid="grid"
|
||||
:loading="loading"
|
||||
:show-teacher="showTeacher"
|
||||
:show-room="showRoom"
|
||||
:show-team="showTeam"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TimetableGridView from '@/components/TimetableGridView'
|
||||
import { getTimetableGrid, exportTimetableGrid } from '@/api/teachBusiness/timetable'
|
||||
import { listKcbmbOptions } from '@/api/teachBusiness/kcbmb'
|
||||
import { allSemester } from '@/api/studentRecords/semester'
|
||||
import { listTeam } from '@/api/studentRecords/team'
|
||||
import { listTeacher } from '@/api/teachOffice/teacher'
|
||||
import { listAllClassroom } from '@/api/teachBusiness/classroom'
|
||||
import { saveAs } from 'file-saver'
|
||||
|
||||
const DIM_LABELS = { semester: '班次学期', team: '学员队', teacher: '教员', room: '教室' }
|
||||
|
||||
export default {
|
||||
name: 'TimetableGrid',
|
||||
components: { TimetableGridView },
|
||||
data() {
|
||||
return {
|
||||
dim: 'semester',
|
||||
targetId: undefined,
|
||||
targetOptions: [],
|
||||
optionsLoading: false,
|
||||
dateRange: null,
|
||||
mbbh: undefined,
|
||||
templateOptions: [],
|
||||
showTeacher: true,
|
||||
showRoom: true,
|
||||
showTeam: false,
|
||||
loading: false,
|
||||
exporting: false,
|
||||
grid: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dimLabel() {
|
||||
return DIM_LABELS[this.dim] || '对象'
|
||||
},
|
||||
templateName() {
|
||||
const t = this.templateOptions.find(o => o.bh === this.mbbh)
|
||||
return t ? t.mbmc : ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadTemplates()
|
||||
this.loadTargetOptions()
|
||||
},
|
||||
methods: {
|
||||
loadTemplates() {
|
||||
listKcbmbOptions().then(response => {
|
||||
this.templateOptions = response.data || []
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleDimChange() {
|
||||
this.targetId = undefined
|
||||
this.targetOptions = []
|
||||
this.loadTargetOptions()
|
||||
},
|
||||
loadTargetOptions() {
|
||||
this.optionsLoading = true
|
||||
const done = list => {
|
||||
this.targetOptions = list
|
||||
this.optionsLoading = false
|
||||
}
|
||||
const fail = () => {
|
||||
this.targetOptions = []
|
||||
this.optionsLoading = false
|
||||
}
|
||||
if (this.dim === 'semester') {
|
||||
allSemester().then(response => {
|
||||
done((response.data || []).map(s => ({
|
||||
value: s.bh,
|
||||
label: `${s.xydbh}(${s.nd}年度 第${s.xqdc}学期)`
|
||||
})))
|
||||
}).catch(fail)
|
||||
} else if (this.dim === 'team') {
|
||||
listTeam({ pageNum: 1, pageSize: 500 }).then(response => {
|
||||
const page = response.data || {}
|
||||
done((page.records || []).map(t => ({ value: t.xydbh, label: t.xydmc || t.xydbh })))
|
||||
}).catch(fail)
|
||||
} else if (this.dim === 'teacher') {
|
||||
listTeacher({ pageNum: 1, pageSize: 500 }).then(response => {
|
||||
const page = response.data || {}
|
||||
done((page.records || []).map(t => ({ value: t.jybh, label: (t.jyxm || '-') + '(' + t.jybh + ')' })))
|
||||
}).catch(fail)
|
||||
} else {
|
||||
listAllClassroom().then(response => {
|
||||
done((response.data || []).map(r => ({ value: r.jsbh, label: (r.jsmc || '-') + '(' + r.jsbh + ')' })))
|
||||
}).catch(fail)
|
||||
}
|
||||
},
|
||||
buildQuery() {
|
||||
const q = { dim: this.dim, id: this.targetId, mbbh: this.mbbh }
|
||||
if (this.dateRange && this.dateRange.length === 2) {
|
||||
q.start = this.dateRange[0]
|
||||
q.end = this.dateRange[1]
|
||||
}
|
||||
return q
|
||||
},
|
||||
handleGenerate() {
|
||||
if (!this.targetId) {
|
||||
this.$message.warning('请选择' + this.dimLabel)
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
getTimetableGrid(this.buildQuery()).then(response => {
|
||||
this.grid = response.data
|
||||
}).catch(() => {
|
||||
this.grid = null
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleExport() {
|
||||
this.exporting = true
|
||||
exportTimetableGrid(this.buildQuery()).then(blob => {
|
||||
saveAs(blob, `课表_${this.grid && this.grid.targetName ? this.grid.targetName : this.dim}.xlsx`)
|
||||
}).catch(() => {
|
||||
this.$message.error('导出失败')
|
||||
}).finally(() => {
|
||||
this.exporting = false
|
||||
})
|
||||
},
|
||||
handlePrint() {
|
||||
window.print()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tg-page {
|
||||
.section-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
margin-top: 6px;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.filter-form ::v-deep .el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.grid-title {
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
margin-bottom: 14px;
|
||||
|
||||
.plan-tag {
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
.tg-page .no-print {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,292 @@
|
||||
<template>
|
||||
<div class="app-container tpl-page">
|
||||
<div class="section-card">
|
||||
<div class="section-header">
|
||||
<div>
|
||||
<div class="section-title">课表模板管理</div>
|
||||
<div class="section-desc">维护课表输出样式模板;「课表生成」页可选择模板套用其显示开关(78节 / 晚上 / 夜间 / 选修 / 显示天数)</div>
|
||||
</div>
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAdd">新增模板</el-button>
|
||||
</div>
|
||||
<el-form inline class="filter-form" @submit.native.prevent>
|
||||
<el-form-item label="模板名称">
|
||||
<el-input v-model="queryMbmc" placeholder="按名称模糊" clearable style="width: 200px" @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="mini" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button size="mini" icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="section-card">
|
||||
<el-table v-loading="loading" :data="tableData" border stripe size="mini">
|
||||
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||
<el-table-column prop="mbmc" label="模板名称" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="78节" width="70" align="center">
|
||||
<template slot-scope="scope">{{ boolText(scope.row.zxxs78j) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="晚上" width="70" align="center">
|
||||
<template slot-scope="scope">{{ boolText(scope.row.zxxsws) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="夜间" width="70" align="center">
|
||||
<template slot-scope="scope">{{ boolText(scope.row.xsyj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="含选修" width="70" align="center">
|
||||
<template slot-scope="scope">{{ boolText(scope.row.kbbhxx) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="zxxsts" label="显示天数" width="80" align="center" />
|
||||
<el-table-column prop="wkzwzf" label="无课站位" width="90" align="center" />
|
||||
<el-table-column label="可用" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-switch
|
||||
:value="isTrue(scope.row.mbky)"
|
||||
active-text=""
|
||||
@change="v => handleToggle(scope.row, v)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="gxsj" label="更新时间" width="150" align="center">
|
||||
<template slot-scope="scope">{{ fmt(scope.row.gxsj) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bz" label="备注" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="操作" width="130" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" icon="el-icon-delete" class="danger-text" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
v-if="total > 0"
|
||||
class="pagination"
|
||||
background
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:current-page="pageNum"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
@current-change="handlePageChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="620px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="130px">
|
||||
<el-form-item label="模板名称" prop="mbmc">
|
||||
<el-input v-model="form.mbmc" placeholder="如:标准周课表" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示 7-8 节">
|
||||
<el-switch v-model="form.zxxs78j" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示晚上时段">
|
||||
<el-switch v-model="form.zxxsws" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示夜间时段">
|
||||
<el-switch v-model="form.xsyj" />
|
||||
</el-form-item>
|
||||
<el-form-item label="包含选修课">
|
||||
<el-switch v-model="form.kbbhxx" />
|
||||
</el-form-item>
|
||||
<el-form-item label="一周显示天数">
|
||||
<el-input-number v-model="form.zxxsts" :min="1" :max="7" />
|
||||
<span class="form-tip">5 = 只显示工作日</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="无课站位字符">
|
||||
<el-input v-model="form.wkzwzf" placeholder="留空则空格,如:—" maxlength="10" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="form.bz" type="textarea" :rows="2" maxlength="200" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="handleSave">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listKcbmb, addKcbmb, updateKcbmb, deleteKcbmb, toggleKcbmb } from '@/api/teachBusiness/kcbmb'
|
||||
|
||||
export default {
|
||||
name: 'TimetableTemplate',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saving: false,
|
||||
queryMbmc: '',
|
||||
tableData: [],
|
||||
total: 0,
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
dialogVisible: false,
|
||||
dialogTitle: '新增模板',
|
||||
form: this.emptyForm(),
|
||||
rules: {
|
||||
mbmc: [{ required: true, message: '请输入模板名称', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadList()
|
||||
},
|
||||
methods: {
|
||||
emptyForm() {
|
||||
return {
|
||||
bh: undefined,
|
||||
mbmc: '',
|
||||
zxxs78j: true,
|
||||
zxxsws: true,
|
||||
xsyj: false,
|
||||
kbbhxx: true,
|
||||
zxxsts: 7,
|
||||
wkzwzf: '',
|
||||
bz: ''
|
||||
}
|
||||
},
|
||||
isTrue(v) {
|
||||
return v === true || v === 1 || v === '1' || v === 'true'
|
||||
},
|
||||
boolText(v) {
|
||||
return this.isTrue(v) ? '显示' : '隐藏'
|
||||
},
|
||||
fmt(t) {
|
||||
return (t || '').replace('T', ' ').substring(0, 16)
|
||||
},
|
||||
loadList() {
|
||||
this.loading = true
|
||||
listKcbmb({ pageNum: this.pageNum, pageSize: this.pageSize, mbmc: this.queryMbmc }).then(response => {
|
||||
const page = response.data || {}
|
||||
this.tableData = page.records || []
|
||||
this.total = page.total || 0
|
||||
}).catch(() => {
|
||||
this.tableData = []
|
||||
this.total = 0
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
handleReset() {
|
||||
this.queryMbmc = ''
|
||||
this.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
handlePageChange(p) {
|
||||
this.pageNum = p
|
||||
this.loadList()
|
||||
},
|
||||
handleSizeChange(s) {
|
||||
this.pageSize = s
|
||||
this.pageNum = 1
|
||||
this.loadList()
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogTitle = '新增模板'
|
||||
this.form = this.emptyForm()
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.dialogTitle = '编辑模板'
|
||||
this.form = {
|
||||
bh: row.bh,
|
||||
mbmc: row.mbmc,
|
||||
zxxs78j: this.isTrue(row.zxxs78j),
|
||||
zxxsws: this.isTrue(row.zxxsws),
|
||||
xsyj: this.isTrue(row.xsyj),
|
||||
kbbhxx: this.isTrue(row.kbbhxx),
|
||||
zxxsts: row.zxxsts || 7,
|
||||
wkzwzf: row.wkzwzf || '',
|
||||
bz: row.bz || ''
|
||||
}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleSave() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
this.saving = true
|
||||
const fn = this.form.bh ? updateKcbmb : addKcbmb
|
||||
fn(this.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.loadList()
|
||||
}).finally(() => {
|
||||
this.saving = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleToggle(row, enabled) {
|
||||
toggleKcbmb(row.bh, enabled).then(() => {
|
||||
row.mbky = enabled
|
||||
this.$message.success(enabled ? '已启用' : '已停用')
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$confirm(`确认删除模板「${row.mbmc}」?`, '提示', { type: 'warning' }).then(() => {
|
||||
return deleteKcbmb(row.bh)
|
||||
}).then(() => {
|
||||
this.$message.success('已删除')
|
||||
this.loadList()
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tpl-page {
|
||||
.section-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 16px 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
margin-top: 6px;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.filter-form ::v-deep .el-form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-tip {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.danger-text {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 12px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user