Initial commit: HR Performance System

- Database schema with 31 tables for 4-card system
- LLM API integration (Gemini, DeepSeek, OpenAI)
- Error handling system with modal component
- Connection test UI for LLM services
- Environment configuration files
- Complete database documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
donald
2025-12-03 23:34:13 +08:00
commit c24634f4b7
18 changed files with 8179 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
{
"permissions": {
"allow": [
"Bash(git init:*)",
"Bash(git remote add:*)",
"Bash(git config:*)",
"Bash(git add:*)"
],
"deny": [],
"ask": []
}
}

73
.gitignore vendored Normal file
View File

@@ -0,0 +1,73 @@
# Environment variables
.env
.env.local
.env.development
.env.production
.env.test
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
yarn.lock
pnpm-lock.yaml
# Build outputs
dist/
build/
out/
.next/
.nuxt/
.cache/
# IDE and Editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
*.sublime-project
*.sublime-workspace
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
pids
*.pid
*.seed
*.pid.lock
# Testing
coverage/
.nyc_output/
*.lcov
.jest/
# Uploads and temporary files
uploads/
temp/
tmp/
*.tmp
# Database
*.sqlite
*.sqlite3
*.db
# OS files
Thumbs.db
.DS_Store
desktop.ini
# Misc
.env.backup
*.bak
*.swp
.vscode-test/

View File

@@ -0,0 +1,692 @@
# HR 績效評核系統 - 功能規格書
**文件版本**v1.1 正式版
**建立日期**2024年12月
**文件狀態**:需求確認完成
---
## 一、系統概述
### 1.1 核心概念
本系統以「四卡循環」為核心架構,建立完整的績效管理生命週期:
```
┌─────────────────────────────────────────────────────────────────────┐
│ 績效管理四卡循環 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│
│ │ 角色卡 │ ───▶ │ 能力卡 │ ───▶ │ 績效卡 │ ───▶ │ 成長卡 ││
│ │ Role Card│ │Competency│ │Performance│ │Growth Card││
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘│
│ │ │ │
│ └─────────────── 回饋循環 ◀───────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 1.2 四卡定位與關聯
| 卡片 | 定位 | 回答的問題 | 主要產出 |
|------|------|------------|----------|
| **角色卡** | 崗位定義 | 我是誰?做什麼? | 職責、KRA/KPI |
| **能力卡** | 能力基準 | 需要什麼能力? | 技能清單、熟練度要求 |
| **績效卡** | 週期評核 | 做得如何? | 目標達成率、行為評分 |
| **成長卡** | 發展規劃 | 如何提升? | IDP計畫、追蹤紀錄 |
### 1.3 確認的系統配置
| 項目 | 確認選項 | 說明 |
|------|----------|------|
| 角色卡管理模式 | **B 職位+人員模式** | 角色卡可為空白職位,也可綁定特定人員 |
| 能力卡類型 | **D 職能字典** | 建立公司級職能字典,初期從通用軟性能力開始 |
| 評核週期 | **C 季度+年度** | 季度輕量評核,年度完整評核 |
| 評分機制 | **B 自評+主管評** | 員工先自評,主管後評,成熟後擴展 360 |
| 等級分佈 | **B 建議分佈** | 系統提示理想分佈比例,但不強制 |
| 培訓整合 | **A 獨立運作** | Phase 1 獨立Phase 2 擴展課程推薦 |
| 四卡連動 | **B 單向連動** | 角色→能力→績效→成長,資料自動帶入 |
| 審批流程 | **B 單層審批** | 直屬主管審批 |
| 版本管理 | **C 週期保留** | 每個評核週期保留一個快照 |
| 報表功能 | **A+B 基礎+儀表板** | 個人四卡檢視 + 績效分佈儀表板 |
| 多語系 | **B 繁中+英文** | 支援繁體中文與英文切換 |
| 行動支援 | **B 響應式網頁** | 自適應桌面與行動裝置 |
---
## 二、功能模組規格
### 2.1 角色卡模組 (Role Card)
#### 2.1.1 功能說明
- **職位+人員模式**:角色卡可為「職位範本」或「個人角色卡」
- 職位範本:定義標準職責,供新進人員認領
- 個人角色卡:綁定特定員工,可微調職責內容
#### 2.1.2 資料欄位
| 區塊 | 欄位 | 類型 | 必填 | 說明 |
|------|------|------|------|------|
| **基本資訊** | 角色卡類型 | 選單 | ✓ | 職位範本/個人角色卡 |
| | 部門名稱 | 選單 | ✓ | 連動組織架構 |
| | 角色名稱 | 文字 | ✓ | 職位/角色標準名稱 |
| | 職級 | 選單 | ✓ | 職等級別 |
| | 綁定人員 | 選單 | | 個人角色卡時必填 |
| **角色使命** | 使命描述 | 長文字 | ✓ | 一句話說明崗位核心價值 |
| **核心職責** | 職責清單 | 多筆文字 | ✓ | 4-8項動詞開頭 |
| **組織關聯** | 匯報對象 | 選單 | ✓ | 連動人員資料 |
| | 督導對象 | 多選 | | 直接管理的人員/角色 |
| | 內部協作夥伴 | 多選 | | 跨部門協作對象 |
| | 外部接口 | 文字 | | 對外聯繫窗口 |
| **KRA/KPI** | KRA | 文字 | ✓ | 關鍵成果領域3-6項 |
| | KPI 指標 | 文字 | ✓ | 關鍵績效指標名稱 |
| | 衡量方式 | 文字 | ✓ | 計算公式/判斷標準 |
| | 目標值 | 文字 | ✓ | 達標基準值 |
| | 權重 | 數字 | ✓ | 佔比 %,總和須為 100% |
#### 2.1.3 業務規則
1. 職位範本可被多人認領,系統自動建立個人角色卡副本
2. 個人角色卡修改不影響原職位範本
3. KRA 權重總和必須等於 100%
4. 角色卡變更需主管審批後生效
---
### 2.2 能力卡模組 (Competency Card)
#### 2.2.1 功能說明
- **職能字典架構**:建立公司級職能字典,各角色選用適用項目
- 初期先建立通用管理職能(軟性能力)
- 各部門可擴充專業技能(硬性能力)
#### 2.2.2 職能字典結構
```
職能字典
├── 通用職能 (Core Competencies)
│ ├── 溝通協調
│ ├── 團隊合作
│ ├── 問題解決
│ ├── 執行力
│ └── 學習成長
├── 管理職能 (Management Competencies)
│ ├── 策略思維
│ ├── 團隊領導
│ ├── 橫向整合力
│ ├── 決策判斷
│ └── 人才培育
└── 專業職能 (Professional Competencies)
├── [依部門/職類定義]
└── ...
```
#### 2.2.3 資料欄位
| 區塊 | 欄位 | 類型 | 必填 | 說明 |
|------|------|------|------|------|
| **基本資訊** | 連動角色卡 | 關聯 | ✓ | 自動帶入角色資訊 |
| **硬性能力** | 技能/證照名稱 | 文字 | ✓ | 專業技能或認證項目 |
| | 技能類別 | 選單 | ✓ | 專業知識/工具使用/證照資質 |
| | 是否必備 | 開關 | ✓ | 必須具備或加分項 |
| | 要求熟練度 | 選單 | ✓ | 1-5 級 |
| | 說明 | 文字 | | 具體應用情境 |
| **軟性能力** | 職能項目 | 選單 | ✓ | 從職能字典選取 |
| | 職能定義 | 文字 | 自動 | 系統帶入 |
| | 要求等級 | 選單 | ✓ | L1-L5 |
| | 行為指標 | 文字 | 自動 | 系統依等級帶入 |
#### 2.2.4 熟練度/等級定義
| 等級 | 硬性能力定義 | 軟性能力定義 |
|------|-------------|-------------|
| **L1** | 了解概念,需指導操作 | 初學新手:需指導才能展現 |
| **L2** | 基礎應用,可完成標準任務 | 基礎應用:在簡單情境中展現 |
| **L3** | 獨立操作,處理一般問題 | 獨立勝任:穩定展現於日常工作 |
| **L4** | 精通深化,可指導初學者 | 精通深化:在複雜情境中展現 |
| **L5** | 專家創新,可培訓/優化流程 | 專家引領:可指導他人並創新 |
---
### 2.3 績效卡模組 (Performance Card)
#### 2.3.1 功能說明
- **評核週期**:季度輕量評核 + 年度完整評核
- **評分機制**:員工自評 → 主管評核 → 績效面談
- **等級分佈**:系統顯示建議分佈比例,不強制執行
#### 2.3.2 評核週期設計
| 週期 | 類型 | 內容 | 時間點 |
|------|------|------|--------|
| Q1 | 季度輕量 | 目標追蹤、簡要回饋 | 4月 |
| Q2 | 季度輕量 | 目標追蹤、簡要回饋 | 7月 |
| Q3 | 季度輕量 | 目標追蹤、簡要回饋 | 10月 |
| Q4 | 年度完整 | 完整目標+行為評估 | 1月 |
#### 2.3.3 資料欄位
| 區塊 | 欄位 | 類型 | 說明 |
|------|------|------|------|
| **基本資訊** | 評核週期 | 選單 | 季度/年度 |
| | 考核年度 | 選單 | 連動年度設定 |
| | 考核期間 | 日期 | 起迄日期 |
| | 被評核人 | 關聯 | 連動角色卡 |
| | 填寫日期 | 日期 | 系統自動記錄 |
| **目標與成果** | KRA | 關聯 | 連動角色卡 KRA |
| | 權重 | 數字 | 連動角色卡權重 |
| | 具體產出 | 長文字 | 實際完成事項描述 |
| | 自評完成度 | 百分比 | 員工自評 |
| | 自評說明 | 文字 | 自評依據 |
| | 主管評完成度 | 百分比 | 主管確認 |
| | 主管評說明 | 文字 | 主管回饋 |
| | 共識完成度 | 百分比 | 面談後確認 |
| **行為能力評估** | 職能項目 | 關聯 | 連動能力卡 |
| | 職能定義 | 文字 | 系統帶入 |
| | 自評等級 | 選單 | L1-L5 |
| | 自評舉例 | 長文字 | SBI 格式 |
| | 主管評等級 | 選單 | L1-L5 |
| | 主管評舉例 | 長文字 | SBI 格式 |
| **績效自評** | 自述 | 長文字 | 員工整體自我評價 |
| **主管建議** | 回饋 | 長文字 | 給受評人建議 |
| **綜合評價** | 目標得分 | 計算 | 加權平均 |
| | 行為得分 | 計算 | 平均等級轉換 |
| | 目標佔比 | 設定 | 預設 70% |
| | 行為佔比 | 設定 | 預設 30% |
| | 總分 | 計算 | 加權總分 |
| | 考核等級 | 選單 | A+/A/B+/B/C |
#### 2.3.4 建議等級分佈
| 等級 | 定義 | 建議比例 |
|------|------|----------|
| **A+** | 卓越超群 | ≤ 10% |
| **A** | 優秀達標 | 20-25% |
| **B+** | 良好穩定 | 30-40% |
| **B** | 合格待進 | 20-25% |
| **C** | 需要改善 | ≤ 10% |
#### 2.3.5 評核原則(系統呈現)
1. **證據導向 (Evidence-Based)**:所有評核須有量化數據或行為事例佐證
2. **雙向對話 (Two-Way Dialogue)**:先員工自評 → 主管評核 → 績效面談共識
3. **發展導向 (Development Oriented)**:績效卡輸出是能力卡的輸入,非僅為評分
4. **持續記錄 (Continuous Process)**:全週期持續記錄,非期末才填寫
5. **SBI 格式**:情境(Situation)-行為(Behavior)-影響(Impact) 的具體描述
---
### 2.4 成長卡模組 (Growth Card)
#### 2.4.1 功能說明
- 承接績效卡輸出,自動帶入優勢項與待發展領域
- 制定個人發展計畫 (IDP),採 SMART 原則
- Phase 1 獨立運作Phase 2 連結培訓系統
#### 2.4.2 資料欄位
| 區塊 | 欄位 | 類型 | 說明 |
|------|------|------|------|
| **基本資訊** | 連動績效卡 | 關聯 | 自動帶入 |
| | 成長週期 | 日期 | IDP 適用期間 |
| | 主管 | 關聯 | 輔導主管 |
| **發展焦點** | 優勢項 | 多選 | 連動績效卡高分項 |
| | 待發展領域 | 多選 | 連動績效卡待改善項 |
| | 職業志向 | 文字 | 員工職涯期望 |
| **IDP 計畫** | 發展目標 | 文字 | SMART 原則 |
| | 對應能力 | 選單 | 連動能力卡項目 |
| | 具體行動 | 多筆文字 | 做什麼 |
| | 資源與支持 | 文字 | 需要什麼協助 |
| | 時間線 | 日期 | 預計完成時間 |
| | 成果證據 | 文字 | 如何證明達成 |
| **支持與承諾** | 員工承諾 | 簽核 | 員工簽署+日期 |
| | 主管承諾 | 簽核 | 主管簽署+日期 |
| | 檢視節奏 | 選單 | 月檢視/季回顧 |
| **追蹤紀錄** | 日期 | 日期 | 檢視日期 |
| | 進度更新 | 長文字 | 實際進展描述 |
| | 調整事項 | 文字 | 計畫調整內容 |
| | 簽名確認 | 簽核 | 雙方確認 |
| **其他建議** | 建議內容 | 長文字 | 對部門/公司建議 |
#### 2.4.3 IDP 目標建議數量
- 每位員工建議聚焦 **3-4 個**發展目標
- 避免資源分散,確保專注與落地
---
## 三、流程設計
### 3.1 年度主流程
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 年度績效管理流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 12月-1月 Q1-Q3 Q4 年末 次年 1月 │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │角色卡│──確認──▶│績效卡│──季度──▶│績效卡│──產出──▶│成長卡│ │
│ │能力卡│ 年度目標 │季度版│ 輕量追蹤 │年度版│ 完整評核 │ IDP │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 3.2 單向連動資料流
```
角色卡 能力卡 績效卡 成長卡
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ • 部門/職級 │ │ • 基本資訊 │ │ • 基本資訊 │ │ • 基本資訊 │
│ • 角色/人員 │──────▶│ • 硬性能力 │──────▶│ • KRA 清單 │──────▶│ • 優勢項 │
│ • KRA/KPI │ │ • 軟性能力 │ │ • 職能項目 │ │ • 待發展 │
│ • 權重 │ │ • 要求等級 │ │ • 評核結果 │ │ • IDP 計畫 │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
│ │ │ │
│ │ │ │
└────────────────────┴────────────────────┴────────────────────┘
基本資訊自動帶入連動
```
### 3.3 審批流程
採用**單層審批**,直屬主管審批即可:
```
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 員工 │─────▶│ 直屬主管 │─────▶│ 生效 │
│ 填寫 │ 送審 │ 審批 │ 核准 │ 歸檔 │
└─────────┘ └─────────┘ └─────────┘
│ 退回
┌─────────┐
│ 員工 │
│ 修改 │
└─────────┘
```
### 3.4 版本管理
採用**週期保留快照**策略:
| 事件 | 動作 | 保留內容 |
|------|------|----------|
| 季度評核完成 | 建立快照 | 該季績效卡完整內容 |
| 年度評核完成 | 建立快照 | 年度績效卡 + 成長卡 |
| 角色卡變更 | 建立快照 | 變更前後版本比對 |
---
## 四、報表功能規格
### 4.1 基礎報表
| 報表名稱 | 說明 | 使用者 |
|----------|------|--------|
| 個人四卡總覽 | 員工檢視自己的四卡完整資訊 | 全員 |
| 部門人員清單 | 部門內所有人員四卡狀態 | 主管 |
| 待審批清單 | 等待審批的卡片列表 | 主管 |
| 評核進度追蹤 | 各週期評核完成率 | HR/主管 |
### 4.2 儀表板
| 儀表板名稱 | 圖表類型 | 說明 |
|------------|----------|------|
| 績效等級分佈 | 圓餅圖/長條圖 | 顯示 A+/A/B+/B/C 分佈 |
| 部門績效比較 | 長條圖 | 跨部門績效平均比較 |
| 能力缺口分析 | 雷達圖 | 能力要求 vs 實際評估差距 |
| 目標達成率 | 儀表板 | KRA 整體達成百分比 |
| 評核完成進度 | 進度條 | 各階段完成率 |
---
## 五、系統設定
### 5.1 基礎設定
| 設定項目 | 說明 | 預設值 |
|----------|------|--------|
| 目標佔比 | 目標成果在總分的權重 | 70% |
| 行為佔比 | 行為能力在總分的權重 | 30% |
| 等級分界 | A+/A/B+/B/C 的分數區間 | 可調整 |
| 評核週期 | 季度/年度時間設定 | 依公司日曆 |
| 語系設定 | 預設語言 | 繁體中文 |
### 5.2 權限設定
| 角色 | 角色卡 | 能力卡 | 績效卡 | 成長卡 | 報表 |
|------|--------|--------|--------|--------|------|
| 員工 | 檢視(自己) | 檢視(自己) | 自評+檢視 | 填寫+檢視 | 個人 |
| 主管 | 檢視(部屬) | 檢視(部屬) | 評核+審批 | 審批+追蹤 | 部門 |
| HR | 全部 | 全部 | 全部 | 全部 | 全部 |
| 管理員 | 全部+設定 | 全部+字典 | 全部+設定 | 全部 | 全部 |
---
## 六、多語系支援
### 6.1 支援語言
- **繁體中文** (zh-TW) - 預設
- **英文** (en-US)
### 6.2 翻譯範圍
| 項目 | 說明 |
|------|------|
| 系統介面 | 選單、按鈕、標籤、提示訊息 |
| 固定欄位 | 欄位名稱、選項值 |
| 職能字典 | 職能名稱、定義、行為指標 |
| 報表標題 | 報表名稱、圖表標籤 |
### 6.3 使用者資料
使用者填寫的內容(如:具體產出、自評說明)不做自動翻譯,保持原始語言。
---
## 七、響應式設計規格
### 7.1 斷點設計
| 裝置類型 | 寬度範圍 | 佈局調整 |
|----------|----------|----------|
| Desktop | ≥ 1280px | 三欄:側邊欄 + 主內容 + 輔助面板 |
| Tablet | 768-1279px | 雙欄:可收合側邊欄 + 主內容 |
| Mobile | < 768px | 單欄底部導航 + 主內容 |
### 7.2 行動版優化
| 元件 | 桌面版 | 行動版 |
|------|--------|--------|
| 四卡進度條 | 水平展開 | 可橫向捲動 |
| Tab 切換 | 水平標籤 | 下拉選單 |
| 表格 | 完整顯示 | 卡片式呈現 |
| 按鈕組 | 水平排列 | 垂直堆疊 |
---
## 八、開發階段規劃
### Phase 1 - MVP (8-10 週)
| 週次 | 交付項目 |
|------|----------|
| W1-2 | 資料庫設計API 架構基礎 UI 框架 |
| W3-4 | 角色卡模組完整功能 |
| W5-6 | 能力卡模組 + 職能字典基礎版 |
| W7-8 | 績效卡模組年度版 |
| W9-10 | 成長卡模組 + 審批流程 + 基礎報表 |
### Phase 2 - 擴展 (4-6 週)
| 週次 | 交付項目 |
|------|----------|
| W11-12 | 季度評核流程 + 儀表板報表 |
| W13-14 | 多語系支援 + 響應式優化 |
| W15-16 | 培訓系統整合課程推薦 |
### Phase 3 - 進階 (規劃中)
- 360 度評估擴展
- AI 分析與建議
- HR 系統整合
---
## 十、Help Me AI 智能填寫功能
### 10.1 功能概述
| 項目 | 說明 |
|------|------|
| 功能名稱 | Help Me - AI 智能填寫 |
| 功能定位 | 輔助使用者快速完成表單填寫 |
| 觸發方式 | 點擊頁面右上角「✨ Help Me按鈕 |
| 適用範圍 | 所有可填寫欄位的卡片頁面 |
### 10.2 運作邏輯
```
┌─────────────────────────────────────────────────────────────────────┐
│ Help Me AI 運作流程 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 使用者點擊 Help Me │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 1: 掃描頁面所有可填寫欄位 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 2: 判斷欄位狀態 │ │
│ │ ├── 已有內容 → 跳過(不修改) │ │
│ │ └── 空白欄位 → 標記為待填寫 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 3: 收集上下文資訊 │ │
│ │ ├── 已填寫欄位內容 │ │
│ │ ├── 卡片類型與結構 │ │
│ │ ├── 連動資料(角色卡→能力卡→績效卡) │ │
│ │ └── 職能字典定義 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 4: AI 生成建議內容 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 5: 填入空白欄位並標示 AI 填寫 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Step 6: 顯示完成通知(已填寫 X 個欄位) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 10.3 支援的欄位類型
| 欄位類型 | 支援 | AI 生成方式 |
|----------|------|-------------|
| 文字輸入 (input) | | 依據上下文生成文字 |
| 多行文字 (textarea) | | 依據上下文生成段落 |
| 滑桿/百分比 (slider) | | 依據相關描述推測數值 |
| 等級選擇 (level) | | 依據 SBI 描述推測等級 |
| 下拉選單 (select) | | 依據上下文選擇選項 |
| 日期選擇 | | 不自動填寫 |
| 簽核欄位 | | 不自動填寫 |
### 10.4 各卡片 AI 填寫邏輯
#### 角色卡
| 欄位 | AI 參考來源 | 生成邏輯 |
|------|-------------|----------|
| 角色使命 | 角色名稱部門 | 生成標準使命描述 |
| 核心職責 | 角色名稱職級 | 依職位特性生成職責清單 |
| KRA 描述 | 職責清單 | 依職責推導關鍵成果 |
| KPI 指標 | KRA 描述 | KRA 生成可衡量指標 |
#### 能力卡
| 欄位 | AI 參考來源 | 生成邏輯 |
|------|-------------|----------|
| 技能說明 | 技能名稱 | 生成應用情境描述 |
| 熟練度建議 | 職級角色 | 依職級建議適當熟練度 |
#### 績效卡
| 欄位 | AI 參考來源 | 生成邏輯 |
|------|-------------|----------|
| 具體產出 | KRA 名稱目標值 | 生成成果描述範例 |
| 自評說明 | 具體產出完成度 | 生成自評依據說明 |
| SBI 情境 | 職能名稱工作內容 | 生成情境描述 |
| SBI 行為 | 職能定義 | 生成行為描述 |
| SBI 影響 | 行為描述 | 生成影響結果 |
| 自評等級 | SBI 完整度 | SBI 內容推測等級 |
| 績效自評 | 所有 KRA 成果 | 整合生成自我評價 |
#### 成長卡
| 欄位 | AI 參考來源 | 生成邏輯 |
|------|-------------|----------|
| 發展目標 | 待發展領域 | 生成 SMART 目標 |
| 具體行動 | 發展目標 | 生成行動步驟清單 |
| 資源與支持 | 行動內容 | 建議所需資源 |
| 成果證據 | 發展目標 | 建議驗收標準 |
### 10.5 UI 元件規格
#### Help Me 按鈕
```css
/* 按鈕樣式 */
.help-me-btn {
background: linear-gradient(135deg, #8b5cf6, #ec4899);
color: white;
padding: 12px 24px;
border-radius: 12px;
font-weight: 600;
box-shadow: 0 4px 15px rgba(139, 92, 246, 0.4);
}
/* 懸停效果 */
.help-me-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(139, 92, 246, 0.5);
}
/* 載入中狀態 */
.help-me-btn.loading {
opacity: 0.8;
pointer-events: none;
}
```
#### AI 填寫標示
```css
/* AI 填寫的欄位樣式 */
.form-input.ai-filled,
.form-textarea.ai-filled {
border-color: #8b5cf6;
background: linear-gradient(135deg,
rgba(139, 92, 246, 0.05),
rgba(236, 72, 153, 0.05));
animation: ai-glow 2s ease-out;
}
/* 發光動畫 */
@keyframes ai-glow {
0% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(139, 92, 246, 0); }
100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0); }
}
```
#### 完成通知 Toast
```css
/* Toast 通知樣式 */
.ai-toast {
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
background: #0f172a;
color: white;
padding: 1rem 1.5rem;
border-radius: 12px;
display: flex;
align-items: center;
gap: 0.75rem;
}
```
### 10.6 API 規格(後端整合)
#### 請求
```json
POST /api/ai/help-me-fill
{
"cardType": "performance",
"cardId": "PF-2024-001",
"filledFields": {
"kra1_title": "產品上市時程",
"kra1_weight": 40,
"kra1_output": "Q1 完成 MVP..."
},
"emptyFields": [
"kra2_output",
"kra2_self_note",
"comp1_sbi_s",
"comp1_sbi_b",
"comp1_sbi_i"
],
"context": {
"roleCard": { ... },
"competencyCard": { ... }
}
}
```
#### 回應
```json
{
"success": true,
"filledCount": 5,
"suggestions": {
"kra2_output": "NPS 從 32 分提升至 48 分...",
"kra2_self_note": "超額達成目標...",
"comp1_sbi_s": "Q2 產品發布專案中...",
"comp1_sbi_b": "主動建立每週同步會議...",
"comp1_sbi_i": "專案準時上線..."
}
}
```
---
## 十一、附錄
### A. 名詞定義
| 名詞 | 英文 | 定義 |
|------|------|------|
| KRA | Key Result Area | 關鍵成果領域角色需達成的核心成果面向 |
| KPI | Key Performance Indicator | 關鍵績效指標衡量 KRA 達成程度的量化指標 |
| IDP | Individual Development Plan | 個人發展計畫 |
| SBI | Situation-Behavior-Impact | 情境-行為-影響行為描述格式 |
| SMART | Specific-Measurable-Achievable-Relevant-Time-bound | 目標設定原則 |
### B. 文件版本歷史
| 版本 | 日期 | 說明 |
|------|------|------|
| v1.0 | 2024/12 | 初版草稿提出 12 道選擇題 |
| v1.1 | 2024/12 | 確認選項正式功能規格 |
---
**文件結束**

