diff --git a/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue b/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue index e7a47594..999428ac 100644 --- a/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue +++ b/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue @@ -74,7 +74,7 @@ :data-key="cellKey(wIdx, col.colIndex)" @dblclick="onCellDblClick(wIdx, col)" > - {{ getEvent(wIdx, col.colIndex).name }} + {{ getEvent(wIdx, col.colIndex).name }} {{ dateNumberOf(wIdx, col.dayIndex) }} @@ -134,6 +134,8 @@ export default { // 学期日期范围 startDate: null, endDate: null, + // 日历渲染起点(学期当周周一) + calendarStart: null, totalWeeks: 0, dateRangeText: '', weeks: [], @@ -248,6 +250,7 @@ export default { if (kx && jx) { this.startDate = new Date(kx.replace(/-/g, '/')) this.endDate = new Date(jx.replace(/-/g, '/')) + this.calendarStart = null this.buildWeeks() } this.loadXqxlbEvents() @@ -292,10 +295,10 @@ export default { }, // 根据假期记录反推时间格位置(jqsj 日期 + courseClass 节次),与列是否可见无关 locateXqxlb(item) { - if (!this.startDate || !item.jqsj) return null + if (!this.calendarStart || !item.jqsj) return null const d = new Date(String(item.jqsj).slice(0, 10).replace(/-/g, '/')) if (isNaN(d.getTime())) return null - const offset = Math.round((d - this.startDate) / (24 * 3600 * 1000)) + const offset = Math.round((d - this.calendarStart) / (24 * 3600 * 1000)) if (offset < 0) return null const wIdx = Math.floor(offset / 7) const dayIndex = offset % 7 @@ -315,13 +318,22 @@ export default { if (s === '1112') return 'late' return null }, + // 获取日期所在周的周一(周一为一周起点) + getMonday(d) { + const date = new Date(d) + const day = date.getDay() // 0=周日,1=周一,...,6=周六 + const diff = date.getDate() - day + (day === 0 ? -6 : 1) + date.setDate(diff) + return date + }, buildWeeks() { if (!this.startDate || !this.endDate) return - const start = new Date(this.startDate) + const start = this.getMonday(new Date(this.startDate)) const end = new Date(this.endDate) + this.calendarStart = start const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1 this.totalWeeks = Math.ceil(days / 7) - this.dateRangeText = fmtDate(start) + ' 到 ' + fmtDate(end) + this.dateRangeText = fmtDate(new Date(this.startDate)) + ' 到 ' + fmtDate(new Date(this.endDate)) const weeks = [] for (let w = 0; w < this.totalWeeks; w++) { const wkStart = new Date(start) @@ -355,21 +367,18 @@ export default { }, // 单元格内显示的日期数字(如 0703) dateNumberOf(wIdx, dayIndex) { - if (!this.startDate) return '' - const d = new Date(this.startDate) - d.setDate(this.startDate.getDate() + wIdx * 7 + dayIndex) + if (!this.calendarStart) return '' + const d = new Date(this.calendarStart) + d.setDate(this.calendarStart.getDate() + wIdx * 7 + dayIndex) return pad2(d.getMonth() + 1) + pad2(d.getDate()) }, cellClass(wIdx, col) { const classes = [] - // 星期交替背景(单双日不同底色) - if (col.dayIndex % 2 === 0) classes.push('sce-cell-odd') - else classes.push('sce-cell-even') if (this.selectedKeys.includes(this.cellKey(wIdx, col.colIndex))) classes.push('is-selected') const ev = this.getEvent(wIdx, col.colIndex) - if (ev) { - classes.push('has-event') - if (!ev.schedulable) classes.push('no-schedule') + // 可排课的全部白色;不可排课且事件名非空才标红 + if (ev && ev.name && !ev.schedulable) { + classes.push('no-schedule') } return classes }, @@ -467,8 +476,9 @@ export default { return } const name = this.toolbar.eventName.trim() + // 空名称时按清除处理 if (!name) { - this.$message.warning('请输入事件名称') + this.deleteEvent() return } const keys = [...this.selectedKeys] @@ -492,16 +502,20 @@ export default { return } const keys = [...this.selectedKeys] - keys.forEach(key => { - this.$delete(this.events, key) + this.persistDeleteEvents(keys).then(({ ok, fail }) => { + if (fail === 0) { + keys.forEach(key => { + this.$delete(this.events, key) + }) + this.selectedKeys = [] + } }) - this.$message.success('已删除 ' + keys.length + ' 个时间格事件') }, absorbEvent() { - // 吸取:取选择中第一个有事件的格 + // 吸取:取选择中第一个事件名非空的格 let target = null for (const key of this.selectedKeys) { - if (this.events[key]) { target = this.events[key]; break } + if (this.events[key] && this.events[key].name) { target = this.events[key]; break } } if (!target) { this.$message.warning('所选时间格中无事件可吸取') @@ -517,7 +531,7 @@ export default { }, onCellDblClick(wIdx, col) { const ev = this.getEvent(wIdx, col.colIndex) - if (ev) { + if (ev && ev.name) { this.toolbar.eventName = ev.name this.toolbar.bold = !!ev.bold this.toolbar.schedulable = !!ev.schedulable @@ -561,12 +575,35 @@ export default { return { ok: ok, fail: fail } }) }, + // 批量删除选中格事件 + persistDeleteEvents(keys) { + const tasks = keys + .filter(key => this.events[key]) + .map(key => { + const payload = this.buildXqxlbPayload(key, this.events[key]) + if (!payload) return Promise.resolve(false) + payload.delFlag = 1 + return updateXqxlb(payload) + .then(() => true) + .catch(() => false) + }) + return Promise.all(tasks).then(results => { + const ok = results.filter(r => r === true).length + const fail = results.length - ok + if (fail > 0) { + this.$message.error(fail + ' 个事件删除失败,请检查后端接口') + } else if (ok > 0) { + this.$message.success('已删除 ' + ok + ' 个时间格事件') + } + return { ok: ok, fail: fail } + }) + }, // 构造 xqxlb 提交数据 buildXqxlbPayload(key, ev) { const pos = this.parseCellKey(key) if (!pos) return null - const d = new Date(this.startDate) - d.setDate(this.startDate.getDate() + pos.wIdx * 7 + pos.dayIndex) + const d = new Date(this.calendarStart) + d.setDate(this.calendarStart.getDate() + pos.wIdx * 7 + pos.dayIndex) return { delFlag: 0, bh: ev.bh || undefined, @@ -722,14 +759,20 @@ export default { background: #fff; transition: background 0.15s; - .sce-date-num { color: #c0c4cc; } + .sce-event-name { + display: block; + line-height: 1; + padding: 2px 0; + } - // 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白,便于区分星期 - &.sce-cell-odd { background: #eef6f1; } - &.sce-cell-even { background: #ffffff; } - &.has-event { background: #e6f4ea; } - &.has-event .sce-event-name { color: #00663e; font-weight: 500; } - &.has-event .sce-event-name.is-bold { font-weight: 700; } + .sce-date-num { + display: block; + font-size: 10px; + color: #c0c4cc; + line-height: 1; + } + + // 可排课白色,不可排课且有事件标红 &.no-schedule { background: #fde2e2; } &.is-selected { diff --git a/frontend/src/views/teachBusiness/calendar/index.vue b/frontend/src/views/teachBusiness/calendar/index.vue index d5bcb56f..7418c594 100644 --- a/frontend/src/views/teachBusiness/calendar/index.vue +++ b/frontend/src/views/teachBusiness/calendar/index.vue @@ -40,7 +40,7 @@ class="cal-cell" :class="cellClass(wIdx, col)" > -