# 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.emoon.okr ├── controller/ # REST 控制器,参数校验,调用 service ├── service/ # 业务逻辑,事务管理 ├── mapper/ # MyBatis-Plus BaseMapper,无 XML ├── entity/ # 数据库实体,@TableName 映射 ├── dto/ # 请求/响应对象,ApiResult 统一包装 ├── 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` = `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、变更前后数据