forked from liweijie/education
校历
This commit is contained in:
@@ -74,7 +74,7 @@
|
|||||||
:data-key="cellKey(wIdx, col.colIndex)"
|
:data-key="cellKey(wIdx, col.colIndex)"
|
||||||
@dblclick="onCellDblClick(wIdx, col)"
|
@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>
|
<span v-else class="sce-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -134,6 +134,8 @@ export default {
|
|||||||
// 学期日期范围
|
// 学期日期范围
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
|
// 日历渲染起点(学期当周周一)
|
||||||
|
calendarStart: null,
|
||||||
totalWeeks: 0,
|
totalWeeks: 0,
|
||||||
dateRangeText: '',
|
dateRangeText: '',
|
||||||
weeks: [],
|
weeks: [],
|
||||||
@@ -248,6 +250,7 @@ export default {
|
|||||||
if (kx && jx) {
|
if (kx && jx) {
|
||||||
this.startDate = new Date(kx.replace(/-/g, '/'))
|
this.startDate = new Date(kx.replace(/-/g, '/'))
|
||||||
this.endDate = new Date(jx.replace(/-/g, '/'))
|
this.endDate = new Date(jx.replace(/-/g, '/'))
|
||||||
|
this.calendarStart = null
|
||||||
this.buildWeeks()
|
this.buildWeeks()
|
||||||
}
|
}
|
||||||
this.loadXqxlbEvents()
|
this.loadXqxlbEvents()
|
||||||
@@ -292,10 +295,10 @@ export default {
|
|||||||
},
|
},
|
||||||
// 根据假期记录反推时间格位置(jqsj 日期 + courseClass 节次),与列是否可见无关
|
// 根据假期记录反推时间格位置(jqsj 日期 + courseClass 节次),与列是否可见无关
|
||||||
locateXqxlb(item) {
|
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, '/'))
|
const d = new Date(String(item.jqsj).slice(0, 10).replace(/-/g, '/'))
|
||||||
if (isNaN(d.getTime())) return null
|
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
|
if (offset < 0) return null
|
||||||
const wIdx = Math.floor(offset / 7)
|
const wIdx = Math.floor(offset / 7)
|
||||||
const dayIndex = offset % 7
|
const dayIndex = offset % 7
|
||||||
@@ -315,13 +318,22 @@ export default {
|
|||||||
if (s === '1112') return 'late'
|
if (s === '1112') return 'late'
|
||||||
return null
|
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() {
|
buildWeeks() {
|
||||||
if (!this.startDate || !this.endDate) return
|
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)
|
const end = new Date(this.endDate)
|
||||||
|
this.calendarStart = start
|
||||||
const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1
|
const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1
|
||||||
this.totalWeeks = Math.ceil(days / 7)
|
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 = []
|
const weeks = []
|
||||||
for (let w = 0; w < this.totalWeeks; w++) {
|
for (let w = 0; w < this.totalWeeks; w++) {
|
||||||
const wkStart = new Date(start)
|
const wkStart = new Date(start)
|
||||||
@@ -355,21 +367,18 @@ export default {
|
|||||||
},
|
},
|
||||||
// 单元格内显示的日期数字(如 0703)
|
// 单元格内显示的日期数字(如 0703)
|
||||||
dateNumberOf(wIdx, dayIndex) {
|
dateNumberOf(wIdx, dayIndex) {
|
||||||
if (!this.startDate) return ''
|
if (!this.calendarStart) return ''
|
||||||
const d = new Date(this.startDate)
|
const d = new Date(this.calendarStart)
|
||||||
d.setDate(this.startDate.getDate() + wIdx * 7 + dayIndex)
|
d.setDate(this.calendarStart.getDate() + wIdx * 7 + dayIndex)
|
||||||
return pad2(d.getMonth() + 1) + pad2(d.getDate())
|
return pad2(d.getMonth() + 1) + pad2(d.getDate())
|
||||||
},
|
},
|
||||||
cellClass(wIdx, col) {
|
cellClass(wIdx, col) {
|
||||||
const classes = []
|
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')
|
if (this.selectedKeys.includes(this.cellKey(wIdx, col.colIndex))) classes.push('is-selected')
|
||||||
const ev = this.getEvent(wIdx, col.colIndex)
|
const ev = this.getEvent(wIdx, col.colIndex)
|
||||||
if (ev) {
|
// 可排课的全部白色;不可排课且事件名非空才标红
|
||||||
classes.push('has-event')
|
if (ev && ev.name && !ev.schedulable) {
|
||||||
if (!ev.schedulable) classes.push('no-schedule')
|
classes.push('no-schedule')
|
||||||
}
|
}
|
||||||
return classes
|
return classes
|
||||||
},
|
},
|
||||||
@@ -467,8 +476,9 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const name = this.toolbar.eventName.trim()
|
const name = this.toolbar.eventName.trim()
|
||||||
|
// 空名称时按清除处理
|
||||||
if (!name) {
|
if (!name) {
|
||||||
this.$message.warning('请输入事件名称')
|
this.deleteEvent()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const keys = [...this.selectedKeys]
|
const keys = [...this.selectedKeys]
|
||||||
@@ -492,16 +502,20 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const keys = [...this.selectedKeys]
|
const keys = [...this.selectedKeys]
|
||||||
|
this.persistDeleteEvents(keys).then(({ ok, fail }) => {
|
||||||
|
if (fail === 0) {
|
||||||
keys.forEach(key => {
|
keys.forEach(key => {
|
||||||
this.$delete(this.events, key)
|
this.$delete(this.events, key)
|
||||||
})
|
})
|
||||||
this.$message.success('已删除 ' + keys.length + ' 个时间格事件')
|
this.selectedKeys = []
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
absorbEvent() {
|
absorbEvent() {
|
||||||
// 吸取:取选择中第一个有事件的格
|
// 吸取:取选择中第一个事件名非空的格
|
||||||
let target = null
|
let target = null
|
||||||
for (const key of this.selectedKeys) {
|
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) {
|
if (!target) {
|
||||||
this.$message.warning('所选时间格中无事件可吸取')
|
this.$message.warning('所选时间格中无事件可吸取')
|
||||||
@@ -517,7 +531,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onCellDblClick(wIdx, col) {
|
onCellDblClick(wIdx, col) {
|
||||||
const ev = this.getEvent(wIdx, col.colIndex)
|
const ev = this.getEvent(wIdx, col.colIndex)
|
||||||
if (ev) {
|
if (ev && ev.name) {
|
||||||
this.toolbar.eventName = ev.name
|
this.toolbar.eventName = ev.name
|
||||||
this.toolbar.bold = !!ev.bold
|
this.toolbar.bold = !!ev.bold
|
||||||
this.toolbar.schedulable = !!ev.schedulable
|
this.toolbar.schedulable = !!ev.schedulable
|
||||||
@@ -561,12 +575,35 @@ export default {
|
|||||||
return { ok: ok, fail: fail }
|
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 提交数据
|
// 构造 xqxlb 提交数据
|
||||||
buildXqxlbPayload(key, ev) {
|
buildXqxlbPayload(key, ev) {
|
||||||
const pos = this.parseCellKey(key)
|
const pos = this.parseCellKey(key)
|
||||||
if (!pos) return null
|
if (!pos) return null
|
||||||
const d = new Date(this.startDate)
|
const d = new Date(this.calendarStart)
|
||||||
d.setDate(this.startDate.getDate() + pos.wIdx * 7 + pos.dayIndex)
|
d.setDate(this.calendarStart.getDate() + pos.wIdx * 7 + pos.dayIndex)
|
||||||
return {
|
return {
|
||||||
delFlag: 0,
|
delFlag: 0,
|
||||||
bh: ev.bh || undefined,
|
bh: ev.bh || undefined,
|
||||||
@@ -722,14 +759,20 @@ export default {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
|
|
||||||
.sce-date-num { color: #c0c4cc; }
|
.sce-event-name {
|
||||||
|
display: block;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白,便于区分星期
|
.sce-date-num {
|
||||||
&.sce-cell-odd { background: #eef6f1; }
|
display: block;
|
||||||
&.sce-cell-even { background: #ffffff; }
|
font-size: 10px;
|
||||||
&.has-event { background: #e6f4ea; }
|
color: #c0c4cc;
|
||||||
&.has-event .sce-event-name { color: #00663e; font-weight: 500; }
|
line-height: 1;
|
||||||
&.has-event .sce-event-name.is-bold { font-weight: 700; }
|
}
|
||||||
|
|
||||||
|
// 可排课白色,不可排课且有事件标红
|
||||||
&.no-schedule { background: #fde2e2; }
|
&.no-schedule { background: #fde2e2; }
|
||||||
|
|
||||||
&.is-selected {
|
&.is-selected {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
class="cal-cell"
|
class="cal-cell"
|
||||||
:class="cellClass(wIdx, col)"
|
: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>
|
<span class="cal-event-name">{{ getEvent(wIdx, col.colIndex).name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<span v-else-if="showDate" class="cal-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
|
<span v-else-if="showDate" class="cal-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
|
||||||
@@ -102,6 +102,8 @@ export default {
|
|||||||
// 学期日期范围
|
// 学期日期范围
|
||||||
startDate: null,
|
startDate: null,
|
||||||
endDate: null,
|
endDate: null,
|
||||||
|
// 日历渲染起点(学期当周周一)
|
||||||
|
calendarStart: null,
|
||||||
totalWeeks: 0,
|
totalWeeks: 0,
|
||||||
dateRangeText: '',
|
dateRangeText: '',
|
||||||
weeks: [],
|
weeks: [],
|
||||||
@@ -173,6 +175,7 @@ export default {
|
|||||||
if (!this.nd) return
|
if (!this.nd) return
|
||||||
this.startDate = null
|
this.startDate = null
|
||||||
this.endDate = null
|
this.endDate = null
|
||||||
|
this.calendarStart = null
|
||||||
getSemester(this.nd)
|
getSemester(this.nd)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
const data = res.data || res || {}
|
const data = res.data || res || {}
|
||||||
@@ -215,10 +218,10 @@ export default {
|
|||||||
},
|
},
|
||||||
// 根据假期记录反推时间格 key(jqsj 日期 + courseClass 节次)
|
// 根据假期记录反推时间格 key(jqsj 日期 + courseClass 节次)
|
||||||
locateXqxlb(item) {
|
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, '/'))
|
const d = new Date(String(item.jqsj).slice(0, 10).replace(/-/g, '/'))
|
||||||
if (isNaN(d.getTime())) return null
|
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
|
if (offset < 0) return null
|
||||||
const wIdx = Math.floor(offset / 7)
|
const wIdx = Math.floor(offset / 7)
|
||||||
const dayIndex = offset % 7
|
const dayIndex = offset % 7
|
||||||
@@ -240,13 +243,22 @@ export default {
|
|||||||
if (s === '1112') return 'late'
|
if (s === '1112') return 'late'
|
||||||
return null
|
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() {
|
buildWeeks() {
|
||||||
if (!this.startDate || !this.endDate) return
|
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)
|
const end = new Date(this.endDate)
|
||||||
|
this.calendarStart = start
|
||||||
const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1
|
const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1
|
||||||
this.totalWeeks = Math.ceil(days / 7)
|
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 = []
|
const weeks = []
|
||||||
for (let w = 0; w < this.totalWeeks; w++) {
|
for (let w = 0; w < this.totalWeeks; w++) {
|
||||||
const wkStart = new Date(start)
|
const wkStart = new Date(start)
|
||||||
@@ -276,20 +288,17 @@ export default {
|
|||||||
},
|
},
|
||||||
// 单元格内显示的日期数字(如 0703)
|
// 单元格内显示的日期数字(如 0703)
|
||||||
dateNumberOf(wIdx, dayIndex) {
|
dateNumberOf(wIdx, dayIndex) {
|
||||||
if (!this.startDate) return ''
|
if (!this.calendarStart) return ''
|
||||||
const d = new Date(this.startDate)
|
const d = new Date(this.calendarStart)
|
||||||
d.setDate(this.startDate.getDate() + wIdx * 7 + dayIndex)
|
d.setDate(this.calendarStart.getDate() + wIdx * 7 + dayIndex)
|
||||||
return pad2(d.getMonth() + 1) + pad2(d.getDate())
|
return pad2(d.getMonth() + 1) + pad2(d.getDate())
|
||||||
},
|
},
|
||||||
cellClass(wIdx, col) {
|
cellClass(wIdx, col) {
|
||||||
const classes = []
|
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)
|
const ev = this.getEvent(wIdx, col.colIndex)
|
||||||
if (ev) {
|
// 可排课的全部白色;不可排课且事件名非空才标红
|
||||||
classes.push('has-event')
|
if (ev && ev.name && !ev.schedulable) {
|
||||||
if (!ev.schedulable) classes.push('no-schedule')
|
classes.push('no-schedule')
|
||||||
}
|
}
|
||||||
return classes
|
return classes
|
||||||
},
|
},
|
||||||
@@ -339,7 +348,7 @@ export default {
|
|||||||
html += '<td>' + week.rangeText + '</td>'
|
html += '<td>' + week.rangeText + '</td>'
|
||||||
this.visibleColumns.forEach(col => {
|
this.visibleColumns.forEach(col => {
|
||||||
const ev = this.getEvent(wIdx, col.colIndex)
|
const ev = this.getEvent(wIdx, col.colIndex)
|
||||||
if (ev) {
|
if (ev && ev.name) {
|
||||||
const remark = ev.remark && ev.remarkShow ? '(' + ev.remark + ')' : ''
|
const remark = ev.remark && ev.remarkShow ? '(' + ev.remark + ')' : ''
|
||||||
html += '<td>' + ev.name + remark + '</td>'
|
html += '<td>' + ev.name + remark + '</td>'
|
||||||
} else if (this.showDate) {
|
} else if (this.showDate) {
|
||||||
@@ -466,13 +475,20 @@ export default {
|
|||||||
position: relative;
|
position: relative;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|
||||||
.cal-date-num { color: #c0c4cc; }
|
.cal-event-name {
|
||||||
|
display: block;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白
|
.cal-date-num {
|
||||||
&.cal-cell-odd { background: #eef6f1; }
|
display: block;
|
||||||
&.cal-cell-even { background: #ffffff; }
|
font-size: 10px;
|
||||||
&.has-event { background: #e6f4ea; }
|
color: #c0c4cc;
|
||||||
&.has-event .cal-event-name { color: #00663e; font-weight: 500; }
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可排课白色,不可排课且有事件标红
|
||||||
&.no-schedule { background: #fde2e2; }
|
&.no-schedule { background: #fde2e2; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user