Compare commits

...

23 Commits

Author SHA1 Message Date
zhaichao a731eafe29 报错修复 2026-08-25 17:17:00 +08:00
zhaichao f60db56719 Merge branch 'main' of https://gitea.fengyingkj.top/zhaichao/education 2026-08-25 17:05:48 +08:00
zhaichao 872eb4c84a 序号跨页连续 2026-08-25 17:05:41 +08:00
yangbin 99436d14c5 “分组教学任务”的“任务名称”列已居中
同步修正“教学任务计划管理”中的相同列
检查并统一了教学场地、培养方案、课表、调课、课表冲突、班次学期等列表中的短名称和编号列
2026-08-25 16:59:49 +08:00
yangbin 9d45526af2 Merge remote-tracking branch 'origin/main' 2026-08-25 16:52:32 +08:00
yangbin c98cd0aaca 分组教学任务查不到数据bug修复 2026-08-25 16:52:02 +08:00
zhaichao af7370def4 教学大纲新增对话框停用改复选框 2026-08-25 15:45:10 +08:00
yangbin 99ae7a7947 Merge remote-tracking branch 'origin/main' 2026-08-25 15:40:19 +08:00
yangbin b2d27c87d2 教学大纲字典统一 新增专业 课程等字典调整 2026-08-25 15:40:13 +08:00
zhaichao ada2d04736 Merge branch 'main' of https://gitea.fengyingkj.top/zhaichao/education 2026-08-25 15:11:14 +08:00
zhaichao 5a55d74a86 学期信息新增重复校验 2026-08-25 15:11:01 +08:00
yangbin e89863900e tab页面修改 只保持最近的八个页面 2026-08-25 15:09:20 +08:00
yangbin 2d738549b5 Merge remote-tracking branch 'origin/main' 2026-08-25 14:53:43 +08:00
yangbin d58d044c6a 全局主按钮 颜色样式统一 2026-08-25 14:53:34 +08:00
zhaichao ebf4928e3f 课表 2026-08-25 14:48:51 +08:00
yangbin 6f61e87303 Merge remote-tracking branch 'origin/main' 2026-08-25 14:46:35 +08:00
yangbin cab512e033 全局列表展示下侧的滚动条隐藏 2026-08-25 14:46:28 +08:00
zhaichao 656ee817e6 样式变更 2026-08-25 14:16:12 +08:00
zhaichao 7bfc19c4f4 样式变更 2026-08-25 10:43:24 +08:00
zhaichao 54fa1c6be2 样式变更 2026-08-25 09:47:30 +08:00
zhaichao 0934a4d910 样式变更 2026-08-25 09:29:11 +08:00
yangbin 763bf34c3a 系统风格以及部分页面样式变更 2026-08-24 18:35:40 +08:00
zhaichao 9f4571a40e 首页只保留通知公告 2026-08-24 16:11:05 +08:00
51 changed files with 2121 additions and 1592 deletions
-1
View File
@@ -2,7 +2,6 @@
<project version="4"> <project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true"> <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="DM" uuid="a3a7e92a-b8da-4229-8b83-5db11f9db9a9"> <data-source source="LOCAL" name="DM" uuid="a3a7e92a-b8da-4229-8b83-5db11f9db9a9">
<driver-ref>9fcb59ee-b3c5-470d-89df-ad01e7cabb15</driver-ref>
<imported>true</imported> <imported>true</imported>
<configured-by-url>true</configured-by-url> <configured-by-url>true</configured-by-url>
<remarks>$PROJECT_DIR$/backend/roomroot-admin/src/main/resources/application-druid.yml</remarks> <remarks>$PROJECT_DIR$/backend/roomroot-admin/src/main/resources/application-druid.yml</remarks>
+2 -1
View File
@@ -8,7 +8,8 @@
"dev": "vue-cli-service serve", "dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview" "preview": "node build/index.js --preview",
"dict:init-course-type": "node scripts/init-course-type-dict.js"
}, },
"keywords": [ "keywords": [
"vue", "vue",
+193
View File
@@ -0,0 +1,193 @@
/**
* 版权所有,内部使用。
*
* @description 初始化教学大纲使用的课类型字典,可重复执行且不会重复插入。
* @author 软件研发部
* @since 2026-08-25
*/
const DICT_TYPE = 'course_type'
const DICT_NAME = '课类型'
const DEFAULT_API_BASE_URL = 'http://localhost/api'
const DEFAULT_ADMIN_USERNAME = 'admin'
const DICT_ITEMS = [
{ label: '必修', value: '必修' },
{ label: '选修', value: '选修' },
{ label: '实践', value: '实践' }
]
let authToken = ''
function readHiddenInput(prompt) {
if (!process.stdin.isTTY || !process.stdin.setRawMode) {
throw new Error('当前终端不支持隐藏输入,请在 PowerShell 中直接运行该脚本')
}
return new Promise((resolve, reject) => {
let input = ''
function cleanup() {
process.stdin.removeListener('data', handleInput)
process.stdin.setRawMode(false)
process.stdin.pause()
process.stdout.write('\n')
}
function handleInput(characters) {
for (const character of characters) {
if (character === '\u0003') {
cleanup()
reject(new Error('用户取消执行'))
return
}
if (character === '\r' || character === '\n') {
cleanup()
resolve(input)
return
}
if (character === '\u0008' || character === '\u007f') {
input = input.slice(0, -1)
continue
}
if (character >= ' ') {
input += character
}
}
}
process.stdout.write(prompt)
process.stdin.setEncoding('utf8')
process.stdin.setRawMode(true)
process.stdin.resume()
process.stdin.on('data', handleInput)
})
}
async function authenticate() {
const environmentToken = process.env.EDUCATION_API_TOKEN
if (environmentToken) {
authToken = environmentToken.replace(/^Bearer\s+/i, '')
return
}
const username = process.env.EDUCATION_ADMIN_USERNAME || DEFAULT_ADMIN_USERNAME
let password = await readHiddenInput(`请输入管理员 ${username} 的密码:`)
const response = await fetch(getApiBaseUrl() + '/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json;charset=utf-8' },
body: JSON.stringify({ username, password, code: '', uuid: '' })
})
password = ''
const result = await response.json()
if (!response.ok || result.code !== 200 || !result.token) {
throw new Error(result.msg || `登录失败:HTTP ${response.status}`)
}
authToken = result.token
}
function getApiBaseUrl() {
const configuredUrl = process.env.EDUCATION_API_BASE_URL || DEFAULT_API_BASE_URL
return configuredUrl.replace(/\/+$/, '')
}
async function request(path, options = {}) {
if (!authToken) {
throw new Error('尚未完成管理员认证')
}
const response = await fetch(getApiBaseUrl() + path, {
...options,
headers: {
Authorization: 'Bearer ' + authToken,
'Content-Type': 'application/json;charset=utf-8',
...(options.headers || {})
}
})
const result = await response.json()
if (!response.ok || result.code !== 200) {
throw new Error(result.msg || `请求失败:HTTP ${response.status}`)
}
return result
}
async function ensureDictType() {
const query = new URLSearchParams({
pageNum: '1',
pageSize: '10',
dictType: DICT_TYPE
})
const result = await request('/system/dict/type/list?' + query.toString())
const hasDictType = (result.rows || []).some(item => item.dictType === DICT_TYPE)
if (hasDictType) {
console.log(`字典类型 ${DICT_TYPE} 已存在,跳过新增`)
return
}
await request('/system/dict/type', {
method: 'POST',
body: JSON.stringify({
dictName: DICT_NAME,
dictType: DICT_TYPE,
status: '0',
remark: '教学大纲课类型列表'
})
})
console.log(`已新增字典类型 ${DICT_TYPE}`)
}
async function ensureDictItems() {
const query = new URLSearchParams({
pageNum: '1',
pageSize: '100',
dictType: DICT_TYPE
})
const result = await request('/system/dict/data/list?' + query.toString())
const existingValues = new Set((result.rows || []).map(item => item.dictValue))
for (const [index, item] of DICT_ITEMS.entries()) {
if (existingValues.has(item.value)) {
console.log(`字典项 ${item.label} 已存在,跳过新增`)
continue
}
await request('/system/dict/data', {
method: 'POST',
body: JSON.stringify({
dictSort: index + 1,
dictLabel: item.label,
dictValue: item.value,
dictType: DICT_TYPE,
cssClass: '',
listClass: 'default',
isDefault: 'N',
status: '0',
remark: '教学大纲课类型'
})
})
console.log(`已新增字典项 ${item.label}`)
}
}
async function refreshDictCache() {
await request('/system/dict/type/refreshCache', { method: 'DELETE' })
console.log('字典缓存已刷新')
}
async function main() {
await authenticate()
await ensureDictType()
await ensureDictItems()
await refreshDictCache()
console.log('课类型字典初始化完成')
}
main().catch(error => {
console.error('课类型字典初始化失败:' + error.message)
process.exitCode = 1
})
@@ -0,0 +1,89 @@
import request from '@/utils/request'
// 课表查询管理(KCBController /kcb,前端 baseURL 为 /api,此处不重复 /api 前缀)
// 接口依据:课表页面接口规格
// 查询实体 TimetableQuery:nd 年度(可选,不传自动取当前学期)、xydbh 学员队编号/班次(可选,按班次筛选)
/**
* 今日课表
* GET /kcb/today/list
* @param params TimetableQuerynd、xydbh(均可选)
* 返回:今日课表记录(实体字段 bh/sksj/kc/zrdw/bc/jy/cd/jxnrxff/bz
*/
export function listToday(data) {
return request({
url: '/kcb/today/list',
method: 'get',
params: data
})
}
/**
* 本周课表
* GET /kcb/week/list
* @param params TimetableQuerynd、xydbh(均可选)
* 返回:本周课表记录
*/
export function listWeek(data) {
return request({
url: '/kcb/week/list',
method: 'get',
params: data
})
}
/**
* 班次课表(分页)
* GET /kcb/class/list
* @param params pageNum、pageSizecond=TimetableQuerynd、xydbh
* 返回:PageResult<班次课程记录>records/total
*/
export function listClass(params) {
return request({
url: '/kcb/class/list',
method: 'get',
params
})
}
/**
* 下载学期教学实施计划 Excel
* GET /kcb/class/export-plan
* @param data TimetableQuerynd、xydbh
*/
export function exportClassPlan(data) {
return request({
url: '/kcb/class/export-plan',
method: 'get',
params: data,
responseType: 'blob'
})
}
/**
* 下载学期成绩表 Excel
* GET /kcb/class/export-grades
* @param data TimetableQuerynd、xydbh
*/
export function exportClassGrades(data) {
return request({
url: '/kcb/class/export-grades',
method: 'get',
params: data,
responseType: 'blob'
})
}
/**
* 班次课程列表另存 Excel
* GET /kcb/class/export-courses
* @param data TimetableQuerynd、xydbh
*/
export function exportClassCourses(data) {
return request({
url: '/kcb/class/export-courses',
method: 'get',
params: data,
responseType: 'blob'
})
}
@@ -0,0 +1,615 @@
/**
* Copyright (c) 2026 软件研发部
* 内部使用,未经授权禁止外传。
* @description 教学管理信息系统全局视觉主题
* @author 软件研发部
* @since 2026-08-24
*/
:root {
--edu-color-primary: #0b6b55;
--edu-color-primary-hover: #085442;
--edu-color-primary-active: #063f34;
--edu-color-primary-soft: #e8f3ef;
--edu-color-primary-faint: #f3f8f6;
--edu-color-accent: #c69b3c;
--edu-color-text: #172b25;
--edu-color-text-secondary: #52645f;
--edu-color-text-muted: #7a8a85;
--edu-color-border: #dce6e2;
--edu-color-border-strong: #c8d8d2;
--edu-color-canvas: #f4f7f6;
--edu-color-surface: #ffffff;
--edu-color-success: #238b68;
--edu-color-warning: #b77a17;
--edu-color-danger: #c94b52;
--edu-shadow-sm: 0 1px 2px rgba(19, 45, 37, 0.05);
--edu-shadow-md: 0 6px 18px rgba(19, 45, 37, 0.08);
--edu-shadow-dialog: 0 18px 48px rgba(14, 36, 30, 0.18);
--edu-radius-sm: 5px;
--edu-radius-md: 8px;
--edu-radius-lg: 12px;
--edu-transition-fast: 160ms ease;
--edu-transition-base: 220ms ease;
}
body {
color: var(--edu-color-text);
background: var(--edu-color-canvas);
}
button,
input,
textarea,
select {
font-family: inherit;
}
button,
[role="button"],
.el-button,
.el-dropdown,
.el-menu-item,
.el-submenu__title {
-webkit-tap-highlight-color: transparent;
}
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
.el-button:focus-visible,
.el-input__inner:focus-visible,
.el-textarea__inner:focus-visible {
outline: 2px solid var(--edu-color-primary);
outline-offset: 2px;
}
#app .main-container,
#app .app-main {
background: var(--edu-color-canvas);
}
#app .app-container {
padding: 20px 22px;
}
/* 按钮采用清晰的主次层级,避免同屏操作全部呈现为高强调。 */
#app .el-button {
min-height: 36px;
padding: 9px 16px;
border-radius: var(--edu-radius-sm);
border-color: var(--edu-color-border-strong);
color: #334740;
font-size: 14px;
font-weight: 500;
letter-spacing: 0.1px;
box-shadow: var(--edu-shadow-sm);
transition:
color var(--edu-transition-fast),
background-color var(--edu-transition-fast),
border-color var(--edu-transition-fast),
box-shadow var(--edu-transition-fast);
}
#app .el-button:hover,
#app .el-button:focus {
color: var(--edu-color-primary);
background: var(--edu-color-primary-faint);
border-color: #9cbdb1;
box-shadow: 0 2px 6px rgba(11, 107, 85, 0.10);
}
#app .el-button:active {
color: var(--edu-color-primary-active);
background: #dfede8;
border-color: var(--edu-color-primary);
box-shadow: inset 0 1px 2px rgba(8, 76, 63, 0.12);
}
#app .el-button--primary {
color: #ffffff;
background: var(--edu-color-primary);
border-color: var(--edu-color-primary);
box-shadow: 0 2px 5px rgba(11, 107, 85, 0.18);
}
#app .el-button--primary:hover,
#app .el-button--primary:focus {
color: #ffffff;
background: var(--edu-color-primary-hover);
border-color: var(--edu-color-primary-hover);
box-shadow: 0 4px 10px rgba(11, 107, 85, 0.22);
}
#app .el-button--primary:active {
color: #ffffff;
background: var(--edu-color-primary-active);
border-color: var(--edu-color-primary-active);
}
#app .el-button--primary.is-plain {
color: var(--edu-color-primary);
background: var(--edu-color-primary-faint);
border-color: #9cbdb1;
box-shadow: none;
}
#app .el-button--primary.is-plain:hover,
#app .el-button--primary.is-plain:focus {
color: #ffffff;
background: var(--edu-color-primary);
border-color: var(--edu-color-primary);
}
#app .el-button--success.is-plain,
#app .el-button--warning.is-plain,
#app .el-button--danger.is-plain,
#app .el-button--info.is-plain {
box-shadow: none;
}
#app .el-button--success.is-plain {
color: var(--edu-color-success);
background: #eef8f4;
border-color: #afd5c7;
}
#app .el-button--warning.is-plain {
color: var(--edu-color-warning);
background: #fbf6ea;
border-color: #dfc58f;
}
#app .el-button--danger.is-plain {
color: var(--edu-color-danger);
background: #fbf0f1;
border-color: #e4b3b7;
}
#app .el-button--info.is-plain {
color: #5f706b;
background: #f3f5f4;
border-color: #c8d1ce;
}
#app .el-button--success.is-plain:hover,
#app .el-button--warning.is-plain:hover,
#app .el-button--danger.is-plain:hover,
#app .el-button--info.is-plain:hover {
color: #ffffff;
}
#app .el-button--success {
background: var(--edu-color-success);
border-color: var(--edu-color-success);
}
#app .el-button--warning {
background: var(--edu-color-warning);
border-color: var(--edu-color-warning);
}
#app .el-button--danger {
background: var(--edu-color-danger);
border-color: var(--edu-color-danger);
}
#app .el-button--info {
background: #5f706b;
border-color: #5f706b;
}
#app .el-button--success,
#app .el-button--warning,
#app .el-button--danger,
#app .el-button--info {
color: #ffffff;
}
#app .el-button--success.is-plain:hover {
background: var(--edu-color-success);
border-color: var(--edu-color-success);
}
#app .el-button--warning.is-plain:hover {
background: var(--edu-color-warning);
border-color: var(--edu-color-warning);
}
#app .el-button--danger.is-plain:hover {
background: var(--edu-color-danger);
border-color: var(--edu-color-danger);
}
#app .el-button--info.is-plain:hover {
background: #5f706b;
border-color: #5f706b;
}
#app .el-button--mini {
min-height: 30px;
padding: 6px 11px;
font-size: 13px;
}
#app .el-button--small {
min-height: 32px;
padding: 7px 13px;
}
#app .el-button--text {
min-height: 30px;
padding: 5px 7px;
color: var(--edu-color-primary);
border-color: transparent;
background: transparent;
box-shadow: none;
}
#app .el-button--text:hover,
#app .el-button--text:focus {
color: var(--edu-color-primary-hover);
background: var(--edu-color-primary-soft);
border-color: transparent;
}
#app .el-button.is-circle {
min-width: 36px;
padding: 0;
}
#app .el-button.is-disabled,
#app .el-button.is-disabled:hover,
#app .el-button.is-disabled:focus {
color: #9aa7a3;
background: #f2f4f3;
border-color: #e1e7e4;
box-shadow: none;
}
/* 表单控件保持紧凑,同时用统一焦点状态提升批量录入效率。 */
#app .el-input__inner,
#app .el-textarea__inner,
#app .el-range-editor.el-input__inner {
border-color: var(--edu-color-border-strong);
border-radius: var(--edu-radius-sm);
color: var(--edu-color-text);
background: var(--edu-color-surface);
transition:
border-color var(--edu-transition-fast),
box-shadow var(--edu-transition-fast);
}
#app .el-input__inner:hover,
#app .el-textarea__inner:hover,
#app .el-range-editor.el-input__inner:hover {
border-color: #91b3a7;
}
#app .el-input.is-active .el-input__inner,
#app .el-input__inner:focus,
#app .el-textarea__inner:focus,
#app .el-range-editor.is-active {
border-color: var(--edu-color-primary);
box-shadow: 0 0 0 3px rgba(11, 107, 85, 0.10);
}
#app .el-form-item__label {
color: #344a42;
font-weight: 500;
}
#app .el-checkbox__input.is-checked .el-checkbox__inner,
#app .el-checkbox__input.is-indeterminate .el-checkbox__inner,
#app .el-radio__input.is-checked .el-radio__inner {
background-color: var(--edu-color-primary);
border-color: var(--edu-color-primary);
}
#app .el-checkbox__input.is-checked + .el-checkbox__label,
#app .el-radio__input.is-checked + .el-radio__label {
color: var(--edu-color-primary-hover);
}
/* 数据表格用浅层表头和克制分隔线,强调扫描效率。 */
#app .el-table {
color: #344740;
border-radius: var(--edu-radius-md);
border: 1px solid var(--edu-color-border);
overflow: hidden;
}
#app .el-table::before,
#app .el-table--border::after {
background-color: var(--edu-color-border);
}
#app .el-table th.el-table__cell {
color: #29443b;
font-weight: 600;
background: #edf4f1;
border-bottom-color: #d7e4df;
}
#app .el-table td.el-table__cell {
border-bottom-color: #e7eeeb;
}
#app .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
background: #f2f8f5;
}
#app .el-table .current-row > td.el-table__cell {
background: #e8f3ef;
}
/* 行级操作保持单行,避免按钮被列宽挤压后增加表格行高。 */
#app .el-table .table-action-column .cell {
white-space: nowrap;
}
/* 卡片与弹窗采用一致的白色工作面,不使用装饰性大渐变。 */
#app .el-card {
border: 1px solid var(--edu-color-border);
border-radius: var(--edu-radius-lg);
background: var(--edu-color-surface);
box-shadow: var(--edu-shadow-sm);
}
#app .el-card__header {
padding: 15px 18px;
color: var(--edu-color-text);
font-weight: 600;
background: #fbfcfc;
border-bottom-color: var(--edu-color-border);
}
#app .el-dialog {
border-radius: var(--edu-radius-lg);
box-shadow: var(--edu-shadow-dialog);
overflow: hidden;
}
#app .el-dialog__header {
padding: 18px 22px 16px;
background: #f8faf9;
border-bottom: 1px solid var(--edu-color-border);
}
#app .el-dialog__title {
color: var(--edu-color-text);
font-size: 17px;
font-weight: 600;
}
#app .el-dialog__body {
padding: 22px;
}
#app .el-dialog__footer {
padding: 14px 22px 18px;
background: #fbfcfc;
border-top: 1px solid #edf1ef;
}
#app .el-pagination.is-background .el-pager li:not(.disabled).active {
background: var(--edu-color-primary);
}
#app .el-pagination button:hover,
#app .el-pager li:hover {
color: var(--edu-color-primary);
}
#app .el-tag {
border-radius: 4px;
font-weight: 500;
}
/* 教学管理列表页保持统一的信息层级,同时允许各业务页面保留原有结构。 */
#app .management-page {
--management-section-gap: 16px;
--management-section-padding: 18px;
}
#app .management-page .section-card {
padding: var(--management-section-padding);
margin-bottom: var(--management-section-gap);
border: 1px solid var(--edu-color-border);
border-radius: var(--edu-radius-lg);
background: var(--edu-color-surface);
box-shadow: var(--edu-shadow-sm);
}
#app .management-page .section-heading {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 24px;
padding-bottom: 16px;
margin-bottom: 18px;
border-bottom: 1px solid #edf1ef;
}
#app .management-page .section-heading--compact {
padding-bottom: 12px;
margin-bottom: 14px;
}
#app .management-page .section-title {
margin: 0;
color: var(--edu-color-text);
font-size: 16px;
font-weight: 600;
line-height: 1.4;
}
#app .management-page .section-description {
margin: 4px 0 0;
color: var(--edu-color-text-secondary);
font-size: 12px;
line-height: 1.5;
}
#app .management-page .export-bar,
#app .management-page .action-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
#app .management-page .export-bar .el-button + .el-button,
#app .management-page .action-row .el-button + .el-button {
margin-left: 0;
}
#app .management-page .table-heading {
margin-bottom: 0;
}
/* 选修课操作较多,宽屏时并列展示操作与导出,降低按钮堆叠造成的视觉噪音。 */
#app .elective-page {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(360px, 1fr);
gap: var(--management-section-gap);
}
#app .elective-page .section-card {
margin-bottom: 0;
}
#app .elective-page .query-card,
#app .elective-page .upload-card,
#app .elective-page .table-card {
grid-column: 1 / -1;
}
#app .elective-page .action-card {
grid-column: 1;
grid-row: 2;
}
#app .elective-page .export-card {
grid-column: 2;
grid-row: 2;
}
#app .management-page .query-card .q-control,
#app .management-page .search-card .q-control {
max-width: 520px;
}
/* 首页沿用原有模块,不改变信息结构,仅降低大色块与渐变的视觉重量。 */
#app .home {
background: var(--edu-color-canvas);
}
#app .home .module-card {
border: 1px solid var(--edu-color-border);
background: var(--edu-color-surface);
box-shadow: var(--edu-shadow-sm);
}
#app .home .module-card:hover {
border-color: #c9dcd5;
box-shadow: var(--edu-shadow-md);
}
#app .home .module-card .el-card__header {
color: var(--edu-color-text);
background: #fbfcfc;
border-bottom: 1px solid var(--edu-color-border);
}
#app .home .card-header {
color: var(--edu-color-text);
}
#app .home .card-header .card-icon {
color: var(--edu-color-primary);
}
#app .home .card-header .more-btn {
color: var(--edu-color-primary);
}
#app .home .contact-item .contact-icon {
background: var(--edu-color-primary-soft);
color: var(--edu-color-primary);
border-radius: var(--edu-radius-md);
box-shadow: none;
}
/* 下拉浮层渲染在 body 下,因此使用系统级选择器统一其视觉。 */
.el-select-dropdown,
.el-dropdown-menu,
.el-picker-panel,
.el-popover {
border-color: var(--edu-color-border);
border-radius: var(--edu-radius-md);
box-shadow: var(--edu-shadow-md);
}
.el-select-dropdown__item.hover,
.el-select-dropdown__item:hover,
.el-dropdown-menu__item:not(.is-disabled):hover,
.el-dropdown-menu__item:not(.is-disabled):focus {
color: var(--edu-color-primary);
background: var(--edu-color-primary-soft);
}
.el-select-dropdown__item.selected {
color: var(--edu-color-primary);
font-weight: 600;
}
@media (max-width: 768px) {
#app .app-container {
padding: 14px;
}
#app .el-button {
min-height: 38px;
}
#app .el-dialog {
width: calc(100% - 24px);
margin-top: 4vh;
}
#app .management-page {
--management-section-padding: 14px;
}
#app .management-page .section-heading,
#app .management-page .upload-row {
align-items: stretch;
flex-direction: column;
}
#app .management-page .section-heading .el-button,
#app .management-page .upload-right .el-button {
width: 100%;
}
}
@media (max-width: 1200px) {
#app .elective-page {
display: block;
}
#app .elective-page .section-card {
margin-bottom: var(--management-section-gap);
}
}
@media (prefers-reduced-motion: reduce) {
#app *,
#app *::before,
#app *::after {
scroll-behavior: auto;
transition-duration: 0.01ms;
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
}
@@ -4,13 +4,13 @@
**/ **/
/* theme color */ /* theme color */
$--color-primary: #00875A; $--color-primary: #0b6b55;
$--color-success: #13ce66; $--color-success: #238b68;
$--color-warning: #ffba00; $--color-warning: #c58a22;
$--color-danger: #ff4949; $--color-danger: #c94b52;
// $--color-info: #1E1E1E; // $--color-info: #1E1E1E;
$--button-font-weight: 400; $--button-font-weight: 500;
// $--color-text-regular: #1f2d3d; // $--color-text-regular: #1f2d3d;
+7 -6
View File
@@ -4,20 +4,21 @@
@import './element-ui.scss'; @import './element-ui.scss';
@import './sidebar.scss'; @import './sidebar.scss';
@import './btn.scss'; @import './btn.scss';
@import './education-theme.scss';
/* ================= 系统主题色(教育绿) ================= */ /* ================= 系统主题色(教育绿) ================= */
:root { :root {
/* 基础绿 */ /* 基础绿 */
--edu-green: #007F4F; --edu-green: #0b6b55;
--edu-green-hover: #00663E; --edu-green-hover: #085442;
--edu-green-bg: #E3F2E9; --edu-green-bg: #e8f3ef;
/* 主色:导航、按钮、主题色 */ /* 主色:导航、按钮、主题色 */
--edu-green-primary: #00875A; /* rgb(0,135,90) */ --edu-green-primary: #0b6b55;
/* hover 加深 */ /* hover 加深 */
--edu-green-dark: #006B47; /* rgb(0,107,71) */ --edu-green-dark: #084c3f;
/* 浅色背景、标签底色 */ /* 浅色背景、标签底色 */
--edu-green-light: #E6F4EA; /* rgb(230,244,234) */ --edu-green-light: #e8f3ef;
} }
body { body {
+20 -2
View File
@@ -109,18 +109,36 @@
} }
.el-table__body-wrapper { .el-table__body-wrapper {
// 宽表格统一通过内容区拖拽横向查看,隐藏重复的底部滚动条但保留滚动能力。
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
.el-button [class*="el-icon-"] + span { .el-button [class*="el-icon-"] + span {
margin-left: 1px; margin-left: 1px;
} }
} }
// 表格横向拖拽滚动:拖拽过程中光标切换为“抓手” // 表格横向拖拽滚动:拖拽过程中光标保持默认箭头,不切换为“抓手”
.el-table__body-wrapper.is-dragging, .el-table__body-wrapper.is-dragging,
.el-table__fixed-body-wrapper.is-dragging { .el-table__fixed-body-wrapper.is-dragging {
cursor: grabbing; cursor: default;
} }
} }
/* 表格横拖期间锁定整页光标与文本选中:
避免光标划过按钮/链接时闪变成手型、以及拖拽过程误选中文字 */
body.el-table-dragging,
body.el-table-dragging * {
user-select: none !important;
cursor: default !important;
}
/* 原生表格同样禁止选中文本,避免横向滑动/滚动时误触发复制前的文本选中 */ /* 原生表格同样禁止选中文本,避免横向滑动/滚动时误触发复制前的文本选中 */
table { table {
-webkit-user-select: none; -webkit-user-select: none;
+12 -9
View File
@@ -5,6 +5,8 @@
transition: width 0.28s; transition: width 0.28s;
width: $base-sidebar-width !important; width: $base-sidebar-width !important;
background-color: $base-menu-background; background-color: $base-menu-background;
border-right: 1px solid rgba(3, 49, 40, 0.32);
box-shadow: 4px 0 14px rgba(8, 51, 42, 0.08);
height: 100%; height: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
@@ -52,14 +54,15 @@
white-space: nowrap !important; white-space: nowrap !important;
height: 44px !important; height: 44px !important;
line-height: 44px !important; line-height: 44px !important;
font-weight: 600; font-weight: 500;
letter-spacing: 0.2px;
} }
// menu hover // menu hover
.submenu-title-noDropdown, .submenu-title-noDropdown,
.el-submenu__title { .el-submenu__title {
&:hover { &:hover {
background-color: rgba(0, 0, 0, 0.06) !important; background-color: rgba(255, 255, 255, 0.08) !important;
} }
} }
@@ -111,29 +114,29 @@
content: ''; content: '';
position: absolute; position: absolute;
inset: 0; inset: 0;
background-color: rgba(255, 255, 255, 0.15); background-color: rgba(255, 255, 255, 0.13);
border-right: 3px solid #FFC53D; border-left: 3px solid #d7b45a;
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 1;
} }
} }
.el-submenu.is-active > .el-submenu__title { .el-submenu.is-active > .el-submenu__title {
color: #E6F4EA !important; color: #ffffff !important;
font-weight: 600; font-weight: 600;
&::before { &::before {
background-color: rgba(255, 255, 255, 0.15); background-color: rgba(255, 255, 255, 0.10);
border-right: 3px solid #FFC53D; border-left: 3px solid #d7b45a;
} }
.el-submenu__icon-arrow { .el-submenu__icon-arrow {
color: #FFC53D !important; color: #e2c36f !important;
} }
} }
.el-submenu__title .el-submenu__icon-arrow { .el-submenu__title .el-submenu__icon-arrow {
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.76);
font-size: 12px; font-size: 12px;
font-weight: 700; font-weight: 700;
transition: transform 0.2s; transition: transform 0.2s;
+5 -5
View File
@@ -8,16 +8,16 @@ $tiffany: #4AB7BD;
$yellow:#FEC171; $yellow:#FEC171;
$panGreen: #30B08F; $panGreen: #30B08F;
// 默认菜单主题风格(教育绿) // 默认菜单主题风格(学院绿)
$base-menu-color: #e8f5ef; $base-menu-color: #dcebe6;
$base-menu-color-active: #ffffff; $base-menu-color-active: #ffffff;
$base-menu-background: #00875A; $base-menu-background: #0b5f4a;
$base-menu-light-color:rgba(0,0,0,.70); $base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff; $base-menu-light-background:#ffffff;
$base-sub-menu-background: #006B47; $base-sub-menu-background: #084c3f;
$base-sub-menu-hover: rgba(255,255,255,.12); $base-sub-menu-hover: rgba(255,255,255,.10);
$base-sidebar-width: 200px; $base-sidebar-width: 200px;
+73 -35
View File
@@ -3,15 +3,18 @@
* 隐藏表格的横向滚动条,按住鼠标左键横向拖动即可查看后面的字段。 * 隐藏表格的横向滚动条,按住鼠标左键横向拖动即可查看后面的字段。
* 通过 document 事件委托全局生效,所有 el-table 自动支持,无需逐页绑定。 * 通过 document 事件委托全局生效,所有 el-table 自动支持,无需逐页绑定。
* *
* 手感优化: * 实现要点(全面优化
* - 文本选中已在全局样式中禁用(user-select: none),拖拽过程不会再误选文字 * - 采用 Pointer Events + setPointerCapture:按下瞬间把指针捕获到滚动容器上,
* - 位移以横向为主且超过阈值才触发滚动,轻微手抖、普通点击、纵向拖拽(如行排序)不受影响 * 之后无论光标移动到固定列、表格下方还是窗口外,移动事件都不会中断,真正"跟手"。
* - 光标仅在真正拖动时变为抓手,平时保持默认 * - requestAnimationFrame 合并每帧滚动,避免高频事件造成卡顿/闪烁。
* - 拖拽结束(确实发生了滚动)后屏蔽本次 click,避免误触发行点击、复选框等 * - 横向位移超过阈值即触发,允许轻微斜向/弧线;仅当纵向明显占优时才不触发,
* 保留普通点击与纵向拖拽(如行排序)的区分。
* - 拖拽期间整页锁定光标与文本选中,光标保持默认箭头,不闪变为抓手/手型。
* - 拖拽结束(确实发生了滚动)后屏蔽本次 click,避免误触发行点击、复选框等。
*/ */
const DRAG_THRESHOLD = 4 // 横向位移超过该像素且以横向为主,才判定为拖动 const DRAG_THRESHOLD = 2 // 横向位移超过该像素即判定为拖动,越小越跟手
// 在这些元素上按下鼠标不触发拖拽,保证按钮、复选框等交互不受影响 // 在这些元素上按下不触发拖拽,保证按钮、复选框等交互不受影响
const INTERACTIVE_SELECTOR = [ const INTERACTIVE_SELECTOR = [
'a', 'button', 'input', 'textarea', 'select', 'label', 'a', 'button', 'input', 'textarea', 'select', 'label',
'.el-button', '.el-checkbox', '.el-radio', '.el-switch', '.el-select', '.el-button', '.el-checkbox', '.el-radio', '.el-switch', '.el-select',
@@ -20,77 +23,112 @@ const INTERACTIVE_SELECTOR = [
].join(',') ].join(',')
let wrapper = null let wrapper = null
let pointerId = null
let startX = 0 let startX = 0
let startY = 0 let startY = 0
let startScrollLeft = 0 let startScrollLeft = 0
let dragging = false let dragging = false
let rafId = null
let pendingScrollLeft = 0
function isHorizontallyScrollable(el) { function isHorizontallyScrollable(el) {
return el.scrollWidth > el.clientWidth + 1 return el.scrollWidth > el.clientWidth + 1
} }
function handleMouseDown(e) { // 每帧只应用一次滚动位置,提升平滑度
if (e.button !== 0) return function applyScroll() {
if (!wrapper) return
wrapper.scrollLeft = pendingScrollLeft
rafId = null
}
function handlePointerDown(e) {
if (e.button !== 0 && e.pointerType === 'mouse') return
if (e.target.closest(INTERACTIVE_SELECTOR)) return if (e.target.closest(INTERACTIVE_SELECTOR)) return
const wrap = e.target.closest('.el-table__body-wrapper') // 固定列(如 fixed="right" 的操作列)渲染在 .el-table__fixed-body-wrapper 中,悬浮覆盖在
// 表体右侧,需一并识别;最终统一落到真正负责横向滚动的 .el-table__body-wrapper 上
const anyWrapper = e.target.closest('.el-table__body-wrapper, .el-table__fixed-body-wrapper')
if (!anyWrapper) return
const table = anyWrapper.closest('.el-table')
const wrap = table && table.querySelector('.el-table__body-wrapper')
if (!wrap || !isHorizontallyScrollable(wrap)) return if (!wrap || !isHorizontallyScrollable(wrap)) return
wrapper = wrap wrapper = wrap
pointerId = e.pointerId
startX = e.clientX startX = e.clientX
startY = e.clientY startY = e.clientY
startScrollLeft = wrap.scrollLeft startScrollLeft = wrap.scrollLeft
pendingScrollLeft = startScrollLeft
dragging = false dragging = false
// 关键:捕获指针,之后所有 pointermove/pointerup 都持续派发到容器,
// 即使光标移出表体/窗口也不中断
if (wrap.setPointerCapture && e.pointerId != null) {
try { wrap.setPointerCapture(e.pointerId) } catch (err) { /* 忽略捕获失败 */ }
}
// 阻止默认行为,抑制原生图片/文本拖拽与选中
e.preventDefault()
} }
function handleMouseMove(e) { function handlePointerMove(e) {
if (!wrapper) return if (!wrapper || e.pointerId !== pointerId) return
e.preventDefault()
const dx = e.clientX - startX const dx = e.clientX - startX
const dy = e.clientY - startY const dy = e.clientY - startY
if (!dragging) { if (!dragging) {
// 轻微位移视为点击,不触发滚动;位移必须以横向为主,避免与纵向拖拽(如行排序)冲突 // 仅当纵向明显占优(超过横向 3 倍且超过 12px)才判定为纵向操作、不触发横向拖动,
if (Math.abs(dx) <= DRAG_THRESHOLD || Math.abs(dx) <= Math.abs(dy)) return // 其余情况(含轻微斜向/弧线)都正常触发,避免"拖不动"
// 开始拖动:以当前位置为基准,避免起始跳变 if (Math.abs(dx) <= DRAG_THRESHOLD || (Math.abs(dy) > Math.abs(dx) * 3 && Math.abs(dy) > 12)) return
dragging = true dragging = true
startX = e.clientX
startY = e.clientY
startScrollLeft = wrapper.scrollLeft
wrapper.classList.add('is-dragging') wrapper.classList.add('is-dragging')
// 整页锁定光标与文本选中,保证拖拽手感一致(光标不闪变、文字不误选)
document.body.classList.add('el-table-dragging')
} }
e.preventDefault()
wrapper.scrollLeft = startScrollLeft - (e.clientX - startX) // 记录目标位置,交由 rAF 统一应用
pendingScrollLeft = startScrollLeft - (e.clientX - startX)
if (rafId == null) rafId = requestAnimationFrame(applyScroll)
} }
function handleMouseUp() { function endDrag(blockClick) {
if (!wrapper) return if (!wrapper) return
if (rafId != null) {
cancelAnimationFrame(rafId)
rafId = null
}
wrapper.classList.remove('is-dragging') wrapper.classList.remove('is-dragging')
if (dragging) { document.body.classList.remove('el-table-dragging')
if (blockClick && dragging) {
// 拖拽确实发生了滚动,屏蔽本次 click,避免误触发行点击、复选框等 // 拖拽确实发生了滚动,屏蔽本次 click,避免误触发行点击、复选框等
const blockClick = (ev) => { const suppress = (ev) => {
ev.preventDefault() ev.preventDefault()
ev.stopPropagation() ev.stopPropagation()
document.removeEventListener('click', blockClick, true) document.removeEventListener('click', suppress, true)
} }
document.addEventListener('click', blockClick, true) document.addEventListener('click', suppress, true)
} }
wrapper = null wrapper = null
pointerId = null
dragging = false dragging = false
} }
// 鼠标拖出窗口外时清理拖拽状态,防止状态残留 function handlePointerUp(e) {
function handleMouseLeave() { if (e.pointerId !== pointerId) return
if (!wrapper) return endDrag(true)
wrapper.classList.remove('is-dragging') }
wrapper = null
dragging = false function handlePointerCancel() {
endDrag(false)
} }
const install = function() { const install = function() {
if (install.installed) return if (install.installed) return
install.installed = true install.installed = true
document.addEventListener('mousedown', handleMouseDown, false) document.addEventListener('pointerdown', handlePointerDown, true)
document.addEventListener('mousemove', handleMouseMove, false) document.addEventListener('pointermove', handlePointerMove, true)
document.addEventListener('mouseup', handleMouseUp, false) document.addEventListener('pointerup', handlePointerUp, true)
document.addEventListener('mouseleave', handleMouseLeave, false) document.addEventListener('pointercancel', handlePointerCancel, true)
} }
export default install export default install
+19 -19
View File
@@ -159,19 +159,19 @@ export default {
justify-content: center; justify-content: center;
width: 38px; width: 38px;
height: 38px; height: 38px;
border-radius: 50%; border-radius: 7px;
background: rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.07);
transition: all 0.25s ease; border: 1px solid rgba(255, 255, 255, 0.10);
transition: background-color 0.18s ease, border-color 0.18s ease;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.15);
transform: translateY(-1px); border-color: rgba(255, 255, 255, 0.28);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
} }
&:active { &:active {
transform: translateY(0); background: rgba(255, 255, 255, 0.21);
} }
.svg-icon { .svg-icon {
@@ -192,19 +192,19 @@ export default {
justify-content: center; justify-content: center;
width: 38px; width: 38px;
height: 38px; height: 38px;
border-radius: 50%; border-radius: 7px;
background: rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.07);
transition: all 0.25s ease; border: 1px solid rgba(255, 255, 255, 0.10);
transition: background-color 0.18s ease, border-color 0.18s ease;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.15);
transform: translateY(-1px); border-color: rgba(255, 255, 255, 0.28);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
} }
&:active { &:active {
transform: translateY(0); background: rgba(255, 255, 255, 0.21);
} }
.svg-icon { .svg-icon {
@@ -282,7 +282,7 @@ export default {
margin-right: 0; margin-right: 0;
padding: 0 6px 0 10px; padding: 0 6px 0 10px;
height: 100%; height: 100%;
border-radius: 22px; border-radius: 8px;
cursor: pointer; cursor: pointer;
&.is-active .user-caret { &.is-active .user-caret {
@@ -299,10 +299,10 @@ export default {
position: relative; position: relative;
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 50%; border-radius: 8px;
padding: 2px; padding: 2px;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.55)); background: rgba(255, 255, 255, 0.92);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -310,7 +310,7 @@ export default {
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 50%; border-radius: 6px;
object-fit: cover; object-fit: cover;
background: var(--edu-green-light); background: var(--edu-green-light);
display: block; display: block;
@@ -147,7 +147,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 12px; gap: 10px;
height: 36px; height: 36px;
font-size: 13px; font-size: 13px;
color: rgba(255, 255, 255, 0.85); color: rgba(255, 255, 255, 0.85);
@@ -159,10 +159,9 @@ export default {
justify-content: center; justify-content: center;
height: 36px; height: 36px;
padding: 0 16px; padding: 0 16px;
border-radius: 18px; border-radius: 7px;
background: rgba(255, 255, 255, 0.12); background: rgba(255, 255, 255, 0.09);
border: 1px solid rgba(255, 255, 255, 0.22); border: 1px solid rgba(255, 255, 255, 0.16);
backdrop-filter: blur(2px);
box-sizing: border-box; box-sizing: border-box;
i { i {
@@ -251,7 +250,7 @@ export default {
background: rgba(255, 255, 255, 0.12); background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.35); border: 1px solid rgba(255, 255, 255, 0.35);
color: #fff; color: #fff;
border-radius: 18px; border-radius: 7px;
height: 36px; height: 36px;
padding: 0 12px; padding: 0 12px;
display: flex; display: flex;
@@ -81,7 +81,15 @@ export default {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
color: #bfcbd9; color: rgba(255, 255, 255, 0.72);
border-top: 1px solid rgba(255, 255, 255, 0.10);
background: rgba(3, 49, 40, 0.18);
transition: background-color 160ms ease, color 160ms ease;
&:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.10);
}
.collapse-hamburger { .collapse-hamburger {
line-height: 48px; line-height: 48px;
@@ -135,8 +135,8 @@ export default {
tagActiveStyle(tag) { tagActiveStyle(tag) {
if (!this.isActive(tag)) return {} if (!this.isActive(tag)) return {}
return { return {
"background-color": "#00875A", "background-color": "#e8f3ef",
"border-color": "#00875A" "border-color": "#0b6b55"
} }
}, },
isAffix(tag) { isAffix(tag) {
@@ -363,7 +363,8 @@ $tags-bar-height: 34px;
height: $tags-bar-height; height: $tags-bar-height;
width: 100%; width: 100%;
background: #fff; background: #fff;
border-bottom: 1px solid #d8dce5; border-bottom: 1px solid #dce6e2;
box-shadow: 0 1px 2px rgba(19, 45, 37, 0.04);
display: flex; display: flex;
align-items: center; align-items: center;
overflow: hidden; overflow: hidden;
@@ -413,29 +414,37 @@ $tags-bar-height: 34px;
cursor: pointer; cursor: pointer;
height: 26px; height: 26px;
line-height: 26px; line-height: 26px;
border: 1px solid #d8dce5; border: 1px solid #dce6e2;
color: #495060; color: #52645f;
background: #fff; background: #fff;
padding: 0 8px; padding: 0 8px;
font-size: 12px; font-size: 12px;
margin-left: 5px; margin-left: 5px;
border-radius: 3px; border-radius: 5px;
transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease;
&:hover {
color: #0b6b55;
background: #f3f8f6;
border-color: #b6cec5;
}
&:first-of-type { margin-left: 6px; } &:first-of-type { margin-left: 6px; }
&:last-of-type { margin-right: 15px; } &:last-of-type { margin-right: 15px; }
} }
} }
&:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active { &:not(.tags-view-container--chrome) .tags-view-wrapper .tags-view-item.active {
background-color: #42b983; background-color: #e8f3ef;
color: #fff; color: #085442;
border-color: #42b983; border-color: #0b6b55;
font-weight: 600;
&::before { &::before {
content: ''; content: '';
background: #fff; background: #c69b3c;
display: inline-block; display: inline-block;
width: 8px; width: 3px;
height: 8px; height: 12px;
border-radius: 50%; border-radius: 2px;
position: relative; position: relative;
margin-right: 2px; margin-right: 2px;
} }
+14 -6
View File
@@ -1,5 +1,13 @@
<template> <template>
<div :class="classObj" class="app-wrapper" :style="{'--current-color': '#00875A', '--current-color-light': '#00875A1a', '--current-color-dark-bg': '#00875A33'}"> <div
:class="classObj"
class="app-wrapper"
:style="{
'--current-color': '#0B6B55',
'--current-color-light': '#0B6B551a',
'--current-color-dark-bg': '#0B6B5533'
}"
>
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/> <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<!-- 顶部全宽 Header --> <!-- 顶部全宽 Header -->
@@ -103,9 +111,9 @@ export default {
height: 60px; height: 60px;
display: flex; display: flex;
align-items: center; align-items: center;
background: var(--edu-green-primary); background: linear-gradient(104deg, #0b6b55 0%, #095b49 58%, #084c3f 100%);
background: linear-gradient(90deg, var(--edu-green-primary) 0%, var(--edu-green-dark) 100%); border-bottom: 1px solid rgba(198, 155, 60, 0.5);
box-shadow: 0 2px 8px rgba(0, 21, 41, 0.16); box-shadow: 0 3px 12px rgba(8, 51, 42, 0.16);
padding: 0 20px; padding: 0 20px;
z-index: 10; z-index: 10;
@@ -140,7 +148,7 @@ export default {
letter-spacing: 1.5px; letter-spacing: 1.5px;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
cursor: pointer; cursor: pointer;
border-radius: 6px; border-radius: 5px;
padding: 4px 10px; padding: 4px 10px;
transition: background 0.25s ease; transition: background 0.25s ease;
@@ -184,7 +192,7 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
background-color: #f5f7fa; background-color: var(--edu-color-canvas);
} }
.drawer-bg { .drawer-bg {
+28
View File
@@ -1,6 +1,32 @@
import cache from '@/plugins/cache' import cache from '@/plugins/cache'
const PERSIST_KEY = 'tags-view-visited' const PERSIST_KEY = 'tags-view-visited'
const MAX_VISITED_VIEWS = 8
function removeViewCache(state, view) {
const cachedViewIndex = state.cachedViews.indexOf(view.name)
if (cachedViewIndex > -1) {
state.cachedViews.splice(cachedViewIndex, 1)
}
state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
}
function trimVisitedViews(state, currentView) {
while (state.visitedViews.length > MAX_VISITED_VIEWS) {
const removableViewIndex = state.visitedViews.findIndex(view => {
const isAffix = view.meta && view.meta.affix
return !isAffix && view.path !== currentView.path
})
if (removableViewIndex === -1) {
return
}
const [removedView] = state.visitedViews.splice(removableViewIndex, 1)
removeViewCache(state, removedView)
}
}
// 布局已固定,不启用标签页持久化 // 布局已固定,不启用标签页持久化
function isPersistEnabled() { function isPersistEnabled() {
@@ -43,6 +69,7 @@ const mutations = {
title: view.meta.title || 'no-name' title: view.meta.title || 'no-name'
}) })
) )
trimVisitedViews(state, view)
saveVisitedViews(state.visitedViews) saveVisitedViews(state.visitedViews)
}, },
ADD_VISITED_VIEW_FIRST: (state, view) => { ADD_VISITED_VIEW_FIRST: (state, view) => {
@@ -52,6 +79,7 @@ const mutations = {
title: view.meta.title || 'no-name' title: view.meta.title || 'no-name'
}) })
) )
trimVisitedViews(state, view)
}, },
ADD_CACHED_VIEW: (state, view) => { ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return if (state.cachedViews.includes(view.name)) return
@@ -25,12 +25,12 @@
<div class="upload-row"> <div class="upload-row">
<div class="upload-left"> <div class="upload-left">
<el-button type="primary" @click="handleAdd">新增联教联训</el-button> <el-button type="primary" @click="handleAdd">新增联教联训</el-button>
<el-button type="primary" plain @click="handleExport">导出 Excel</el-button> <el-button icon="el-icon-download" @click="handleExport">导出 Excel</el-button>
<el-button @click="handleDownloadTemplate">联教联训数据文件模板下载</el-button> <el-button icon="el-icon-download" @click="handleDownloadTemplate">联教联训数据文件模板下载</el-button>
<el-button plain @click="handleChooseFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleChooseFile">选择文件</el-button>
<span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span> <span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span>
<input ref="fileInputRef" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" /> <input ref="fileInputRef" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" />
<el-button type="success" :loading="uploading" @click="handleUpload">上传数据</el-button> <el-button type="primary" icon="el-icon-upload2" :loading="uploading" @click="handleUpload">上传数据</el-button>
</div> </div>
</div> </div>
</el-card> </el-card>
+2 -210
View File
@@ -1,89 +1,8 @@
<template> <template>
<div class="app-container home"> <div class="app-container home">
<!-- 第一行信息/日志/公告 --> <!-- 通知公告 -->
<el-row :gutter="20" class="bottom-row"> <el-row :gutter="20" class="bottom-row">
<el-col :xs="24" :sm="24" :md="12" :lg="8"> <el-col :xs="24" :sm="24" :md="24" :lg="24">
<el-card class="module-card info-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-phone-outline card-icon"></i> 联系信息</span>
</div>
<div class="card-body">
<div class="contact-item">
<div class="contact-icon"><i class="el-icon-s-promotion"></i></div>
<div class="contact-text">
<div class="label">官网</div>
<el-link href="http://www.roomroot.vip" target="_blank">http://www.roomroot.vip</el-link>
</div>
</div>
<div class="contact-item">
<div class="contact-icon"><i class="el-icon-user-solid"></i></div>
<div class="contact-text">
<div class="label">QQ群</div>
<a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=M9y5NjAl44lAL_Vh2crmEehZU_PMU6KS&authKey=ZSDz8hEREWSaPuxQV3gEwqGIaGjfRNnkB4rJjf0IvXhrSUGSGwQFmBA%2Boe8HFxyl&noverify=0&group_code=127358632" target="_blank">127358632</a>
</div>
</div>
<div class="contact-item">
<div class="contact-icon"><i class="el-icon-chat-dot-round"></i></div>
<div class="contact-text">
<div class="label">微信</div>
<span>风影随行</span>
</div>
</div>
<div class="contact-item">
<div class="contact-icon"><i class="el-icon-money"></i></div>
<div class="contact-text">
<div class="label">支付宝</div>
<span>风影随行</span>
</div>
</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="module-card log-card" shadow="hover">
<div slot="header" class="card-header">
<span><i class="el-icon-time card-icon"></i> 登录日志</span>
</div>
<div class="card-body" v-loading="loginLogLoading">
<table v-if="loginLogList.length > 0" class="data-table">
<thead>
<tr>
<th>登录人</th>
<th>登录时间</th>
</tr>
</thead>
<tbody>
<tr v-for="item in loginLogList" :key="item.infoId">
<td>
<i class="el-icon-user table-icon"></i>
{{ item.userName }}
</td>
<td>{{ parseTime(item.loginTime) }}</td>
</tr>
</tbody>
</table>
<div v-else class="empty-state">
<i class="el-icon-folder-opened empty-icon"></i>
<p>暂无记录</p>
</div>
</div>
<div class="card-footer">
<el-pagination
@size-change="handleLoginLogSizeChange"
@current-change="handleLoginLogCurrentChange"
:current-page="loginLogPage.currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="loginLogPage.pageSize"
:total="loginLogPage.total"
layout="total, prev, pager, next"
small
/>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="module-card notice-card" shadow="hover"> <el-card class="module-card notice-card" shadow="hover">
<div slot="header" class="card-header"> <div slot="header" class="card-header">
<span><i class="el-icon-bell card-icon"></i> 通知公告</span> <span><i class="el-icon-bell card-icon"></i> 通知公告</span>
@@ -131,7 +50,6 @@
<script> <script>
import { listNotice } from "@/api/system/notice" import { listNotice } from "@/api/system/notice"
import { homeList } from "@/api/monitor/logininfor"
import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView" import NoticeDetailView from "@/layout/components/HeaderNotice/DetailView"
export default { export default {
@@ -142,13 +60,6 @@ export default {
version: "3.9.2", version: "3.9.2",
noticeList: [], noticeList: [],
noticeLoading: false, noticeLoading: false,
loginLogList: [],
loginLogLoading: false,
loginLogPage: {
currentPage: 1,
pageSize: 10,
total: 0
},
noticePage: { noticePage: {
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
@@ -158,7 +69,6 @@ export default {
}, },
mounted() { mounted() {
this.loadNoticeList() this.loadNoticeList()
this.loadLoginLogList()
}, },
methods: { methods: {
goTarget(href) { goTarget(href) {
@@ -208,28 +118,6 @@ export default {
handleViewNotice(item) { handleViewNotice(item) {
this.$refs.noticeViewRef.open(item) this.$refs.noticeViewRef.open(item)
}, },
loadLoginLogList() {
this.loginLogLoading = true
homeList({
pageNum: this.loginLogPage.currentPage,
pageSize: this.loginLogPage.pageSize
}).then(response => {
this.loginLogList = response.rows || []
this.loginLogPage.total = response.total || 0
this.loginLogLoading = false
}).catch(() => {
this.loginLogLoading = false
})
},
handleLoginLogSizeChange(val) {
this.loginLogPage.pageSize = val
this.loginLogPage.currentPage = 1
this.loadLoginLogList()
},
handleLoginLogCurrentChange(val) {
this.loginLogPage.currentPage = val
this.loadLoginLogList()
},
handleNoticeSizeChange(val) { handleNoticeSizeChange(val) {
this.noticePage.pageSize = val this.noticePage.pageSize = val
this.noticePage.currentPage = 1 this.noticePage.currentPage = 1
@@ -371,102 +259,6 @@ export default {
} }
} }
.contact-item {
display: flex;
align-items: center;
padding: 14px 0;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.contact-icon {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(135deg, var(--edu-green-dark) 0%, var(--edu-green-primary) 100%);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
margin-right: 12px;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(15, 25, 86, 0.2);
}
.contact-text {
flex: 1;
min-width: 0;
.label {
font-size: 12px;
color: #909399;
margin-bottom: 2px;
}
a, .el-link {
font-size: 13px;
color: var(--edu-green-primary);
}
a:hover, .el-link:hover {
color: var(--edu-green-dark);
}
span {
font-size: 13px;
color: #606266;
}
}
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
thead {
tr {
background: linear-gradient(135deg, rgba(0, 135, 90, 0.06) 0%, rgba(0, 135, 90, 0.04) 100%);
}
th {
padding: 10px 20px;
text-align: center;
font-weight: 600;
color: var(--edu-green-dark);
border-bottom: 1px solid rgba(0, 135, 90, 0.1);
}
}
tbody {
tr {
transition: background 0.2s;
&:hover {
background: rgba(0, 135, 90, 0.04);
}
td {
padding: 10px 20px;
color: #4a4f6b;
border-bottom: 1px solid #f0f1f7;
.table-icon {
color: var(--edu-green-light);
margin-right: 6px;
}
}
&:last-child td {
border-bottom: none;
}
}
}
}
.notice-list { .notice-list {
.notice-item { .notice-item {
padding: 14px 0; padding: 14px 0;
-2
View File
@@ -91,8 +91,6 @@
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning"
plain
icon="el-icon-close" icon="el-icon-close"
size="mini" size="mini"
@click="handleClose" @click="handleClose"
@@ -34,13 +34,10 @@
<!-- 下面分左右两栏 --> <!-- 下面分左右两栏 -->
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :xs="24" :md="12"> <el-col :xs="24" :md="12">
<el-form-item> <el-form-item label="检查状态">
<template slot="label">
<el-checkbox v-model="searchForm.jcztEnabled">检查状态</el-checkbox>
</template>
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox v-model="searchForm.jcztYtg" :disabled="!searchForm.jcztEnabled">已通过</el-checkbox> <el-checkbox v-model="searchForm.jcztYtg">已通过</el-checkbox>
<el-checkbox v-model="searchForm.jcztWtg" :disabled="!searchForm.jcztEnabled">未通过</el-checkbox> <el-checkbox v-model="searchForm.jcztWtg">未通过</el-checkbox>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="教员姓名"> <el-form-item label="教员姓名">
@@ -51,13 +48,10 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :md="12"> <el-col :xs="24" :md="12">
<el-form-item> <el-form-item label="忽略状态">
<template slot="label">
<el-checkbox v-model="searchForm.hlztEnabled">忽略状态</el-checkbox>
</template>
<div class="checkbox-group"> <div class="checkbox-group">
<el-checkbox v-model="searchForm.hlztYc" :disabled="!searchForm.hlztEnabled">有用</el-checkbox> <el-checkbox v-model="searchForm.hlztYc">有用</el-checkbox>
<el-checkbox v-model="searchForm.hlztYbl" :disabled="!searchForm.hlztEnabled">已被忽略</el-checkbox> <el-checkbox v-model="searchForm.hlztYbl">已被忽略</el-checkbox>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="班次名称"> <el-form-item label="班次名称">
@@ -81,7 +75,7 @@
<el-card shadow="never" class="action-card"> <el-card shadow="never" class="action-card">
<div class="action-bar"> <div class="action-bar">
<div class="bar-left"> <div class="bar-left">
<el-button type="primary" @click="handleDownloadTemplate"> <el-button icon="el-icon-download" @click="handleDownloadTemplate">
课程表数据文件模板下载 课程表数据文件模板下载
</el-button> </el-button>
</div> </div>
@@ -89,16 +83,16 @@
<div class="bar-center"> <div class="bar-center">
<div class="file-area"> <div class="file-area">
<input ref="fileInputRef" type="file" accept=".xlsx,.xls" style="display: none" @change="handleFileChange" /> <input ref="fileInputRef" type="file" accept=".xlsx,.xls" style="display: none" @change="handleFileChange" />
<el-button @click="handleChooseFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleChooseFile">选择文件</el-button>
<span class="file-name">{{ selectedFileName }}</span> <span class="file-name">{{ selectedFileName }}</span>
</div> </div>
</div> </div>
<div class="bar-right"> <div class="bar-right">
<el-button type="primary" @click="handleImportToSystem" :loading="importing">缓存数据导入到系统</el-button> <el-button type="primary" @click="handleImportToSystem" :loading="importing">缓存数据导入到系统</el-button>
<el-button type="primary" @click="handleUploadToCache">上传数据至缓存</el-button> <el-button type="primary" icon="el-icon-upload2" @click="handleUploadToCache">上传数据至缓存</el-button>
<el-button type="primary" @click="handleCheckCache">检查缓存数据</el-button> <el-button @click="handleCheckCache">检查缓存数据</el-button>
<el-button type="danger" @click="handleDeleteCache">删除缓存数据</el-button> <el-button type="danger" plain @click="handleDeleteCache">删除缓存数据</el-button>
</div> </div>
</div> </div>
</el-card> </el-card>
@@ -169,10 +163,8 @@ export default {
searchForm: { searchForm: {
kssj: '', kssj: '',
jssj: '', jssj: '',
jcztEnabled: true,
jcztYtg: false, jcztYtg: false,
jcztWtg: true, jcztWtg: true,
hlztEnabled: true,
hlztYc: false, hlztYc: false,
hlztYbl: true, hlztYbl: true,
jyxm: '', jyxm: '',
@@ -208,10 +200,8 @@ export default {
if (f.bcmc && f.bcmc.trim()) params.bc = f.bcmc.trim() if (f.bcmc && f.bcmc.trim()) params.bc = f.bcmc.trim()
if (f.kmmc && f.kmmc.trim()) params.kcmc = f.kmmc.trim() if (f.kmmc && f.kmmc.trim()) params.kcmc = f.kmmc.trim()
// 检查状态:仅勾选「已通过」或「未通过」其中之一时才按该条件过滤 // 检查状态:仅勾选「已通过」或「未通过」其中之一时才按该条件过滤
if (f.jcztEnabled) {
if (f.jcztYtg && !f.jcztWtg) params.ytgjc = true if (f.jcztYtg && !f.jcztWtg) params.ytgjc = true
else if (!f.jcztYtg && f.jcztWtg) params.ytgjc = false else if (!f.jcztYtg && f.jcztWtg) params.ytgjc = false
}
return params return params
}, },
@@ -50,13 +50,13 @@
<!-- ==================== 2. 工具栏新增 / 导入 / 导出 ==================== --> <!-- ==================== 2. 工具栏新增 / 导入 / 导出 ==================== -->
<div class="toolbar"> <div class="toolbar">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增学员队</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增学员队</el-button>
<el-button type="primary" plain icon="el-icon-download" @click="handleExport">导出 Excel</el-button> <el-button icon="el-icon-download" @click="handleExport">导出 Excel</el-button>
<el-button type="primary" plain icon="el-icon-download" @click="handleDownloadTemplate">模板下载</el-button> <el-button icon="el-icon-download" @click="handleDownloadTemplate">模板下载</el-button>
<div class="file-input"> <div class="file-input">
<input ref="fileInputRef" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" /> <input ref="fileInputRef" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" />
<el-button type="primary" plain icon="el-icon-upload2" @click="handleChooseFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleChooseFile">选择文件</el-button>
<span class="file-name">{{ fileName }}</span> <span class="file-name">{{ fileName }}</span>
<el-button type="primary" plain :loading="uploading" @click="handleUpload">上传数据</el-button> <el-button type="primary" icon="el-icon-upload2" :loading="uploading" @click="handleUpload">上传数据</el-button>
</div> </div>
</div> </div>
@@ -12,12 +12,11 @@
<el-form-item label="姓名"> <el-form-item label="姓名">
<el-input v-model="searchForm.xm" placeholder="请输入姓名" clearable /> <el-input v-model="searchForm.xm" placeholder="请输入姓名" clearable />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item label="性别">
<template slot="label"><el-checkbox v-model="searchForm.xbEnabled">性别</el-checkbox></template> <el-select v-model="searchForm.xb" placeholder="请选择性别" clearable class="full-width">
<el-radio-group v-model="searchForm.xb" :disabled="!searchForm.xbEnabled"> <el-option label="男" value="男" />
<el-radio :label="'男'"></el-radio> <el-option label="女" value="女" />
<el-radio :label="'女'"></el-radio> </el-select>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="证件号码"> <el-form-item label="证件号码">
<el-input v-model="searchForm.zjhm" placeholder="请输入证件号码" clearable /> <el-input v-model="searchForm.zjhm" placeholder="请输入证件号码" clearable />
@@ -63,7 +62,7 @@
</el-row> </el-row>
<div class="search-actions"> <div class="search-actions">
<el-button class="gray-btn" @click="handleSearch">查询</el-button> <el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
</div> </div>
</el-form> </el-form>
</el-card> </el-card>
@@ -224,7 +223,7 @@ export default {
// ==================== 查询条件 ==================== // ==================== 查询条件 ====================
// 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件 // 仅保留后端 XYXX 实体支持的字段:/student-records/list 会按实体字段动态构建查询条件
searchForm: { searchForm: {
xh: '', xm: '', xbEnabled: false, xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '', xh: '', xm: '', xb: '', zjhm: '', zzmm: '', mz: '', jg: '', xw: '',
ybzb: '', sfzh: '', whcd: '', bkbyyx: '', bq: '', lxdh: '', txdz: '' ybzb: '', sfzh: '', whcd: '', bkbyyx: '', bq: '', lxdh: '', txdz: ''
}, },
@@ -312,7 +311,7 @@ export default {
const v = this.searchForm[key] const v = this.searchForm[key]
if (v !== '' && v !== null && v !== undefined) params[key] = v.trim() if (v !== '' && v !== null && v !== undefined) params[key] = v.trim()
}) })
if (this.searchForm.xbEnabled) params.xb = this.searchForm.xb if (this.searchForm.xb) params.xb = this.searchForm.xb
}, },
// ==================== 查询/分页 ==================== // ==================== 查询/分页 ====================
@@ -485,21 +484,5 @@ export default {
width: 100%; width: 100%;
} }
.gray-btn {
height: 28px;
padding: 2px 16px;
font-size: 12px;
background: #f5f5f5;
border: 1px solid #c0c4cc;
color: #333;
border-radius: 2px;
&:hover,
&:focus {
background: #ebebeb;
border-color: #c0c4cc;
color: #333;
}
}
} }
</style> </style>
@@ -412,6 +412,11 @@ export default {
this.fetchList() this.fetchList()
}, },
methods: { methods: {
/** 表格序号(跨页连续) */
fmtXh(index) {
return (this.pageNum - 1) * this.pageSize + index + 1
},
/** 创建空表单 */ /** 创建空表单 */
createEmptyForm() { createEmptyForm() {
return { return {
-2
View File
@@ -80,8 +80,6 @@
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning"
plain
icon="el-icon-close" icon="el-icon-close"
size="mini" size="mini"
@click="handleClose" @click="handleClose"
@@ -49,8 +49,6 @@
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning"
plain
icon="el-icon-close" icon="el-icon-close"
size="mini" size="mini"
@click="handleClose" @click="handleClose"
@@ -11,7 +11,7 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" size="mini" @click="submit">保存</el-button> <el-button type="primary" size="mini" @click="submit">保存</el-button>
<el-button type="danger" size="mini" @click="close">关闭</el-button> <el-button size="mini" @click="close">关闭</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -17,7 +17,7 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" size="mini" @click="submit">保存</el-button> <el-button type="primary" size="mini" @click="submit">保存</el-button>
<el-button type="danger" size="mini" @click="close">关闭</el-button> <el-button size="mini" @click="close">关闭</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -18,7 +18,7 @@
<div class="sce-panel-row"> <div class="sce-panel-row">
<span class="sce-label">事件名称:</span> <span class="sce-label">事件名称:</span>
<el-input v-model="toolbar.eventName" size="small" class="sce-event-input" placeholder="请输入校历事件名称" /> <el-input v-model="toolbar.eventName" size="small" class="sce-event-input" placeholder="请输入校历事件名称" />
<el-checkbox v-model="boldDisplay" class="sce-cb">加粗显示</el-checkbox> <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.schedulable" class="sce-cb">可排课</el-checkbox>
<el-checkbox v-model="toolbar.mainCourse" 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> <el-checkbox v-model="toolbar.remarkShow" class="sce-cb">备注显示</el-checkbox>
@@ -74,18 +74,8 @@
: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': boldDisplay }">{{ getEvent(wIdx, col.colIndex).name }}</span> <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> <span v-else class="sce-date-num">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>
<span
v-if="getEvent(wIdx, col.colIndex) && !getEvent(wIdx, col.colIndex).schedulable"
class="sce-flag sce-flag-noschedule"
title="全校不允许排课"
/>
<span
v-if="getEvent(wIdx, col.colIndex) && getEvent(wIdx, col.colIndex).mainCourse"
class="sce-flag sce-flag-maincourse"
title="正课"
/>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@@ -147,8 +137,6 @@ export default {
totalWeeks: 0, totalWeeks: 0,
dateRangeText: '', dateRangeText: '',
weeks: [], weeks: [],
// 加粗显示:全局开关,勾选后所有有事件的格子事件名加粗(纯前端效果,不持久化)
boldDisplay: false,
// 显示开关(默认不勾选,每天仅显示 1-2/3-4/5-6 三个节次) // 显示开关(默认不勾选,每天仅显示 1-2/3-4/5-6 三个节次)
show78: false, show78: false,
showNight: false, showNight: false,
@@ -156,6 +144,7 @@ export default {
// 工具栏表单 // 工具栏表单
toolbar: { toolbar: {
eventName: '', eventName: '',
bold: false,
schedulable: false, schedulable: false,
mainCourse: false, mainCourse: false,
remarkShow: false, remarkShow: false,
@@ -163,6 +152,8 @@ export default {
}, },
// 事件存储:key = cellKey -> event // 事件存储:key = cellKey -> event
events: {}, events: {},
// 暂存被隐藏节次列上的事件:key = 周-星期-节次 -> event,列再次显示时恢复
hiddenEvents: {},
// 选择集(用数组以保证 Vue2 响应式) // 选择集(用数组以保证 Vue2 响应式)
selectedKeys: [], selectedKeys: [],
// 拖拽状态 // 拖拽状态
@@ -188,6 +179,10 @@ export default {
}) })
}) })
return cols return cols
},
// xqxlb 的年度(nd)为年份(如 2026),由 6 位学期代号(如 202601)截取前 4 位得出
xqxlbNd() {
return Number(String(this.nd).slice(0, 4))
} }
}, },
watch: { watch: {
@@ -197,7 +192,43 @@ export default {
if (val) this.loadSemester() if (val) this.loadSemester()
} }
}, },
visibleColumns() { 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 = [] this.selectedKeys = []
} }
@@ -225,9 +256,9 @@ export default {
this.$message.warning('学期详情获取失败,请确认学期数据') this.$message.warning('学期详情获取失败,请确认学期数据')
}) })
}, },
// 从后端拉取本学期校历假期,渲染到对应时间格(nd 为 6 位学期代号,如 202601 // 从后端拉取本学期校历事件,渲染到对应时间格(年度由 6 位学期代号截取前 4 位
loadXqxlbEvents() { loadXqxlbEvents() {
listXqxlb({ nd: this.nd }).then(res => { listXqxlb({ nd: this.xqxlbNd }).then(res => {
const data = res.data const data = res.data
const list = Array.isArray(data) ? data : (data && data.records) || [] const list = Array.isArray(data) ? data : (data && data.records) || []
return list return list
@@ -235,15 +266,22 @@ export default {
const loaded = {} const loaded = {}
list.forEach(item => { list.forEach(item => {
const pos = this.locateXqxlb(item) const pos = this.locateXqxlb(item)
if (pos) { if (!pos) return
loaded[pos.key] = { const ev = {
bh: item.bh, bh: item.bh,
name: item.jqmc || '', name: item.jqmc || '',
bold: !!item.jc,
schedulable: !!item.kpk, schedulable: !!item.kpk,
mainCourse: !!item.zdpk, mainCourse: !!item.zdpk,
remarkShow: !!item.bzxs, remarkShow: !!item.bzxs,
remark: item.bz || '' 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
} }
}) })
// 合并到现有格子(后端数据覆盖已有状态) // 合并到现有格子(后端数据覆盖已有状态)
@@ -252,7 +290,7 @@ export default {
this.$message.warning('校历事件加载失败') this.$message.warning('校历事件加载失败')
}) })
}, },
// 根据假期记录反推时间格 keyjqsj 日期 + courseClass 节次) // 根据假期记录反推时间格位置jqsj 日期 + courseClass 节次),与列是否可见无关
locateXqxlb(item) { locateXqxlb(item) {
if (!this.startDate || !item.jqsj) return null if (!this.startDate || !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, '/'))
@@ -263,9 +301,7 @@ export default {
const dayIndex = offset % 7 const dayIndex = offset % 7
const slotKey = this.courseClassToSlotKey(item.courseClass) const slotKey = this.courseClassToSlotKey(item.courseClass)
if (slotKey === null) return null if (slotKey === null) return null
const colIndex = this.colIndexOf(dayIndex, slotKey) return { wIdx, dayIndex, slotKey }
if (colIndex < 0) return null
return { key: this.cellKey(wIdx, colIndex) }
}, },
// 后端 courseClass 节次范围 -> 前端节次 key // 后端 courseClass 节次范围 -> 前端节次 key
courseClassToSlotKey(courseClass) { courseClassToSlotKey(courseClass) {
@@ -307,6 +343,10 @@ export default {
cellKey(wIdx, colIndex) { cellKey(wIdx, colIndex) {
return 'w' + wIdx + '-c' + colIndex return 'w' + wIdx + '-c' + colIndex
}, },
// 稳定的单元格身份:不随列显隐变化的周-星期-节次
cellStableKey(wIdx, dayIndex, slotKey) {
return wIdx + '-' + dayIndex + '-' + slotKey
},
getEvent(wIdx, colIndex) { getEvent(wIdx, colIndex) {
return this.events[this.cellKey(wIdx, colIndex)] || null return this.events[this.cellKey(wIdx, colIndex)] || null
}, },
@@ -437,6 +477,7 @@ export default {
this.$set(this.events, key, { this.$set(this.events, key, {
bh: prev ? prev.bh : undefined, bh: prev ? prev.bh : undefined,
name: name, name: name,
bold: this.toolbar.bold,
schedulable: this.toolbar.schedulable, schedulable: this.toolbar.schedulable,
mainCourse: this.toolbar.mainCourse, mainCourse: this.toolbar.mainCourse,
remarkShow: this.toolbar.remarkShow, remarkShow: this.toolbar.remarkShow,
@@ -467,6 +508,7 @@ export default {
return return
} }
this.toolbar.eventName = target.name this.toolbar.eventName = target.name
this.toolbar.bold = !!target.bold
this.toolbar.schedulable = !!target.schedulable this.toolbar.schedulable = !!target.schedulable
this.toolbar.mainCourse = !!target.mainCourse this.toolbar.mainCourse = !!target.mainCourse
this.toolbar.remarkShow = !!target.remarkShow this.toolbar.remarkShow = !!target.remarkShow
@@ -477,6 +519,7 @@ export default {
const ev = this.getEvent(wIdx, col.colIndex) const ev = this.getEvent(wIdx, col.colIndex)
if (ev) { if (ev) {
this.toolbar.eventName = ev.name this.toolbar.eventName = ev.name
this.toolbar.bold = !!ev.bold
this.toolbar.schedulable = !!ev.schedulable this.toolbar.schedulable = !!ev.schedulable
this.toolbar.mainCourse = !!ev.mainCourse this.toolbar.mainCourse = !!ev.mainCourse
this.toolbar.remarkShow = !!ev.remarkShow this.toolbar.remarkShow = !!ev.remarkShow
@@ -489,6 +532,7 @@ export default {
this.selectedKeys = [] this.selectedKeys = []
this.absorbPreview = '' this.absorbPreview = ''
this.events = {} this.events = {}
this.hiddenEvents = {}
this.loadXqxlbEvents() this.loadXqxlbEvents()
this.$message.info('已刷新') this.$message.info('已刷新')
}, },
@@ -526,10 +570,10 @@ export default {
return { return {
delFlag: 0, delFlag: 0,
bh: ev.bh || undefined, bh: ev.bh || undefined,
nd: this.nd, nd: this.xqxlbNd,
jqsj: fmtDate(d), jqsj: fmtDate(d),
jqmc: ev.name || '', jqmc: ev.name || '',
jc: null, jc: !!ev.bold,
bz: ev.remark || null, bz: ev.remark || null,
kpk: !!ev.schedulable, kpk: !!ev.schedulable,
bzxs: !!ev.remarkShow, bzxs: !!ev.remarkShow,
@@ -694,16 +738,6 @@ export default {
background: #d4ecdf !important; background: #d4ecdf !important;
} }
} }
/* 状态标记小方块 */
.sce-flag {
position: absolute;
width: 7px;
height: 7px;
border-radius: 1px;
}
.sce-flag-noschedule { left: 2px; top: 2px; background: #909399; }
.sce-flag-maincourse { right: 2px; top: 2px; background: #409eff; }
} }
.sce-status { .sce-status {
@@ -42,16 +42,6 @@
> >
<template v-if="getEvent(wIdx, col.colIndex)"> <template v-if="getEvent(wIdx, col.colIndex)">
<span class="cal-event-name">{{ getEvent(wIdx, col.colIndex).name }}</span> <span class="cal-event-name">{{ getEvent(wIdx, col.colIndex).name }}</span>
<span
v-if="!getEvent(wIdx, col.colIndex).schedulable"
class="cal-flag cal-flag-noschedule"
title="全校不允许排课"
/>
<span
v-if="getEvent(wIdx, col.colIndex).mainCourse"
class="cal-flag cal-flag-maincourse"
title="正课"
/>
</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>
</td> </td>
@@ -115,8 +105,8 @@ export default {
totalWeeks: 0, totalWeeks: 0,
dateRangeText: '', dateRangeText: '',
weeks: [], weeks: [],
// 显示控制:默认勾选显示日期;节次全部展示 // 显示控制:默认勾选显示日期;节次全部展示
showDate: true, showDate: false,
// 事件存储:key = cellKey -> event // 事件存储:key = cellKey -> event
events: {}, events: {},
loading: false loading: false
@@ -199,9 +189,9 @@ export default {
this.$message.warning('学期详情获取失败,请确认学期数据') this.$message.warning('学期详情获取失败,请确认学期数据')
}) })
}, },
// 从后端拉取本学期校历假期,渲染到对应时间格(nd 为 6 位学期代号,如 202601 // 从后端拉取本学期校历事件,渲染到对应时间格(年度为 6 位学期代号截取前 4 位
loadXqxlbEvents() { loadXqxlbEvents() {
listXqxlb({ nd: this.nd }).then(res => { listXqxlb({ nd: String(this.nd).slice(0, 4) }).then(res => {
const data = res.data const data = res.data
const list = Array.isArray(data) ? data : (data && data.records) || [] const list = Array.isArray(data) ? data : (data && data.records) || []
const loaded = {} const loaded = {}
@@ -485,16 +475,6 @@ export default {
&.has-event .cal-event-name { color: #00663e; font-weight: 500; } &.has-event .cal-event-name { color: #00663e; font-weight: 500; }
&.no-schedule { background: #fde2e2; } &.no-schedule { background: #fde2e2; }
} }
/* 状态标记小方块 */
.cal-flag {
position: absolute;
width: 7px;
height: 7px;
border-radius: 1px;
}
.cal-flag-noschedule { left: 2px; top: 2px; background: #909399; }
.cal-flag-maincourse { right: 2px; top: 2px; background: #409eff; }
} }
/* 底部状态栏 */ /* 底部状态栏 */
@@ -5,109 +5,111 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新添</el-button> <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新添</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.8">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">编辑</el-button> <el-button type="success" plain icon="el-icon-date" size="mini" :disabled="!currentSemester"
@click="handleEditCalendar">
编辑校历
</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">删除</el-button> <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">
</el-col> 批量删除
<el-col :span="1.5"> </el-button>
<el-button type="warning" plain icon="el-icon-date" size="mini" :disabled="single" @click="handleEditCalendar">编辑校历</el-button>
</el-col> </el-col>
</el-row> </el-row>
<!-- 数据表格 --> <!-- 数据表格 -->
<el-table <el-table v-loading="loading" :data="semesterList" border :height="tableHeight" highlight-current-row
v-loading="loading" @current-change="handleCurrentChange" @selection-change="handleSelectionChange">
:data="semesterList"
border
:height="tableHeight"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" align="center" width="50" /> <el-table-column type="selection" align="center" width="50" />
<el-table-column label="学期名称" align="center" min-width="190"> <el-table-column label="学期名称" align="center" width="250">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ getSemesterName(scope.row.nd) }}</span> <span>{{ getSemesterName(scope.row.nd) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="当前" align="center" width="70"> <el-table-column label="当前" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag v-if="scope.row.dqxq" type="success" size="mini">当前</el-tag> <el-tag v-if="scope.row.dqxq" type="success" size="mini">当前</el-tag>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="开学日期" align="center" prop="kxrq" min-width="130"> <el-table-column label="开学日期" align="center" prop="kxrq" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ formatDate(scope.row.kxrq) }}</span> <span>{{ formatDate(scope.row.kxrq) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="结束日期" align="center" prop="jsrq" min-width="130"> <el-table-column label="结束日期" align="center" prop="jsrq" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ formatDate(scope.row.jsrq) }}</span> <span>{{ formatDate(scope.row.jsrq) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="周数" align="center" prop="sdzs" width="70" /> <el-table-column label="周数" align="center" prop="sdzs" width="100" />
<el-table-column label="调课不审批" align="center" width="100"> <el-table-column label="调课不审批" align="center" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="scope.row.tkbsp ? 'primary' : 'info'" size="mini">{{ scope.row.tkbsp ? '是' : '否' }}</el-tag> <el-tag :type="scope.row.tkbsp ? 'primary' : 'info'" size="mini">{{ scope.row.tkbsp ? '是' : '否' }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="禁止调课" align="center" width="90"> <el-table-column label="禁止调课" align="center" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="scope.row.jztk ? 'danger' : 'info'" size="mini">{{ scope.row.jztk ? '是' : '否' }}</el-tag> <el-tag :type="scope.row.jztk ? 'danger' : 'info'" size="mini">{{ scope.row.jztk ? '是' : '否' }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="终结成绩定及格" align="center" width="120"> <el-table-column label="终结成绩定及格" align="center" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="scope.row.zjcjdjg ? 'primary' : 'info'" size="mini">{{ scope.row.zjcjdjg ? '是' : '否' }}</el-tag> <el-tag :type="scope.row.zjcjdjg ? 'primary' : 'info'" size="mini">{{ scope.row.zjcjdjg ? '是' : '否'
}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="课时系数方案" align="center" min-width="120"> <el-table-column label="课时系数方案" align="center" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ getCoefficientLabel(scope.row.ksxsfabh) }}</span> <span>{{ getCoefficientLabel(scope.row.ksxsfabh) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="锁定时长" align="center" min-width="100"> <el-table-column label="锁定时长" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.sdjldw || '-' }}</span> <span>{{ scope.row.sdjldw || '-' }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" fixed="right" class-name="table-action-column">
<template slot-scope="scope">
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleUpdate(scope.row)">编辑</el-button>
<el-button type="text" size="mini" icon="el-icon-delete" class="text-danger"
@click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table> </el-table>
<pagination <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
v-show="total > 0" @pagination="getList" />
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 学期信息弹窗 --> <!-- 学期信息弹窗 -->
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body class="semester-dialog"> <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body class="semester-dialog">
<el-form ref="form" class="semester-dialog-form" :model="form" :rules="rules" label-width="96px" label-position="right"> <el-alert v-if="isSemesterNameDuplicated()" class="semester-dup-alert" type="warning" show-icon
title="该学期已存在,不能重复添加" :closable="false" />
<el-form ref="form" class="semester-dialog-form" :model="form" :rules="rules" label-width="96px"
label-position="right">
<el-row :gutter="20" class="semester-dialog-body"> <el-row :gutter="20" class="semester-dialog-body">
<!-- 左侧表单区 --> <!-- 左侧表单区 -->
<el-col :span="15" class="semester-form-col"> <el-col :span="15" class="semester-form-col">
<el-form-item label="学期名称"> <el-form-item label="学期名称">
<el-input <el-input :value="getSemesterName(buildNd(form.xn, form.xq))" readonly placeholder="请在下方选择年份和学期类型"
:value="getSemesterName(buildNd(form.xn, form.xq))" prefix-icon="el-icon-office-building" />
readonly
placeholder="由年份+学期类型自动拼接"
prefix-icon="el-icon-office-building"
/>
</el-form-item> </el-form-item>
<el-row :gutter="14"> <el-row :gutter="14">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="年份" prop="xn"> <el-form-item label="年份" prop="xn">
<el-select v-model="form.xn" placeholder="请选择年份" :disabled="!isAdd" style="width: 100%"> <el-select v-model="form.xn" placeholder="请选择年份" :disabled="!isAdd" style="width: 100%"
@change="checkSemesterNameUnique">
<el-option v-for="item in yearOptions" :key="item" :label="item + '年'" :value="item" /> <el-option v-for="item in yearOptions" :key="item" :label="item + '年'" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="学期类型" prop="xq"> <el-form-item label="学期类型" prop="xq">
<el-select v-model="form.xq" placeholder="请选择学期类型" :disabled="!isAdd" style="width: 100%"> <el-select v-model="form.xq" placeholder="请选择学期类型" :disabled="!isAdd" style="width: 100%"
<el-option v-for="item in semesterOptions" :key="item.value" :label="item.label" :value="item.value" /> @change="checkSemesterNameUnique">
<el-option v-for="item in semesterOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -115,44 +117,37 @@
<el-row :gutter="14"> <el-row :gutter="14">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="开学日期" prop="kxrq"> <el-form-item label="开学日期" prop="kxrq">
<el-date-picker <el-date-picker v-model="form.kxrq" type="date" placeholder="开学日期" value-format="yyyy-MM-dd"
v-model="form.kxrq" style="width: 100%" />
type="date"
placeholder="开学日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="结束日期" prop="jsrq"> <el-form-item label="结束日期" prop="jsrq">
<el-date-picker <el-date-picker v-model="form.jsrq" type="date" placeholder="结束日期" value-format="yyyy-MM-dd"
v-model="form.jsrq" style="width: 100%" />
type="date"
placeholder="结束日期"
value-format="yyyy-MM-dd"
style="width: 100%"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="14"> <el-row :gutter="14">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="学期周数" prop="sdzs"> <el-form-item label="学期周数" prop="sdzs">
<el-input-number v-model="form.sdzs" :min="1" :max="60" controls-position="right" style="width: 100%" /> <el-input-number v-model="form.sdzs" :min="1" :max="60" controls-position="right"
style="width: 100%" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="课时系数方案" prop="ksxsfabh"> <el-form-item label="课时系数方案" prop="ksxsfabh">
<el-select v-model="form.ksxsfabh" placeholder="请选择" clearable style="width: 100%"> <el-select v-model="form.ksxsfabh" placeholder="请选择" clearable style="width: 100%">
<el-option v-for="item in coefficientOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in coefficientOptions" :key="item.value" :label="item.label"
:value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-form-item label="锁定时长"> <el-form-item label="锁定时长">
<div class="lock-group"> <div class="lock-group">
<el-input-number v-model="form.lockValue" :min="0" :max="99" controls-position="right" style="width: 120px" /> <el-input-number v-model="form.lockValue" :min="0" :max="99" controls-position="right"
style="width: 120px" />
<el-radio-group v-model="form.lockUnit" class="lock-unit" style="margin-left: 28px"> <el-radio-group v-model="form.lockUnit" class="lock-unit" style="margin-left: 28px">
<el-radio label="周"></el-radio> <el-radio label="周"></el-radio>
<el-radio label="月"></el-radio> <el-radio label="月"></el-radio>
@@ -178,7 +173,9 @@
<div class="switch-item"> <div class="switch-item">
<el-checkbox v-model="form.tkbsp">调课不审批</el-checkbox> <el-checkbox v-model="form.tkbsp">调课不审批</el-checkbox>
<div class="switch-tip">设定调课不审批在教学信息系统中调课时如果只是更改教员或更改授课地点调课申请会立即生效而对于改变授课地点调课申请会立即生效而对于改变授课时间增加或减少授课教员的调课申请依然不受该设置影响依然需要逐级审批后才能生效</div> <div class="switch-tip">
设定调课不审批在教学信息系统中调课时如果只是更改教员或更改授课地点调课申请会立即生效而对于改变授课地点调课申请会立即生效而对于改变授课时间增加或减少授课教员的调课申请依然不受该设置影响依然需要逐级审批后才能生效
</div>
</div> </div>
<div class="switch-item"> <div class="switch-item">
@@ -219,6 +216,8 @@ export default {
semesterList: [], semesterList: [],
// 选中的学期数组 // 选中的学期数组
ids: [], ids: [],
// 当前点击选中的学期
currentSemester: null,
// 非单个禁用 // 非单个禁用
single: true, single: true,
// 非多个禁用 // 非多个禁用
@@ -310,6 +309,17 @@ export default {
const s = String(nd) const s = String(nd)
return { xn: s.slice(0, 4), xq: s.slice(4) } return { xn: s.slice(0, 4), xq: s.slice(4) }
}, },
/** 新增时校验学期名称(年份+学期类型拼接)是否已存在于表格 */
isSemesterNameDuplicated() {
if (!this.isAdd) return false
const nd = this.buildNd(this.form.xn, this.form.xq)
if (!nd) return false
return this.semesterList.some(item => String(item.nd) === String(nd))
},
/** 年份/学期类型切换时实时刷新顶部重复提示 */
checkSemesterNameUnique() {
this.$forceUpdate()
},
/** 课时系数方案编号 -> 名称 */ /** 课时系数方案编号 -> 名称 */
getCoefficientLabel(value) { getCoefficientLabel(value) {
if (!value && value !== 0) return '-' if (!value && value !== 0) return '-'
@@ -341,6 +351,10 @@ export default {
this.single = selection.length !== 1 this.single = selection.length !== 1
this.multiple = !selection.length this.multiple = !selection.length
}, },
/** 单击行选中变化:记录当前选中的学期,用于启用「编辑校历」 */
handleCurrentChange(currentRow) {
this.currentSemester = currentRow || null
},
/** 组装提交数据 */ /** 组装提交数据 */
buildPayload(form) { buildPayload(form) {
const lockValue = form.lockValue !== undefined && form.lockValue !== null ? form.lockValue : '' const lockValue = form.lockValue !== undefined && form.lockValue !== null ? form.lockValue : ''
@@ -370,11 +384,12 @@ export default {
this.title = "学期信息 - 新增" this.title = "学期信息 - 新增"
}, },
/** 编辑按钮 */ /** 编辑按钮 */
handleUpdate() { handleUpdate(row) {
if (this.ids.length !== 1) return const semesterId = row && row.nd ? row.nd : this.ids[0]
if (!semesterId) return
this.reset() this.reset()
this.isAdd = false this.isAdd = false
getSemester(this.ids[0]).then(response => { getSemester(semesterId).then(response => {
const data = response.data || {} const data = response.data || {}
const { xn, xq } = this.parseNd(data.nd) const { xn, xq } = this.parseNd(data.nd)
// 解析锁定时长(如 "2周" / "1月" / "1" // 解析锁定时长(如 "2周" / "1月" / "1"
@@ -403,32 +418,37 @@ export default {
} }
this.open = true this.open = true
this.title = "学期信息 - 编辑" this.title = "学期信息 - 编辑"
}).catch(() => {}) }).catch(() => { })
}, },
/** 编辑校历按钮 */ /** 编辑校历按钮:对当前选中的学期编辑校历 */
handleEditCalendar() { handleEditCalendar() {
if (this.ids.length !== 1) return const row = this.currentSemester
const nd = this.ids[0] if (!row || !row.nd) return
this.$router.push({ this.$router.push({
path: '/teachBusiness/semester/semesterCalendar', path: '/teachBusiness/semester/semesterCalendar',
query: { nd: nd, name: this.getSemesterName(nd) } query: { nd: row.nd, name: this.getSemesterName(row.nd) }
}) })
}, },
/** 删除按钮 */ /** 删除按钮 */
handleDelete() { handleDelete(row) {
if (!this.ids.length) return const semesterIds = row && row.nd ? [row.nd] : this.ids
const names = this.ids.map(nd => this.getSemesterName(nd)).join('、') if (!semesterIds.length) return
const names = semesterIds.map(nd => this.getSemesterName(nd)).join('、')
this.$modal.confirm('确认删除学期【' + names + '】吗?').then(() => { this.$modal.confirm('确认删除学期【' + names + '】吗?').then(() => {
// 批量删除:逐个调用 // 批量删除:逐个调用
const delList = this.ids.map(nd => delSemester(nd)) const delList = semesterIds.map(nd => delSemester(nd))
return Promise.all(delList) return Promise.all(delList)
}).then(() => { }).then(() => {
this.getList() this.getList()
this.$modal.msgSuccess("删除成功") this.$modal.msgSuccess("删除成功")
}).catch(() => {}) }).catch(() => { })
}, },
/** 提交表单 */ /** 提交表单 */
submitForm() { submitForm() {
if (this.isSemesterNameDuplicated()) {
this.$modal.msgWarning("该学期已存在,不能重复添加")
return
}
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
const payload = this.buildPayload(this.form) const payload = this.buildPayload(this.form)
@@ -446,7 +466,7 @@ export default {
this.$modal.msgSuccess(this.isAdd ? "新增成功" : "修改成功") this.$modal.msgSuccess(this.isAdd ? "新增成功" : "修改成功")
this.open = false this.open = false
this.getList() this.getList()
}).catch(() => {}) }).catch(() => { })
} }
}) })
}, },
@@ -506,6 +526,11 @@ export default {
display: block; display: block;
} }
/* 顶部学期重复提示与表单间距 */
.semester-dup-alert {
margin-bottom: 16px;
}
.semester-form-col { .semester-form-col {
padding-right: 4px; padding-right: 4px;
} }
@@ -33,7 +33,13 @@
<div class="list-title">教学大纲列表</div> <div class="list-title">教学大纲列表</div>
<div class="list-actions"> <div class="list-actions">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
<el-button type="danger" icon="el-icon-delete" :disabled="!selection.length" @click="handleBatchDelete">删除所选</el-button> <el-button
type="danger"
plain
icon="el-icon-delete"
:disabled="!selection.length"
@click="handleBatchDelete"
>删除所选</el-button>
<el-button icon="el-icon-download" @click="handleDownload">下载</el-button> <el-button icon="el-icon-download" @click="handleDownload">下载</el-button>
</div> </div>
</div> </div>
@@ -68,7 +74,7 @@
<el-table-column label="停用时间" width="150" align="center"> <el-table-column label="停用时间" width="150" align="center">
<template slot-scope="scope">{{ fmtDateTime(scope.row.tysj) }}</template> <template slot-scope="scope">{{ fmtDateTime(scope.row.tysj) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="140" align="center" fixed="right"> <el-table-column label="操作" width="160" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button> <el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button> <el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button>
@@ -94,13 +100,41 @@
<el-form ref="syllabusForm" :model="dialog.form" :rules="rules" label-width="130px"> <el-form ref="syllabusForm" :model="dialog.form" :rules="rules" label-width="130px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="专业代号" prop="zydh"> <el-form-item label="专业" prop="zydh">
<el-input v-model="dialog.form.zydh" placeholder="请输入专业代号" /> <el-select
v-model="dialog.form.zydh"
filterable
clearable
placeholder="请选择专业"
class="w-full"
:loading="referenceDataLoading"
>
<el-option
v-for="item in majorOptions"
:key="item.zydh"
:label="item.zymc"
:value="item.zydh"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="课编号" prop="kbh"> <el-form-item label="课" prop="kbh">
<el-input v-model="dialog.form.kbh" placeholder="请输入课编号" /> <el-select
v-model="dialog.form.kbh"
filterable
clearable
placeholder="请选择课程"
class="w-full"
:loading="referenceDataLoading"
>
<el-option
v-for="item in subjectOptions"
:key="item.kbh"
:label="item.kmc"
:value="item.kbh"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -110,7 +144,21 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="课类型" prop="klx"> <el-form-item label="课类型" prop="klx">
<el-input v-model="dialog.form.klx" placeholder="请输入课类型" /> <el-select
v-model="dialog.form.klx"
filterable
clearable
placeholder="请选择课类型"
class="w-full"
:loading="referenceDataLoading"
>
<el-option
v-for="item in courseTypeOptions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -120,10 +168,10 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="停用" prop="ty"> <el-form-item label="停用" prop="ty">
<el-select v-model="dialog.form.ty" class="w-full"> <el-radio-group v-model="dialog.form.ty">
<el-option :value="0" label="正常" /> <el-radio :label="0"></el-radio>
<el-option :value="1" label="停用" /> <el-radio :label="1"></el-radio>
</el-select> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -152,8 +200,22 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="教研室代号"> <el-form-item label="教研室">
<el-input v-model="dialog.form.jysdh" placeholder="请输入教研室代号" /> <el-select
v-model="dialog.form.jysdh"
filterable
clearable
placeholder="请选择教研室"
class="w-full"
:loading="referenceDataLoading"
>
<el-option
v-for="item in officeOptions"
:key="item.jysdh"
:label="item.jysmc"
:value="item.jysdh"
/>
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -219,6 +281,13 @@ import {
listSyllabus, listSyllabus,
listSyllabusByZydhAndTy listSyllabusByZydhAndTy
} from '@/api/teachBusiness/syllabus' } from '@/api/teachBusiness/syllabus'
import { listMajor } from '@/api/subjectMajor/major'
import { listKb } from '@/api/teachOffice/kb'
import { listOffice } from '@/api/teachOffice/office'
import { getDicts } from '@/api/system/dict/data'
const REFERENCE_DATA_PAGE_SIZE = 10000
const COURSE_TYPE_DICT_CODE = 'course_type'
export default { export default {
name: 'SyllabusIndex', name: 'SyllabusIndex',
@@ -234,6 +303,11 @@ export default {
pageNum: 1, pageNum: 1,
pageSize: 20, pageSize: 20,
selection: [], selection: [],
referenceDataLoading: false,
majorOptions: [],
subjectOptions: [],
courseTypeOptions: [],
officeOptions: [],
dialog: { dialog: {
visible: false, visible: false,
title: '', title: '',
@@ -241,10 +315,10 @@ export default {
form: this.createEmptyForm() form: this.createEmptyForm()
}, },
rules: { rules: {
zydh: [{ required: true, message: '请输入专业代号', trigger: 'blur' }], zydh: [{ required: true, message: '请选择专业', trigger: 'change' }],
kbh: [{ required: true, message: '请输入课编号', trigger: 'blur' }], kbh: [{ required: true, message: '请选择课程', trigger: 'change' }],
xqdc: [{ required: true, message: '请输入学期第次', trigger: 'blur' }], xqdc: [{ required: true, message: '请输入学期第次', trigger: 'blur' }],
klx: [{ required: true, message: '请输入课类型', trigger: 'blur' }], klx: [{ required: true, message: '请选择课类型', trigger: 'change' }],
xs: [{ required: true, message: '请输入学时', trigger: 'blur' }], xs: [{ required: true, message: '请输入学时', trigger: 'blur' }],
ty: [{ required: true, message: '请选择停用标识', trigger: 'change' }] ty: [{ required: true, message: '请选择停用标识', trigger: 'change' }]
} }
@@ -258,8 +332,51 @@ export default {
}, },
created() { created() {
this.fetchList() this.fetchList()
this.loadReferenceData()
}, },
methods: { methods: {
loadReferenceData() {
this.referenceDataLoading = true
const query = { pageNum: 1, pageSize: REFERENCE_DATA_PAGE_SIZE }
const requests = [
listMajor(query),
listKb(query),
listOffice(query),
getDicts(COURSE_TYPE_DICT_CODE)
].map(request => {
return request
.then(response => this.getResponseRecords(response))
.catch(() => [])
})
Promise.all(requests).then(([majors, subjects, offices, courseTypes]) => {
this.majorOptions = this.getUniqueOptions(majors, 'zydh', 'zymc')
this.subjectOptions = this.getUniqueOptions(subjects, 'kbh', 'kmc')
this.officeOptions = this.getUniqueOptions(offices, 'jysdh', 'jysmc')
this.courseTypeOptions = this.getUniqueOptions(courseTypes, 'dictValue', 'dictLabel')
}).finally(() => {
this.referenceDataLoading = false
})
},
getResponseRecords(response) {
const data = response.data || {}
return Array.isArray(data) ? data : data.records || []
},
getUniqueOptions(items, valueKey, labelKey) {
const values = new Set()
return items.filter(item => {
const value = item[valueKey]
const label = item[labelKey]
if (!value || !label || values.has(value)) {
return false
}
values.add(value)
return true
})
},
/* ---------- 列表加载 ---------- */ /* ---------- 列表加载 ---------- */
fetchList() { fetchList() {
this.loading = true this.loading = true
@@ -48,7 +48,7 @@
</el-col> </el-col>
</el-row> </el-row>
<div class="search-actions"> <div class="search-actions">
<el-button class="gray-btn" @click="handleQuery">查询</el-button> <el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
</div> </div>
</el-form> </el-form>
</el-card> </el-card>
@@ -60,21 +60,21 @@
<span>无数据</span> <span>无数据</span>
</template> </template>
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="bh" label="编号" width="200" align="center" show-overflow-tooltip /> <el-table-column prop="bh" label="编号" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="rwmc" label="任务名称" min-width="160" align="left" header-align="center" show-overflow-tooltip /> <el-table-column prop="rwmc" label="任务名称" width="250" align="center" show-overflow-tooltip />
<el-table-column prop="nd" label="年度" width="90" align="center" /> <el-table-column prop="nd" label="年度" width="150" align="center" />
<el-table-column label="状态" width="100" align="center"> <el-table-column label="状态" width="100" align="center">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-tag :type="row.zt === '发布' ? 'success' : 'info'" size="small"> <el-tag :type="row.zt === '发布' ? 'success' : 'info'" size="small">
{{ row.zt || '-' }} {{ row.zt || '-' }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="fbsj" label="发布时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="fbsj" label="发布时间" width="200" align="center" :formatter="fmtDateTime" />
<el-table-column prop="jssj" label="结束时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="jssj" label="结束时间" width="200" align="center" :formatter="fmtDateTime" />
<el-table-column prop="cjsj" label="创建时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="cjsj" label="创建时间" width="200" align="center" :formatter="fmtDateTime" />
<el-table-column prop="jcxqscsj" label="教材需求生成时间" width="170" align="center" :formatter="fmtDateTime" /> <el-table-column prop="jcxqscsj" label="教材需求生成时间" width="200" align="center" :formatter="fmtDateTime" />
<el-table-column label="操作" width="80" align="center" fixed="right"> <el-table-column label="操作" align="center" fixed="right">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-button type="text" size="small" @click="handleDetail(row)">详情</el-button> <el-button type="text" size="small" @click="handleDetail(row)">详情</el-button>
</template> </template>
@@ -113,7 +113,7 @@
</el-descriptions> </el-descriptions>
<div v-else v-loading="detailLoading" class="detail-empty">加载中...</div> <div v-else v-loading="detailLoading" class="detail-empty">加载中...</div>
<div slot="footer"> <div slot="footer">
<el-button type="primary" @click="detailVisible = false">关闭</el-button> <el-button @click="detailVisible = false">关闭</el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@@ -142,7 +142,7 @@ export default {
yearOptions: [], yearOptions: [],
statusOptions: [ statusOptions: [
{ label: '未发布', value: '未发布' }, { label: '未发布', value: '未发布' },
{ label: '发布', value: '发布' } { label: '发布', value: '发布' }
], ],
// ==================== 2. 表格数据 ==================== // ==================== 2. 表格数据 ====================
@@ -293,20 +293,4 @@ export default {
} }
} }
.gray-btn {
height: 28px;
padding: 2px 16px;
font-size: 12px;
background: #f5f5f5;
border: 1px solid #c0c4cc;
color: #333;
border-radius: 2px;
&:hover,
&:focus {
background: #ebebeb;
border-color: #c0c4cc;
color: #333;
}
}
</style> </style>
@@ -1,236 +1,126 @@
<template> <template>
<div class="app-container timetable-page"> <div class="app-container timetable-page">
<el-tabs v-model="activeTab" class="timetable-tabs"> <el-tabs v-model="activeTab" class="timetable-tabs">
<!-- 今日 --> <!-- ==================== 今日教学实施计划 ==================== -->
<el-tab-pane label="今日" name="today"> <el-tab-pane label="今日教学实施计划" name="today">
<div class="tab-body"> <div class="tab-body">
<!-- 日期导航 --> <div class="date-header">
<div class="nav-header">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevDay">前一天</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handlePrevDay">前一天</el-link>
<div class="nav-title">{{ todayTitle }}</div> <div class="date-title">{{ dateTitle }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextDay">后一天</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handleNextDay">后一天</el-link>
</div> </div>
<!-- 今日表格 -->
<div class="table-card"> <div class="table-card">
<el-table :data="todayList" v-loading="todayLoading" stripe border> <el-table :data="todayData" v-loading="loading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip> <el-table-column label="上课时间" width="130" align="center">
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template> <template #default="{ row }">{{ formatJc(row.jc) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" /> <el-table-column prop="zrdw" label="责任单位" width="110" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center"> <el-table-column prop="bc" label="班次" width="120" align="center" show-overflow-tooltip />
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template> <el-table-column prop="skjy" label="教员" width="90" align="center" />
<el-table-column label="场地" width="140" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip> <el-table-column label="教学内容方法" min-width="160" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template> <template #default="{ row }">{{ row.jxnrff || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="填写状态" width="100" align="center"> <el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
<template slot-scope="scope"> <template #default="{ row }">{{ row.jybz || '-' }}</template>
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-empty v-show="!todayLoading && !todayList.length" description="当日暂无教学计划数据" /> <el-empty v-show="!loading && !todayData.length" description="暂无教学计划数据" />
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- 本周 --> <!-- ==================== 本周教学实施计划 ==================== -->
<el-tab-pane label="本周" name="week"> <el-tab-pane label="本周教学实施计划" name="week">
<div class="tab-body"> <div class="tab-body">
<!-- 周次导航 --> <div class="week-header">
<div class="nav-header">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek">上一周</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek">上一周</el-link>
<div class="nav-title">{{ weekTitle }}</div> <div class="week-title">{{ weekRangeText }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek">下一周</el-link> <el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek">下一周</el-link>
</div> </div>
<!-- 本周表格 -->
<div class="table-card"> <div class="table-card">
<el-table :data="weekList" v-loading="weekLoading" stripe border> <el-table :data="weekData" v-loading="loading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip> <el-table-column label="上课时间" width="170" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template> <template #default="{ row }">{{ row.sjsj || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程" min-width="130" align="center" show-overflow-tooltip />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" /> <el-table-column prop="zrdw" label="责任单位" width="100" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center"> <el-table-column prop="bc" label="班次" width="130" align="center" show-overflow-tooltip />
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template> <el-table-column prop="skjy" label="教员" width="90" align="center" />
<el-table-column label="场地" width="140" align="center" show-overflow-tooltip>
<template #default="{ row }">{{ row.jxcd || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip> <el-table-column label="教学内容方法" min-width="150" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template> <template #default="{ row }">{{ row.jxnrff || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="填写状态" width="100" align="center"> <el-table-column prop="jybz" label="备注" width="100" show-overflow-tooltip header-align="center">
<template slot-scope="scope"> <template #default="{ row }">{{ row.jybz || '-' }}</template>
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-empty v-show="!weekLoading && !weekList.length" description="本周暂无教学计划数据" /> <el-empty v-show="!loading && !weekData.length" description="本周暂无教学计划数据" />
<pagination
v-show="weekTotal > 0"
:total="weekTotal"
:page.sync="weekQuery.pageNum"
:limit.sync="weekQuery.pageSize"
@pagination="getWeekList"
/>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<!-- 三实 --> <!-- ==================== 教学班次教学实施计划 ==================== -->
<el-tab-pane label="三实" name="practice"> <el-tab-pane label="教学班次教学实施计划" name="shift">
<div class="tab-body"> <div class="tab-body">
<!-- 周次导航 --> <!-- 选择条件 -->
<div class="nav-header"> <div class="search-card">
<el-link type="primary" :underline="false" class="nav-link" @click="handlePrevWeek3">上一周</el-link> <el-form :model="searchForm" inline class="search-form">
<div class="nav-title">{{ practiceTitle }}</div>
<el-link type="primary" :underline="false" class="nav-link" @click="handleNextWeek3">下一周</el-link>
</div>
<el-alert
class="mb8"
type="info"
:closable="false"
show-icon
title="说明:后端教学实施计划课次接口未返回课程类型字段,无法按三实课类型筛选,当前展示本周全部教学实施计划课次。"
/>
<!-- 三实表格 -->
<div class="table-card">
<el-table :data="practiceList" v-loading="practiceLoading" stripe border>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column label="上课时间" width="200" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ fmtLessonTime(scope.row) }}</template>
</el-table-column>
<el-table-column prop="kcmc" label="课程" min-width="150" show-overflow-tooltip header-align="center" />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" />
<el-table-column label="教学内容" min-width="180" show-overflow-tooltip header-align="center">
<template slot-scope="scope">{{ scope.row.jxnr || '-' }}</template>
</el-table-column>
<el-table-column label="教学方法" width="130" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.jxff || '-' }}</template>
</el-table-column>
<el-table-column label="填写状态" width="100" align="center">
<template slot-scope="scope">
<el-tag :type="txztType(scope.row.txzt)" size="mini">{{ txztText(scope.row.txzt) }}</el-tag>
</template>
</el-table-column>
</el-table>
<el-empty v-show="!practiceLoading && !practiceList.length" description="本周暂无三实教学计划数据" />
<pagination
v-show="practiceTotal > 0"
:total="practiceTotal"
:page.sync="practiceQuery.pageNum"
:limit.sync="practiceQuery.pageSize"
@pagination="getPracticeList"
/>
</div>
</div>
</el-tab-pane>
<!-- 班次 -->
<el-tab-pane label="班次" name="shift">
<div class="tab-body">
<!-- 查询条件 -->
<el-form :inline="true" class="shift-search">
<el-form-item label="队别班次"> <el-form-item label="队别班次">
<el-select <el-select v-model="searchForm.teamClass" placeholder="请选择队别班次" clearable filterable class="shift-select">
v-model="shiftXydbh" <el-option v-for="item in teamClassOptions" :key="item" :label="item" :value="item" />
placeholder="请选择队别班次"
clearable
filterable
class="shift-select"
>
<el-option v-for="t in teamOptions" :key="t.xydbh" :label="t.xydmc" :value="t.xydbh" />
</el-select>
</el-form-item>
<el-form-item label="年度">
<el-select v-model="shiftNd" placeholder="请选择年度" class="shift-select">
<el-option v-for="y in yearOptions" :key="y" :label="y" :value="y" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleShiftSearch">查询</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div>
<!-- 标题 --> <!-- 标题 -->
<div class="shift-title">{{ shiftTitle }}</div> <div class="page-title">{{ pageTitle }}</div>
<!-- 操作按钮 --> <!-- 下载操作按钮 -->
<el-row :gutter="10" class="mb8"> <el-card shadow="never" class="action-card">
<el-col :span="1.5"> <div class="button-row">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期教学实施计划</el-button> <el-button type="primary" plain size="mini" @click="handleExportPlan">学期教学实施计划</el-button>
</el-col> <el-button type="primary" plain size="mini" @click="handleExportGrades">学期成绩表</el-button>
<el-col :span="1.5"> <el-button type="primary" plain size="mini" @click="handleExportCourses">课程列表另存Excel</el-button>
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表周次星期</el-button> </div>
</el-col> </el-card>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表班次视图</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表排课周含选修</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期教学实施计划含选修</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期课程表周次星期详细</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleNotProvided">学期成绩表</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-download" size="mini" @click="handleNotProvided">课程列表另存Excel</el-button>
</el-col>
</el-row>
<!-- 班次课程表 --> <!-- 数据表格 -->
<div class="table-card"> <div class="table-card">
<el-table v-loading="shiftLoading" :data="shiftList" border stripe> <el-table :data="shiftData" v-loading="loading" border stripe style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="课程名称/简称" min-width="200" header-align="center"> <el-table-column label="课程名称/课时系数" min-width="220" align="center">
<template slot-scope="scope"> <template #default="{ row }">
<div>{{ scope.row._kcmc || '-' }}</div> <div>{{ row.kcmc || '-' }}</div>
<div class="sub-text">{{ scope.row.jc || '-' }}</div> <div class="sub-text">{{ row.kssk || '-' }}</div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="责任教员/课次" width="160" header-align="center"> <el-table-column prop="zrjs" label="责任教员/课次" min-width="150" align="center" show-overflow-tooltip />
<template slot-scope="scope"> <el-table-column prop="bc" label="班次" min-width="120" align="center" show-overflow-tooltip />
<div>{{ scope.row._zrjy || '-' }}</div> <el-table-column prop="nj" label="年级" width="80" align="center" />
<div class="sub-text">{{ scope.row.kcxh || '-' }}次课</div> <el-table-column prop="zy" label="专业" min-width="120" align="center" show-overflow-tooltip />
</template> <el-table-column prop="jhxs" label="计划学时" width="90" align="center" />
</el-table-column> <el-table-column prop="yxxs" label="运行学时" width="90" align="center" />
<el-table-column prop="xydmc" label="班次" width="130" show-overflow-tooltip header-align="center" /> <el-table-column prop="khlxfs" label="考核类型方式" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="xs" label="计划学时" width="90" align="center" /> <el-table-column prop="ssjs" label="实施教员" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="llxs" label="理论学时" width="90" align="center" /> <el-table-column prop="rscd" label="人数/场地" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="sjxs" label="实践学时" width="90" align="center" /> <el-table-column prop="kcjd" label="课程进度" width="120" align="center" />
<el-table-column prop="cjfz" label="考核类型方式" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="ssjhbg" label="实施计划变更" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="实施教员" width="110" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row._ssjy || '-' }}</template>
</el-table-column>
<el-table-column label="人数/场地" width="130" header-align="center">
<template slot-scope="scope">
<div>{{ scope.row.rs || '-' }} </div>
<div class="sub-text">{{ scope.row.jsbh || '-' }}</div>
</template>
</el-table-column>
<el-table-column prop="xf" label="学分" width="80" align="center" />
<el-table-column label="实施计划变更" width="150" header-align="center">
<template slot-scope="scope">{{ fmtKbbdsj(scope.row.kbbdsj) }}</template>
</el-table-column>
</el-table> </el-table>
<el-empty v-show="!shiftLoading && !shiftList.length" description="该班次暂无课程数据" /> <el-empty v-show="!loading && !shiftData.length" description="请选择队别班次后查询" />
<pagination
v-show="shiftTotal > 0"
:total="shiftTotal"
:page.sync="shiftQuery.pageNum"
:limit.sync="shiftQuery.pageSize"
@pagination="getShiftList"
/>
</div> </div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@@ -239,14 +129,9 @@
</template> </template>
<script> <script>
import { listTeachingPlan } from '@/api/teachBusiness/courseRunning' import { listToday, listWeek, listClass, exportClassPlan, exportClassGrades, exportClassCourses } from '@/api/teachBusiness/timetable'
import { listStudentTeamTask } from '@/api/teachBusiness/studentTeamTask'
import { listTeam } from '@/api/studentRecords/team' import { listTeam } from '@/api/studentRecords/team'
import { listKb } from '@/api/teachOffice/kb'
import { listTeacher } from '@/api/teachOffice/teacher'
import { listAllSemester } from '@/api/teachBusiness/semester'
// 节次 -> 节次区间映射
const JC_SECTION = { const JC_SECTION = {
1: '1-2节', 2: '3-4节', 3: '5-6节', 4: '7-8节', 5: '9-10节', 6: '11-12节' 1: '1-2节', 2: '3-4节', 3: '5-6节', 4: '7-8节', 5: '9-10节', 6: '11-12节'
} }
@@ -273,124 +158,49 @@ export default {
data() { data() {
return { return {
activeTab: 'today', activeTab: 'today',
loading: false,
// 今日 // 今日
todayDate: new Date(), todayDate: new Date(),
todayList: [], todayData: [],
todayLoading: false,
// 本周 // 本周
weekStart: getMonday(new Date()), weekStart: getMonday(new Date()),
weekList: [], weekData: [],
weekLoading: false,
weekTotal: 0,
weekQuery: { pageNum: 1, pageSize: 20 },
// 三实
practiceStart: getMonday(new Date()),
practiceList: [],
practiceLoading: false,
practiceTotal: 0,
practiceQuery: { pageNum: 1, pageSize: 20 },
// 班次 // 班次
teamOptions: [], searchForm: { teamClass: '' },
shiftXydbh: '', teamClassOptions: [],
shiftNd: undefined, teamMap: {},
shiftList: [], shiftData: []
shiftLoading: false,
shiftTotal: 0,
shiftQuery: { pageNum: 1, pageSize: 20 },
// 年度下拉数据来自 /semester/all(真实后端数据)
yearOptions: [],
defaultNd: undefined,
// 名称映射(真实接口数据,用于班次 tab 课程/教员编号转名称)
kbMap: {},
teacherMap: {}
} }
}, },
computed: { computed: {
todayTitle() { dateTitle() {
return '当前日期:' + formatDate(this.todayDate) + '时间顺序教学实施计划' return formatDate(this.todayDate) + ' 今日教学实施计划'
}, },
weekTitle() { weekRangeText() {
const end = new Date(this.weekStart) const end = new Date(this.weekStart)
end.setDate(end.getDate() + 6) end.setDate(end.getDate() + 6)
return formatDate(this.weekStart) + '(' + this.weekDayName(this.weekStart) + ') 至 ' + return formatDate(this.weekStart) + '(' + this.weekDayName(this.weekStart) + ') 至 ' +
formatDate(end) + '(' + this.weekDayName(end) + ') 教学实施计划' formatDate(end) + '(' + this.weekDayName(end) + ') 本周教学实施计划'
}, },
practiceTitle() { pageTitle() {
const end = new Date(this.practiceStart) const name = this.searchForm.teamClass || ''
end.setDate(end.getDate() + 6) return (name ? name + ' ' : '') + '教学班次教学实施计划'
return formatDate(this.practiceStart) + '(' + this.weekDayName(this.practiceStart) + ') 至 ' +
formatDate(end) + '(' + this.weekDayName(end) + ') 三实教学实施计划'
},
shiftTitle() {
const team = this.teamOptions.find(t => t.xydbh === this.shiftXydbh)
const name = (team && team.xydmc) || ''
return (this.shiftNd ? this.shiftNd + '年' : '') + name + '课程表'
} }
}, },
created() { created() {
this.loadYearOptions() this.loadTeamOptions()
this.getTodayList() this.getTodayList()
this.getWeekList() this.getWeekList()
this.getPracticeList()
this.loadTeamOptions()
this.loadKbMap()
this.loadTeacherMap()
}, },
methods: { methods: {
/* ---------- 年度下拉(数据来自 /semester/all ---------- */
loadYearOptions() {
return listAllSemester().then(response => {
const list = response.data || []
// 去重并按年度倒序
const map = {}
list.forEach(item => {
if (item.nd !== null && item.nd !== undefined && item.nd !== '') map[item.nd] = item
})
const arr = Object.keys(map).sort((a, b) => String(b).localeCompare(String(a)))
this.yearOptions = arr
// 默认年度:优先当前学期(dqxq=true),否则取最新年度
const current = list.find(item => item.dqxq === true)
this.defaultNd = (current && current.nd) || arr[0]
if (!this.shiftNd) this.shiftNd = this.defaultNd
return arr
}).catch(() => {
this.yearOptions = []
this.defaultNd = undefined
return []
})
},
weekDayName(d) { weekDayName(d) {
return WEEK_DAY_NAMES[d.getDay()] return WEEK_DAY_NAMES[d.getDay()]
}, },
formatSection(jc) { formatJc(jc) {
if (jc === null || jc === undefined || jc === '') return '第?节' if (jc === null || jc === undefined || jc === '') return '第?节'
return JC_SECTION[jc] || ('第' + jc + '节') return JC_SECTION[jc] || ('第' + jc + '节')
}, },
/** 后端 LocalDateTime -> 日期+周X+节次区间 */ /* ---------- 今日:日期导航 ---------- */
fmtLessonTime(row) {
const rq = row.rq || ''
const date = String(rq).substring(0, 10)
if (!date) return '-'
const d = new Date(date.replace(/-/g, '/'))
const wn = WEEK_DAY_NAMES[d.getDay()]
return (date + ' 周' + wn + ' ' + this.formatSection(row.jc)).trim()
},
/** 后端 LocalDateTime -> yyyy-MM-dd HH:mm */
fmtKbbdsj(v) {
if (!v) return '-'
return String(v).replace('T', ' ').substring(0, 16)
},
txztText(txzt) {
if (txzt === 1) return '已填写'
if (txzt === 2) return '已提交'
return '未填写'
},
txztType(txzt) {
if (txzt === 1) return 'success'
if (txzt === 2) return 'primary'
return 'info'
},
/* ---------- 今日 ---------- */
handlePrevDay() { handlePrevDay() {
const d = new Date(this.todayDate) const d = new Date(this.todayDate)
d.setDate(d.getDate() - 1) d.setDate(d.getDate() - 1)
@@ -403,179 +213,163 @@ export default {
this.todayDate = d this.todayDate = d
this.getTodayList() this.getTodayList()
}, },
getTodayList() { /* ---------- 本周:周次导航 ---------- */
const day = formatDate(this.todayDate)
const params = {
rqStart: day + 'T00:00:00',
rqEnd: day + 'T23:59:59',
pageNum: 1,
pageSize: 200
}
this.todayLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.todayList = data.records || []
this.todayLoading = false
}).catch(() => {
this.todayList = []
this.todayLoading = false
})
},
/* ---------- 本周 ---------- */
handlePrevWeek() { handlePrevWeek() {
const d = new Date(this.weekStart) const d = new Date(this.weekStart)
d.setDate(d.getDate() - 7) d.setDate(d.getDate() - 7)
this.weekStart = d this.weekStart = d
this.weekQuery.pageNum = 1
this.getWeekList() this.getWeekList()
}, },
handleNextWeek() { handleNextWeek() {
const d = new Date(this.weekStart) const d = new Date(this.weekStart)
d.setDate(d.getDate() + 7) d.setDate(d.getDate() + 7)
this.weekStart = d this.weekStart = d
this.weekQuery.pageNum = 1
this.getWeekList() this.getWeekList()
}, },
weekRange() { /* ---------- 队别班次下拉(真实接口) ---------- */
const start = formatDate(this.weekStart) + 'T00:00:00'
const endDate = new Date(this.weekStart)
endDate.setDate(endDate.getDate() + 6)
const end = formatDate(endDate) + 'T23:59:59'
return { start: start, end: end }
},
getWeekList() {
const range = this.weekRange()
const params = {
rqStart: range.start,
rqEnd: range.end,
pageNum: this.weekQuery.pageNum,
pageSize: this.weekQuery.pageSize
}
this.weekLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.weekList = data.records || []
this.weekTotal = data.total || 0
this.weekLoading = false
}).catch(() => {
this.weekList = []
this.weekTotal = 0
this.weekLoading = false
})
},
/* ---------- 三实 ---------- */
handlePrevWeek3() {
const d = new Date(this.practiceStart)
d.setDate(d.getDate() - 7)
this.practiceStart = d
this.practiceQuery.pageNum = 1
this.getPracticeList()
},
handleNextWeek3() {
const d = new Date(this.practiceStart)
d.setDate(d.getDate() + 7)
this.practiceStart = d
this.practiceQuery.pageNum = 1
this.getPracticeList()
},
practiceRange() {
const start = formatDate(this.practiceStart) + 'T00:00:00'
const endDate = new Date(this.practiceStart)
endDate.setDate(endDate.getDate() + 6)
const end = formatDate(endDate) + 'T23:59:59'
return { start: start, end: end }
},
getPracticeList() {
// 后端 plan/list 接口未返回课程类型字段,无法按三实课筛选,与本周共用同一数据源
const range = this.practiceRange()
const params = {
rqStart: range.start,
rqEnd: range.end,
pageNum: this.practiceQuery.pageNum,
pageSize: this.practiceQuery.pageSize
}
this.practiceLoading = true
listTeachingPlan(params).then(response => {
const data = response.data || {}
this.practiceList = data.records || []
this.practiceTotal = data.total || 0
this.practiceLoading = false
}).catch(() => {
this.practiceList = []
this.practiceTotal = 0
this.practiceLoading = false
})
},
/* ---------- 班次 ---------- */
loadTeamOptions() { loadTeamOptions() {
listTeam({ pageNum: 1, pageSize: 1000 }).then(response => { listTeam({ pageNum: 1, pageSize: 1000 }).then(response => {
const data = response.data || {} const data = response.data || {}
this.teamOptions = data.records || [] const list = data.records || []
}).catch(() => {
this.teamOptions = []
})
},
loadKbMap() {
listKb({ pageNum: 1, pageSize: 1000 }).then(response => {
const data = response.data || {}
const map = {} const map = {}
;(data.records || []).forEach(item => { ;(list || []).forEach(item => {
if (item.kbh) map[item.kbh] = item.kmc if (item.xydmc) map[item.xydmc] = item.xydbh
}) })
this.kbMap = map this.teamMap = map
this.teamClassOptions = list.map(item => item.xydmc).filter(Boolean)
}).catch(() => { }).catch(() => {
this.kbMap = {} this.teamMap = {}
this.teamClassOptions = []
}) })
}, },
loadTeacherMap() { /* ---------- 数据字段映射(接口字段 -> 页面字段) ---------- */
listTeacher({ pageNum: 1, pageSize: 1000 }).then(response => { parseSection(sksj) {
const m = String(sksj || '').match(/第(\d+)节/)
return m ? Number(m[1]) : undefined
},
mapLessonRow(apiRow) {
// 接口今日/本周实体:bh sksj kc zrdw bc jy cd jxnrxff bz
const row = Object.assign({}, apiRow)
row.kcmc = apiRow.kc
row.skjy = apiRow.jy
row.jxcd = apiRow.cd
row.jxnrff = apiRow.jxnrxff
row.jybz = apiRow.bz
row.sjsj = apiRow.sksj
row.jc = this.parseSection(apiRow.sksj)
return row
},
mapClassRow(apiRow) {
// 接口班次实体:sskcbh kcmcksxs zrjykc jhxs yxxs khlxfs ssjy rscd ssjhbg
const row = Object.assign({}, apiRow)
const parts = String(apiRow.kcmcksxs || '').split(' / ')
row.kcmc = parts[0] || '-'
row.kssk = parts[1] || '-'
row.zrjs = apiRow.zrjykc
row.ssjs = apiRow.ssjy
return row
},
/* ---------- 今日:拉取数据 ---------- */
getTodayList() {
this.loading = true
listToday({}).then(response => {
const data = response.data
this.todayData = Array.isArray(data)
? (data || []).map(item => this.mapLessonRow(item))
: ((data && data.records) || []).map(item => this.mapLessonRow(item))
this.loading = false
}).catch(() => {
this.todayData = []
this.loading = false
})
},
/* ---------- 本周:拉取数据 ---------- */
getWeekList() {
this.loading = true
listWeek({}).then(response => {
const data = response.data
this.weekData = Array.isArray(data)
? (data || []).map(item => this.mapLessonRow(item))
: ((data && data.records) || []).map(item => this.mapLessonRow(item))
this.loading = false
}).catch(() => {
this.weekData = []
this.loading = false
})
},
/* ---------- 班次:拉取数据 ---------- */
getShiftList() {
if (!this.searchForm.teamClass) return
const xydbh = this.teamMap[this.searchForm.teamClass] || this.searchForm.teamClass
const params = { xydbh: xydbh, pageNum: 1, pageSize: 1000 }
this.loading = true
listClass(params).then(response => {
const data = response.data || {} const data = response.data || {}
const map = {} this.shiftData = (data.records || []).map(item => this.mapClassRow(item))
;(data.records || []).forEach(item => { this.loading = false
if (item.jybh) map[item.jybh] = item.jyxm
})
this.teacherMap = map
}).catch(() => { }).catch(() => {
this.teacherMap = {} this.shiftData = []
this.loading = false
}) })
}, },
handleShiftSearch() { /* ---------- 班次:查询 ---------- */
if (!this.shiftXydbh) { handleQuery() {
if (!this.searchForm.teamClass) {
this.$message.warning('请先选择队别班次') this.$message.warning('请先选择队别班次')
return return
} }
this.shiftQuery.pageNum = 1
this.getShiftList() this.getShiftList()
}, },
getShiftList() { /* ---------- 下载 ---------- */
const params = { downloadBlob(blob, filename) {
xydbh: this.shiftXydbh, const link = document.createElement('a')
nd: this.shiftNd, link.href = window.URL.createObjectURL(blob)
pageNum: this.shiftQuery.pageNum, link.download = filename
pageSize: this.shiftQuery.pageSize document.body.appendChild(link)
} link.click()
this.shiftLoading = true document.body.removeChild(link)
listStudentTeamTask(params).then(response => { window.URL.revokeObjectURL(link.href)
const data = response.data || {}
const team = this.teamOptions.find(t => t.xydbh === this.shiftXydbh)
this.shiftList = (data.records || []).map(item => ({
...item,
xydmc: (team && team.xydmc) || item.xydbh,
_kcmc: this.kbMap[item.kbh] || item.kbh,
_zrjy: this.teacherMap[item.jysjhjybh] || item.jysjhjybh || '-',
_ssjy: this.teacherMap[item.jybh] || item.jybh || '-'
}))
this.shiftTotal = data.total || 0
this.shiftLoading = false
}).catch(() => {
this.shiftList = []
this.shiftTotal = 0
this.shiftLoading = false
})
}, },
/* ---------- 无后端接口的操作 ---------- */ shiftQueryParams() {
handleNotProvided() { if (!this.searchForm.teamClass) return null
this.$message.info('后端暂未提供该接口') const xydbh = this.teamMap[this.searchForm.teamClass] || this.searchForm.teamClass
return { xydbh: xydbh }
},
/** 下载学期教学实施计划 ExcelGET /kcb/class/export-plan */
handleExportPlan() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassPlan(params).then(blob => {
this.downloadBlob(blob, '学期教学实施计划.xlsx')
this.$message.success('学期教学实施计划导出成功')
}).catch(() => {})
},
/** 下载学期成绩表 ExcelGET /kcb/class/export-grades */
handleExportGrades() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassGrades(params).then(blob => {
this.downloadBlob(blob, '学期成绩表.xlsx')
this.$message.success('学期成绩表导出成功')
}).catch(() => {})
},
/** 班次课程列表另存 ExcelGET /kcb/class/export-courses */
handleExportCourses() {
const params = this.shiftQueryParams()
if (!params) {
this.$message.warning('请先选择队别班次')
return
}
exportClassCourses(params).then(blob => {
this.downloadBlob(blob, '班次课程列表.xlsx')
this.$message.success('班次课程列表导出成功')
}).catch(() => {})
} }
} }
} }
@@ -594,12 +388,15 @@ export default {
padding-bottom: 16px; padding-bottom: 16px;
} }
.mb8 { .sub-text {
margin-bottom: 8px; font-size: 12px;
color: #909399;
margin-top: 2px;
} }
/* 日期/周次导航 */ /* 日期/周次导航 */
.nav-header { .date-header,
.week-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -614,30 +411,28 @@ export default {
font-size: 14px; font-size: 14px;
} }
.nav-title { .date-title,
font-size: 18px; .week-title {
font-size: 16px;
font-weight: 700; font-weight: 700;
color: #303133; color: #303133;
} }
} }
/* 表格区 */
.table-card {
.danger-text {
color: #f56c6c;
}
}
/* 班次 */ /* 班次 */
.shift-search { .search-card {
margin-bottom: 8px; margin-bottom: 12px;
.search-form {
margin-bottom: 0;
} }
.shift-select { .shift-select {
width: 220px; width: 240px;
}
} }
.shift-title { .page-title {
font-size: 17px; font-size: 17px;
font-weight: 700; font-weight: 700;
color: #303133; color: #303133;
@@ -645,10 +440,14 @@ export default {
margin-bottom: 12px; margin-bottom: 12px;
} }
.sub-text { .action-card {
font-size: 12px; margin-bottom: 12px;
color: #909399;
margin-top: 2px; .button-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
} }
} }
</style> </style>
@@ -2,7 +2,6 @@
<div class="page-container"> <div class="page-container">
<!-- 统计卡片 --> <!-- 统计卡片 -->
<div class="section-card"> <div class="section-card">
<div class="section-title">调课申请统计当前页</div>
<div class="stat-grid"> <div class="stat-grid">
<div <div
v-for="card in statCards" v-for="card in statCards"
@@ -54,21 +53,21 @@
<el-table :data="tableData" v-loading="loading" size="small" border stripe class="compact-table" max-height="520"> <el-table :data="tableData" v-loading="loading" size="small" border stripe class="compact-table" max-height="520">
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="kcmc" label="课程名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程名称" width="200" align="center" show-overflow-tooltip />
<el-table-column label="申请教员" min-width="110" align="center" show-overflow-tooltip> <el-table-column label="申请教员" width="150" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.sqjyxm || scope.row.sqjybh || '-' }}</template> <template slot-scope="scope">{{ scope.row.sqjyxm || scope.row.sqjybh || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="sy" label="调课事由" min-width="180" show-overflow-tooltip header-align="center" /> <el-table-column prop="sy" label="调课事由" width="230" show-overflow-tooltip header-align="center" />
<el-table-column label="拟调整时间" width="170" align="center" show-overflow-tooltip> <el-table-column label="拟调整时间" width="200" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template> <template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="nd" label="年度" width="80" align="center" /> <el-table-column prop="nd" label="年度" width="150" align="center" />
<el-table-column label="教研室审批状态" width="110" align="center"> <el-table-column label="教研室审批状态" width="150" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="auditStatusTag(scope.row.jyspzzt).type" size="mini">{{ auditStatusTag(scope.row.jyspzzt).label }}</el-tag> <el-tag :type="auditStatusTag(scope.row.jyspzzt).type" size="mini">{{ auditStatusTag(scope.row.jyspzzt).label }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="教研室查收状态" width="100" align="center"> <el-table-column label="教研室查收状态" width="150" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="receiveStatusTag(scope.row.jyscszt).type" size="mini">{{ receiveStatusTag(scope.row.jyscszt).label }}</el-tag> <el-tag :type="receiveStatusTag(scope.row.jyscszt).type" size="mini">{{ receiveStatusTag(scope.row.jyscszt).label }}</el-tag>
</template> </template>
@@ -76,7 +75,7 @@
<el-table-column label="创建时间" width="150" align="center"> <el-table-column label="创建时间" width="150" align="center">
<template slot-scope="scope">{{ fmtDateTime(scope.row.cjsj) }}</template> <template slot-scope="scope">{{ fmtDateTime(scope.row.cjsj) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="210" align="center" fixed="right"> <el-table-column label="操作" width="180" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<div class="ops-cell"> <div class="ops-cell">
<el-button type="text" size="mini" icon="el-icon-view" @click="openDetail(scope.row)">详情</el-button> <el-button type="text" size="mini" icon="el-icon-view" @click="openDetail(scope.row)">详情</el-button>
@@ -164,13 +163,13 @@
<!-- 可供调课课次选择弹窗 --> <!-- 可供调课课次选择弹窗 -->
<el-dialog title="选择可供调课课次" :visible.sync="lessonDialogVisible" width="760px" append-to-body> <el-dialog title="选择可供调课课次" :visible.sync="lessonDialogVisible" width="760px" append-to-body>
<el-table :data="lessonOptions" v-loading="lessonLoading" size="small" border stripe max-height="420"> <el-table :data="lessonOptions" v-loading="lessonLoading" size="small" border stripe max-height="420">
<el-table-column prop="kcmc" label="课程名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="kcmc" label="课程名称" min-width="140" align="center" show-overflow-tooltip />
<el-table-column label="原上课时间" width="160" align="center"> <el-table-column label="原上课时间" width="160" align="center">
<template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template> <template slot-scope="scope">{{ fmtRqJc(scope.row.rq, scope.row.jc) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="xydmc" label="学员队" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="xydmc" label="学员队" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="kcxh" label="课次序号" width="90" align="center" /> <el-table-column prop="kcxh" label="课次序号" width="90" align="center" />
<el-table-column prop="jsbh" label="教室编号" width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="jsbh" label="教室编号" width="110" align="center" show-overflow-tooltip />
<el-table-column label="操作" width="90" align="center"> <el-table-column label="操作" width="90" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" size="mini" @click="pickLesson(scope.row)">选择</el-button> <el-button type="text" size="mini" @click="pickLesson(scope.row)">选择</el-button>
@@ -229,6 +228,7 @@
<el-descriptions-item label="课程名称">{{ detailData.kcmc || '-' }}</el-descriptions-item> <el-descriptions-item label="课程名称">{{ detailData.kcmc || '-' }}</el-descriptions-item>
<el-descriptions-item label="申请教员">{{ detailData.sqjyxm || detailData.sqjybh || '-' }}</el-descriptions-item> <el-descriptions-item label="申请教员">{{ detailData.sqjyxm || detailData.sqjybh || '-' }}</el-descriptions-item>
<el-descriptions-item label="调课事由" :span="2">{{ detailData.sy || '-' }}</el-descriptions-item> <el-descriptions-item label="调课事由" :span="2">{{ detailData.sy || '-' }}</el-descriptions-item>
<el-descriptions-item label="原上课时间">{{ detailData.ydsjap || '-' }}</el-descriptions-item>
<el-descriptions-item label="拟调整时间">{{ fmtRqJc(detailData.rq, detailData.jc) }}</el-descriptions-item> <el-descriptions-item label="拟调整时间">{{ fmtRqJc(detailData.rq, detailData.jc) }}</el-descriptions-item>
<el-descriptions-item label="年度">{{ detailData.nd || '-' }}</el-descriptions-item> <el-descriptions-item label="年度">{{ detailData.nd || '-' }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ fmtDateTime(detailData.cjsj) }}</el-descriptions-item> <el-descriptions-item label="创建时间">{{ fmtDateTime(detailData.cjsj) }}</el-descriptions-item>
@@ -242,7 +242,6 @@
<el-descriptions-item label="教研室审批时间">{{ fmtDateTime(detailData.jyspzsj) }}</el-descriptions-item> <el-descriptions-item label="教研室审批时间">{{ fmtDateTime(detailData.jyspzsj) }}</el-descriptions-item>
<el-descriptions-item label="教研室查收人">{{ detailData.jyscsrbh || '-' }}</el-descriptions-item> <el-descriptions-item label="教研室查收人">{{ detailData.jyscsrbh || '-' }}</el-descriptions-item>
<el-descriptions-item label="教研室查收时间">{{ fmtDateTime(detailData.jyscssj) }}</el-descriptions-item> <el-descriptions-item label="教研室查收时间">{{ fmtDateTime(detailData.jyscssj) }}</el-descriptions-item>
<el-descriptions-item label="发回意见" :span="2">{{ detailData.fhyj || '-' }}</el-descriptions-item>
<el-descriptions-item label="教学内容" :span="2">{{ detailData.jxnr || '-' }}</el-descriptions-item> <el-descriptions-item label="教学内容" :span="2">{{ detailData.jxnr || '-' }}</el-descriptions-item>
<el-descriptions-item label="教学要点" :span="2">{{ detailData.jxyd || '-' }}</el-descriptions-item> <el-descriptions-item label="教学要点" :span="2">{{ detailData.jxyd || '-' }}</el-descriptions-item>
<el-descriptions-item label="教学方法" :span="2">{{ detailData.jxff || '-' }}</el-descriptions-item> <el-descriptions-item label="教学方法" :span="2">{{ detailData.jxff || '-' }}</el-descriptions-item>
@@ -255,8 +254,8 @@
<div v-if="detailData && detailData.roomList && detailData.roomList.length" class="sub-section"> <div v-if="detailData && detailData.roomList && detailData.roomList.length" class="sub-section">
<div class="sub-title">新教室</div> <div class="sub-title">新教室</div>
<el-table :data="detailData.roomList" size="small" border stripe> <el-table :data="detailData.roomList" size="small" border stripe>
<el-table-column prop="jsbh" label="教室编号" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="jsbh" label="教室编号" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="jsmc" label="教室名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="jsmc" label="教室名称" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="bz" label="备注" min-width="160" show-overflow-tooltip header-align="center" /> <el-table-column prop="bz" label="备注" min-width="160" show-overflow-tooltip header-align="center" />
</el-table> </el-table>
</div> </div>
@@ -265,8 +264,8 @@
<div v-if="detailData && detailData.teacherList && detailData.teacherList.length" class="sub-section"> <div v-if="detailData && detailData.teacherList && detailData.teacherList.length" class="sub-section">
<div class="sub-title">新辅助教员</div> <div class="sub-title">新辅助教员</div>
<el-table :data="detailData.teacherList" size="small" border stripe> <el-table :data="detailData.teacherList" size="small" border stripe>
<el-table-column prop="fzjybh" label="教员编号" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="fzjybh" label="教员编号" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="fzjyxm" label="教员姓名" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="fzjyxm" label="教员姓名" min-width="120" align="center" show-overflow-tooltip />
<el-table-column label="是否主教员" width="100" align="center"> <el-table-column label="是否主教员" width="100" align="center">
<template slot-scope="scope">{{ scope.row.zjy === 1 ? '是' : '否' }}</template> <template slot-scope="scope">{{ scope.row.zjy === 1 ? '是' : '否' }}</template>
</el-table-column> </el-table-column>
@@ -278,8 +277,8 @@
<div v-if="detailData && detailData.teamList && detailData.teamList.length" class="sub-section"> <div v-if="detailData && detailData.teamList && detailData.teamList.length" class="sub-section">
<div class="sub-title">新学员队</div> <div class="sub-title">新学员队</div>
<el-table :data="detailData.teamList" size="small" border stripe> <el-table :data="detailData.teamList" size="small" border stripe>
<el-table-column prop="xydbh" label="学员队编号" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="xydbh" label="学员队编号" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="xydmc" label="学员队名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="xydmc" label="学员队名称" min-width="140" align="center" show-overflow-tooltip />
</el-table> </el-table>
</div> </div>
@@ -287,8 +286,8 @@
<div v-if="detailData && detailData.supportList && detailData.supportList.length" class="sub-section"> <div v-if="detailData && detailData.supportList && detailData.supportList.length" class="sub-section">
<div class="sub-title">新保障明细</div> <div class="sub-title">新保障明细</div>
<el-table :data="detailData.supportList" size="small" border stripe> <el-table :data="detailData.supportList" size="small" border stripe>
<el-table-column prop="bztgmxbh" label="保障编号" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="bztgmxbh" label="保障编号" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="bztgmxmc" label="保障名称" min-width="160" show-overflow-tooltip header-align="center" /> <el-table-column prop="bztgmxmc" label="保障名称" min-width="160" align="center" show-overflow-tooltip />
<el-table-column prop="sl" label="数量" width="80" align="center" /> <el-table-column prop="sl" label="数量" width="80" align="center" />
<el-table-column prop="bz" label="备注" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="bz" label="备注" min-width="140" show-overflow-tooltip header-align="center" />
</el-table> </el-table>
@@ -298,7 +297,7 @@
<div v-if="detailData && detailData.auditList && detailData.auditList.length" class="sub-section"> <div v-if="detailData && detailData.auditList && detailData.auditList.length" class="sub-section">
<div class="sub-title">机关审批记录</div> <div class="sub-title">机关审批记录</div>
<el-table :data="detailData.auditList" size="small" border stripe> <el-table :data="detailData.auditList" size="small" border stripe>
<el-table-column prop="jgmc" label="机关" min-width="140" show-overflow-tooltip header-align="center"> <el-table-column prop="jgmc" label="机关" min-width="140" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.jgmc || scope.row.jgbh || '-' }}</template> <template slot-scope="scope">{{ scope.row.jgmc || scope.row.jgbh || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="审批状态" width="100" align="center"> <el-table-column label="审批状态" width="100" align="center">
@@ -306,7 +305,7 @@
<el-tag :type="auditStatusTag(scope.row.spzt).type" size="mini">{{ auditStatusTag(scope.row.spzt).label }}</el-tag> <el-tag :type="auditStatusTag(scope.row.spzt).type" size="mini">{{ auditStatusTag(scope.row.spzt).label }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sprxm" label="审批人" min-width="110" show-overflow-tooltip header-align="center"> <el-table-column prop="sprxm" label="审批人" min-width="110" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.sprxm || scope.row.sprbh || '-' }}</template> <template slot-scope="scope">{{ scope.row.sprxm || scope.row.sprbh || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="审批时间" width="150" align="center"> <el-table-column label="审批时间" width="150" align="center">
@@ -60,15 +60,15 @@
<el-table-column label="冲突号" width="90" align="center" show-overflow-tooltip> <el-table-column label="冲突号" width="90" align="center" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.conflictNo || '-' }}</template> <template slot-scope="scope">{{ scope.row.conflictNo || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="courseNames" label="课程" min-width="150" show-overflow-tooltip header-align="center" /> <el-table-column prop="courseNames" label="课程" min-width="150" align="center" show-overflow-tooltip />
<el-table-column label="日期" width="100" align="center"> <el-table-column label="日期" width="100" align="center">
<template slot-scope="scope">{{ fmtDate(scope.row.rq) }}</template> <template slot-scope="scope">{{ fmtDate(scope.row.rq) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="jc" label="节次" width="70" align="center" /> <el-table-column prop="jc" label="节次" width="70" align="center" />
<el-table-column prop="xydNames" label="班次" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="xydNames" label="班次" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="teacherNames" label="教员" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="teacherNames" label="教员" min-width="120" align="center" show-overflow-tooltip />
<el-table-column prop="classroomNames" label="场地" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="classroomNames" label="场地" min-width="140" align="center" show-overflow-tooltip />
<el-table-column prop="responsibleDept" label="责任单位" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="responsibleDept" label="责任单位" min-width="110" align="center" show-overflow-tooltip />
</el-table> </el-table>
<el-pagination <el-pagination
v-if="detailTotal > 0" v-if="detailTotal > 0"
@@ -6,22 +6,22 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :xs="24" :md="8"> <el-col :xs="24" :md="8">
<el-form-item label="专业名称"> <el-form-item label="专业名称">
<el-input v-model="searchForm.zymc" placeholder="请输入专业名称(模糊)" clearable /> <el-input v-model="searchForm.zymc" placeholder="请输入专业名称" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :md="8"> <el-col :xs="24" :md="8">
<el-form-item label="专业代码"> <el-form-item label="专业代码">
<el-input v-model="searchForm.zydm" placeholder="请输入专业代码(模糊)" clearable /> <el-input v-model="searchForm.zydm" placeholder="请输入专业代码" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :md="8"> <el-col :xs="24" :md="8">
<el-form-item label="培训类型"> <el-form-item label="培训类型">
<el-input v-model="searchForm.pxlx" placeholder="请输入培训类型(精确)" clearable /> <el-input v-model="searchForm.pxlx" placeholder="请输入培训类型" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :md="8"> <el-col :xs="24" :md="8">
<el-form-item label="培训层次"> <el-form-item label="培训层次">
<el-input v-model="searchForm.pxcc" placeholder="请输入培训层次(精确)" clearable /> <el-input v-model="searchForm.pxcc" placeholder="请输入培训层次" clearable />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :md="8"> <el-col :xs="24" :md="8">
@@ -65,17 +65,17 @@
</div> </div>
<el-table v-loading="loading" :data="tableData" border stripe highlight-current-row> <el-table v-loading="loading" :data="tableData" border stripe highlight-current-row>
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="zydh" label="专业代号" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="zydh" label="专业代号" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="zymc" label="专业名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="zymc" label="专业名称" width="140" align="center" show-overflow-tooltip />
<el-table-column prop="zyfx" label="专业方向" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="zyfx" label="专业方向" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="zydm" label="专业代码" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="zydm" label="专业代码" width="110" align="center" show-overflow-tooltip />
<el-table-column prop="pxlx" label="培训类型" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="pxlx" label="培训类型" width="110" align="center" show-overflow-tooltip />
<el-table-column prop="pxcc" label="培训层次" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="pxcc" label="培训层次" width="120" align="center" show-overflow-tooltip />
<el-table-column prop="pxlx2" label="培训类型2" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="pxlx2" label="培训类型2" width="110" align="center" show-overflow-tooltip />
<el-table-column prop="xylb" label="学员类别" min-width="100" show-overflow-tooltip header-align="center" /> <el-table-column prop="xylb" label="学员类别" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="xnz" label="学年制" min-width="80" show-overflow-tooltip header-align="center" /> <el-table-column prop="xnz" label="学年制" width="80" align="center" show-overflow-tooltip />
<el-table-column prop="xqs" label="学期数" width="80" align="center" /> <el-table-column prop="xqs" label="学期数" width="80" align="center" />
<el-table-column prop="zybb" label="专业版本" min-width="100" show-overflow-tooltip header-align="center" /> <el-table-column prop="zybb" label="专业版本" width="100" align="center" show-overflow-tooltip />
<el-table-column label="主干专业" width="90" align="center"> <el-table-column label="主干专业" width="90" align="center">
<template slot-scope="scope">{{ fmtYesNo(scope.row.zgzy) }}</template> <template slot-scope="scope">{{ fmtYesNo(scope.row.zgzy) }}</template>
</el-table-column> </el-table-column>
@@ -92,7 +92,7 @@
<el-table-column label="停用时间" width="150" align="center"> <el-table-column label="停用时间" width="150" align="center">
<template slot-scope="scope">{{ fmtDateTime(scope.row.tysj) }}</template> <template slot-scope="scope">{{ fmtDateTime(scope.row.tysj) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="180" align="center" fixed="right"> <el-table-column label="操作" width="240" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" size="mini" icon="el-icon-view" @click="handleDetail(scope.row)">详情</el-button> <el-button type="text" size="mini" icon="el-icon-view" @click="handleDetail(scope.row)">详情</el-button>
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button> <el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
@@ -122,7 +122,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="专业代号" prop="zydh"> <el-form-item label="专业代号" prop="zydh">
<el-input v-model="dialog.form.zydh" placeholder="请输入专业代号(主键)" :disabled="dialog.isEdit" /> <el-input v-model="dialog.form.zydh" placeholder="请输入专业代号" :disabled="dialog.isEdit" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@@ -495,7 +495,8 @@ export default {
return this.isTrue(val) ? '是' : '否' return this.isTrue(val) ? '是' : '否'
}, },
fmtDateTime(val) { fmtDateTime(val) {
return (val || '').substring(0, 19) || '-' const s = (val || '').substring(0, 10)
return s || '-'
}, },
fmtVal(val) { fmtVal(val) {
return val === '' || val === null || val === undefined ? '-' : val return val === '' || val === null || val === undefined ? '-' : val
@@ -55,11 +55,11 @@
</div> </div>
<el-table v-loading="loading" :data="tableData" border stripe highlight-current-row> <el-table v-loading="loading" :data="tableData" border stripe highlight-current-row>
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="jsbh" label="教室编号" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="jsbh" label="教室编号" width="130" align="center" show-overflow-tooltip />
<el-table-column prop="jsmc" label="教室名称" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="jsmc" label="教室名称" width="140" align="center" show-overflow-tooltip />
<el-table-column prop="jxldh" label="教学楼代号" min-width="110" show-overflow-tooltip header-align="center" /> <el-table-column prop="jxldh" label="教学楼代号" width="150" align="center" show-overflow-tooltip />
<el-table-column prop="jxcdlx" label="教学场地类型" min-width="120" show-overflow-tooltip header-align="center" /> <el-table-column prop="jxcdlx" label="教学场地类型" width="150" align="center" show-overflow-tooltip />
<el-table-column prop="jc" label="简称" min-width="90" show-overflow-tooltip header-align="center" /> <el-table-column prop="jc" label="简称" width="100" align="center" show-overflow-tooltip />
<el-table-column prop="rnrs" label="容纳人数" width="90" align="center" /> <el-table-column prop="rnrs" label="容纳人数" width="90" align="center" />
<el-table-column prop="mj" label="面积" width="90" align="center" /> <el-table-column prop="mj" label="面积" width="90" align="center" />
<el-table-column prop="ksrnrs" label="考试容纳人数" width="110" align="center" /> <el-table-column prop="ksrnrs" label="考试容纳人数" width="110" align="center" />
@@ -74,8 +74,8 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sssb" label="设施设备" min-width="140" show-overflow-tooltip header-align="center" /> <el-table-column prop="sssb" label="设施设备" width="140" show-overflow-tooltip header-align="center" />
<el-table-column label="操作" width="140" align="center" fixed="right"> <el-table-column label="操作" align="center" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button> <el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button> <el-button type="text" size="mini" icon="el-icon-delete" class="danger-text-btn" @click="handleDelete(scope.row)">删除</el-button>
@@ -100,11 +100,6 @@
:close-on-click-modal="false"> :close-on-click-modal="false">
<el-form ref="classroomForm" :model="dialog.form" :rules="rules" label-width="110px"> <el-form ref="classroomForm" :model="dialog.form" :rules="rules" label-width="110px">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="主键编号" prop="id">
<el-input v-model="dialog.form.id" placeholder="请输入主键编号" />
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="教室编号" prop="jsbh"> <el-form-item label="教室编号" prop="jsbh">
<el-input v-model="dialog.form.jsbh" placeholder="请输入教室编号" /> <el-input v-model="dialog.form.jsbh" placeholder="请输入教室编号" />
@@ -230,7 +225,6 @@ export default {
form: this.createEmptyForm() form: this.createEmptyForm()
}, },
rules: { rules: {
id: [{ required: true, message: '请输入主键编号', trigger: 'blur' }],
jsbh: [{ required: true, message: '请输入教室编号', trigger: 'blur' }], jsbh: [{ required: true, message: '请输入教室编号', trigger: 'blur' }],
jsmc: [{ required: true, message: '请输入教室名称', trigger: 'blur' }] jsmc: [{ required: true, message: '请输入教室名称', trigger: 'blur' }]
} }
+40 -61
View File
@@ -1,17 +1,5 @@
<template> <template>
<div class="app-container teach-notice"> <div class="app-container teach-notice">
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
</el-row>
<!-- 查询条件区域 --> <!-- 查询条件区域 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
<el-form-item label="标题" prop="title"> <el-form-item label="标题" prop="title">
@@ -22,21 +10,6 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="优先级">
<el-input
v-model="queryParams.priorityFrom"
placeholder="从"
type="number"
style="width: 100px"
/>
<span class="range-sep">-</span>
<el-input
v-model="queryParams.priorityTo"
placeholder="到"
type="number"
style="width: 100px"
/>
</el-form-item>
<el-form-item label="公告类别"> <el-form-item label="公告类别">
<el-select <el-select
v-model="queryParams.category" v-model="queryParams.category"
@@ -49,13 +22,7 @@
:key="item" :key="item"
:label="item" :label="item"
:value="item" :value="item"
>
<el-checkbox
:value="queryParams.category === item"
@click.stop.prevent="onCategoryCheck(item)"
/> />
<span style="margin-left: 6px">{{ item }}</span>
</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="发布日期"> <el-form-item label="发布日期">
@@ -81,34 +48,40 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-alert
class="query-tip"
title="注意:勾选'选择框'表示启用该项对应的查询条件"
type="info"
:closable="false"
show-icon
/>
<!-- 数据列表区域 --> <!-- 数据列表区域 -->
<div class="list-heading">
<div class="list-title">公告列表</div> <div class="list-title">公告列表</div>
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</div>
<el-table v-loading="loading" :data="noticeList" border :height="tableHeight"> <el-table v-loading="loading" :data="noticeList" border :height="tableHeight">
<el-table-column label="序号" type="index" align="center" width="70" /> <el-table-column label="序号" type="index" align="center" width="70" />
<el-table-column label="发布时间" align="center" min-width="160"> <el-table-column label="发布时间" align="center" width="165">
<template slot-scope="scope">{{ formatTime(scope.row.publishTime) }}</template> <template slot-scope="scope">{{ formatTime(scope.row.publishTime) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="标题" align="center" prop="title" min-width="280" :show-overflow-tooltip="true" /> <el-table-column label="标题" align="left" prop="title" min-width="300" :show-overflow-tooltip="true" />
<el-table-column label="公告状态" align="center" width="100"> <el-table-column label="公告状态" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tag :type="statusTagType(scope.row.status)">{{ scope.row.status }}</el-tag> <el-tag :type="statusTagType(scope.row.status)">{{ scope.row.status }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="公告类别" align="center" prop="category" width="100" /> <el-table-column label="公告类别" align="center" prop="category" width="110" />
<el-table-column label="优先级" align="center" prop="priority" width="90" /> <el-table-column label="优先级" align="center" prop="priority" width="80" />
<el-table-column label="阅读次数" align="center" prop="readCount" width="100" /> <el-table-column label="阅读次数" align="center" prop="readCount" width="90" />
<el-table-column label="接收/已读" align="center" width="110"> <el-table-column label="接收/已读" align="center" width="110">
<template slot-scope="scope">{{ scope.row.recipientCount }}/{{ scope.row.readerCount }}</template> <template slot-scope="scope">{{ scope.row.recipientCount }}/{{ scope.row.readerCount }}</template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="240" class-name="small-padding fixed-width"> <el-table-column
label="操作"
align="center"
width="300"
fixed="right"
class-name="small-padding fixed-width action-column"
>
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
type="text" type="text"
@@ -248,8 +221,6 @@ export default {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
title: undefined, title: undefined,
priorityFrom: undefined,
priorityTo: undefined,
category: undefined, category: undefined,
publishDateFrom: undefined, publishDateFrom: undefined,
publishDateTo: undefined publishDateTo: undefined
@@ -300,10 +271,6 @@ export default {
if (status === '已下架') return 'info' if (status === '已下架') return 'info'
return 'warning' return 'warning'
}, },
/** 公告类别复选框:点击即选中该项作为查询条件 */
onCategoryCheck(item) {
this.queryParams.category = this.queryParams.category === item ? undefined : item
},
/** 查询按钮 */ /** 查询按钮 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1 this.queryParams.pageNum = 1
@@ -315,8 +282,6 @@ export default {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
title: undefined, title: undefined,
priorityFrom: undefined,
priorityTo: undefined,
category: undefined, category: undefined,
publishDateFrom: undefined, publishDateFrom: undefined,
publishDateTo: undefined publishDateTo: undefined
@@ -412,24 +377,27 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.teach-notice { .teach-notice {
.mb8 {
margin-bottom: 8px;
}
.range-sep { .range-sep {
margin: 0 8px; margin: 0 8px;
color: #909399; color: #909399;
} }
.query-tip { .list-heading {
margin: 4px 0 16px; display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 12px;
} }
.list-title { .list-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
margin-bottom: 12px;
padding-left: 10px; padding-left: 10px;
border-left: 4px solid var(--edu-green-primary); border-left: 4px solid var(--edu-green-primary);
} }
::v-deep .action-column .cell {
white-space: nowrap;
}
.detail-body { .detail-body {
padding: 0 8px; padding: 0 8px;
.detail-row { .detail-row {
@@ -454,5 +422,16 @@ export default {
} }
} }
} }
@media (max-width: 768px) {
.list-heading {
align-items: stretch;
flex-direction: column;
}
.list-heading .el-button {
width: 100%;
}
}
} }
</style> </style>
@@ -1,7 +1,14 @@
<template> <template>
<div class="app-container"> <div class="app-container management-page elective-page">
<!-- ==================== 2. 查询条件区域 ==================== --> <!-- ==================== 2. 查询条件区域 ==================== -->
<div class="section-card query-card"> <div class="section-card query-card">
<div class="section-heading">
<div>
<h2 class="section-title">筛选条件</h2>
<p class="section-description">按课程班次教员及状态筛选选修课</p>
</div>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
</div>
<el-form> <el-form>
<el-row :gutter="32"> <el-row :gutter="32">
<!-- 左栏 --> <!-- 左栏 -->
@@ -15,9 +22,13 @@
<el-input v-model="searchForm.kbcnj" placeholder="请输入可选班次年级" clearable class="q-control" /> <el-input v-model="searchForm.kbcnj" placeholder="请输入可选班次年级" clearable class="q-control" />
</div> </div>
<div class="query-field"> <div class="query-field">
<el-checkbox v-model="searchForm.xxkztEnabled" /> <span class="q-label no-check">选修课状态</span>
<span class="q-label">选修课状态</span> <el-select
<el-select v-model="searchForm.xxkzt" class="q-control" :disabled="!searchForm.xxkztEnabled"> v-model="searchForm.xxkzt"
placeholder="请选择选修课状态"
clearable
class="q-control"
>
<el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</div> </div>
@@ -34,9 +45,8 @@
<el-input v-model="searchForm.xxbmc" placeholder="请输入选修班名称" clearable class="q-control" /> <el-input v-model="searchForm.xxbmc" placeholder="请输入选修班名称" clearable class="q-control" />
</div> </div>
<div class="query-field"> <div class="query-field">
<el-checkbox v-model="searchForm.pxccEnabled" /> <span class="q-label no-check">培训层次</span>
<span class="q-label">培训层次</span> <el-select v-model="searchForm.pxcc" placeholder="请选择培训层次" clearable class="q-control">
<el-select v-model="searchForm.pxcc" class="q-control" :disabled="!searchForm.pxccEnabled">
<el-option v-for="item in pxccOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in pxccOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</div> </div>
@@ -44,50 +54,79 @@
</el-row> </el-row>
</el-form> </el-form>
<div class="query-footer">
<el-button class="gray-btn" @click="handleQuery">查询</el-button>
</div>
</div> </div>
<!-- ==================== 3. 导出按钮区域 ==================== --> <!-- ==================== 3. 导出按钮区域 ==================== -->
<div class="section-card export-card"> <div class="section-card export-card">
<div class="section-heading section-heading--compact">
<div>
<h2 class="section-title">数据导出</h2>
<p class="section-description">下载选修班及学员名单</p>
</div>
</div>
<div class="export-bar"> <div class="export-bar">
<el-button type="primary" @click="handleDownloadList">下载选修班列表</el-button> <el-button icon="el-icon-download" @click="handleDownloadList">下载选修班列表</el-button>
<el-button type="primary" @click="handleDownloadWord">下载选修班学员名单Word</el-button> <el-button icon="el-icon-download" @click="handleDownloadWord">下载选修班学员名单Word</el-button>
<el-button type="primary" @click="handleDownloadExcel">下载选修班学员名单Excel</el-button> <el-button icon="el-icon-download" @click="handleDownloadExcel">下载选修班学员名单Excel</el-button>
</div> </div>
</div> </div>
<!-- ==================== 4. 操作按钮区域 ==================== --> <!-- ==================== 4. 操作按钮区域 ==================== -->
<div class="section-card action-card"> <div class="section-card action-card">
<div class="action-row"> <div class="section-heading section-heading--compact">
<el-button type="primary" @click="handleOpenNew">新建选修课</el-button> <div>
<el-button type="primary" @click="handleOpenEarly">所选批量开放报名</el-button> <h2 class="section-title">选修课操作</h2>
<el-button type="primary" @click="handleCancelEarly">所选批量取消开放报名</el-button> <p class="section-description">新建选修课或对已选数据执行批量操作</p>
<el-button type="primary" @click="handleStopSignup">批量停止报名</el-button> </div>
<el-button type="primary" @click="handleReverseRange">所选批量根据学员反向确定班次范围</el-button>
</div> </div>
<div class="action-row"> <div class="action-row">
<el-button type="primary" @click="handleDownloadTemplate">选修课数据文件模板下载</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleOpenNew">新建选修课</el-button>
<el-button type="primary" plain icon="el-icon-circle-check" @click="handleOpenEarly">
所选批量开放报名
</el-button>
<el-button type="warning" plain icon="el-icon-remove-outline" @click="handleCancelEarly">
所选批量取消开放报名
</el-button>
<el-button type="danger" plain icon="el-icon-circle-close" @click="handleStopSignup">
批量停止报名
</el-button>
<el-button icon="el-icon-refresh" @click="handleReverseRange">
所选批量根据学员反向确定班次范围
</el-button>
</div>
<div class="action-row">
<el-button icon="el-icon-download" @click="handleDownloadTemplate">选修课数据文件模板下载</el-button>
</div> </div>
</div> </div>
<!-- ==================== 5. 文件上传区域 ==================== --> <!-- ==================== 5. 文件上传区域 ==================== -->
<div class="section-card upload-card"> <div class="section-card upload-card">
<div class="section-heading section-heading--compact">
<div>
<h2 class="section-title">数据导入</h2>
<p class="section-description">选择填写完成的模板文件并上传</p>
</div>
</div>
<div class="upload-row"> <div class="upload-row">
<div class="upload-left"> <div class="upload-left">
<el-button @click="handleSelectFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleSelectFile">选择文件</el-button>
<span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span> <span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span>
<input ref="fileInputRef" type="file" style="display: none" @change="handleFileChange" /> <input ref="fileInputRef" type="file" style="display: none" @change="handleFileChange" />
</div> </div>
<div class="upload-right"> <div class="upload-right">
<el-button type="primary" @click="handleUpload">上传数据</el-button> <el-button type="primary" icon="el-icon-upload2" @click="handleUpload">上传数据</el-button>
</div> </div>
</div> </div>
</div> </div>
<!-- ==================== 6. 数据表格区域 ==================== --> <!-- ==================== 6. 数据表格区域 ==================== -->
<div class="section-card table-card"> <div class="section-card table-card">
<div class="section-heading section-heading--compact table-heading">
<div>
<h2 class="section-title">选修课列表</h2>
<p class="section-description"> {{ total }} 条数据</p>
</div>
</div>
<el-table v-loading="loading" :data="tableData" border stripe class="main-table" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="tableData" border stripe class="main-table" @selection-change="handleSelectionChange">
<template slot="empty"> <template slot="empty">
<span>无数据</span> <span>无数据</span>
@@ -204,12 +243,10 @@ export default {
searchForm: { searchForm: {
js: '', js: '',
kbcnj: '', kbcnj: '',
xxkztEnabled: false, xxkzt: '',
xxkzt: '拟制',
kckmmc: '', kckmmc: '',
xxbmc: '', xxbmc: '',
pxccEnabled: false, pxcc: ''
pxcc: '无'
}, },
// ==================== 数据表格 ==================== // ==================== 数据表格 ====================
@@ -259,8 +296,8 @@ export default {
if (this.searchForm.kbcnj) q.kxbcnj = this.searchForm.kbcnj if (this.searchForm.kbcnj) q.kxbcnj = this.searchForm.kbcnj
if (this.searchForm.kckmmc) q.kmc = this.searchForm.kckmmc if (this.searchForm.kckmmc) q.kmc = this.searchForm.kckmmc
if (this.searchForm.xxbmc) q.xxbmc = this.searchForm.xxbmc if (this.searchForm.xxbmc) q.xxbmc = this.searchForm.xxbmc
if (this.searchForm.xxkztEnabled) q.xkzt = this.searchForm.xxkzt if (this.searchForm.xxkzt) q.xkzt = this.searchForm.xxkzt
if (this.searchForm.pxccEnabled) q.pxcc = this.searchForm.pxcc if (this.searchForm.pxcc) q.pxcc = this.searchForm.pxcc
return q return q
}, },
@@ -423,11 +460,6 @@ export default {
margin-bottom: 14px; margin-bottom: 14px;
min-height: 32px; min-height: 32px;
::v-deep .el-checkbox {
margin-right: 6px;
flex-shrink: 0;
}
.q-label { .q-label {
width: 120px; width: 120px;
flex-shrink: 0; flex-shrink: 0;
@@ -436,10 +468,6 @@ export default {
text-align: right; text-align: right;
margin-right: 10px; margin-right: 10px;
white-space: nowrap; white-space: nowrap;
&.no-check {
margin-left: 24px;
}
} }
.q-control { .q-control {
@@ -447,21 +475,10 @@ export default {
min-width: 0; min-width: 0;
} }
} }
}
.notice { .export-bar {
font-size: 12px; align-items: center;
color: #f56c6c;
margin-top: 8px;
text-align: left;
}
.query-footer {
display: flex;
justify-content: flex-end;
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #ebeef5;
}
} }
// ==================== 4. 操作按钮区域 ==================== // ==================== 4. 操作按钮区域 ====================
@@ -501,6 +518,11 @@ export default {
} }
} }
} }
.upload-right {
display: flex;
align-items: center;
}
} }
} }
@@ -518,23 +540,11 @@ export default {
flex-direction: column; flex-direction: column;
line-height: 1.4; line-height: 1.4;
} }
}
// ==================== 按钮样式 ==================== .pagination-wrap {
.gray-btn { display: flex;
height: 28px; justify-content: flex-end;
padding: 2px 16px; margin-top: 16px;
font-size: 12px;
background: #f5f5f5;
border: 1px solid #c0c4cc;
color: #333;
border-radius: 2px;
&:hover,
&:focus {
background: #ebebeb;
border-color: #c0c4cc;
color: #333;
} }
} }
</style> </style>
@@ -67,7 +67,7 @@
type="text" type="text"
icon="el-icon-circle-close" icon="el-icon-circle-close"
style="color: #f56c6c" style="color: #f56c6c"
:disabled="scope.row.ty" :disabled="scope.row.ty === 1"
@click="handleDisable(scope.row)" @click="handleDisable(scope.row)"
>停用</el-button> >停用</el-button>
</template> </template>
@@ -13,10 +13,10 @@
<div class="info-panel"> <div class="info-panel">
<div class="info-title-row"> <div class="info-title-row">
<span class="semester-name">{{ semesterTitle }}</span> <span class="semester-name">{{ semesterTitle }}</span>
<span class="class-name">{{ semester.xydmc || semester.xydbh || '' }}</span> <span class="class-name">{{ className }}</span>
</div> </div>
<div class="date-range-row"> <div class="date-range-row">
<div class="range-item">学期日期{{ fmtDate(semester.kxrq) }} {{ fmtDate(semester.jsrq) }} {{ semesterWeeks }} </div> <div class="range-item">学期日期{{ fmtDate(safeSemester.kxrq) }} {{ fmtDate(safeSemester.jsrq) }} {{ semesterWeeks }} </div>
<div class="range-item">班历记录{{ records.length }} 总学时 {{ summary.totalXs }}总学分 {{ summary.totalXf }}</div> <div class="range-item">班历记录{{ records.length }} 总学时 {{ summary.totalXs }}总学分 {{ summary.totalXf }}</div>
</div> </div>
</div> </div>
@@ -24,13 +24,13 @@
<!-- ==================== 2. 操作按钮区域 ==================== --> <!-- ==================== 2. 操作按钮区域 ==================== -->
<div class="settings-panel"> <div class="settings-panel">
<div class="action-buttons-row"> <div class="action-buttons-row">
<button type="button" class="blue-btn" @click="handleAdd">新增记录</button> <el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增记录</el-button>
<button type="button" class="gray-btn" @click="handleAutoGenerate">自动生成必修课程</button> <el-button size="small" @click="handleAutoGenerate">自动生成必修课程</el-button>
<button type="button" class="gray-btn" @click="handlePresetMerge">预设合班</button> <el-button size="small" @click="handlePresetMerge">预设合班</el-button>
<button type="button" class="gray-btn" @click="handlePresetSplit">预设拆班</button> <el-button size="small" @click="handlePresetSplit">预设拆班</el-button>
<button type="button" class="gray-btn" @click="handleApplyRegion">选定区域应用于其它班次</button> <el-button size="small" @click="handleApplyRegion">选定区域应用于其它班次</el-button>
<button type="button" class="gray-btn" @click="handleApplyWhole">整个班历应用于其它班次</button> <el-button size="small" @click="handleApplyWhole">整个班历应用于其它班次</el-button>
<button type="button" class="gray-btn" @click="handleRefresh">刷新</button> <el-button size="small" icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
</div> </div>
</div> </div>
@@ -370,14 +370,21 @@ export default {
this.$emit('update:visible', val) this.$emit('update:visible', val)
} }
}, },
safeSemester() {
return this.semester || {}
},
className() {
const s = this.safeSemester
return s.xydmc || s.xydbh || ''
},
semesterTitle() { semesterTitle() {
const s = this.semester || {} const s = this.safeSemester
const nd = s.nd !== undefined && s.nd !== null && s.nd !== '' ? `${s.nd}` : '' const nd = s.nd !== undefined && s.nd !== null && s.nd !== '' ? `${s.nd}` : ''
const xq = this.xqdcLabel(s.xqdc) const xq = this.xqdcLabel(s.xqdc)
return `${nd}${xq}` return `${nd}${xq}`
}, },
semesterWeeks() { semesterWeeks() {
const s = this.semester || {} const s = this.safeSemester
if (!s.kxrq || !s.jsrq) return '-' if (!s.kxrq || !s.jsrq) return '-'
const start = new Date(String(s.kxrq).slice(0, 10)) const start = new Date(String(s.kxrq).slice(0, 10))
const end = new Date(String(s.jsrq).slice(0, 10)) const end = new Date(String(s.jsrq).slice(0, 10))
@@ -741,44 +748,4 @@ export default {
} }
} }
// ========== 银灰色 / 蓝色边框按钮 ==========
.gray-btn {
min-width: 90px;
height: 28px;
padding: 0 14px;
font-size: 12px;
color: #000;
background: linear-gradient(180deg, #fdfdfd 0%, #ececec 50%, #dcdcdc 100%);
border: 1px solid #7a7a7a;
border-radius: 2px;
cursor: pointer;
&:hover {
background: linear-gradient(180deg, #ffffff 0%, #f4f4f4 50%, #e6e6e6 100%);
}
&:active {
background: #c8c8c8;
}
}
.blue-btn {
min-width: 90px;
height: 28px;
padding: 0 14px;
font-size: 12px;
color: #1e6fff;
background: #ecf5ff;
border: 1px solid #1e6fff;
border-radius: 2px;
cursor: pointer;
&:hover {
background: #d9ecff;
}
&:active {
background: #c6e2ff;
}
}
</style> </style>
@@ -53,7 +53,7 @@
<el-table-column label="学期第次" width="90" align="center"> <el-table-column label="学期第次" width="90" align="center">
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template> <template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="xydbh" label="班次编号" min-width="150" align="left" header-align="center" show-overflow-tooltip /> <el-table-column prop="xydbh" label="班次编号" min-width="150" align="center" show-overflow-tooltip />
<el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" /> <el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" />
<el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" /> <el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" />
<el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip /> <el-table-column prop="bz" label="备注" min-width="120" align="left" header-align="center" show-overflow-tooltip />
@@ -62,7 +62,7 @@
</template> </template>
<el-table-column type="selection" width="44" align="center" /> <el-table-column type="selection" width="44" align="center" />
<el-table-column type="index" label="序号" width="55" align="center" /> <el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="xydbh" label="班次编号" min-width="150" align="left" header-align="center" show-overflow-tooltip /> <el-table-column prop="xydbh" label="班次编号" min-width="150" align="center" show-overflow-tooltip />
<el-table-column prop="nd" label="年度" width="80" align="center" show-overflow-tooltip /> <el-table-column prop="nd" label="年度" width="80" align="center" show-overflow-tooltip />
<el-table-column label="学期第次" width="90" align="center"> <el-table-column label="学期第次" width="90" align="center">
<template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template> <template slot-scope="{ row }">{{ xqdcLabel(row.xqdc) }}</template>
@@ -70,7 +70,7 @@
<el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" /> <el-table-column prop="kxrq" label="开学日期" width="110" align="center" :formatter="fmtDate" />
<el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" /> <el-table-column prop="jsrq" label="结束日期" width="110" align="center" :formatter="fmtDate" />
<el-table-column prop="zyjsbh" label="专用教室" width="100" align="center" show-overflow-tooltip /> <el-table-column prop="zyjsbh" label="专用教室" width="100" align="center" show-overflow-tooltip />
<el-table-column label="教学任务" min-width="160" align="left" header-align="center" show-overflow-tooltip> <el-table-column label="教学任务" min-width="160" align="center" show-overflow-tooltip>
<template slot-scope="{ row }">{{ taskName(row.jxrwbh) }}</template> <template slot-scope="{ row }">{{ taskName(row.jxrwbh) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="开放教员排课" width="110" align="center"> <el-table-column label="开放教员排课" width="110" align="center">
@@ -1,8 +1,15 @@
<template> <template>
<div class="app-container subject-page"> <div class="app-container management-page subject-page">
<!-- ==================== 2. 查询条件区域 ==================== --> <!-- ==================== 2. 查询条件区域 ==================== -->
<el-card shadow="never" class="search-card"> <el-card shadow="never" class="search-card">
<div class="section-heading">
<div>
<h2 class="section-title">筛选条件</h2>
<p class="section-description">按课程名称代码和培训属性筛选课程科目</p>
</div>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
</div>
<el-form :model="searchForm"> <el-form :model="searchForm">
<el-row :gutter="32"> <el-row :gutter="32">
<!-- 左栏 --> <!-- 左栏 -->
@@ -43,41 +50,56 @@
</el-row> </el-row>
</el-form> </el-form>
<div class="query-footer">
<el-button class="gray-btn" @click="handleQuery">查询</el-button>
</div>
</el-card> </el-card>
<!-- ==================== 3. 操作按钮区域 ==================== --> <!-- ==================== 3. 操作按钮区域 ==================== -->
<el-card shadow="never" class="action-card"> <el-card shadow="never" class="action-card">
<div class="action-row"> <div class="section-heading section-heading--compact">
<el-button type="primary" @click="handleOpenDialog">新建课程科目</el-button> <div>
<el-button type="primary" @click="handleBatchDelete">删除所选</el-button> <h2 class="section-title">课程科目操作</h2>
<el-button type="primary" @click="handleDownloadCourse">下载课程科目基本信息</el-button> <p class="section-description">维护课程科目或下载业务数据与导入模板</p>
<el-button type="primary" @click="handleDownloadTextbook">下载课程教材基本信息</el-button> </div>
</div> </div>
<div class="action-row"> <div class="action-row">
<el-button type="primary" @click="handleDownloadTemplate">课程科目数据文件模板下载</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleOpenDialog">新建课程科目</el-button>
<el-button type="danger" plain icon="el-icon-delete" @click="handleBatchDelete">删除所选</el-button>
<el-button icon="el-icon-download" @click="handleDownloadCourse">下载课程科目基本信息</el-button>
<el-button icon="el-icon-download" @click="handleDownloadTextbook">下载课程教材基本信息</el-button>
</div>
<div class="action-row">
<el-button icon="el-icon-download" @click="handleDownloadTemplate">课程科目数据文件模板下载</el-button>
</div> </div>
</el-card> </el-card>
<!-- ==================== 4. 文件上传区域 ==================== --> <!-- ==================== 4. 文件上传区域 ==================== -->
<el-card shadow="never" class="upload-card"> <el-card shadow="never" class="upload-card">
<div class="section-heading section-heading--compact">
<div>
<h2 class="section-title">数据导入</h2>
<p class="section-description">选择填写完成的课程科目模板并上传</p>
</div>
</div>
<div class="upload-row"> <div class="upload-row">
<div class="upload-left"> <div class="upload-left">
<el-button @click="handleSelectFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleSelectFile">选择文件</el-button>
<span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span> <span class="file-name" :class="{ 'has-file': selectedFile }">{{ fileName }}</span>
<input ref="fileInputRef" type="file" style="display: none" @change="handleFileChange" /> <input ref="fileInputRef" type="file" style="display: none" @change="handleFileChange" />
</div> </div>
<div class="upload-right"> <div class="upload-right">
<el-checkbox v-model="coverExist">覆盖已存在课程科目</el-checkbox> <el-checkbox v-model="coverExist">覆盖已存在课程科目</el-checkbox>
<el-button type="primary" @click="handleUpload">上传数据</el-button> <el-button type="primary" icon="el-icon-upload2" @click="handleUpload">上传数据</el-button>
</div> </div>
</div> </div>
</el-card> </el-card>
<!-- ==================== 6. 数据表格区域 ==================== --> <!-- ==================== 6. 数据表格区域 ==================== -->
<el-card shadow="never" class="table-card"> <el-card shadow="never" class="table-card">
<div class="section-heading section-heading--compact table-heading">
<div>
<h2 class="section-title">课程科目列表</h2>
<p class="section-description"> {{ total }} 条数据</p>
</div>
</div>
<el-table v-loading="loading" :data="tableData" stripe border highlight-current-row <el-table v-loading="loading" :data="tableData" stripe border highlight-current-row
@selection-change="handleSelectionChange"> @selection-change="handleSelectionChange">
<el-table-column type="selection" width="40" align="center" /> <el-table-column type="selection" width="40" align="center" />
@@ -622,13 +644,6 @@ export default {
text-align: left; text-align: left;
} }
.query-footer {
display: flex;
justify-content: flex-end;
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #ebeef5;
}
} }
// ==================== 3. 操作按钮区域 ==================== // ==================== 3. 操作按钮区域 ====================
@@ -726,20 +741,4 @@ export default {
gap: 12px; gap: 12px;
} }
.gray-btn {
height: 28px;
padding: 2px 16px;
font-size: 12px;
background: #f5f5f5;
border: 1px solid #c0c4cc;
color: #333;
border-radius: 2px;
&:hover,
&:focus {
background: #ebebeb;
border-color: #c0c4cc;
color: #333;
}
}
</style> </style>
@@ -50,8 +50,8 @@
<span>无数据</span> <span>无数据</span>
</template> </template>
<el-table-column type="index" label="序号" width="70" align="center" /> <el-table-column type="index" label="序号" width="70" align="center" />
<el-table-column prop="rwmc" label="任务名称" min-width="180" align="left" header-align="center" show-overflow-tooltip /> <el-table-column prop="rwmc" label="任务名称" width="250" align="center" show-overflow-tooltip />
<el-table-column prop="nd" label="年度" width="90" align="center" /> <el-table-column prop="nd" label="年度" width="150" align="center" />
<el-table-column label="状态" width="100" align="center"> <el-table-column label="状态" width="100" align="center">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-tag :type="row.zt === '发布' ? 'success' : 'info'" size="small"> <el-tag :type="row.zt === '发布' ? 'success' : 'info'" size="small">
@@ -59,11 +59,11 @@
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="fbsj" label="发布时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="fbsj" label="发布时间" width="180" align="center" :formatter="fmtDateTime" />
<el-table-column prop="jssj" label="结束时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="jssj" label="结束时间" width="180" align="center" :formatter="fmtDateTime" />
<el-table-column prop="cjsj" label="创建时间" width="150" align="center" :formatter="fmtDateTime" /> <el-table-column prop="cjsj" label="创建时间" width="180" align="center" :formatter="fmtDateTime" />
<el-table-column prop="jcxqscsj" label="教材需求生成时间" width="170" align="center" :formatter="fmtDateTime" /> <el-table-column prop="jcxqscsj" label="教材需求生成时间" align="center" :formatter="fmtDateTime" />
<el-table-column label="操作" width="200" align="center" fixed="right"> <el-table-column label="操作" width="300" align="center" fixed="right">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-button type="text" size="small" @click="handleDetail(row)">详情</el-button> <el-button type="text" size="small" @click="handleDetail(row)">详情</el-button>
<el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button> <el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
@@ -177,7 +177,7 @@
</el-descriptions> </el-descriptions>
<div v-else v-loading="detailLoading" class="detail-empty">加载中...</div> <div v-else v-loading="detailLoading" class="detail-empty">加载中...</div>
<div slot="footer"> <div slot="footer">
<el-button type="primary" @click="detailVisible = false">关闭</el-button> <el-button @click="detailVisible = false">关闭</el-button>
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
@@ -37,11 +37,11 @@
<div class="list-toolbar"> <div class="list-toolbar">
<div class="left-group"> <div class="left-group">
<el-button type="primary" icon="el-icon-plus" @click="handleNew">新建</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleNew">新建</el-button>
<el-button type="primary" icon="el-icon-delete" @click="handleDeleteSelected">删除所选</el-button> <el-button type="danger" plain icon="el-icon-delete" @click="handleDeleteSelected">删除所选</el-button>
<el-button type="primary" icon="el-icon-upload" @click="handleImport">导入教员信息</el-button> <el-button icon="el-icon-upload" @click="handleImport">导入教员信息</el-button>
</div> </div>
<div class="right-group"> <div class="right-group">
<el-button type="primary" icon="el-icon-download" @click="handleDownloadTemplate">教员数据文件模板下载</el-button> <el-button icon="el-icon-download" @click="handleDownloadTemplate">教员数据文件模板下载</el-button>
</div> </div>
</div> </div>
@@ -50,26 +50,26 @@
@selection-change="handleSelectionChange"> @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" /> <el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="jybh" label="教员工号" min-width="110" align="center" /> <el-table-column prop="jybh" label="教员工号" width="110" align="center" />
<el-table-column prop="jyxm" label="教员姓名" min-width="90" align="center" /> <el-table-column prop="jyxm" label="教员姓名" width="90" align="center" />
<el-table-column label="性别" min-width="60" align="center"> <el-table-column label="性别" width="60" align="center">
<template slot-scope="{ row }">{{ fmtGender(row.xb) }}</template> <template slot-scope="{ row }">{{ fmtGender(row.xb) }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="jysmc" label="教研室名称" min-width="120" show-overflow-tooltip /> <el-table-column prop="jysmc" label="教研室名称" width="200" show-overflow-tooltip align="center"/>
<el-table-column prop="zc" label="职称" min-width="90" align="center" /> <el-table-column prop="zc" label="职称" width="120" align="center" />
<el-table-column prop="xl" label="学历" min-width="90" align="center" /> <el-table-column prop="xl" label="学历" width="120" align="center" />
<el-table-column prop="xw" label="学位" min-width="90" align="center" /> <el-table-column prop="xw" label="学位" width="120" align="center" />
<el-table-column label="出生时间" min-width="110" align="center"> <el-table-column label="出生时间" width="110" align="center">
<template slot-scope="{ row }">{{ fmtDateTime(row.cssj) || '-' }}</template> <template slot-scope="{ row }">{{ fmtDateTime(row.cssj) || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column label="入伍工作时间" min-width="120" align="center"> <el-table-column label="入伍工作时间" width="120" align="center">
<template slot-scope="{ row }">{{ fmtDateTime(row.rwgzsj) || '-' }}</template> <template slot-scope="{ row }">{{ fmtDateTime(row.rwgzsj) || '-' }}</template>
</el-table-column> </el-table-column>
<el-table-column prop="sjh" label="联系方式" min-width="110" align="center" /> <el-table-column prop="sjh" label="联系方式" width="110" align="center" />
<el-table-column label="虚实类型" min-width="80" align="center"> <el-table-column label="虚实类型" width="80" align="center">
<template slot-scope="{ row }">{{ fmtXslx(row.xslx) }}</template> <template slot-scope="{ row }">{{ fmtXslx(row.xslx) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="180" align="center" fixed="right"> <el-table-column label="操作" align="center" fixed="right">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<el-button type="text" size="small" icon="el-icon-view" @click="handleViewAttribute(row)">查看属性</el-button> <el-button type="text" size="small" icon="el-icon-view" @click="handleViewAttribute(row)">查看属性</el-button>
<el-button type="text" size="small" icon="el-icon-edit" @click="handleEdit(row)">编辑</el-button> <el-button type="text" size="small" icon="el-icon-edit" @click="handleEdit(row)">编辑</el-button>
@@ -5,40 +5,28 @@
<el-form :model="searchForm" label-width="110px" class="search-form"> <el-form :model="searchForm" label-width="110px" class="search-form">
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="开始日期">
<template slot="label">
<el-checkbox v-model="searchForm.ksrqEnabled">开始日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.ksrq" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期" <el-date-picker v-model="searchForm.ksrq" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期"
class="w-full" :disabled="!searchForm.ksrqEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="结束日期">
<template slot="label">
<el-checkbox v-model="searchForm.jsrqEnabled">结束日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.jsrq" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期" <el-date-picker v-model="searchForm.jsrq" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期"
class="w-full" :disabled="!searchForm.jsrqEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="课程名称">
<template slot="label"> <el-input v-model="searchForm.kcmc" placeholder="请输入课程名称" clearable />
<el-checkbox v-model="searchForm.kcmcEnabled">课程名称</el-checkbox>
</template>
<el-input v-model="searchForm.kcmc" placeholder="请输入课程名称" clearable :disabled="!searchForm.kcmcEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教研室">
<template slot="label"> <el-select v-model="searchForm.jys" placeholder="请选择教研室" clearable class="w-full">
<el-checkbox v-model="searchForm.jysEnabled">教研室</el-checkbox>
</template>
<el-select v-model="searchForm.jys" placeholder="请选择教研室" class="w-full" :disabled="!searchForm.jysEnabled">
<el-option v-for="item in jysOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in jysOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -47,21 +35,15 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教学方法">
<template slot="label"> <el-select v-model="searchForm.jxff" placeholder="请选择教学方法" clearable class="w-full">
<el-checkbox v-model="searchForm.jxffEnabled">教学方法</el-checkbox>
</template>
<el-select v-model="searchForm.jxff" placeholder="请选择教学方法" class="w-full" :disabled="!searchForm.jxffEnabled">
<el-option v-for="item in jxffOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in jxffOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="授课教员">
<template slot="label"> <el-select v-model="searchForm.skjy" placeholder="请选择授课教员" clearable class="w-full">
<el-checkbox v-model="searchForm.skjyEnabled">授课教员</el-checkbox>
</template>
<el-select v-model="searchForm.skjy" placeholder="请选择授课教员" class="w-full" :disabled="!searchForm.skjyEnabled">
<el-option v-for="item in skjyOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in skjyOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -70,15 +52,12 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="24"> <el-col :span="24">
<el-form-item> <el-form-item label="改动情况">
<template slot="label"> <div class="change-options">
<el-checkbox v-model="searchForm.gdqkEnabled">改动情况</el-checkbox> <el-radio-group v-model="searchForm.createSource">
</template>
<div class="change-options" :class="{ disabled: !searchForm.gdqkEnabled }">
<el-radio-group v-model="searchForm.createSource" :disabled="!searchForm.gdqkEnabled">
<el-radio v-for="item in createSourceOptions" :key="item" :label="item">{{ item }}</el-radio> <el-radio v-for="item in createSourceOptions" :key="item" :label="item">{{ item }}</el-radio>
</el-radio-group> </el-radio-group>
<el-checkbox-group v-model="searchForm.changeTypes" :disabled="!searchForm.gdqkEnabled"> <el-checkbox-group v-model="searchForm.changeTypes">
<el-checkbox v-for="item in changeTypeOptions" :key="item" :label="item">{{ item }}</el-checkbox> <el-checkbox v-for="item in changeTypeOptions" :key="item" :label="item">{{ item }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
@@ -88,21 +67,15 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="任务类别">
<template slot="label"> <el-select v-model="searchForm.rwlb" placeholder="请选择任务类别" clearable class="w-full">
<el-checkbox v-model="searchForm.rwlbEnabled">任务类别</el-checkbox>
</template>
<el-select v-model="searchForm.rwlb" placeholder="请选择任务类别" class="w-full" :disabled="!searchForm.rwlbEnabled">
<el-option v-for="item in rwlbOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in rwlbOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="培训期班">
<template slot="label"> <el-input v-model="searchForm.pxqb" placeholder="请输入培训期班" clearable />
<el-checkbox v-model="searchForm.pxqbEnabled">培训期班</el-checkbox>
</template>
<el-input v-model="searchForm.pxqb" placeholder="请输入培训期班" clearable :disabled="!searchForm.pxqbEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -141,7 +114,7 @@
<el-table-column prop="zt" label="日志状态" width="100" align="center" /> <el-table-column prop="zt" label="日志状态" width="100" align="center" />
<el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip /> <el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip />
<el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" /> <el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" />
<el-table-column label="详细" width="80" align="center" fixed="right"> <el-table-column label="操作" width="80" align="center" fixed="right" class-name="table-action-column">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" @click="handleDetail(scope.row)">详细</el-button> <el-button type="text" @click="handleDetail(scope.row)">详细</el-button>
</template> </template>
@@ -203,24 +176,15 @@ export default {
// ==================== 查询表单 ==================== // ==================== 查询表单 ====================
searchForm: { searchForm: {
ksrq: '', ksrq: '',
ksrqEnabled: false,
jsrq: '', jsrq: '',
jsrqEnabled: false,
kcmc: '', kcmc: '',
kcmcEnabled: false,
jys: '', jys: '',
jysEnabled: false, jxff: '',
jxff: '理论讲授', skjy: '',
jxffEnabled: false,
skjy: '教务处',
skjyEnabled: false,
gdqkEnabled: false,
createSource: '', createSource: '',
changeTypes: [], changeTypes: [],
rwlb: '全军院校训练规划内任务', rwlb: '',
rwlbEnabled: false, pxqb: ''
pxqb: '',
pxqbEnabled: false
}, },
jysOptions: ['教研室', '防空兵系', '通信工程系', '装甲兵系'], jysOptions: ['教研室', '防空兵系', '通信工程系', '装甲兵系'],
@@ -261,20 +225,20 @@ export default {
this.selectedRows = rows this.selectedRows = rows
}, },
/** 根据"勾选启用"模式构建实际查询参数 */ /** 根据已填写的查询值构建实际查询参数 */
buildSearchParams() { buildSearchParams() {
const form = this.searchForm const form = this.searchForm
const params = { pageNum: this.pageNum, pageSize: this.pageSize } const params = { pageNum: this.pageNum, pageSize: this.pageSize }
if (form.ksrqEnabled && form.ksrq) params.ksrq = form.ksrq if (form.ksrq) params.ksrq = form.ksrq
if (form.jsrqEnabled && form.jsrq) params.jsrq = form.jsrq if (form.jsrq) params.jsrq = form.jsrq
if (form.kcmcEnabled && form.kcmc) params.kcmc = form.kcmc if (form.kcmc) params.kcmc = form.kcmc
if (form.jysEnabled && form.jys) params.jys = form.jys if (form.jys) params.jys = form.jys
if (form.jxffEnabled && form.jxff) params.jxff = form.jxff if (form.jxff) params.jxff = form.jxff
if (form.skjyEnabled && form.skjy) params.skjy = form.skjy if (form.skjy) params.skjy = form.skjy
if (form.rwlbEnabled && form.rwlb) params.rwlb = form.rwlb if (form.rwlb) params.rwlb = form.rwlb
if (form.pxqbEnabled && form.pxqb) params.pxqb = form.pxqb if (form.pxqb) params.pxqb = form.pxqb
if (form.gdqkEnabled && form.createSource) params.gdqk = form.createSource if (form.createSource) params.gdqk = form.createSource
if (form.gdqkEnabled && form.changeTypes.length > 0) { if (form.changeTypes.length > 0) {
params.gdxxqk = form.changeTypes.join(',') params.gdxxqk = form.changeTypes.join(',')
} }
return params return params
@@ -393,9 +357,6 @@ export default {
gap: 12px; gap: 12px;
} }
&.disabled {
opacity: 0.6;
}
} }
} }
@@ -5,40 +5,28 @@
<el-form :model="searchForm" label-width="110px" class="search-form"> <el-form :model="searchForm" label-width="110px" class="search-form">
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="开始日期">
<template slot="label">
<el-checkbox v-model="searchForm.ksrqEnabled">开始日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.ksrq" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期" <el-date-picker v-model="searchForm.ksrq" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期"
class="w-full" :disabled="!searchForm.ksrqEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="结束日期">
<template slot="label">
<el-checkbox v-model="searchForm.jsrqEnabled">结束日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.jsrq" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期" <el-date-picker v-model="searchForm.jsrq" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期"
class="w-full" :disabled="!searchForm.jsrqEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="课程名称">
<template slot="label"> <el-input v-model="searchForm.kcmc" placeholder="请输入课程名称" clearable />
<el-checkbox v-model="searchForm.kcmcEnabled">课程名称</el-checkbox>
</template>
<el-input v-model="searchForm.kcmc" placeholder="请输入课程名称" clearable :disabled="!searchForm.kcmcEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教研室">
<template slot="label"> <el-select v-model="searchForm.jys" placeholder="请选择教研室" clearable class="w-full">
<el-checkbox v-model="searchForm.jysEnabled">教研室</el-checkbox>
</template>
<el-select v-model="searchForm.jys" placeholder="请选择教研室" class="w-full" :disabled="!searchForm.jysEnabled">
<el-option v-for="item in jysOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in jysOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -47,21 +35,15 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教学方法">
<template slot="label"> <el-select v-model="searchForm.jxff" placeholder="请选择教学方法" clearable class="w-full">
<el-checkbox v-model="searchForm.jxffEnabled">教学方法</el-checkbox>
</template>
<el-select v-model="searchForm.jxff" placeholder="请选择教学方法" class="w-full" :disabled="!searchForm.jxffEnabled">
<el-option v-for="item in jxffOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in jxffOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="日志状态">
<template slot="label"> <el-select v-model="searchForm.rzzt" placeholder="请选择日志状态" clearable class="w-full">
<el-checkbox v-model="searchForm.rzztEnabled">日志状态</el-checkbox>
</template>
<el-select v-model="searchForm.rzzt" placeholder="请选择日志状态" class="w-full" :disabled="!searchForm.rzztEnabled">
<el-option v-for="item in rzztOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in rzztOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -70,37 +52,28 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="授课教员">
<template slot="label"> <el-select v-model="searchForm.skjy" placeholder="请选择授课教员" clearable class="w-full">
<el-checkbox v-model="searchForm.skjyEnabled">授课教员</el-checkbox>
</template>
<el-select v-model="searchForm.skjy" placeholder="请选择授课教员" class="w-full" :disabled="!searchForm.skjyEnabled">
<el-option v-for="item in skjyOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in skjyOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="培训期班">
<template slot="label"> <el-input v-model="searchForm.pxqb" placeholder="请输入培训期班" clearable />
<el-checkbox v-model="searchForm.pxqbEnabled">培训期班</el-checkbox>
</template>
<el-input v-model="searchForm.pxqb" placeholder="请输入培训期班" clearable :disabled="!searchForm.pxqbEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="改动情况">
<template slot="label"> <div class="change-options">
<el-checkbox v-model="searchForm.changeTypeEnabled">改动情况</el-checkbox> <el-radio-group v-model="searchForm.changeType">
</template>
<div class="change-options" :class="{ disabled: !searchForm.changeTypeEnabled }">
<el-radio-group v-model="searchForm.changeType" :disabled="!searchForm.changeTypeEnabled">
<el-radio v-for="item in changeTypeOptions" :key="item.value" :label="item.value">{{ item.label <el-radio v-for="item in changeTypeOptions" :key="item.value" :label="item.value">{{ item.label
}}</el-radio> }}</el-radio>
</el-radio-group> </el-radio-group>
<el-checkbox-group v-model="searchForm.changeTypes" :disabled="!searchForm.changeTypeEnabled"> <el-checkbox-group v-model="searchForm.changeTypes">
<el-checkbox v-for="item in changeTypeList" :key="item.value" :label="item.value">{{ item.label <el-checkbox v-for="item in changeTypeList" :key="item.value" :label="item.value">{{ item.label
}}</el-checkbox> }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
@@ -108,11 +81,8 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="任务类别">
<template slot="label"> <el-select v-model="searchForm.rwlb" placeholder="请选择任务类别" clearable class="w-full">
<el-checkbox v-model="searchForm.rwlbEnabled">任务类别</el-checkbox>
</template>
<el-select v-model="searchForm.rwlb" placeholder="请选择任务类别" class="w-full" :disabled="!searchForm.rwlbEnabled">
<el-option v-for="item in rwlbOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in rwlbOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -122,13 +92,13 @@
<div class="search-actions"> <div class="search-actions">
<div class="left-group"> <div class="left-group">
<el-button type="primary" @click="handleDeleteSelected">删除所选</el-button> <el-button type="danger" plain @click="handleDeleteSelected">删除所选</el-button>
<el-button type="primary" @click="handleBatchReport">批准上报所选</el-button> <el-button type="primary" @click="handleBatchReport">批准上报所选</el-button>
<el-button type="primary" @click="handleRecheck">重新检查通报变更情况</el-button> <el-button @click="handleRecheck">重新检查通报变更情况</el-button>
<el-button type="primary" @click="handleExport">导出到 Word</el-button> <el-button icon="el-icon-download" @click="handleExport">导出到 Word</el-button>
<el-button type="primary" @click="handleRefresh">刷新</el-button> <el-button icon="el-icon-refresh" @click="handleRefresh">刷新</el-button>
<el-button type="success" :loading="importing" @click="handleImportExcel">导入教学日志</el-button> <el-button icon="el-icon-upload2" :loading="importing" @click="handleImportExcel">导入教学日志</el-button>
<el-button type="primary" @click="handleDownloadTemplate">下载模板</el-button> <el-button icon="el-icon-download" @click="handleDownloadTemplate">下载模板</el-button>
</div> </div>
<el-button type="primary" @click="handleSearch">查询</el-button> <el-button type="primary" @click="handleSearch">查询</el-button>
</div> </div>
@@ -165,7 +135,7 @@
<el-table-column prop="zt" label="日志状态" width="100" align="center" /> <el-table-column prop="zt" label="日志状态" width="100" align="center" />
<el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip /> <el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip />
<el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" /> <el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" />
<el-table-column label="详细" width="80" align="center" fixed="right"> <el-table-column label="操作" width="80" align="center" fixed="right" class-name="table-action-column">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" @click="handleDetail(scope.row)">详细</el-button> <el-button type="text" @click="handleDetail(scope.row)">详细</el-button>
</template> </template>
@@ -234,26 +204,16 @@ export default {
// ==================== 查询表单 ==================== // ==================== 查询表单 ====================
searchForm: { searchForm: {
ksrq: '', ksrq: '',
ksrqEnabled: false,
jsrq: '', jsrq: '',
jsrqEnabled: false,
kcmc: '', kcmc: '',
kcmcEnabled: false, jys: '',
jys: '教研室', jxff: '',
jysEnabled: false, rzzt: '',
jxff: '理论讲授', skjy: '',
jxffEnabled: false,
rzzt: '教务部门导入教员类',
rzztEnabled: false,
skjy: '教务处',
skjyEnabled: false,
pxqb: '', pxqb: '',
pxqbEnabled: false, changeType: '',
changeType: '与教学计划一致',
changeTypeEnabled: false,
changeTypes: [], changeTypes: [],
rwlb: '全军院校训练规划内任务', rwlb: ''
rwlbEnabled: false
}, },
jysOptions: ['教研室', '防空兵系', '通信工程系', '装甲兵系'], jysOptions: ['教研室', '防空兵系', '通信工程系', '装甲兵系'],
@@ -301,21 +261,21 @@ export default {
this.selectedRows = rows this.selectedRows = rows
}, },
/** 根据"勾选启用"模式构建实际查询参数 */ /** 根据已填写的查询值构建实际查询参数 */
buildSearchParams() { buildSearchParams() {
const form = this.searchForm const form = this.searchForm
const params = { pageNum: this.pageNum, pageSize: this.pageSize } const params = { pageNum: this.pageNum, pageSize: this.pageSize }
if (form.ksrqEnabled && form.ksrq) params.ksrq = form.ksrq if (form.ksrq) params.ksrq = form.ksrq
if (form.jsrqEnabled && form.jsrq) params.jsrq = form.jsrq if (form.jsrq) params.jsrq = form.jsrq
if (form.kcmcEnabled && form.kcmc) params.kcmc = form.kcmc if (form.kcmc) params.kcmc = form.kcmc
if (form.jysEnabled && form.jys) params.jys = form.jys if (form.jys) params.jys = form.jys
if (form.jxffEnabled && form.jxff) params.jxff = form.jxff if (form.jxff) params.jxff = form.jxff
if (form.rzztEnabled && form.rzzt) params.rzzt = form.rzzt if (form.rzzt) params.rzzt = form.rzzt
if (form.skjyEnabled && form.skjy) params.skjy = form.skjy if (form.skjy) params.skjy = form.skjy
if (form.pxqbEnabled && form.pxqb) params.pxqb = form.pxqb if (form.pxqb) params.pxqb = form.pxqb
if (form.rwlbEnabled && form.rwlb) params.rwlb = form.rwlb if (form.rwlb) params.rwlb = form.rwlb
if (form.changeTypeEnabled && form.changeType) params.gdqk = form.changeType if (form.changeType) params.gdqk = form.changeType
if (form.changeTypeEnabled && form.changeTypes.length > 0) { if (form.changeTypes.length > 0) {
params.gdxxqk = form.changeTypes.join(',') params.gdxxqk = form.changeTypes.join(',')
} }
return params return params
@@ -544,9 +504,6 @@ export default {
gap: 12px; gap: 12px;
} }
&.disabled {
opacity: 0.6;
}
} }
} }
@@ -5,42 +5,28 @@
<el-form :model="searchForm" label-width="110px" class="search-form"> <el-form :model="searchForm" label-width="110px" class="search-form">
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="开始日期">
<template slot="label">
<el-checkbox v-model="searchForm.startDateEnabled">开始日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.startDate" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期" <el-date-picker v-model="searchForm.startDate" type="date" value-format="yyyy-MM-dd" placeholder="选择开始日期"
class="w-full" :disabled="!searchForm.startDateEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="结束日期">
<template slot="label">
<el-checkbox v-model="searchForm.endDateEnabled">结束日期</el-checkbox>
</template>
<el-date-picker v-model="searchForm.endDate" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期" <el-date-picker v-model="searchForm.endDate" type="date" value-format="yyyy-MM-dd" placeholder="选择结束日期"
class="w-full" :disabled="!searchForm.endDateEnabled" /> class="w-full" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="课程名称">
<template slot="label"> <el-input v-model="searchForm.courseName" placeholder="请输入课程名称" clearable />
<el-checkbox v-model="searchForm.courseNameEnabled">课程名称</el-checkbox>
</template>
<el-input v-model="searchForm.courseName" placeholder="请输入课程名称" clearable
:disabled="!searchForm.courseNameEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教学方法">
<template slot="label"> <el-select v-model="searchForm.teachMethod" placeholder="请选择教学方法" clearable class="w-full">
<el-checkbox v-model="searchForm.teachMethodEnabled">教学方法</el-checkbox>
</template>
<el-select v-model="searchForm.teachMethod" placeholder="请选择教学方法" class="w-full"
:disabled="!searchForm.teachMethodEnabled">
<el-option v-for="item in teachMethodOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in teachMethodOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -49,22 +35,15 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="改动情况">
<template slot="label"> <el-select v-model="searchForm.change" placeholder="请选择改动情况" clearable class="w-full">
<el-checkbox v-model="searchForm.changeEnabled">改动情况</el-checkbox>
</template>
<el-select v-model="searchForm.change" placeholder="请选择改动情况" class="w-full" :disabled="!searchForm.changeEnabled">
<el-option v-for="item in changeOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in changeOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="任务类别">
<template slot="label"> <el-select v-model="searchForm.taskCategory" placeholder="请选择任务类别" clearable class="w-full">
<el-checkbox v-model="searchForm.taskCategoryEnabled">任务类别</el-checkbox>
</template>
<el-select v-model="searchForm.taskCategory" placeholder="请选择任务类别" class="w-full"
:disabled="!searchForm.taskCategoryEnabled">
<el-option v-for="item in taskCategoryOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in taskCategoryOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -73,22 +52,15 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="教研室">
<template slot="label"> <el-select v-model="searchForm.dept" placeholder="请选择教研室" clearable class="w-full">
<el-checkbox v-model="searchForm.deptEnabled">教研室</el-checkbox>
</template>
<el-select v-model="searchForm.dept" placeholder="请选择教研室" class="w-full" :disabled="!searchForm.deptEnabled">
<el-option v-for="item in deptOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in deptOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="授课教员">
<template slot="label"> <el-select v-model="searchForm.teacher" placeholder="请选择授课教员" clearable class="w-full">
<el-checkbox v-model="searchForm.teacherEnabled">授课教员</el-checkbox>
</template>
<el-select v-model="searchForm.teacher" placeholder="请选择授课教员" class="w-full"
:disabled="!searchForm.teacherEnabled">
<el-option v-for="item in teacherOptions" :key="item" :label="item" :value="item" /> <el-option v-for="item in teacherOptions" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -97,12 +69,8 @@
<el-row :gutter="0"> <el-row :gutter="0">
<el-col :span="12"> <el-col :span="12">
<el-form-item> <el-form-item label="培训班">
<template slot="label"> <el-input v-model="searchForm.className" placeholder="请输入培训班" clearable />
<el-checkbox v-model="searchForm.classNameEnabled">培训班</el-checkbox>
</template>
<el-input v-model="searchForm.className" placeholder="请输入培训班" clearable
:disabled="!searchForm.classNameEnabled" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@@ -110,12 +78,12 @@
<div class="search-actions"> <div class="search-actions">
<div class="left-group"> <div class="left-group">
<el-button type="primary" @click="handleDelete">删除所选</el-button> <el-button type="danger" plain @click="handleDelete">删除所选</el-button>
<el-button type="primary" @click="handleAudit">审核通过所选</el-button> <el-button type="primary" @click="handleAudit">审核通过所选</el-button>
<el-input v-model="remark" placeholder="退回原因/意见" clearable class="action-input" /> <el-input v-model="remark" placeholder="退回原因/意见" clearable class="action-input" />
<el-button type="primary" @click="handleWithdraw">撤回重填所选</el-button> <el-button type="warning" plain @click="handleWithdraw">撤回重填所选</el-button>
<el-button type="primary" @click="handleRecheck">重新检查所选变更情况</el-button> <el-button @click="handleRecheck">重新检查所选变更情况</el-button>
<el-button type="primary" @click="handleExport">导出到 Word</el-button> <el-button icon="el-icon-download" @click="handleExport">导出到 Word</el-button>
</div> </div>
<div class="right-group"> <div class="right-group">
<el-button @click="handleReset">重置</el-button> <el-button @click="handleReset">重置</el-button>
@@ -152,7 +120,7 @@
<el-table-column prop="zt" label="日志状态" width="100" align="center" /> <el-table-column prop="zt" label="日志状态" width="100" align="center" />
<el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip /> <el-table-column prop="gdqk" label="变动汇总" min-width="120" show-overflow-tooltip />
<el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" /> <el-table-column prop="jxrzcjfs" label="创建方式" width="100" align="center" />
<el-table-column label="详细" width="80" align="center" fixed="right"> <el-table-column label="操作" width="80" align="center" fixed="right" class-name="table-action-column">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button type="text" @click="handleDetail(scope.row)">详细</el-button> <el-button type="text" @click="handleDetail(scope.row)">详细</el-button>
</template> </template>
@@ -220,23 +188,14 @@ export default {
// ==================== 查询表单 ==================== // ==================== 查询表单 ====================
searchForm: { searchForm: {
startDate: '', startDate: '',
startDateEnabled: false,
endDate: '', endDate: '',
endDateEnabled: false,
courseName: '', courseName: '',
courseNameEnabled: false, teachMethod: '',
teachMethod: '理论讲授', change: '',
teachMethodEnabled: false, taskCategory: '',
change: '与教学计划一致', dept: '',
changeEnabled: false, teacher: '',
taskCategory: '全军院校训练规划内任务', className: ''
taskCategoryEnabled: false,
dept: '教务处',
deptEnabled: false,
teacher: '教务处',
teacherEnabled: false,
className: '',
classNameEnabled: false
}, },
teachMethodOptions: ['理论讲授', '实践教学', '研讨教学', '案例教学', '实操演练'], teachMethodOptions: ['理论讲授', '实践教学', '研讨教学', '案例教学', '实操演练'],
@@ -282,19 +241,19 @@ export default {
this.selectedRows = rows this.selectedRows = rows
}, },
/** 根据"勾选启用"模式构建实际查询参数 */ /** 根据已填写的查询值构建实际查询参数 */
buildSearchParams() { buildSearchParams() {
const form = this.searchForm const form = this.searchForm
const params = { pageNum: this.pageNum, pageSize: this.pageSize } const params = { pageNum: this.pageNum, pageSize: this.pageSize }
if (form.startDateEnabled && form.startDate) params.ksrq = form.startDate if (form.startDate) params.ksrq = form.startDate
if (form.endDateEnabled && form.endDate) params.jsrq = form.endDate if (form.endDate) params.jsrq = form.endDate
if (form.courseNameEnabled && form.courseName) params.kcmc = form.courseName if (form.courseName) params.kcmc = form.courseName
if (form.teachMethodEnabled && form.teachMethod) params.jxff = form.teachMethod if (form.teachMethod) params.jxff = form.teachMethod
if (form.changeEnabled && form.change) params.gdqk = form.change if (form.change) params.gdqk = form.change
if (form.taskCategoryEnabled && form.taskCategory) params.rwlb = form.taskCategory if (form.taskCategory) params.rwlb = form.taskCategory
if (form.deptEnabled && form.dept) params.jys = form.dept if (form.dept) params.jys = form.dept
if (form.teacherEnabled && form.teacher) params.skjy = form.teacher if (form.teacher) params.skjy = form.teacher
if (form.classNameEnabled && form.className) params.pxqb = form.className if (form.className) params.pxqb = form.className
return params return params
}, },
@@ -329,23 +288,14 @@ export default {
handleReset() { handleReset() {
this.searchForm = { this.searchForm = {
startDate: '', startDate: '',
startDateEnabled: false,
endDate: '', endDate: '',
endDateEnabled: false,
courseName: '', courseName: '',
courseNameEnabled: false, teachMethod: '',
teachMethod: '理论讲授', change: '',
teachMethodEnabled: false, taskCategory: '',
change: '与教学计划一致', dept: '',
changeEnabled: false, teacher: '',
taskCategory: '全军院校训练规划内任务', className: ''
taskCategoryEnabled: false,
dept: '教务处',
deptEnabled: false,
teacher: '教务处',
teacherEnabled: false,
className: '',
classNameEnabled: false
} }
this.remark = '' this.remark = ''
this.handleSearch() this.handleSearch()
+5 -5
View File
@@ -68,16 +68,16 @@
<div class="list-toolbar"> <div class="list-toolbar">
<div class="left-group"> <div class="left-group">
<el-button type="primary" icon="el-icon-plus" @click="handleNew">新建教材信息</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleNew">新建教材信息</el-button>
<el-button type="primary" icon="el-icon-download" @click="handleDownloadList">下载教材列表</el-button> <el-button icon="el-icon-download" @click="handleDownloadList">下载教材列表</el-button>
<el-button type="primary" icon="el-icon-folder-opened" @click="handleDownloadZip">所选文件资料打包ZIP下载</el-button> <el-button icon="el-icon-folder-opened" @click="handleDownloadZip">所选文件资料打包ZIP下载</el-button>
</div> </div>
<div class="right-group"> <div class="right-group">
<el-button type="primary" icon="el-icon-download" @click="handleDownloadTemplate">教材数据文件模板下载</el-button> <el-button icon="el-icon-download" @click="handleDownloadTemplate">教材数据文件模板下载</el-button>
<div class="file-input"> <div class="file-input">
<input ref="fileInput" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" /> <input ref="fileInput" type="file" accept=".xls,.xlsx" style="display: none" @change="handleFileChange" />
<el-button type="primary" plain icon="el-icon-upload" @click="handleChooseFile">选择文件</el-button> <el-button icon="el-icon-folder-opened" @click="handleChooseFile">选择文件</el-button>
<span class="file-name">{{ fileName }}</span> <span class="file-name">{{ fileName }}</span>
<el-button type="success" icon="el-icon-upload2" @click="handleImport">上传数据</el-button> <el-button type="primary" icon="el-icon-upload2" @click="handleImport">上传数据</el-button>
</div> </div>
</div> </div>
</div> </div>