页面接口对接,以及样式调整

This commit is contained in:
2026-08-24 15:28:13 +08:00
parent 1a1b1ce66b
commit 48aa410130
32 changed files with 824 additions and 919 deletions
+1 -1
View File
@@ -92,4 +92,4 @@ export function listClassroomByJxldh(jxldh) {
method: 'get', method: 'get',
params: { jxldh } params: { jxldh }
}) })
} }
@@ -1,81 +0,0 @@
import request from '@/utils/request'
// 课表(课程表 KCB)管理(KCBController /kcb
// 接口依据:KCBController + KCBServiceImpl
// 说明:KCB 实体主键为 bh(编号,IdType.INPUT);新增时后端强制 setBh(UUID) 覆盖、cjsj/bdsj 自动生成;
// delete/get/update 中的 URL 参数 kbh 实为 bh(编号)值;list 无分页返回全部记录
/**
* 新增课程表
* POST /kcb/add
* body 为 KCB 实体;bh 可留空(后端自动生成 UUID),cjsj/bdsj 后端自动维护
*/
export function addKcb(data) {
return request({
url: '/kcb/add',
method: 'post',
data
})
}
/**
* 删除课程表
* POST /kcb/delete?kbh= kbh 实为 bh 编号值)
*/
export function deleteKcb(kbh) {
return request({
url: '/kcb/delete',
method: 'post',
params: { kbh }
})
}
/**
* 批量删除课程表
* POST /kcb/batchDelete
* body 为 bh(编号)字符串数组
*/
export function batchDeleteKcb(kbhList) {
return request({
url: '/kcb/batchDelete',
method: 'post',
data: kbhList
})
}
/**
* 更新课程表
* POST /kcb/update
* body 为 KCB 实体,bh 编号必传
*/
export function updateKcb(data) {
return request({
url: '/kcb/update',
method: 'post',
data
})
}
/**
* 根据编号查询课程表详情
* GET /kcb/get?kbh= kbh 实为 bh 编号值)
*/
export function getKcb(kbh) {
return request({
url: '/kcb/get',
method: 'get',
params: { kbh }
})
}
/**
* 查询所有课程表数据
* GET /kcb/list
* 返回 List<KCB>,无分页,页面做本地过滤与本地分页
*/
export function listKcb() {
return request({
url: '/kcb/list',
method: 'get'
})
}
+68
View File
@@ -0,0 +1,68 @@
import request from '@/utils/request'
// 分页查询选修班
// pageNum/pageSize/jyxm(通信)/kmc(通信)/kxbcnj(通信)/xxbmc(通信)/xkzt(等值)/pxcc(等值)
export function listElective(query) {
return request({
url: '/jys/elective/list',
method: 'get',
params: query
})
}
// 批量开放报名
export function batchOpenElective(bhList) {
return request({
url: '/jys/elective/batch-open',
method: 'post',
data: { bhList: bhList }
})
}
// 批量取消开放报名
export function batchCancelOpenElective(bhList) {
return request({
url: '/jys/elective/batch-cancel-open',
method: 'post',
data: { bhList: bhList }
})
}
// 批量停止报名
export function batchStopElective(bhList) {
return request({
url: '/jys/elective/batch-stop',
method: 'post',
data: { bhList: bhList }
})
}
// 下载选修班列表(Excel
export function exportElectiveList(query) {
return request({
url: '/jys/elective/export',
method: 'get',
params: query,
responseType: 'blob'
})
}
// 下载选修班学员名单(Excel)
export function exportElectiveStudentsExcel(bhList) {
return request({
url: '/jys/elective/students/export-excel',
method: 'get',
params: { bhList: bhList },
responseType: 'blob'
})
}
// 下载选修班学员名单(Word
export function exportElectiveStudentsWord(bhList) {
return request({
url: '/jys/elective/students/export-word',
method: 'get',
params: { bhList: bhList },
responseType: 'blob'
})
}
+47
View File
@@ -0,0 +1,47 @@
import request from '@/utils/request'
// 分页查询课程科目(课表 KB
// kmc/kmdm/jc 模糊,jysdh/kclx/pxlx/pxcc 等值
export function listKb(query) {
return request({
url: '/jys/kb/list',
method: 'get',
params: query
})
}
// 课程科目详情(kbh 课编号)
export function getKb(kbh) {
return request({
url: '/jys/kb/get',
method: 'get',
params: { kbh: kbh }
})
}
// 新增课程科目(kbh 留空后端生成 UUID)
export function addKb(data) {
return request({
url: '/jys/kb/add',
method: 'post',
data: data
})
}
// 删除课程科目(kbh 课编号)
export function deleteKb(kbh) {
return request({
url: '/jys/kb/delete',
method: 'post',
params: { kbh: kbh }
})
}
// 编辑课程科目(kbh 必传)
export function updateKb(data) {
return request({
url: '/jys/kb/update',
method: 'post',
data: data
})
}
-70
View File
@@ -1,70 +0,0 @@
import request from '@/utils/request'
// 课程科目(课标 KB)管理(JYSController /jys/kb
// 接口依据:JYSController 控制器(前端 baseURL 为 /api,此处不重复 /api 前缀)
// 实体 KB 主键为 kbh(课编号);新增时 kbh 留空由后端生成 UUID;xhbs 字段无需传递(后端 NEVER)
/**
* 新增课程科目
* POST /jys/kb/add
* body 为 KB 实体;kbh 可留空(后端生成 UUID)
*/
export function addSubject(data) {
return request({
url: '/jys/kb/add',
method: 'post',
data
})
}
/**
* 删除课程科目
* POST /jys/kb/delete?kbh=
*/
export function deleteSubject(kbh) {
return request({
url: '/jys/kb/delete',
method: 'post',
params: { kbh }
})
}
/**
* 编辑课程科目
* POST /jys/kb/update
* body 为 KB 实体,kbh 课编号必传
*/
export function updateSubject(data) {
return request({
url: '/jys/kb/update',
method: 'post',
data
})
}
/**
* 查询课程科目详情
* GET /jys/kb/get?kbh=
*/
export function getSubject(kbh) {
return request({
url: '/jys/kb/get',
method: 'get',
params: { kbh }
})
}
/**
* 分页查询课程科目(课标 KB
* GET /jys/kb/list
* 查询参数:pageNum、pageSize、kmc 课名称(模糊)、jc 简称(模糊)、kmdm 科目代码(模糊)、
* jysdh 教研室代号(等值)、kclx 课程类型、pxlx 培训类型、pxcc 培训层次
* 返回:PageResult<KB>records/total
*/
export function listSubject(params) {
return request({
url: '/jys/kb/list',
method: 'get',
params
})
}
@@ -1,326 +0,0 @@
// ============================================================
// 全局设计系统(Design System
// 收敛 Element 基元 + 统一页面结构基线 + 工具类
// 依赖 design-tokens.scss 中的 $token 与 --token
//
// 用途:业务页面优先复用以下区块/工具类,删除各自 scoped 中重复定义,
// 实现全站风格、排版、按钮统一。仅需在 index.scss 末尾引入一次。
// ============================================================
// ------------------------- 1. Element 基元收敛 -------------------------
// 1.1 按钮——统一主色、尺寸、圆角、hover/active 反馈与外光晕
.el-button {
--el-button-primary-text: #fff;
border-radius: var(--token-radius-md, 4px);
transition: background-color 0.2s, border-color 0.2s, color 0.2s,
box-shadow 0.2s;
// 主按钮统一教育绿
&.el-button--primary {
background-color: var(--token-color-primary, #00875a);
border-color: var(--token-color-primary, #00875a);
color: #fff;
&:hover,
&:focus {
background-color: var(--token-color-primary-hover, #0b9e6c);
border-color: var(--token-color-primary-hover, #0b9e6c);
}
&:active {
background-color: var(--token-color-primary-active, #006b47);
border-color: var(--token-color-primary-active, #006b47);
}
&.is-plain {
color: var(--token-color-primary, #00875a);
background-color: var(--token-color-primary-lighter, #f0f9f4);
border-color: var(--token-color-primary, #00875a);
&:hover,
&:focus {
color: #fff;
background-color: var(--token-color-primary, #00875a);
}
}
&.is-disabled {
background-color: #a0cfb8;
border-color: #a0cfb8;
color: rgba(255, 255, 255, 0.9);
}
}
// 危险按钮
&.el-button--danger {
background-color: var(--token-color-danger, #ff4949);
border-color: var(--token-color-danger, #ff4949);
&:hover,
&:focus {
background-color: #ff6b6b;
border-color: #ff6b6b;
}
}
// 聚焦外光晕(键盘可访问性),除 text 按钮外
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--token-color-primary-ring, rgba(0, 135, 90, 0.35));
}
// 表格内文字操作按钮保持紧凑
&.el-button--text {
font-size: var(--token-font-size-sm, 13px);
padding: 0 4px;
&.danger-link {
color: var(--token-color-danger, #ff4949);
}
}
}
// 1.2 卡片——统一无内阴影、body 内边距
.el-card {
border-color: var(--token-color-border-lighter, #ebeef5);
&.is-always-shadow {
box-shadow: var(--token-shadow-card, 0 1px 4px rgba(0, 0, 0, 0.06));
}
}
// 1.3 表格——统一表头背景与居中、行 hover、斑马
.el-table {
th.el-table__cell {
background-color: var(--token-color-fill, #f5f7fa);
color: var(--token-color-text-main, #303133);
font-weight: 600;
}
th.el-table__cell > .cell {
text-align: center;
}
.el-table__body tr.hover-row > td.el-table__cell,
.el-table__body tr:hover > td.el-table__cell {
background-color: var(--token-color-primary-lighter, #f0f9f4);
}
&.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell {
background-color: var(--token-color-fill-light, #f0f2f5);
}
}
// 1.4 表单——统一 label 对齐与错误/必填语义
.el-form {
.el-form-item {
.el-form-item__label {
color: var(--token-color-text-regular, #606266);
}
.el-form-item__error {
color: var(--token-color-danger, #ff4949);
}
}
}
// 1.5 分页——统一置于底部右侧
.el-pagination {
color: var(--token-color-text-regular, #606266);
&.pagination-right {
justify-content: flex-end;
}
}
// ------------------------- 2. 页面结构基线 -------------------------
// 说明:这些类名与历史业务页 scoped 中的自定义类名保持同名,
// 统一后应删除页面内的 scoped 重复定义,避免覆盖。
// 2.1 基础页面容器
.page-shell {
padding: var(--token-space-xl, 20px);
box-sizing: border-box;
}
// 2.2 页面标题
.page-title {
font-size: var(--token-font-size-xl, 20px);
font-weight: 600;
color: var(--token-color-text-main, #303133);
margin-bottom: var(--token-space-lg, 16px);
}
// 2.3 区块/卡片容器——统一白底 + 圆角 + 轻阴影 + 内边距
.section-card {
background: #fff;
border-radius: var(--token-radius-xl, 8px);
box-shadow: var(--token-shadow-light, 0 1px 4px rgba(0, 0, 0, 0.08));
padding: var(--token-space-lg, 16px) var(--token-space-xl, 20px);
margin-bottom: var(--token-space-lg, 16px);
&:last-child {
margin-bottom: 0;
}
}
// 兼容:el-card 封装的查询/表格卡
.search-card.el-card,
.table-card.el-card {
border-radius: var(--token-radius-xl, 8px);
}
.search-card,
.table-card {
margin-bottom: var(--token-space-lg, 16px);
}
.search-card {
.search-form {
.el-form-item {
margin-bottom: 0;
}
}
// 底部操作区(右侧对齐)
.search-actions,
.search-footer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: var(--token-space-md, 12px);
}
// 仅明确标记为页脚的操作区才带轻分割线(避免误伤页面自有分割结构)
.search-footer {
margin-top: var(--token-space-md, 12px);
padding-top: var(--token-space-md, 12px);
border-top: 1px solid var(--token-color-border-lighter, #ebeef5);
}
}
.table-card {
.pagination-wrap,
.pagination-wrapper,
.pagination {
display: flex;
justify-content: flex-end;
margin-top: var(--token-space-md, 12px);
}
}
// 2.4 查询控件——统一纵向排列的表单:标签右对齐 + 控件自适应
.query-field {
display: flex;
align-items: center;
margin-bottom: var(--token-space-sm, 8px);
min-height: 32px;
.q-label {
width: 120px;
flex-shrink: 0;
font-size: var(--token-font-size-sm, 13px);
color: var(--token-color-text-main, #303133);
text-align: right;
margin-right: var(--token-space-sm, 8px);
white-space: nowrap;
&.no-check {
margin-left: var(--token-space-2xl, 24px);
}
}
.q-control {
flex: 1;
min-width: 0;
}
}
// 2.5 操作/导出按钮行——统一 flex + 等比间距 + 自动换行
.action-row,
.export-bar {
display: flex;
flex-wrap: wrap;
gap: var(--token-space-md, 12px);
}
.action-row + .action-row {
margin-top: var(--token-space-md, 12px);
}
// 2.6 列表工具栏——左右分组
.list-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--token-space-md, 12px);
flex-wrap: wrap;
margin-bottom: var(--token-space-lg, 16px);
.left-group,
.right-group {
display: flex;
align-items: center;
gap: var(--token-space-md, 12px);
flex-wrap: wrap;
}
}
// 列表标题
.list-title,
.section-title {
font-size: var(--token-font-size-lg, 16px);
font-weight: 600;
color: var(--token-color-text-main, #303133);
margin-bottom: var(--token-space-md, 12px);
}
// 2.7 危险文字(删除/停用等)
.text-danger,
.danger-text,
.danger-link {
color: var(--token-color-danger, #ff4949);
}
// ------------------------- 3. 工具类 -------------------------
// 字体
.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }
.text-primary { color: var(--token-color-primary, #00875a); }
.text-regular { color: var(--token-color-text-regular, #606266); }
.text-secondary { color: var(--token-color-text-secondary, #909399); }
.font-sm { font-size: var(--token-font-size-sm, 13px); }
.font-lg { font-size: var(--token-font-size-lg, 16px); }
// 布局
.flex { display: flex; align-items: center; }
.flex-center { display: flex; align-items: center; justify-content: center; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.flex-end { display: flex; align-items: center; justify-content: flex-end; }
.flex-wrap { flex-wrap: wrap; }
.flex-1 { flex: 1; min-width: 0; }
.w-full { width: 100%; }
// 间距(上/下)
.mt-0 { margin-top: 0; }
.mt-xs { margin-top: var(--token-space-xs, 4px); }
.mt-sm { margin-top: var(--token-space-sm, 8px); }
.mt-md { margin-top: var(--token-space-md, 12px); }
.mt-lg { margin-top: var(--token-space-lg, 16px); }
.mt-xl { margin-top: var(--token-space-xl, 20px); }
.mb-0 { margin-bottom: 0; }
.mb-xs { margin-bottom: var(--token-space-xs, 4px); }
.mb-sm { margin-bottom: var(--token-space-sm, 8px); }
.mb-md { margin-bottom: var(--token-space-md, 12px); }
.mb-lg { margin-bottom: var(--token-space-lg, 16px); }
.mb-xl { margin-bottom: var(--token-space-xl, 20px); }
// 圆角/阴影
.radius-sm { border-radius: var(--token-radius-sm, 2px); }
.radius-md { border-radius: var(--token-radius-md, 4px); }
.radius-lg { border-radius: var(--token-radius-lg, 6px); }
.radius-xl { border-radius: var(--token-radius-xl, 8px); }
.shadow-light { box-shadow: var(--token-shadow-light, 0 1px 4px rgba(0, 0, 0, 0.08)); }
// 等宽
.mono {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
}
@@ -1,147 +0,0 @@
// ============================================================
// 设计 Token 体系(Design Tokens
// 全站统一颜色 / 字体 / 间距 / 圆角 / 阴影 / 边框 / 层级 / 断点
// 约定:
// 1. 业务代码禁止散落魔法数字,一律引用下方 $token / --token
// 2. SCSS 变量供样式内使用,:root 自定义属性供内联/动态样式使用
// ============================================================
@import './variables.scss';
// ------------------------- 色彩 Token -------------------------
// 主色:教育绿
$token-color-primary: #00875a; // 主色
$token-color-primary-hover: #0b9e6c; // hover
$token-color-primary-active: #006b47; // active
$token-color-primary-light: #e6f4ea; // 浅底(标签/选中背景)
$token-color-primary-lighter: #f0f9f4; // 更浅(hover 背景/斑马)
$token-color-primary-ring: rgba(0, 135, 90, 0.35); // 聚焦外光晕
// 语义色
$token-color-danger: #ff4949; // 危险
$token-color-success: #13ce66; // 成功
$token-color-warning: #ffba00; // 警告
$token-color-info: #909399; // 中性信息
// 中性灰阶(对齐 Element 三级文字)
$token-color-text-main: #303133; // 主要文字
$token-color-text-regular: #606266; // 常规文字
$token-color-text-secondary: #909399; // 次要文字
$token-color-text-placeholder: #c0c4cc; // 占位
$token-color-border: #dcdfe6; // 边框
$token-color-border-light: #e4e7ed; // 浅边框
$token-color-border-lighter: #ebeef5; // 极浅边框(分割线)
$token-color-fill: #f5f7fa; // 填充/底灰
$token-color-fill-light: #f0f2f5; // 更浅填充
// ------------------------- 字体 Token -------------------------
$token-font-family: 'Helvetica Neue', Helvetica, 'PingFang SC',
'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
$token-font-size-xs: 12px;
$token-font-size-sm: 13px;
$token-font-size-base: 14px;
$token-font-size-lg: 16px;
$token-font-size-xl: 20px;
// ------------------------- 间距 Token -------------------------
$token-space-xs: 4px;
$token-space-sm: 8px;
$token-space-md: 12px;
$token-space-lg: 16px;
$token-space-xl: 20px;
$token-space-2xl: 24px;
// ------------------------- 圆角 Token -------------------------
$token-radius-sm: 2px;
$token-radius-md: 4px;
$token-radius-lg: 6px;
$token-radius-xl: 8px;
$token-radius-circle: 50%;
// ------------------------- 阴影 Token -------------------------
$token-shadow-light: 0 1px 4px rgba(0, 0, 0, 0.08);
$token-shadow-card: 0 1px 4px rgba(0, 0, 0, 0.06);
$token-shadow-popup: 0 2px 12px rgba(0, 0, 0, 0.12);
// ------------------------- 层级 Token -------------------------
$token-z-index-dropdown: 2000; // 下拉/气泡
$token-z-index-mask: 2001; // 遮罩
$token-z-index-modal: 2002; // 弹窗
$token-z-index-toast: 3000; // 消息/通知
// ------------------------- 断点 Token -------------------------
$token-breakpoint-xs: 480px;
$token-breakpoint-sm: 768px;
$token-breakpoint-md: 992px;
$token-breakpoint-lg: 1200px;
$token-breakpoint-xl: 1920px;
// ------------------------- 暴露给运行时(CSS 变量) -------------------------
:root {
--token-color-primary: #{$token-color-primary};
--token-color-primary-hover: #{$token-color-primary-hover};
--token-color-primary-active: #{$token-color-primary-active};
--token-color-primary-light: #{$token-color-primary-light};
--token-color-primary-lighter: #{$token-color-primary-lighter};
--token-color-primary-ring: #{$token-color-primary-ring};
--token-color-danger: #{$token-color-danger};
--token-color-success: #{$token-color-success};
--token-color-warning: #{$token-color-warning};
--token-color-info: #{$token-color-info};
--token-color-text-main: #{$token-color-text-main};
--token-color-text-regular: #{$token-color-text-regular};
--token-color-text-secondary: #{$token-color-text-secondary};
--token-color-text-placeholder: #{$token-color-text-placeholder};
--token-color-border: #{$token-color-border};
--token-color-border-light: #{$token-color-border-light};
--token-color-border-lighter: #{$token-color-border-lighter};
--token-color-fill: #{$token-color-fill};
--token-color-fill-light: #{$token-color-fill-light};
--token-font-family: #{$token-font-family};
--token-font-size-xs: #{$token-font-size-xs};
--token-font-size-sm: #{$token-font-size-sm};
--token-font-size-base: #{$token-font-size-base};
--token-font-size-lg: #{$token-font-size-lg};
--token-font-size-xl: #{$token-font-size-xl};
--token-space-xs: #{$token-space-xs};
--token-space-sm: #{$token-space-sm};
--token-space-md: #{$token-space-md};
--token-space-lg: #{$token-space-lg};
--token-space-xl: #{$token-space-xl};
--token-space-2xl: #{$token-space-2xl};
--token-radius-sm: #{$token-radius-sm};
--token-radius-md: #{$token-radius-md};
--token-radius-lg: #{$token-radius-lg};
--token-radius-xl: #{$token-radius-xl};
--token-shadow-light: #{$token-shadow-light};
--token-shadow-card: #{$token-shadow-card};
--token-shadow-popup: #{$token-shadow-popup};
--token-z-index-dropdown: #{$token-z-index-dropdown};
--token-z-index-mask: #{$token-z-index-mask};
--token-z-index-modal: #{$token-z-index-modal};
--token-z-index-toast: #{$token-z-index-toast};
}
// ------------------------- 暴露给 JS 模块 -------------------------
:export {
colorPrimary: $token-color-primary;
colorPrimaryHover: $token-color-primary-hover;
colorPrimaryActive: $token-color-primary-active;
colorPrimaryLight: $token-color-primary-light;
colorPrimaryLighter: $token-color-primary-lighter;
colorDanger: $token-color-danger;
colorSuccess: $token-color-success;
colorWarning: $token-color-warning;
fontFamily: $token-font-family;
breakpointXs: $token-breakpoint-xs;
breakpointSm: $token-breakpoint-sm;
breakpointMd: $token-breakpoint-md;
breakpointLg: $token-breakpoint-lg;
breakpointXl: $token-breakpoint-xl;
}
-6
View File
@@ -245,9 +245,3 @@ aside {
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
/* ================= 全局设计系统 =================
居于最末加载,收敛 Element 基元与页面结构基线
Token 体系在 design-tokens.scss,页面统一类名在 design-system.scss */
@import './design-tokens.scss';
@import './design-system.scss';
+2 -2
View File
@@ -114,10 +114,10 @@
} }
} }
// 表格横向拖拽滚动:拖拽过程中保持默认光标,不显示“抓手”,避免干扰操作手感 // 表格横向拖拽滚动:拖拽过程中光标切换为“抓手”
.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: default; cursor: grabbing;
} }
} }
@@ -455,7 +455,13 @@ export default {
// ==================== 1. 查询条件区域 ==================== // ==================== 1. 查询条件区域 ====================
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions { .search-actions {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
@@ -467,6 +473,8 @@ export default {
// ==================== 2. 操作区域 ==================== // ==================== 2. 操作区域 ====================
.upload-card { .upload-card {
margin-bottom: 16px;
.upload-row { .upload-row {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -493,12 +501,24 @@ export default {
// ==================== 3. 数据表格 ==================== // ==================== 3. 数据表格 ====================
.table-card { .table-card {
margin-bottom: 16px;
.table-title { .table-title {
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
margin-bottom: 12px; margin-bottom: 12px;
} }
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.text-danger {
color: #f56c6c;
}
} }
// ==================== 4. 新增/修改表单 ==================== // ==================== 4. 新增/修改表单 ====================
@@ -641,6 +641,30 @@ export default {
margin-bottom: 12px; margin-bottom: 12px;
} }
// ==================== 1. 查询区域 ====================
.search-card {
margin-bottom: 16px;
.search-form {
.el-form-item {
margin-bottom: 0;
}
}
}
// ==================== 2. 数据表格 ====================
.table-card {
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.text-danger {
color: #f56c6c;
}
}
// ==================== 3. 新增/修改表单 ==================== // ==================== 3. 新增/修改表单 ====================
.add-form { .add-form {
max-height: 62vh; max-height: 62vh;
@@ -251,9 +251,22 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.subsidy-page { .subsidy-page {
.list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
}
// ==================== 1. 查询条件区域 ==================== // ==================== 1. 查询条件区域 ====================
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.search-actions-col { .search-actions-col {
display: flex; display: flex;
@@ -275,6 +288,12 @@ export default {
color: #303133; color: #303133;
margin-bottom: 12px; margin-bottom: 12px;
} }
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
} }
} }
</style> </style>
+210 -2
View File
@@ -1,8 +1,89 @@
<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="24" :lg="24"> <el-col :xs="24" :sm="24" :md="12" :lg="8">
<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>
@@ -50,6 +131,7 @@
<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 {
@@ -60,6 +142,13 @@ 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,
@@ -69,6 +158,7 @@ export default {
}, },
mounted() { mounted() {
this.loadNoticeList() this.loadNoticeList()
this.loadLoginLogList()
}, },
methods: { methods: {
goTarget(href) { goTarget(href) {
@@ -118,6 +208,28 @@ 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
@@ -259,6 +371,102 @@ 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;
@@ -218,6 +218,18 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.score-page { .score-page {
padding: 20px;
.search-card {
margin-bottom: 16px;
.search-form {
.el-form-item {
margin-bottom: 0;
}
}
}
.toolbar { .toolbar {
margin-bottom: 16px; margin-bottom: 16px;
} }
@@ -226,6 +238,12 @@ export default {
.el-table { .el-table {
width: 100%; width: 100%;
} }
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
} }
</style> </style>
@@ -627,14 +627,31 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.shift-team-page { .shift-team-page {
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions-row { .search-actions-row {
margin-top: 2px; margin-top: 2px;
border-top: 1px dashed #ebeef5; border-top: 1px dashed #ebeef5;
padding-top: 14px; padding-top: 14px;
} }
.search-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
} }
} }
@@ -674,6 +691,12 @@ export default {
color: #303133; color: #303133;
} }
} }
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
.form-dialog-form { .form-dialog-form {
@@ -427,8 +427,20 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.status-change-page { .status-change-page {
.search-card {
margin-bottom: 16px;
}
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions { .search-actions {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -460,6 +472,12 @@ export default {
color: #303133; color: #303133;
} }
} }
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
.add-form { .add-form {
@@ -476,6 +476,10 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.warning-condition-page { .warning-condition-page {
.search-card {
margin-bottom: 16px;
}
.search-form { .search-form {
::v-deep .el-form-item { ::v-deep .el-form-item {
margin-bottom: 18px; margin-bottom: 18px;
@@ -486,6 +490,13 @@ export default {
border-top: 1px dashed #ebeef5; border-top: 1px dashed #ebeef5;
padding-top: 14px; padding-top: 14px;
} }
.search-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
} }
.table-card { .table-card {
@@ -507,6 +518,12 @@ export default {
gap: 10px; gap: 10px;
} }
} }
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
.form-dialog-form { .form-dialog-form {
@@ -204,13 +204,32 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.warning-result-page { .warning-result-page {
.search-card {
margin-bottom: 16px;
}
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions-row { .search-actions-row {
margin-top: 2px; margin-top: 2px;
border-top: 1px dashed #ebeef5; border-top: 1px dashed #ebeef5;
padding-top: 14px; padding-top: 14px;
} }
.search-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
} }
.table-card { .table-card {
@@ -226,6 +245,12 @@ export default {
color: #303133; color: #303133;
} }
} }
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
} }
</style> </style>
@@ -648,6 +648,10 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.major-page { .major-page {
.search-card {
margin-bottom: 16px;
}
.search-form { .search-form {
::v-deep .el-form-item { ::v-deep .el-form-item {
margin-bottom: 18px; margin-bottom: 18px;
@@ -658,6 +662,13 @@ export default {
border-top: 1px dashed #ebeef5; border-top: 1px dashed #ebeef5;
padding-top: 14px; padding-top: 14px;
} }
.search-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
} }
.table-card { .table-card {
@@ -679,6 +690,12 @@ export default {
gap: 10px; gap: 10px;
} }
} }
.pagination-wrapper {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
.form-dialog-form { .form-dialog-form {
@@ -115,8 +115,8 @@ export default {
totalWeeks: 0, totalWeeks: 0,
dateRangeText: '', dateRangeText: '',
weeks: [], weeks: [],
// 显示控制:默认勾选显示日期;节次全部展示 // 显示控制:默认勾选显示日期;节次全部展示
showDate: false, showDate: true,
// 事件存储:key = cellKey -> event // 事件存储:key = cellKey -> event
events: {}, events: {},
loading: false loading: false
@@ -1,7 +1,7 @@
<template> <template>
<div class="app-container teach-semester"> <div class="app-container teach-semester">
<!-- 工具栏 --> <!-- 工具栏 -->
<el-row :gutter="10" class="semester-toolbar"> <el-row :gutter="10" class="mb8">
<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>
@@ -17,75 +17,62 @@
</el-row> </el-row>
<!-- 数据表格 --> <!-- 数据表格 -->
<div class="semester-table-wrap"> <el-table
<el-table v-loading="loading"
v-loading="loading" :data="semesterList"
:data="semesterList" border
border :height="tableHeight"
stripe @selection-change="handleSelectionChange"
:height="tableHeight" >
:row-class-name="tableRowClassName" <el-table-column type="selection" align="center" width="50" />
:header-cell-style="{ background: '#F4F8F5', color: '#303133', fontWeight: 600 }" <el-table-column label="学期名称" align="center" min-width="190">
@selection-change="handleSelectionChange" <template slot-scope="scope">
> <span>{{ getSemesterName(scope.row.nd) }}</span>
<el-table-column type="selection" align="center" width="50" /> </template>
<el-table-column label="学期名称" align="center" min-width="190"> </el-table-column>
<template slot-scope="scope"> <el-table-column label="当前" align="center" width="70">
<span class="semester-name"> <template slot-scope="scope">
<i v-if="scope.row.dqxq" class="semester-name-icon el-icon-star-on"></i> <el-tag v-if="scope.row.dqxq" type="success" size="mini">当前</el-tag>
<span>{{ getSemesterName(scope.row.nd) }}</span> <span v-else>-</span>
</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" width="80"> <template slot-scope="scope">
<template slot-scope="scope"> <span>{{ formatDate(scope.row.kxrq) }}</span>
<el-tag v-if="scope.row.dqxq" type="success" effect="dark" size="mini">当前学期</el-tag> </template>
<span v-else class="text-muted"></span> </el-table-column>
</template> <el-table-column label="结束日期" align="center" prop="jsrq" min-width="130">
</el-table-column> <template slot-scope="scope">
<el-table-column label="开学日期" align="center" min-width="120"> <span>{{ formatDate(scope.row.jsrq) }}</span>
<template slot-scope="scope"> </template>
<span class="date-cell"><i class="el-icon-date"></i>{{ formatDate(scope.row.kxrq) || '—' }}</span> </el-table-column>
</template> <el-table-column label="周数" align="center" prop="sdzs" width="70" />
</el-table-column> <el-table-column label="调课不审批" align="center" width="100">
<el-table-column label="结束日期" align="center" min-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>
<span class="date-cell"><i class="el-icon-date"></i>{{ formatDate(scope.row.jsrq) || '—' }}</span> </template>
</template> </el-table-column>
</el-table-column> <el-table-column label="禁止调课" align="center" width="90">
<el-table-column label="周数" align="center" prop="sdzs" width="80"> <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 v-if="scope.row.sdzs !== undefined && scope.row.sdzs !== null" type="info" effect="plain" size="mini">{{ scope.row.sdzs }} </el-tag> </template>
<span v-else class="text-muted"></span> </el-table-column>
</template> <el-table-column label="终结成绩定及格" align="center" width="120">
</el-table-column> <template slot-scope="scope">
<el-table-column label="调课不审批" align="center" width="116"> <el-tag :type="scope.row.zjcjdjg ? 'primary' : 'info'" size="mini">{{ scope.row.zjcjdjg ? '是' : '否' }}</el-tag>
<template slot-scope="scope"> </template>
<span :class="boolCellClass(scope.row.tkbsp)">{{ scope.row.tkbsp ? '是' : '否' }}</span> </el-table-column>
</template> <el-table-column label="课时系数方案" align="center" min-width="120">
</el-table-column> <template slot-scope="scope">
<el-table-column label="禁止调课" align="center" width="100"> <span>{{ getCoefficientLabel(scope.row.ksxsfabh) }}</span>
<template slot-scope="scope"> </template>
<span :class="boolCellClass(scope.row.jztk)">{{ scope.row.jztk ? '是' : '否' }}</span> </el-table-column>
</template> <el-table-column label="锁定时长" align="center" min-width="100">
</el-table-column> <template slot-scope="scope">
<el-table-column label="终结成绩定及格" align="center" width="132"> <span>{{ scope.row.sdjldw || '-' }}</span>
<template slot-scope="scope"> </template>
<span :class="boolCellClass(scope.row.zjcjdjg)">{{ scope.row.zjcjdjg ? '是' : '否' }}</span> </el-table-column>
</template> </el-table>
</el-table-column>
<el-table-column label="课时系数方案" align="center" min-width="120">
<template slot-scope="scope">
<span>{{ getCoefficientLabel(scope.row.ksxsfabh) }}</span>
</template>
</el-table-column>
<el-table-column label="锁定时长" align="center" min-width="96">
<template slot-scope="scope">
<span class="lock-cell">{{ scope.row.sdjldw || '—' }}</span>
</template>
</el-table-column>
</el-table>
</div>
<pagination <pagination
v-show="total > 0" v-show="total > 0"
@@ -348,14 +335,6 @@ export default {
this.loading = false this.loading = false
}) })
}, },
/** 当前学期行高亮类名 */
tableRowClassName({ row }) {
return row.dqxq ? 'current-semester-row' : ''
},
/** 布尔开关单元格样式:是=实心绿点,否=灰色横线标记 */
boolCellClass(val) {
return val ? 'bool-cell is-true' : 'bool-cell is-false'
},
/** 多选变化 */ /** 多选变化 */
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.ids = selection.map(item => item.nd) this.ids = selection.map(item => item.nd)
@@ -512,146 +491,8 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.teach-semester { .teach-semester {
/* 页面标题区 */ .mb8 {
.semester-header { margin-bottom: 8px;
display: flex;
align-items: center;
gap: 12px;
padding-bottom: 14px;
margin-bottom: 14px;
border-bottom: 1px solid #ebeef5;
}
.semester-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 18px;
font-weight: 600;
color: #303133;
white-space: nowrap;
}
.title-dot {
width: 5px;
height: 18px;
border-radius: 3px;
background: var(--color, #00875A);
}
.semester-subtitle {
font-size: 13px;
color: #909399;
line-height: 1.5;
padding-top: 1px;
}
/* 工具栏 */
.semester-toolbar {
margin-bottom: 14px;
}
/* 表格卡片容器 */
.semester-table-wrap {
background: #fff;
border: 1px solid #ebeef5;
border-radius: 8px;
padding: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
}
/* 表头由 header-cell-style 设置底色,这里兜底 */
::v-deep .el-table__header th {
font-weight: 600;
}
/* 当前学期行高亮:浅绿底 + 左侧加深强调 */
::v-deep .el-table .current-semester-row td {
background: #F2FAF5;
}
::v-deep .el-table .current-semester-row:hover > td {
background: #EAF6EF;
}
::v-deep .el-table .current-semester-row td:first-child {
box-shadow: inset 3px 0 0 #00875A;
}
/* 学期名称 + 当前星标 */
.semester-name {
display: inline-flex;
align-items: center;
gap: 4px;
font-weight: 500;
color: #303133;
}
.semester-name-icon {
color: #00875A;
font-size: 14px;
}
/* 日期单元格 */
.date-cell {
display: inline-flex;
align-items: center;
gap: 4px;
color: #606266;
font-variant-numeric: tabular-nums;
i {
color: #a0a6ad;
font-size: 13px;
}
}
/* 锁定时长 */
.lock-cell {
background: #F4F6F8;
border: 1px solid #EBEEF5;
border-radius: 4px;
padding: 1px 8px;
font-size: 12px;
color: #606266;
}
/* 布尔开关:实心圆点 + 是/否 */
.bool-cell {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
&::before {
content: '';
display: inline-block;
width: 9px;
height: 9px;
border-radius: 50%;
}
&.is-true {
color: #00875A;
font-weight: 600;
&::before {
background: #00875A;
}
}
&.is-false {
color: #C0C4CC;
&::before {
border: 1px solid #CDD1D6;
background: transparent;
}
}
}
.text-muted {
color: #C0C4CC;
} }
/* 弹窗内表单:防止 label 文字换行、字段拥挤换行 */ /* 弹窗内表单:防止 label 文字换行、字段拥挤换行 */
@@ -424,9 +424,19 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.syllabus-page { .syllabus-page {
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions { .search-actions {
padding-top: 4px; padding-top: 4px;
} }
@@ -247,6 +247,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.teaching-task-page { .teaching-task-page {
.page-title { .page-title {
text-align: center; text-align: center;
@@ -258,6 +262,8 @@ export default {
// ==================== 1. 查询条件区域 ==================== // ==================== 1. 查询条件区域 ====================
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.search-actions { .search-actions {
display: flex; display: flex;
@@ -268,6 +274,15 @@ export default {
} }
} }
// ==================== 2. 数据表格 ====================
.table-card {
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
}
// ==================== 3. 详情 ==================== // ==================== 3. 详情 ====================
.detail-empty { .detail-empty {
min-height: 120px; min-height: 120px;
@@ -242,7 +242,7 @@
import { listTeachingPlan } from '@/api/teachBusiness/courseRunning' import { listTeachingPlan } from '@/api/teachBusiness/courseRunning'
import { listStudentTeamTask } from '@/api/teachBusiness/studentTeamTask' import { listStudentTeamTask } from '@/api/teachBusiness/studentTeamTask'
import { listTeam } from '@/api/studentRecords/team' import { listTeam } from '@/api/studentRecords/team'
import { listSubject } from '@/api/teachOffice/subject' import { listKb } from '@/api/teachOffice/kb'
import { listTeacher } from '@/api/teachOffice/teacher' import { listTeacher } from '@/api/teachOffice/teacher'
import { listAllSemester } from '@/api/teachBusiness/semester' import { listAllSemester } from '@/api/teachBusiness/semester'
@@ -516,7 +516,7 @@ export default {
}) })
}, },
loadKbMap() { loadKbMap() {
listSubject({ pageNum: 1, pageSize: 1000 }).then(response => { listKb({ pageNum: 1, pageSize: 1000 }).then(response => {
const data = response.data || {} const data = response.data || {}
const map = {} const map = {}
;(data.records || []).forEach(item => { ;(data.records || []).forEach(item => {
@@ -505,9 +505,19 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.training-plan-page { .training-plan-page {
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions { .search-actions {
padding-top: 4px; padding-top: 4px;
} }
@@ -394,9 +394,19 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.venue-page { .venue-page {
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.w-full {
width: 100%;
}
.search-actions { .search-actions {
padding-top: 4px; padding-top: 4px;
} }
+116 -61
View File
@@ -88,17 +88,17 @@
<!-- ==================== 6. 数据表格区域 ==================== --> <!-- ==================== 6. 数据表格区域 ==================== -->
<div class="section-card table-card"> <div class="section-card table-card">
<el-table :data="pagedData" 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>
</template> </template>
<el-table-column type="selection" width="40" align="center" /> <el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="序号" width="60" align="center" :index="tableIndex" /> <el-table-column type="index" label="序号" width="60" align="center" :index="tableIndex" />
<el-table-column prop="course" label="课程" min-width="110" show-overflow-tooltip /> <el-table-column prop="kmc" label="课程" min-width="110" show-overflow-tooltip />
<el-table-column prop="textbook" label="教材" min-width="120" show-overflow-tooltip /> <el-table-column prop="jcmc" label="教材" min-width="120" show-overflow-tooltip />
<el-table-column prop="teacher" label="实施教员" width="90" align="center" /> <el-table-column prop="jyxm" label="实施教员" width="90" align="center" />
<el-table-column prop="place" label="教学场地" width="100" show-overflow-tooltip /> <el-table-column prop="jsmc" label="教学场地" width="100" show-overflow-tooltip />
<el-table-column prop="teamClass" label="显示可选队别班次" min-width="150" align="center" show-overflow-tooltip /> <el-table-column prop="kxdlbc" label="显示可选队别班次" min-width="150" align="center" show-overflow-tooltip />
<el-table-column label="计划学时/运行学时/学分" width="130" align="center"> <el-table-column label="计划学时/运行学时/学分" width="130" align="center">
<template slot="header"> <template slot="header">
<div class="triple-header"> <div class="triple-header">
@@ -109,31 +109,29 @@
</template> </template>
<template slot-scope="{ row }"> <template slot-scope="{ row }">
<div class="triple-cell"> <div class="triple-cell">
<span>{{ row.planHours }}</span> <span>{{ row.jhyxxsxf }}</span>
<span>{{ row.runHours }}</span>
<span>{{ row.credit }}</span>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="开课结课日期" min-width="150" align="center"> <el-table-column label="开课结课日期" min-width="150" align="center">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
{{ row.startDate }} ~ {{ row.endDate }} {{ row.kkjkrq }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="报名日期" min-width="140" align="center"> <el-table-column label="报名日期" min-width="140" align="center">
<template slot-scope="{ row }"> <template slot-scope="{ row }">
{{ row.signupStart }} ~ {{ row.signupEnd }} {{ row.bmrq }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="planCount" label="计划人数" width="90" align="center" /> <el-table-column prop="jhrs" label="计划人数" width="90" align="center" />
<el-table-column prop="requirement" label="要求说明" min-width="120" show-overflow-tooltip /> <el-table-column prop="yqsm" label="要求说明" min-width="120" show-overflow-tooltip />
</el-table> </el-table>
<div class="pagination-wrap"> <div class="pagination-wrap">
<el-pagination <el-pagination
background background
layout="total, prev, pager, next, jumper" layout="total, prev, pager, next, jumper"
:total="tableData.length" :total="total"
:page-size="pageSize" :page-size="pageSize"
:current-page="currentPage" :current-page="currentPage"
@current-change="handlePageChange" @current-change="handlePageChange"
@@ -183,6 +181,17 @@
</template> </template>
<script> <script>
import {
listElective,
batchOpenElective,
batchCancelOpenElective,
batchStopElective,
exportElectiveList,
exportElectiveStudentsExcel,
exportElectiveStudentsWord
} from '@/api/teachOffice/elective'
import { saveAs } from 'file-saver'
export default { export default {
name: 'Elective', name: 'Elective',
data() { data() {
@@ -203,14 +212,10 @@ export default {
pxcc: '无' pxcc: '无'
}, },
// ==================== 数据表格 mock ==================== // ==================== 数据表格 ====================
tableData: [ tableData: [],
{ id: 1, course: '军事英语', textbook: '军事英语教程', teacher: '张三', place: '教室101', teamClass: '2025级学员1-5队', planHours: 32, runHours: 30, credit: 2, startDate: '2026-09-01', endDate: '2027-01-15', signupStart: '2026-08-20', signupEnd: '2026-09-01', planCount: 60, requirement: '限选50人' }, total: 0,
{ id: 2, course: '摄影技术', textbook: '摄影基础', teacher: '李四', place: '教室102', teamClass: '2024级学员1-4队', planHours: 24, runHours: 24, credit: 1.5, startDate: '2026-09-01', endDate: '2027-01-15', signupStart: '2026-08-20', signupEnd: '2026-09-01', planCount: 40, requirement: '自备相机' }, loading: false,
{ id: 3, course: '网球', textbook: '网球教程', teacher: '王五', place: '操场', teamClass: '2025级学员2-6队', planHours: 24, runHours: 22, credit: 1.5, startDate: '2026-09-01', endDate: '2027-01-15', signupStart: '2026-08-21', signupEnd: '2026-09-02', planCount: 30, requirement: '需自备球拍' },
{ id: 4, course: '书法鉴赏', textbook: '中国书法', teacher: '赵六', place: '教室103', teamClass: '2026级学员1-3队', planHours: 16, runHours: 16, credit: 1, startDate: '2026-09-08', endDate: '2026-12-30', signupStart: '2026-08-25', signupEnd: '2026-09-05', planCount: 35, requirement: '' },
{ id: 5, course: '无人机操作', textbook: '无人机原理', teacher: '孙七', place: '室外训练场', teamClass: '2025级学员1-6队', planHours: 32, runHours: 28, credit: 2, startDate: '2026-09-08', endDate: '2027-01-10', signupStart: '2026-08-26', signupEnd: '2026-09-06', planCount: 25, requirement: '需通过体检' }
],
selectedRows: [], selectedRows: [],
// ==================== 文件上传 ==================== // ==================== 文件上传 ====================
@@ -241,73 +246,124 @@ export default {
computed: { computed: {
fileName() { fileName() {
return (this.selectedFile && this.selectedFile.name) || '未选择任何文件' return (this.selectedFile && this.selectedFile.name) || '未选择任何文件'
},
pagedData() {
const start = (this.currentPage - 1) * this.pageSize
return this.tableData.slice(start, start + this.pageSize)
} }
}, },
created() {
this.loadList()
},
methods: { methods: {
// 组装查询过滤条件(列表与导出共用,导出不含分页参数)
buildFilter() {
const q = {}
if (this.searchForm.js) q.jyxm = this.searchForm.js
if (this.searchForm.kbcnj) q.kxbcnj = this.searchForm.kbcnj
if (this.searchForm.kckmmc) q.kmc = this.searchForm.kckmmc
if (this.searchForm.xxbmc) q.xxbmc = this.searchForm.xxbmc
if (this.searchForm.xxkztEnabled) q.xkzt = this.searchForm.xxkzt
if (this.searchForm.pxccEnabled) q.pxcc = this.searchForm.pxcc
return q
},
// ==================== 查询 ==================== // ==================== 查询 ====================
handleQuery() { handleQuery() {
console.log('查询条件:', JSON.parse(JSON.stringify(this.searchForm))) this.currentPage = 1
this.$message.success('查询完成(前端模拟)') this.loadList()
},
loadList() {
this.loading = true
const params = Object.assign({ pageNum: this.currentPage, pageSize: this.pageSize }, this.buildFilter())
listElective(params)
.then(res => {
const data = (res && res.data) || {}
this.tableData = data.records || []
this.total = data.total || 0
})
.finally(() => {
this.loading = false
})
}, },
// ==================== 导出 ==================== // ==================== 导出 ====================
downloadBlob(content, filename) {
const blob = new Blob(['\ufeff' + content], { type: 'text/plain;charset=utf-8;' })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = filename
link.click()
URL.revokeObjectURL(link.href)
},
handleDownloadList() { handleDownloadList() {
this.downloadBlob('课程,教材,实施教员,教学场地,计划人数\n', '选修班列表.txt') exportElectiveList(this.buildFilter())
this.$message.success('选修班列表已下载(前端模拟)') .then(blob => {
saveAs(blob, '选修班列表.xlsx')
this.$message.success('选修班列表已下载')
})
.catch(() => {})
}, },
handleDownloadWord() { handleDownloadWord() {
this.downloadBlob('选修班学员名单\n', '选修班学员名单Word.txt') const bhList = this.selectedRows.map(row => row.bh)
this.$message.success('选修班学员名单Word已下载(前端模拟)') if (bhList.length === 0) {
this.$message.warning('请先选择选修班')
return
}
exportElectiveStudentsWord(bhList)
.then(blob => {
saveAs(blob, '选修班学员名单.docx')
this.$message.success('选修班学员名单Word已下载')
})
.catch(() => {})
}, },
handleDownloadExcel() { handleDownloadExcel() {
this.downloadBlob('选修班学员名单\n', '选修班学员名单Excel.txt') const bhList = this.selectedRows.map(row => row.bh)
this.$message.success('选修班学员名单Excel已下载(前端模拟)') if (bhList.length === 0) {
}, this.$message.warning('请先选择选修班')
handleDownloadTemplate() { return
this.downloadBlob('课程,教材,实施教员,教学场地,计划学时,学分,开课结课日期,报名日期,计划人数,要求说明\n', '选修课数据文件模板.txt') }
this.$message.success('【选修课数据文件模板】已下载(前端模拟)') exportElectiveStudentsExcel(bhList)
.then(blob => {
saveAs(blob, '选修班学员名单.xlsx')
this.$message.success('选修班学员名单Excel已下载')
})
.catch(() => {})
}, },
// ==================== 操作按钮 ==================== // ==================== 操作按钮 ====================
handleOpenEarly() { handleOpenEarly() {
if (this.selectedRows.length === 0) { const bhList = this.selectedRows.map(row => row.bh)
if (bhList.length === 0) {
this.$message.warning('请先选择选修班') this.$message.warning('请先选择选修班')
return return
} }
this.$message.success('所选班已早开放报名(前端模拟)') batchOpenElective(bhList)
.then(() => {
this.$message.success('所选班已开放报名')
this.loadList()
})
.catch(() => {})
}, },
handleCancelEarly() { handleCancelEarly() {
if (this.selectedRows.length === 0) { const bhList = this.selectedRows.map(row => row.bh)
if (bhList.length === 0) {
this.$message.warning('请先选择选修班') this.$message.warning('请先选择选修班')
return return
} }
this.$message.success('所选班已早取消开放报名(前端模拟)') batchCancelOpenElective(bhList)
.then(() => {
this.$message.success('所选班已取消开放报名')
this.loadList()
})
.catch(() => {})
}, },
handleStopSignup() { handleStopSignup() {
if (this.selectedRows.length === 0) { const bhList = this.selectedRows.map(row => row.bh)
if (bhList.length === 0) {
this.$message.warning('请先选择选修班') this.$message.warning('请先选择选修班')
return return
} }
this.$message.success('已批量停止报名(前端模拟)') batchStopElective(bhList)
.then(() => {
this.$message.success('已批量停止报名')
this.loadList()
})
.catch(() => {})
}, },
handleReverseRange() { handleReverseRange() {
if (this.selectedRows.length === 0) { this.$message.warning('后端暂未提供该接口')
this.$message.warning('请先选择选修班') },
return handleDownloadTemplate() {
} this.$message.warning('后端暂未提供该接口')
this.$message.success('已根据学员反向确定班次范围(前端模拟)')
}, },
// ==================== 文件上传 ==================== // ==================== 文件上传 ====================
@@ -322,8 +378,7 @@ export default {
this.$message.warning('请先选择文件') this.$message.warning('请先选择文件')
return return
} }
console.log('上传文件:', this.selectedFile.name) this.$message.warning('后端暂未提供该接口')
this.$message.success(`文件「${this.selectedFile.name}」上传成功(前端模拟)`)
}, },
// ==================== 表格多选 ==================== // ==================== 表格多选 ====================
@@ -333,8 +388,7 @@ export default {
// ==================== 新建选修课弹窗 ==================== // ==================== 新建选修课弹窗 ====================
handleOpenNew() { handleOpenNew() {
Object.assign(this.form, { kcmc: '', js: '', jc: '', jxcd: '', jhsxs: 0, yxsxs: 0, xf: 0, jh: 0 }) this.$message.warning('后端暂未提供该接口')
this.dialogVisible = true
}, },
handleNewConfirm() { handleNewConfirm() {
if (!this.$refs.formRef) return if (!this.$refs.formRef) return
@@ -349,6 +403,7 @@ export default {
// ==================== 分页 ==================== // ==================== 分页 ====================
handlePageChange(page) { handlePageChange(page) {
this.currentPage = page this.currentPage = page
this.loadList()
}, },
// 表格序号(跨页连续) // 表格序号(跨页连续)
@@ -592,6 +592,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.shift-semester-page { .shift-semester-page {
// ========== 页面标题 ========== // ========== 页面标题 ==========
.page-title { .page-title {
@@ -603,6 +607,11 @@ export default {
border-left: 4px solid var(--edu-green-primary); border-left: 4px solid var(--edu-green-primary);
} }
// ========== 1. 查询条件区域 ==========
.search-card {
margin-bottom: 16px;
}
// ========== 2. 工具栏按钮区 ========== // ========== 2. 工具栏按钮区 ==========
.list-toolbar { .list-toolbar {
display: flex; display: flex;
@@ -298,7 +298,7 @@
</template> </template>
<script> <script>
import { listSubject, addSubject, updateSubject, deleteSubject, getSubject } from '@/api/teachOffice/subject' import { listKb as listSubject, addKb as addSubject, updateKb as updateSubject, deleteKb as deleteSubject, getKb } from '@/api/teachOffice/kb'
export default { export default {
name: 'SubjectIndex', name: 'SubjectIndex',
@@ -565,6 +565,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
// ==================== 1. 顶部状态提示 ==================== // ==================== 1. 顶部状态提示 ====================
.status-tip { .status-tip {
display: inline-block; display: inline-block;
@@ -578,6 +582,8 @@ export default {
// ==================== 2. 查询条件区域 ==================== // ==================== 2. 查询条件区域 ====================
.search-card { .search-card {
margin-bottom: 16px;
.query-field { .query-field {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -441,6 +441,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.task-plan-page { .task-plan-page {
.page-title { .page-title {
text-align: center; text-align: center;
@@ -452,6 +456,8 @@ export default {
// ========== 1. 查询条件区域 ========== // ========== 1. 查询条件区域 ==========
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.el-form-item { .el-form-item {
margin-bottom: 0; margin-bottom: 0;
@@ -484,6 +490,12 @@ export default {
width: 100%; width: 100%;
} }
.pagination {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
.text-danger { .text-danger {
color: #f56c6c; color: #f56c6c;
} }
@@ -992,6 +992,8 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.teacher-page { .teacher-page {
.search-card { .search-card {
margin-bottom: 16px;
.search-form { .search-form {
.el-form-item { .el-form-item {
margin-bottom: 0; margin-bottom: 0;
@@ -1006,5 +1008,47 @@ export default {
border-top: 1px solid #ebeef5; border-top: 1px solid #ebeef5;
} }
} }
.list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
}
.list-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 16px;
.left-group,
.right-group {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
}
.table-card {
margin-bottom: 16px;
::v-deep(.el-table) {
width: 100%;
}
.pagination-wrap {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
}
.danger-text {
color: #f56c6c;
}
} }
</style> </style>
+19
View File
@@ -1468,6 +1468,10 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.app-container {
padding: 20px;
}
.textbook-tabs { .textbook-tabs {
.search-card { .search-card {
margin-bottom: 16px; margin-bottom: 16px;
@@ -1491,6 +1495,13 @@ export default {
} }
} }
.list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
}
.list-toolbar { .list-toolbar {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1521,9 +1532,17 @@ export default {
} }
.table-card { .table-card {
margin-bottom: 16px;
::v-deep(.el-table) { ::v-deep(.el-table) {
width: 100%; width: 100%;
} }
.pagination-wrap {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
} }
.margin-left-10 { .margin-left-10 {