# OKR 绩效考核系统 — 技术设计文档

## 文档信息

| 项目 | 内容 |
|------|------|
| 文档名称 | 医梦AI OKR 绩效考核系统技术设计 |
| 版本 | v1.0 |
| 日期 | 2026-04-15 |
| 作者 | 产品研发部 |
| 状态 | 已评审 |

---

## 1. 技术选型

| 层级 | 技术 | 版本 | 选型理由 |
|------|------|------|----------|
| 运行时 | JDK | 17 LTS | 企业级长期支持版本，生态成熟 |
| 后端框架 | Spring Boot | 3.2.x | 约定优于配置，内嵌 Tomcat，适合快速交付 |
| ORM | MyBatis-Plus | 3.5.x | 无 XML 配置、自动 CRUD、逻辑删除、分页插件，开发效率高 |
| 数据库 | SQLite (WAL) | 3.45 | 零安装、零配置、单文件存储，适合内部小规模部署 |
| 认证 | Spring Security + JWT | 6.x / jjwt 0.12 | 无状态认证，适合前后端分离架构 |
| 前端框架 | Vue 3 Composition API | 3.4+ | 响应式、组合式 API、TypeScript 友好 |
| UI 组件库 | Element Plus | 2.6+ | 企业级中后台组件丰富，中文生态好 |
| 状态管理 | Pinia | 2.x | Vue 3 官方推荐，类型推导好 |
| 前端构建 | Vite | 5.x | 冷启动快、HMR 极速 |
| 后端构建 | Maven | 3.9 | Spring Boot 标准构建工具 |

---

## 2. 部署架构

```
┌─────────────────────────────────────────┐
│              okr-performance.jar         │
│  ┌──────────────┐  ┌──────────────────┐ │
│  │  Spring Boot  │  │  static/         │ │
│  │  (port 18080) │  │  Vue build 产物   │ │
│  │  ┌──────────┐│  │  index.html      │ │
│  │  │ /api/*   ││  │  assets/*.js     │ │
│  │  │ REST API ││  │  assets/*.css    │ │
│  │  └──────────┘│  └──────────────────┘ │
│  │       │       │                       │
│  │       ▼       │                       │
│  │  ┌──────────┐│                       │
│  │  │ SQLite   ││                       │
│  │  │ (WAL)    ││                       │
│  │  └──────────┘│                       │
│  └──────────────┘                       │
└─────────────────────────────────────────┘
```

- 单 JAR 文件 + 1 个 `.db` 文件组成完整部署单元
- Spring Boot 同时提供 API 服务与静态资源服务
- 前端开发时 `:5173` 通过 Vite proxy 代理到后端 `:18080`
- SQLite WAL 模式支持读写并发

---

## 3. 后端分层架构

```
com.yimeng.okr
├── controller/     # REST 控制器，参数校验，调用 service
├── service/        # 业务逻辑，事务管理
├── mapper/         # MyBatis-Plus BaseMapper，无 XML
├── entity/         # 数据库实体，@TableName 映射
├── dto/            # 请求/响应对象，ApiResult<T> 统一包装
├── security/       # JwtTokenProvider, JwtAuthenticationFilter, SecurityUtils
├── config/         # SecurityConfig, DatabaseInitializer, DataInitializer, MybatisPlusConfig
├── exception/      # BusinessException + GlobalExceptionHandler
├── enums/          # 枚举：UserRole, PeriodStatus, KrStatus, Grade, ScoreType, ObjectiveType
├── schedule/       # PeriodScheduler（每日 2:00 自动推进周期状态）
└── annotation/     # @OperationLog 操作日志切面注解
```

### 3.1 API 设计规范

- Base path: `/api/*`
- 统一响应体：`ApiResult<T>` = `code`(200=成功) + `message` + `data`
- 认证方式：JWT Bearer Token，`/api/auth/**` 公开，其余需认证
- 当前用户获取：`SecurityUtils.getCurrentUserId()`

### 3.2 异常处理

- 业务异常统一抛出 `BusinessException(code, message)`
- `GlobalExceptionHandler(@RestControllerAdvice)` 全局捕获
- 集成 MyBatis-Plus 逻辑删除（`deleted=0` 有效，`deleted=1` 删除）

---

## 4. 数据库设计

