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:
12
.claude/settings.local.json
Normal file
12
.claude/settings.local.json
Normal 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
73
.gitignore
vendored
Normal 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/
|
||||
692
HR績效評核系統_功能規格書_v1.1.md
Normal file
692
HR績效評核系統_功能規格書_v1.1.md
Normal 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
257
components/ErrorModal.css
Normal 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
127
components/ErrorModal.jsx
Normal 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;
|
||||
404
components/LLMConnectionTest.css
Normal file
404
components/LLMConnectionTest.css
Normal 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;
|
||||
}
|
||||
}
|
||||
228
components/LLMConnectionTest.jsx
Normal file
228
components/LLMConnectionTest.jsx
Normal 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
77
config/llm.config.js
Normal 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
256
database/README.md
Normal 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
581
database/schema.sql
Normal 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
242
database/seed_data.sql
Normal 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
171
routes/llm.routes.js
Normal 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
364
services/llm.service.js
Normal 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
211
utils/errorHandler.js
Normal 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
733
使用說明.md
Normal 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 Me,AI 會填寫新的空白欄位 |
|
||||
|
||||
### 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:如何修改已送出的卡片?
|
||||
|
||||
- **待審批中**:請聯繫主管退回後修改
|
||||
- **已核准**:需重新發起變更申請,經主管審批
|
||||
|
||||
### Q3:KRA 權重加總不到 100% 怎麼辦?
|
||||
|
||||
系統會自動檢查,權重總和必須等於 100% 才能送出。請調整各項權重分配。
|
||||
|
||||
### Q4:季度評核與年度評核有什麼不同?
|
||||
|
||||
| 項目 | 季度評核 | 年度評核 |
|
||||
|------|----------|----------|
|
||||
| 頻率 | Q1/Q2/Q3 各一次 | 年度一次 |
|
||||
| 內容 | 僅目標進度追蹤 | 目標成果 + 行為能力 |
|
||||
| 佔比 | 無 | 目標 70% + 行為 30% |
|
||||
| 產出 | 快照歸檔 | 績效等級 + 成長卡 |
|
||||
|
||||
### Q5:如何查看歷史績效紀錄?
|
||||
|
||||
點擊側邊欄「歷史快照」,可查看過去各週期的績效卡與成長卡。
|
||||
|
||||
### Q6:主管沒有審批怎麼辦?
|
||||
|
||||
1. 先透過系統發送提醒
|
||||
2. 若持續未處理,聯繫 HR 協助
|
||||
|
||||
### Q7:績效等級是強制分佈嗎?
|
||||
|
||||
不是。系統顯示的是「建議分佈」,僅供主管參考,不強制執行。最終等級由主管依實際績效判定。
|
||||
|
||||
### Q8:成長卡的 IDP 目標建議設幾個?
|
||||
|
||||
建議 **3-4 個**,避免目標過多導致資源分散、無法專注落實。
|
||||
|
||||
### Q9:如何切換語言?
|
||||
|
||||
點擊頂部導航列的「繁中 | EN」按鈕即可切換。目前支援繁體中文與英文。
|
||||
|
||||
### Q10:手機可以使用嗎?
|
||||
|
||||
可以。系統採用響應式設計,支援手機、平板、電腦等各種裝置。
|
||||
|
||||
### Q11:Help Me AI 按鈕在哪裡?
|
||||
|
||||
在每個可填寫卡片的頁面右上角,您會看到一個紫色漸層的「✨ Help Me」按鈕。
|
||||
|
||||
### Q12:Help Me AI 會修改我已經填寫的內容嗎?
|
||||
|
||||
不會。AI 只會填寫**空白欄位**,已經有內容的欄位不會被修改。您的原始輸入會完整保留。
|
||||
|
||||
### Q13:Help Me AI 生成的內容可以直接使用嗎?
|
||||
|
||||
建議您務必檢視 AI 生成的內容,並根據實際情況調整。AI 可能使用示意數據或通用描述,請替換為您的實際資料。
|
||||
|
||||
### Q14:可以多次使用 Help Me AI 嗎?
|
||||
|
||||
可以。每次點擊都會檢查當前空白欄位並填寫。如果您清空某個欄位後再點擊,AI 會重新生成該欄位的內容。
|
||||
|
||||
### Q15:Help Me AI 如何知道該填什麼內容?
|
||||
|
||||
AI 會參考:
|
||||
- 您已填寫的欄位內容
|
||||
- 卡片類型與結構
|
||||
- 職能字典定義
|
||||
- 角色卡的 KRA/KPI 設定
|
||||
|
||||
---
|
||||
|
||||
## 十一、聯絡與支援
|
||||
|
||||
| 問題類型 | 聯絡方式 |
|
||||
|----------|----------|
|
||||
| 系統操作問題 | HR 部門 |
|
||||
| 技術問題 | IT 服務台 |
|
||||
| 績效評核相關 | 直屬主管 / HR BP |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
|
||||
如有任何問題,歡迎隨時聯繫 HR 部門!
|
||||
618
流程設計.md
Normal file
618
流程設計.md
Normal 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 1:IDP 規劃 │ │
|
||||
│ │ │ │
|
||||
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
||||
│ │ │績效卡產出│───▶│識別發展 │───▶│設定 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 系統錯誤處理
|
||||
|
||||
| 錯誤類型 | 處理方式 |
|
||||
|----------|----------|
|
||||
| 資料連動失敗 | 記錄錯誤日誌,通知管理員 |
|
||||
| 審批流程中斷 | 保留當前狀態,可手動繼續 |
|
||||
| 快照建立失敗 | 重試機制,失敗通知管理員 |
|
||||
|
||||
---
|
||||
|
||||
**文件結束**
|
||||
1771
績效管理系統_UI預覽_v1.1.html
Normal file
1771
績效管理系統_UI預覽_v1.1.html
Normal file
File diff suppressed because it is too large
Load Diff
1362
績效管理系統_UI預覽_v1.2_AI輔助.html
Normal file
1362
績效管理系統_UI預覽_v1.2_AI輔助.html
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user