排课版本新建、编辑、复制、发布、归档和删除。

周课表视图,支持12节课、单双周和起止周。
自动校验教师、行政班、教室、时间段冲突。
校验教室容量、教学任务状态和学期范围。
SQLite 开发环境自动升级,MySQL 提供正式 EF Core 迁移。
Vue 已编译为静态文件并随 ASP.NET Core 发布,无需 npm run dev。
桌面端和390px移动端页面均已验收。
This commit is contained in:
biss committed 2026-07-24 14:27:01 +08:00
1 parent 628944f64d
commit 0b463fa4f2
19 files changed
+2950 -9

No files matched your search

+10 -1
View File
@@ -8,6 +8,7 @@ import {
Operation,
Reading,
Tickets,
Calendar,
User,
UserFilled,
} from '@element-plus/icons-vue'
@@ -27,6 +28,7 @@ const pageTitle = computed(() => {
courses: '课程库',
curriculum: '培养方案',
'teaching-tasks': '教学任务',
schedules: '排课与课表',
users: '用户与权限',
}
return titles[String(route.name)] ?? '教务管理'
@@ -98,6 +100,13 @@ onMounted(() => auth.refresh().catch(() => undefined))
<el-icon><Tickets /></el-icon>
<template #title>教学任务</template>
</el-menu-item>
<el-menu-item
v-if="auth.user?.roles.some((role) => ['SuperAdmin', 'AcademicAdmin'].includes(role))"
index="/schedules"
>
<el-icon><Calendar /></el-icon>
<template #title>排课与课表</template>
</el-menu-item>
<el-menu-item v-if="auth.isSuperAdmin" index="/users">
<el-icon><User /></el-icon>
<template #title>用户与权限</template>
@@ -106,7 +115,7 @@ onMounted(() => auth.refresh().catch(() => undefined))
<div v-if="!collapsed" class="phase-note">
<span>第一阶段 · 核心可用版</span>
<p>主数据与培养方案正在运行</p>
<p>主数据、培养方案与教学运行已就绪</p>
</div>
</aside>
+6
View File
@@ -51,6 +51,12 @@ const router = createRouter({
component: () => import('../views/TeachingTasksView.vue'),
meta: { roles: ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin'] },
},
{
path: 'schedules',
name: 'schedules',
component: () => import('../views/SchedulesView.vue'),
meta: { roles: ['SuperAdmin', 'AcademicAdmin'] },
},
{
path: 'users',
name: 'users',
+44
View File
@@ -205,6 +205,42 @@ button { cursor: pointer; }
.task-summary b { margin-left: auto; color: #58d1c0; font: 700 30px/1 Consolas, monospace; }
.task-summary p { margin: 0; padding-left: 28px; border-left: 1px solid rgba(255,255,255,.16); color: #d4daeb; font-size: 11px; letter-spacing: .03em; }
.muted-action { color: #9aa1ae; font-size: 11px; }
.schedule-toolbar { min-height: 86px; padding: 12px 16px; display: flex; align-items: stretch; gap: 14px; border: 1px solid var(--line); background: white; }
.schedule-toolbar > .el-select { width: 245px; align-self: center; }
.schedule-version-strip { min-width: 0; display: flex; align-items: stretch; gap: 8px; overflow-x: auto; }
.schedule-version-strip > button { min-width: 120px; padding: 10px 14px; display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; text-align: left; border: 1px solid var(--line); background: #fafbfc; }
.schedule-version-strip > button:hover { background: white; }
.schedule-version-strip > button.active { color: white; border-color: var(--indigo); background: var(--indigo); }
.schedule-version-strip b { font: 700 14px/1.2 Consolas, monospace; }
.schedule-version-strip span, .schedule-version-strip small { font-size: 9px; }
.schedule-version-strip small { grid-column: 1 / -1; color: #9199a8; }
.schedule-version-strip > button.active small { color: #cbd3eb; }
.schedule-version-strip > span { align-self: center; color: var(--muted); font-size: 11px; }
.schedule-sheet { min-width: 0; border: 1px solid var(--line); background: white; }
.schedule-sheet-head { padding: 21px 22px; display: flex; justify-content: space-between; gap: 20px; border-bottom: 1px solid var(--line); }
.schedule-sheet-head > div:first-child > span { color: var(--teal); font-size: 10px; letter-spacing: .07em; }
.schedule-sheet-head h3 { margin: 6px 0 5px; font-family: "STZhongsong", "Songti SC", serif; font-size: 21px; }
.schedule-sheet-head p { margin: 0; color: var(--muted); font-size: 10px; }
.schedule-search { padding: 12px 16px; display: flex; align-items: center; gap: 10px; background: #fafbfc; border-bottom: 1px solid var(--line); }
.schedule-search .el-input { width: 320px; }
.schedule-search > span { margin-left: auto; color: var(--muted); font-size: 10px; }
.timetable-scroll { width: 100%; overflow: auto; }
.timetable-grid { min-width: 1120px; display: grid; grid-template-columns: 72px repeat(7, minmax(145px, 1fr)); }
.timetable-corner, .timetable-day { min-height: 45px; display: grid; place-items: center; color: #555f72; background: #f4f6f9; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: 11px; font-weight: 650; }
.timetable-period { min-height: 88px; padding: 14px 8px; display: grid; align-content: start; justify-items: center; gap: 5px; color: var(--indigo); background: #fafbfc; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.timetable-period b { font: 700 17px/1 Consolas, monospace; }
.timetable-period span { color: var(--muted); font-size: 9px; }
.timetable-cell { min-width: 0; min-height: 88px; padding: 5px; display: grid; align-content: start; gap: 5px; position: relative; border-right: 1px solid var(--line); border-bottom: 1px solid var(--line); background: white; }
.timetable-cell.editable:hover { background: #f7fbfa; }
.cell-add { margin: auto; color: transparent; font-size: 9px; }
.timetable-cell.editable:hover .cell-add { color: #a0a8b4; }
.schedule-card { min-width: 0; padding: 8px 9px; display: grid; gap: 4px; position: relative; border-left: 3px solid #45bcae; color: #eaf2ff; background: linear-gradient(130deg, #263f80, #1a2e64); box-shadow: 0 4px 10px rgba(24,40,83,.12); cursor: pointer; }
.schedule-card.readonly { cursor: default; }
.schedule-card span { padding-right: 16px; color: #74d5c8; font: 700 8px/1.2 Consolas, monospace; letter-spacing: .04em; }
.schedule-card b { overflow: hidden; font-size: 11px; white-space: nowrap; text-overflow: ellipsis; }
.schedule-card small, .schedule-card i { overflow: hidden; color: #c6cfe6; font-size: 8px; font-style: normal; white-space: nowrap; text-overflow: ellipsis; }
.schedule-card > button { position: absolute; right: 4px; top: 3px; border: none; color: #b9c4df; background: transparent; font-size: 14px; }
.schedule-card > button:hover { color: white; }
.login-page { min-height: 100vh; display: grid; grid-template-columns: minmax(440px, 1.2fr) minmax(420px, .8fr); background: white; }
.login-story { min-height: 100vh; padding: 54px clamp(45px, 6vw, 90px); display: flex; flex-direction: column; color: white; background: linear-gradient(142deg, #13224d, #243a77 62%, #176b71); overflow: hidden; position: relative; }
@@ -288,6 +324,14 @@ button { cursor: pointer; }
.task-summary { align-items: flex-start; flex-direction: column; gap: 12px; }
.task-summary > div { width: 100%; }
.task-summary p { padding: 12px 0 0; border-left: none; border-top: 1px solid rgba(255,255,255,.16); line-height: 1.6; }
.schedule-toolbar { display: block; }
.schedule-toolbar > .el-select { width: 100%; }
.schedule-version-strip { margin-top: 10px; }
.schedule-sheet-head { display: block; }
.schedule-sheet-head .plan-actions { margin-top: 15px; }
.schedule-search { flex-wrap: wrap; }
.schedule-search .el-input { width: 100%; }
.schedule-search > span { width: 100%; margin-left: 0; }
.form-grid, .form-grid.three { grid-template-columns: 1fr; gap: 0; }
.el-dialog { width: calc(100vw - 24px) !important; }
.login-page { display: block; min-height: 100vh; background: #f4f6f9; }
Loaded 3 of 19 files, more files were not shown because too many files have changed in this diff. Show more