257
components/ErrorModal.css Normal file
View File

@@ -0,0 +1,257 @@
/* 錯誤彈窗樣式 */
.error-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.error-modal-overlay.visible {
opacity: 1;
pointer-events: all;
}
.error-modal {
background: white;
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
width: 90%;
max-width: 500px;
max-height: 80vh;
overflow: hidden;
display: flex;
flex-direction: column;
transform: scale(0.9);
opacity: 0;
transition: all 0.3s ease;
}
.error-modal.visible {
transform: scale(1);
opacity: 1;
}
/* Header */
.error-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 1px solid #e5e7eb;
}
.error-modal-title {
display: flex;
align-items: center;
gap: 12px;
}
.error-icon {
font-size: 24px;
}
.error-modal-title h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #1f2937;
}
.error-modal-close {
background: none;
border: none;
font-size: 24px;
color: #6b7280;
cursor: pointer;
padding: 4px 8px;
line-height: 1;
border-radius: 4px;
transition: all 0.2s;
}
.error-modal-close:hover {
background-color: #f3f4f6;
color: #1f2937;
}
/* Body */
.error-modal-body {
padding: 20px;
overflow-y: auto;
flex: 1;
}
.error-message {
margin: 0 0 16px 0;
font-size: 15px;
color: #374151;
line-height: 1.6;
}
.error-metadata {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
font-size: 13px;
color: #6b7280;
}
.error-code {
padding: 4px 8px;
background-color: #fee2e2;
color: #991b1b;
border-radius: 4px;
font-weight: 500;
}
.error-time {
padding: 4px 8px;
background-color: #f3f4f6;
color: #4b5563;
border-radius: 4px;
}
.error-details {
margin-top: 16px;
padding: 12px;
background-color: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 6px;
}
.error-details summary {
cursor: pointer;
font-weight: 500;
color: #4b5563;
user-select: none;
}
.error-details summary:hover {
color: #1f2937;
}
.error-details pre {
margin-top: 12px;
padding: 12px;
background-color: #1f2937;
color: #f9fafb;
border-radius: 4px;
font-size: 12px;
overflow-x: auto;
}
.error-path {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e5e7eb;
}
.error-path small {
color: #6b7280;
font-size: 12px;
}
/* Footer */
.error-modal-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
border-top: 1px solid #e5e7eb;
background-color: #f9fafb;
}
.error-countdown {
font-size: 13px;
color: #6b7280;
}
.error-modal-button {
padding: 8px 20px;
background-color: #3b82f6;
color: white;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;
}
.error-modal-button:hover {
background-color: #2563eb;
}
.error-modal-button:active {
transform: scale(0.98);
}
/* Severity Colors */
.error-modal.error .error-modal-title h3 {
color: #dc2626;
}
.error-modal.warning .error-modal-title h3 {
color: #ea580c;
}
.error-modal.warning .error-modal-button {
background-color: #ea580c;
}
.error-modal.warning .error-modal-button:hover {
background-color: #c2410c;
}
.error-modal.info .error-modal-title h3 {
color: #0284c7;
}
.error-modal.info .error-modal-button {
background-color: #0284c7;
}
.error-modal.info .error-modal-button:hover {
background-color: #0369a1;
}
/* 響應式設計 */
@media (max-width: 768px) {
.error-modal {
width: 95%;
max-height: 90vh;
}
.error-modal-header {
padding: 16px;
}
.error-modal-body {
padding: 16px;
}
.error-modal-footer {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.error-countdown {
text-align: center;
}
.error-modal-button {
width: 100%;
}
}

127
components/ErrorModal.jsx Normal file
View File

@@ -0,0 +1,127 @@
/**
* 錯誤彈窗元件
* 統一顯示應用程式中的錯誤訊息
*/
import React, { useEffect, useState } from 'react';
import './ErrorModal.css';
const ErrorModal = ({ error, onClose, autoClose = true, duration = 5000 }) => {
const [isVisible, setIsVisible] = useState(false);
const [countdown, setCountdown] = useState(duration / 1000);
useEffect(() => {
if (error) {
setIsVisible(true);
setCountdown(duration / 1000);
if (autoClose) {
const timer = setTimeout(() => {
handleClose();
}, duration);
const countdownInterval = setInterval(() => {
setCountdown((prev) => Math.max(0, prev - 1));
}, 1000);
return () => {
clearTimeout(timer);
clearInterval(countdownInterval);
};
}
}
}, [error, autoClose, duration]);
const handleClose = () => {
setIsVisible(false);
setTimeout(() => {
if (onClose) onClose();
}, 300);
};
if (!error) return null;
const getSeverityClass = () => {
if (!error.statusCode) return 'error';
if (error.statusCode >= 500) return 'error';
if (error.statusCode >= 400) return 'warning';
return 'info';
};
const getSeverityIcon = () => {
const severity = getSeverityClass();
switch (severity) {
case 'error':
return '❌';
case 'warning':
return '⚠️';
case 'info':
return '';
default:
return '❌';
}
};
return (
<div className={`error-modal-overlay ${isVisible ? 'visible' : ''}`} onClick={handleClose}>
<div
className={`error-modal ${getSeverityClass()} ${isVisible ? 'visible' : ''}`}
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="error-modal-header">
<div className="error-modal-title">
<span className="error-icon">{getSeverityIcon()}</span>
<h3>{error.title || '錯誤'}</h3>
</div>
<button className="error-modal-close" onClick={handleClose} aria-label="關閉">
</button>
</div>
{/* Body */}
<div className="error-modal-body">
<p className="error-message">{error.message}</p>
{error.statusCode && (
<div className="error-metadata">
<span className="error-code">錯誤代碼: {error.statusCode}</span>
{error.timestamp && (
<span className="error-time">
時間: {new Date(error.timestamp).toLocaleString('zh-TW')}
</span>
)}
</div>
)}
{error.details && (
<details className="error-details">
<summary>詳細資訊</summary>
<pre>{JSON.stringify(error.details, null, 2)}</pre>
</details>
)}
{error.path && (
<div className="error-path">
<small>路徑: {error.path}</small>
</div>
)}
</div>
{/* Footer */}
<div className="error-modal-footer">
{autoClose && (
<span className="error-countdown">
{countdown > 0 ? `${countdown} 秒後自動關閉` : '關閉中...'}
</span>
)}
<button className="error-modal-button" onClick={handleClose}>
確定
</button>
</div>
</div>
</div>
);
};
export default ErrorModal;

View File

@@ -0,0 +1,404 @@
/* LLM 連線測試樣式 */
.llm-connection-test {
max-width: 1200px;
margin: 0 auto;
padding: 24px;
}
/* Header */
.test-header {
margin-bottom: 32px;
text-align: center;
}
.test-header h2 {
font-size: 28px;
font-weight: 700;
color: #1f2937;
margin: 0 0 12px 0;
}
.test-description {
font-size: 15px;
color: #6b7280;
margin: 0;
}
/* Actions */
.test-actions {
display: flex;
justify-content: center;
margin-bottom: 32px;
}
.test-all-button {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
}
.test-all-button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
}
.test-all-button:active:not(:disabled) {
transform: translateY(0);
}
.test-all-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Providers Grid */
.providers-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 24px;
margin-bottom: 32px;
}
.provider-card {
background: white;
border: 2px solid #e5e7eb;
border-radius: 12px;
padding: 24px;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.provider-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.provider-card.success {
border-color: #10b981;
background: linear-gradient(135deg, #ffffff 0%, #f0fdf4 100%);
}
.provider-card.failure {
border-color: #ef4444;
background: linear-gradient(135deg, #ffffff 0%, #fef2f2 100%);
}
/* Provider Header */
.provider-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.provider-info {
display: flex;
align-items: center;
gap: 12px;
}
.provider-icon {
font-size: 32px;
}
.provider-info h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #1f2937;
}
.result-icon {
font-size: 24px;
}
/* Provider Body */
.provider-body {
min-height: 120px;
margin-bottom: 16px;
}
.result-details {
display: flex;
flex-direction: column;
gap: 12px;
}
.status-badge {
display: inline-block;
padding: 6px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 600;
width: fit-content;
}
.status-badge.success {
background-color: #d1fae5;
color: #065f46;
}
.status-badge.failure {
background-color: #fee2e2;
color: #991b1b;
}
.result-message {
margin: 0;
font-size: 14px;
color: #4b5563;
line-height: 1.6;
}
.result-meta {
display: flex;
gap: 8px;
font-size: 13px;
padding: 8px 12px;
background-color: #f9fafb;
border-radius: 6px;
}
.meta-label {
font-weight: 600;
color: #6b7280;
}
.meta-value {
color: #1f2937;
}
.error-details {
margin-top: 8px;
}
.error-details summary {
cursor: pointer;
font-size: 13px;
font-weight: 500;
color: #ef4444;
user-select: none;
}
.error-details summary:hover {
color: #dc2626;
}
.error-details pre {
margin-top: 8px;
padding: 12px;
background-color: #1f2937;
color: #f9fafb;
border-radius: 6px;
font-size: 12px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.no-result {
margin: 0;
padding: 24px;
text-align: center;
color: #9ca3af;
font-size: 14px;
}
/* Provider Footer */
.provider-footer {
border-top: 1px solid #e5e7eb;
padding-top: 16px;
}
.test-button {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
width: 100%;
padding: 10px 16px;
background: white;
border: 2px solid;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.test-button:hover:not(:disabled) {
background-color: rgba(0, 0, 0, 0.02);
transform: translateY(-1px);
}
.test-button:active:not(:disabled) {
transform: translateY(0);
}
.test-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* Spinner */
.spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
.spinner.small {
width: 12px;
height: 12px;
border-width: 2px;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Footer */
.test-footer {
margin-top: 32px;
}
.info-box {
display: flex;
gap: 16px;
padding: 20px;
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
border: 1px solid #bfdbfe;
border-radius: 12px;
}
.info-icon {
font-size: 24px;
flex-shrink: 0;
}
.info-content {
flex: 1;
}
.info-content strong {
display: block;
margin-bottom: 8px;
color: #1e40af;
font-size: 15px;
}
.info-content p {
margin: 0 0 12px 0;
color: #1e3a8a;
font-size: 14px;
line-height: 1.6;
}
.info-content ul {
margin: 0;
padding-left: 20px;
color: #1e3a8a;
}
.info-content li {
margin-bottom: 6px;
font-size: 13px;
font-family: 'Courier New', monospace;
}
/* 響應式設計 */
@media (max-width: 768px) {
.llm-connection-test {
padding: 16px;
}
.test-header h2 {
font-size: 24px;
}
.providers-grid {
grid-template-columns: 1fr;
gap: 16px;
}
.provider-card {
padding: 20px;
}
.info-box {
flex-direction: column;
gap: 12px;
}
.info-icon {
font-size: 20px;
}
}
/* 深色模式支援 (可選) */
@media (prefers-color-scheme: dark) {
.llm-connection-test {
background-color: #111827;
}
.test-header h2 {
color: #f9fafb;
}
.test-description {
color: #9ca3af;
}
.provider-card {
background: #1f2937;
border-color: #374151;
}
.provider-info h3 {
color: #f9fafb;
}
.result-message {
color: #d1d5db;
}
.result-meta {
background-color: #111827;
}
.test-button {
background: #1f2937;
}
.test-button:hover:not(:disabled) {
background-color: #374151;
}
.info-box {
background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%);
border-color: #2563eb;
}
.info-content strong,
.info-content p,
.info-content li {
color: #dbeafe;
}
}

View File

@@ -0,0 +1,228 @@
/**
* LLM 連線測試元件
* 測試 Gemini, DeepSeek, OpenAI 三種 LLM API 的連線狀態
*/
import React, { useState } from 'react';
import axios from 'axios';
import './LLMConnectionTest.css';
const LLMConnectionTest = () => {
const [testResults, setTestResults] = useState({
gemini: null,
deepseek: null,
openai: null,
});
const [testing, setTesting] = useState({
gemini: false,
deepseek: false,
openai: false,
});
const [testingAll, setTestingAll] = useState(false);
const providers = [
{
id: 'gemini',
name: 'Google Gemini',
icon: '🤖',
color: '#4285f4',
},
{
id: 'deepseek',
name: 'DeepSeek',
icon: '🧠',
color: '#7c3aed',
},
{
id: 'openai',
name: 'OpenAI',
icon: '✨',
color: '#10a37f',
},
];
/**
* 測試單一 LLM 連線
*/
const testConnection = async (provider) => {
setTesting((prev) => ({ ...prev, [provider]: true }));
setTestResults((prev) => ({ ...prev, [provider]: null }));
try {
const response = await axios.post(`/api/llm/test/${provider}`);
setTestResults((prev) => ({ ...prev, [provider]: response.data }));
} catch (error) {
const errorData = error.response?.data || {
success: false,
message: error.message || '連線測試失敗',
provider,
};
setTestResults((prev) => ({ ...prev, [provider]: errorData }));
} finally {
setTesting((prev) => ({ ...prev, [provider]: false }));
}
};
/**
* 測試所有 LLM 連線
*/
const testAllConnections = async () => {
setTestingAll(true);
setTestResults({
gemini: null,
deepseek: null,
openai: null,
});
try {
const response = await axios.post('/api/llm/test/all');
setTestResults(response.data);
} catch (error) {
console.error('測試所有連線失敗:', error);
} finally {
setTestingAll(false);
}
};
/**
* 取得測試結果樣式
*/
const getResultClass = (result) => {
if (!result) return '';
return result.success ? 'success' : 'failure';
};
/**
* 取得測試結果圖示
*/
const getResultIcon = (result) => {
if (!result) return '⏳';
return result.success ? '✅' : '❌';
};
return (
<div className="llm-connection-test">
<div className="test-header">
<h2>LLM API 連線測試</h2>
<p className="test-description">
測試與外部 LLM 服務的連線狀態確保 API 金鑰配置正確
</p>
</div>
<div className="test-actions">
<button
className="test-all-button"
onClick={testAllConnections}
disabled={testingAll || Object.values(testing).some(Boolean)}
>
{testingAll ? (
<>
<span className="spinner"></span>
測試中...
</>
) : (
<>
<span>🔄</span>
測試所有連線
</>
)}
</button>
</div>
<div className="providers-grid">
{providers.map((provider) => {
const result = testResults[provider.id];
const isTesting = testing[provider.id];
return (
<div
key={provider.id}
className={`provider-card ${getResultClass(result)}`}
style={{ borderColor: provider.color }}
>
<div className="provider-header">
<div className="provider-info">
<span className="provider-icon" style={{ color: provider.color }}>
{provider.icon}
</span>
<h3>{provider.name}</h3>
</div>
<span className="result-icon">{getResultIcon(result)}</span>
</div>
<div className="provider-body">
{result && (
<div className="result-details">
<div className={`status-badge ${result.success ? 'success' : 'failure'}`}>
{result.success ? '連線成功' : '連線失敗'}
</div>
<p className="result-message">{result.message}</p>
{result.model && (
<div className="result-meta">
<span className="meta-label">模型:</span>
<span className="meta-value">{result.model}</span>
</div>
)}
{result.error && (
<details className="error-details">
<summary>錯誤詳情</summary>
<pre>{result.error}</pre>
</details>
)}
</div>
)}
{!result && !isTesting && (
<p className="no-result">尚未測試</p>
)}
</div>
<div className="provider-footer">
<button
className="test-button"
onClick={() => testConnection(provider.id)}
disabled={isTesting || testingAll}
style={{ borderColor: provider.color, color: provider.color }}
>
{isTesting ? (
<>
<span className="spinner small"></span>
測試中...
</>
) : (
<>
<span>🔌</span>
測試連線
</>
)}
</button>
</div>
</div>
);
})}
</div>
<div className="test-footer">
<div className="info-box">
<span className="info-icon"></span>
<div className="info-content">
<strong>提示:</strong>
<p>請確保在 .env 文件中正確配置了對應的 API 金鑰</p>
<ul>
<li>GEMINI_API_KEY - Google Gemini API 金鑰</li>
<li>DEEPSEEK_API_KEY - DeepSeek API 金鑰</li>
<li>OPENAI_API_KEY - OpenAI API 金鑰</li>
</ul>
</div>
</div>
</div>
</div>
);
};
export default LLMConnectionTest;

77
config/llm.config.js Normal file
View File

@@ -0,0 +1,77 @@
/**
* LLM API Configuration
* 支援 Gemini, DeepSeek, OpenAI 三種 LLM 服務
*/
require('dotenv').config();
const llmConfig = {
// Gemini Configuration
gemini: {
apiKey: process.env.GEMINI_API_KEY,
model: process.env.GEMINI_MODEL || 'gemini-pro',
apiUrl: 'https://generativelanguage.googleapis.com/v1beta',
enabled: !!process.env.GEMINI_API_KEY,
timeout: 30000, // 30 seconds
},
// DeepSeek Configuration
deepseek: {
apiKey: process.env.DEEPSEEK_API_KEY,
apiUrl: process.env.DEEPSEEK_API_URL || 'https://api.deepseek.com/v1',
model: process.env.DEEPSEEK_MODEL || 'deepseek-chat',
enabled: !!process.env.DEEPSEEK_API_KEY,
timeout: 30000,
},
// OpenAI Configuration
openai: {
apiKey: process.env.OPENAI_API_KEY,
apiUrl: process.env.OPENAI_API_URL || 'https://api.openai.com/v1',
model: process.env.OPENAI_MODEL || 'gpt-4',
enabled: !!process.env.OPENAI_API_KEY,
timeout: 30000,
},
// Default LLM Provider
defaultProvider: 'gemini',
// Common Settings
maxTokens: 2000,
temperature: 0.7,
};
/**
* 取得啟用的 LLM 服務清單
*/
function getEnabledProviders() {
const enabled = [];
if (llmConfig.gemini.enabled) enabled.push('gemini');
if (llmConfig.deepseek.enabled) enabled.push('deepseek');
if (llmConfig.openai.enabled) enabled.push('openai');
return enabled;
}
/**
* 取得指定 LLM 服務的設定
*/
function getProviderConfig(provider) {
if (!llmConfig[provider]) {
throw new Error(`Unknown LLM provider: ${provider}`);
}
return llmConfig[provider];
}
/**
* 檢查 LLM 服務是否可用
*/
function isProviderEnabled(provider) {
return llmConfig[provider]?.enabled || false;
}
module.exports = {
llmConfig,
getEnabledProviders,
getProviderConfig,
isProviderEnabled,
};

256
database/README.md Normal file
View File

@@ -0,0 +1,256 @@
# HR 績效評核系統 - 資料庫說明
## 資料庫連線資訊
```
DB_HOST: mysql.theaken.com
DB_PORT: 33306
DB_NAME: db_A102
DB_USER: A102
DB_PASSWORD: Bb123456
```
## 資料庫結構
本系統使用 MySQL 資料庫,包含以下主要模組:
### 一、基礎資料表 (5張)
- `hr_departments` - 部門組織架構
- `hr_job_levels` - 職級定義
- `hr_employees` - 員工資料
- `hr_system_roles` - 系統角色權限
- `hr_employee_roles` - 員工角色關聯
### 二、職能字典 (3張)
- `hr_competency_categories` - 職能分類
- `hr_competency_dictionary` - 職能字典
- `hr_competency_behaviors` - 職能行為指標
### 三、角色卡模組 (6張)
- `hr_role_cards` - 角色卡主表
- `hr_role_responsibilities` - 角色卡職責
- `hr_role_supervisees` - 角色卡督導對象
- `hr_role_collaborators` - 角色卡協作夥伴
- `hr_role_kra` - 角色卡KRA
- `hr_role_kpi` - 角色卡KPI
### 四、能力卡模組 (3張)
- `hr_competency_cards` - 能力卡主表
- `hr_competency_card_hard_skills` - 能力卡硬性能力
- `hr_competency_card_soft_skills` - 能力卡軟性能力
### 五、績效卡模組 (4張)
- `hr_review_cycles` - 評核週期設定
- `hr_performance_cards` - 績效卡主表
- `hr_performance_goals` - 績效卡目標評核
- `hr_performance_behaviors` - 績效卡行為評估
### 六、成長卡模組 (5張)
- `hr_growth_cards` - 成長卡主表
- `hr_growth_focus_areas` - 成長卡發展焦點
- `hr_growth_idp_goals` - 成長卡IDP目標
- `hr_growth_actions` - 成長卡行動計畫
- `hr_growth_tracking` - 成長卡追蹤紀錄
### 七、系統支援 (5張)
- `hr_approval_records` - 審批記錄
- `hr_system_settings` - 系統設定
- `hr_rating_thresholds` - 等級分界設定
- `hr_version_snapshots` - 版本快照
- `hr_audit_logs` - 操作日誌
**總計31張資料表**
## 安裝步驟
### 1. 建立資料庫結構
連線到 MySQL 伺服器後,執行以下命令:
```bash
mysql -h mysql.theaken.com -P 33306 -u A102 -p db_A102 < schema.sql
```
或使用 MySQL Workbench / phpMyAdmin 等工具匯入 [schema.sql](schema.sql)
### 2. 匯入初始資料
```bash
mysql -h mysql.theaken.com -P 33306 -u A102 -p db_A102 < seed_data.sql
```
或使用 MySQL Workbench / phpMyAdmin 等工具匯入 [seed_data.sql](seed_data.sql)
## 初始資料內容
執行 `seed_data.sql` 後會建立以下初始資料:
### 系統角色 (4個)
- ADMIN - 系統管理員
- HR - 人力資源
- MANAGER - 部門主管
- EMPLOYEE - 一般員工
### 職級 (9個)
- L1 助理專員 → L9 總經理
### 職能字典 (10個核心職能)
**通用職能 (5個)**
- CORE-001: 溝通協調
- CORE-002: 團隊合作
- CORE-003: 問題解決
- CORE-004: 執行力
- CORE-005: 學習成長
**管理職能 (5個)**
- MGMT-001: 策略思維
- MGMT-002: 團隊領導
- MGMT-003: 橫向整合力
- MGMT-004: 決策判斷
- MGMT-005: 人才培育
### 職能行為指標
每個職能都包含 L1-L5 共5個等級的行為指標描述
### 系統設定
- 目標權重70%
- 行為權重30%
- 預設語言:繁體中文
- 啟用季度評核
- IDP最大目標數4
### 等級分界
- A+: 90-100分 (建議10%)
- A: 80-89.99分 (建議22.5%)
- B+: 70-79.99分 (建議35%)
- B: 60-69.99分 (建議22.5%)
- C: 0-59.99分 (建議10%)
## 資料庫特性
### 字符集
- 使用 `utf8mb4_unicode_ci` 支援多語系與特殊字符
### 引擎
- 使用 `InnoDB` 引擎支援交易與外鍵約束
### 索引優化
- 已在常用查詢欄位建立索引
- 外鍵關聯已建立索引
### 資料完整性
- 使用外鍵約束確保資料關聯正確
- 設定適當的 `ON DELETE` 策略
## 開發建議
### 連線測試
```javascript
// Node.js 範例
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'A102',
password: 'Bb123456',
database: 'db_A102'
});
connection.connect((err) => {
if (err) {
console.error('連線失敗:', err);
return;
}
console.log('資料庫連線成功!');
});
```
### 常用查詢範例
#### 查詢員工及其部門資訊
```sql
SELECT
e.employee_no,
e.name_zh,
d.dept_name_zh,
l.level_name_zh
FROM hr_employees e
JOIN hr_departments d ON e.department_id = d.id
JOIN hr_job_levels l ON e.job_level_id = l.id
WHERE e.status = 'active';
```
#### 查詢職能字典完整資訊
```sql
SELECT
cd.competency_code,
cd.competency_name_zh,
cc.category_name_zh,
cb.level_num,
cb.behavior_description_zh
FROM hr_competency_dictionary cd
JOIN hr_competency_categories cc ON cd.category_id = cc.id
LEFT JOIN hr_competency_behaviors cb ON cd.id = cb.competency_id
WHERE cd.is_active = TRUE
ORDER BY cd.id, cb.level_num;
```
#### 查詢員工的角色卡資訊
```sql
SELECT
rc.card_code,
rc.role_name_zh,
e.name_zh AS employee_name,
d.dept_name_zh,
GROUP_CONCAT(rr.responsibility_zh SEPARATOR '; ') AS responsibilities
FROM hr_role_cards rc
JOIN hr_employees e ON rc.employee_id = e.id
JOIN hr_departments d ON rc.department_id = d.id
LEFT JOIN hr_role_responsibilities rr ON rc.id = rr.role_card_id
WHERE rc.status = 'approved'
GROUP BY rc.id;
```
## 維護建議
### 定期備份
```bash
# 完整備份
mysqldump -h mysql.theaken.com -P 33306 -u A102 -p db_A102 > backup_$(date +%Y%m%d).sql
# 僅備份結構
mysqldump -h mysql.theaken.com -P 33306 -u A102 -p --no-data db_A102 > schema_backup.sql
# 僅備份資料
mysqldump -h mysql.theaken.com -P 33306 -u A102 -p --no-create-info db_A102 > data_backup.sql
```
### 效能監控
- 定期檢查慢查詢日誌
- 監控資料表大小成長
- 定期執行 `OPTIMIZE TABLE` 優化資料表
### 擴充建議
- 職能字典可依需求新增專業職能
- 部門結構可依組織調整
- 評核週期需每年設定
## 注意事項
1. **密碼安全**: 請定期更換資料庫密碼
2. **權限管理**: 建議為不同環境建立不同的資料庫使用者
3. **資料保護**: 員工個資需遵守相關法規保護
4. **版本控制**: 資料庫結構變更需建立遷移腳本
5. **測試環境**: 建議另建測試資料庫進行開發測試
## 技術支援
如有任何資料庫相關問題,請聯繫系統管理員。
---
**最後更新**: 2025-12-03
**版本**: 1.0

581
database/schema.sql Normal file
View File

@@ -0,0 +1,581 @@
-- ============================================
-- HR 績效評核系統 - 資料庫結構
-- Database: db_A102
-- Version: 1.0
-- Created: 2025-12-03
-- ============================================
-- 使用資料庫
USE db_A102;
-- ============================================
-- 一、基礎資料表
-- ============================================
-- 1.1 組織架構表
CREATE TABLE IF NOT EXISTS hr_departments (
id INT AUTO_INCREMENT PRIMARY KEY,
dept_code VARCHAR(20) UNIQUE NOT NULL COMMENT '部門代碼',
dept_name_zh VARCHAR(100) NOT NULL COMMENT '部門名稱(中文)',
dept_name_en VARCHAR(100) COMMENT '部門名稱(英文)',
parent_dept_id INT COMMENT '上級部門ID',
dept_level INT DEFAULT 1 COMMENT '部門層級',
is_active BOOLEAN DEFAULT TRUE COMMENT '是否啟用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_parent (parent_dept_id),
INDEX idx_active (is_active),
FOREIGN KEY (parent_dept_id) REFERENCES hr_departments(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='部門組織架構';
-- 1.2 職級表
CREATE TABLE IF NOT EXISTS hr_job_levels (
id INT AUTO_INCREMENT PRIMARY KEY,
level_code VARCHAR(20) UNIQUE NOT NULL COMMENT '職級代碼',
level_name_zh VARCHAR(50) NOT NULL COMMENT '職級名稱(中文)',
level_name_en VARCHAR(50) COMMENT '職級名稱(英文)',
level_order INT NOT NULL COMMENT '職級順序(數字越大級別越高)',
is_management BOOLEAN DEFAULT FALSE COMMENT '是否管理職',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_order (level_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='職級定義';
-- 1.3 人員表
CREATE TABLE IF NOT EXISTS hr_employees (
id INT AUTO_INCREMENT PRIMARY KEY,
employee_no VARCHAR(20) UNIQUE NOT NULL COMMENT '員工編號',
email VARCHAR(100) UNIQUE NOT NULL COMMENT '電子郵件',
name_zh VARCHAR(50) NOT NULL COMMENT '姓名(中文)',
name_en VARCHAR(50) COMMENT '姓名(英文)',
department_id INT NOT NULL COMMENT '部門ID',
job_level_id INT NOT NULL COMMENT '職級ID',
job_title_zh VARCHAR(100) COMMENT '職稱(中文)',
job_title_en VARCHAR(100) COMMENT '職稱(英文)',
supervisor_id INT COMMENT '直屬主管ID',
hire_date DATE COMMENT '到職日期',
status ENUM('active', 'inactive', 'resigned') DEFAULT 'active' COMMENT '員工狀態',
preferred_language ENUM('zh-TW', 'en-US') DEFAULT 'zh-TW' COMMENT '偏好語言',
password_hash VARCHAR(255) COMMENT '密碼雜湊',
last_login_at TIMESTAMP NULL COMMENT '最後登入時間',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_dept (department_id),
INDEX idx_supervisor (supervisor_id),
INDEX idx_status (status),
INDEX idx_email (email),
FOREIGN KEY (department_id) REFERENCES hr_departments(id),
FOREIGN KEY (job_level_id) REFERENCES hr_job_levels(id),
FOREIGN KEY (supervisor_id) REFERENCES hr_employees(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='員工資料';
-- 1.4 系統角色表
CREATE TABLE IF NOT EXISTS hr_system_roles (
id INT AUTO_INCREMENT PRIMARY KEY,
role_code VARCHAR(20) UNIQUE NOT NULL COMMENT '角色代碼',
role_name_zh VARCHAR(50) NOT NULL COMMENT '角色名稱(中文)',
role_name_en VARCHAR(50) COMMENT '角色名稱(英文)',
permissions JSON COMMENT '權限設定(JSON格式)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系統角色權限';
-- 1.5 員工角色關聯表
CREATE TABLE IF NOT EXISTS hr_employee_roles (
id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT NOT NULL COMMENT '員工ID',
role_id INT NOT NULL COMMENT '角色ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_employee_role (employee_id, role_id),
FOREIGN KEY (employee_id) REFERENCES hr_employees(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES hr_system_roles(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='員工角色關聯';
-- ============================================
-- 二、職能字典
-- ============================================
-- 2.1 職能分類表
CREATE TABLE IF NOT EXISTS hr_competency_categories (
id INT AUTO_INCREMENT PRIMARY KEY,
category_code VARCHAR(20) UNIQUE NOT NULL COMMENT '分類代碼',
category_name_zh VARCHAR(50) NOT NULL COMMENT '分類名稱(中文)',
category_name_en VARCHAR(50) COMMENT '分類名稱(英文)',
category_type ENUM('core', 'management', 'professional') NOT NULL COMMENT '職能類型',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_type (category_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='職能分類';
-- 2.2 職能字典表
CREATE TABLE IF NOT EXISTS hr_competency_dictionary (
id INT AUTO_INCREMENT PRIMARY KEY,
competency_code VARCHAR(30) UNIQUE NOT NULL COMMENT '職能代碼',
category_id INT NOT NULL COMMENT '職能分類ID',
competency_name_zh VARCHAR(100) NOT NULL COMMENT '職能名稱(中文)',
competency_name_en VARCHAR(100) COMMENT '職能名稱(英文)',
definition_zh TEXT NOT NULL COMMENT '職能定義(中文)',
definition_en TEXT COMMENT '職能定義(英文)',
is_active BOOLEAN DEFAULT TRUE COMMENT '是否啟用',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_category (category_id),
INDEX idx_active (is_active),
FOREIGN KEY (category_id) REFERENCES hr_competency_categories(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='職能字典';
-- 2.3 職能等級行為指標表
CREATE TABLE IF NOT EXISTS hr_competency_behaviors (
id INT AUTO_INCREMENT PRIMARY KEY,
competency_id INT NOT NULL COMMENT '職能ID',
level_num INT NOT NULL COMMENT '等級(1-5)',
behavior_description_zh TEXT NOT NULL COMMENT '行為指標(中文)',
behavior_description_en TEXT COMMENT '行為指標(英文)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_comp_level (competency_id, level_num),
FOREIGN KEY (competency_id) REFERENCES hr_competency_dictionary(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='職能行為指標';
-- ============================================
-- 三、角色卡模組
-- ============================================
-- 3.1 角色卡主表
CREATE TABLE IF NOT EXISTS hr_role_cards (
id INT AUTO_INCREMENT PRIMARY KEY,
card_code VARCHAR(30) UNIQUE NOT NULL COMMENT '角色卡編號',
card_type ENUM('template', 'personal') NOT NULL COMMENT '角色卡類型: template職位範本, personal個人角色卡',
department_id INT NOT NULL COMMENT '部門ID',
role_name_zh VARCHAR(100) NOT NULL COMMENT '角色名稱(中文)',
role_name_en VARCHAR(100) COMMENT '角色名稱(英文)',
job_level_id INT NOT NULL COMMENT '職級ID',
employee_id INT COMMENT '綁定員工ID(個人角色卡)',
mission_zh TEXT NOT NULL COMMENT '角色使命(中文)',
mission_en TEXT COMMENT '角色使命(英文)',
supervisor_id INT COMMENT '匯報對象ID',
external_contacts TEXT COMMENT '外部接口',
template_id INT COMMENT '來源範本ID(個人角色卡)',
status ENUM('draft', 'pending_approval', 'approved', 'archived') DEFAULT 'draft' COMMENT '狀態',
version INT DEFAULT 1 COMMENT '版本號',
approved_by INT COMMENT '審批人ID',
approved_at TIMESTAMP NULL COMMENT '審批時間',
created_by INT NOT NULL COMMENT '建立人ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_type (card_type),
INDEX idx_employee (employee_id),
INDEX idx_status (status),
INDEX idx_dept (department_id),
FOREIGN KEY (department_id) REFERENCES hr_departments(id),
FOREIGN KEY (job_level_id) REFERENCES hr_job_levels(id),
FOREIGN KEY (employee_id) REFERENCES hr_employees(id) ON DELETE SET NULL,
FOREIGN KEY (supervisor_id) REFERENCES hr_employees(id) ON DELETE SET NULL,
FOREIGN KEY (template_id) REFERENCES hr_role_cards(id) ON DELETE SET NULL,
FOREIGN KEY (approved_by) REFERENCES hr_employees(id),
FOREIGN KEY (created_by) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡主表';
-- 3.2 角色卡核心職責表
CREATE TABLE IF NOT EXISTS hr_role_responsibilities (
id INT AUTO_INCREMENT PRIMARY KEY,
role_card_id INT NOT NULL COMMENT '角色卡ID',
responsibility_zh TEXT NOT NULL COMMENT '職責描述(中文)',
responsibility_en TEXT COMMENT '職責描述(英文)',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_role_card (role_card_id),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡職責';
-- 3.3 角色卡督導對象表
CREATE TABLE IF NOT EXISTS hr_role_supervisees (
id INT AUTO_INCREMENT PRIMARY KEY,
role_card_id INT NOT NULL COMMENT '角色卡ID',
supervisee_id INT NOT NULL COMMENT '督導對象ID(員工或角色)',
supervisee_type ENUM('employee', 'role') NOT NULL COMMENT '督導對象類型',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_role_card (role_card_id),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡督導對象';
-- 3.4 角色卡協作夥伴表
CREATE TABLE IF NOT EXISTS hr_role_collaborators (
id INT AUTO_INCREMENT PRIMARY KEY,
role_card_id INT NOT NULL COMMENT '角色卡ID',
collaborator_id INT NOT NULL COMMENT '協作對象ID',
collaborator_type ENUM('employee', 'department', 'role') NOT NULL COMMENT '協作對象類型',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_role_card (role_card_id),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡協作夥伴';
-- 3.5 角色卡 KRA 表
CREATE TABLE IF NOT EXISTS hr_role_kra (
id INT AUTO_INCREMENT PRIMARY KEY,
role_card_id INT NOT NULL COMMENT '角色卡ID',
kra_name_zh VARCHAR(200) NOT NULL COMMENT 'KRA名稱(中文)',
kra_name_en VARCHAR(200) COMMENT 'KRA名稱(英文)',
weight_percentage DECIMAL(5,2) NOT NULL COMMENT '權重百分比',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_role_card (role_card_id),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡KRA';
-- 3.6 角色卡 KPI 表
CREATE TABLE IF NOT EXISTS hr_role_kpi (
id INT AUTO_INCREMENT PRIMARY KEY,
kra_id INT NOT NULL COMMENT 'KRA ID',
kpi_name_zh VARCHAR(200) NOT NULL COMMENT 'KPI指標名稱(中文)',
kpi_name_en VARCHAR(200) COMMENT 'KPI指標名稱(英文)',
measurement_zh TEXT NOT NULL COMMENT '衡量方式(中文)',
measurement_en TEXT COMMENT '衡量方式(英文)',
target_value VARCHAR(100) NOT NULL COMMENT '目標值',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_kra (kra_id),
FOREIGN KEY (kra_id) REFERENCES hr_role_kra(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='角色卡KPI';
-- ============================================
-- 四、能力卡模組
-- ============================================
-- 4.1 能力卡主表
CREATE TABLE IF NOT EXISTS hr_competency_cards (
id INT AUTO_INCREMENT PRIMARY KEY,
card_code VARCHAR(30) UNIQUE NOT NULL COMMENT '能力卡編號',
role_card_id INT NOT NULL COMMENT '關聯角色卡ID',
employee_id INT NOT NULL COMMENT '員工ID',
status ENUM('draft', 'active', 'archived') DEFAULT 'draft' COMMENT '狀態',
version INT DEFAULT 1 COMMENT '版本號',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_role_card (role_card_id),
INDEX idx_employee (employee_id),
INDEX idx_status (status),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id),
FOREIGN KEY (employee_id) REFERENCES hr_employees(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='能力卡主表';
-- 4.2 能力卡硬性能力表
CREATE TABLE IF NOT EXISTS hr_competency_card_hard_skills (
id INT AUTO_INCREMENT PRIMARY KEY,
competency_card_id INT NOT NULL COMMENT '能力卡ID',
skill_name_zh VARCHAR(100) NOT NULL COMMENT '技能名稱(中文)',
skill_name_en VARCHAR(100) COMMENT '技能名稱(英文)',
skill_category ENUM('knowledge', 'tool', 'certification') NOT NULL COMMENT '技能類別',
is_required BOOLEAN DEFAULT TRUE COMMENT '是否必備',
required_level INT NOT NULL COMMENT '要求熟練度(1-5)',
description_zh TEXT COMMENT '說明(中文)',
description_en TEXT COMMENT '說明(英文)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_comp_card (competency_card_id),
FOREIGN KEY (competency_card_id) REFERENCES hr_competency_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='能力卡硬性能力';
-- 4.3 能力卡軟性能力表
CREATE TABLE IF NOT EXISTS hr_competency_card_soft_skills (
id INT AUTO_INCREMENT PRIMARY KEY,
competency_card_id INT NOT NULL COMMENT '能力卡ID',
competency_dict_id INT NOT NULL COMMENT '職能字典ID',
required_level INT NOT NULL COMMENT '要求等級(1-5)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_comp_card (competency_card_id),
INDEX idx_comp_dict (competency_dict_id),
FOREIGN KEY (competency_card_id) REFERENCES hr_competency_cards(id) ON DELETE CASCADE,
FOREIGN KEY (competency_dict_id) REFERENCES hr_competency_dictionary(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='能力卡軟性能力';
-- ============================================
-- 五、績效卡模組
-- ============================================
-- 5.1 評核週期設定表
CREATE TABLE IF NOT EXISTS hr_review_cycles (
id INT AUTO_INCREMENT PRIMARY KEY,
cycle_code VARCHAR(30) UNIQUE NOT NULL COMMENT '週期代碼(如: 2024-Q1, 2024-Annual)',
cycle_year INT NOT NULL COMMENT '年度',
cycle_type ENUM('quarterly', 'annual') NOT NULL COMMENT '週期類型',
cycle_quarter INT COMMENT '季度(1-4)',
start_date DATE NOT NULL COMMENT '開始日期',
end_date DATE NOT NULL COMMENT '結束日期',
review_deadline DATE COMMENT '評核截止日期',
status ENUM('planned', 'active', 'closed') DEFAULT 'planned' COMMENT '狀態',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_year (cycle_year),
INDEX idx_type (cycle_type),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='評核週期設定';
-- 5.2 績效卡主表
CREATE TABLE IF NOT EXISTS hr_performance_cards (
id INT AUTO_INCREMENT PRIMARY KEY,
card_code VARCHAR(30) UNIQUE NOT NULL COMMENT '績效卡編號',
review_cycle_id INT NOT NULL COMMENT '評核週期ID',
employee_id INT NOT NULL COMMENT '被評核人ID',
role_card_id INT NOT NULL COMMENT '關聯角色卡ID',
competency_card_id INT NOT NULL COMMENT '關聯能力卡ID',
supervisor_id INT NOT NULL COMMENT '評核主管ID',
self_review_date TIMESTAMP NULL COMMENT '自評完成時間',
supervisor_review_date TIMESTAMP NULL COMMENT '主管評完成時間',
discussion_date DATE COMMENT '績效面談日期',
self_summary TEXT COMMENT '績效自評總結',
supervisor_feedback TEXT COMMENT '主管建議回饋',
goal_score DECIMAL(5,2) COMMENT '目標得分',
behavior_score DECIMAL(5,2) COMMENT '行為得分',
goal_weight DECIMAL(5,2) DEFAULT 70.00 COMMENT '目標佔比',
behavior_weight DECIMAL(5,2) DEFAULT 30.00 COMMENT '行為佔比',
total_score DECIMAL(5,2) COMMENT '總分',
rating ENUM('A+', 'A', 'B+', 'B', 'C') COMMENT '考核等級',
status ENUM('not_started', 'self_review', 'supervisor_review', 'completed', 'archived') DEFAULT 'not_started' COMMENT '狀態',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_cycle (review_cycle_id),
INDEX idx_employee (employee_id),
INDEX idx_supervisor (supervisor_id),
INDEX idx_status (status),
INDEX idx_rating (rating),
FOREIGN KEY (review_cycle_id) REFERENCES hr_review_cycles(id),
FOREIGN KEY (employee_id) REFERENCES hr_employees(id),
FOREIGN KEY (role_card_id) REFERENCES hr_role_cards(id),
FOREIGN KEY (competency_card_id) REFERENCES hr_competency_cards(id),
FOREIGN KEY (supervisor_id) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='績效卡主表';
-- 5.3 績效卡目標評核表
CREATE TABLE IF NOT EXISTS hr_performance_goals (
id INT AUTO_INCREMENT PRIMARY KEY,
performance_card_id INT NOT NULL COMMENT '績效卡ID',
kra_id INT NOT NULL COMMENT 'KRA ID',
weight_percentage DECIMAL(5,2) NOT NULL COMMENT '權重百分比',
actual_output TEXT COMMENT '具體產出描述',
self_completion DECIMAL(5,2) COMMENT '自評完成度(%)',
self_note TEXT COMMENT '自評說明',
supervisor_completion DECIMAL(5,2) COMMENT '主管評完成度(%)',
supervisor_note TEXT COMMENT '主管評說明',
consensus_completion DECIMAL(5,2) COMMENT '共識完成度(%)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_perf_card (performance_card_id),
INDEX idx_kra (kra_id),
FOREIGN KEY (performance_card_id) REFERENCES hr_performance_cards(id) ON DELETE CASCADE,
FOREIGN KEY (kra_id) REFERENCES hr_role_kra(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='績效卡目標評核';
-- 5.4 績效卡行為評估表
CREATE TABLE IF NOT EXISTS hr_performance_behaviors (
id INT AUTO_INCREMENT PRIMARY KEY,
performance_card_id INT NOT NULL COMMENT '績效卡ID',
competency_dict_id INT NOT NULL COMMENT '職能字典ID',
self_level INT COMMENT '自評等級(1-5)',
self_sbi_situation TEXT COMMENT '自評-情境(S)',
self_sbi_behavior TEXT COMMENT '自評-行為(B)',
self_sbi_impact TEXT COMMENT '自評-影響(I)',
supervisor_level INT COMMENT '主管評等級(1-5)',
supervisor_sbi_situation TEXT COMMENT '主管評-情境(S)',
supervisor_sbi_behavior TEXT COMMENT '主管評-行為(B)',
supervisor_sbi_impact TEXT COMMENT '主管評-影響(I)',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_perf_card (performance_card_id),
INDEX idx_comp_dict (competency_dict_id),
FOREIGN KEY (performance_card_id) REFERENCES hr_performance_cards(id) ON DELETE CASCADE,
FOREIGN KEY (competency_dict_id) REFERENCES hr_competency_dictionary(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='績效卡行為評估';
-- ============================================
-- 六、成長卡模組
-- ============================================
-- 6.1 成長卡主表
CREATE TABLE IF NOT EXISTS hr_growth_cards (
id INT AUTO_INCREMENT PRIMARY KEY,
card_code VARCHAR(30) UNIQUE NOT NULL COMMENT '成長卡編號',
performance_card_id INT NOT NULL COMMENT '關聯績效卡ID',
employee_id INT NOT NULL COMMENT '員工ID',
supervisor_id INT NOT NULL COMMENT '輔導主管ID',
growth_period_start DATE NOT NULL COMMENT '成長週期開始',
growth_period_end DATE NOT NULL COMMENT '成長週期結束',
career_aspiration TEXT COMMENT '職業志向',
employee_commitment TEXT COMMENT '員工承諾',
employee_signed_at TIMESTAMP NULL COMMENT '員工簽署時間',
supervisor_commitment TEXT COMMENT '主管承諾',
supervisor_signed_at TIMESTAMP NULL COMMENT '主管簽署時間',
review_frequency ENUM('monthly', 'quarterly') DEFAULT 'quarterly' COMMENT '檢視節奏',
other_suggestions TEXT COMMENT '其他建議',
status ENUM('draft', 'active', 'completed', 'archived') DEFAULT 'draft' COMMENT '狀態',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_perf_card (performance_card_id),
INDEX idx_employee (employee_id),
INDEX idx_supervisor (supervisor_id),
INDEX idx_status (status),
FOREIGN KEY (performance_card_id) REFERENCES hr_performance_cards(id),
FOREIGN KEY (employee_id) REFERENCES hr_employees(id),
FOREIGN KEY (supervisor_id) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成長卡主表';
-- 6.2 成長卡發展焦點表
CREATE TABLE IF NOT EXISTS hr_growth_focus_areas (
id INT AUTO_INCREMENT PRIMARY KEY,
growth_card_id INT NOT NULL COMMENT '成長卡ID',
focus_type ENUM('strength', 'development') NOT NULL COMMENT '焦點類型: strength優勢, development待發展',
competency_dict_id INT COMMENT '關聯職能字典ID',
kra_id INT COMMENT '關聯KRA ID',
description TEXT COMMENT '描述',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_growth_card (growth_card_id),
FOREIGN KEY (growth_card_id) REFERENCES hr_growth_cards(id) ON DELETE CASCADE,
FOREIGN KEY (competency_dict_id) REFERENCES hr_competency_dictionary(id),
FOREIGN KEY (kra_id) REFERENCES hr_role_kra(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成長卡發展焦點';
-- 6.3 成長卡IDP計畫表
CREATE TABLE IF NOT EXISTS hr_growth_idp_goals (
id INT AUTO_INCREMENT PRIMARY KEY,
growth_card_id INT NOT NULL COMMENT '成長卡ID',
goal_title TEXT NOT NULL COMMENT '發展目標(SMART)',
competency_dict_id INT COMMENT '對應能力ID',
timeline_start DATE COMMENT '開始時間',
timeline_end DATE COMMENT '預計完成時間',
success_criteria TEXT COMMENT '成果證據',
status ENUM('pending', 'in_progress', 'completed', 'cancelled') DEFAULT 'pending' COMMENT '狀態',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_growth_card (growth_card_id),
INDEX idx_comp_dict (competency_dict_id),
FOREIGN KEY (growth_card_id) REFERENCES hr_growth_cards(id) ON DELETE CASCADE,
FOREIGN KEY (competency_dict_id) REFERENCES hr_competency_dictionary(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成長卡IDP目標';
-- 6.4 成長卡行動計畫表
CREATE TABLE IF NOT EXISTS hr_growth_actions (
id INT AUTO_INCREMENT PRIMARY KEY,
idp_goal_id INT NOT NULL COMMENT 'IDP目標ID',
action_description TEXT NOT NULL COMMENT '具體行動',
resources_needed TEXT COMMENT '資源與支持',
display_order INT DEFAULT 0 COMMENT '顯示順序',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_idp_goal (idp_goal_id),
FOREIGN KEY (idp_goal_id) REFERENCES hr_growth_idp_goals(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成長卡行動計畫';
-- 6.5 成長卡追蹤紀錄表
CREATE TABLE IF NOT EXISTS hr_growth_tracking (
id INT AUTO_INCREMENT PRIMARY KEY,
growth_card_id INT NOT NULL COMMENT '成長卡ID',
review_date DATE NOT NULL COMMENT '檢視日期',
progress_update TEXT NOT NULL COMMENT '進度更新',
adjustments TEXT COMMENT '調整事項',
employee_confirmed BOOLEAN DEFAULT FALSE COMMENT '員工確認',
supervisor_confirmed BOOLEAN DEFAULT FALSE COMMENT '主管確認',
confirmed_at TIMESTAMP NULL COMMENT '確認時間',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_growth_card (growth_card_id),
INDEX idx_review_date (review_date),
FOREIGN KEY (growth_card_id) REFERENCES hr_growth_cards(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成長卡追蹤紀錄';
-- ============================================
-- 七、審批流程
-- ============================================
-- 7.1 審批記錄表
CREATE TABLE IF NOT EXISTS hr_approval_records (
id INT AUTO_INCREMENT PRIMARY KEY,
entity_type ENUM('role_card', 'competency_card', 'performance_card', 'growth_card') NOT NULL COMMENT '實體類型',
entity_id INT NOT NULL COMMENT '實體ID',
approver_id INT NOT NULL COMMENT '審批人ID',
action ENUM('submit', 'approve', 'reject', 'return') NOT NULL COMMENT '操作',
comments TEXT COMMENT '審批意見',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_entity (entity_type, entity_id),
INDEX idx_approver (approver_id),
FOREIGN KEY (approver_id) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='審批記錄';
-- ============================================
-- 八、系統設定
-- ============================================
-- 8.1 系統配置表
CREATE TABLE IF NOT EXISTS hr_system_settings (
id INT AUTO_INCREMENT PRIMARY KEY,
setting_key VARCHAR(50) UNIQUE NOT NULL COMMENT '設定鍵',
setting_value TEXT COMMENT '設定值',
setting_type ENUM('text', 'number', 'boolean', 'json') DEFAULT 'text' COMMENT '設定類型',
description_zh VARCHAR(200) COMMENT '說明(中文)',
description_en VARCHAR(200) COMMENT '說明(英文)',
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by INT COMMENT '更新人ID',
FOREIGN KEY (updated_by) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系統設定';
-- 8.2 等級分界設定表
CREATE TABLE IF NOT EXISTS hr_rating_thresholds (
id INT AUTO_INCREMENT PRIMARY KEY,
rating ENUM('A+', 'A', 'B+', 'B', 'C') NOT NULL UNIQUE COMMENT '等級',
min_score DECIMAL(5,2) NOT NULL COMMENT '最低分數',
max_score DECIMAL(5,2) NOT NULL COMMENT '最高分數',
suggested_percentage DECIMAL(5,2) COMMENT '建議比例',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='等級分界設定';
-- ============================================
-- 九、版本管理
-- ============================================
-- 9.1 版本快照表
CREATE TABLE IF NOT EXISTS hr_version_snapshots (
id INT AUTO_INCREMENT PRIMARY KEY,
entity_type ENUM('role_card', 'competency_card', 'performance_card', 'growth_card') NOT NULL COMMENT '實體類型',
entity_id INT NOT NULL COMMENT '實體ID',
version_number INT NOT NULL COMMENT '版本號',
snapshot_data JSON NOT NULL COMMENT '快照資料(JSON格式)',
snapshot_reason VARCHAR(200) COMMENT '快照原因',
created_by INT NOT NULL COMMENT '建立人ID',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_entity (entity_type, entity_id),
INDEX idx_version (version_number),
FOREIGN KEY (created_by) REFERENCES hr_employees(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='版本快照';
-- ============================================
-- 十、系統日誌
-- ============================================
-- 10.1 操作日誌表
CREATE TABLE IF NOT EXISTS hr_audit_logs (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id INT COMMENT '操作人ID',
action VARCHAR(50) NOT NULL COMMENT '操作動作',
entity_type VARCHAR(50) COMMENT '實體類型',
entity_id INT COMMENT '實體ID',
ip_address VARCHAR(45) COMMENT 'IP位址',
user_agent TEXT COMMENT '使用者代理',
request_data JSON COMMENT '請求資料',
response_status INT COMMENT '回應狀態',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user (user_id),
INDEX idx_action (action),
INDEX idx_entity (entity_type, entity_id),
INDEX idx_created_at (created_at),
FOREIGN KEY (user_id) REFERENCES hr_employees(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='操作日誌';
-- ============================================
-- 資料庫結構建立完成
-- ============================================

242
database/seed_data.sql Normal file
View File

@@ -0,0 +1,242 @@
-- ============================================
-- HR 績效評核系統 - 初始資料
-- Database: db_A102
-- Version: 1.0
-- Created: 2025-12-03
-- ============================================
USE db_A102;
-- ============================================
-- 一、系統角色初始資料
-- ============================================
INSERT INTO hr_system_roles (role_code, role_name_zh, role_name_en, permissions) VALUES
('ADMIN', '系統管理員', 'System Administrator', '{"all": true}'),
('HR', '人力資源', 'HR Manager', '{"view_all": true, "manage_settings": true, "manage_competency_dict": true}'),
('MANAGER', '部門主管', 'Department Manager', '{"view_team": true, "approve": true, "review": true}'),
('EMPLOYEE', '一般員工', 'Employee', '{"view_self": true, "self_review": true}');
-- ============================================
-- 二、職級初始資料
-- ============================================
INSERT INTO hr_job_levels (level_code, level_name_zh, level_name_en, level_order, is_management) VALUES
('L1', '助理專員', 'Junior Associate', 1, FALSE),
('L2', '專員', 'Associate', 2, FALSE),
('L3', '資深專員', 'Senior Associate', 3, FALSE),
('L4', '副理', 'Assistant Manager', 4, TRUE),
('L5', '經理', 'Manager', 5, TRUE),
('L6', '資深經理', 'Senior Manager', 6, TRUE),
('L7', '協理', 'Director', 7, TRUE),
('L8', '副總經理', 'Vice President', 8, TRUE),
('L9', '總經理', 'General Manager', 9, TRUE);
-- ============================================
-- 三、職能分類初始資料
-- ============================================
INSERT INTO hr_competency_categories (category_code, category_name_zh, category_name_en, category_type, display_order) VALUES
('CORE', '通用職能', 'Core Competencies', 'core', 1),
('MGMT', '管理職能', 'Management Competencies', 'management', 2),
('PROF', '專業職能', 'Professional Competencies', 'professional', 3);
-- ============================================
-- 四、職能字典初始資料 - 通用職能
-- ============================================
INSERT INTO hr_competency_dictionary (competency_code, category_id, competency_name_zh, competency_name_en, definition_zh, definition_en) VALUES
('CORE-001', 1, '溝通協調', 'Communication & Coordination',
'能夠清晰表達想法,有效傾聽他人意見,並促進團隊成員間的理解與協作',
'Ability to clearly express ideas, actively listen to others, and facilitate understanding and collaboration among team members'),
('CORE-002', 1, '團隊合作', 'Teamwork',
'願意與他人合作,主動支援團隊目標,並在團隊中發揮正向影響力',
'Willingness to collaborate with others, proactively support team goals, and create positive impact within the team'),
('CORE-003', 1, '問題解決', 'Problem Solving',
'能夠識別問題核心,運用邏輯思維分析問題,並提出有效的解決方案',
'Ability to identify core issues, apply logical thinking to analyze problems, and propose effective solutions'),
('CORE-004', 1, '執行力', 'Execution',
'能夠按時完成任務,對工作結果負責,並持續追蹤直到目標達成',
'Ability to complete tasks on time, take ownership of work results, and persistently track progress until goals are achieved'),
('CORE-005', 1, '學習成長', 'Learning Agility',
'保持開放心態學習新知,從經驗中反思改進,並持續提升個人能力',
'Maintain an open mindset for learning, reflect and improve from experiences, and continuously enhance personal capabilities');
-- ============================================
-- 五、職能字典初始資料 - 管理職能
-- ============================================
INSERT INTO hr_competency_dictionary (competency_code, category_id, competency_name_zh, competency_name_en, definition_zh, definition_en) VALUES
('MGMT-001', 2, '策略思維', 'Strategic Thinking',
'能夠從全局角度思考,預見未來趨勢,並制定符合組織目標的策略方向',
'Ability to think from a holistic perspective, anticipate future trends, and develop strategic directions aligned with organizational goals'),
('MGMT-002', 2, '團隊領導', 'Team Leadership',
'能夠激勵團隊成員,建立信任關係,並帶領團隊達成目標',
'Ability to motivate team members, build trust relationships, and lead teams to achieve goals'),
('MGMT-003', 2, '橫向整合力', 'Cross-functional Integration',
'能夠跨部門協調資源,整合不同觀點,並促進組織整體效能',
'Ability to coordinate resources across departments, integrate diverse perspectives, and enhance overall organizational effectiveness'),
('MGMT-004', 2, '決策判斷', 'Decision Making',
'能夠在不確定情境中做出明智決策,權衡利弊並承擔決策責任',
'Ability to make sound decisions in uncertain situations, weigh pros and cons, and take responsibility for decisions'),
('MGMT-005', 2, '人才培育', 'People Development',
'能夠識別團隊成員潛力,提供發展機會,並有效輔導人才成長',
'Ability to identify team members\' potential, provide development opportunities, and effectively coach talent growth');
-- ============================================
-- 六、職能行為指標初始資料 - 溝通協調 (CORE-001)
-- ============================================
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(1, 1, '',
'Can clearly express own ideas, listen to others, and perform basic communication in simple situations'),
(1, 2, '調',
'Can adjust communication style based on audience, effectively convey information and confirm understanding in daily work'),
(1, 3, '調',
'Can facilitate communication among team members, coordinate different opinions, and seek consensus in conflict situations'),
(1, 4, '',
'Can conduct cross-departmental communication in complex situations, effectively integrate multiple perspectives and drive decisions'),
(1, 5, '',
'Can establish organizational communication mechanisms, develop others\' communication skills, and exert influence at critical moments');
-- ============================================
-- 七、職能行為指標初始資料 - 團隊合作 (CORE-002)
-- ============================================
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(2, 1, '願意配合團隊需要,接受任務分配,並在團隊中扮演支持角色',
'Willing to accommodate team needs, accept task assignments, and play a supportive role in the team'),
(2, 2, '主動分享資訊與資源,協助團隊成員解決問題,並維持良好團隊氛圍',
'Proactively share information and resources, help team members solve problems, and maintain positive team atmosphere'),
(2, 3, '能夠在團隊中發揮協調作用,促進成員間合作,並為團隊目標貢獻想法',
'Can play a coordinating role in the team, facilitate member collaboration, and contribute ideas to team goals'),
(2, 4, '能夠跨團隊建立合作關係,整合不同專業,並帶動團隊創新',
'Can build collaborative relationships across teams, integrate different expertise, and drive team innovation'),
(2, 5, '能夠塑造合作文化,培養團隊協作能力,並成為組織協作的典範',
'Can shape collaborative culture, develop team collaboration capabilities, and become an organizational collaboration role model');
-- ============================================
-- 八、職能行為指標初始資料 - 問題解決 (CORE-003)
-- ============================================
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(3, 1, '能夠發現明顯問題,依據指導尋找解決方法,並執行基本的問題處理',
'Can identify obvious problems, seek solutions with guidance, and execute basic problem handling'),
(3, 2, '能夠分析問題成因,運用既有方法解決問題,並從中學習改進',
'Can analyze problem causes, apply existing methods to solve problems, and learn for improvement'),
(3, 3, '能夠系統化分析複雜問題,提出創新解決方案,並評估方案可行性',
'Can systematically analyze complex problems, propose innovative solutions, and evaluate solution feasibility'),
(3, 4, '能夠處理高度複雜問題,整合多方資源找出最佳解,並預防問題再發生',
'Can handle highly complex problems, integrate multiple resources to find optimal solutions, and prevent recurrence'),
(3, 5, '能夠建立問題解決機制,培養組織解決問題能力,並推動持續改善文化',
'Can establish problem-solving mechanisms, develop organizational problem-solving capabilities, and drive continuous improvement culture');
-- ============================================
-- 九、職能行為指標初始資料 - 執行力 (CORE-004)
-- ============================================
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(4, 1, '能夠按照指示完成任務,遵守時程與品質要求,並主動回報進度',
'Can complete tasks as instructed, comply with timeline and quality requirements, and proactively report progress'),
(4, 2, '能夠獨立規劃工作,有效管理時間與優先順序,並確保任務如期達成',
'Can independently plan work, effectively manage time and priorities, and ensure tasks are completed on schedule'),
(4, 3, '能夠在多任務情境中保持專注,克服障礙推動執行,並達成挑戰性目標',
'Can stay focused in multi-tasking situations, overcome obstacles to drive execution, and achieve challenging goals'),
(4, 4, '能夠帶領團隊高效執行專案,監控進度並即時調整,確保目標達成',
'Can lead teams to execute projects efficiently, monitor progress and adjust in time, ensuring goal achievement'),
(4, 5, '能夠建立執行管理機制,提升組織執行效能,並塑造結果導向文化',
'Can establish execution management mechanisms, enhance organizational execution effectiveness, and shape results-oriented culture');
-- ============================================
-- 十、職能行為指標初始資料 - 學習成長 (CORE-005)
-- ============================================
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(5, 1, '願意學習新知識與技能,接受回饋並嘗試改進,保持積極學習態度',
'Willing to learn new knowledge and skills, accept feedback and try to improve, maintain positive learning attitude'),
(5, 2, '主動尋求學習機會,從工作經驗中反思,並將所學應用於實務工作',
'Proactively seek learning opportunities, reflect from work experiences, and apply learning to practical work'),
(5, 3, '能夠快速掌握新領域知識,跨領域學習並整合應用,持續提升專業能力',
'Can quickly master new domain knowledge, learn across fields and integrate applications, continuously enhance professional capabilities'),
(5, 4, '能夠引領團隊學習,分享知識與經驗,並建立學習型團隊文化',
'Can lead team learning, share knowledge and experiences, and build learning team culture'),
(5, 5, '能夠推動組織學習與創新,建立知識管理機制,並培養組織學習能力',
'Can drive organizational learning and innovation, establish knowledge management mechanisms, and cultivate organizational learning capabilities');
-- ============================================
-- 十一、職能行為指標初始資料 - 管理職能 (簡化版)
-- ============================================
-- 策略思維 (MGMT-001)
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(6, 1, '能夠理解部門目標,並將其與個人工作連結', 'Can understand department goals and connect them with personal work'),
(6, 2, '能夠掌握業務全貌,識別關鍵成功因素', 'Can grasp business overview and identify key success factors'),
(6, 3, '能夠分析市場趨勢,制定部門策略方向', 'Can analyze market trends and develop department strategic direction'),
(6, 4, '能夠整合內外部資源,推動組織策略執行', 'Can integrate internal and external resources to drive organizational strategy execution'),
(6, 5, '能夠制定公司級策略,引領組織轉型創新', 'Can develop company-level strategy and lead organizational transformation and innovation');
-- 團隊領導 (MGMT-002)
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(7, 1, '能夠在團隊中發揮正向影響力', 'Can exert positive influence within the team'),
(7, 2, '能夠帶領小型專案團隊達成目標', 'Can lead small project teams to achieve goals'),
(7, 3, '能夠有效管理團隊,激勵成員績效', 'Can effectively manage teams and motivate member performance'),
(7, 4, '能夠建立高效團隊,培養後備領導人才', 'Can build high-performing teams and develop future leaders'),
(7, 5, '能夠跨組織領導變革,建立領導梯隊', 'Can lead cross-organizational change and build leadership pipeline');
-- 橫向整合力 (MGMT-003)
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(8, 1, '能夠與其他部門建立良好工作關係', 'Can establish good working relationships with other departments'),
(8, 2, '能夠協調跨部門合作完成專案', 'Can coordinate cross-departmental collaboration to complete projects'),
(8, 3, '能夠整合跨部門資源解決複雜問題', 'Can integrate cross-departmental resources to solve complex problems'),
(8, 4, '能夠建立跨部門協作機制提升效能', 'Can establish cross-departmental collaboration mechanisms to enhance effectiveness'),
(8, 5, '能夠推動組織整體整合優化', 'Can drive overall organizational integration and optimization');
-- 決策判斷 (MGMT-004)
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(9, 1, '能夠依據標準流程做出日常決策', 'Can make daily decisions based on standard procedures'),
(9, 2, '能夠在一般情境中做出合理判斷', 'Can make reasonable judgments in general situations'),
(9, 3, '能夠在複雜情境中權衡利弊做決策', 'Can weigh pros and cons to make decisions in complex situations'),
(9, 4, '能夠在不確定性下做出關鍵決策', 'Can make critical decisions under uncertainty'),
(9, 5, '能夠做出影響組織長遠發展的戰略決策', 'Can make strategic decisions affecting long-term organizational development');
-- 人才培育 (MGMT-005)
INSERT INTO hr_competency_behaviors (competency_id, level_num, behavior_description_zh, behavior_description_en) VALUES
(10, 1, '願意協助新人適應工作環境', 'Willing to help newcomers adapt to work environment'),
(10, 2, '能夠指導同事提升工作技能', 'Can guide colleagues to improve work skills'),
(10, 3, '能夠識別人才潛力並提供發展機會', 'Can identify talent potential and provide development opportunities'),
(10, 4, '能夠系統化培育團隊人才', 'Can systematically develop team talent'),
(10, 5, '能夠建立組織人才發展體系', 'Can establish organizational talent development system');
-- ============================================
-- 十二、系統設定初始資料
-- ============================================
INSERT INTO hr_system_settings (setting_key, setting_value, setting_type, description_zh, description_en) VALUES
('goal_weight', '70.00', 'number', '目標成果權重百分比', 'Goal achievement weight percentage'),
('behavior_weight', '30.00', 'number', '行為能力權重百分比', 'Behavior competency weight percentage'),
('default_language', 'zh-TW', 'text', '系統預設語言', 'System default language'),
('enable_quarterly_review', 'true', 'boolean', '是否啟用季度評核', 'Enable quarterly review'),
('max_idp_goals', '4', 'number', 'IDP計畫最大目標數', 'Maximum IDP goals count');
-- ============================================
-- 十三、等級分界初始資料
-- ============================================
INSERT INTO hr_rating_thresholds (rating, min_score, max_score, suggested_percentage) VALUES
('A+', 90.00, 100.00, 10.00),
('A', 80.00, 89.99, 22.50),
('B+', 70.00, 79.99, 35.00),
('B', 60.00, 69.99, 22.50),
('C', 0.00, 59.99, 10.00);
-- ============================================
-- 初始資料建立完成
-- ============================================

171
routes/llm.routes.js Normal file
View File

@@ -0,0 +1,171 @@
/**
* LLM API Routes
* 處理 LLM 相關的 API 請求
*/
const express = require('express');
const router = express.Router();
const llmService = require('../services/llm.service');
const { asyncHandler, createError } = require('../utils/errorHandler');
/**
* POST /api/llm/test/gemini
* 測試 Gemini API 連線
*/
router.post('/test/gemini', asyncHandler(async (req, res) => {
const result = await llmService.testGeminiConnection();
res.json(result);
}));
/**
* POST /api/llm/test/deepseek
* 測試 DeepSeek API 連線
*/
router.post('/test/deepseek', asyncHandler(async (req, res) => {
const result = await llmService.testDeepSeekConnection();
res.json(result);
}));
/**
* POST /api/llm/test/openai
* 測試 OpenAI API 連線
*/
router.post('/test/openai', asyncHandler(async (req, res) => {
const result = await llmService.testOpenAIConnection();
res.json(result);
}));
/**
* POST /api/llm/test/all
* 測試所有 LLM API 連線
*/
router.post('/test/all', asyncHandler(async (req, res) => {
const results = await llmService.testAllConnections();
res.json(results);
}));
/**
* POST /api/llm/generate
* 使用 LLM 生成內容
*
* Body:
* {
* "prompt": "你的提示內容",
* "provider": "gemini|deepseek|openai", (可選,預設使用 gemini)
* "options": {
* "temperature": 0.7,
* "maxTokens": 2000
* }
* }
*/
router.post('/generate', asyncHandler(async (req, res) => {
const { prompt, provider, options } = req.body;
if (!prompt) {
throw createError('BAD_REQUEST', '缺少必要參數: prompt');
}
const result = await llmService.generate(prompt, provider, options);
res.json(result);
}));
/**
* POST /api/llm/help-me-fill
* Help Me AI 智能填寫功能
*
* Body:
* {
* "cardType": "role|competency|performance|growth",
* "cardId": "卡片ID",
* "filledFields": { ... },
* "emptyFields": [ ... ],
* "context": { ... }
* }
*/
router.post('/help-me-fill', asyncHandler(async (req, res) => {
const { cardType, cardId, filledFields, emptyFields, context } = req.body;
if (!cardType || !emptyFields || emptyFields.length === 0) {
throw createError('BAD_REQUEST', '缺少必要參數');
}
// 建立提示詞
const prompt = buildHelpMeFillPrompt(cardType, filledFields, emptyFields, context);
// 使用 LLM 生成建議內容
const result = await llmService.generate(prompt, 'gemini', {
temperature: 0.7,
maxTokens: 2000,
});
if (!result.success) {
throw createError('LLM_API_ERROR', '生成內容失敗');
}
// 解析生成的內容
const suggestions = parseHelpMeFillResponse(result.content, emptyFields);
res.json({
success: true,
filledCount: Object.keys(suggestions).length,
suggestions,
});
}));
/**
* 建立 Help Me Fill 提示詞
*/
function buildHelpMeFillPrompt(cardType, filledFields, emptyFields, context) {
let prompt = `你是一個 HR 績效評核系統的智能助手。請根據以下資訊,為空白欄位生成合適的內容。\n\n`;
prompt += `卡片類型: ${cardType}\n\n`;
if (Object.keys(filledFields).length > 0) {
prompt += `已填寫的欄位:\n`;
for (const [key, value] of Object.entries(filledFields)) {
prompt += `- ${key}: ${value}\n`;
}
prompt += `\n`;
}
if (context) {
prompt += `上下文資訊:\n`;
prompt += JSON.stringify(context, null, 2);
prompt += `\n\n`;
}
prompt += `請為以下空白欄位生成內容:\n`;
emptyFields.forEach(field => {
prompt += `- ${field}\n`;
});
prompt += `\n請以 JSON 格式回覆,格式如下:\n`;
prompt += `{\n`;
emptyFields.forEach(field => {
prompt += ` "${field}": "生成的內容",\n`;
});
prompt += `}\n`;
return prompt;
}
/**
* 解析 Help Me Fill 回應
*/
function parseHelpMeFillResponse(content, emptyFields) {
try {
// 嘗試直接解析 JSON
const jsonMatch = content.match(/\{[\s\S]*\}/);
if (jsonMatch) {
return JSON.parse(jsonMatch[0]);
}
// 如果無法解析 JSON則返回空物件
return {};
} catch (error) {
console.error('解析 LLM 回應失敗:', error);
return {};
}
}
module.exports = router;

364
services/llm.service.js Normal file
View File

@@ -0,0 +1,364 @@
/**
* LLM Service
* 整合 Gemini, DeepSeek, OpenAI 三種 LLM API
*/
const axios = require('axios');
const { llmConfig, getProviderConfig, isProviderEnabled } = require('../config/llm.config');
class LLMService {
/**
* 測試 Gemini API 連線
*/
async testGeminiConnection() {
try {
if (!isProviderEnabled('gemini')) {
return {
success: false,
message: 'Gemini API key not configured',
provider: 'gemini',
};
}
const config = getProviderConfig('gemini');
const url = `${config.apiUrl}/models/${config.model}:generateContent`;
const response = await axios.post(
url,
{
contents: [
{
parts: [
{
text: 'Hello, this is a connection test.',
},
],
},
],
},
{
headers: {
'Content-Type': 'application/json',
},
params: {
key: config.apiKey,
},
timeout: config.timeout,
}
);
if (response.status === 200 && response.data) {
return {
success: true,
message: 'Gemini API connection successful',
provider: 'gemini',
model: config.model,
};
}
return {
success: false,
message: 'Unexpected response from Gemini API',
provider: 'gemini',
};
} catch (error) {
return {
success: false,
message: error.response?.data?.error?.message || error.message,
provider: 'gemini',
error: error.message,
};
}
}
/**
* 測試 DeepSeek API 連線
*/
async testDeepSeekConnection() {
try {
if (!isProviderEnabled('deepseek')) {
return {
success: false,
message: 'DeepSeek API key not configured',
provider: 'deepseek',
};
}
const config = getProviderConfig('deepseek');
const url = `${config.apiUrl}/chat/completions`;
const response = await axios.post(
url,
{
model: config.model,
messages: [
{
role: 'user',
content: 'Hello, this is a connection test.',
},
],
max_tokens: 50,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${config.apiKey}`,
},
timeout: config.timeout,
}
);
if (response.status === 200 && response.data.choices) {
return {
success: true,
message: 'DeepSeek API connection successful',
provider: 'deepseek',
model: config.model,
};
}
return {
success: false,
message: 'Unexpected response from DeepSeek API',
provider: 'deepseek',
};
} catch (error) {
return {
success: false,
message: error.response?.data?.error?.message || error.message,
provider: 'deepseek',
error: error.message,
};
}
}
/**
* 測試 OpenAI API 連線
*/
async testOpenAIConnection() {
try {
if (!isProviderEnabled('openai')) {
return {
success: false,
message: 'OpenAI API key not configured',
provider: 'openai',
};
}
const config = getProviderConfig('openai');
const url = `${config.apiUrl}/chat/completions`;
const response = await axios.post(
url,
{
model: config.model,
messages: [
{
role: 'user',
content: 'Hello, this is a connection test.',
},
],
max_tokens: 50,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${config.apiKey}`,
},
timeout: config.timeout,
}
);
if (response.status === 200 && response.data.choices) {
return {
success: true,
message: 'OpenAI API connection successful',
provider: 'openai',
model: config.model,
};
}
return {
success: false,
message: 'Unexpected response from OpenAI API',
provider: 'openai',
};
} catch (error) {
return {
success: false,
message: error.response?.data?.error?.message || error.message,
provider: 'openai',
error: error.message,
};
}
}
/**
* 測試所有 LLM 連線
*/
async testAllConnections() {
const results = {
gemini: await this.testGeminiConnection(),
deepseek: await this.testDeepSeekConnection(),
openai: await this.testOpenAIConnection(),
};
return results;
}
/**
* 使用 Gemini 生成內容
*/
async generateWithGemini(prompt, options = {}) {
try {
if (!isProviderEnabled('gemini')) {
throw new Error('Gemini API not configured');
}
const config = getProviderConfig('gemini');
const url = `${config.apiUrl}/models/${config.model}:generateContent`;
const response = await axios.post(
url,
{
contents: [
{
parts: [{ text: prompt }],
},
],
generationConfig: {
temperature: options.temperature || llmConfig.temperature,
maxOutputTokens: options.maxTokens || llmConfig.maxTokens,
},
},
{
headers: {
'Content-Type': 'application/json',
},
params: {
key: config.apiKey,
},
timeout: config.timeout,
}
);
if (response.data?.candidates?.[0]?.content?.parts?.[0]?.text) {
return {
success: true,
content: response.data.candidates[0].content.parts[0].text,
provider: 'gemini',
};
}
throw new Error('Invalid response format from Gemini');
} catch (error) {
throw new Error(`Gemini API error: ${error.message}`);
}
}
/**
* 使用 DeepSeek 生成內容
*/
async generateWithDeepSeek(prompt, options = {}) {
try {
if (!isProviderEnabled('deepseek')) {
throw new Error('DeepSeek API not configured');
}
const config = getProviderConfig('deepseek');
const url = `${config.apiUrl}/chat/completions`;
const response = await axios.post(
url,
{
model: config.model,
messages: [{ role: 'user', content: prompt }],
temperature: options.temperature || llmConfig.temperature,
max_tokens: options.maxTokens || llmConfig.maxTokens,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${config.apiKey}`,
},
timeout: config.timeout,
}
);
if (response.data?.choices?.[0]?.message?.content) {
return {
success: true,
content: response.data.choices[0].message.content,
provider: 'deepseek',
};
}
throw new Error('Invalid response format from DeepSeek');
} catch (error) {
throw new Error(`DeepSeek API error: ${error.message}`);
}
}
/**
* 使用 OpenAI 生成內容
*/
async generateWithOpenAI(prompt, options = {}) {
try {
if (!isProviderEnabled('openai')) {
throw new Error('OpenAI API not configured');
}
const config = getProviderConfig('openai');
const url = `${config.apiUrl}/chat/completions`;
const response = await axios.post(
url,
{
model: config.model,
messages: [{ role: 'user', content: prompt }],
temperature: options.temperature || llmConfig.temperature,
max_tokens: options.maxTokens || llmConfig.maxTokens,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${config.apiKey}`,
},
timeout: config.timeout,
}
);
if (response.data?.choices?.[0]?.message?.content) {
return {
success: true,
content: response.data.choices[0].message.content,
provider: 'openai',
};
}
throw new Error('Invalid response format from OpenAI');
} catch (error) {
throw new Error(`OpenAI API error: ${error.message}`);
}
}
/**
* 使用預設或指定的 LLM 生成內容
*/
async generate(prompt, provider = null, options = {}) {
const selectedProvider = provider || llmConfig.defaultProvider;
switch (selectedProvider) {
case 'gemini':
return await this.generateWithGemini(prompt, options);
case 'deepseek':
return await this.generateWithDeepSeek(prompt, options);
case 'openai':
return await this.generateWithOpenAI(prompt, options);
default:
throw new Error(`Unknown provider: ${selectedProvider}`);
}
}
}
module.exports = new LLMService();

211
utils/errorHandler.js Normal file
View File

@@ -0,0 +1,211 @@
/**
* 錯誤處理工具
* 統一處理應用程式中的錯誤
*/
class ErrorHandler extends Error {
constructor(statusCode, message, details = null) {
super(message);
this.statusCode = statusCode;
this.details = details;
this.timestamp = new Date().toISOString();
Error.captureStackTrace(this, this.constructor);
}
}
/**
* 錯誤類型定義
*/
const ErrorTypes = {
// 4xx Client Errors
BAD_REQUEST: { code: 400, message: '請求參數錯誤' },
UNAUTHORIZED: { code: 401, message: '未授權訪問' },
FORBIDDEN: { code: 403, message: '禁止訪問' },
NOT_FOUND: { code: 404, message: '資源不存在' },
CONFLICT: { code: 409, message: '資源衝突' },
VALIDATION_ERROR: { code: 422, message: '資料驗證失敗' },
// 5xx Server Errors
INTERNAL_ERROR: { code: 500, message: '伺服器內部錯誤' },
DATABASE_ERROR: { code: 500, message: '資料庫錯誤' },
LLM_API_ERROR: { code: 500, message: 'LLM API 錯誤' },
EXTERNAL_API_ERROR: { code: 502, message: '外部 API 錯誤' },
SERVICE_UNAVAILABLE: { code: 503, message: '服務暫時無法使用' },
};
/**
* 建立錯誤實例
*/
function createError(type, customMessage = null, details = null) {
const errorType = ErrorTypes[type] || ErrorTypes.INTERNAL_ERROR;
const message = customMessage || errorType.message;
return new ErrorHandler(errorType.code, message, details);
}
/**
* Express 錯誤處理中介層
*/
function handleError(err, req, res, next) {
const statusCode = err.statusCode || 500;
const message = err.message || '未知錯誤';
// 記錄錯誤日誌
console.error('[Error]', {
timestamp: new Date().toISOString(),
path: req.path,
method: req.method,
statusCode,
message,
details: err.details,
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
});
// 回傳錯誤訊息
res.status(statusCode).json({
success: false,
error: {
statusCode,
message,
details: err.details,
timestamp: err.timestamp || new Date().toISOString(),
path: req.path,
// 只在開發環境顯示堆疊資訊
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
},
});
}
/**
* 捕獲非同步錯誤的包裝器
*/
function asyncHandler(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
/**
* 驗證錯誤處理
*/
function validationError(errors) {
return createError('VALIDATION_ERROR', '資料驗證失敗', errors);
}
/**
* 資料庫錯誤處理
*/
function databaseError(error) {
const message = error.code === 'ER_DUP_ENTRY'
? '資料重複,請檢查輸入的內容'
: '資料庫操作失敗';
return createError('DATABASE_ERROR', message, {
code: error.code,
sqlMessage: error.sqlMessage,
});
}
/**
* LLM API 錯誤處理
*/
function llmApiError(provider, error) {
return createError('LLM_API_ERROR', `${provider} API 錯誤`, {
provider,
error: error.message,
});
}
/**
* 前端錯誤處理輔助函數
*/
const FrontendErrorHandler = {
/**
* 顯示錯誤訊息
*/
showError(error, options = {}) {
const {
title = '錯誤',
duration = 5000,
showDetails = false,
} = options;
const errorData = error.response?.data?.error || error;
const message = errorData.message || error.message || '發生未知錯誤';
const details = showDetails ? errorData.details : null;
// 這裡可以整合不同的前端 UI 框架
return {
title,
message,
details,
statusCode: errorData.statusCode,
timestamp: errorData.timestamp,
duration,
};
},
/**
* 處理 API 錯誤
*/
handleApiError(error) {
if (error.response) {
// 伺服器回應錯誤
const { status, data } = error.response;
switch (status) {
case 400:
return this.showError(error, { title: '請求錯誤' });
case 401:
return this.showError(error, { title: '未授權' });
case 403:
return this.showError(error, { title: '禁止訪問' });
case 404:
return this.showError(error, { title: '資源不存在' });
case 422:
return this.showError(error, {
title: '資料驗證失敗',
showDetails: true
});
case 500:
return this.showError(error, { title: '伺服器錯誤' });
default:
return this.showError(error);
}
} else if (error.request) {
// 請求已發送但沒有收到回應
return {
title: '網路錯誤',
message: '無法連接到伺服器,請檢查網路連線',
duration: 5000,
};
} else {
// 其他錯誤
return this.showError(error, { title: '錯誤' });
}
},
/**
* 驗證表單錯誤
*/
handleValidationErrors(errors) {
if (Array.isArray(errors)) {
return errors.map(err => ({
field: err.field || err.param,
message: err.message || err.msg,
}));
}
return [];
},
};
module.exports = {
ErrorHandler,
ErrorTypes,
createError,
handleError,
asyncHandler,
validationError,
databaseError,
llmApiError,
FrontendErrorHandler,
};

733
使用說明.md Normal file
View File

@@ -0,0 +1,733 @@
# 績效管理系統 - 使用說明
**文件版本**v1.1
**建立日期**2024年12月
**適用對象**全體員工、主管、HR 管理者
---
## 目錄
1. [系統概述](#一系統概述)
2. [登入與介面導覽](#二登入與介面導覽)
3. [Help Me AI 智能填寫功能](#三help-me-ai-智能填寫功能)
4. [角色卡操作指南](#四角色卡操作指南)
5. [能力卡操作指南](#五能力卡操作指南)
6. [績效卡操作指南](#六績效卡操作指南)
7. [成長卡操作指南](#七成長卡操作指南)
8. [審批操作指南](#八審批操作指南)
9. [報表與儀表板](#九報表與儀表板)
10. [常見問題 FAQ](#十常見問題-faq)
---
## 一、系統概述
### 1.1 什麼是四卡績效管理系統?
本系統採用「四卡循環」架構,協助您完成從職責定義到個人發展的完整績效管理:
| 卡片 | 用途 | 簡單說明 |
|------|------|----------|
| 🧑 **角色卡** | 定義職責 | 說明「我是誰、負責什麼」 |
| 🎯 **能力卡** | 設定標準 | 說明「需要什麼能力」 |
| 📊 **績效卡** | 評核績效 | 記錄「做得如何」 |
| 🌱 **成長卡** | 規劃發展 | 規劃「如何成長」 |
### 1.2 四卡如何連動?
```
角色卡 ──▶ 能力卡 ──▶ 績效卡 ──▶ 成長卡
│ │ │ │
│ │ │ │
└───────────┴───────────┴───────────┘
基本資訊自動帶入
```
- 系統會自動將前一張卡的資料帶入下一張卡
- 您不需要重複填寫相同資訊
- 所有卡片會保留歷史快照供查閱
### 1.3 評核週期說明
| 週期 | 時間 | 評核內容 |
|------|------|----------|
| Q1 季度 | 4月 | 目標進度追蹤(輕量) |
| Q2 季度 | 7月 | 目標進度追蹤(輕量) |
| Q3 季度 | 10月 | 目標進度追蹤(輕量) |
| 年度完整 | 1月 | 目標成果(70%) + 行為能力(30%) |
---
## 二、登入與介面導覽
### 2.1 系統登入
1. 開啟瀏覽器,輸入系統網址
2. 使用公司帳號密碼登入(支援 SSO 單一登入)
3. 首次登入請確認個人資料正確
### 2.2 主介面說明
```
┌─────────────────────────────────────────────────────────────────────┐
│ ① 頂部導航列 │
│ ┌─────────────────────────────────────────────────────────────────┐│
│ │ 🏆 績效管理系統 [繁中|EN] 🔔通知 👤王小明 產品部PM ││
│ └─────────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────────┤
│ ② 評核週期選擇 │
│ ┌─────────────────────────────────────────────────────────────────┐│
│ │ [Q1季度] [Q2季度] [Q3季度] [年度完整] 期間2024/01-2024/12 ││
│ └─────────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────────┤
│ ③ 四卡進度指示器 │
│ ┌─────────────────────────────────────────────────────────────────┐│
│ │ ✅角色卡 ──▶ ✅能力卡 ──▶ 🔵績效卡 ──▶ ⚪成長卡 ││
│ │ 已完成 已完成 進行中 待開始 ││
│ └─────────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────────┤
│ ④側邊欄│ ⑤ 主內容區 │⑥ 右側儀表板 │
│ ┌─────┐│ ┌─────────────────────────────────────┐ │ ┌───────────┐ │
│ │角色卡││ │ │ │ │績效分佈 │ │
│ │能力卡││ │ 卡片內容編輯區域 │ │ │快速統計 │ │
│ │績效卡││ │ │ │ │待審批 │ │
│ │成長卡││ │ │ │ │ │ │
│ │─────││ │ │ │ │ │ │
│ │儀表板││ └─────────────────────────────────────┘ │ └───────────┘ │
│ │歷史 ││ │ │
│ └─────┘│ │ │
└─────────────────────────────────────────────────────────────────────┘
```
| 區域 | 功能說明 |
|------|----------|
| ① 頂部導航 | 語系切換、通知中心、個人資訊 |
| ② 週期選擇 | 切換季度/年度評核 |
| ③ 進度指示 | 顯示四卡完成狀態 |
| ④ 側邊欄 | 快速切換卡片、報表 |
| ⑤ 主內容區 | 編輯卡片內容 |
| ⑥ 儀表板 | 績效統計、待辦事項 |
### 2.3 語系切換
1. 點擊頂部導航列的「繁中 | EN」
2. 選擇您偏好的語言
3. 介面立即切換(填寫內容維持原語言)
---
## 三、Help Me AI 智能填寫功能
### 10.1 功能介紹
**Help Me** 是本系統的 AI 智能輔助功能,可以幫助您快速填寫表單中的空白欄位。
```
┌─────────────────────────────────────────────────────────────────────┐
│ Help Me AI 功能示意 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ✨ Help Me │ │
│ │ AI 智能填寫 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ AI 檢查頁面所有可填寫欄位 │ │
│ │ ├── 已有內容 → 不做任何變更 │ │
│ │ └── 空白欄位 → 依據已填內容智能生成建議 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
```
### 10.2 適用頁面
| 卡片類型 | 可使用 Help Me | 說明 |
|----------|----------------|------|
| 角色卡 | ✓ | 自動補充職責描述、KRA/KPI |
| 能力卡 | ✓ | 自動建議技能說明、熟練度 |
| 績效卡 | ✓ | 自動生成具體產出、SBI 舉例 |
| 成長卡 | ✓ | 自動補充 IDP 行動計畫 |
### 10.3 使用方式
**步驟說明:**
1. 先填寫部分欄位AI 會參考已填內容)
2. 找到頁面右上角的 **「✨ Help Me」** 按鈕
3. 點擊按鈕
4. 等待 AI 處理(約 2-3 秒)
5. 系統自動填入空白欄位
6. 檢視 AI 生成的內容,視需要調整
### 10.4 AI 填寫規則
| 情境 | AI 行為 |
|------|---------|
| 欄位已有內容 | **不會變更**,保留您的原始輸入 |
| 欄位為空白 | AI 依據相關內容生成建議 |
| 所有欄位已填 | 顯示「所有欄位已填寫」提示 |
### 10.5 AI 填寫辨識
AI 填寫的欄位會有特殊標示:
- 🟣 **紫色邊框**:表示該欄位由 AI 填寫
- 📍 **AI 標籤**部分欄位會顯示「AI」標籤
- 🔔 **底部通知**顯示「AI 已填寫 X 個欄位」
```
┌─────────────────────────────────────────┐
│ 具體產出 AI 已填寫 │
├─────────────────────────────────────────┤
│ ┌─────────────────────────────────────┐ │
│ │ NPS 從 32 分提升至 48 分,超越 │ │ ◀── 紫色邊框標示
│ │ 目標 6.7%。客戶續約率達 92%... │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
```
### 10.6 最佳使用建議
| 建議 | 說明 |
|------|------|
| **先填關鍵資訊** | 先填寫 KRA 名稱、基本描述AI 會更精準 |
| **檢查並調整** | AI 生成的內容為建議,請務必檢視並調整 |
| **補充細節** | AI 可能缺少您才知道的具體數據,請補充 |
| **多次使用** | 可多次點擊 Help MeAI 會填寫新的空白欄位 |
### 10.7 使用範例
**情境:填寫績效卡的 KRA**
| 步驟 | 您的操作 | AI 行為 |
|------|----------|---------|
| 1 | 填寫 KRA 名稱:「客戶滿意度提升」 | - |
| 2 | 填寫權重30% | - |
| 3 | 「具體產出」留空 | - |
| 4 | 點擊 **Help Me** | AI 生成具體產出內容 |
| 5 | 檢視 AI 建議 | - |
| 6 | 補充實際數據 | - |
**AI 生成範例:**
```
AI 生成的「具體產出」:
NPS 從 32 分提升至 48 分(目標 45 分),超越目標 6.7%。
客戶續約率達 92%,較去年提升 8 個百分點。
主導客戶滿意度調查改革,建立季度客戶訪談機制。
```
### 10.8 注意事項
⚠️ **重要提醒:**
1. **AI 內容僅供參考**:請務必檢視並確認內容正確性
2. **數據需自行核實**AI 可能使用示意數據,請替換為實際數據
3. **個人化調整**AI 無法完全了解您的工作細節,請自行補充
4. **保密資訊**:請勿依賴 AI 生成涉及機密的具體內容
---
## 四、角色卡操作指南
### 10.1 適用對象
| 角色 | 可執行操作 |
|------|------------|
| 員工 | 認領職位範本、微調個人角色卡 |
| 主管 | 審批部屬角色卡 |
| HR | 建立/維護職位範本 |
### 10.2 認領職位範本(員工)
**步驟說明:**
1. 點擊側邊欄「角色卡」
2. 若尚未有個人角色卡,系統會顯示可認領的職位範本
3. 瀏覽符合您職級的職位範本
4. 點擊「認領此職位」
5. 系統自動複製為您的個人角色卡
### 10.3 編輯角色卡(員工)
**填寫欄位說明:**
| 區塊 | 欄位 | 填寫說明 | 範例 |
|------|------|----------|------|
| **基本資訊** | 部門名稱 | 自動帶入 | 產品部 |
| | 角色名稱 | 自動帶入 | 產品經理 |
| | 職級 | 自動帶入 | P3 |
| **角色使命** | 使命描述 | 一句話說明您的崗位價值 | 我的使命是透過優質產品解決客戶痛點,創造商業價值 |
| **核心職責** | 職責清單 | 4-8項動詞開頭 | ・規劃產品路線圖<br>・收集用戶需求<br>・協調跨部門資源 |
| **組織關聯** | 匯報對象 | 直屬主管 | 張經理 |
| | 督導對象 | 您管理的人員 | 產品助理 x2 |
| | 內部協作 | 跨部門夥伴 | 研發部、設計部、行銷部 |
| **KRA/KPI** | KRA | 關鍵成果領域 | 產品上市時程 |
| | KPI | 績效指標 | 準時上市率 |
| | 衡量方式 | 如何計算 | 實際上市日 vs 計畫日 |
| | 目標值 | 達標基準 | ≥90% |
| | 權重 | 佔比(總和=100% | 40% |
**操作步驟:**
1. 在各區塊填寫或修改內容
2. 可點擊「+ 新增職責」增加項目
3. KRA 權重總和必須等於 100%
4. 填寫完成後點擊「暫存草稿」或「送出審批」
### 10.4 送出審批
1. 確認所有必填欄位已完成
2. 點擊「送出審批」按鈕
3. 系統自動通知您的直屬主管
4. 您可在「通知中心」追蹤審批狀態
---
## 五、能力卡操作指南
### 10.1 能力卡結構
能力卡分為兩大類:
| 類型 | 說明 | 來源 |
|------|------|------|
| **軟性能力** | 管理職能、通用職能 | 從職能字典選取 |
| **硬性能力** | 專業技能、證照資質 | 自行填寫 |
### 10.2 選用軟性能力
**步驟說明:**
1. 點擊側邊欄「能力卡」
2. 系統自動帶入角色卡基本資訊
3. 在「軟性能力」區塊點擊「+ 從職能字典選取」
4. 瀏覽可選用的職能項目:
- 通用職能(全員適用)
- 管理職能(管理職適用)
- 專業職能(依部門)
5. 勾選適用項目,點擊「確認選取」
6. 系統自動帶入職能定義與 L1-L5 行為描述
7. 為每項職能設定「要求等級」
**等級說明:**
| 等級 | 定義 | 行為描述 |
|------|------|----------|
| L1 | 初學新手 | 了解概念,需他人指導才能展現 |
| L2 | 基礎應用 | 在簡單情境中能展現基本行為 |
| L3 | 獨立勝任 | 穩定展現於日常工作中 |
| L4 | 精通深化 | 在複雜情境中能有效展現 |
| L5 | 專家引領 | 能指導他人並創新優化 |
### 10.3 填寫硬性能力
**填寫欄位說明:**
| 欄位 | 填寫說明 | 範例 |
|------|----------|------|
| 技能/證照名稱 | 專業技能或認證 | Python 程式設計 |
| 技能類別 | 選擇分類 | 專業知識 / 工具使用 / 證照資質 |
| 是否必備 | 必須具備或加分 | 是 |
| 熟練度要求 | 1-5級 | 4 |
| 說明 | 應用情境 | 用於數據分析與自動化腳本開發 |
**熟練度定義:**
| 等級 | 定義 |
|------|------|
| 1 | 了解概念,需指導操作 |
| 2 | 基礎應用,可完成標準任務 |
| 3 | 獨立操作,處理一般問題 |
| 4 | 精通深化,可指導初學者 |
| 5 | 專家創新,可培訓/優化流程 |
### 10.4 送出審批
1. 確認軟性能力與硬性能力皆已填寫
2. 點擊「送出審批」
3. 等待主管審核
---
## 六、績效卡操作指南
### 10.1 評核流程概述
```
開啟評核 ──▶ 員工自評 ──▶ 主管評核 ──▶ 績效面談 ──▶ 確認等級
```
### 10.2 選擇評核週期
1. 在頂部「評核週期選擇」區塊選擇:
- **Q1/Q2/Q3 季度**:輕量評核,僅追蹤目標進度
- **年度完整**:完整評核,包含目標成果 + 行為能力
### 10.3 填寫目標成果(自評)
**步驟說明:**
1. 點擊側邊欄「績效卡」
2. 系統自動帶入角色卡的 KRA 清單
3. 針對每個 KRA
| 欄位 | 填寫說明 |
|------|----------|
| 具體產出 | 描述您實際完成的工作成果 |
| 自評完成度 | 拖曳滑桿或輸入百分比0-100% |
| 自評說明 | 說明自評依據 |
**填寫範例:**
```
KRA產品上市時程
權重40%
具體產出:
Q1 完成 MVP 開發Q2 Beta 測試上線,獲得 500+ 測試用戶回饋。
整體進度符合預期,僅延遲 2 週。
自評完成度80%
自評說明:
原訂 6/15 上線,實際 6/30 上線,延遲 15 天(約 10%)。
主因為第三方 API 整合問題,已及時調整並解決。
```
### 10.4 填寫行為能力(自評)- 僅年度評核
**步驟說明:**
1. 切換到「行為評估」Tab
2. 系統自動帶入能力卡的職能項目
3. 針對每項職能:
| 欄位 | 填寫說明 |
|------|----------|
| 自評等級 | 點選 L1-L5 按鈕 |
| 評估舉例 | 使用 SBI 格式填寫具體事例 |
**SBI 格式說明:**
| 元素 | 說明 | 範例 |
|------|------|------|
| **S** - Situation | 情境:何時、何地、什麼背景 | 跨部門產品發布專案中 |
| **B** - Behavior | 行為:您具體做了什麼 | 主動召開週會,建立共享進度看板 |
| **I** - Impact | 影響:產生什麼結果 | 專案準時上線,協作效率提升 30% |
**填寫範例:**
```
職能:橫向整合力
定義:整合跨部門資源,建立有效協作關係
自評等級L3 獨立勝任
評估舉例SBI
【情境】Q2 產品發布專案,需協調研發、設計、行銷三個部門
【行為】主動建立每週同步會議機制,使用 Notion 建立共享看板追蹤進度
【影響】所有部門同步率提升,專案準時上線,獲得主管肯定
```
### 10.5 填寫績效自評
1. 切換到「綜合評價」Tab
2. 在「績效自評」區塊撰寫整體自我評價
3. 可回顧本年度的成就、挑戰、學習
### 10.6 送出自評
1. 確認所有區塊已填寫完成
2. 點擊「送出自評」
3. 系統通知主管進行評核
### 10.7 查看主管評核結果
1. 主管評核完成後,您會收到通知
2. 進入績效卡可看到:
- 主管評完成度(與您的自評並列顯示)
- 主管評行為等級
- 主管回饋建議
3. 系統會自動安排績效面談
### 10.8 績效面談與確認
1. 依約定時間與主管進行績效面談
2. 討論自評與主管評的差異
3. 達成共識後,確認「共識完成度」
4. 雙方電子簽核,績效卡定稿
---
## 七、成長卡操作指南
### 10.1 成長卡自動產生
年度評核完成後,系統會自動:
- 建立您的成長卡草稿
- 帶入績效卡的優勢項(高分項目)
- 帶入待發展領域(待改善項目)
### 10.2 填寫發展焦點
| 區塊 | 填寫說明 |
|------|----------|
| 優勢項 | 系統自動帶入,可調整 |
| 待發展領域 | 系統自動帶入,可調整 |
| 職業志向 | 填寫您的職涯發展期望 |
**職業志向範例:**
```
短期1年內精進產品數據分析能力
中期1-3年晉升為資深產品經理
長期3-5年成為產品總監帶領產品團隊
```
### 10.3 設定 IDP 目標
建議聚焦 **3-4 個**發展目標,避免資源分散。
**SMART 原則提示:**
| 原則 | 說明 | 範例 |
|------|------|------|
| **S** - Specific | 具體明確 | 提升數據分析能力 |
| **M** - Measurable | 可衡量 | 完成 3 個數據專案 |
| **A** - Achievable | 可達成 | 考量現有資源與時間 |
| **R** - Relevant | 相關性 | 與工作職責相關 |
| **T** - Time-bound | 有時限 | 2024年Q2前完成 |
**填寫欄位:**
| 欄位 | 填寫說明 | 範例 |
|------|----------|------|
| 發展目標 | SMART 格式的目標描述 | 2024年Q2前完成數據分析線上課程認證 |
| 對應能力 | 連結能力卡項目 | 數據分析技能 |
| 具體行動 | 要做什麼(多項) | ・報名 Coursera 課程<br>・每週投入 5 小時學習<br>・完成 3 個實作專案 |
| 資源與支持 | 需要什麼協助 | 申請培訓預算 NT$5,000 |
| 時間線 | 預計完成時間 | 2024/06/30 |
| 成果證據 | 如何證明達成 | 取得課程認證證書 |
### 10.4 設定檢視節奏
| 選項 | 說明 |
|------|------|
| 月檢視 | 每月與主管進行簡短進度確認 |
| 季回顧 | 每季進行較完整的回顧與調整 |
建議選擇「月檢視 + 季回顧」組合。
### 10.5 承諾簽署
1. 員工承諾:確認將主動執行計畫
2. 點擊「員工簽署」完成電子簽核
3. 送出給主管審批
4. 主管審批並簽署「主管承諾」
5. 成長卡正式生效
### 10.6 持續追蹤
**月檢視操作:**
1. 點擊成長卡中的「+ 新增追蹤紀錄」
2. 填寫日期、進度更新
3. 與主管確認後簽名
**追蹤紀錄範例:**
```
日期2024/02/15
進度更新:
・完成 Coursera 課程第 1-3 模組
・已開始第一個實作專案(客戶流失預測)
・預計下月完成課程一半進度
調整事項:
簽名確認:員工 ✓ 主管 ✓
```
---
## 八、審批操作指南
### 10.1 查看待審批項目(主管)
1. 收到系統通知時,點擊通知連結
2. 或在首頁右側「待審批清單」查看
3. 或點擊側邊欄「待審批」頁面
### 10.2 審批角色卡/能力卡
**步驟說明:**
1. 點擊待審批項目進入詳情
2. 檢視員工填寫內容
3. 若有修改,系統會標示與範本的差異
4. 選擇操作:
| 操作 | 說明 |
|------|------|
| **核准** | 內容無誤,同意生效 |
| **退回** | 需要修改,填寫退回原因 |
### 10.3 審批績效卡(主管評核)
**步驟說明:**
1. 進入部屬的績效卡
2. 檢視員工自評內容
3. 填寫主管評核:
| 區塊 | 操作 |
|------|------|
| 目標成果 | 針對每個 KRA 填寫「主管評完成度」與說明 |
| 行為能力 | 針對每項職能選擇「主管評等級」並補充舉例 |
| 主管回饋 | 撰寫整體回饋與建議 |
4. 邀請績效面談(系統可發送行事曆邀請)
5. 面談後確認「共識完成度」與「績效等級」
6. 雙方簽核完成評核
### 10.4 審批成長卡
1. 檢視員工 IDP 計畫是否合理
2. 確認目標、行動、時間線可行性
3. 核准或提供修改建議
4. 簽署「主管承諾」
---
## 九、報表與儀表板
### 10.1 個人報表
| 報表 | 內容 |
|------|------|
| 四卡總覽 | 自己的四張卡片完整內容 |
| 歷史快照 | 各週期績效卡、成長卡歷史版本 |
| 能力雷達圖 | 各項能力等級視覺化 |
### 10.2 主管儀表板
| 報表 | 內容 |
|------|------|
| 部門人員清單 | 所有部屬四卡狀態 |
| 績效等級分佈 | A+/A/B+/B/C 分佈圓餅圖 |
| 待審批清單 | 等待您處理的項目 |
| 評核進度追蹤 | 部門評核完成率 |
### 10.3 查看績效分佈
1. 點擊側邊欄「儀表板」
2. 查看「績效等級分佈」圖表
3. 虛線標示建議分佈比例(僅供參考,不強制)
**建議分佈:**
| 等級 | 建議比例 |
|------|----------|
| A+ | ≤ 10% |
| A | 20-25% |
| B+ | 30-40% |
| B | 20-25% |
| C | ≤ 10% |
---
## 十、常見問題 FAQ
### Q1忘記密碼怎麼辦
點擊登入頁面的「忘記密碼」,依指示重設密碼。或聯繫 IT 部門協助。
### Q2如何修改已送出的卡片
- **待審批中**:請聯繫主管退回後修改
- **已核准**:需重新發起變更申請,經主管審批
### Q3KRA 權重加總不到 100% 怎麼辦?
系統會自動檢查,權重總和必須等於 100% 才能送出。請調整各項權重分配。
### Q4季度評核與年度評核有什麼不同
| 項目 | 季度評核 | 年度評核 |
|------|----------|----------|
| 頻率 | Q1/Q2/Q3 各一次 | 年度一次 |
| 內容 | 僅目標進度追蹤 | 目標成果 + 行為能力 |
| 佔比 | 無 | 目標 70% + 行為 30% |
| 產出 | 快照歸檔 | 績效等級 + 成長卡 |
### Q5如何查看歷史績效紀錄
點擊側邊欄「歷史快照」,可查看過去各週期的績效卡與成長卡。
### Q6主管沒有審批怎麼辦
1. 先透過系統發送提醒
2. 若持續未處理,聯繫 HR 協助
### Q7績效等級是強制分佈嗎
不是。系統顯示的是「建議分佈」,僅供主管參考,不強制執行。最終等級由主管依實際績效判定。
### Q8成長卡的 IDP 目標建議設幾個?
建議 **3-4 個**,避免目標過多導致資源分散、無法專注落實。
### Q9如何切換語言
點擊頂部導航列的「繁中 | EN」按鈕即可切換。目前支援繁體中文與英文。
### Q10手機可以使用嗎
可以。系統採用響應式設計,支援手機、平板、電腦等各種裝置。
### Q11Help Me AI 按鈕在哪裡?
在每個可填寫卡片的頁面右上角,您會看到一個紫色漸層的「✨ Help Me」按鈕。
### Q12Help Me AI 會修改我已經填寫的內容嗎?
不會。AI 只會填寫**空白欄位**,已經有內容的欄位不會被修改。您的原始輸入會完整保留。
### Q13Help Me AI 生成的內容可以直接使用嗎?
建議您務必檢視 AI 生成的內容並根據實際情況調整。AI 可能使用示意數據或通用描述,請替換為您的實際資料。
### Q14可以多次使用 Help Me AI 嗎?
可以。每次點擊都會檢查當前空白欄位並填寫。如果您清空某個欄位後再點擊AI 會重新生成該欄位的內容。
### Q15Help Me AI 如何知道該填什麼內容?
AI 會參考:
- 您已填寫的欄位內容
- 卡片類型與結構
- 職能字典定義
- 角色卡的 KRA/KPI 設定
---
## 十一、聯絡與支援
| 問題類型 | 聯絡方式 |
|----------|----------|
| 系統操作問題 | HR 部門 |
| 技術問題 | IT 服務台 |
| 績效評核相關 | 直屬主管 / HR BP |
---
**文件結束**
如有任何問題,歡迎隨時聯繫 HR 部門!

618
流程設計.md Normal file
View File

@@ -0,0 +1,618 @@
# 績效管理系統 - 流程設計文件
**文件版本**v1.1
**建立日期**2024年12月
**適用對象**系統開發團隊、HR管理者
---
## 一、流程總覽
### 1.1 四卡循環架構
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 四卡績效管理循環 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ │ │ │ │
│ ┌────│ 角色卡 │────┐ ┌────│ 成長卡 │◀───┐ │
│ │ │ Role Card│ │ │ │Growth Card│ │ │
│ │ └──────────┘ │ │ └──────────┘ │ │
│ │ │ │ │ ▲ │ │
│ │ │ 職責定義 │ │ │ IDP規劃 │ │
│ │ ▼ │ │ │ │ │
│ │ ┌──────────┐ │ │ ┌──────────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ └───▶│ 能力卡 │────┴───────────────────┴───▶│ 績效卡 │────┘ │
│ │Competency│ 能力基準 │Performance│ │
│ └──────────┘ └──────────┘ │
│ │
│ ════════════════════════════════════════════════════════════════════ │
│ 單向連動・週期快照保留 │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 1.2 年度主時程
| 月份 | 階段 | 主要活動 | 產出 |
|------|------|----------|------|
| 12月 | 年初規劃 | 角色卡確認、目標設定 | 角色卡、能力卡定稿 |
| 1-3月 | Q1 執行 | 目標執行、持續記錄 | - |
| 4月 | Q1 回顧 | 季度輕量評核 | Q1 績效卡快照 |
| 4-6月 | Q2 執行 | 目標執行、持續記錄 | - |
| 7月 | Q2 回顧 | 季度輕量評核 | Q2 績效卡快照 |
| 7-9月 | Q3 執行 | 目標執行、持續記錄 | - |
| 10月 | Q3 回顧 | 季度輕量評核 | Q3 績效卡快照 |
| 10-12月 | Q4 執行 | 目標執行、年度總結 | - |
| 1月 | 年度評核 | 完整績效評估 | 年度績效卡、成長卡 |
---
## 二、角色卡流程
### 2.1 流程圖
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 角色卡建立與維護流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 【職位範本模式】 【個人角色卡模式】 │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ HR/主管 │ │ 員工 │ │
│ │建立職位 │ │ 認領職位│ │
│ │ 範本 │ │ 範本 │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 定義職責│ │ 複製為 │ │
│ │ KRA/KPI │ │個人角色卡│ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 設定能力│ │ 微調職責│ │
│ │ 要求 │ │ (可選) │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ 發布 │ │ 主管審批│◀── 單層審批 │
│ │ 職位範本│ │ │ │
│ └─────────┘ └────┬────┘ │
│ │ │
│ ▼ │
│ ┌─────────┐ │
│ │角色卡生效│ │
│ │建立快照 │ │
│ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 2.2 詳細步驟
#### Step 1建立職位範本HR/部門主管)
| 步驟 | 操作者 | 動作 | 系統行為 |
|------|--------|------|----------|
| 1.1 | HR | 點擊「新增職位範本」 | 開啟空白角色卡表單 |
| 1.2 | HR | 填寫部門、角色名稱、職級 | 自動帶入組織架構選項 |
| 1.3 | HR | 撰寫角色使命 | 提示:一句話說明崗位價值 |
| 1.4 | HR | 新增核心職責4-8項 | 提示:使用動詞開頭 |
| 1.5 | HR | 設定組織關聯 | 自動帶入人員選單 |
| 1.6 | HR | 定義 KRA/KPI | 自動計算權重總和 |
| 1.7 | HR | 點擊「發布範本」 | 職位範本上架可認領 |
#### Step 2認領與個人化員工
| 步驟 | 操作者 | 動作 | 系統行為 |
|------|--------|------|----------|
| 2.1 | 員工 | 瀏覽可認領職位 | 顯示符合職級的範本 |
| 2.2 | 員工 | 點擊「認領此職位」 | 複製為個人角色卡 |
| 2.3 | 員工 | 微調職責內容(可選) | 標記差異處 |
| 2.4 | 員工 | 點擊「送出審批」 | 通知直屬主管 |
#### Step 3審批直屬主管
| 步驟 | 操作者 | 動作 | 系統行為 |
|------|--------|------|----------|
| 3.1 | 主管 | 收到審批通知 | 顯示待審批清單 |
| 3.2 | 主管 | 檢視角色卡內容 | 顯示與範本差異 |
| 3.3a | 主管 | 點擊「核准」 | 角色卡生效,建立快照 |
| 3.3b | 主管 | 點擊「退回」並填寫意見 | 通知員工修改 |
### 2.3 角色卡變更流程
```
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 員工/主管 │────▶│ 編輯角色卡│────▶│ 主管審批 │────▶│ 生效歸檔 │
│ 發起變更 │ │ 標記變更點│ │ │ │ 保留快照 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
```
---
## 三、能力卡流程
### 3.1 流程圖
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 能力卡建立流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 職能字典管理HR │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ 通用職能 │ │ 管理職能 │ │ 專業職能 │ │ │
│ │ │ ・溝通協調 │ │ ・策略思維 │ │ ・[部門] │ │ │
│ │ │ ・團隊合作 │ │ ・團隊領導 │ │ ・[專業] │ │ │
│ │ │ ・問題解決 │ │ ・橫向整合 │ │ │ │ │
│ │ └───────────┘ └───────────┘ └───────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ 選用 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 能力卡建立(員工) │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │連動角色卡│─────▶│選用軟性 │─────▶│ 填寫硬性│─────▶│ 主管審批│ │ │
│ │ │ 基本資訊 │ │能力項目 │ │能力清單 │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └────┬────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │能力卡生效│ │ │
│ │ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 3.2 職能字典維護流程
| 步驟 | 操作者 | 動作 | 說明 |
|------|--------|------|------|
| 1 | HR 管理員 | 建立/維護職能字典 | 定義職能名稱、定義、L1-L5 行為指標 |
| 2 | HR 管理員 | 設定職能適用對象 | 依職級/部門設定可選用範圍 |
| 3 | HR 管理員 | 發布職能字典 | 開放員工選用 |
### 3.3 能力卡填寫流程
| 步驟 | 操作者 | 動作 | 系統行為 |
|------|--------|------|----------|
| 1 | 員工 | 開啟能力卡 | 自動帶入角色卡基本資訊 |
| 2 | 員工 | 選用軟性能力項目 | 從職能字典篩選適用項目 |
| 3 | 系統 | 自動帶入職能定義 | 顯示 L1-L5 行為描述 |
| 4 | 員工 | 設定各項要求等級 | 選擇該角色應達到的等級 |
| 5 | 員工 | 填寫硬性能力清單 | 專業技能、證照資質 |
| 6 | 員工 | 設定各項熟練度要求 | 1-5 級熟練度 |
| 7 | 員工 | 送出審批 | 通知直屬主管 |
| 8 | 主管 | 審批能力卡 | 核准/退回 |
---
## 四、績效卡流程
### 4.1 評核週期流程
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 績效評核週期流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 季度輕量評核 (Q1/Q2/Q3) │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │
│ │ │ 開啟 │───▶│ 員工 │───▶│ 主管 │───▶│ 績效 │───▶│ 快照 │ │ │
│ │ │季度評核│ │ 自評 │ │ 評核 │ │ 面談 │ │ 歸檔 │ │ │
│ │ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘ │ │
│ │ │ │ │
│ │ └── 僅評估「目標進度」,不評行為能力 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 年度完整評核 (Annual) │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │
│ │ │ 開啟 │───▶│ 員工 │───▶│ 主管 │───▶│ 績效 │───▶│ 等級 │ │ │
│ │ │年度評核│ │ 自評 │ │ 評核 │ │ 面談 │ │ 確認 │ │ │
│ │ └───────┘ └───────┘ └───────┘ └───────┘ └───┬───┘ │ │
│ │ │ │ │ │
│ │ └── 目標成果(70%) + 行為能力(30%) │ │ │
│ │ ▼ │ │
│ │ ┌───────┐ │ │
│ │ │ 產出 │ │ │
│ │ │成長卡 │ │ │
│ │ └───────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.2 自評+主管評流程
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 評分機制流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 階段一:員工自評 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌───────────────────┐ ┌───────────────────┐ │ │
│ │ │ 目標成果自評 │ │ 行為能力自評 │ │ │
│ │ │ ・各 KRA 完成度 │ │ ・各職能等級 │ │ │
│ │ │ ・具體產出描述 │ │ ・SBI 舉例 │ │ │
│ │ └───────────────────┘ └───────────────────┘ │ │
│ │ │ │ │ │
│ │ └────────┬───────────┘ │ │
│ │ ▼ │ │
│ │ ┌───────────────────┐ │ │
│ │ │ 績效自評總結 │ │ │
│ │ │ 送出給主管 │ │ │
│ │ └───────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 階段二:主管評核 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌───────────────────┐ ┌───────────────────┐ │ │
│ │ │ 目標成果評核 │ │ 行為能力評核 │ │ │
│ │ │ ・確認完成度 │ │ ・評定等級 │ │ │
│ │ │ ・調整/補充說明 │ │ ・補充觀察舉例 │ │ │
│ │ └───────────────────┘ └───────────────────┘ │ │
│ │ │ │ │ │
│ │ └────────┬───────────┘ │ │
│ │ ▼ │ │
│ │ ┌───────────────────┐ │ │
│ │ │ 主管回饋建議 │ │ │
│ │ │ 邀請績效面談 │ │ │
│ │ └───────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 階段三:績效面談 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐│ │
│ │ │ 回顧自評 │───▶│ 討論差異 │───▶│ 達成共識 │───▶│ 確認等級 ││ │
│ │ │ vs 主管評 │ │ 與期望 │ │ 完成度 │ │ 簽核 ││ │
│ │ └───────────┘ └───────────┘ └───────────┘ └───────────┘│ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.3 績效等級判定流程
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 績效等級判定流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 計分規則 │ │
│ │ │ │
│ │ 目標成果分數 = Σ(各 KRA 共識完成度 × 權重) × 70% │ │
│ │ 行為能力分數 = 各職能等級平均 × 20 × 30% │ │
│ │ 總分 = 目標成果分數 + 行為能力分數 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 等級對照表(建議) │ │
│ │ │ │
│ │ ┌────────┬──────────┬──────────┬─────────────────────────────┐ │ │
│ │ │ 等級 │ 分數區間 │ 建議比例 │ 說明 │ │ │
│ │ ├────────┼──────────┼──────────┼─────────────────────────────┤ │ │
│ │ │ A+ │ ≥95 │ ≤10% │ 卓越超群,大幅超越預期 │ │ │
│ │ │ A │ 85-94 │ 20-25% │ 優秀達標,穩定超越預期 │ │ │
│ │ │ B+ │ 75-84 │ 30-40% │ 良好穩定,達成預期目標 │ │ │
│ │ │ B │ 65-74 │ 20-25% │ 合格待進,基本達成但有進步空間│ │ │
│ │ │ C │ <65 │ ≤10% │ 需要改善,未達預期需輔導 │ │ │
│ │ └────────┴──────────┴──────────┴─────────────────────────────┘ │ │
│ │ │ │
│ │ ⚠️ 建議比例為參考,不強制執行 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 部門校準 │ │
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ 系統顯示 │───▶│ HR 檢視 │───▶│ 確認或 │ │ │
│ │ │ 分佈統計 │ │ 分佈狀況 │ │ 提醒調整 │ │ │
│ │ └───────────┘ └───────────┘ └───────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.4 詳細步驟表
| 階段 | 步驟 | 操作者 | 動作 | 系統行為 |
|------|------|--------|------|----------|
| **開啟** | 1 | HR | 開啟評核週期 | 通知全員、建立績效卡 |
| | 2 | 系統 | 自動帶入資料 | 連動角色卡 KRA、能力卡職能 |
| **自評** | 3 | 員工 | 填寫各 KRA 完成度 | 顯示目標值對照 |
| | 4 | 員工 | 描述具體產出 | 支援附件上傳 |
| | 5 | 員工 | 選擇行為能力等級 | 顯示 L1-L5 定義 |
| | 6 | 員工 | 填寫 SBI 舉例 | 提示格式 |
| | 7 | 員工 | 撰寫績效自評 | 整體自我評價 |
| | 8 | 員工 | 送出自評 | 通知主管 |
| **主管評** | 9 | 主管 | 檢視員工自評 | 顯示自評內容 |
| | 10 | 主管 | 評定各 KRA 完成度 | 可調整員工自評 |
| | 11 | 主管 | 評定行為能力等級 | 顯示自評 vs 主管評對照 |
| | 12 | 主管 | 撰寫回饋建議 | - |
| | 13 | 主管 | 邀請績效面談 | 發送行事曆邀請 |
| **面談** | 14 | 雙方 | 進行績效面談 | 可線上記錄重點 |
| | 15 | 雙方 | 確認共識完成度 | 最終評分依據 |
| | 16 | 雙方 | 確認績效等級 | 系統計算建議等級 |
| | 17 | 雙方 | 電子簽核 | 績效卡定稿 |
| **歸檔** | 18 | 系統 | 建立週期快照 | 保存完整績效卡 |
| | 19 | 系統 | 產出成長卡輸入 | 帶入優勢/待發展 |
---
## 五、成長卡流程
### 5.1 流程圖
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 成長卡建立與追蹤流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Phase 1IDP 規劃 │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │績效卡產出│───▶│識別發展 │───▶│設定 IDP │───▶│雙方承諾 │ │ │
│ │ │優勢/待改│ │ 焦點 │ │ 目標 │ │ 簽署 │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └────┬────┘ │ │
│ │ │ │ │
│ └──────────────────────────────────────────────────────┼────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Phase 2持續追蹤 │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ 月檢視 │────────▶│ 季回顧 │────────▶│ 年評估 │ │ │
│ │ │ 進度更新│ 累積 │ 調整計畫│ 累積 │ 成效驗收│ │ │
│ │ └─────────┘ └─────────┘ └────┬────┘ │ │
│ │ │ │ │
│ └─────────────────────────────────────────────────────┼─────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Phase 3回饋循環 │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │成長卡歸檔│───▶│回饋角色卡│───▶│ 下週期 │ │ │
│ │ │ 快照保存 │ │能力更新 │ │ 目標設定│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 5.2 IDP 規劃詳細步驟
| 步驟 | 操作者 | 動作 | 系統行為 |
|------|--------|------|----------|
| 1 | 系統 | 產生成長卡草稿 | 連動績效卡結果 |
| 2 | 系統 | 帶入優勢項 | 績效卡高分項目 |
| 3 | 系統 | 帶入待發展領域 | 績效卡待改善項目 |
| 4 | 員工 | 填寫職業志向 | 職涯發展期望 |
| 5 | 員工 | 設定發展目標3-4個 | SMART 原則提示 |
| 6 | 員工 | 對應能力項目 | 連動能力卡 |
| 7 | 員工 | 填寫具體行動 | 做什麼 |
| 8 | 員工 | 填寫資源與支持 | 需要什麼協助 |
| 9 | 員工 | 設定時間線 | 預計完成時間 |
| 10 | 員工 | 定義成果證據 | 如何證明達成 |
| 11 | 員工 | 設定檢視節奏 | 月檢視/季回顧 |
| 12 | 員工 | 員工承諾簽署 | 電子簽核 |
| 13 | 員工 | 送出主管審批 | 通知主管 |
| 14 | 主管 | 審批 IDP 計畫 | 核准/建議修改 |
| 15 | 主管 | 主管承諾簽署 | 電子簽核 |
### 5.3 追蹤機制
| 檢視週期 | 頻率 | 內容 | 動作 |
|----------|------|------|------|
| **月檢視** | 每月 | 進度更新 | 記錄實際進展 |
| | | 障礙識別 | 標記需要協助項目 |
| | | 簽名確認 | 雙方確認紀錄 |
| **季回顧** | 每季 | 進度評估 | 檢視目標達成率 |
| | | 計畫調整 | 必要時修改目標/行動 |
| | | 資源調整 | 增減支援資源 |
| **年評估** | 年度 | 成效驗收 | 依成果證據判定 |
| | | 經驗總結 | 記錄學習心得 |
| | | 回饋循環 | 產出下週期輸入 |
---
## 六、審批流程
### 6.1 單層審批機制
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 單層審批流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 適用對象:角色卡、能力卡、績效卡、成長卡 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 員工 │────────▶│ 直屬主管│────────▶│ 生效 │ │
│ │ 填寫 │ 送審 │ 審批 │ 核准 │ 歸檔 │ │
│ └─────────┘ └────┬────┘ └─────────┘ │
│ │ │
│ │ 退回 │
│ ▼ │
│ ┌─────────┐ │
│ │ 員工 │ │
│ │修改重送 │ │
│ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 6.2 審批狀態說明
| 狀態 | 說明 | 可操作者 |
|------|------|----------|
| **草稿** | 員工編輯中,尚未送審 | 員工 |
| **待審批** | 已送審,等待主管處理 | 主管 |
| **已核准** | 主管核准,卡片生效 | - |
| **已退回** | 主管退回,需員工修改 | 員工 |
| **已歸檔** | 週期結束,保存快照 | - |
### 6.3 審批通知機制
| 事件 | 通知對象 | 通知方式 |
|------|----------|----------|
| 員工送審 | 直屬主管 | 系統通知 + Email |
| 主管核准 | 員工 | 系統通知 |
| 主管退回 | 員工 | 系統通知 + 退回原因 |
| 逾期未審 | 直屬主管 | 系統提醒 |
---
## 七、版本管理
### 7.1 週期保留快照策略
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 版本快照策略 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 保留時機 保留內容 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 季度評核完成 ──────▶ 該季績效卡完整內容 │ │
│ │ │ │
│ │ 年度評核完成 ──────▶ 年度績效卡 + 成長卡 │ │
│ │ │ │
│ │ 角色卡變更 ──────▶ 變更前版本(供比對) │ │
│ │ │ │
│ │ 能力卡變更 ──────▶ 變更前版本(供比對) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ 快照命名規則 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 績效卡:{員工ID}_{年度}_{週期}_績效卡_{版本號} │ │
│ │ 範例EMP001_2024_Q1_績效卡_v1 │ │
│ │ │ │
│ │ 成長卡:{員工ID}_{年度}_成長卡_{版本號} │ │
│ │ 範例EMP001_2024_成長卡_v1 │ │
│ │ │ │
│ │ 角色卡:{角色ID}_{日期}_角色卡_{版本號} │ │
│ │ 範例ROLE_PM_20241201_角色卡_v3 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 7.2 快照存取權限
| 角色 | 可存取範圍 |
|------|------------|
| 員工 | 自己的所有歷史快照 |
| 主管 | 直屬部屬的所有歷史快照 |
| HR | 全公司所有歷史快照 |
| 管理員 | 全公司所有歷史快照 + 系統設定 |
---
## 八、資料連動規則
### 8.1 單向連動邏輯
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 單向連動規則 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 角色卡 ──────▶ 能力卡 │
│ ├── 部門/職級/角色名稱 ──▶ 基本資訊(自動帶入) │
│ ├── 職責清單 ──▶ 建議選用職能(參考) │
│ └── KRA/KPI ──▶ 績效卡評核項目 │
│ │
│ 能力卡 ──────▶ 績效卡 │
│ ├── 軟性能力項目 ──▶ 行為評估項目(自動帶入) │
│ ├── 要求等級 ──▶ 評估基準(參考) │
│ └── 硬性能力 ──▶ 專業技能評估(可選) │
│ │
│ 績效卡 ──────▶ 成長卡 │
│ ├── 高分項目 ──▶ 優勢項(自動帶入) │
│ ├── 低分項目 ──▶ 待發展領域(自動帶入) │
│ ├── 主管建議 ──▶ 發展參考(參考) │
│ └── 績效等級 ──▶ 發展優先順序(參考) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 8.2 連動觸發時機
| 來源 | 目標 | 觸發時機 | 連動方式 |
|------|------|----------|----------|
| 角色卡 | 能力卡 | 角色卡生效時 | 自動帶入基本資訊 |
| 角色卡 | 績效卡 | 開啟評核週期時 | 自動帶入 KRA 清單 |
| 能力卡 | 績效卡 | 開啟評核週期時 | 自動帶入職能項目 |
| 績效卡 | 成長卡 | 年度評核完成時 | 自動帶入優勢/待發展 |
---
## 九、例外處理
### 9.1 常見例外情境
| 情境 | 處理方式 |
|------|----------|
| 員工中途離職 | 結算至離職日,績效卡標記「提前結束」 |
| 員工中途轉調 | 原部門評核至轉調日,新部門接續評核 |
| 主管職位異動 | 原主管完成已送審項目,新主管接手後續 |
| 評核週期逾期 | 系統自動提醒HR 可延長期限 |
| 角色卡重大變更 | 需重新評估能力卡,影響進行中評核 |
### 9.2 系統錯誤處理
| 錯誤類型 | 處理方式 |
|----------|----------|
| 資料連動失敗 | 記錄錯誤日誌,通知管理員 |
| 審批流程中斷 | 保留當前狀態,可手動繼續 |
| 快照建立失敗 | 重試機制,失敗通知管理員 |
---
**文件結束**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff