This commit is contained in:
2026-08-28 14:24:51 +08:00
parent ab3daeed65
commit d37c05aaad
3 changed files with 52 additions and 78 deletions
@@ -123,6 +123,16 @@ function fmtDate(d) {
return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate())
}
// 生成 32 位小写 UUID(去横线),与后端 UuidUtil.getUUID 一致,用于 bh 缺失时兜底
function genUUID() {
let s = ''
const chars = '0123456789abcdef'
for (let i = 0; i < 32; i++) {
s += chars[Math.floor(Math.random() * 16)]
}
return s
}
export default {
name: 'SchoolCalendarEditor',
props: {
@@ -182,12 +192,10 @@ export default {
})
return cols
},
// xqxlb 的 nd 存的是「年份」,必须与某条记录的 jqsj 实际日期同一年,
// 按「学期代号前4位」取会与格子真实年月脱节(如 2027 春学期首周落在 2026 年)
// 这里统一以「日历起点 calendarStart 所在年」作为年度口径。
// xqxlb 的 nd 后端已统一为「6 位学期代号」(如 202701),与 this.nd 一致。
// 不再按日历起点/季度取年份,避免跨年度学期解析出错
xqxlbNd() {
if (this.calendarStart) return this.calendarStart.getFullYear()
return Number(String(this.nd).slice(0, 4))
return Number(String(this.nd).slice(0, 6)) || Number(this.nd) || 0
}
},
watch: {
@@ -269,15 +277,10 @@ export default {
// 调用 /xqxlb/add 只按本学期 kxrq/jsrq 预生成这一张网格,再重新拉取,
// 这样后续 /xqxlb/update 的 updateById 才能命中每一格。(区间有覆盖则跳过,幂等)
loadXqxlbEvents() {
const fetchList = () => {
console.warn('[校历编辑] 查询nd=', this.xqxlbNd, '学期nd=', this.nd)
return listXqxlb({ nd: this.xqxlbNd }).then(res => {
const fetchList = () => listXqxlb({ nd: this.xqxlbNd }).then(res => {
const data = res.data
const arr = Array.isArray(data) ? data : (data && data.records) || []
console.warn('[校历编辑] 返回条数=', arr.length, '含事件名=', arr.filter(it => it.jqmc).map(it => ({ nd: it.nd, jqsj: it.jqsj, jqmc: it.jqmc, courseClass: it.courseClass })).slice(0, 10))
return arr
return Array.isArray(data) ? data : (data && data.records) || []
})
}
const render = (list) => {
// 后端 add() 的按「月日」去重对已存的全量日期不生效,同一年度多次打开/刷新会
// 积累同一格的重复占位记录(各带不同 bh)。updateById 只改其中一行,其余空记录
@@ -519,9 +522,9 @@ export default {
return
}
const name = this.toolbar.eventName.trim()
// 空名称时按清除处理
// 设定时未填写事件名:提示,不触发清除
if (!name) {
this.deleteEvent()
this.$message.warning('请输入事件名')
return
}
const keys = [...this.selectedKeys]
@@ -610,8 +613,14 @@ export default {
const payload = this.buildXqxlbPayload(key, this.events[key])
if (!payload) return Promise.resolve(false)
return updateXqxlb(payload)
.then(() => true)
.catch(() => false)
.then(() => {
console.warn('[设定] key=', key, 'bh来源=', this.events[key] && this.events[key].bh ? '已有' : '生成', 'bh=', payload.bh, 'nd=', payload.nd, 'name=', payload.jqmc)
return true
})
.catch(err => {
console.warn('[设定] key=', key, '保存失败', err && (err.message || err))
return false
})
})
return Promise.all(tasks).then(results => {
const ok = results.filter(r => r === true).length
@@ -659,10 +668,10 @@ export default {
d.setDate(this.calendarStart.getDate() + pos.wIdx * 7 + pos.dayIndex)
return {
delFlag: 0,
bh: ev.bh || undefined,
// nd 必须与 jqsj 同一年:取本条记录真实日期的年份,
// 不能沿用学派代号前4位(如 2027 春学期首周可能落在 2026 年,会存错年度、查不到)。
nd: d.getFullYear(),
// bh 编号必须传:有后端记录则沿用其 bh,否则前端生成 UUID 兜底(避免 payload 缺主键导致 updateById 失效)
bh: ev.bh || genUUID(),
// nd 后端已统一为 6 位学期代号(如 202701),与查询口径一致,不再取记录日期的年份
nd: this.xqxlbNd,
jqsj: fmtDate(d),
jqmc: ev.name || '',
jc: !!ev.bold,
@@ -193,31 +193,14 @@ export default {
})
},
// 从后端拉取校历事件,渲染到对应时间格
// xqxlb.nd 存的是记录真实日期的年份,不是学期代号前4位(避免跨年度学期查询出错)
// xqxlb.nd 后端已统一为 6 位学期代号(如 202701),与 this.nd 一致,一次查询即可
loadXqxlbEvents() {
if (!this.calendarStart) return
// 学期校历从 calendarStart 到 endDate,查询覆盖整个跨度的全部年份
const startYear = this.calendarStart.getFullYear()
const endYear = (this.endDate || this.calendarStart).getFullYear()
// 一次性拉取覆盖起止年份的所有记录,由前端过滤
const requests = []
const range = []
for (let y = startYear; y <= endYear; y++) {
range.push(y)
requests.push(listXqxlb({ nd: y }))
}
console.warn('[校历只读] 查询nd范围=', range, 'calendarStart=', fmtDate(this.calendarStart), 'endDate=', this.endDate ? fmtDate(this.endDate) : null)
Promise.all(requests).then(responses => {
const list = []
responses.forEach(res => {
if (!this.calendarStart || !this.nd) return
listXqxlb({ nd: Number(String(this.nd).slice(0, 6)) || Number(this.nd) }).then(res => {
const data = res.data
const part = Array.isArray(data) ? data : (data && data.records) || []
list.push(...part)
})
console.warn('[校历只读] listXqxlb 返回记录条数=', list.length, 'nd字段分布=', list.reduce((m, it) => { const k = String(it.nd); m[k] = (m[k] || 0) + 1; return m }, {}), '样例=', list.slice(0, 3).map(it => ({ nd: it.nd, jqsj: it.jqsj, jqmc: it.jqmc, courseClass: it.courseClass })))
const list = Array.isArray(data) ? data : (data && data.records) || []
const loaded = {}
let matched = 0
// 23694 条里同一格可能有多条(add() 去重失效累积的重复占位)。
// 同一格可能有多条(后端 add() 去重失效累积的重复占位)。
// 按格子去重:同一格优先保留「有事件名(jqmc非空)」的那条,避免空占位把事件盖成空白。
const unique = {}
list.forEach(item => {
@@ -239,11 +222,11 @@ export default {
remarkShow: !!item.bzxs,
remark: item.bz || ''
}
if (item.jqmc) matched++
})
console.warn('[校历只读] 定位到的事件条数=', matched, 'events=', Object.keys(loaded).length, loaded)
this.events = loaded
}).catch(e => { console.error('[校历只读] 拉取失败', e) })
}).catch(() => {
this.$message.warning('校历事件加载失败')
})
},
// 根据假期记录反推时间格 keyjqsj 日期 + courseClass 节次)
locateXqxlb(item) {
@@ -6,22 +6,16 @@
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新添</el-button>
</el-col>
<el-col :span="1.8">
<el-button type="success" plain icon="el-icon-date" size="mini" :disabled="!currentSemester"
<el-button type="success" plain icon="el-icon-date" size="mini"
@click="handleEditCalendar">
编辑校历
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">
批量删除
</el-button>
</el-col>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="semesterList" border :height="tableHeight" highlight-current-row
@current-change="handleCurrentChange" @selection-change="handleSelectionChange">
<el-table-column type="selection" align="center" width="50" />
@current-change="handleCurrentChange">
<el-table-column label="学期名称" align="center" width="250">
<template slot-scope="scope">
<span>{{ getSemesterName(scope.row.nd) }}</span>
@@ -214,14 +208,8 @@ export default {
total: 0,
// 学期列表数据
semesterList: [],
// 选中的学期数组
ids: [],
// 当前点击选中的学期
currentSemester: null,
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 弹出层标题
title: "",
// 是否显示弹出层
@@ -365,12 +353,6 @@ export default {
this.loading = false
})
},
/** 多选变化 */
handleSelectionChange(selection) {
this.ids = selection.map(item => item.nd)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 单击行选中变化:记录当前选中的学期,用于启用「编辑校历」 */
handleCurrentChange(currentRow) {
this.currentSemester = currentRow || null
@@ -405,7 +387,7 @@ export default {
},
/** 编辑按钮 */
handleUpdate(row) {
const semesterId = row && row.nd ? row.nd : this.ids[0]
const semesterId = row && row.nd ? row.nd : ''
if (!semesterId) return
this.reset()
this.isAdd = false
@@ -443,21 +425,21 @@ export default {
/** 编辑校历按钮:对当前选中的学期编辑校历 */
handleEditCalendar() {
const row = this.currentSemester
if (!row || !row.nd) return
if (!row || !row.nd) {
this.$modal.msgWarning('请选择学期')
return
}
this.$router.push({
path: '/teachBusiness/semester/semesterCalendar',
query: { nd: row.nd, name: this.getSemesterName(row.nd) }
})
},
/** 删除按钮 */
/** 删除按钮:单行删除 */
handleDelete(row) {
const semesterIds = row && row.nd ? [row.nd] : this.ids
if (!semesterIds.length) return
const names = semesterIds.map(nd => this.getSemesterName(nd)).join('、')
this.$modal.confirm('确认删除学期【' + names + '】吗?').then(() => {
// 批量删除:逐个调用
const delList = semesterIds.map(nd => delSemester(nd))
return Promise.all(delList)
if (!row || !row.nd) return
const name = this.getSemesterName(row.nd)
this.$modal.confirm('确认删除学期【' + name + '】吗?').then(() => {
return delSemester(row.nd)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")