gitignore更新

This commit is contained in:
2026-01-15 10:37:50 +08:00
parent 140c586128
commit bc4a89258e
34 changed files with 823 additions and 591 deletions

View File

@@ -1,18 +1,137 @@
# 培训系统 (Peixun) # 道路救援企业培训系统
基于 Spring Boot 3.1.2 的企业级培训管理系统 > 版本V1.0.1 | 基于 Spring Boot 3.1.2
为道路救援企业打造的一站式内部培训平台,通过知识沉淀、在线考核、培训管理三大核心能力,提升员工专业技能水平和服务标准化程度。
---
## 技术栈 ## 技术栈
- **Java**: 17 | 类别 | 技术 | 版本 |
- **构建工具**: Maven |-----|------|------|
- **框架**: Spring Boot 3.1.2 | 语言 | Java | 17 |
- **ORM**: MyBatis Plus 3.5.3.1 | 构建 | Maven | 3.6+ |
- **数据库**: MySQL 8.0.33 | 框架 | Spring Boot | 3.1.2 |
- **API文档**: Springdoc OpenAPI 2.2.0 | ORM | MyBatis Plus | 3.5.3.1 |
- **序列化**: Jackson | 数据库 | MySQL | 8.0+ |
- **工具库**: Lombok | 认证 | JWT (java-jwt) | 4.4.0 |
| API文档 | Springdoc OpenAPI | 2.2.0 |
| 工具库 | Lombok、Hutool | - |
---
## 功能模块
| 模块 | 功能说明 |
|-----|---------|
| **人员管理** | 组织架构(中心→部门→小组)、员工管理、角色权限 |
| **知识库** | 文档/视频上传、在线预览、分类管理、状态流转 |
| **考题管理** | 单选/多选/判断题、题目解析、题库分类 |
| **试卷管理** | 手动组卷、自动组卷、试卷预览 |
| **考试管理** | 发布考试、指定对象、在线答题、自动阅卷 |
| **培训计划** | 关联多个知识+多个考试、分配学员、进度跟踪 |
---
## 快速开始
### 环境要求
- JDK 17+
- Maven 3.6+
- MySQL 8.0+
### 1. 克隆项目
```bash
git clone <repository-url>
cd training-system
```
### 2. 初始化数据库
```sql
CREATE DATABASE training_system DEFAULT CHARACTER SET utf8mb4;
USE training_system;
SOURCE sql/init.sql;
```
### 3. 修改配置
编辑 `src/main/resources/application.yml`,配置数据库连接:
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/training_system
username: root
password: 你的密码
```
### 4. 启动应用
```bash
mvn spring-boot:run
```
### 5. 访问系统
- 系统地址http://localhost:8080
- API文档http://localhost:8080/swagger-ui.html
- 默认账号:`admin` / `123456`
---
## 生产部署
### 打包
```bash
mvn clean package -DskipTests
```
生成文件:`target/training-system-1.0.0.jar`
### Linux部署
```bash
# 上传JAR包和SQL脚本到服务器
scp target/training-system-1.0.0.jar user@server:/opt/training/
scp sql/init.sql user@server:/opt/training/
# 创建生产配置 /opt/training/application-prod.yml
# 启动应用
java -jar training-system-1.0.0.jar --spring.profiles.active=prod
```
详细部署指南见 [部署文档](docs/Deploy.md)
---
## 项目结构
```
training-system/
├── src/main/java/com/sino/training/
│ ├── common/ # 公共模块(配置、异常、工具类)
│ ├── module/
│ │ ├── system/ # 系统模块(用户、部门、小组)
│ │ ├── knowledge/ # 知识库模块
│ │ ├── exam/ # 考试模块(题目、试卷、考试)
│ │ └── training/ # 培训计划模块
│ └── TrainingApplication.java
├── src/main/resources/
│ ├── static/ # 前端静态资源
│ ├── application.yml # 配置文件
│ └── mapper/ # MyBatis XML
├── sql/
│ └── init.sql # 数据库初始化脚本
├── docs/ # 项目文档
└── pom.xml
```
---
## 编码规范 ## 编码规范
@@ -21,6 +140,20 @@
- Service + Impl 负责业务处理 - Service + Impl 负责业务处理
- Mapper 只做数据访问 - Mapper 只做数据访问
- 必须使用 Lombok 简化代码 - 必须使用 Lombok 简化代码
- 所有代码必须可读、可维护、有必要注释
- 生成的代码必须可直接运行
---
## 相关文档
- [产品需求文档 (PRD)](docs/PRD.md)
- [低层级需求文档 (LLR)](docs/LLR.md)
- [测试计划](docs/TestPlan.md)
---
## 版本记录
| 版本 | 日期 | 更新内容 |
|-----|------|---------|
| V1.0.1 | 2026-01-13 | 培训计划支持多考试任务 |
| V1.0.0 | 2026-01-08 | 初始版本发布 |

View File

@@ -0,0 +1,31 @@
# Role: Architect Agent系统架构师
## 你的身份
你是系统架构师,负责整体技术设计。
## 你的目标
- 设计清晰、可扩展的系统架构
- 降低长期复杂度
## 你可以做的事
- 技术选型
- 系统拆分
- 定义模块边界和接口规范
## 你不能做的事
- 不实现具体业务逻辑
- 不写完整功能代码
## 输入
- requirements.md
- Supervisor 指令
## 输出
- architecture.md
- 目录结构建议
- API 设计说明
## 工作规则
- 设计必须支持未来扩展
- 避免过度设计
- 明确模块职责

View File

@@ -0,0 +1,30 @@
# Role: Backend Agent后端工程师
## 你的身份
你是后端工程师,只负责实现后端业务逻辑。
## 你的目标
- 按架构和需求实现稳定、可测试的代码
## 你可以做的事
- 编写业务代码
- 实现 API
- 编写必要的单元测试
## 你不能做的事
- 不更改架构设计
- 不新增未经批准的功能
## 输入
- architecture.md
- requirements.md
- Supervisor 指令
## 输出
- 后端源码
- 测试代码
## 工作规则
- 代码必须可读
- 必须遵循项目规范
- 所有假设必须说明

View File

@@ -0,0 +1,20 @@
# Role: DevOps Agent部署与运维
## 你的身份
你负责系统交付与运行环境。
## 你的目标
- 系统可部署、可回滚、可监控
## 输入
- 架构设计
- 运行要求
## 输出
- 部署方案
- CI/CD 建议
- 环境说明
## 工作规则
- 优先稳定性
- 避免复杂配置

View File

@@ -0,0 +1,28 @@
# Role: Doc Agent文档工程师
## 你的身份
你是项目文档负责人。
## 你的目标
- 让人和 AI 都能快速理解项目
## 你可以做的事
- 编写 README
- 编写使用说明和开发规范
## 你不能做的事
- 不修改代码
- 不解释未实现的功能
## 输入
- 最终代码
- 架构与需求文档
## 输出
- README.md
- 使用与维护说明
## 工作规则
- 文档必须准确
- 避免废话
- 假设读者是新加入的开发者或 AI

View File

@@ -0,0 +1,28 @@
# Role: Frontend Agent前端工程师
## 你的身份
你是前端工程师,负责 UI 与交互实现。
## 你的目标
- 提供清晰、一致的用户体验
## 你可以做的事
- 编写前端代码
- 实现页面和交互逻辑
## 你不能做的事
- 不改后端接口定义
- 不引入未确认的 UI 框架
## 输入
- architecture.md
- requirements.md
- API 文档
## 输出
- 前端源码
- 简要交互说明
## 工作规则
- 优先可维护性
- 不做“看起来更酷”的无关改动

View File

@@ -0,0 +1,32 @@
# Role: Product Manager Agent产品经理
## 你的身份
你是负责需求分析和功能拆解的产品经理。
## 你的目标
- 将模糊需求转化为清晰、可执行的需求
- 定义验收标准
## 你可以做的事
- 追问需求细节
- 编写用户故事User Story
- 定义功能边界和非功能需求
## 你不能做的事
- 不做技术选型
- 不设计系统架构
- 不写代码
## 输入
- 用户原始需求
- Supervisor 的指令
## 输出
- requirements.md
- 功能清单
- 验收标准Acceptance Criteria
## 工作规则
- 所有需求必须可测试
- 明确“不做什么”
- 避免模糊词(如:尽量、可能)

View File

@@ -0,0 +1,29 @@
# Role: QA / Tester Agent测试工程师
## 你的身份
你是专门负责找问题的人。
## 你的目标
- 尽可能暴露缺陷和风险
## 你可以做的事
- 设计测试用例
- 提出反例和异常场景
- 发现逻辑漏洞
## 你不能做的事
- 不修复代码
- 不修改需求
## 输入
- 功能说明
- 源码或接口定义
## 输出
- 测试用例
- Bug 列表
- 风险说明
## 工作规则
- 假设开发会犯错
- 重点关注边界条件

View File

@@ -0,0 +1,29 @@
# Role: Security Agent安全审计
## 你的身份
你是安全专家。
## 你的目标
- 发现安全漏洞和设计风险
## 你可以做的事
- 审查代码和接口
- 指出潜在攻击面
- 提供修复建议
## 你不能做的事
- 不实现功能
- 不更改业务逻辑
## 输入
- 架构设计
- 代码或接口文档
## 输出
- 安全问题清单
- 风险等级
- 修复建议
## 工作规则
- 默认系统处于敌对环境
- 不忽略“看起来不太可能”的问题

View File

@@ -0,0 +1,34 @@
# Role: Supervisor Agent项目总负责人
## 你的身份
你是整个项目的总负责人,负责项目最终质量与方向。
你不写具体业务代码。
## 你的目标
- 确保项目符合需求、可维护、可扩展
- 确保每个 Agent 各司其职
- 防止范围蔓延和架构混乱
## 你可以做的事
- 拆分项目阶段
- 指派 Agent 执行任务
- 审核、拒绝或要求返工任何 Agent 的输出
- 汇总各 Agent 结果
## 你不能做的事
- 不直接编写业务代码
- 不绕过其他 Agent 直接下结论
## 输入
- 用户需求
- 各 Agent 的输出文档
## 输出
- 决策说明
- 是否通过 / 是否返工
- 下一步执行指令
## 工作规则
- 若信息不足,必须要求澄清
- 优先考虑长期维护而非短期实现
- 所有结论必须有理由

View File

@@ -29,3 +29,6 @@ MVP原型设计与确认:在我确认上述路线图后,请你仅针对 MVP版
## prompt:适用于需求变更 ## prompt:适用于需求变更
{我想增加/修改/优化.......。}请给出解决方案用ASCII绘制成原型图把所有影响到的部分绘制出来包括原型和技术方案。注意请仔细检查不要影响非相关模块要保证依据你的方案实现后能完成完美的实现需求。 {我想增加/修改/优化.......。}请给出解决方案用ASCII绘制成原型图把所有影响到的部分绘制出来包括原型和技术方案。注意请仔细检查不要影响非相关模块要保证依据你的方案实现后能完成完美的实现需求。
## prompt:版本更新-PRD.md文档变更
汇总一下本次版本更新这个版本号设定为1.0.1在PRD.md文档顶部新版本更新区域写入对应的产品更新对应的ASCII图以及涉及到的技术架构和要点更新。

View File

@@ -3,6 +3,63 @@
* 基于 Bootstrap 5 扩展 * 基于 Bootstrap 5 扩展
*/ */
/* ========== CSS变量体系 ========== */
:root {
/* 主色系 - 蓝色 */
--primary-color: #0d6efd;
--primary-hover: #0b5ed7;
--primary-light: rgba(13, 110, 253, 0.1);
--primary-gradient: linear-gradient(135deg, #0d6efd 0%, #0dcaf0 100%);
/* 侧边栏 */
--sidebar-bg: linear-gradient(180deg, #1a1c23 0%, #2d3748 100%);
--sidebar-width: 250px;
/* 文字颜色 */
--text-primary: #1a1c23;
--text-secondary: #6c757d;
--text-muted: #94a3b8;
/* 边框与背景 */
--border-color: #e9ecef;
--bg-light: #f8f9fa;
--bg-card: #ffffff;
--bg-hover: rgba(255, 255, 255, 0.08);
/* 状态色 */
--success-color: #198754;
--success-light: rgba(25, 135, 84, 0.1);
--warning-color: #ffc107;
--warning-light: rgba(255, 193, 7, 0.1);
--danger-color: #dc3545;
--danger-light: rgba(220, 53, 69, 0.1);
--info-color: #0dcaf0;
--info-light: rgba(13, 202, 240, 0.1);
/* 阴影 */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);
/* 圆角 */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
/* 间距 */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
/* 动画 */
--transition-fast: 0.15s ease;
--transition-normal: 0.2s ease;
--transition-slow: 0.3s ease;
}
/* ========== 布局相关 ========== */ /* ========== 布局相关 ========== */
html, body { html, body {
height: 100%; height: 100%;
@@ -16,14 +73,14 @@ html, body {
/* ========== 侧边栏 ========== */ /* ========== 侧边栏 ========== */
.sidebar { .sidebar {
width: 250px; width: var(--sidebar-width);
min-height: 100vh; min-height: 100vh;
background: linear-gradient(180deg, #1a1c23 0%, #2d3748 100%); background: var(--sidebar-bg);
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
z-index: 1000; z-index: 1000;
transition: all 0.3s ease; transition: all var(--transition-slow);
} }
.sidebar-logo { .sidebar-logo {
@@ -38,8 +95,8 @@ html, body {
.sidebar-logo-icon { .sidebar-logo-icon {
width: 36px; width: 36px;
height: 36px; height: 36px;
background: linear-gradient(135deg, #0d6efd 0%, #0dcaf0 100%); background: var(--primary-gradient);
border-radius: 8px; border-radius: var(--radius-md);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -75,20 +132,20 @@ html, body {
padding: 12px 20px; padding: 12px 20px;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
text-decoration: none; text-decoration: none;
transition: all 0.2s ease; transition: all var(--transition-normal);
cursor: pointer; cursor: pointer;
border-left: 3px solid transparent; border-left: 3px solid transparent;
} }
.menu-item:hover { .menu-item:hover {
color: #fff; color: #fff;
background: rgba(255, 255, 255, 0.08); background: var(--bg-hover);
} }
.menu-item.active { .menu-item.active {
color: #fff; color: #fff;
background: rgba(13, 110, 253, 0.2); background: var(--primary-light);
border-left-color: #0d6efd; border-left-color: var(--primary-color);
} }
.menu-item i { .menu-item i {
@@ -135,12 +192,18 @@ html, body {
font-size: 14px; font-size: 14px;
} }
/* 侧边栏分隔线 */
.sidebar-divider {
border-top: 1px solid rgba(255, 255, 255, 0.1);
margin: var(--spacing-md) 0;
}
/* ========== 主内容区 ========== */ /* ========== 主内容区 ========== */
.main-wrapper { .main-wrapper {
flex: 1; flex: 1;
margin-left: 250px; margin-left: var(--sidebar-width);
min-height: 100vh; min-height: 100vh;
background-color: #f8f9fa; background-color: var(--bg-light);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
@@ -148,12 +211,12 @@ html, body {
/* 顶部导航 */ /* 顶部导航 */
.top-header { .top-header {
height: 64px; height: 64px;
background: #fff; background: var(--bg-card);
border-bottom: 1px solid #e9ecef; border-bottom: 1px solid var(--border-color);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 24px; padding: 0 var(--spacing-lg);
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 100; z-index: 100;
@@ -162,7 +225,7 @@ html, body {
.header-title { .header-title {
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
color: #1a1c23; color: var(--text-primary);
} }
.header-user { .header-user {
@@ -175,32 +238,32 @@ html, body {
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 50%; border-radius: 50%;
background: linear-gradient(135deg, #0d6efd 0%, #0dcaf0 100%); background: var(--primary-gradient);
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-weight: 500; font-weight: 500;
margin-right: 8px; margin-right: var(--spacing-sm);
} }
/* 内容区域 */ /* 内容区域 */
.main-content { .main-content {
flex: 1; flex: 1;
padding: 24px; padding: var(--spacing-lg);
} }
/* ========== 页面卡片 ========== */ /* ========== 页面卡片 ========== */
.page-card { .page-card {
background: #fff; background: var(--bg-card);
border-radius: 8px; border-radius: var(--radius-md);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); box-shadow: var(--shadow-sm);
margin-bottom: 24px; margin-bottom: var(--spacing-lg);
} }
.page-card-header { .page-card-header {
padding: 16px 24px; padding: var(--spacing-md) var(--spacing-lg);
border-bottom: 1px solid #e9ecef; border-bottom: 1px solid var(--border-color);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@@ -209,69 +272,69 @@ html, body {
.page-card-title { .page-card-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #1a1c23; color: var(--text-primary);
margin: 0; margin: 0;
} }
.page-card-body { .page-card-body {
padding: 24px; padding: var(--spacing-lg);
} }
/* ========== 统计卡片 ========== */ /* ========== 统计卡片 ========== */
.stat-card { .stat-card {
background: #fff; background: var(--bg-card);
border-radius: 8px; border-radius: var(--radius-md);
padding: 24px; padding: var(--spacing-lg);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); box-shadow: var(--shadow-sm);
transition: all 0.2s ease; transition: all var(--transition-normal);
} }
.stat-card:hover { .stat-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); box-shadow: var(--shadow-md);
transform: translateY(-2px); transform: translateY(-2px);
} }
.stat-card-icon { .stat-card-icon {
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 12px; border-radius: var(--radius-lg);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 24px; font-size: 24px;
margin-bottom: 16px; margin-bottom: var(--spacing-md);
} }
.stat-card-icon.primary { .stat-card-icon.primary {
background: rgba(13, 110, 253, 0.1); background: var(--primary-light);
color: #0d6efd; color: var(--primary-color);
} }
.stat-card-icon.success { .stat-card-icon.success {
background: rgba(25, 135, 84, 0.1); background: var(--success-light);
color: #198754; color: var(--success-color);
} }
.stat-card-icon.warning { .stat-card-icon.warning {
background: rgba(255, 193, 7, 0.1); background: var(--warning-light);
color: #ffc107; color: var(--warning-color);
} }
.stat-card-icon.info { .stat-card-icon.info {
background: rgba(13, 202, 240, 0.1); background: var(--info-light);
color: #0dcaf0; color: var(--info-color);
} }
.stat-card-value { .stat-card-value {
font-size: 28px; font-size: 28px;
font-weight: 700; font-weight: 700;
color: #1a1c23; color: var(--text-primary);
margin-bottom: 4px; margin-bottom: var(--spacing-xs);
} }
.stat-card-label { .stat-card-label {
font-size: 14px; font-size: 14px;
color: #6c757d; color: var(--text-secondary);
} }
/* ========== 工具栏 ========== */ /* ========== 工具栏 ========== */
@@ -280,21 +343,21 @@ html, body {
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: var(--spacing-sm);
margin-bottom: 20px; margin-bottom: var(--spacing-lg);
} }
.toolbar-left { .toolbar-left {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
gap: 12px; gap: var(--spacing-sm);
} }
.toolbar-right { .toolbar-right {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: var(--spacing-sm);
} }
/* ========== 表格增强 ========== */ /* ========== 表格增强 ========== */
@@ -304,8 +367,8 @@ html, body {
.table th { .table th {
font-weight: 600; font-weight: 600;
color: #495057; color: var(--text-secondary);
background-color: #f8f9fa; background-color: var(--bg-light);
white-space: nowrap; white-space: nowrap;
} }
@@ -365,8 +428,8 @@ html, body {
/* ========== 空状态 ========== */ /* ========== 空状态 ========== */
.empty-state { .empty-state {
text-align: center; text-align: center;
padding: 48px 24px; padding: 48px var(--spacing-lg);
color: #6c757d; color: var(--text-secondary);
} }
.empty-state i { .empty-state i {
@@ -390,34 +453,34 @@ html, body {
/* ========== 文件上传区域 ========== */ /* ========== 文件上传区域 ========== */
.upload-area { .upload-area {
border: 2px dashed #dee2e6; border: 2px dashed var(--border-color);
border-radius: 8px; border-radius: var(--radius-md);
padding: 32px; padding: var(--spacing-xl);
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease; transition: all var(--transition-normal);
background: #f8f9fa; background: var(--bg-light);
} }
.upload-area:hover { .upload-area:hover {
border-color: #0d6efd; border-color: var(--primary-color);
background: rgba(13, 110, 253, 0.02); background: rgba(13, 110, 253, 0.02);
} }
.upload-area.dragover { .upload-area.dragover {
border-color: #0d6efd; border-color: var(--primary-color);
background: rgba(13, 110, 253, 0.05); background: rgba(13, 110, 253, 0.05);
} }
.upload-area i { .upload-area i {
font-size: 48px; font-size: 48px;
color: #6c757d; color: var(--text-secondary);
margin-bottom: 16px; margin-bottom: var(--spacing-md);
} }
.upload-area p { .upload-area p {
margin: 0; margin: 0;
color: #6c757d; color: var(--text-secondary);
} }
.upload-area .upload-hint { .upload-area .upload-hint {
@@ -457,54 +520,54 @@ html, body {
.answer-sheet { .answer-sheet {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: var(--spacing-sm);
} }
.answer-sheet-item { .answer-sheet-item {
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 4px; border-radius: var(--radius-sm);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
cursor: pointer; cursor: pointer;
border: 1px solid #dee2e6; border: 1px solid var(--border-color);
background: #fff; background: var(--bg-card);
transition: all 0.2s ease; transition: all var(--transition-normal);
} }
.answer-sheet-item:hover { .answer-sheet-item:hover {
border-color: #0d6efd; border-color: var(--primary-color);
} }
.answer-sheet-item.current { .answer-sheet-item.current {
border-color: #0d6efd; border-color: var(--primary-color);
background: #0d6efd; background: var(--primary-color);
color: #fff; color: #fff;
} }
.answer-sheet-item.answered { .answer-sheet-item.answered {
background: #d1e7dd; background: #d1e7dd;
border-color: #198754; border-color: var(--success-color);
color: #198754; color: var(--success-color);
} }
/* ========== 考试计时器 ========== */ /* ========== 考试计时器 ========== */
.exam-timer { .exam-timer {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: var(--spacing-sm);
padding: 8px 16px; padding: var(--spacing-sm) var(--spacing-md);
background: #fff3cd; background: var(--warning-light);
border-radius: 8px; border-radius: var(--radius-md);
font-weight: 600; font-weight: 600;
} }
.exam-timer.warning { .exam-timer.warning {
background: #f8d7da; background: var(--danger-light);
color: #842029; color: var(--danger-color);
} }
.exam-timer i { .exam-timer i {
@@ -526,11 +589,11 @@ html, body {
} }
.top-header { .top-header {
padding: 0 16px; padding: 0 var(--spacing-md);
} }
.main-content { .main-content {
padding: 16px; padding: var(--spacing-md);
} }
} }

View File

@@ -17,20 +17,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item active"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/list.html">考试管理</a></li><li class="breadcrumb-item active" id="pageTitle">发布考试</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/list.html">考试管理</a></li><li class="breadcrumb-item active" id="pageTitle">发布考试</li></ol></nav>
@@ -147,6 +134,8 @@
let examId = null, allUsers = [], filteredUsers = [], selectedUserIds = new Set(), papers = []; let examId = null, allUsers = [], filteredUsers = [], selectedUserIds = new Set(), papers = [];
document.addEventListener('DOMContentLoaded', async function() { document.addEventListener('DOMContentLoaded', async function() {
TrainingSystem.initSidebar('exam');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
examId = urlParams.get('id'); examId = urlParams.get('id');
loadPapers(); loadPapers();

View File

@@ -10,20 +10,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item active"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">考试管理</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">考试管理</li></ol></nav>
@@ -98,6 +85,8 @@
let currentPage = 1, pageSize = 10, detailModal; let currentPage = 1, pageSize = 10, detailModal;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('exam');
TrainingSystem.initUserInfo();
detailModal = new bootstrap.Modal(document.getElementById('detailModal')); detailModal = new bootstrap.Modal(document.getElementById('detailModal'));
loadList(); loadList();
}); });

View File

@@ -32,17 +32,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<a href="/exam/my-exams.html" class="menu-item active"><i class="bi bi-clipboard-check"></i><span>我的考试</span></a>
<a href="/training/my-training.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>我的培训</span></a>
<a href="/knowledge/list.html" class="menu-item"><i class="bi bi-journal-richtext"></i><span>知识学习</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>个人设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">我的考试</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">我的考试</li></ol></nav>
@@ -76,6 +66,8 @@
let allExams = [], currentTab = 'all'; let allExams = [], currentTab = 'all';
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('my-exams');
TrainingSystem.initUserInfo();
loadExams(); loadExams();
}); });

View File

@@ -37,20 +37,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item active"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/paper.html">试卷管理</a></li><li class="breadcrumb-item active" id="pageTitle">创建试卷</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/paper.html">试卷管理</a></li><li class="breadcrumb-item active" id="pageTitle">创建试卷</li></ol></nav>
@@ -197,6 +184,8 @@
let questionPage = 1, questionPageSize = 20, hasMore = true; let questionPage = 1, questionPageSize = 20, hasMore = true;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('paper');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
paperId = urlParams.get('id'); paperId = urlParams.get('id');
loadCategories(); loadCategories();

View File

@@ -39,20 +39,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar no-print"> <div id="sidebarContainer" class="no-print"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item active"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header no-print"> <header class="top-header no-print">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/paper.html">试卷管理</a></li><li class="breadcrumb-item active">试卷预览</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/paper.html">试卷管理</a></li><li class="breadcrumb-item active">试卷预览</li></ol></nav>
@@ -75,6 +62,8 @@
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('paper');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const paperId = urlParams.get('id'); const paperId = urlParams.get('id');
if (paperId) { if (paperId) {

View File

@@ -23,20 +23,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item active"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">试卷管理</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">试卷管理</li></ol></nav>
@@ -82,6 +69,8 @@
let currentPage = 1, pageSize = 10; let currentPage = 1, pageSize = 10;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('paper');
TrainingSystem.initUserInfo();
loadList(); loadList();
}); });

View File

@@ -20,20 +20,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item active">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item active">题库分类</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item active">题库分类</li></ol></nav>
@@ -63,7 +50,7 @@
<script> <script>
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
let treeData = [], selectedId = null, formModal; let treeData = [], selectedId = null, formModal;
document.addEventListener('DOMContentLoaded', function() { formModal = new bootstrap.Modal(document.getElementById('formModal')); loadTree(); }); document.addEventListener('DOMContentLoaded', function() { TrainingSystem.initSidebar('question-category'); TrainingSystem.initUserInfo(); formModal = new bootstrap.Modal(document.getElementById('formModal')); loadTree(); });
async function loadTree() { async function loadTree() {
const result = await TrainingSystem.get('/exam/question-category/tree'); const result = await TrainingSystem.get('/exam/question-category/tree');

View File

@@ -32,20 +32,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item active">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item"><a href="/exam/question.html">题目列表</a></li><li class="breadcrumb-item active" id="pageTitle">新增题目</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item"><a href="/exam/question.html">题目列表</a></li><li class="breadcrumb-item active" id="pageTitle">新增题目</li></ol></nav>
@@ -197,6 +184,8 @@
let currentType = 'SINGLE', selectedAnswers = [], judgeAnswer = '', questionId = null; let currentType = 'SINGLE', selectedAnswers = [], judgeAnswer = '', questionId = null;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('question');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
questionId = urlParams.get('id'); questionId = urlParams.get('id');
loadCategories(); loadCategories();

View File

@@ -29,20 +29,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item active">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item active">题目列表</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">考题管理</li><li class="breadcrumb-item active">题目列表</li></ol></nav>
@@ -153,6 +140,8 @@
let currentPage = 1, pageSize = 10, currentCategoryId = 0, categories = [], importModal; let currentPage = 1, pageSize = 10, currentCategoryId = 0, categories = [], importModal;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('question');
TrainingSystem.initUserInfo();
importModal = new bootstrap.Modal(document.getElementById('importModal')); importModal = new bootstrap.Modal(document.getElementById('importModal'));
// 从URL参数获取分类ID // 从URL参数获取分类ID
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);

View File

@@ -50,17 +50,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<a href="/exam/my-exams.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>我的考试</span></a>
<a href="/training/my-training.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>我的培训</span></a>
<a href="/knowledge/list.html" class="menu-item"><i class="bi bi-journal-richtext"></i><span>知识学习</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>个人设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/my-exams.html">我的考试</a></li><li class="breadcrumb-item active">考试成绩</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/exam/my-exams.html">我的考试</a></li><li class="breadcrumb-item active">考试成绩</li></ol></nav>
@@ -78,6 +68,8 @@
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('my-exams');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const recordId = urlParams.get('recordId'); const recordId = urlParams.get('recordId');
const examId = urlParams.get('examId'); const examId = urlParams.get('examId');

View File

@@ -13,76 +13,8 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<!-- 侧边栏 --> <!-- 侧边栏容器 - 动态渲染 -->
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo">
<div class="sidebar-logo-icon">
<i class="bi bi-truck text-white"></i>
</div>
<span class="sidebar-logo-text">道路救援培训系统</span>
</div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item active">
<i class="bi bi-grid-1x2"></i>
<span>工作台</span>
</a>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-people me-2"></i>人员管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/system/org.html" class="menu-item">组织架构</a>
<a href="/system/user.html" class="menu-item">员工管理</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-journal-richtext me-2"></i>知识库</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/knowledge/category.html" class="menu-item">知识分类</a>
<a href="/knowledge/list.html" class="menu-item">知识列表</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-pencil-square me-2"></i>考题管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/exam/question-category.html" class="menu-item">题库分类</a>
<a href="/exam/question.html" class="menu-item">题目列表</a>
</div>
</div>
<a href="/exam/paper.html" class="menu-item">
<i class="bi bi-file-earmark-text"></i>
<span>试卷管理</span>
</a>
<a href="/exam/list.html" class="menu-item">
<i class="bi bi-clipboard-check"></i>
<span>考试管理</span>
</a>
<a href="/training/plan.html" class="menu-item">
<i class="bi bi-calendar-check"></i>
<span>培训计划</span>
</a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item">
<i class="bi bi-gear"></i>
<span>系统设置</span>
</a>
</nav>
</aside>
<!-- 主内容区 --> <!-- 主内容区 -->
<div class="main-wrapper"> <div class="main-wrapper">
@@ -292,6 +224,9 @@
} }
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// 初始化侧边栏
TrainingSystem.initSidebar('dashboard');
// 初始化用户信息 // 初始化用户信息
initUserDisplay(); initUserDisplay();
@@ -301,7 +236,7 @@
// 加载工作台数据 // 加载工作台数据
loadDashboardData(); loadDashboardData();
// 初始化菜单 // 初始化用户头像显示
TrainingSystem.initUserInfo(); TrainingSystem.initUserInfo();
}); });

View File

@@ -468,12 +468,144 @@ function getStatusBadge(status, statusName) {
return `<span class="status-badge ${statusClass[status] || ''}">${statusName || status}</span>`; return `<span class="status-badge ${statusClass[status] || ''}">${statusName || status}</span>`;
} }
/**
* 菜单配置 - 根据角色控制可见性
* roles: ADMIN=管理员, LECTURER=讲师, STUDENT=学员
*/
const MENU_CONFIG = [
{
id: 'dashboard',
name: '工作台',
icon: 'bi-grid-1x2',
url: '/index.html',
roles: ['ADMIN', 'LECTURER', 'STUDENT']
},
{
id: 'system',
name: '人员管理',
icon: 'bi-people',
roles: ['ADMIN', 'LECTURER'],
children: [
{ id: 'org', name: '组织架构', url: '/system/org.html', roles: ['ADMIN'] },
{ id: 'user', name: '员工管理', url: '/system/user.html', roles: ['ADMIN', 'LECTURER'] }
]
},
{
id: 'knowledge',
name: '知识库',
icon: 'bi-journal-richtext',
roles: ['ADMIN', 'LECTURER', 'STUDENT'],
children: [
{ id: 'knowledge-category', name: '知识分类', url: '/knowledge/category.html', roles: ['ADMIN', 'LECTURER'] },
{ id: 'knowledge-list', name: '知识列表', url: '/knowledge/list.html', roles: ['ADMIN', 'LECTURER', 'STUDENT'] }
]
},
{
id: 'question',
name: '考题管理',
icon: 'bi-pencil-square',
roles: ['ADMIN', 'LECTURER'],
children: [
{ id: 'question-category', name: '题库分类', url: '/exam/question-category.html', roles: ['ADMIN', 'LECTURER'] },
{ id: 'question-list', name: '题目列表', url: '/exam/question.html', roles: ['ADMIN', 'LECTURER'] }
]
},
{
id: 'paper',
name: '试卷管理',
icon: 'bi-file-earmark-text',
url: '/exam/paper.html',
roles: ['ADMIN', 'LECTURER']
},
{
id: 'exam',
name: '考试管理',
icon: 'bi-clipboard-check',
url: '/exam/list.html',
roles: ['ADMIN', 'LECTURER', 'STUDENT']
},
{
id: 'training',
name: '培训计划',
icon: 'bi-calendar-check',
url: '/training/plan.html',
roles: ['ADMIN', 'LECTURER', 'STUDENT']
},
{
id: 'divider',
type: 'divider',
roles: ['ADMIN']
},
{
id: 'setting',
name: '系统设置',
icon: 'bi-gear',
url: '/system/setting.html',
roles: ['ADMIN']
}
];
/**
* 根据角色过滤菜单
*/
function filterMenuByRole(menuConfig, userRole) {
return menuConfig
.filter(item => item.roles.includes(userRole))
.map(item => {
if (item.children) {
return {
...item,
children: item.children.filter(child => child.roles.includes(userRole))
};
}
return item;
})
.filter(item => !item.children || item.children.length > 0);
}
/** /**
* 生成侧边栏HTML * 生成侧边栏HTML
*/ */
function renderSidebar(activeMenu) { function renderSidebar(activeMenu) {
const user = getCurrentUser();
const userRole = user?.role || 'STUDENT';
const filteredMenu = filterMenuByRole(MENU_CONFIG, userRole);
let menuHtml = '';
filteredMenu.forEach(item => {
if (item.type === 'divider') {
menuHtml += '<div class="sidebar-divider"></div>';
return;
}
if (item.children) {
// 判断子菜单是否有激活项
const hasActiveChild = item.children.some(child => child.id === activeMenu);
menuHtml += `
<div class="menu-group${hasActiveChild ? '' : ' collapsed'}">
<div class="menu-group-title">
<span><i class="bi ${item.icon} me-2"></i>${item.name}</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
${item.children.map(child => `
<a href="${child.url}" class="menu-item${child.id === activeMenu ? ' active' : ''}">${child.name}</a>
`).join('')}
</div>
</div>
`;
} else {
menuHtml += `
<a href="${item.url}" class="menu-item${item.id === activeMenu ? ' active' : ''}">
<i class="bi ${item.icon}"></i>
<span>${item.name}</span>
</a>
`;
}
});
return ` return `
<aside class="sidebar"> <aside class="sidebar" id="sidebar">
<div class="sidebar-logo"> <div class="sidebar-logo">
<div class="sidebar-logo-icon"> <div class="sidebar-logo-icon">
<i class="bi bi-truck text-white"></i> <i class="bi bi-truck text-white"></i>
@@ -481,70 +613,23 @@ function renderSidebar(activeMenu) {
<span class="sidebar-logo-text">道路救援培训系统</span> <span class="sidebar-logo-text">道路救援培训系统</span>
</div> </div>
<nav class="sidebar-menu"> <nav class="sidebar-menu">
<a href="/index.html" class="menu-item ${activeMenu === 'dashboard' ? 'active' : ''}"> ${menuHtml}
<i class="bi bi-grid-1x2"></i>
<span>工作台</span>
</a>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-people me-2"></i>人员管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/system/org.html" class="menu-item ${activeMenu === 'org' ? 'active' : ''}">组织架构</a>
<a href="/system/user.html" class="menu-item ${activeMenu === 'user' ? 'active' : ''}">员工管理</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-journal-richtext me-2"></i>知识库</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/knowledge/category.html" class="menu-item ${activeMenu === 'knowledge-category' ? 'active' : ''}">知识分类</a>
<a href="/knowledge/list.html" class="menu-item ${activeMenu === 'knowledge-list' ? 'active' : ''}">知识列表</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-pencil-square me-2"></i>考题管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/exam/question-category.html" class="menu-item ${activeMenu === 'question-category' ? 'active' : ''}">题库分类</a>
<a href="/exam/question.html" class="menu-item ${activeMenu === 'question' ? 'active' : ''}">题目列表</a>
</div>
</div>
<a href="/exam/paper.html" class="menu-item ${activeMenu === 'paper' ? 'active' : ''}">
<i class="bi bi-file-earmark-text"></i>
<span>试卷管理</span>
</a>
<a href="/exam/list.html" class="menu-item ${activeMenu === 'exam' ? 'active' : ''}">
<i class="bi bi-clipboard-check"></i>
<span>考试管理</span>
</a>
<a href="/training/plan.html" class="menu-item ${activeMenu === 'training' ? 'active' : ''}">
<i class="bi bi-calendar-check"></i>
<span>培训计划</span>
</a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item ${activeMenu === 'setting' ? 'active' : ''}">
<i class="bi bi-gear"></i>
<span>系统设置</span>
</a>
</nav> </nav>
</aside> </aside>
`; `;
} }
/**
* 初始化侧边栏(动态渲染到页面)
*/
function initSidebar(activeMenu) {
const sidebarContainer = document.getElementById('sidebarContainer');
if (sidebarContainer) {
sidebarContainer.innerHTML = renderSidebar(activeMenu);
initMenuState();
}
}
/** /**
* 生成顶部导航HTML * 生成顶部导航HTML
*/ */
@@ -611,8 +696,10 @@ window.TrainingSystem = {
renderPagination, renderPagination,
initPage, initPage,
initUserInfo, initUserInfo,
initMenuState,
logout, logout,
getStatusBadge, getStatusBadge,
renderSidebar, renderSidebar,
initSidebar,
renderHeader renderHeader
}; };

View File

@@ -29,41 +29,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo">
<div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div>
<span class="sidebar-logo-text">道路救援培训系统</span>
</div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group">
<div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div>
<div class="menu-submenu">
<a href="/system/org.html" class="menu-item">组织架构</a>
<a href="/system/user.html" class="menu-item">员工管理</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div>
<div class="menu-submenu">
<a href="/knowledge/category.html" class="menu-item active">知识分类</a>
<a href="/knowledge/list.html" class="menu-item">知识列表</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div>
<div class="menu-submenu">
<a href="/exam/question-category.html" class="menu-item">题库分类</a>
<a href="/exam/question.html" class="menu-item">题目列表</a>
</div>
</div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
@@ -136,6 +102,8 @@
let treeData = [], selectedId = null, formModal; let treeData = [], selectedId = null, formModal;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('knowledge-category');
TrainingSystem.initUserInfo();
formModal = new bootstrap.Modal(document.getElementById('formModal')); formModal = new bootstrap.Modal(document.getElementById('formModal'));
loadTree(); loadTree();
}); });

View File

@@ -14,75 +14,7 @@
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<!-- 侧边栏 --> <!-- 侧边栏 -->
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo">
<div class="sidebar-logo-icon">
<i class="bi bi-truck text-white"></i>
</div>
<span class="sidebar-logo-text">道路救援培训系统</span>
</div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item">
<i class="bi bi-grid-1x2"></i>
<span>工作台</span>
</a>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-people me-2"></i>人员管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/system/org.html" class="menu-item">组织架构</a>
<a href="/system/user.html" class="menu-item">员工管理</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-journal-richtext me-2"></i>知识库</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/knowledge/category.html" class="menu-item">知识分类</a>
<a href="/knowledge/list.html" class="menu-item active">知识列表</a>
</div>
</div>
<div class="menu-group">
<div class="menu-group-title">
<span><i class="bi bi-pencil-square me-2"></i>考题管理</span>
<i class="bi bi-chevron-down arrow"></i>
</div>
<div class="menu-submenu">
<a href="/exam/question-category.html" class="menu-item">题库分类</a>
<a href="/exam/question.html" class="menu-item">题目列表</a>
</div>
</div>
<a href="/exam/paper.html" class="menu-item">
<i class="bi bi-file-earmark-text"></i>
<span>试卷管理</span>
</a>
<a href="/exam/list.html" class="menu-item">
<i class="bi bi-clipboard-check"></i>
<span>考试管理</span>
</a>
<a href="/training/plan.html" class="menu-item">
<i class="bi bi-calendar-check"></i>
<span>培训计划</span>
</a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item">
<i class="bi bi-gear"></i>
<span>系统设置</span>
</a>
</nav>
</aside>
<!-- 主内容区 --> <!-- 主内容区 -->
<div class="main-wrapper"> <div class="main-wrapper">
@@ -283,6 +215,8 @@
let formModal; let formModal;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('knowledge-list');
TrainingSystem.initUserInfo();
formModal = new bootstrap.Modal(document.getElementById('formModal')); formModal = new bootstrap.Modal(document.getElementById('formModal'));
loadCategories(); loadCategories();
loadList(); loadList();

View File

@@ -34,17 +34,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<a href="/exam/my-exams.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>我的考试</span></a>
<a href="/training/my-training.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>我的培训</span></a>
<a href="/knowledge/list.html" class="menu-item active"><i class="bi bi-journal-richtext"></i><span>知识学习</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>个人设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/knowledge/list.html">知识学习</a></li><li class="breadcrumb-item active" id="breadcrumbTitle">详情</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/knowledge/list.html">知识学习</a></li><li class="breadcrumb-item active" id="breadcrumbTitle">详情</li></ol></nav>
@@ -63,6 +53,8 @@
let knowledgeId = null, startTime = null; let knowledgeId = null, startTime = null;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('knowledge-list');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
knowledgeId = urlParams.get('id'); knowledgeId = urlParams.get('id');
if (knowledgeId) { if (knowledgeId) {

View File

@@ -9,12 +9,17 @@
<!-- Bootstrap Icons --> <!-- Bootstrap Icons -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" rel="stylesheet">
<style> <style>
:root {
--primary-color: #0d6efd;
--primary-hover: #0b5ed7;
--primary-gradient: linear-gradient(135deg, #0d6efd 0%, #0dcaf0 100%);
}
body { body {
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: var(--primary-gradient);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
} }
@@ -40,13 +45,13 @@
.login-logo { .login-logo {
width: 64px; width: 64px;
height: 64px; height: 64px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: var(--primary-gradient);
border-radius: 16px; border-radius: 16px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin: 0 auto 20px; margin: 0 auto 20px;
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4); box-shadow: 0 8px 24px rgba(13, 110, 253, 0.4);
} }
.login-logo i { .login-logo i {
@@ -83,8 +88,8 @@
} }
.form-floating > .form-control:focus { .form-floating > .form-control:focus {
border-color: #667eea; border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.15); box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15);
} }
.form-floating > label { .form-floating > label {
@@ -103,7 +108,7 @@
} }
.form-floating:focus-within .input-icon { .form-floating:focus-within .input-icon {
color: #667eea; color: var(--primary-color);
} }
.btn-login { .btn-login {
@@ -112,14 +117,14 @@
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
border-radius: 8px; border-radius: 8px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: var(--primary-gradient);
border: none; border: none;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
.btn-login:hover { .btn-login:hover {
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.4); box-shadow: 0 8px 24px rgba(13, 110, 253, 0.4);
} }
.divider { .divider {
@@ -189,7 +194,7 @@
} }
.password-toggle:hover { .password-toggle:hover {
color: #667eea; color: var(--primary-color);
} }
@media (max-width: 480px) { @media (max-width: 480px) {
@@ -328,7 +333,7 @@
if (result && result.code === 200) { if (result && result.code === 200) {
TrainingSystem.setToken(result.data.token); TrainingSystem.setToken(result.data.token);
TrainingSystem.setCurrentUser(result.data.user); TrainingSystem.setCurrentUser(result.data);
TrainingSystem.showMessage('登录成功', 'success'); TrainingSystem.showMessage('登录成功', 'success');
setTimeout(() => { setTimeout(() => {

View File

@@ -24,20 +24,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item active">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">人员管理</li><li class="breadcrumb-item active">组织架构</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">人员管理</li><li class="breadcrumb-item active">组织架构</li></ol></nav>
@@ -67,7 +54,12 @@
<script> <script>
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
let orgData = [], selectedNode = null, formModal; let orgData = [], selectedNode = null, formModal;
document.addEventListener('DOMContentLoaded', function() { formModal = new bootstrap.Modal(document.getElementById('formModal')); loadOrgTree(); }); document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('org');
TrainingSystem.initUserInfo();
formModal = new bootstrap.Modal(document.getElementById('formModal'));
loadOrgTree();
});
async function loadOrgTree() { async function loadOrgTree() {
const result = await TrainingSystem.get('/system/org/tree'); const result = await TrainingSystem.get('/system/org/tree');

View File

@@ -10,20 +10,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item active">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">人员管理</li><li class="breadcrumb-item active">员工管理</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item">人员管理</li><li class="breadcrumb-item active">员工管理</li></ol></nav>
@@ -60,7 +47,13 @@
<script> <script>
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
let currentPage = 1, pageSize = 10, departments = [], formModal; let currentPage = 1, pageSize = 10, departments = [], formModal;
document.addEventListener('DOMContentLoaded', function() { formModal = new bootstrap.Modal(document.getElementById('formModal')); loadDepartments(); loadList(); }); document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('user');
TrainingSystem.initUserInfo();
formModal = new bootstrap.Modal(document.getElementById('formModal'));
loadDepartments();
loadList();
});
document.getElementById('formDept').addEventListener('change', function() { loadGroups(this.value); }); document.getElementById('formDept').addEventListener('change', function() { loadGroups(this.value); });
async function loadDepartments() { async function loadDepartments() {

View File

@@ -35,20 +35,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item active"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/training/plan.html">培训计划</a></li><li class="breadcrumb-item active">培训详情</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/training/plan.html">培训计划</a></li><li class="breadcrumb-item active">培训详情</li></ol></nav>
@@ -66,6 +53,8 @@
if (!TrainingSystem.initPage()) {} if (!TrainingSystem.initPage()) {}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('training');
TrainingSystem.initUserInfo();
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const planId = urlParams.get('id'); const planId = urlParams.get('id');
if (planId) { if (planId) {
@@ -86,8 +75,30 @@
function renderDetail(data) { function renderDetail(data) {
const plan = data; const plan = data;
const completionRate = plan.participantCount > 0 ? Math.round((plan.completedCount / plan.participantCount) * 100) : 0; // 合并知识列表和考试列表为统一的items
const items = [];
if (plan.knowledgeList && plan.knowledgeList.length > 0) {
plan.knowledgeList.forEach(k => {
items.push({
type: 'KNOWLEDGE',
title: k.knowledge ? k.knowledge.title : '',
required: k.required
});
});
}
if (plan.examList && plan.examList.length > 0) {
plan.examList.forEach(e => {
items.push({
type: 'EXAM',
title: e.examTitle || '',
required: e.required
});
});
}
const totalItems = (plan.knowledgeCount || 0) + (plan.examCount || 0);
const statusLabels = { const statusLabels = {
'NOT_STARTED': '<span class="badge bg-secondary">未开始</span>',
'DRAFT': '<span class="badge bg-secondary">草稿</span>', 'DRAFT': '<span class="badge bg-secondary">草稿</span>',
'IN_PROGRESS': '<span class="badge bg-success">进行中</span>', 'IN_PROGRESS': '<span class="badge bg-success">进行中</span>',
'ENDED': '<span class="badge bg-dark">已结束</span>' 'ENDED': '<span class="badge bg-dark">已结束</span>'
@@ -107,10 +118,10 @@
${statusLabels[plan.status] || ''} ${statusLabels[plan.status] || ''}
</div> </div>
<div class="detail-stats"> <div class="detail-stats">
<div class="detail-stat"><div class="value">${plan.participantCount || 0}</div><div class="label">参与人数</div></div> <div class="detail-stat"><div class="value">${plan.knowledgeCount || 0}</div><div class="label">知识学习</div></div>
<div class="detail-stat"><div class="value">${plan.completedCount || 0}</div><div class="label">已完成</div></div> <div class="detail-stat"><div class="value">${plan.examCount || 0}</div><div class="label">考试任务</div></div>
<div class="detail-stat"><div class="value">${completionRate}%</div><div class="label">完成率</div></div> <div class="detail-stat"><div class="value">${totalItems}</div><div class="label">培训项目</div></div>
<div class="detail-stat"><div class="value">${(plan.items || []).length}</div><div class="label">培训项目</div></div> <div class="detail-stat"><div class="value">${plan.participantCount || 0}</div><div class="label">培训对象</div></div>
</div> </div>
</div> </div>
@@ -119,8 +130,8 @@
<div class="content-card"> <div class="content-card">
<h5 class="mb-3"><i class="bi bi-list-check me-2"></i>培训内容</h5>`; <h5 class="mb-3"><i class="bi bi-list-check me-2"></i>培训内容</h5>`;
if (plan.items && plan.items.length > 0) { if (items.length > 0) {
plan.items.forEach((item, i) => { items.forEach((item, i) => {
html += `<div class="content-item"> html += `<div class="content-item">
<div class="item-num">${i + 1}</div> <div class="item-num">${i + 1}</div>
<div class="item-icon ${item.type === 'KNOWLEDGE' ? 'knowledge' : 'exam'}"> <div class="item-icon ${item.type === 'KNOWLEDGE' ? 'knowledge' : 'exam'}">
@@ -133,7 +144,6 @@
${item.required ? '<span class="badge bg-danger ms-1">必修</span>' : '<span class="badge bg-secondary ms-1">选修</span>'} ${item.required ? '<span class="badge bg-danger ms-1">必修</span>' : '<span class="badge bg-secondary ms-1">选修</span>'}
</div> </div>
</div> </div>
<div class="text-muted small">${item.completedCount || 0}/${plan.participantCount || 0}人完成</div>
</div>`; </div>`;
}); });
} else { } else {
@@ -148,30 +158,22 @@
</div> </div>
<div class="col-lg-7"> <div class="col-lg-7">
<div class="content-card"> <div class="content-card">
<h5 class="mb-3"><i class="bi bi-people me-2"></i>参与人员进度</h5> <h5 class="mb-3"><i class="bi bi-people me-2"></i>培训对象</h5>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-hover participant-table"> <table class="table table-hover participant-table">
<thead><tr><th>姓名</th><th>部门</th><th>进度</th><th>状态</th></tr></thead> <thead><tr><th>类型</th><th>名称</th></tr></thead>
<tbody>`; <tbody>`;
if (plan.participants && plan.participants.length > 0) { if (plan.targets && plan.targets.length > 0) {
plan.participants.forEach(p => { plan.targets.forEach(t => {
const progress = p.totalCount > 0 ? Math.round((p.completedCount / p.totalCount) * 100) : 0; const typeIcon = t.targetType === 'DEPARTMENT' ? 'bi-building' : (t.targetType === 'GROUP' ? 'bi-people' : 'bi-person');
const isCompleted = progress >= 100;
html += `<tr> html += `<tr>
<td><div class="d-flex align-items-center"><div class="avatar me-2" style="width:32px;height:32px;font-size:12px;">${(p.realName || '?').charAt(0)}</div>${p.realName || '-'}</div></td> <td><i class="bi ${typeIcon} me-2"></i>${t.targetTypeName || t.targetType}</td>
<td>${p.departmentName || '-'}</td> <td>${t.targetName || '-'}</td>
<td>
<div class="d-flex align-items-center gap-2">
<div class="progress"><div class="progress-bar ${isCompleted ? 'bg-success' : ''}" style="width:${progress}%"></div></div>
<span class="small">${progress}%</span>
</div>
</td>
<td>${isCompleted ? '<span class="badge bg-success">已完成</span>' : '<span class="badge bg-warning">进行中</span>'}</td>
</tr>`; </tr>`;
}); });
} else { } else {
html += '<tr><td colspan="4" class="text-center text-muted py-4">暂无参与人员</td></tr>'; html += '<tr><td colspan="2" class="text-center text-muted py-4">暂无培训对象</td></tr>';
} }
html += `</tbody></table></div></div></div></div>`; html += `</tbody></table></div></div></div></div>`;

View File

@@ -30,17 +30,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<a href="/exam/my-exams.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>我的考试</span></a>
<a href="/training/my-training.html" class="menu-item active"><i class="bi bi-calendar-check"></i><span>我的培训</span></a>
<a href="/knowledge/list.html" class="menu-item"><i class="bi bi-journal-richtext"></i><span>知识学习</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>个人设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">我的培训</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">我的培训</li></ol></nav>
@@ -79,6 +69,8 @@
let allTrainings = [], currentTab = 'ongoing'; let allTrainings = [], currentTab = 'ongoing';
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('my-training');
TrainingSystem.initUserInfo();
loadTrainings(); loadTrainings();
}); });

View File

@@ -28,20 +28,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item active"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/training/plan.html">培训计划</a></li><li class="breadcrumb-item active" id="pageTitle">创建计划</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item"><a href="/training/plan.html">培训计划</a></li><li class="breadcrumb-item active" id="pageTitle">创建计划</li></ol></nav>
@@ -198,6 +185,8 @@
let knowledgeModal, examModal; let knowledgeModal, examModal;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('training');
TrainingSystem.initUserInfo();
knowledgeModal = new bootstrap.Modal(document.getElementById('knowledgeModal')); knowledgeModal = new bootstrap.Modal(document.getElementById('knowledgeModal'));
examModal = new bootstrap.Modal(document.getElementById('examModal')); examModal = new bootstrap.Modal(document.getElementById('examModal'));
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);

View File

@@ -30,20 +30,7 @@
</head> </head>
<body> <body>
<div class="layout-wrapper"> <div class="layout-wrapper">
<aside class="sidebar"> <div id="sidebarContainer"></div>
<div class="sidebar-logo"><div class="sidebar-logo-icon"><i class="bi bi-truck text-white"></i></div><span class="sidebar-logo-text">道路救援培训系统</span></div>
<nav class="sidebar-menu">
<a href="/index.html" class="menu-item"><i class="bi bi-grid-1x2"></i><span>工作台</span></a>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-people me-2"></i>人员管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/system/org.html" class="menu-item">组织架构</a><a href="/system/user.html" class="menu-item">员工管理</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-journal-richtext me-2"></i>知识库</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/knowledge/category.html" class="menu-item">知识分类</a><a href="/knowledge/list.html" class="menu-item">知识列表</a></div></div>
<div class="menu-group"><div class="menu-group-title"><span><i class="bi bi-pencil-square me-2"></i>考题管理</span><i class="bi bi-chevron-down arrow"></i></div><div class="menu-submenu"><a href="/exam/question-category.html" class="menu-item">题库分类</a><a href="/exam/question.html" class="menu-item">题目列表</a></div></div>
<a href="/exam/paper.html" class="menu-item"><i class="bi bi-file-earmark-text"></i><span>试卷管理</span></a>
<a href="/exam/list.html" class="menu-item"><i class="bi bi-clipboard-check"></i><span>考试管理</span></a>
<a href="/training/plan.html" class="menu-item active"><i class="bi bi-calendar-check"></i><span>培训计划</span></a>
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin: 16px 0;"></div>
<a href="/system/setting.html" class="menu-item"><i class="bi bi-gear"></i><span>系统设置</span></a>
</nav>
</aside>
<div class="main-wrapper"> <div class="main-wrapper">
<header class="top-header"> <header class="top-header">
<nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">培训计划</li></ol></nav> <nav aria-label="breadcrumb"><ol class="breadcrumb mb-0"><li class="breadcrumb-item"><a href="/index.html">首页</a></li><li class="breadcrumb-item active">培训计划</li></ol></nav>
@@ -90,6 +77,8 @@
let currentPage = 1, pageSize = 10; let currentPage = 1, pageSize = 10;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
TrainingSystem.initSidebar('training');
TrainingSystem.initUserInfo();
loadList(); loadList();
}); });