1、校历的78、晚上、夜间等直接落库,

2、配当、任务书完善、排课窗完善;
3、任务书批量发布、删除等;
4、班历同步校历
This commit is contained in:
2026-09-18 10:38:39 +08:00
parent 911dfe911b
commit f3ae9fb2fd
62 changed files with 3508 additions and 143 deletions
@@ -20,6 +20,7 @@
<el-input v-model="toolbar.eventName" size="small" class="sce-event-input" :placeholder="mode === 'class' ? '请输入班历事件名称' : (mode === 'venue' ? '请输入场地事件名称' : '请输入校历事件名称')" />
<el-checkbox v-if="mode !== 'venue'" v-model="toolbar.bold" class="sce-cb">加粗显示</el-checkbox>
<el-checkbox v-model="toolbar.schedulable" class="sce-cb">可排课</el-checkbox>
<el-checkbox v-if="mode !== 'venue'" v-model="toolbar.autoSchedule" class="sce-cb">自动排课</el-checkbox>
<el-checkbox v-if="mode !== 'venue'" v-model="toolbar.mainCourse" class="sce-cb">正课</el-checkbox>
<el-checkbox v-if="mode !== 'venue'" v-model="toolbar.remarkShow" class="sce-cb">备注显示</el-checkbox>
<span class="sce-label">备注:</span>
@@ -148,25 +149,47 @@ import {
listVenueLessons,
listVenueDesignatedTeams
} from '@/api/teachBusiness/venueCalendar'
import { getSystemSettings, updateSystemSettings, getPeriodSlots } from '@/api/teachBusiness/systemSettings'
// 节次定义:12/34/56 常显,78/晚上/夜间由开关控制可见
const SLOT_DEFS = [
{ key: '12', label: '1-2', ctrl: null },
{ key: '34', label: '3-4', ctrl: null },
{ key: '56', label: '5-6', ctrl: null },
{ key: '78', label: '7-8', ctrl: 'show78' },
{ key: 'night', label: '晚上', ctrl: 'showNight' },
{ key: 'late', label: '夜间', ctrl: 'showLateNight' }
// 节次定义回退值:节次时间表为空时使用,12/34/56 常显,78/晚上/夜间由开关控制可见
const DEFAULT_SLOT_DEFS = [
{ key: '12', label: '1-2', courseClass: '1-2', ctrl: null },
{ key: '34', label: '3-4', courseClass: '3-4', ctrl: null },
{ key: '56', label: '5-6', courseClass: '5-6', ctrl: null },
{ key: '78', label: '7-8', courseClass: '7-8', ctrl: 'show78' },
{ key: 'night', label: '晚上', courseClass: '9-10', ctrl: 'showNight' },
{ key: 'late', label: '夜间', courseClass: '11-12', ctrl: 'showLateNight' }
]
// 前端节次 key -> 后端 xqxlb.courseClass 节次范围(如 12 节 -> "1-2"、夜间 -> "11-12")
const SLOT_COURSE_MAP = {
'12': '1-2',
'34': '3-4',
'56': '5-6',
'78': '7-8',
night: '9-10',
late: '11-12'
const SLOT_COURSE_MAP = {}
DEFAULT_SLOT_DEFS.forEach(s => { SLOT_COURSE_MAP[s.key] = s.courseClass })
// 节次范围解析:"1-2"/"7~8" -> [1,2];单数字 -> [n,n];非数字返回 null
function parseSlotRange(label) {
if (label == null) return null
const s = String(label).trim()
const m = s.match(/(\d+)\s*[-~—–]\s*(\d+)/)
if (m) return [+m[1], +m[2]]
if (/^\d+$/.test(s)) return [+s, +s]
return null
}
// 节次段受哪个显示开关控制:前 6 节常显,7-8 -> show78,9-10 -> showNight,11+ -> showLateNight;
// 非数字标签按名称/时段推断(晚->晚上,夜->夜间)
function ctrlOfSlot(label, sd) {
const range = parseSlotRange(label)
if (range) {
const first = range[0]
if (first <= 6) return null
if (first <= 8) return 'show78'
if (first <= 10) return 'showNight'
return 'showLateNight'
}
const s = String(label || '') + String(sd || '')
if (s.indexOf('夜') >= 0) return 'showLateNight'
if (s.indexOf('晚') >= 0) return 'showNight'
return null
}
const WEEK_DAYS = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
@@ -215,15 +238,20 @@ export default {
totalWeeks: 0,
dateRangeText: '',
weeks: [],
// 显示开关(默认不勾选,每天仅显示 1-2/3-4/5-6 三个节次)
// 显示开关(默认不勾选,挂载时从系统参数 DBVersion 恢复)
show78: false,
showNight: false,
showLateNight: false,
// 系统参数是否已加载(加载完成前的开关赋值不回写)
settingsReady: false,
// 节次列定义:由节次时间表驱动,空表时回退默认六段
slotDefs: DEFAULT_SLOT_DEFS.slice(),
// 工具栏表单
toolbar: {
eventName: '',
bold: false,
schedulable: false,
autoSchedule: false,
mainCourse: false,
remarkShow: false,
remark: ''
@@ -250,7 +278,6 @@ export default {
// 指定本场地为专用教室的班次(顶部横幅)
designatedTeams: [],
weekDayOptions: WEEK_DAYS,
slotOptions: SLOT_DEFS,
ruleDialog: {
visible: false,
submitting: false,
@@ -262,12 +289,16 @@ export default {
}
},
computed: {
// 规律生成弹窗的节次选项(同节次时间表口径)
slotOptions() {
return this.slotDefs
},
// 当前可见列(由开关过滤,默认每天三个节次)
visibleColumns() {
const cols = []
let colIndex = 0
WEEK_DAYS.forEach((dayLabel, dayIndex) => {
SLOT_DEFS.forEach(slot => {
this.slotDefs.forEach(slot => {
if (slot.ctrl && !this[slot.ctrl]) return
cols.push({ colIndex: colIndex, dayIndex: dayIndex, slotKey: slot.key, slotLabel: slot.label, dayLabel: dayLabel })
colIndex++
@@ -312,6 +343,10 @@ export default {
}
},
watch: {
// 显示开关变更即写回系统参数(防抖合并连续变更)
show78() { this.persistDisplaySettings() },
showNight() { this.persistDisplaySettings() },
showLateNight() { this.persistDisplaySettings() },
nd: {
immediate: true,
handler(val) {
@@ -371,10 +406,72 @@ export default {
this.selectedKeys = []
}
},
created() {
this.loadDisplaySettings()
this.loadPeriodSlots()
},
beforeDestroy() {
this.removeGlobalListeners()
if (this._settingsTimer) clearTimeout(this._settingsTimer)
},
methods: {
/* ---------- 系统参数 / 节次字典 ---------- */
// 显示开关从 DBVersion 恢复,刷新不丢配置
loadDisplaySettings() {
getSystemSettings().then(res => {
const d = (res && res.data) || {}
const pick = (a, b) => (d[a] !== undefined ? d[a] : d[b])
this.show78 = !!pick('xs78J', 'xs78j')
this.showNight = !!pick('xsws', 'xsws')
this.showLateNight = !!pick('xsyj', 'xsyj')
this.$nextTick(() => { this.settingsReady = true })
}).catch(() => {
this.settingsReady = true
})
},
// 开关变更回写 DBVersion(只提交三个字段,后端只写非空字段不影响其它参数)
persistDisplaySettings() {
if (!this.settingsReady) return
if (this._settingsTimer) clearTimeout(this._settingsTimer)
this._settingsTimer = setTimeout(() => {
updateSystemSettings({
xs78J: this.show78,
xsws: this.showNight,
xsyj: this.showLateNight
}).catch(() => {})
}, 400)
},
// 节次列由节次时间表驱动;空表或拉取失败保留默认六段
loadPeriodSlots() {
getPeriodSlots().then(res => {
const rows = (res && res.data) || []
const defs = rows
.filter(r => r && r.jcsy)
.map(r => ({
key: String(r.jcsy),
label: String(r.jcsy),
courseClass: String(r.jcsy),
ctrl: ctrlOfSlot(r.jcsy, r.sd)
}))
if (defs.length) this.slotDefs = defs
}).catch(() => {})
},
// 节次格 key -> 后端 courseClass 值(动态节次表优先)
courseClassOfSlot(slotKey) {
const s = this.slotDefs.find(x => x.key === slotKey)
return s ? s.courseClass : (SLOT_COURSE_MAP[slotKey] || null)
},
// 单节次 -> 节次格 key(动态范围优先,回退固定 1-12 映射)
jcToSlotKey(jc) {
const n = Number(jc)
if (!n) return null
for (const s of this.slotDefs) {
const r = parseSlotRange(s.courseClass)
if (r && n >= r[0] && n <= r[1]) return s.key
}
const fallback = JC_SLOT_MAP[n]
return this.slotDefs.some(x => x.key === fallback) ? fallback : null
},
/* ---------- 数据加载 ---------- */
loadClassCalendar() {
const start = (this.rangeStart || '').slice(0, 10)
@@ -504,7 +601,7 @@ export default {
const lessons = {}
lsList.forEach(item => {
const dateStr = String(item.rq || '').slice(0, 10)
const slotKey = JC_SLOT_MAP[item.jc]
const slotKey = this.jcToSlotKey(item.jc)
if (!dateStr || !slotKey) return
const key = dateStr + '#' + slotKey
if (!lessons[key]) lessons[key] = []
@@ -519,7 +616,7 @@ export default {
const merged = {}
list.forEach(row => {
const dateStr = String(row.rq || '').slice(0, 10)
const slotKey = JC_SLOT_MAP[row.jc]
const slotKey = this.jcToSlotKey(row.jc)
if (!dateStr || !slotKey) return
const pos = this.locateDateSlot(dateStr, slotKey)
if (!pos) return
@@ -610,9 +707,11 @@ export default {
return { ok, skipped }
},
periodsOfSlot(slotKey) {
const seg = SLOT_COURSE_MAP[slotKey]
if (!seg) return []
return seg.split('-').map(Number).filter(n => !isNaN(n))
const range = parseSlotRange(this.courseClassOfSlot(slotKey))
if (!range) return []
const list = []
for (let n = range[0]; n <= range[1]; n++) list.push(n)
return list
},
/* ---------- 规律生成 ---------- */
openRuleDialog() {
@@ -676,17 +775,18 @@ export default {
if (slotKey === null) return null
return { wIdx, dayIndex, slotKey }
},
// 后端 courseClass 节次范围 -> 前端节次 key
// 后端 courseClass 节次范围 -> 前端节次 key(动态节次表 + 紧凑写法兼容)
courseClassToSlotKey(courseClass) {
if (!courseClass) return null
const s = String(courseClass).trim()
for (const key in SLOT_COURSE_MAP) {
if (s === SLOT_COURSE_MAP[key]) return key
const direct = this.slotDefs.find(x => x.courseClass === s)
if (direct) return direct.key
// 兼容 "910"/"1112"/"12" 等紧凑写法:按单节次归并到所属段
if (/^\d+$/.test(s) && s.length > 1) {
const first = this.jcToSlotKey(Number(s.slice(0, s.length - 1)))
if (first) return first
}
// 兼容 "910"/"1112" 等紧凑写法
if (s === '910') return 'night'
if (s === '1112') return 'late'
return null
return this.jcToSlotKey(s)
},
// 获取日期所在周的周一(周一为一周起点)
getMonday(d) {
@@ -914,7 +1014,7 @@ export default {
name: name,
bold: this.toolbar.bold,
schedulable: this.toolbar.schedulable,
autoSchedule: !!(prev && prev.autoSchedule),
autoSchedule: !!this.toolbar.autoSchedule,
mainCourse: this.toolbar.mainCourse,
remarkShow: this.toolbar.remarkShow,
remark: this.toolbar.remark
@@ -975,6 +1075,7 @@ export default {
this.toolbar.eventName = target.name
this.toolbar.bold = !!target.bold
this.toolbar.schedulable = !!target.schedulable
this.toolbar.autoSchedule = !!target.autoSchedule
this.toolbar.mainCourse = !!target.mainCourse
this.toolbar.remarkShow = !!target.remarkShow
this.toolbar.remark = target.remark || ''
@@ -997,6 +1098,7 @@ export default {
this.toolbar.eventName = ev.name
this.toolbar.bold = !!ev.bold
this.toolbar.schedulable = !!ev.schedulable
this.toolbar.autoSchedule = !!ev.autoSchedule
this.toolbar.mainCourse = !!ev.mainCourse
this.toolbar.remarkShow = !!ev.remarkShow
this.toolbar.remark = ev.remark || ''
@@ -1132,7 +1234,7 @@ export default {
bzxs: !!ev.remarkShow,
zdpk: !!ev.autoSchedule,
zk: !!ev.mainCourse,
courseClass: SLOT_COURSE_MAP[pos.slotKey] || null,
courseClass: this.courseClassOfSlot(pos.slotKey),
xydxqbh: this.mode === 'class' ? this.xydxqbh : undefined,
xydbh: this.mode === 'class' ? this.xydbh : undefined
}