### 4.1 ER 关系

```
sys_department ──┐
                 │ 1:N
                 ▼
sys_user ────────► okr_objective ──► kr_key_result ──► kr_progress_log
  │                     │                   │
  │ superior_id         │ period_id         │ assignedTo
  │ (自引用树)           ▼                   │ sourceKrId (自引用)
  │              assessment_period           ▼
  │                     │               kpi_config
  │                     ▼
  └──────────────► performance_score ──► audit_correction
                        │
                        ▼
                performance_feedback

kpi_template          assessment_dimension          operation_log
```

### 4.2 核心表结构

#### sys_user（用户）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增主键 |
| username | VARCHAR(64) UNIQUE | 登录名 |
| password_hash | VARCHAR(256) | BCrypt 加密 |
| real_name | VARCHAR(64) | 真实姓名 |
| position | VARCHAR(128) | 岗位名称 |
| department_id | INTEGER FK | 所属部门 |
| superior_id | INTEGER | 直属上级 ID（自引用，构建汇报树） |
| role | VARCHAR(20) | EMPLOYEE / SUPER_ADMIN |
| deleted | INTEGER | 0=有效, 1=删除 |

**关键设计**：`superior_id` 构建树形汇报关系，权限由此推导。`role=SUPER_ADMIN` 为超级管理员旁路标志。

#### assessment_period（考核周期）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增 |
| name | VARCHAR(128) | 周期名称 |
| period_type | VARCHAR(20) | MONTHLY / QUARTERLY / YEARLY |
| start_date | TEXT | 开始日期 |
| end_date | TEXT | 结束日期 |
| status | VARCHAR(20) | DRAFT→OKR_ALIGN→EXECUTING→ASSESSING→ARCHIVED |

#### okr_objective（目标 O）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增 |
| period_id | INTEGER FK | 所属周期 |
| user_id | INTEGER FK | 所属用户 |
| title | VARCHAR(256) | O 标题 |
| status | VARCHAR(20) | DRAFT / SUBMITTED / APPROVED / REJECTED |
| aligned_objective_ids | TEXT | 逗号分隔的对齐上级 O 的 ID 列表 |
| snapshot_json | TEXT | 归档快照 |
| reviewed_by | INTEGER | 审核人 |
| reviewed_at | TEXT | 审核时间 |

#### kr_key_result（关键结果 KR）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增 |
| objective_id | INTEGER FK | 所属 O |
| title | VARCHAR(256) | KR 标题 |
| target_value | REAL | 目标值 |
| current_value | REAL | 当前值 |
| status | VARCHAR(20) | NOT_STARTED / IN_PROGRESS / COMPLETED / BLOCKED |
| weight | INTEGER | 权重（和为 100） |
| assigned_to | INTEGER | @指派的下属用户 ID |
| source_kr_id | INTEGER | 承接的上级 KR ID（引用持久化） |

**关键设计**：`source_kr_id` 持久化上下级 KR 对齐关系。员工编辑自定义标题后，此引用不丢失，确保审批链可追溯。

#### performance_score（绩效评分）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增 |
| period_id | INTEGER FK | 所属周期 |
| user_id | INTEGER FK | 被评用户 |
| evaluator_id | INTEGER FK | 评估人 |
| okr_score | REAL | OKR 得分（0-60） |
| kpi_score | REAL | 工作成果得分（0-40） |
| bonus | REAL | 加分 |
| penalty | REAL | 扣分 |
| total | REAL | 总分 |
| grade | VARCHAR(2) | S/A/B/C |
| type | VARCHAR(20) | SELF / SUPERIOR / FINAL |
| comments_json | TEXT | 评分详情 JSON（维度分、KR 分、自述等） |
| confirmed_at | TEXT | 员工确认时间 |

**关键设计**：`type` 字段区分三阶段评分。`comments_json` 存储维度评分明细，支持结构化的自评内容展示。

#### assessment_dimension（考核维度）

| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER PK | 自增 |
| name | VARCHAR(64) | 维度名称 |
| max_score | INTEGER | 满分分值 |
| sort_order | INTEGER | 排序 |
| deleted | INTEGER | 0=有效, 1=删除 |

**约束**：所有未删除维度的 `max_score` 之和必须为 40，由后端 `DimensionService.validateTotal()` 强制校验。

