This commit is contained in:
2026-08-26 14:10:01 +08:00
parent 09578b9b58
commit 9ae21acaf8
2 changed files with 110 additions and 51 deletions
@@ -74,7 +74,7 @@
:data-key="cellKey(wIdx, col.colIndex)"
@dblclick="onCellDblClick(wIdx, col)"
>
<span v-if="getEvent(wIdx, col.colIndex)" class="sce-event-name" :class="{ 'is-bold': getEvent(wIdx, col.colIndex).bold }">{{ getEvent(wIdx, col.colIndex).name }}</span>
<span v-if="getEvent(wIdx, col.colIndex) && getEvent(wIdx, col.colIndex).name" class="sce-event-name" :class="{ 'is-bold': getEvent(wIdx, col.colIndex).bold }">{{ getEvent(wIdx, col.colIndex).name }}</span>
<span v-else class="sce-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
</td>
</tr>
@@ -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 {
@@ -40,7 +40,7 @@
class="cal-cell"
:class="cellClass(wIdx, col)"
>
<template v-if="getEvent(wIdx, col.colIndex)">
<template v-if="getEvent(wIdx, col.colIndex) && getEvent(wIdx, col.colIndex).name">
<span class="cal-event-name">{{ getEvent(wIdx, col.colIndex).name }}</span>
</template>
<span v-else-if="showDate" class="cal-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
@@ -102,6 +102,8 @@ export default {
// 学期日期范围
startDate: null,
endDate: null,
// 日历渲染起点(学期当周周一)
calendarStart: null,
totalWeeks: 0,
dateRangeText: '',
weeks: [],
@@ -173,6 +175,7 @@ export default {
if (!this.nd) return
this.startDate = null
this.endDate = null
this.calendarStart = null
getSemester(this.nd)
.then(res => {
const data = res.data || res || {}
@@ -215,10 +218,10 @@ export default {
},
// 根据假期记录反推时间格 key(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
@@ -240,13 +243,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)
@@ -276,20 +288,17 @@ 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('cal-cell-odd')
else classes.push('cal-cell-even')
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
},
@@ -339,7 +348,7 @@ export default {
html += '<td>' + week.rangeText + '</td>'
this.visibleColumns.forEach(col => {
const ev = this.getEvent(wIdx, col.colIndex)
if (ev) {
if (ev && ev.name) {
const remark = ev.remark && ev.remarkShow ? '(' + ev.remark + ')' : ''
html += '<td>' + ev.name + remark + '</td>'
} else if (this.showDate) {
@@ -466,13 +475,20 @@ export default {
position: relative;
background: #fff;
.cal-date-num { color: #c0c4cc; }
.cal-event-name {
display: block;
line-height: 1;
padding: 2px 0;
}
// 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白
&.cal-cell-odd { background: #eef6f1; }
&.cal-cell-even { background: #ffffff; }
&.has-event { background: #e6f4ea; }
&.has-event .cal-event-name { color: #00663e; font-weight: 500; }
.cal-date-num {
display: block;
font-size: 10px;
color: #c0c4cc;
line-height: 1;
}
// 可排课白色,不可排课且有事件标红
&.no-schedule { background: #fde2e2; }
}
}