From 8069f1b6289ac26294134613dca84a34c6dc43e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DonaldFang=20=E6=96=B9=E5=A3=AB=E7=A2=A9?= Date: Sat, 6 Dec 2025 01:19:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=A6=E4=BD=9C=E4=B8=89=E5=80=8B?= =?UTF-8?q?=E9=8C=A6=E5=9B=8A=20AI=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AI 錦囊 CSS 樣式到 components.css - 創建 js/ai-bags.js 模組,包含: * 5個模組各3個錦囊的預設 prompt 模板 * executeAIBag() - 執行 AI 生成並填充表單 * editBagPrompt() - 編輯自定義 prompt * LocalStorage 管理自定義 prompt - 更新 index.html: * 替換 5 處 AI 按鈕為三個錦囊(崗位基礎、招聘要求、職務、部門職責、崗位描述) * 新增 Prompt 編輯模態框 - 更新 main.js 引入 ai-bags.js 並初始化 - 新增設計文檔:三個錦囊設計.md - 新增欄位對照文檔:表單欄位清單.md、更新欄位名稱.md、ID重命名對照表.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ID重命名對照表.md | 286 +++++++++++++++++++ index.html | 160 +++++++++-- js/ai-bags.js | 628 ++++++++++++++++++++++++++++++++++++++++++ js/main.js | 4 + styles/components.css | 82 +++++- 三個錦囊設計.md | 263 ++++++++++++++++++ 更新欄位名稱.md | 176 ++++++++++++ 表單欄位清單.md | 347 +++++++++++++++++++++++ 8 files changed, 1925 insertions(+), 21 deletions(-) create mode 100644 ID重命名對照表.md create mode 100644 js/ai-bags.js create mode 100644 三個錦囊設計.md create mode 100644 更新欄位名稱.md create mode 100644 表單欄位清單.md diff --git a/ID重命名對照表.md b/ID重命名對照表.md new file mode 100644 index 0000000..e035592 --- /dev/null +++ b/ID重命名對照表.md @@ -0,0 +1,286 @@ +# HTML ID 重命名對照表 + +## 變更概覽 +- **總計需變更:72 個** +- **無需變更:13 個** +- **總欄位數:85 個** + +--- + +## 模組 1: 崗位基礎資料 - 基礎資料頁籤 +**需變更:15 / 15** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `businessUnit` | `pos_businessUnit` | 事業體 (Business Unit) | | +| `division` | `pos_division` | 處級單位 (Division) | | +| `department` | `pos_department` | 部級單位 (Department) | | +| `section` | `pos_section` | 課級單位 (Section) | | +| `positionCode` | `pos_code` | 崗位編號 | 必填欄位 | +| `effectiveDate` | `pos_effectiveDate` | 生效日期 | | +| `positionName` | `pos_name` | 崗位名稱 | 必填欄位 | +| `positionLevel` | `pos_level` | 崗位級別 | | +| `positionCategory` | `pos_category` | 崗位類別 | onchange 事件 | +| `positionCategoryName` | `pos_categoryName` | 崗位類別名稱 | readonly | +| `positionNature` | `pos_type` | 崗位性質 | onchange 事件,注意:資料庫改為 positionType | +| `positionNatureName` | `pos_typeName` | 崗位性質名稱 | readonly,資料庫改為 positionTypeName | +| `headcount` | `pos_headcount` | 編制人數 | | +| `positionDesc` | `pos_desc` | 崗位描述 | 資料庫改為 description | +| `positionRemark` | `pos_remark` | 崗位備注 | 資料庫改為 remark | + +--- + +## 模組 2: 崗位基礎資料 - 招聘要求頁籤 +**需變更:18 / 18** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `minEducation` | `rec_eduLevel` | 最低學歷 | 資料庫改為 educationLevel | +| `requiredGender` | `rec_gender` | 要求性別 | | +| `salaryRange` | `rec_salaryRange` | 薪酬范圍 | | +| `workExperience` | `rec_expYears` | 工作經驗 | 資料庫改為 experienceYears | +| `minAge` | `rec_minAge` | 最小年齡 | | +| `maxAge` | `rec_maxAge` | 最大年齡 | | +| `jobType` | `rec_jobType` | 工作性質 | | +| `recruitPosition` | `rec_position` | 招聘職位 | 資料庫改為 recruitPosition | +| `jobTitle` | `rec_jobTitle` | 職位名稱(對外) | | +| `superiorPosition` | `rec_superiorCode` | 上級崗位編號 | 資料庫改為 superiorPositionCode | +| `jobDesc` | `rec_jobDesc` | 職位描述(JD) | 資料庫改為 recruitJobDesc | +| `positionReq` | `rec_positionReq` | 崗位要求(Req) | 資料庫改為 recruitRequirements | +| `titleReq` | `rec_certReq` | 職稱要求 | 語義更正為「證照要求」,資料庫改為 certRequirements | +| `majorReq` | `rec_majorReq` | 專業要求 | 資料庫改為 majorRequirements | +| `skillReq` | `rec_skillReq` | 技能要求 | 資料庫改為 skillRequirements | +| `langReq` | `rec_langReq` | 語言要求 | 資料庫改為 langRequirements | +| `otherReq` | `rec_otherReq` | 其他要求 | 資料庫改為 otherRequirements | +| `recruitRemark` | `rec_remark` | 招聘備注 | 資料庫改為 recruitRemark | + +--- + +## 模組 3: 職務基礎資料 +**需變更:12 / 12** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jobCategoryCode` | `job_category` | 職務類別編號 | 必填欄位,onchange 事件 | +| `jobCategoryName` | `job_categoryName` | 職務類別名稱 | readonly | +| `jobCode` | `job_code` | 職務編號 | 必填欄位 | +| `jobName` | `job_name` | 職務名稱 | 必填欄位 | +| `jobNameEn` | `job_nameEn` | 職務英文 | | +| `jobEffectiveDate` | `job_effectiveDate` | 生效日期 | 資料庫改為 effectiveDate | +| `jobLevel` | `job_level` | 職務層級 | 敏感欄位 | +| `jobHeadcount` | `job_headcount` | 編制人數 | 資料庫改為 headcount | +| `jobSortOrder` | `job_sortOrder` | 排列順序 | 資料庫改為 sortOrder | +| `hasAttendanceBonus` | `job_hasAttBonus` | 全勤獎金 | Toggle Switch | +| `hasHousingAllowance` | `job_hasHouseAllow` | 住房補貼 | Toggle Switch | +| `jobRemark` | `job_remark` | 職務備注 | 資料庫改為 remark | + +--- + +## 模組 4: 部門職責 +**需變更:19 / 19** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `deptFunctionCode` | `df_code` | 部門職責編號 | 必填欄位,資料庫改為 dfCode | +| `deptFunctionName` | `df_name` | 部門職責名稱 | 必填欄位,資料庫改為 dfName | +| `deptFunctionBU` | `df_businessUnit` | 事業體 (第1個) | 必填欄位,已合併重複欄位 | +| `deptFunc_businessUnit` | `df_businessUnit` | 事業體 (第2個) | **合併為同一欄位** | +| `deptFunc_division` | `df_division` | 處級單位 | 必填欄位 | +| `deptFunc_department` | `df_department` | 部級單位 | 必填欄位 | +| `deptFunc_section` | `df_section` | 課級單位 | | +| `deptFunc_positionTitle` | `df_posTitle` | 崗位名稱 | 必填欄位,資料庫改為 positionTitle | +| `deptFunc_positionLevel` | `df_posLevel` | 崗位級別 | 資料庫保持 positionLevel | +| `deptManager` | `df_managerTitle` | 部門主管職稱 | 資料庫改為 managerTitle | +| `deptFunctionEffectiveDate` | `df_effectiveDate` | 生效日期 | 必填欄位,資料庫改為 effectiveDate | +| `deptHeadcount` | `df_headcountLimit` | 部門人數上限 | 資料庫改為 headcountLimit | +| `deptStatus` | `df_status` | 部門狀態 | 資料庫改為 status | +| `deptMission` | `df_mission` | 部門使命 | 資料庫改為 mission | +| `deptVision` | `df_vision` | 部門願景 | 資料庫改為 vision | +| `deptCoreFunctions` | `df_coreFunc` | 核心職責 | 必填欄位,資料庫改為 coreFunctions | +| `deptKPIs` | `df_kpis` | 關鍵績效指標 | 資料庫改為 kpis | +| `deptCollaboration` | `df_collab` | 協作部門 | 資料庫改為 collaboration | +| `deptFunctionRemark` | `df_remark` | 備注 | 資料庫改為 remark | + +**特別注意:** 原本有兩個事業體欄位 (`deptFunctionBU` 和 `deptFunc_businessUnit`),新規範已合併為單一欄位 `df_businessUnit`。 + +--- + +## 模組 5: 崗位描述 - 基本信息 +**需變更:3 / 4** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jd_empNo` | `jd_empNo` | 工號 | ✓ 無需變更 | +| `jd_empName` | `jd_empName` | 姓名 | ✓ 無需變更 | +| `jd_positionCode` | `jd_posCode` | 崗位代碼 | | +| `jd_versionDate` | `jd_versionDate` | 版本更新日期 | ✓ 無需變更 | + +--- + +## 模組 6: 崗位描述 - 崗位基本信息 +**需變更:10 / 14** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jd_positionName` | `jd_posName` | 崗位名稱 | | +| `jd_businessUnit` | `jd_businessUnit` | 事業體 | ✓ 無需變更 | +| `jd_division` | `jd_division` | 處級單位 | ✓ 無需變更 | +| `jd_department` | `jd_department` | 部級單位 | ✓ 無需變更 | +| `jd_section` | `jd_section` | 課級單位 | ✓ 無需變更 | +| `jd_positionTitle` | `(刪除)` | 崗位名稱 (重複) | 與 positionName 重複,建議刪除 | +| `jd_positionLevel` | `jd_posLevel` | 崗位級別 | | +| `jd_positionEffectiveDate` | `jd_posEffDate` | 崗位生效日期 | | +| `jd_directSupervisor` | `jd_supervisor` | 直接領導職務 | | +| `jd_positionGradeJob` | `jd_gradeJob` | 崗位職等&職務 | Modal 選擇器 | +| `jd_reportTo` | `jd_reportTo` | 匯報對象職務 | ✓ 無需變更 | +| `jd_directReports` | `jd_directReports` | 直接下級 | ✓ 無需變更 | +| `jd_workLocation` | `jd_location` | 任職地點 | | +| `jd_empAttribute` | `jd_empAttr` | 員工屬性 | | + +--- + +## 模組 7: 崗位描述 - 部門職責資訊 +**需變更:3 / 5** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jd_deptFunctionCode` | `jd_dfCode` | 部門職責編號 | readonly | +| `jd_deptFunctionBU` | `(保留)` | 事業體 | 建議保留或改為 jd_dfBU | +| `jd_deptMission` | `jd_deptMission` | 部門使命 | ✓ 無需變更 | +| `jd_deptCoreFunctions` | `jd_deptCoreFunctions` | 部門核心職責 | ✓ 無需變更 | +| `jd_deptKPIs` | `jd_deptKPIs` | 部門 KPIs | ✓ 無需變更 | + +**說明:** 這些是 readonly 欄位,自動帶入,可保持現有命名以維持與來源資料的一致性。 + +--- + +## 模組 8: 崗位描述 - 職責描述 +**需變更:1 / 2** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jd_positionPurpose` | `jd_purpose` | 崗位設置目的 | | +| `jd_mainResponsibilities` | `jd_mainResp` | 主要崗位職責 | Numbered textarea | + +--- + +## 模組 9: 崗位描述 - 崗位要求 +**需變更:5 / 5** + +| 舊 ID | 新 ID | 欄位名稱 | 備註 | +|-------|-------|---------|------| +| `jd_education` | `jd_eduLevel` | 教育程度 | | +| `jd_basicSkills` | `jd_basicSkills` | 基本技能 | ✓ 無需變更 | +| `jd_professionalKnowledge` | `jd_proKnowledge` | 專業知識 | | +| `jd_workExperienceReq` | `jd_expReq` | 工作經驗 | | +| `jd_otherRequirements` | `jd_otherReq` | 其他 | | + +--- + +## 重要變更說明 + +### 1. 前綴標準化 +所有欄位統一採用模組前綴: +- `pos_` - 崗位基礎資料 +- `rec_` - 招聘要求 +- `job_` - 職務基礎資料 +- `df_` - 部門職責 +- `jd_` - 崗位描述 + +### 2. 命名簡化 +- `positionCode` → `pos_code` +- `positionName` → `pos_name` +- `positionCategory` → `pos_category` +- `positionNature` → `pos_type` (語義更精確) +- `hasAttendanceBonus` → `job_hasAttBonus` (縮寫簡化) + +### 3. 語義改善 +- `titleReq` → `rec_certReq` (職稱要求 → 證照要求) +- `positionNature` → `pos_type` (性質 → 類型,更符合英文語義) +- `workExperience` → `rec_expYears` (經驗年數更明確) + +### 4. 資料庫欄位同步變更 +部分 HTML ID 變更時,資料庫欄位名稱也需要對應修改: +- `positionNature` → `positionType` +- `positionDesc` → `description` +- `positionRemark` → `remark` +- `minEducation` → `educationLevel` + +### 5. 重複欄位合併 +部門職責模組中的兩個事業體欄位: +- 原:`deptFunctionBU` 和 `deptFunc_businessUnit` +- 新:統一為 `df_businessUnit` + +--- + +## 實施建議 + +### 階段 1: 資料庫遷移 +1. 執行資料庫欄位重命名 SQL 腳本 +2. 更新所有 ORM Model 定義 +3. 更新 API 回應的欄位名稱 + +### 階段 2: 前端更新 +1. 全局搜尋替換 HTML ID +2. 更新所有 JavaScript 選擇器 +3. 更新 CSS 樣式選擇器 +4. 更新表單驗證邏輯 + +### 階段 3: 測試驗證 +1. 單元測試:驗證所有表單欄位綁定 +2. 整合測試:驗證資料儲存與讀取 +3. E2E 測試:完整流程測試 +4. 回歸測試:確保無遺漏欄位 + +### 階段 4: 文檔更新 +1. API 文檔更新 +2. 資料字典更新 +3. 開發指南更新 +4. 使用者手冊更新(如有影響) + +--- + +## 風險評估 + +### 高風險變更 (必填欄位) +- `positionCode` → `pos_code` +- `positionName` → `pos_name` +- `jobCode` → `job_code` +- `jobName` → `job_name` +- `deptFunctionCode` → `df_code` + +**建議:** 優先測試這些欄位的儲存與驗證邏輯。 + +### 中風險變更 (聯動欄位) +- 組織結構欄位:`businessUnit`, `division`, `department`, `section` +- 自動帶出欄位:`positionCategoryName`, `positionNatureName` + +**建議:** 仔細測試聯動邏輯和 onchange 事件。 + +### 低風險變更 (選填欄位) +- 備注類欄位 +- 描述類欄位 + +--- + +## 檢查清單 + +- [ ] 資料庫遷移腳本已準備 +- [ ] Model 定義已更新 +- [ ] HTML 表單 ID 已更新 +- [ ] JavaScript 選擇器已更新 +- [ ] CSS 樣式已更新 +- [ ] API 端點已更新 +- [ ] 驗證邏輯已更新 +- [ ] 單元測試已通過 +- [ ] 整合測試已通過 +- [ ] E2E 測試已通過 +- [ ] 文檔已更新 +- [ ] 程式碼審查已完成 + +--- + +**文檔版本:** v1.0 +**建立日期:** 2025-12-06 +**最後更新:** 2025-12-06 +**維護者:** 系統開發團隊 diff --git a/index.html b/index.html index bd6a826..26c27de 100644 --- a/index.html +++ b/index.html @@ -98,10 +98,27 @@
- + +
+
+
🎁
+
錦囊一
+
簡化版
+ +
+
+
🎁
+
錦囊二
+
標準版
+ +
+
+
🎁
+
錦囊三
+
詳細版
+ +
+
@@ -212,10 +229,27 @@
- + +
+
+
🎁
+
錦囊一
+
基本需求
+ +
+
+
🎁
+
錦囊二
+
標準需求
+ +
+
+
🎁
+
錦囊三
+
完整需求
+ +
+
@@ -402,10 +436,27 @@
- + +
+
+
🎁
+
錦囊一
+
簡化版
+ +
+
+
🎁
+
錦囊二
+
標準版
+ +
+
+
🎁
+
錦囊三
+
完整版
+ +
+
@@ -546,10 +597,27 @@
- + +
+
+
🎁
+
錦囊一
+
基本版
+ +
+
+
🎁
+
錦囊二
+
標準版
+ +
+
+
🎁
+
錦囊三
+
完整版
+ +
+
@@ -732,10 +800,27 @@
- + +
+
+
🎁
+
錦囊一
+
基本版
+ +
+
+
🎁
+
錦囊二
+
標準版
+ +
+
+
🎁
+
錦囊三
+
完整版
+ +
+
@@ -4024,5 +4109,40 @@ ${contextInfo} + + + + diff --git a/js/ai-bags.js b/js/ai-bags.js new file mode 100644 index 0000000..b904104 --- /dev/null +++ b/js/ai-bags.js @@ -0,0 +1,628 @@ +/** + * AI Bags - 三個錦囊功能 + * 提供可自定義 prompt 的 AI 生成按鈕 + */ + +import { callClaudeAPI } from './api.js'; +import { showToast, fillIfEmpty } from './utils.js'; +import { getPositionFormData, getJobFormData, getJobDescFormData, getDeptFunctionFormData } from './ui.js'; + +// ==================== 預設 Prompt 模板 ==================== + +const DEFAULT_PROMPTS = { + positionBasic: { + bag1: { + title: '簡化版', + subtitle: '僅必填欄位', + prompt: `你是專業人資顧問,熟悉半導體製造業。請生成崗位基礎資料(僅必填欄位)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag2: { + title: '標準版', + subtitle: '常用欄位', + prompt: `你是專業人資顧問,熟悉半導體製造業。請生成崗位基礎資料(標準版)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName, positionCategory, positionLevel, headcount + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001) +- positionName: 崗位名稱 +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +- positionLevel: 崗位級別(L1-L7) +- headcount: 編制人數(1-10) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag3: { + title: '詳細版', + subtitle: '所有欄位', + prompt: `你是專業人資顧問,熟悉半導體製造業的人資所有流程。請生成完整的崗位基礎資料。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName, positionCategory, positionNature, headcount, positionLevel, positionDesc, positionRemark + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001, MGR-002) +- positionName: 崗位名稱 +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +- positionNature: 崗位性質代碼(FT=全職, PT=兼職, CT=約聘, IN=實習) +- headcount: 編制人數(1-10之間的數字字串) +- positionLevel: 崗位級別(L1到L7) +- positionDesc: 崗位描述(條列式,用換行分隔) +- positionRemark: 崗位備注(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + } + }, + positionRecruit: { + bag1: { + title: '基本需求', + subtitle: '核心要求', + prompt: `請生成「{positionName}」的基本招聘要求。 + +已填寫的資料:{existingData} +需要生成的欄位:minEducation, workExperience, jobType, jobTitle + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag2: { + title: '標準需求', + subtitle: '完整資訊', + prompt: `請生成「{positionName}」的標準招聘要求。 + +已填寫的資料:{existingData} +需要生成的欄位:minEducation, salaryRange, workExperience, jobType, recruitPosition, jobTitle, positionReq, skillReq + +欄位說明: +- minEducation: 最低學歷代碼(HS=高中職, JC=專科, BA=大學, MA=碩士, PHD=博士) +- salaryRange: 薪酬范圍代碼(A=30000以下, B=30000-50000, C=50000-80000, D=80000-120000, E=120000以上, N=面議) +- workExperience: 工作經驗年數(0=不限, 1, 3, 5, 10) +- jobType: 工作性質代碼(FT=全職, PT=兼職, CT=約聘, DP=派遣) +- recruitPosition: 招聘職位代碼(ENG=工程師, MGR=經理, AST=助理, OP=作業員, SAL=業務) +- positionReq: 崗位要求(條列式,用換行分隔) +- skillReq: 技能要求(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag3: { + title: '完整需求', + subtitle: '18個欄位', + prompt: `請生成「{positionName}」的完整招聘要求資料。 + +已填寫的資料:{existingData} +需要生成所有空白欄位。 + +欄位說明: +- minEducation: 最低學歷代碼(HS=高中職, JC=專科, BA=大學, MA=碩士, PHD=博士) +- requiredGender: 性別要求代碼(M=限男性, F=限女性, N=不限) +- salaryRange: 薪酬范圍代碼(A=30000以下, B=30000-50000, C=50000-80000, D=80000-120000, E=120000以上, N=面議) +- workExperience: 工作經驗年數(0=不限, 1, 3, 5, 10) +- minAge: 最低年齡(18-65) +- maxAge: 最高年齡(18-65) +- jobType: 工作性質代碼(FT=全職, PT=兼職, CT=約聘, DP=派遣) +- recruitPosition: 招聘職位代碼(ENG=工程師, MGR=經理, AST=助理, OP=作業員, SAL=業務) +- jobTitle: 職位名稱 +- jobDesc: 工作內容(條列式,用換行分隔) +- positionReq: 崗位要求(條列式,用換行分隔) +- titleReq: 職稱要求(條列式,用換行分隔) +- majorReq: 科系要求(多個科系用逗號分隔) +- skillReq: 技能要求(條列式,用換行分隔) +- langReq: 語言要求(條列式,用換行分隔) +- otherReq: 其他要求(條列式,用換行分隔) +- superiorPosition: 直屬主管職位 +- recruitRemark: 招聘備注 + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + } + }, + jobBasic: { + bag1: { + title: '簡化版', + subtitle: '核心欄位', + prompt: `請生成職務基礎資料(簡化版)。 + +已填寫的資料:{existingData} +需要生成的欄位:jobCode, jobName, jobCategoryCode + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag2: { + title: '標準版', + subtitle: '常用欄位', + prompt: `請生成職務基礎資料(標準版)。 + +已填寫的資料:{existingData} +需要生成的欄位:jobCode, jobName, jobNameEn, jobCategoryCode, jobLevel, jobHeadcount + +欄位說明: +- jobCode: 職務編號(格式如 J001) +- jobName: 職務名稱(繁體中文) +- jobNameEn: 職務名稱英文 +- jobCategoryCode: 職務類別代碼(01=技術類, 02=管理類, 03=業務類, 04=行政類) +- jobLevel: 職務級別(J1-J7) +- jobHeadcount: 職務人數(1-100) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag3: { + title: '完整版', + subtitle: '所有欄位', + prompt: `請生成完整的職務基礎資料。 + +已填寫的資料:{existingData} +需要生成所有空白欄位。 + +欄位說明: +- jobCode: 職務編號(格式如 J001) +- jobName: 職務名稱(繁體中文) +- jobNameEn: 職務名稱英文 +- jobCategoryCode: 職務類別代碼(01=技術類, 02=管理類, 03=業務類, 04=行政類) +- jobLevel: 職務級別(J1-J7) +- jobHeadcount: 職務人數(1-100) +- jobEffectiveDate: 生效日期(YYYY-MM-DD) +- jobSortOrder: 排序順序(1-999) +- hasAttendanceBonus: 是否有全勤獎金(true/false) +- hasHousingAllowance: 是否有住宿津貼(true/false) +- jobRemark: 職務備註 + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + } + }, + deptFunction: { + bag1: { + title: '基本版', + subtitle: '核心資訊', + prompt: `請生成部門職責資料(基本版)。 + +已填寫的資料:{existingData} +需要生成的欄位:deptFunctionCode, deptFunctionName, deptFunctionBU, deptFunctionDept + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag2: { + title: '標準版', + subtitle: '含職責描述', + prompt: `請生成部門職責資料(標準版)。 + +已填寫的資料:{existingData} +需要生成的欄位:deptFunctionCode, deptFunctionName, deptFunctionBU, deptFunctionDept, deptManager, deptMission, deptCoreFunctions + +欄位說明: +- deptFunctionCode: 部門職責編號(格式如 DF001) +- deptFunctionName: 部門職責名稱 +- deptFunctionBU: 事業單位代碼(BU1-BU5) +- deptFunctionDept: 部門代碼(DEPT1-DEPT20) +- deptManager: 部門主管 +- deptMission: 部門使命(簡短描述) +- deptCoreFunctions: 核心職能(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag3: { + title: '完整版', + subtitle: '含KPI指標', + prompt: `請生成完整的部門職責資料。 + +已填寫的資料:{existingData} +需要生成所有空白欄位。 + +欄位說明: +- deptFunctionCode: 部門職責編號(格式如 DF001) +- deptFunctionName: 部門職責名稱 +- deptFunctionBU: 事業單位代碼(BU1-BU5) +- deptFunctionDept: 部門代碼(DEPT1-DEPT20) +- deptManager: 部門主管 +- deptMission: 部門使命(簡短描述) +- deptVision: 部門願景(條列式,用換行分隔) +- deptCoreFunctions: 核心職能(條列式,用換行分隔) +- deptKPIs: KPI 指標(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + } + }, + jobDesc: { + bag1: { + title: '基本版', + subtitle: '核心資訊', + prompt: `請生成崗位描述資料(基本版)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionName, department, positionPurpose + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag2: { + title: '標準版', + subtitle: '含職責說明', + prompt: `請生成崗位描述資料(標準版)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionName, department, directSupervisor, positionPurpose, mainResponsibilities, education, basicSkills + +欄位說明: +- positionName: 崗位名稱 +- department: 所屬部門 +- directSupervisor: 直屬主管 +- positionPurpose: 崗位目的(簡短描述) +- mainResponsibilities: 主要職責(條列式,用換行分隔) +- education: 學歷要求 +- basicSkills: 基本技能(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + }, + bag3: { + title: '完整版', + subtitle: '33個欄位', + prompt: `請生成完整的崗位描述資料。 + +已填寫的資料:{existingData} +需要生成所有空白欄位。 + +包含以下區塊: +1. 基本資訊:empNo, empName, positionCode, versionDate +2. 崗位資訊:positionName, department, positionEffectiveDate, directSupervisor, positionGradeJob, reportTo, directReports, workLocation, empAttribute +3. 職責與目的:positionPurpose, mainResponsibilities +4. 任職要求:education, basicSkills, professionalKnowledge, workExperienceReq, otherRequirements + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。` + } + } +}; + +// ==================== LocalStorage 管理 ==================== + +/** + * 獲取模組的 prompts(優先使用自定義,否則使用預設) + * @param {string} module - 模組名稱 + * @returns {Object} - 包含三個 bag 的 prompt 物件 + */ +function getModulePrompts(module) { + try { + const saved = localStorage.getItem('aiPrompts'); + const prompts = saved ? JSON.parse(saved) : {}; + + // 如果沒有保存的 prompts,使用預設值 + if (!prompts[module]) { + return DEFAULT_PROMPTS[module] || {}; + } + + return prompts[module]; + } catch (e) { + console.error('讀取 prompts 失敗:', e); + return DEFAULT_PROMPTS[module] || {}; + } +} + +/** + * 保存模組的 prompts + * @param {string} module - 模組名稱 + * @param {number} bagNumber - 錦囊編號 (1-3) + * @param {Object} bagData - 包含 title, subtitle, prompt 的物件 + */ +function saveModulePrompt(module, bagNumber, bagData) { + try { + const saved = localStorage.getItem('aiPrompts'); + const prompts = saved ? JSON.parse(saved) : {}; + + if (!prompts[module]) { + prompts[module] = {}; + } + + prompts[module][`bag${bagNumber}`] = bagData; + localStorage.setItem('aiPrompts', JSON.stringify(prompts)); + + return true; + } catch (e) { + console.error('保存 prompt 失敗:', e); + return false; + } +} + +/** + * 初始化所有模組的預設 prompts(如果尚未設定) + */ +function initializeDefaultPrompts() { + const saved = localStorage.getItem('aiPrompts'); + if (!saved) { + localStorage.setItem('aiPrompts', JSON.stringify(DEFAULT_PROMPTS)); + } +} + +// ==================== 執行 AI 錦囊 ==================== + +/** + * 執行 AI 錦囊 + * @param {string} module - 模組名稱 + * @param {number} bagNumber - 錦囊編號 (1-3) + */ +export async function executeAIBag(module, bagNumber) { + const bagElement = document.querySelector(`.ai-bag[data-module="${module}"][data-bag="${bagNumber}"]`); + if (!bagElement) return; + + // 防止重複點擊 + if (bagElement.classList.contains('loading')) return; + + try { + // 顯示載入狀態 + bagElement.classList.add('loading'); + const icon = bagElement.querySelector('.bag-icon'); + const originalIcon = icon.textContent; + icon.innerHTML = '
'; + + // 獲取當前表單資料 + let existingData = {}; + if (module === 'positionBasic' || module === 'positionRecruit') { + const positionData = getPositionFormData(); + existingData = module === 'positionBasic' ? positionData.basicInfo : positionData.recruitInfo; + } else if (module === 'jobBasic') { + existingData = getJobFormData(); + } else if (module === 'jobDesc') { + existingData = getJobDescFormData(); + } else if (module === 'deptFunction') { + existingData = getDeptFunctionFormData(); + } + + // 獲取 prompt 模板 + const prompts = getModulePrompts(module); + const bagPrompt = prompts[`bag${bagNumber}`]; + + if (!bagPrompt || !bagPrompt.prompt) { + throw new Error('Prompt 模板不存在'); + } + + // 替換 prompt 中的變數 + let finalPrompt = bagPrompt.prompt + .replace('{existingData}', JSON.stringify(existingData, null, 2)) + .replace('{positionName}', existingData.positionName || '此崗位'); + + // 調用 AI API + const result = await callClaudeAPI(finalPrompt); + + // 填充表單 + fillFormWithAIResult(module, result); + + showToast('✨ AI 生成成功!'); + } catch (error) { + console.error('AI 錦囊執行失敗:', error); + showToast('❌ AI 生成失敗: ' + error.message); + } finally { + // 恢復正常狀態 + bagElement.classList.remove('loading'); + const icon = bagElement.querySelector('.bag-icon'); + icon.textContent = '🎁'; + } +} + +/** + * 根據 AI 結果填充表單 + * @param {string} module - 模組名稱 + * @param {Object} result - AI 返回的 JSON 結果 + */ +function fillFormWithAIResult(module, result) { + if (module === 'positionBasic') { + // 崗位基礎資料 - 基礎資料頁籤 + Object.entries(result).forEach(([key, value]) => { + fillIfEmpty(key, value); + }); + } else if (module === 'positionRecruit') { + // 崗位基礎資料 - 招聘要求頁籤 + Object.entries(result).forEach(([key, value]) => { + fillIfEmpty(key, value); + }); + } else if (module === 'jobBasic') { + // 職務基礎資料 + Object.entries(result).forEach(([key, value]) => { + if (key === 'hasAttendanceBonus' || key === 'hasHousingAllowance') { + const checkbox = document.getElementById(key); + if (checkbox) checkbox.checked = value; + } else { + fillIfEmpty(key, value); + } + }); + } else if (module === 'deptFunction') { + // 部門職責 + Object.entries(result).forEach(([key, value]) => { + fillIfEmpty('df_' + key, value); + }); + } else if (module === 'jobDesc') { + // 崗位描述 + if (result.basicInfo) { + Object.entries(result.basicInfo).forEach(([key, value]) => { + fillIfEmpty('jd_' + key, value); + }); + } + if (result.positionInfo) { + Object.entries(result.positionInfo).forEach(([key, value]) => { + fillIfEmpty('jd_' + key, value); + }); + } + if (result.responsibilities) { + Object.entries(result.responsibilities).forEach(([key, value]) => { + fillIfEmpty('jd_' + key, value); + }); + } + if (result.requirements) { + Object.entries(result.requirements).forEach(([key, value]) => { + fillIfEmpty('jd_' + key, value); + }); + } + } +} + +// ==================== 編輯 Prompt ==================== + +/** + * 編輯錦囊 Prompt + * @param {Event} event - 點擊事件 + * @param {string} module - 模組名稱 + * @param {number} bagNumber - 錦囊編號 (1-3) + */ +export function editBagPrompt(event, module, bagNumber) { + event.stopPropagation(); // 防止觸發父元素的 click 事件 + + const prompts = getModulePrompts(module); + const bagPrompt = prompts[`bag${bagNumber}`]; + + if (!bagPrompt) { + showToast('❌ Prompt 不存在'); + return; + } + + // 顯示編輯對話框 + showPromptEditModal(module, bagNumber, bagPrompt); +} + +/** + * 顯示 Prompt 編輯對話框 + * @param {string} module - 模組名稱 + * @param {number} bagNumber - 錦囊編號 (1-3) + * @param {Object} bagData - 包含 title, subtitle, prompt 的物件 + */ +function showPromptEditModal(module, bagNumber, bagData) { + const modal = document.getElementById('promptEditModal'); + if (!modal) { + console.error('找不到編輯對話框'); + return; + } + + // 填充對話框內容 + document.getElementById('promptModalTitle').textContent = `編輯錦囊 ${bagNumber} - ${bagData.title}`; + document.getElementById('promptTitle').value = bagData.title || ''; + document.getElementById('promptSubtitle').value = bagData.subtitle || ''; + document.getElementById('promptContent').value = bagData.prompt || ''; + + // 保存當前編輯的模組和錦囊編號 + modal.dataset.module = module; + modal.dataset.bagNumber = bagNumber; + + // 顯示對話框 + modal.classList.add('show'); +} + +/** + * 保存編輯的 Prompt + */ +export function savePromptEdit() { + const modal = document.getElementById('promptEditModal'); + const module = modal.dataset.module; + const bagNumber = parseInt(modal.dataset.bagNumber); + + const title = document.getElementById('promptTitle').value.trim(); + const subtitle = document.getElementById('promptSubtitle').value.trim(); + const prompt = document.getElementById('promptContent').value.trim(); + + if (!title || !prompt) { + showToast('⚠️ 標題和 Prompt 內容不能為空'); + return; + } + + // 保存到 LocalStorage + const success = saveModulePrompt(module, bagNumber, { title, subtitle, prompt }); + + if (success) { + // 更新頁面上的錦囊標題 + const bagElement = document.querySelector(`.ai-bag[data-module="${module}"][data-bag="${bagNumber}"]`); + if (bagElement) { + const titleElement = bagElement.querySelector('.bag-title'); + const subtitleElement = bagElement.querySelector('.bag-subtitle'); + if (titleElement) titleElement.textContent = title; + if (subtitleElement) { + if (subtitle) { + if (!subtitleElement.classList) { + const newSubtitle = document.createElement('div'); + newSubtitle.className = 'bag-subtitle'; + newSubtitle.textContent = subtitle; + bagElement.querySelector('.bag-title').after(newSubtitle); + } else { + subtitleElement.textContent = subtitle; + } + } + } + } + + closePromptEditModal(); + showToast('✅ Prompt 已保存'); + } else { + showToast('❌ 保存失敗'); + } +} + +/** + * 關閉編輯對話框 + */ +export function closePromptEditModal() { + const modal = document.getElementById('promptEditModal'); + if (modal) { + modal.classList.remove('show'); + } +} + +/** + * 重置為預設 Prompt + */ +export function resetToDefaultPrompt() { + const modal = document.getElementById('promptEditModal'); + const module = modal.dataset.module; + const bagNumber = parseInt(modal.dataset.bagNumber); + + const defaultPrompt = DEFAULT_PROMPTS[module]?.[`bag${bagNumber}`]; + + if (!defaultPrompt) { + showToast('❌ 找不到預設 Prompt'); + return; + } + + if (confirm('確定要重置為預設 Prompt 嗎?')) { + document.getElementById('promptTitle').value = defaultPrompt.title || ''; + document.getElementById('promptSubtitle').value = defaultPrompt.subtitle || ''; + document.getElementById('promptContent').value = defaultPrompt.prompt || ''; + + showToast('✅ 已重置為預設值'); + } +} + +// ==================== 初始化 ==================== + +/** + * 初始化錦囊標題 + */ +export function initializeBagTitles() { + document.querySelectorAll('.ai-bag').forEach(bag => { + const module = bag.dataset.module; + const bagNumber = parseInt(bag.dataset.bag); + + const prompts = getModulePrompts(module); + const bagPrompt = prompts[`bag${bagNumber}`]; + + if (bagPrompt) { + const titleElement = bag.querySelector('.bag-title'); + const subtitleElement = bag.querySelector('.bag-subtitle'); + + if (titleElement) titleElement.textContent = bagPrompt.title || `錦囊${bagNumber}`; + if (subtitleElement && bagPrompt.subtitle) { + subtitleElement.textContent = bagPrompt.subtitle; + } + } + }); +} + +// 頁面載入時初始化 +document.addEventListener('DOMContentLoaded', () => { + initializeDefaultPrompts(); + initializeBagTitles(); +}); + +// ==================== 掛載到 window ==================== + +if (typeof window !== 'undefined') { + window.executeAIBag = executeAIBag; + window.editBagPrompt = editBagPrompt; + window.savePromptEdit = savePromptEdit; + window.closePromptEditModal = closePromptEditModal; + window.resetToDefaultPrompt = resetToDefaultPrompt; +} diff --git a/js/main.js b/js/main.js index 5c8a43a..df4b300 100644 --- a/js/main.js +++ b/js/main.js @@ -5,6 +5,7 @@ import { showToast } from './utils.js'; import { switchModule, updatePreview, updateCategoryName, updateNatureName, updateJobCategoryName } from './ui.js'; +import { initializeBagTitles } from './ai-bags.js'; // ==================== 初始化 ==================== @@ -187,6 +188,9 @@ document.addEventListener('DOMContentLoaded', () => { setupFormListeners(); setupKeyboardShortcuts(); + // 初始化 AI 錦囊標題 + initializeBagTitles(); + // 初始化預覽 updatePreview(); diff --git a/styles/components.css b/styles/components.css index 420a109..cd4eddb 100644 --- a/styles/components.css +++ b/styles/components.css @@ -265,7 +265,87 @@ select { fill: currentColor; } -/* ==================== AI Button ==================== */ +/* ==================== AI Bags (Three Fortune Bags) ==================== */ +.ai-bags-container { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16px; + margin-bottom: 24px; +} + +.ai-bag { + position: relative; + padding: 20px; + background: linear-gradient(135deg, #9b59b6 0%, #8e44ad 100%); + border-radius: var(--radius); + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(155, 89, 182, 0.3); + text-align: center; +} + +.ai-bag:hover { + transform: translateY(-4px); + box-shadow: 0 6px 20px rgba(155, 89, 182, 0.5); +} + +.ai-bag:active { + transform: translateY(-2px); +} + +.ai-bag .bag-icon { + font-size: 2rem; + margin-bottom: 8px; +} + +.ai-bag .bag-title { + color: white; + font-weight: 600; + font-size: 0.95rem; + margin-bottom: 4px; +} + +.ai-bag .bag-subtitle { + color: rgba(255, 255, 255, 0.8); + font-size: 0.75rem; + margin-top: 4px; +} + +.ai-bag .bag-edit-btn { + position: absolute; + top: 8px; + right: 8px; + background: rgba(255, 255, 255, 0.2); + border: none; + border-radius: 4px; + padding: 4px 8px; + cursor: pointer; + font-size: 0.9rem; + transition: all 0.2s ease; + line-height: 1; +} + +.ai-bag .bag-edit-btn:hover { + background: rgba(255, 255, 255, 0.3); + transform: scale(1.1); +} + +.ai-bag.loading { + pointer-events: none; + opacity: 0.7; +} + +.ai-bag .spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-top-color: white; + border-radius: 50%; + animation: spin 0.8s linear infinite; + margin: 8px auto; +} + +/* ==================== Old AI Button (Deprecated) ==================== */ .ai-generate-btn { display: flex; align-items: center; diff --git a/三個錦囊設計.md b/三個錦囊設計.md new file mode 100644 index 0000000..1c196ea --- /dev/null +++ b/三個錦囊設計.md @@ -0,0 +1,263 @@ +# 三個錦囊功能設計 + +## 功能概述 +將原本的單一 "I'm feeling lucky" 按鈕改為三個可自定義的 AI 生成按鈕("三個錦囊")。 + +## UI 設計 + +### 視覺效果 +``` +┌─────────────────────────────────────────────────────────┐ +│ 🎁 錦囊一 🎁 錦囊二 🎁 錦囊三 │ +│ [標題] [標題] [標題] │ +│ ⚙️ 編輯 ⚙️ 編輯 ⚙️ 編輯 │ +└─────────────────────────────────────────────────────────┘ +``` + +### 互動流程 +1. **點擊錦囊按鈕** → 使用預設或自定義的 prompt 調用 AI +2. **點擊編輯圖示** → 彈出對話框,顯示並可編輯當前 prompt +3. **Prompt 儲存** → 儲存至 localStorage(按模組區分) + +## 資料結構 + +### LocalStorage 結構 +```javascript +{ + "prompts": { + "positionBasic": { + "bag1": { "title": "簡化版", "prompt": "..." }, + "bag2": { "title": "標準版", "prompt": "..." }, + "bag3": { "title": "詳細版", "prompt": "..." } + }, + "positionRecruit": { + "bag1": { "title": "一般需求", "prompt": "..." }, + "bag2": { "title": "高階需求", "prompt": "..." }, + "bag3": { "title": "專業需求", "prompt": "..." } + }, + "jobBasic": { ... }, + "deptFunction": { ... }, + "jobDesc": { ... } + } +} +``` + +## 預設 Prompt 模板 + +### 崗位基礎資料 - 基礎資料頁籤 + +#### 錦囊一:簡化版(僅填必填欄位) +``` +你是專業人資顧問,熟悉半導體製造業。請生成崗位基礎資料(僅必填欄位)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName + +請用繁體中文,返回 JSON 格式。 +``` + +#### 錦囊二:標準版(常用欄位) +``` +你是專業人資顧問,熟悉半導體製造業。請生成崗位基礎資料(標準版)。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName, positionCategory, positionLevel, headcount + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001) +- positionName: 崗位名稱 +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +- positionLevel: 崗位級別(L1-L7) +- headcount: 編制人數(1-10) + +請用繁體中文,返回 JSON 格式。 +``` + +#### 錦囊三:詳細版(所有欄位) +``` +你是專業人資顧問,熟悉半導體製造業的人資所有流程。請生成完整的崗位基礎資料。 + +已填寫的資料:{existingData} +需要生成的欄位:positionCode, positionName, positionCategory, positionNature, headcount, positionLevel, positionDesc, positionRemark + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001, MGR-002) +- positionName: 崗位名稱 +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +- positionNature: 崗位性質代碼(FT=全職, PT=兼職, CT=約聘, IN=實習) +- headcount: 編制人數(1-10之間的數字字串) +- positionLevel: 崗位級別(L1到L7) +- positionDesc: 崗位描述(條列式,用換行分隔) +- positionRemark: 崗位備注(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式,不要有任何其他文字。 +``` + +### 崗位基礎資料 - 招聘要求頁籤 + +#### 錦囊一:基本需求 +``` +請生成「{positionName}」的基本招聘要求。 + +已填寫的資料:{existingData} +需要生成的欄位:minEducation, workExperience, jobType, jobTitle + +請用繁體中文,返回 JSON 格式。 +``` + +#### 錦囊二:標準需求 +``` +請生成「{positionName}」的標準招聘要求。 + +已填寫的資料:{existingData} +需要生成的欄位:minEducation, salaryRange, workExperience, jobType, recruitPosition, jobTitle, positionReq, skillReq + +欄位說明: +- minEducation: 最低學歷代碼(HS=高中職, JC=專科, BA=大學, MA=碩士, PHD=博士) +- salaryRange: 薪酬范圍代碼(A=30000以下, B=30000-50000, C=50000-80000, D=80000-120000, E=120000以上, N=面議) +- workExperience: 工作經驗年數(0=不限, 1, 3, 5, 10) +- jobType: 工作性質代碼(FT=全職, PT=兼職, CT=約聘, DP=派遣) +- recruitPosition: 招聘職位代碼(ENG=工程師, MGR=經理, AST=助理, OP=作業員, SAL=業務) +- positionReq: 崗位要求(條列式,用換行分隔) +- skillReq: 技能要求(條列式,用換行分隔) + +請用繁體中文,返回 JSON 格式。 +``` + +#### 錦囊三:完整需求 +``` +請生成「{positionName}」的完整招聘要求資料。 + +已填寫的資料:{existingData} +需要生成所有空白欄位。 + +(完整欄位說明同標準版,包含所有 18 個欄位) + +請用繁體中文,返回 JSON 格式。 +``` + +## 實作步驟 + +### 1. HTML 結構更新 +將單一按鈕: +```html + +``` + +改為三個錦囊: +```html +
+
+
🎁
+
錦囊一
+ +
+
+
🎁
+
錦囊二
+ +
+
+
🎁
+
錦囊三
+ +
+
+``` + +### 2. CSS 樣式 +```css +.ai-bags-container { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16px; + margin-bottom: 24px; +} + +.ai-bag { + position: relative; + padding: 20px; + background: linear-gradient(135deg, #9b59b6 0%, #8e44ad 100%); + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(155, 89, 182, 0.3); +} + +.ai-bag:hover { + transform: translateY(-4px); + box-shadow: 0 6px 20px rgba(155, 89, 182, 0.5); +} + +.ai-bag .bag-icon { + font-size: 2rem; + text-align: center; + margin-bottom: 8px; +} + +.ai-bag .bag-title { + color: white; + font-weight: 600; + text-align: center; + font-size: 0.95rem; +} + +.ai-bag .bag-edit-btn { + position: absolute; + top: 8px; + right: 8px; + background: rgba(255, 255, 255, 0.2); + border: none; + border-radius: 4px; + padding: 4px 8px; + cursor: pointer; + font-size: 0.9rem; + transition: all 0.2s ease; +} + +.ai-bag .bag-edit-btn:hover { + background: rgba(255, 255, 255, 0.3); + transform: scale(1.1); +} +``` + +### 3. JavaScript 函式 + +#### 執行 AI 錦囊 +```javascript +async function executeAIBag(module, bagNumber) { + const prompts = getModulePrompts(module); + const bagPrompt = prompts[`bag${bagNumber}`]; + + // 使用 prompt 調用 AI + await callClaudeAPI(bagPrompt.prompt); +} +``` + +#### 編輯 Prompt +```javascript +function editBagPrompt(event, module, bagNumber) { + event.stopPropagation(); + + // 顯示編輯對話框 + showPromptEditModal(module, bagNumber); +} +``` + +## 優點 + +1. ✅ **靈活性高** - 用戶可自定義每個錦囊的用途 +2. ✅ **效率提升** - 三個預設選項涵蓋不同需求場景 +3. ✅ **學習友好** - 顯示 prompt 有助於理解 AI 運作 +4. ✅ **可擴展** - 未來可增加更多錦囊或分享功能 + +## 待實作功能 + +- [ ] HTML 結構更新(5 個模組) +- [ ] CSS 樣式新增 +- [ ] JavaScript 函式實作 +- [ ] LocalStorage 管理 +- [ ] 編輯 Modal 對話框 +- [ ] 預設 Prompt 初始化 diff --git a/更新欄位名稱.md b/更新欄位名稱.md new file mode 100644 index 0000000..e2062f9 --- /dev/null +++ b/更新欄位名稱.md @@ -0,0 +1,176 @@ +# 系統表單欄位規範書 (Standardized Field Specifications) + +## 1. 命名規範與前綴定義 (Naming Conventions) + +為了確保系統一致性,HTML 元素 ID 採用 `[模組前綴]_[標準欄位名]` 的命名方式。 + +| 模組名稱 | 模組前綴 (Prefix) | 說明 | +| :--- | :--- | :--- | +| **崗位管理 (Position)** | `pos_` | 崗位基礎資料 | +| **招聘條件 (Recruit)** | `rec_` | 崗位內的招聘頁籤 | +| **職務管理 (Job)** | `job_` | 全公司通用的職務定義 | +| **部門職責 (DeptFunc)** | `df_` | 部門功能與職責定義 | +| **崗位描述 (JobDesc)** | `jd_` | 最終的 JD 產出表單 | + +--- + +## 2. 崗位基礎資料模組 (Position Module) + +**表單代號**: `positionForm` +**資料表**: `Position` + +### 2.1 基礎資料頁籤 (tab-position-basic) + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 預設 | 備註 | +|---|---|---|---|---|---|---|---| +| 1 | 事業體 | `pos_businessUnit` | `businessUnit` | select | 否 | - | SBU, MBU... (聯動L1) | +| 2 | 處級單位 | `pos_division` | `division` | select | 否 | - | (聯動L2) | +| 3 | 部級單位 | `pos_department` | `department` | select | 否 | - | (聯動L3) | +| 4 | 課級單位 | `pos_section` | `section` | text | 否 | - | - | +| 5 | **崗位編號** | `pos_code` | `positionCode` | text | **是** | - | 唯一識別碼 (PK) | +| 6 | 生效日期 | `pos_effectiveDate` | `effectiveDate` | date | 否 | Today | - | +| 7 | **崗位名稱** | `pos_name` | `positionName` | text | **是** | - | - | +| 8 | 崗位級別 | `pos_level` | `positionLevel` | select | 否 | - | L1-L7 | +| 9 | 崗位類別 | `pos_category` | `positionCategory` | select | 否 | - | onchange 觸發 | +| 10 | 崗位類別名稱 | `pos_categoryName` | `positionCategoryName` | text | 否 | - | readonly | +| 11 | 崗位性質 | `pos_type` | `positionType` | select | 否 | - | FT, PT, CT, IN | +| 12 | 崗位性質名稱 | `pos_typeName` | `positionTypeName` | text | 否 | - | readonly | +| 13 | 編制人數 | `pos_headcount` | `headcount` | number | 否 | 0 | min=0 | +| 14 | 崗位描述 | `pos_desc` | `description` | textarea | 否 | - | rows=6 | +| 15 | 崗位備注 | `pos_remark` | `remark` | textarea | 否 | - | rows=6 | + +### 2.2 招聘要求資料頁籤 (tab-position-recruit) + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 預設 | 備註 | +|---|---|---|---|---|---|---|---| +| 1 | 最低學歷 | `rec_eduLevel` | `educationLevel` | select | 否 | - | HS, BA, MA, PHD | +| 2 | 要求性別 | `rec_gender` | `requiredGender` | select | 否 | Any | M, F, Any | +| 3 | 薪酬范圍 | `rec_salaryRange` | `salaryRange` | select | 否 | - | A-E, Negotiable | +| 4 | 工作經驗 | `rec_expYears` | `experienceYears` | select | 否 | - | 0, 1, 3, 5, 10+ | +| 5 | 最小年齡 | `rec_minAge` | `minAge` | number | 否 | - | min=18 | +| 6 | 最大年齡 | `rec_maxAge` | `maxAge` | number | 否 | - | max=65 | +| 7 | 工作性質 | `rec_jobType` | `jobType` | select | 否 | - | 招聘用性質分類 | +| 8 | 招聘職位 | `rec_position` | `recruitPosition` | select | 否 | - | ENG, MGR... | +| 9 | 職位名稱(對外) | `rec_jobTitle` | `jobTitle` | text | 否 | - | 對外招聘用Title | +| 10 | 上級崗位編號 | `rec_superiorCode` | `superiorPositionCode` | text | 否 | - | - | +| 11 | 職位描述(JD) | `rec_jobDesc` | `recruitJobDesc` | textarea | 否 | - | 招聘廣告用 | +| 12 | 崗位要求(Req) | `rec_positionReq` | `recruitRequirements` | textarea | 否 | - | 招聘廣告用 | +| 13 | 證照要求 | `rec_certReq` | `certRequirements` | select | 否 | - | - | +| 14 | 專業要求 | `rec_majorReq` | `majorRequirements` | text | 否 | - | Modal選擇 | +| 15 | 技能要求 | `rec_skillReq` | `skillRequirements` | text | 否 | - | Tags input | +| 16 | 語言要求 | `rec_langReq` | `langRequirements` | text | 否 | - | - | +| 17 | 其他要求 | `rec_otherReq` | `otherRequirements` | text | 否 | - | - | +| 18 | 招聘備注 | `rec_remark` | `recruitRemark` | textarea | 否 | - | - | + +--- + +## 3. 職務基礎資料模組 (Job Module) + +**表單代號**: `jobForm` +**資料表**: `Job` + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 預設 | 備註 | +|---|---|---|---|---|---|---|---| +| 1 | **職務類別編號** | `job_category` | `jobCategoryCode` | select | **是** | - | onchange 觸發 | +| 2 | 職務類別名稱 | `job_categoryName` | `jobCategoryName` | text | 否 | - | readonly | +| 3 | **職務編號** | `job_code` | `jobCode` | text | **是** | - | 唯一識別碼 | +| 4 | **職務名稱** | `job_name` | `jobName` | text | **是** | - | - | +| 5 | 職務英文 | `job_nameEn` | `jobNameEn` | text | 否 | - | - | +| 6 | 生效日期 | `job_effectiveDate`| `effectiveDate` | date | 否 | - | - | +| 7 | 職務層級 | `job_level` | `jobLevel` | text | 否 | *保密* | **敏感欄位** | +| 8 | 編制人數 | `job_headcount` | `headcount` | number | 否 | - | - | +| 9 | 排列順序 | `job_sortOrder` | `sortOrder` | number | 否 | - | - | +| 10 | 全勤獎金 | `job_hasAttBonus` | `hasAttendanceBonus` | checkbox| 否 | false| Toggle Switch | +| 11 | 住房補貼 | `job_hasHouseAllow`| `hasHousingAllowance` | checkbox| 否 | false| Toggle Switch | +| 12 | 職務備注 | `job_remark` | `remark` | textarea | 否 | - | - | + +--- + +## 4. 部門職責模組 (DeptFunction Module) + +**表單代號**: `deptFunctionForm` +**資料表**: `DeptFunction` + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 預設 | 備註 | +|---|---|---|---|---|---|---|---| +| 1 | **職責編號** | `df_code` | `dfCode` | text | **是** | - | DF-001 | +| 2 | **職責名稱** | `df_name` | `dfName` | text | **是** | - | - | +| 3 | **事業體** | `df_businessUnit` | `businessUnit` | select | **是** | - | (已合併重複欄位) | +| 4 | **處級單位** | `df_division` | `division` | select | **是** | - | - | +| 5 | **部級單位** | `df_department` | `department` | select | **是** | - | - | +| 6 | 課級單位 | `df_section` | `section` | text | 否 | - | - | +| 7 | **對應崗位** | `df_posTitle` | `positionTitle` | select | **是** | - | 關聯 Position | +| 8 | 崗位級別 | `df_posLevel` | `positionLevel` | select | 否 | - | 自動帶出或指定 | +| 9 | 部門主管職稱 | `df_managerTitle` | `managerTitle` | text | 否 | - | - | +| 10 | **生效日期** | `df_effectiveDate` | `effectiveDate` | date | **是** | - | - | +| 11 | 人數上限 | `df_headcountLimit`| `headcountLimit` | number | 否 | - | - | +| 12 | 狀態 | `df_status` | `status` | select | 否 | active | - | +| 13 | 部門使命 | `df_mission` | `mission` | textarea | 否 | - | - | +| 14 | 部門願景 | `df_vision` | `vision` | textarea | 否 | - | - | +| 15 | **核心職責** | `df_coreFunc` | `coreFunctions` | textarea | **是** | - | - | +| 16 | KPIs | `df_kpis` | `kpis` | textarea | 否 | - | - | +| 17 | 協作部門 | `df_collab` | `collaboration` | textarea | 否 | - | - | +| 18 | 備注 | `df_remark` | `remark` | textarea | 否 | - | - | + +--- + +## 5. 崗位描述模組 (JobDescription Module) + +**表單代號**: `jobDescForm` +**資料表**: `JobDescription` (部分欄位為 View) + +### 5.1 基本信息 (Header) + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 備註 | +|---|---|---|---|---|---|---| +| 1 | 工號 | `jd_empNo` | `empNo` | text | 否 | Search Modal | +| 2 | 姓名 | `jd_empName` | `empName` | text | 否 | Readonly | +| 3 | 崗位代碼 | `jd_posCode` | `positionCode` | text | 否 | 關聯鍵 | +| 4 | 版本日期 | `jd_versionDate` | `versionDate` | date | 否 | - | + +### 5.2 崗位資訊 (Position Info - Readonly/Derived) + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 備註 | +|---|---|---|---|---|---|---| +| 1 | 崗位名稱 | `jd_posName` | `positionName` | text | 否 | - | +| 2 | 事業體 | `jd_businessUnit` | `businessUnit` | select | 否 | - | +| 3 | 處級單位 | `jd_division` | `division` | select | 否 | - | +| 4 | 部級單位 | `jd_department` | `department` | select | 否 | - | +| 5 | 課級單位 | `jd_section` | `section` | text | 否 | - | +| 6 | 崗位級別 | `jd_posLevel` | `positionLevel` | select | 否 | - | +| 7 | 生效日期 | `jd_posEffDate` | `positionEffectiveDate`| date | 否 | - | +| 8 | **直接主管** | `jd_supervisor` | `directSupervisor` | text | 否 | - | +| 9 | 職等&職務 | `jd_gradeJob` | `positionGradeJob` | text | 否 | Modal | +| 10 | **匯報對象** | `jd_reportTo` | `reportTo` | text | 否 | Modal | +| 11 | 直接下屬 | `jd_directReports` | `directReports` | text | 否 | - | +| 12 | 任職地點 | `jd_location` | `workLocation` | select | 否 | - | +| 13 | 員工屬性 | `jd_empAttr` | `empAttribute` | select | 否 | - | + +### 5.3 職責與要求 (Details) + +| # | 欄位顯示名稱 | 標準化 HTML ID | 資料庫欄位名稱 | 類型 | 必填 | 備註 | +|---|---|---|---|---|---|---| +| 1 | 部門職責代碼 | `jd_dfCode` | `dfCode` | text | 否 | 關聯 DeptFunction | +| 2 | 崗位設置目的 | `jd_purpose` | `positionPurpose` | text | 否 | - | +| 3 | **主要職責** | `jd_mainResp` | `mainResponsibilities`| textarea | 否 | 編號清單 | +| 4 | 教育程度 | `jd_eduLevel` | `educationLevel` | text | 否 | - | +| 5 | 基本技能 | `jd_basicSkills` | `basicSkills` | textarea | 否 | - | +| 6 | 專業知識 | `jd_proKnowledge` | `professionalKnowledge` | textarea | 否 | - | +| 7 | 工作經驗 | `jd_expReq` | `experienceRequirements`| textarea | 否 | - | +| 8 | 其他要求 | `jd_otherReq` | `otherRequirements` | textarea | 否 | - | + +--- + +## 6. 共用設定與資料字典 + +### 6.1 模態框 (Modals) +* `MajorModal` (專業要求) +* `EmpSearchModal` (員工搜索) +* `OrgSearchModal` (組織搜索) +* `GradeJobModal` (職等職務) +* `ReportToModal` (匯報對象) + +### 6.2 特殊控件 +* **Toggle Switch**: 用於所有布林值 (Boolean) 欄位。 +* **Numbered Textarea**: 用於 `mainResponsibilities`,自動產生序號。 +* **Cascading Selects**: 組織層級 (BU -> Div -> Dept -> Section) 統一使用標準聯動邏輯。 \ No newline at end of file diff --git a/表單欄位清單.md b/表單欄位清單.md new file mode 100644 index 0000000..f8e9448 --- /dev/null +++ b/表單欄位清單.md @@ -0,0 +1,347 @@ +# 表單欄位完整清單 + +## 1. 崗位基礎資料模組 - 基礎資料頁籤 (positionForm - tab-position-basic) + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 事業體 (Business Unit) | businessUnit | businessUnit | select | 否 | 空值 | SBU, MBU, HQBU, ITBU, HRBU, ACCBU | +| 2 | 處級單位 (Division) | division | division | select | 否 | 空值 | 根據事業體變動 | +| 3 | 部級單位 (Department) | department | department | select | 否 | 空值 | 根據處級單位變動 | +| 4 | 課級單位 (Section) | section | section | text | 否 | 選填 | - | +| 5 | 崗位編號 * | positionCode | positionCode | text | **是** | 空值 | 唯一識別碼,可更改 | +| 6 | 生效日期 | effectiveDate | effectiveDate | date | 否 | 2001-01-01 | - | +| 7 | 崗位名稱 * | positionName | positionName | text | **是** | 空值 | - | +| 8 | 崗位級別 | positionLevel | positionLevel | select | 否 | 空值 | L1-L7 (基層至總經理) | +| 9 | 崗位類別 | positionCategory | positionCategory | select | 否 | 空值 | 01, 02, 03, 04;有onchange事件 | +| 10 | 崗位類別名稱 | positionCategoryName | positionCategoryName | text | 否 | 自動帶出 | readonly | +| 11 | 崗位性質 | positionNature | positionNature | select | 否 | 空值 | FT(全職), PT(兼職), CT(約聘), IN(實習);有onchange事件 | +| 12 | 崗位性質名稱 | positionNatureName | positionNatureName | text | 否 | 自動帶出 | readonly | +| 13 | 編制人數 | headcount | headcount | number | 否 | 空值 | min=0 | +| 14 | 崗位描述(條列式說明) | positionDesc | positionDesc | textarea | 否 | 空值 | rows=6;有範例提示 | +| 15 | 崗位備注(條列式說明) | positionRemark | positionRemark | textarea | 否 | 空值 | rows=6;有範例提示 | + +--- + +## 2. 崗位基礎資料模組 - 招聘要求資料頁籤 (positionForm - tab-position-recruit) + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 最低學歷 | minEducation | minEducation | select | 否 | 空值 | HS, JC, BA, MA, PHD | +| 2 | 要求性別 | requiredGender | requiredGender | select | 否 | 不限 | M(男), F(女) | +| 3 | 薪酬范圍 | salaryRange | salaryRange | select | 否 | 空值 | A-E, N(面議) | +| 4 | 工作經驗 | workExperience | workExperience | select | 否 | 空值 | 0, 1, 3, 5, 10 (年) | +| 5 | 最小年齡 | minAge | minAge | number | 否 | 空值 | min=18, max=65 | +| 6 | 最大年齡 | maxAge | maxAge | number | 否 | 空值 | min=18, max=65 | +| 7 | 工作性質 | jobType | jobType | select | 否 | 空值 | FT, PT, CT, DP | +| 8 | 職位名稱 | jobTitle | jobTitle | text | 否 | 空值 | - | +| 9 | 招聘職位 | recruitPosition | recruitPosition | select | 否 | 空值 | ENG, MGR, AST, OP, SAL | +| 10 | 上級崗位編號 | superiorPosition | superiorPosition | text | 否 | 空值 | - | +| 11 | 職位描述 | jobDesc | jobDesc | textarea | 否 | 空值 | rows=3 | +| 12 | 崗位要求 | positionReq | positionReq | textarea | 否 | 空值 | rows=3 | +| 13 | 職稱要求 | titleReq | titleReq | select | 否 | 空值 | NONE, CERT, LIC | +| 14 | 專業要求 | majorReq | majorReq | text | 否 | 點擊選擇 | readonly;有modal選擇器 | +| 15 | 技能要求 | skillReq | skillReq | text | 否 | 空值 | 例:Excel, Python, SAP... | +| 16 | 語言要求 | langReq | langReq | text | 否 | 空值 | 例:英文中級、日文N2... | +| 17 | 其他要求 | otherReq | otherReq | text | 否 | 空值 | - | +| 18 | 備注說明 | recruitRemark | recruitRemark | textarea | 否 | 空值 | rows=4 | + +--- + +## 3. 職務基礎資料模組 (jobForm - tab-job-basic) + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 職務類別編號 * | jobCategoryCode | jobCategoryCode | select | **是** | 空值 | MGR, TECH, SALE, ADMIN, RD, PROD;有onchange事件 | +| 2 | 職務類別名稱 | jobCategoryName | jobCategoryName | text | 否 | 自動帶出 | readonly | +| 3 | 職務編號 * | jobCode | jobCode | text | **是** | 空值 | 可更改職務編號 | +| 4 | 職務名稱 * | jobName | jobName | text | **是** | 空值 | - | +| 5 | 職務英文 | jobNameEn | jobNameEn | text | 否 | 空值 | - | +| 6 | 生效日期 | jobEffectiveDate | jobEffectiveDate | date | 否 | 空值 | - | +| 7 | 編制人數 | jobHeadcount | jobHeadcount | number | 否 | 空值 | min=0 | +| 8 | 排列順序 | jobSortOrder | jobSortOrder | number | 否 | 空值 | min=0 | +| 9 | 備注說明 | jobRemark | jobRemark | textarea | 否 | 空值 | rows=4 | +| 10 | 職務層級 | jobLevel | jobLevel | text | 否 | 如:*保密* | 敏感信息欄位 | +| 11 | 是否有全勤 | hasAttendanceBonus | hasAttendanceBonus | checkbox | 否 | 否 | toggle-switch 控件 | +| 12 | 是否住房補貼 | hasHousingAllowance | hasHousingAllowance | checkbox | 否 | 否 | toggle-switch 控件 | + +--- + +## 4. 部門職責模組 (deptFunctionForm) + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 部門職責編號 * | deptFunctionCode | deptFunctionCode | text | **是** | 空值 | 例如: DF-001 | +| 2 | 部門職責名稱 * | deptFunctionName | deptFunctionName | text | **是** | 空值 | 例如: 軟體研發部職責 | +| 3 | 事業體 (Business Unit) * (第1個) | deptFunctionBU | deptFunctionBU | select | **是** | 空值 | SBU, MBU, HQBU, ITBU, HRBU, ACCBU | +| 4 | 事業體 (Business Unit) * (第2個) | deptFunc_businessUnit | businessUnit | select | **是** | 空值 | 聯動選擇 | +| 5 | 處級單位 (Division) * | deptFunc_division | division | select | **是** | 空值 | 聯動選擇 | +| 6 | 部級單位 (Department) * | deptFunc_department | department | select | **是** | 空值 | 聯動選擇 | +| 7 | 課級單位 (Section) | deptFunc_section | section | text | 否 | 選填 | - | +| 8 | 崗位名稱 * | deptFunc_positionTitle | positionTitle | select | **是** | 空值 | 根據部級單位變動 | +| 9 | 崗位級別 | deptFunc_positionLevel | positionLevel | select | 否 | 空值 | E, M, S, D, VP, C | +| 10 | 部門主管職稱 | deptManager | deptManager | text | 否 | 例如: 部門經理 | - | +| 11 | 生效日期 * | deptFunctionEffectiveDate | deptFunctionEffectiveDate | date | **是** | 空值 | - | +| 12 | 部門人數上限 | deptHeadcount | deptHeadcount | number | 否 | 例如: 50 | min=1 | +| 13 | 部門狀態 | deptStatus | deptStatus | select | 否 | active | active, inactive, planning | +| 14 | 部門使命 (Mission) | deptMission | deptMission | textarea | 否 | 空值 | rows=3;有範例提示 | +| 15 | 部門願景 (Vision) | deptVision | deptVision | textarea | 否 | 空值 | rows=3;有範例提示 | +| 16 | 核心職責 (Core Functions) * | deptCoreFunctions | deptCoreFunctions | textarea | **是** | 空值 | rows=6;有範例提示 | +| 17 | 關鍵績效指標 (KPIs) | deptKPIs | deptKPIs | textarea | 否 | 空值 | rows=4;有範例提示 | +| 18 | 協作部門 | deptCollaboration | deptCollaboration | textarea | 否 | 空值 | rows=3;有範例提示 | +| 19 | 備注 | deptFunctionRemark | deptFunctionRemark | textarea | 否 | 空值 | rows=3 | + +--- + +## 5. 崗位描述模組 (jobDescForm - tab-jobdesc-basic) + +### 5.1 基本信息區塊 + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 工號 | jd_empNo | empNo | text | 否 | 空值 | 有員工搜索modal | +| 2 | 姓名 | jd_empName | empName | text | 否 | 自動帶出 | readonly | +| 3 | 崗位代碼 | jd_positionCode | positionCode | text | 否 | 空值 | - | +| 4 | 版本更新日期 | jd_versionDate | versionDate | date | 否 | 空值 | - | + +### 5.2 崗位基本信息區塊 + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 崗位名稱 | jd_positionName | positionName | text | 否 | 空值 | - | +| 2 | 事業體 (Business Unit) | jd_businessUnit | businessUnit | select | 否 | 空值 | 聯動選擇 | +| 3 | 處級單位 (Division) | jd_division | division | select | 否 | 空值 | 聯動選擇 | +| 4 | 部級單位 (Department) | jd_department | department | select | 否 | 空值 | 聯動選擇 | +| 5 | 課級單位 (Section) | jd_section | section | text | 否 | 選填 | - | +| 6 | 崗位名稱 (重複) | jd_positionTitle | positionTitle | select | 否 | 空值 | 根據部級單位變動 | +| 7 | 崗位級別 | jd_positionLevel | positionLevel | select | 否 | 空值 | E, M, S, D, VP, C | +| 8 | 崗位生效日期 | jd_positionEffectiveDate | positionEffectiveDate | date | 否 | 空值 | - | +| 9 | 直接領導職務 | jd_directSupervisor | directSupervisor | text | 否 | 空值 | - | +| 10 | 崗位職等&職務 | jd_positionGradeJob | positionGradeJob | text | 否 | 點擊選擇 | readonly;有modal選擇器 | +| 11 | 匯報對象職務 | jd_reportTo | reportTo | text | 否 | 點擊選擇 | readonly;有modal選擇器 | +| 12 | 直接下級(職位及人數) | jd_directReports | directReports | text | 否 | 例:工程師 x 5人 | - | +| 13 | 任職地點 | jd_workLocation | workLocation | select | 否 | 空值 | HQ, TPE, TYC, KHH, SH, SZ | +| 14 | 員工屬性 | jd_empAttribute | empAttribute | select | 否 | 空值 | FT, CT, PT, IN, DP | + +### 5.3 部門職責資訊區塊 (自動帶入,隱藏顯示) + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 部門職責編號 | jd_deptFunctionCode | deptFunctionCode | text | 否 | 自動帶出 | readonly;id="deptFunctionInfoSection" | +| 2 | 事業體 | jd_deptFunctionBU | deptFunctionBU | text | 否 | 自動帶出 | readonly | +| 3 | 部門使命 | jd_deptMission | deptMission | textarea | 否 | 自動帶出 | readonly;rows=2 | +| 4 | 部門核心職責 | jd_deptCoreFunctions | deptCoreFunctions | textarea | 否 | 自動帶出 | readonly;rows=4 | +| 5 | 部門 KPIs | jd_deptKPIs | deptKPIs | textarea | 否 | 自動帶出 | readonly;rows=3 | + +### 5.4 職責描述區塊 + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 崗位設置目的 | jd_positionPurpose | positionPurpose | text | 否 | 空值 | 有展開編輯按鈕 | +| 2 | 主要崗位職責 | jd_mainResponsibilities | mainResponsibilities | textarea | 否 | 空值 | rows=8;numbered-textarea;有數字編號 | + +### 5.5 崗位要求區塊 + +| # | 欄位顯示名稱 | HTML元素ID | 資料庫欄位名稱 | 資料類型 | 是否必填 | 預設值 | 備註 | +|---|-----------|---------|------------|------|------|------|------| +| 1 | 教育程度 | jd_education | education | text | 否 | 例:大學本科及以上 | - | +| 2 | 基本技能 | jd_basicSkills | basicSkills | textarea | 否 | 空值 | rows=2;有展開編輯按鈕 | +| 3 | 專業知識 | jd_professionalKnowledge | professionalKnowledge | textarea | 否 | 空值 | rows=2;有展開編輯按鈕 | +| 4 | 工作經驗 | jd_workExperienceReq | workExperienceReq | textarea | 否 | 空值 | rows=2;有展開編輯按鈕 | +| 5 | 其他 | jd_otherRequirements | otherRequirements | textarea | 否 | 空值 | rows=3 | + +--- + +## 6. 崗位清單模組 (positionListTable) + +### 6.1 表格列(只讀顯示) + +| # | 列標題 | 資料鍵值 | 資料類型 | 可排序 | 備註 | +|---|------|--------|------|------|------| +| 1 | 崗位編號 | positionCode | text | 是 | 可點擊排序 | +| 2 | 崗位名稱 | positionName | text | 是 | 可點擊排序 | +| 3 | 崗位類別 | positionCategory | text | 是 | 可點擊排序 | +| 4 | 崗位性質 | positionNature | text | 是 | 可點擊排序 | +| 5 | 編制人數 | headcount | number | 是 | 可點擊排序 | +| 6 | 崗位等級 | positionLevel | text | 是 | 可點擊排序 | +| 7 | 生效日期 | effectiveDate | date | 是 | 可點擊排序 | +| 8 | 操作 | - | button | 否 | 編輯/刪除按鈕 | + +--- + +## 數據結構對應關係 + +### Position (崗位基礎資料) +```javascript +{ + id: string, + basicInfo: { + positionCode: string, + positionName: string, + positionCategory: string, + positionCategoryName: string, + positionNature: string, + positionNatureName: string, + headcount: number, + positionLevel: string, + effectiveDate: date, + positionDesc: string, + positionRemark: string + }, + recruitInfo: { + minEducation: string, + requiredGender: string, + salaryRange: string, + workExperience: number, + minAge: number, + maxAge: number, + jobType: string, + recruitPosition: string, + jobTitle: string, + jobDesc: string, + positionReq: string, + titleReq: string, + majorReq: string, + skillReq: string, + langReq: string, + otherReq: string, + superiorPosition: string, + recruitRemark: string + }, + createdAt: datetime, + updatedAt: datetime +} +``` + +### Job (職務基礎資料) +```javascript +{ + id: string, + jobCategoryCode: string, + jobCategoryName: string, + jobCode: string, + jobName: string, + jobNameEn: string, + jobEffectiveDate: date, + jobHeadcount: number, + jobSortOrder: number, + jobRemark: string, + jobLevel: string, + hasAttendanceBonus: boolean, + hasHousingAllowance: boolean, + createdAt: datetime, + updatedAt: datetime +} +``` + +### DeptFunction (部門職責) +```javascript +{ + deptFunctionCode: string, + deptFunctionName: string, + deptFunctionBU: string, + businessUnit: string, + division: string, + department: string, + section: string, + positionTitle: string, + positionLevel: string, + deptManager: string, + deptFunctionEffectiveDate: date, + deptHeadcount: number, + deptStatus: string, + deptMission: string, + deptVision: string, + deptCoreFunctions: string, + deptKPIs: string, + deptCollaboration: string, + deptFunctionRemark: string +} +``` + +### JobDescription (崗位描述) +```javascript +{ + basicInfo: { + empNo: string, + empName: string, + positionCode: string, + versionDate: date + }, + positionInfo: { + positionName: string, + businessUnit: string, + division: string, + department: string, + section: string, + positionTitle: string, + positionLevel: string, + positionEffectiveDate: date, + directSupervisor: string, + positionGradeJob: string, + reportTo: string, + directReports: string, + workLocation: string, + empAttribute: string, + deptFunctionCode: string, + deptFunctionBU: string, + deptMission: string, + deptCoreFunctions: string, + deptKPIs: string + }, + responsibilities: { + positionPurpose: string, + mainResponsibilities: string + }, + requirements: { + education: string, + basicSkills: string, + professionalKnowledge: string, + workExperienceReq: string, + otherRequirements: string + } +} +``` + +--- + +## 關鍵特性總結 + +### 聯動選擇(Cascading Select) +- **事業體 → 處級單位 → 部級單位 → 課級單位** + - 在崗位基礎資料、部門職責、崗位描述中都有此聯動 + - 觸發事件:onchange="onXXXBusinessUnitChange/onXXXDivisionChange" 等 + +### 自動帶出欄位 (readonly) +- 崗位類別名稱 (根據崗位類別自動帶出) +- 崗位性質名稱 (根據崗位性質自動帶出) +- 職務類別名稱 (根據職務類別編號自動帶出) +- 員工姓名 (根據工號自動帶出) +- 部門職責相關資訊 (自動帶入到崗位描述) + +### Modal/模態框 +- 專業要求選擇 (Major Modal - majorModal) +- 員工搜索 (EmpSearchModal) +- 組織搜索 (OrgSearchModal) +- 職等職務選擇 (GradeJobModal) +- 匯報對象選擇 (ReportToModal) + +### CSV 操作 +- 職務基礎資料支援: 下載範本、匯出、匯入 +- 部門職責支援: 匯入、匯出 + +### 特殊欄位 +- **敏感信息欄位**: jobLevel (職務層級) - 標記為 *保密* +- **布林值(Checkbox)**: hasAttendanceBonus, hasHousingAllowance +- **Toggle Switch**: 用於布林值的友善UI + +### 表單驗證 +- 必填欄位用 `*` 標記 +- HTML5 required 屬性用於部分欄位 + +--- + +## 變更紀錄 + +| 日期 | 版本 | 變更內容 | +|------|------|--------| +| 2025-12-05 | v1.0 | 初版完整表單欄位清單 |