#### 其他表

| 表名 | 用途 |
|------|------|
| kr_progress_log | KR 进度变更日志（旧值→新值，旧状态→新状态） |
| kpi_template | 岗位绩效模板（items_json 存储指标项列表） |
| kpi_config | 个人 KPI 配置（周期级） |
| performance_feedback | 面谈记录（亮点/改进/建议/纪要） |
| operation_log | 操作审计日志（操作人/动作/对象/数据快照） |
| audit_correction | 评分修正记录（修正前后数据 JSON） |

---

## 5. API 端点设计

### 5.1 Auth 模块 `/api/auth`

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /login | 登录，返回 JWT accessToken + refreshToken |
| POST | /register | 注册 |
| GET | /me | 获取当前用户信息 |
| PUT | /password | 修改密码 |

### 5.2 组织架构 `/api/org`

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /departments/tree | 部门树 |
| POST | /departments | 创建部门 |
| PUT | /departments/:id | 更新部门 |
| DELETE | /departments/:id | 删除部门 |
| GET | /users | 用户列表 |
| POST | /users | 创建用户 |
| PUT | /users/:id | 更新用户 |
| DELETE | /users/:id | 删除用户 |
| PUT | /users/:id/superior | 调整上级 |
| PUT | /users/:id/department | 调整部门 |

### 5.3 考核周期 `/api/periods`

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | / | 周期列表 |
| POST | / | 创建周期 |
| PUT | /:id | 更新周期 |
| DELETE | /:id | 删除周期 |
| PUT | /:id/status | 状态转换 |

### 5.4 OKR `/api/okr`

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /submit | 提交 OKR |
| PUT | /:id/update | 更新 OKR |
| PUT | /:id/review | 审核（通过/驳回） |
| PUT | /kr/:krId/progress | 更新 KR 进度 |
| GET | /kr/:krId/history | KR 进度历史 |
| GET | /period/:periodId/superior | 上级 OKR（用于对齐） |
| GET | /period/:periodId/my | 我的 OKR |
| GET | /period/:periodId/subordinates | 下属 OKR（团队视图） |
| GET | /period/:periodId/pending-reviews | 待审核列表 |
| GET | /period/:periodId/all | 周期全部 OKR |

### 5.5 绩效评分 `/api/scores`

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /self | 员工自评 |
| POST | /superior | 上级终审评分 |
| GET | /page | 评分详情页（含 OKR） |
| GET | /my | 我的绩效结果 |
| POST | /confirm | 确认终审结果 |
| GET | /subordinates | 下属评分列表 |

### 5.6 考核维度 `/api/dimensions`

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | / | 维度列表 |
| POST | / | 创建维度 |
| PUT | /:id | 更新维度 |
| DELETE | /:id | 删除维度 |

### 5.7 KPI 模板 `/api/kpi`

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /templates | 模板列表 |
| POST | /templates | 创建模板 |
| PUT | /templates/:id | 更新模板 |
| DELETE | /templates/:id | 删除模板 |
| GET | /templates/by-position | 按岗位匹配模板 |

### 5.8 反馈 `/api/feedback`

| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /interview | 保存面谈记录 |
| POST | /reply | 员工回复 |
| GET | /page | 查询反馈详情 |

---

## 6. 前端架构

### 6.1 路由设计

```
/login                    # 登录/注册
/                          # 主布局（侧边栏 + 顶栏 + 内容区）
├── /periods               # 考核周期管理
├── /okr/my                # 我的 OKR（制定/编辑/进度）
├── /okr/team              # 团队 OKR（下属全景）
├── /scores/my             # 我的绩效（自评 + 结果）
├── /scoring               # 绩效打分列表
├── /scoring/:userId       # 绩效考评详情（同屏）
├── /feedback              # 绩效沟通
├── /org                   # 组织架构（管理员）
├── /kpi/templates         # 绩效模板（管理员）
├── /system/dimensions     # 考核维度配置（管理员）
└── /system/logs           # 操作日志（管理员）
```

### 6.2 组件树

