Files
education/frontend/src/views/teachBusiness/calendar/components/SchoolCalendarEditor.vue
T
2026-08-26 09:52:26 +08:00

754 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="school-calendar-editor">
<!-- 标题栏 -->
<div class="sce-titlebar">
<div class="sce-title-left">
<span class="sce-semester-name">{{ semesterName }}</span>
</div>
<div class="sce-title-center">
<span class="sce-date-range"> {{ dateRangeText }} {{ totalWeeks }} </span>
</div>
<div class="sce-title-right">
<i class="el-icon-close" title="关闭" @click="handleClose" />
</div>
</div>
<!-- 设置面板 -->
<div class="sce-panel">
<div class="sce-panel-row">
<span class="sce-label">事件名称:</span>
<el-input v-model="toolbar.eventName" size="small" class="sce-event-input" placeholder="请输入校历事件名称" />
<el-checkbox v-model="toolbar.bold" class="sce-cb">加粗显示</el-checkbox>
<el-checkbox v-model="toolbar.schedulable" class="sce-cb">可排课</el-checkbox>
<el-checkbox v-model="toolbar.mainCourse" class="sce-cb">正课</el-checkbox>
<el-checkbox v-model="toolbar.remarkShow" class="sce-cb">备注显示</el-checkbox>
<span class="sce-label">备注:</span>
<el-input
v-model="toolbar.remark"
size="small"
type="textarea"
:rows="1"
class="sce-remark-input"
resize="none"
placeholder="备注信息"
/>
</div>
<div class="sce-panel-row">
<el-button type="primary" size="small" icon="el-icon-check" @click="applyEvent">设定</el-button>
<el-button type="danger" size="small" icon="el-icon-delete" @click="deleteEvent">删除</el-button>
<el-button size="small" icon="el-icon-brush" @click="absorbEvent">吸取</el-button>
<el-button size="small" icon="el-icon-refresh" @click="refreshGrid">刷新</el-button>
<span class="sce-divider" />
<el-checkbox v-model="show78" class="sce-cb">显示78节</el-checkbox>
<el-checkbox v-model="showNight" class="sce-cb">显示晚上</el-checkbox>
<el-checkbox v-model="showLateNight" class="sce-cb">显示夜间</el-checkbox>
</div>
</div>
<!-- 时间编排区域 -->
<div ref="gridWrap" class="sce-grid-wrap" @mousedown="onGridMouseDown">
<table class="sce-grid" :class="{ 'is-selecting': selecting }">
<thead>
<tr>
<th class="sce-corner sce-th-weekno" :rowspan="2">周次</th>
<th class="sce-corner sce-th-weekrange" :rowspan="2">日期段</th>
<th v-for="col in visibleColumns" :key="'h1-' + col.colIndex" :colspan="1" class="sce-th-day">
{{ weekDayLabel(col.dayIndex) }}
</th>
</tr>
<tr>
<th v-for="col in visibleColumns" :key="'h2-' + col.colIndex" class="sce-th-slot">
{{ col.slotLabel }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(week, wIdx) in weeks" :key="'w-' + wIdx">
<td class="sce-week-cell sce-weekno-cell">{{ wIdx + 1 }}</td>
<td class="sce-week-cell sce-weekrange-cell">{{ week.rangeText }}</td>
<td
v-for="col in visibleColumns"
:key="'c-' + wIdx + '-' + col.colIndex"
class="sce-cell"
:class="cellClass(wIdx, col)"
: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-else class="sce-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
</td>
</tr>
</tbody>
</table>
</div>
<div class="sce-status">
已选 {{ selectedKeys.length }} 个时间格
<span v-if="absorbPreview" class="sce-absorb-tip">已吸取{{ absorbPreview }}</span>
</div>
</div>
</template>
<script>
import { getSemester } from '@/api/teachBusiness/semester'
import { listXqxlb, updateXqxlb } from '@/api/teachBusiness/xqxlb'
// 节次定义: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' }
]
// 前端节次 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 WEEK_DAYS = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
function pad2(n) {
return n < 10 ? '0' + n : '' + n
}
function fmtDate(d) {
return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate())
}
export default {
name: 'SchoolCalendarEditor',
props: {
nd: { type: [String, Number], default: '' },
semesterName: { type: String, default: '' }
},
data() {
return {
// 学期日期范围
startDate: null,
endDate: null,
totalWeeks: 0,
dateRangeText: '',
weeks: [],
// 显示开关(默认不勾选,每天仅显示 1-2/3-4/5-6 三个节次)
show78: false,
showNight: false,
showLateNight: false,
// 工具栏表单
toolbar: {
eventName: '',
bold: false,
schedulable: false,
mainCourse: false,
remarkShow: false,
remark: ''
},
// 事件存储:key = cellKey -> event
events: {},
// 暂存被隐藏节次列上的事件:key = 周-星期-节次 -> event,列再次显示时恢复
hiddenEvents: {},
// 选择集(用数组以保证 Vue2 响应式)
selectedKeys: [],
// 拖拽状态
selecting: false,
dragStart: null,
dragStartSelected: false, // 按下起点在按下前是否已选中
moved: false, // 是否发生移动(区分点击与拖拽)
dragAddMode: false, // ctrl 拖拽为追加
// 窗口控制
absorbPreview: ''
}
},
computed: {
// 当前可见列(由开关过滤,默认每天三个节次)
visibleColumns() {
const cols = []
let colIndex = 0
WEEK_DAYS.forEach((dayLabel, dayIndex) => {
SLOT_DEFS.forEach(slot => {
if (slot.ctrl && !this[slot.ctrl]) return
cols.push({ colIndex: colIndex, dayIndex: dayIndex, slotKey: slot.key, slotLabel: slot.label, dayLabel: dayLabel })
colIndex++
})
})
return cols
},
// xqxlb 的年度(nd)为年份(如 2026),由 6 位学期代号(如 202601)截取前 4 位得出
xqxlbNd() {
return Number(String(this.nd).slice(0, 4))
}
},
watch: {
nd: {
immediate: true,
handler(val) {
if (val) this.loadSemester()
}
},
visibleColumns(newCols, oldCols) {
// 节次列显隐会改变列索引,按「周期-星期-节次」重定位事件,避免事件随时间格列偏移
if (oldCols && oldCols.length) {
const oldPosOf = index => (oldCols[index] || null)
const newIndex = (dayIndex, slotKey) => {
const c = newCols.find(x => x.dayIndex === dayIndex && x.slotKey === slotKey)
return c ? c.colIndex : -1
}
const next = {}
Object.keys(this.events).forEach(key => {
const m = key.match(/^w(\d+)-c(\d+)$/)
if (!m) return
const wIdx = +m[1]
const old = oldPosOf(+m[2])
if (!old) return
const newC = newIndex(old.dayIndex, old.slotKey)
if (newC < 0) {
// 该节次列被隐藏:事件暂存,待列再次显示时恢复
this.hiddenEvents[this.cellStableKey(wIdx, old.dayIndex, old.slotKey)] = this.events[key]
return
}
next['w' + wIdx + '-c' + newC] = this.events[key]
})
// 恢复重新显示的隐藏节次事件
Object.keys(this.hiddenEvents).forEach(stable => {
const p = stable.split('-')
const wIdx = +p[0]
const dayIndex = +p[1]
const slotKey = p[2]
const newC = newIndex(dayIndex, slotKey)
if (newC >= 0) {
next['w' + wIdx + '-c' + newC] = this.hiddenEvents[stable]
delete this.hiddenEvents[stable]
}
})
this.events = next
}
// 列变化后清空无效选择(列索引含义会变)
this.selectedKeys = []
}
},
beforeDestroy() {
this.removeGlobalListeners()
},
methods: {
/* ---------- 数据加载 ---------- */
loadSemester() {
if (!this.nd) return
getSemester(this.nd)
.then(res => {
const data = res.data || res || {}
const kx = (data.kxrq || '').toString().slice(0, 10)
const jx = (data.jsrq || '').toString().slice(0, 10)
if (kx && jx) {
this.startDate = new Date(kx.replace(/-/g, '/'))
this.endDate = new Date(jx.replace(/-/g, '/'))
this.buildWeeks()
}
this.loadXqxlbEvents()
})
.catch(() => {
this.$message.warning('学期详情获取失败,请确认学期数据')
})
},
// 从后端拉取本学期校历事件,渲染到对应时间格(年度由 6 位学期代号截取前 4 位)
loadXqxlbEvents() {
listXqxlb({ nd: this.xqxlbNd }).then(res => {
const data = res.data
const list = Array.isArray(data) ? data : (data && data.records) || []
return list
}).then(list => {
const loaded = {}
list.forEach(item => {
const pos = this.locateXqxlb(item)
if (!pos) return
const ev = {
bh: item.bh,
name: item.jqmc || '',
bold: !!item.jc,
schedulable: !!item.kpk,
mainCourse: !!item.zdpk,
remarkShow: !!item.bzxs,
remark: item.bz || ''
}
const colIndex = this.colIndexOf(pos.dayIndex, pos.slotKey)
if (colIndex >= 0) {
loaded[this.cellKey(pos.wIdx, colIndex)] = ev
} else {
// 该节次列当前隐藏:暂存(含 bh),待列显示时由 visibleColumns 监听恢复
this.hiddenEvents[this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)] = ev
}
})
// 合并到现有格子(后端数据覆盖已有状态)
this.events = Object.assign({}, this.events, loaded)
}).catch(() => {
this.$message.warning('校历事件加载失败')
})
},
// 根据假期记录反推时间格位置(jqsj 日期 + courseClass 节次),与列是否可见无关
locateXqxlb(item) {
if (!this.startDate || !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))
if (offset < 0) return null
const wIdx = Math.floor(offset / 7)
const dayIndex = offset % 7
const slotKey = this.courseClassToSlotKey(item.courseClass)
if (slotKey === null) return null
return { wIdx, dayIndex, slotKey }
},
// 后端 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
}
// 兼容 "910"/"1112" 等紧凑写法
if (s === '910') return 'night'
if (s === '1112') return 'late'
return null
},
buildWeeks() {
if (!this.startDate || !this.endDate) return
const start = new Date(this.startDate)
const end = new Date(this.endDate)
const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1
this.totalWeeks = Math.ceil(days / 7)
this.dateRangeText = fmtDate(start) + ' 到 ' + fmtDate(end)
const weeks = []
for (let w = 0; w < this.totalWeeks; w++) {
const wkStart = new Date(start)
wkStart.setDate(start.getDate() + w * 7)
const wkEnd = new Date(wkStart)
wkEnd.setDate(wkStart.getDate() + 6)
weeks.push({
rangeText: pad2(wkStart.getMonth() + 1) + '-' + pad2(wkStart.getDate()) +
'至' + pad2(wkEnd.getMonth() + 1) + '-' + pad2(wkEnd.getDate())
})
}
this.weeks = weeks
},
colIndexOf(dayIndex, slotKey) {
const col = this.visibleColumns.find(c => c.dayIndex === dayIndex && c.slotKey === slotKey)
return col ? col.colIndex : -1
},
/* ---------- 单元格工具 ---------- */
cellKey(wIdx, colIndex) {
return 'w' + wIdx + '-c' + colIndex
},
// 稳定的单元格身份:不随列显隐变化的周-星期-节次
cellStableKey(wIdx, dayIndex, slotKey) {
return wIdx + '-' + dayIndex + '-' + slotKey
},
getEvent(wIdx, colIndex) {
return this.events[this.cellKey(wIdx, colIndex)] || null
},
weekDayLabel(dayIndex) {
return WEEK_DAYS[dayIndex]
},
// 单元格内显示的日期数字(如 0703)
dateNumberOf(wIdx, dayIndex) {
if (!this.startDate) return ''
const d = new Date(this.startDate)
d.setDate(this.startDate.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')
}
return classes
},
/* ---------- 点击 / 拖拽多选 ---------- */
onGridMouseDown(e) {
const cell = e.target.closest('.sce-cell')
if (!cell) {
// 点击空白区(非单元格,含表头、周次列等)取消所有选中
if (this.selectedKeys.length) this.selectedKeys = []
return
}
e.preventDefault()
const key = cell.getAttribute('data-key')
this.dragStart = key
this.dragAddMode = e.ctrlKey || e.metaKey
// 记录起点格在按下时的选中状态,用于松手时判定"纯点击"的切换行为
this.dragStartSelected = this.selectedKeys.includes(key)
this.moved = false
this.selecting = true
// 非 ctrl 模式下,若起点本身已选中(可能准备拖拽扩展),先不清除,避免误清空
if (!this.dragAddMode && !this.dragStartSelected) this.selectedKeys = []
this.addGlobalListeners()
},
addGlobalListeners() {
document.addEventListener('mousemove', this.onGridMouseMove)
document.addEventListener('mouseup', this.onGridMouseUp)
},
removeGlobalListeners() {
document.removeEventListener('mousemove', this.onGridMouseMove)
document.removeEventListener('mouseup', this.onGridMouseUp)
},
onGridMouseMove(e) {
if (!this.selecting || !this.dragStart) return
if (!this.moved) this.moved = true
const el = document.elementFromPoint(e.clientX, e.clientY)
const cell = el && el.closest ? el.closest('.sce-cell') : null
if (!cell) return
const curKey = cell.getAttribute('data-key')
this.selectRectangle(this.dragStart, curKey, this.dragAddMode)
},
onGridMouseUp() {
if (!this.selecting) {
this.removeGlobalListeners()
return
}
// 纯点击(未移动)时,做单选 / 切换
if (!this.moved) {
const key = this.dragStart
if (this.dragAddMode) {
// Ctrl + 单击:切换该格选中
if (this.selectedKeys.includes(key)) {
this.selectedKeys = this.selectedKeys.filter(k => k !== key)
} else {
this.selectedKeys.push(key)
}
} else {
// 普通单击:已选中则取消该格,未选中则仅选中该格
if (this.dragStartSelected) {
this.selectedKeys = this.selectedKeys.filter(k => k !== key)
} else {
this.selectedKeys = [key]
}
}
}
this.selecting = false
this.dragStart = null
this.dragStartSelected = false
this.removeGlobalListeners()
},
// 根据起点终点 key 选中矩形范围内所有格
selectRectangle(startKey, endKey, addMode) {
const parse = k => {
const m = k.match(/^w(\d+)-c(\d+)$/)
return m ? { w: +m[1], c: +m[2] } : null
}
const s = parse(startKey)
const t = parse(endKey)
if (!s || !t) return
if (!addMode) this.selectedKeys = []
const minW = Math.min(s.w, t.w)
const maxW = Math.max(s.w, t.w)
const minC = Math.min(s.c, t.c)
const maxC = Math.max(s.c, t.c)
for (let w = minW; w <= maxW; w++) {
for (let c = minC; c <= maxC; c++) {
const key = this.cellKey(w, c)
if (this.selectedKeys.indexOf(key) === -1) this.selectedKeys.push(key)
}
}
},
/* ---------- 事件操作 ---------- */
applyEvent() {
if (!this.selectedKeys.length) {
this.$message.warning('请先选择时间格')
return
}
const name = this.toolbar.eventName.trim()
if (!name) {
this.$message.warning('请输入事件名称')
return
}
const keys = [...this.selectedKeys]
keys.forEach(key => {
const prev = this.events[key]
this.$set(this.events, key, {
bh: prev ? prev.bh : undefined,
name: name,
bold: this.toolbar.bold,
schedulable: this.toolbar.schedulable,
mainCourse: this.toolbar.mainCourse,
remarkShow: this.toolbar.remarkShow,
remark: this.toolbar.remark
})
})
this.persistEvents(keys)
},
deleteEvent() {
if (!this.selectedKeys.length) {
this.$message.warning('请先选择时间格')
return
}
const keys = [...this.selectedKeys]
keys.forEach(key => {
this.$delete(this.events, key)
})
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 (!target) {
this.$message.warning('所选时间格中无事件可吸取')
return
}
this.toolbar.eventName = target.name
this.toolbar.bold = !!target.bold
this.toolbar.schedulable = !!target.schedulable
this.toolbar.mainCourse = !!target.mainCourse
this.toolbar.remarkShow = !!target.remarkShow
this.toolbar.remark = target.remark || ''
this.absorbPreview = target.name
},
onCellDblClick(wIdx, col) {
const ev = this.getEvent(wIdx, col.colIndex)
if (ev) {
this.toolbar.eventName = ev.name
this.toolbar.bold = !!ev.bold
this.toolbar.schedulable = !!ev.schedulable
this.toolbar.mainCourse = !!ev.mainCourse
this.toolbar.remarkShow = !!ev.remarkShow
this.toolbar.remark = ev.remark || ''
this.absorbPreview = ev.name
this.$message.info('已吸取事件:' + ev.name)
}
},
refreshGrid() {
this.selectedKeys = []
this.absorbPreview = ''
this.events = {}
this.hiddenEvents = {}
this.loadXqxlbEvents()
this.$message.info('已刷新')
},
/* ---------- 后端持久化(xqxlb 接口) ---------- */
// 批量保存选中格事件,返回各格子保存成功/失败的个数
persistEvents(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)
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 + ' 个时间格')
}
// 保存成功后重新拉取,回写各记录主键,避免重复新增
this.loadXqxlbEvents()
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)
return {
delFlag: 0,
bh: ev.bh || undefined,
nd: this.xqxlbNd,
jqsj: fmtDate(d),
jqmc: ev.name || '',
jc: !!ev.bold,
bz: ev.remark || null,
kpk: !!ev.schedulable,
bzxs: !!ev.remarkShow,
zdpk: !!ev.mainCourse,
courseClass: SLOT_COURSE_MAP[pos.slotKey] || null
}
},
// 时间格 key -> { wIdx, dayIndex, slotKey }
parseCellKey(key) {
const m = key.match(/^w(\d+)-c(\d+)$/)
if (!m) return null
const colIndex = +m[2]
const col = this.visibleColumns.find(c => c.colIndex === colIndex)
if (!col) return null
return { wIdx: +m[1], dayIndex: col.dayIndex, slotKey: col.slotKey }
},
/* ---------- 返回学期管理 ---------- */
handleClose() {
this.$emit('close')
this.$router.replace({ path: '/teachBusiness/semester' })
}
}
}
</script>
<style scoped lang="scss">
.school-calendar-editor {
display: flex;
flex-direction: column;
height: 100%;
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 6px;
overflow: hidden;
/* 标题栏 */
.sce-titlebar {
display: flex;
align-items: center;
height: 44px;
padding: 0 14px;
background: var(--edu-green-primary, #00875a);
color: #fff;
.sce-title-left { flex: 1; font-size: 15px; font-weight: 600; }
.sce-title-center { flex: 1; text-align: center; font-size: 13px; opacity: 0.9; }
.sce-title-right { flex: 0 0 auto; text-align: right; }
.sce-title-right i {
margin-left: 14px;
cursor: pointer;
font-size: 18px;
opacity: 0.85;
&:hover { opacity: 1; }
}
}
/* 设置面板 */
.sce-panel {
padding: 10px 14px;
border-bottom: 1px solid #ebeef5;
background: #fafafa;
.sce-panel-row {
display: flex;
align-items: center;
flex-wrap: wrap;
margin-bottom: 8px;
&:last-child { margin-bottom: 0; }
}
.sce-label { font-size: 13px; color: #606266; margin-right: 6px; white-space: nowrap; }
.sce-event-input { width: 200px; margin-right: 12px; }
.sce-remark-input { width: 240px; margin-left: 6px; }
.sce-cb { margin-right: 14px; }
.sce-divider { width: 1px; height: 18px; background: #dcdfe6; margin: 0 14px; }
}
/* 时间编排区 */
.sce-grid-wrap {
flex: 1;
overflow: auto;
padding: 8px 10px;
background: #fff;
}
.sce-grid {
border-collapse: collapse;
table-layout: fixed;
width: 100%;
font-size: 12px;
user-select: none;
th, td {
border: 1px solid #e4e7ed;
text-align: center;
padding: 0;
}
.sce-corner {
background: #f5f7fa;
font-weight: 600;
color: #303133;
vertical-align: middle;
}
.sce-th-weekno { width: 52px; }
.sce-th-weekrange { width: 110px; }
.sce-th-day {
background: var(--edu-green-primary, #00875a);
color: #fff;
font-weight: 600;
height: 26px;
}
.sce-th-slot {
background: #ecf5f0;
color: #00875a;
height: 22px;
font-weight: 500;
}
.sce-week-cell {
background: #f5f7fa;
vertical-align: middle;
white-space: nowrap;
}
.sce-weekno-cell {
font-weight: 600;
color: #303133;
font-size: 13px;
}
.sce-weekrange-cell {
font-size: 11px;
color: #909399;
}
.sce-cell {
height: 30px;
position: relative;
cursor: pointer;
background: #fff;
transition: background 0.15s;
.sce-date-num { color: #c0c4cc; }
// 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白,便于区分星期
&.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; }
&.no-schedule { background: #fde2e2; }
&.is-selected {
outline: 2px solid var(--edu-green-primary, #00875a);
outline-offset: -2px;
background: #d4ecdf !important;
}
}
}
.sce-status {
padding: 6px 14px;
font-size: 12px;
color: #909399;
border-top: 1px solid #ebeef5;
background: #fafafa;
.sce-absorb-tip { margin-left: 12px; color: #00875a; }
}
}
</style>