```
App.vue
├── LoginView.vue
└── MainLayout.vue (侧边栏 + 顶栏 + router-view)
    ├── PeriodListView.vue
    ├── MyOkrView.vue
    ├── TeamOkrView.vue
    ├── MyResultView.vue           # 自评表单 / 结果展示（条件渲染）
    ├── ScoringListView.vue
    ├── ScoringEditView.vue        # 同屏：左侧记录 + 右侧评分
    ├── FeedbackView.vue
    ├── OrgView.vue
    ├── KpiTemplateView.vue        # 含岗位分类筛选
    ├── DimensionConfigView.vue
    └── LogView.vue
```

### 6.3 状态管理（Pinia）

```javascript
auth store: {
  state:  { user, accessToken, refreshToken }
  getters: { isLoggedIn, isAdmin }
  actions: { login, register, fetchUser, logout }
}
```

### 6.4 API 层

- Axios 实例：baseURL `/api`，请求拦截注入 JWT，响应拦截统一处理 401
- 按模块导出 API 函数：`authApi`, `orgApi`, `periodApi`, `okrApi`, `scoreApi`, `kpiApi`, `feedbackApi`, `dimensionApi`, `systemApi`

---

## 7. UI/UX 设计规范

### 7.1 主题

| 属性 | 值 |
|------|-----|
| 主色 | `#2b1f99`（深靛蓝 — 侧边栏、强调元素） |
| 辅色 | `#3ad4d8`（青绿 — 高亮、CTA、进度条） |
| 侧边栏 | 220px 宽，深色渐变：`#1a1560 → #2b1f99 → #1e1780` |
| 内容区背景 | `#f5f7fa` |
| 顶栏高度 | 48px |

### 7.2 同屏布局（评分页）

```
┌──────────────────────────────────────────────────┐
│  左侧（弹性宽度）          │  右侧（480px 固定）    │
│  ┌────────────────────┐   │  ┌────────────────┐   │
│  │ 当期 OKR 完整记录    │   │  │ 考评打分        │   │
│  │ · O 标题 + 状态     │   │  │ · KR 逐条打分    │   │
│  │ · KR1 进度+日志     │   │  │ · 工作成果维度评分 │   │
│  │ · KR2 进度+日志     │   │  │ · 加减分          │   │
│  │ · KR3 进度+日志     │   │  │ · 总分/评级预览   │   │
│  ├────────────────────┤   │  │ · 提交按钮        │   │
│  │ 员工自评            │   │  └────────────────┘   │
│  │ · OKR 自评分        │   │                       │
│  │ · 维度自评+自述      │   │                       │
│  │ · 加减分            │   │                       │
│  │ · 自评总分          │   │                       │
│  └────────────────────┘   │                       │
└──────────────────────────────────────────────────┘
```

- 宽屏（≥1100px）：左右分栏
- 窄屏（<1100px）：上下分区，面板全宽

### 7.3 考核周期选择器

- 进行中的周期以彩色标签固定在顶部
- 未开始/已归档周期折叠收纳
- 周期左侧色条标识状态：绿色（执行中）、橙黄（对齐中）、红色（考评中）

---

## 8. 关键技术决策

| 决策 | 方案 | 理由 |
|------|------|------|
| 单 JAR 部署 | Vue build 输出拷贝到 `static/` 打包 | 部署物单一、运维简单 |
| 软删除 | MyBatis-Plus `@TableLogic` | 数据可恢复、满足审计要求 |
| 快照存档 | `snapshot_json` 字段 | 归档后历史数据不受后续编辑影响 |
| 修正留痕 | `audit_correction` 表 | "不可修改"语义通过审计日志实现 |
| 树形权限 | `superior_id` 自引用 | 权限随组织调整自动变化，无需单独配置 |
| KR 引用持久化 | `source_kr_id` 字段 | 编辑不丢失对齐关系，确保可追溯 |
| 维度可配置 | `assessment_dimension` 表 | 适配不同组织的考核侧重点 |
| 评分三阶段 | SELF → SUPERIOR → FINAL | 自评先行、上级终审，流程清晰 |

---

## 9. 安全设计

- 密码：BCrypt 加密存储
- 认证：JWT accessToken（24h）+ refreshToken（7d）
- 接口鉴权：Spring Security Filter Chain，`/api/auth/**` 放行，其余需认证
- 跨域：CORS 白名单，允许 `localhost` 来源
- 会话：无状态，不启用服务端 Session
- 审计：操作日志记录操作人、IP、变更前后数据
