diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8bcd0f7..b870aca 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -25,7 +25,17 @@ "Bash(python add_dept_relation.py:*)", "Bash(cat:*)", "Bash(python add_random_positions.py:*)", - "Bash(timeout /t 3 /nobreak)" + "Bash(timeout /t 3 /nobreak)", + "Bash(python -m json.tool:*)", + "Bash(python app.py:*)", + "Bash(tasklist:*)", + "Bash(findstr:*)", + "Bash(netstat:*)", + "Bash(powershell -Command \"Stop-Process -Id 44816,14404,45900 -Force\")", + "Bash(powershell -Command \"Get-Process python | Stop-Process -Force\")", + "Bash(python llm_config.py:*)", + "Bash(python:*)", + "Bash(mkdir:*)" ], "deny": [], "ask": [] diff --git a/.env.example b/.env.example index 6a01f91..aaec6b8 100644 --- a/.env.example +++ b/.env.example @@ -17,8 +17,8 @@ GITEA_TOKEN=your_gitea_access_token # ==================== LLM API Keys ==================== # Google Gemini API -GEMINI_API_KEY=your_gemini_api_key_here -GEMINI_MODEL=gemini-1.5-flash +GEMINI_API_KEY=AIzaSyDWD6TdXgtYyKvmGLF0RiN8AkbSF8eDnHY +GEMINI_MODEL=gemini-2.5-flash # DeepSeek API DEEPSEEK_API_KEY=your_deepseek_api_key_here @@ -28,6 +28,10 @@ DEEPSEEK_API_URL=https://api.deepseek.com/v1 OPENAI_API_KEY=your_openai_api_key_here OPENAI_API_URL=https://api.openai.com/v1 +# Ollama API +OLLAMA_API_URL=https://ollama_pjapi.theaken.com +OLLAMA_MODEL=deepseek-reasoner + # ==================== Flask Configuration ==================== FLASK_APP=start_server.py FLASK_ENV=development diff --git a/SDD_代碼分離優化.md b/SDD_代碼分離優化.md new file mode 100644 index 0000000..877d774 --- /dev/null +++ b/SDD_代碼分離優化.md @@ -0,0 +1,1120 @@ +# 軟體設計文件 (SDD) - 代碼分離優化 + +> **文件版本**: v1.0 +> **建立日期**: 2024-12-04 +> **專案名稱**: HR Position Management System +> **優化目標**: 將 CSS 和 JavaScript 從 index.html 分離 +> **狀態**: 📋 待決策階段 + +--- + +## 📋 目錄 + +1. [專案現況分析](#專案現況分析) +2. [優化目標與效益](#優化目標與效益) +3. [需要決策的事項](#需要決策的事項) +4. [建議的架構方案](#建議的架構方案) +5. [分離策略](#分離策略) +6. [風險評估](#風險評估) +7. [執行計畫](#執行計畫) +8. [驗收標準](#驗收標準) + +--- + +## 專案現況分析 + +### 📊 當前檔案結構 + +``` +d:\00001_Vibe_coding\1204剛為\ +├── index.html (約 4,700 行) ⚠️ 包含 HTML + CSS + JavaScript +├── login.html (約 470 行) ⚠️ 包含 HTML + CSS + JavaScript +├── hierarchical_data.js (已分離) ✅ 組織架構資料 +├── dropdown_data.js (已分離) ✅ 下拉選單資料 +├── app.py (Flask 後端) +├── .env (環境設定) +└── prompt.md (AI Prompt 文件) +``` + +### 📈 當前 index.html 組成分析 + +| 內容類型 | 預估行數 | 佔比 | 說明 | +|---------|---------|------|------| +| **HTML 結構** | ~1,500 行 | 32% | 5 個主要頁籤的表單結構 | +| **CSS 樣式** | ~700 行 | 15% | 內嵌於 ` + + +
+

📊 公司組織架構預覽

+
總計: ''' + str(len(data)) + ''' 筆資料
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + + + + + + + + +''' + +# 添加表格行 +for row in data: + html_content += f''' + + + + + +''' + +html_content += ''' +
事業體處級單位部級單位崗位名稱
{row['事業體']}{row['處級單位'] if row['處級單位'] else ''}{row['部級單位'] if row['部級單位'] else ''}{row['崗位名稱']}
+
+ + + + + +''' + +# 寫入文件 +with open('review.html', 'w', encoding='utf-8') as f: + f.write(html_content) + +print(f"預覽頁面已生成:review.html") +print(f"共包含 {len(data)} 筆組織架構資料") + diff --git a/hierarchical_data.js b/hierarchical_data.js new file mode 100644 index 0000000..0d9e911 --- /dev/null +++ b/hierarchical_data.js @@ -0,0 +1,2066 @@ +// 自動生成的階層關聯資料 + +// 事業體 -> 處級單位的對應 +const businessToDivision = { + "半導體事業群": [ + "半導體事業群" + ], + "汽車事業體": [ + "汽車事業體" + ], + "法務室": [ + "法務室" + ], + "岡山製造事業體": [ + "副總辦公室", + "封裝工程處", + "岡山製造事業體", + "廠務與環安衛管理處", + "測試工程與研發處", + "生產處", + "資材處" + ], + "產品事業體": [ + "先進產品事業處", + "成熟產品事業處", + "產品事業體" + ], + "晶圓三廠": [ + "晶圓三廠", + "製程工程處" + ], + "集團人資行政事業體": [ + "集團人資行政事業體" + ], + "集團財務事業體": [ + "岡山強茂財務處", + "集團財務事業體" + ], + "集團會計事業體": [ + "岡山會計處", + "集團會計事業體", + "集團會計處" + ], + "集團資訊事業體": [ + "資安行動小組", + "資訊一處", + "資訊二處", + "集團資訊事業體" + ], + "新創事業體": [ + "中低壓產品研發處", + "新創事業體", + "研發中心", + "高壓產品研發處" + ], + "稽核室": [ + "稽核室" + ], + "總經理室": [ + "ESG專案辦公室", + "專案管理室", + "總經理室" + ], + "總品質事業體": [ + "總品質事業體" + ], + "營業事業體": [ + "全球技術服務處", + "全球行銷暨業務支援處", + "商業開發暨市場應用處", + "大中華區銷售事業處", + "海外銷售事業處", + "營業事業體" + ] +}; + +// 處級單位 -> 部級單位的對應 +const divisionToDepartment = { + "生產處": [ + "生產企劃部", + "生產部" + ], + "岡山製造事業體": [ + "岡山品質管制部" + ], + "封裝工程處": [ + "製程工程一部", + "製程工程二部", + "設備一部", + "設備二部" + ], + "副總辦公室": [ + "工業工程部" + ], + "測試工程與研發處": [ + "新產品導入部", + "測試工程部", + "研發部" + ], + "資材處": [ + "原物料控制部", + "外部資源部", + "採購部", + "生管部" + ], + "廠務與環安衛管理處": [ + "廠務部" + ], + "產品事業體": [ + "廠務部" + ], + "先進產品事業處": [ + "產品管理部(APD)" + ], + "成熟產品事業處": [ + "產品管理部(MPD)" + ], + "晶圓三廠": [ + "品質部", + "廠務部(Fab3)", + "產品管理部(MPD)", + "製造部" + ], + "製程工程處": [ + "工程一部", + "工程三部", + "工程二部", + "製程整合部(Fab3)" + ], + "集團人資行政事業體": [ + "招募任用部", + "薪酬管理部", + "行政總務管理部", + "製程整合部(Fab3)", + "訓練發展部" + ], + "集團財務事業體": [ + "岡山強茂財務部", + "薪酬管理部" + ], + "岡山強茂財務處": [ + "岡山強茂財務部" + ], + "集團會計事業體": [ + "岡山強茂財務部" + ], + "岡山會計處": [ + "會計部", + "管理會計部" + ], + "集團會計處": [ + "集團合併報表部" + ], + "集團資訊事業體": [ + "集團合併報表部" + ], + "資安行動小組": [ + "集團合併報表部" + ], + "資訊一處": [ + "應用系統部", + "系統網路服務部", + "電腦整合製造部" + ], + "新創事業體": [ + "資源管理部" + ], + "總品質事業體": [ + "品質保證部", + "品質系統及客戶工程整合部", + "客戶品質管理部", + "封測外包品質管理部", + "產品品質管理部" + ], + "營業事業體": [ + "品質保證部" + ], + "海外銷售事業處": [ + "日本區暨代工業務部", + "歐亞區業務部", + "美洲區業務部", + "韓國區業務部-韓國區" + ], + "全球技術服務處": [ + "應用工程部(GTS)", + "特性測試部", + "系統工程部" + ], + "全球行銷暨業務支援處": [ + "MOSFET晶圓採購部", + "市場行銷企劃部", + "業務生管部" + ], + "大中華區銷售事業處": [ + "台灣區業務部", + "業務一部", + "業務二部" + ] +}; + +// 部級單位 -> 崗位名稱的對應 +const departmentToPosition = { + "生產部": [ + "作業員", + "副班長", + "班長", + "組長", + "經副理", + "課長" + ], + "生產企劃部": [ + "專員", + "工程師", + "經副理", + "課長" + ], + "岡山品質管制部": [ + "作業員", + "副班長", + "副總經理", + "副總經理助理", + "工程師", + "班長", + "組長", + "經副理", + "課長" + ], + "製程工程一部": [ + "經副理" + ], + "製程工程二部": [ + "工程師", + "經副理", + "課長" + ], + "設備一部": [ + "經副理" + ], + "設備二部": [ + "工程師", + "經副理", + "課長" + ], + "工業工程部": [ + "副理", + "工程師", + "經副理", + "課長" + ], + "測試工程部": [ + "工程師", + "經副理", + "課長" + ], + "新產品導入部": [ + "專員", + "工程師", + "經副理" + ], + "研發部": [ + "專員", + "工程師", + "經副理", + "課長" + ], + "採購部": [ + "專員", + "經副理", + "課長" + ], + "外部資源部": [ + "專員" + ], + "生管部": [ + "作業員", + "副班長", + "專員", + "班長", + "經副理", + "課長" + ], + "原物料控制部": [ + "作業員", + "副班長", + "專員", + "班長", + "經副理", + "課長" + ], + "廠務部": [ + "專員", + "工程師", + "經副理", + "處長", + "課長" + ], + "產品管理部(APD)": [ + "工程師", + "經副理" + ], + "產品管理部(MPD)": [ + "專員", + "專案經副理", + "工程師", + "經副理", + "顧問" + ], + "品質部": [ + "作業員", + "工程師", + "經副理" + ], + "製造部": [ + "作業員", + "副班長", + "班長", + "經副理", + "課長" + ], + "廠務部(Fab3)": [ + "工程師", + "經副理" + ], + "工程一部": [ + "工程師", + "經副理" + ], + "工程二部": [ + "工程師", + "經副理" + ], + "工程三部": [ + "工程師", + "經副理" + ], + "製程整合部(Fab3)": [ + "人資長", + "工程師", + "經副理" + ], + "行政總務管理部": [ + "助理", + "專員", + "經副理" + ], + "招募任用部": [ + "專員", + "經副理" + ], + "訓練發展部": [ + "專員", + "經副理" + ], + "薪酬管理部": [ + "專員", + "經副理", + "財務長" + ], + "岡山強茂財務部": [ + "專員", + "專案副理", + "會計長", + "經副理", + "課長" + ], + "會計部": [ + "專員", + "經副理", + "課長" + ], + "管理會計部": [ + "專員", + "經副理", + "課長" + ], + "集團合併報表部": [ + "專員", + "經副理", + "課長", + "資訊長" + ], + "應用系統部": [ + "工程師", + "經副理" + ], + "電腦整合製造部": [ + "工程師", + "經副理" + ], + "系統網路服務部": [ + "工程師", + "經副理" + ], + "資源管理部": [ + "專員", + "經副理" + ], + "客戶品質管理部": [ + "專員", + "工程師", + "經副理", + "課長" + ], + "產品品質管理部": [ + "作業員", + "工程師", + "班長", + "經副理", + "課長" + ], + "品質系統及客戶工程整合部": [ + "工程師", + "經副理", + "課長" + ], + "封測外包品質管理部": [ + "工程師", + "經副理", + "課長" + ], + "品質保證部": [ + "作業員", + "副班長", + "副總經理", + "副總經理助理", + "工程師", + "班長", + "經副理", + "課長" + ], + "日本區暨代工業務部": [ + "助理", + "專員", + "經副理", + "課長" + ], + "歐亞區業務部": [ + "助理", + "專員", + "經副理", + "課長" + ], + "韓國區業務部-韓國區": [ + "助理", + "專員", + "專案經理", + "經副理", + "課長" + ], + "美洲區業務部": [ + "助理", + "專員", + "經副理", + "課長" + ], + "應用工程部(GTS)": [ + "專案經副理", + "工程師", + "技術經副理", + "經副理" + ], + "系統工程部": [ + "工程師", + "經副理" + ], + "特性測試部": [ + "工程師", + "經副理", + "課長" + ], + "業務生管部": [ + "專員", + "經副理", + "課長" + ], + "市場行銷企劃部": [ + "專員", + "經理", + "處長" + ], + "MOSFET晶圓採購部": [ + "專員", + "經副理", + "課長" + ], + "台灣區業務部": [ + "助理", + "專員" + ], + "業務一部": [ + "助理", + "專員", + "經副理", + "處長/資深經理" + ], + "業務二部": [ + "助理", + "專員", + "經副理", + "處長/資深經理" + ] +}; + +// 完整階層資料(用於反向查詢) +const fullHierarchyData = [ + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "組長" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "班長" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "副班長" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產部", + "position": "作業員" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產企劃部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產企劃部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產企劃部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "生產處", + "department": "生產企劃部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "組長" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "班長" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "副班長" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "作業員" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "副總經理" + }, + { + "business": "岡山製造事業體", + "division": "岡山製造事業體", + "department": "岡山品質管制部", + "position": "副總經理助理" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程一部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "製程工程二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備一部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "封裝工程處", + "department": "設備二部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "副理" + }, + { + "business": "岡山製造事業體", + "division": "副總辦公室", + "department": "工業工程部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "測試工程部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "測試工程部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "測試工程部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "測試工程部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "測試工程部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "新產品導入部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "新產品導入部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "新產品導入部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "測試工程與研發處", + "department": "研發部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "採購部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "採購部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "採購部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "採購部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "採購部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "外部資源部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "班長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "副班長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "生管部", + "position": "作業員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "班長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "副班長" + }, + { + "business": "岡山製造事業體", + "division": "資材處", + "department": "原物料控制部", + "position": "作業員" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "經副理" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "工程師" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "專員" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "課長" + }, + { + "business": "岡山製造事業體", + "division": "廠務與環安衛管理處", + "department": "廠務部", + "position": "工程師" + }, + { + "business": "產品事業體", + "division": "產品事業體", + "department": "廠務部", + "position": "處長" + }, + { + "business": "產品事業體", + "division": "先進產品事業處", + "department": "產品管理部(APD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "先進產品事業處", + "department": "產品管理部(APD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "先進產品事業處", + "department": "產品管理部(APD)", + "position": "工程師" + }, + { + "business": "產品事業體", + "division": "先進產品事業處", + "department": "產品管理部(APD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "先進產品事業處", + "department": "產品管理部(APD)", + "position": "工程師" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "專案經副理" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "工程師" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "經副理" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "專案經副理" + }, + { + "business": "產品事業體", + "division": "成熟產品事業處", + "department": "產品管理部(MPD)", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "產品管理部(MPD)", + "position": "顧問" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "產品管理部(MPD)", + "position": "專員" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "品質部", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "品質部", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "品質部", + "position": "作業員" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "製造部", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "製造部", + "position": "課長" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "製造部", + "position": "班長" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "製造部", + "position": "副班長" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "製造部", + "position": "作業員" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "廠務部(Fab3)", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "晶圓三廠", + "department": "廠務部(Fab3)", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程一部", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程一部", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程二部", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程二部", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程三部", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "工程三部", + "position": "工程師" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "製程整合部(Fab3)", + "position": "經副理" + }, + { + "business": "晶圓三廠", + "division": "製程工程處", + "department": "製程整合部(Fab3)", + "position": "工程師" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "製程整合部(Fab3)", + "position": "人資長" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "行政總務管理部", + "position": "經副理" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "行政總務管理部", + "position": "專員" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "行政總務管理部", + "position": "助理" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "招募任用部", + "position": "經副理" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "招募任用部", + "position": "專員" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "訓練發展部", + "position": "經副理" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "訓練發展部", + "position": "專員" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "薪酬管理部", + "position": "經副理" + }, + { + "business": "集團人資行政事業體", + "division": "集團人資行政事業體", + "department": "薪酬管理部", + "position": "專員" + }, + { + "business": "集團財務事業體", + "division": "集團財務事業體", + "department": "薪酬管理部", + "position": "財務長" + }, + { + "business": "集團財務事業體", + "division": "岡山強茂財務處", + "department": "岡山強茂財務部", + "position": "經副理" + }, + { + "business": "集團財務事業體", + "division": "岡山強茂財務處", + "department": "岡山強茂財務部", + "position": "課長" + }, + { + "business": "集團財務事業體", + "division": "岡山強茂財務處", + "department": "岡山強茂財務部", + "position": "專員" + }, + { + "business": "集團財務事業體", + "division": "集團財務事業體", + "department": "岡山強茂財務部", + "position": "專案副理" + }, + { + "business": "集團會計事業體", + "division": "集團會計事業體", + "department": "岡山強茂財務部", + "position": "會計長" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "會計部", + "position": "經副理" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "會計部", + "position": "課長" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "會計部", + "position": "專員" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "會計部", + "position": "課長" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "會計部", + "position": "專員" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "管理會計部", + "position": "經副理" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "管理會計部", + "position": "課長" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "管理會計部", + "position": "專員" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "管理會計部", + "position": "課長" + }, + { + "business": "集團會計事業體", + "division": "岡山會計處", + "department": "管理會計部", + "position": "專員" + }, + { + "business": "集團會計事業體", + "division": "集團會計處", + "department": "集團合併報表部", + "position": "經副理" + }, + { + "business": "集團會計事業體", + "division": "集團會計處", + "department": "集團合併報表部", + "position": "專員" + }, + { + "business": "集團資訊事業體", + "division": "集團資訊事業體", + "department": "集團合併報表部", + "position": "資訊長" + }, + { + "business": "集團資訊事業體", + "division": "資安行動小組", + "department": "集團合併報表部", + "position": "課長" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "應用系統部", + "position": "經副理" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "應用系統部", + "position": "工程師" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "電腦整合製造部", + "position": "經副理" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "電腦整合製造部", + "position": "工程師" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "系統網路服務部", + "position": "經副理" + }, + { + "business": "集團資訊事業體", + "division": "資訊一處", + "department": "系統網路服務部", + "position": "工程師" + }, + { + "business": "新創事業體", + "division": "新創事業體", + "department": "資源管理部", + "position": "經副理" + }, + { + "business": "新創事業體", + "division": "新創事業體", + "department": "資源管理部", + "position": "專員" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "經副理" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "專員" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "客戶品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "經副理" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "班長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "產品品質管理部", + "position": "作業員" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質系統及客戶工程整合部", + "position": "經副理" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質系統及客戶工程整合部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質系統及客戶工程整合部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質系統及客戶工程整合部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質系統及客戶工程整合部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "封測外包品質管理部", + "position": "經副理" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "封測外包品質管理部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "封測外包品質管理部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "經副理" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "班長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "副班長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "作業員" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "工程師" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "班長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "副班長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "作業員" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "課長" + }, + { + "business": "總品質事業體", + "division": "總品質事業體", + "department": "品質保證部", + "position": "工程師" + }, + { + "business": "營業事業體", + "division": "營業事業體", + "department": "品質保證部", + "position": "副總經理" + }, + { + "business": "營業事業體", + "division": "營業事業體", + "department": "品質保證部", + "position": "副總經理助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "日本區暨代工業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "歐亞區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "專案經理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "韓國區業務部-韓國區", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "美洲區業務部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "美洲區業務部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "美洲區業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "海外銷售事業處", + "department": "美洲區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "應用工程部(GTS)", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "應用工程部(GTS)", + "position": "專案經副理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "應用工程部(GTS)", + "position": "技術經副理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "應用工程部(GTS)", + "position": "工程師" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "系統工程部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "系統工程部", + "position": "工程師" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "特性測試部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "特性測試部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "全球技術服務處", + "department": "特性測試部", + "position": "工程師" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "業務生管部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "業務生管部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "業務生管部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "業務生管部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "業務生管部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "市場行銷企劃部", + "position": "處長" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "市場行銷企劃部", + "position": "經理" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "市場行銷企劃部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "市場行銷企劃部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "市場行銷企劃部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "MOSFET晶圓採購部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "MOSFET晶圓採購部", + "position": "課長" + }, + { + "business": "營業事業體", + "division": "全球行銷暨業務支援處", + "department": "MOSFET晶圓採購部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "台灣區業務部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "台灣區業務部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務一部", + "position": "處長/資深經理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務一部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務一部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務一部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "處長/資深經理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "助理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "經副理" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "專員" + }, + { + "business": "營業事業體", + "division": "大中華區銷售事業處", + "department": "業務二部", + "position": "助理" + } +]; diff --git a/index.html b/index.html index 737ab3d..bd6a826 100644 --- a/index.html +++ b/index.html @@ -25,7 +25,10 @@ })(); - + + + + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..5c8a43a --- /dev/null +++ b/js/main.js @@ -0,0 +1,201 @@ +/** + * Main - 主程式 + * 初始化應用程式,設定事件監聽器 + */ + +import { showToast } from './utils.js'; +import { switchModule, updatePreview, updateCategoryName, updateNatureName, updateJobCategoryName } from './ui.js'; + +// ==================== 初始化 ==================== + +/** + * 載入用戶信息 + */ +function loadUserInfo() { + const currentUser = localStorage.getItem('currentUser'); + if (!currentUser) { + return; + } + + try { + const userData = JSON.parse(currentUser); + const userName = document.getElementById('userName'); + const userRole = document.getElementById('userRole'); + const userAvatar = document.getElementById('userAvatar'); + + if (userName) userName.textContent = userData.name || '使用者'; + if (userRole) userRole.textContent = userData.role || '一般使用者'; + if (userAvatar) userAvatar.textContent = (userData.name || 'U').charAt(0).toUpperCase(); + } catch (e) { + console.error('解析用戶資料失敗:', e); + } +} + +/** + * 登出功能 + */ +function logout() { + if (confirm('確定要登出嗎?')) { + localStorage.removeItem('currentUser'); + window.location.href = 'login.html'; + } +} + +// ==================== 事件監聽器設置 ==================== + +/** + * 設置模組切換事件 + */ +function setupModuleSwitching() { + document.querySelectorAll('.module-btn').forEach(btn => { + btn.addEventListener('click', () => { + const moduleName = btn.dataset.module; + if (moduleName) { + switchModule(moduleName); + } + }); + }); +} + +/** + * 設置標籤頁切換事件 + */ +function setupTabSwitching() { + document.querySelectorAll('.tab-btn').forEach(btn => { + btn.addEventListener('click', () => { + const parent = btn.closest('.form-card'); + if (!parent) return; + + parent.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); + parent.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); + + btn.classList.add('active'); + const targetTab = document.getElementById('tab-' + btn.dataset.tab); + if (targetTab) { + targetTab.classList.add('active'); + } + }); + }); +} + +/** + * 設置表單欄位監聽 + */ +function setupFormListeners() { + // 監聽所有表單欄位變更,更新預覽 + document.querySelectorAll('input, select, textarea').forEach(field => { + field.addEventListener('change', updatePreview); + field.addEventListener('input', updatePreview); + }); + + // 崗位類別變更 + const positionCategory = document.getElementById('positionCategory'); + if (positionCategory) { + positionCategory.addEventListener('change', updateCategoryName); + } + + // 崗位性質變更 + const positionNature = document.getElementById('positionNature'); + if (positionNature) { + positionNature.addEventListener('change', updateNatureName); + } + + // 職務類別變更 + const jobCategoryCode = document.getElementById('jobCategoryCode'); + if (jobCategoryCode) { + jobCategoryCode.addEventListener('change', updateJobCategoryName); + } + + // Toggle 開關變更 + const hasAttendanceBonus = document.getElementById('hasAttendanceBonus'); + if (hasAttendanceBonus) { + hasAttendanceBonus.addEventListener('change', function() { + const label = document.getElementById('attendanceLabel'); + if (label) { + label.textContent = this.checked ? '是' : '否'; + } + updatePreview(); + }); + } + + const hasHousingAllowance = document.getElementById('hasHousingAllowance'); + if (hasHousingAllowance) { + hasHousingAllowance.addEventListener('change', function() { + const label = document.getElementById('housingLabel'); + if (label) { + label.textContent = this.checked ? '是' : '否'; + } + updatePreview(); + }); + } +} + +/** + * 設置快捷鍵 + */ +function setupKeyboardShortcuts() { + document.addEventListener('keydown', (e) => { + // Ctrl+S 或 Cmd+S: 保存當前模組 + if ((e.ctrlKey || e.metaKey) && e.key === 's') { + e.preventDefault(); + const activeModule = document.querySelector('.module-btn.active'); + if (!activeModule) return; + + const moduleName = activeModule.dataset.module; + if (moduleName === 'position' && typeof window.savePositionAndExit === 'function') { + window.savePositionAndExit(); + } else if (moduleName === 'job' && typeof window.saveJobAndExit === 'function') { + window.saveJobAndExit(); + } else if (moduleName === 'jobdesc' && typeof window.saveJobDescAndExit === 'function') { + window.saveJobDescAndExit(); + } else if (moduleName === 'deptfunction' && typeof window.saveDeptFunctionAndExit === 'function') { + window.saveDeptFunctionAndExit(); + } + } + + // Ctrl+N 或 Cmd+N: 保存並新增下一筆 + if ((e.ctrlKey || e.metaKey) && e.key === 'n') { + e.preventDefault(); + const activeModule = document.querySelector('.module-btn.active'); + if (!activeModule) return; + + const moduleName = activeModule.dataset.module; + if (moduleName === 'position' && typeof window.savePositionAndNew === 'function') { + window.savePositionAndNew(); + } else if (moduleName === 'job' && typeof window.saveJobAndNew === 'function') { + window.saveJobAndNew(); + } else if (moduleName === 'jobdesc' && typeof window.saveJobDescAndNew === 'function') { + window.saveJobDescAndNew(); + } else if (moduleName === 'deptfunction' && typeof window.saveDeptFunctionAndNew === 'function') { + window.saveDeptFunctionAndNew(); + } + } + }); +} + +// ==================== DOMContentLoaded 初始化 ==================== + +document.addEventListener('DOMContentLoaded', () => { + console.log('🚀 HR 系統初始化中...'); + + // 載入用戶信息 + loadUserInfo(); + + // 設置事件監聽器 + setupModuleSwitching(); + setupTabSwitching(); + setupFormListeners(); + setupKeyboardShortcuts(); + + // 初始化預覽 + updatePreview(); + + console.log('✅ HR 系統初始化完成'); +}); + +// ==================== 將函式掛載到 window ==================== + +if (typeof window !== 'undefined') { + window.logout = logout; + window.loadUserInfo = loadUserInfo; +} diff --git a/js/ui.js b/js/ui.js new file mode 100644 index 0000000..f2f8e76 --- /dev/null +++ b/js/ui.js @@ -0,0 +1,291 @@ +/** + * UI - UI 操作函式 + * 包含模組切換、預覽更新、表單資料收集 + */ + +import { showToast } from './utils.js'; +import { categoryMap, natureMap, jobCategoryMap } from './config.js'; + +// ==================== 模組切換 ==================== + +/** + * 切換頁面模組 + * @param {string} moduleName - 模組名稱(position/job/jobdesc/positionlist/deptfunction/admin) + */ +export function switchModule(moduleName) { + document.querySelectorAll('.module-btn').forEach(b => { + b.classList.remove('active', 'job-active', 'desc-active'); + }); + document.querySelectorAll('.module-content').forEach(c => c.classList.remove('active')); + + const targetBtn = document.querySelector(`.module-btn[data-module="${moduleName}"]`); + if (targetBtn) { + targetBtn.classList.add('active'); + if (moduleName === 'job') targetBtn.classList.add('job-active'); + if (moduleName === 'jobdesc') targetBtn.classList.add('desc-active'); + } + + const targetModule = document.getElementById('module-' + moduleName); + if (targetModule) { + targetModule.classList.add('active'); + } + + // 自動刷新崗位清單(需要從其他模組匯入) + if (moduleName === 'positionlist' && typeof window.loadPositionList === 'function') { + window.loadPositionList(); + } + + updatePreview(); +} + +// ==================== 表單資料收集 ==================== + +/** + * 收集崗位表單資料 + * @returns {Object} - 崗位資料(分為 basicInfo 和 recruitInfo) + */ +export function getPositionFormData() { + const form = document.getElementById('positionForm'); + const formData = new FormData(form); + const data = { basicInfo: {}, recruitInfo: {} }; + + const basicFields = ['positionCode', 'positionName', 'positionCategory', 'positionCategoryName', + 'positionNature', 'positionNatureName', 'headcount', 'positionLevel', + 'effectiveDate', 'positionDesc', 'positionRemark']; + const recruitFields = ['minEducation', 'requiredGender', 'salaryRange', 'workExperience', + 'minAge', 'maxAge', 'jobType', 'recruitPosition', 'jobTitle', 'jobDesc', + 'positionReq', 'titleReq', 'majorReq', 'skillReq', 'langReq', 'otherReq', + 'superiorPosition', 'recruitRemark']; + + basicFields.forEach(field => { + const value = formData.get(field); + if (value) data.basicInfo[field] = value; + }); + + recruitFields.forEach(field => { + const value = formData.get(field); + if (value) data.recruitInfo[field] = value; + }); + + return data; +} + +/** + * 收集職務表單資料 + * @returns {Object} - 職務資料 + */ +export function getJobFormData() { + const form = document.getElementById('jobForm'); + const formData = new FormData(form); + const data = {}; + + const fields = ['jobCategoryCode', 'jobCategoryName', 'jobCode', 'jobName', 'jobNameEn', + 'jobEffectiveDate', 'jobHeadcount', 'jobSortOrder', 'jobRemark', 'jobLevel']; + + fields.forEach(field => { + const value = formData.get(field); + if (value) data[field] = value; + }); + + data.hasAttendanceBonus = document.getElementById('hasAttendanceBonus').checked; + data.hasHousingAllowance = document.getElementById('hasHousingAllowance').checked; + + return data; +} + +/** + * 收集崗位描述表單資料 + * @returns {Object} - 崗位描述資料 + */ +export function getJobDescFormData() { + const form = document.getElementById('jobDescForm'); + if (!form) return {}; + + const formData = new FormData(form); + const data = { basicInfo: {}, positionInfo: {}, responsibilities: {}, requirements: {} }; + + // Basic Info + ['empNo', 'empName', 'positionCode', 'versionDate'].forEach(field => { + const el = document.getElementById('jd_' + field); + if (el && el.value) data.basicInfo[field] = el.value; + }); + + // Position Info + ['positionName', 'department', 'positionEffectiveDate', 'directSupervisor', + 'positionGradeJob', 'reportTo', 'directReports', 'workLocation', 'empAttribute'].forEach(field => { + const el = document.getElementById('jd_' + field); + if (el && el.value) data.positionInfo[field] = el.value; + }); + + // Purpose & Responsibilities + const purpose = document.getElementById('jd_positionPurpose'); + if (purpose && purpose.value) data.responsibilities.positionPurpose = purpose.value; + + const mainResp = document.getElementById('jd_mainResponsibilities'); + if (mainResp && mainResp.value) data.responsibilities.mainResponsibilities = mainResp.value; + + // Requirements + ['education', 'basicSkills', 'professionalKnowledge', 'workExperienceReq', 'otherRequirements'].forEach(field => { + const el = document.getElementById('jd_' + field); + if (el && el.value) data.requirements[field] = el.value; + }); + + return data; +} + +/** + * 收集部門職責表單資料 + * @returns {Object} - 部門職責資料 + */ +export function getDeptFunctionFormData() { + const form = document.getElementById('deptFunctionForm'); + if (!form) return {}; + + const formData = new FormData(form); + const data = {}; + + const fields = ['deptFunctionCode', 'deptFunctionName', 'deptFunctionBU', + 'deptFunctionDept', 'deptManager', 'deptMission', 'deptVision', + 'deptCoreFunctions', 'deptKPIs']; + + fields.forEach(field => { + const value = formData.get(field); + if (value) data[field] = value; + }); + + return data; +} + +// ==================== 預覽更新 ==================== + +/** + * 更新 JSON 預覽 + */ +export function updatePreview() { + const activeBtn = document.querySelector('.module-btn.active'); + if (!activeBtn) return; + + const activeModule = activeBtn.dataset.module; + let data; + + if (activeModule === 'position') { + data = { module: '崗位基礎資料', ...getPositionFormData() }; + } else if (activeModule === 'job') { + data = { module: '職務基礎資料', ...getJobFormData() }; + } else if (activeModule === 'jobdesc') { + data = { module: '崗位描述', ...getJobDescFormData() }; + } else if (activeModule === 'deptfunction') { + data = { module: '部門職責', ...getDeptFunctionFormData() }; + } else { + return; // 其他模組不顯示預覽 + } + + const previewEl = document.getElementById('jsonPreview'); + if (previewEl) { + previewEl.textContent = JSON.stringify(data, null, 2); + } +} + +// ==================== 表單邏輯輔助函式 ==================== + +/** + * 更新崗位類別中文名稱 + */ +export function updateCategoryName() { + const category = document.getElementById('positionCategory').value; + document.getElementById('positionCategoryName').value = categoryMap[category] || ''; + updatePreview(); +} + +/** + * 更新崗位性質中文名稱 + */ +export function updateNatureName() { + const nature = document.getElementById('positionNature').value; + document.getElementById('positionNatureName').value = natureMap[nature] || ''; + updatePreview(); +} + +/** + * 更新職務類別中文名稱 + */ +export function updateJobCategoryName() { + const category = document.getElementById('jobCategoryCode').value; + document.getElementById('jobCategoryName').value = jobCategoryMap[category] || ''; + updatePreview(); +} + +/** + * 修改崗位編號 + */ +export function changePositionCode() { + const currentCode = document.getElementById('positionCode').value; + const newCode = prompt('請輸入新的崗位編號:', currentCode); + if (newCode && newCode !== currentCode) { + document.getElementById('positionCode').value = newCode; + showToast('崗位編號已更改!'); + updatePreview(); + } +} + +/** + * 修改職務編號 + */ +export function changeJobCode() { + const currentCode = document.getElementById('jobCode').value; + const newCode = prompt('請輸入新的職務編號:', currentCode); + if (newCode && newCode !== currentCode) { + document.getElementById('jobCode').value = newCode; + showToast('職務編號已更改!'); + updatePreview(); + } +} + +// ==================== 模態框函式(待整合)==================== + +/** + * 開啟專業科目選擇模態框 + */ +export function openMajorModal() { + const modal = document.getElementById('majorModal'); + if (modal) { + modal.classList.add('show'); + } +} + +/** + * 關閉專業科目選擇模態框 + */ +export function closeMajorModal() { + const modal = document.getElementById('majorModal'); + if (modal) { + modal.classList.remove('show'); + } +} + +/** + * 確認選擇專業科目 + */ +export function confirmMajor() { + const selected = []; + document.querySelectorAll('#majorModal input[type="checkbox"]:checked').forEach(cb => { + selected.push(cb.value); + }); + document.getElementById('majorReq').value = selected.join(', '); + closeMajorModal(); + updatePreview(); +} + +// 將函式掛載到 window 上以便內聯事件處理器使用 +if (typeof window !== 'undefined') { + window.switchModule = switchModule; + window.updateCategoryName = updateCategoryName; + window.updateNatureName = updateNatureName; + window.updateJobCategoryName = updateJobCategoryName; + window.changePositionCode = changePositionCode; + window.changeJobCode = changeJobCode; + window.openMajorModal = openMajorModal; + window.closeMajorModal = closeMajorModal; + window.confirmMajor = confirmMajor; + window.updatePreview = updatePreview; +} diff --git a/llm_config.py b/llm_config.py index 9f7efa2..a2e35df 100644 --- a/llm_config.py +++ b/llm_config.py @@ -7,6 +7,10 @@ import os import requests from dotenv import load_dotenv from typing import Dict, List, Tuple +import urllib3 + +# Disable SSL warnings for Ollama endpoint +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # Load environment variables load_dotenv() @@ -34,6 +38,20 @@ class LLMConfig: 'api_key': os.getenv('OPENAI_API_KEY', ''), 'endpoint': os.getenv('OPENAI_API_URL', 'https://api.openai.com/v1'), 'enabled': bool(os.getenv('OPENAI_API_KEY')) + }, + 'ollama': { + 'name': 'Ollama', + 'api_key': '', # Ollama 不需要 API Key + 'endpoint': os.getenv('OLLAMA_API_URL', 'https://ollama_pjapi.theaken.com'), + 'model': os.getenv('OLLAMA_MODEL', 'qwen2.5:3b'), + 'enabled': True # Ollama 預設啟用 + }, + 'gptoss': { + 'name': 'GPT-OSS', + 'api_key': '', # GPT-OSS 不需要 API Key (使用 Ollama 介面) + 'endpoint': os.getenv('GPTOSS_API_URL', 'https://ollama_pjapi.theaken.com'), + 'model': os.getenv('GPTOSS_MODEL', 'gpt-oss:120b'), + 'enabled': True # GPT-OSS 預設啟用 } } @@ -153,6 +171,35 @@ class LLMConfig: except Exception as e: return False, f"錯誤: {str(e)}" + def test_ollama_connection(self) -> Tuple[bool, str]: + """Test Ollama API connection""" + try: + endpoint = self.apis['ollama']['endpoint'] + + # Test endpoint - list models + url = f"{endpoint}/v1/models" + + response = requests.get(url, timeout=10, verify=False) + + if response.status_code == 200: + data = response.json() + models = data.get('data', []) + if models: + model_count = len(models) + model_names = [m.get('id', '') for m in models[:3]] + return True, f"連線成功!找到 {model_count} 個可用模型 (例如: {', '.join(model_names)})" + else: + return True, "連線成功!" + else: + return False, f"連線失敗 (HTTP {response.status_code})" + + except requests.exceptions.Timeout: + return False, "連線逾時" + except requests.exceptions.ConnectionError: + return False, "無法連接到伺服器" + except Exception as e: + return False, f"錯誤: {str(e)}" + def test_all_connections(self) -> Dict[str, Tuple[bool, str]]: """Test all configured API connections""" results = {} @@ -166,6 +213,9 @@ class LLMConfig: if self.apis['openai']['enabled']: results['openai'] = self.test_openai_connection() + if self.apis['ollama']['enabled']: + results['ollama'] = self.test_ollama_connection() + return results def generate_text_gemini(self, prompt: str, max_tokens: int = 2000) -> Tuple[bool, str]: @@ -175,7 +225,9 @@ class LLMConfig: if not api_key: return False, "API Key 未設定" - url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={api_key}" + # 從環境變數讀取模型名稱,默認使用 gemini-1.5-flash + model_name = os.getenv('GEMINI_MODEL', 'gemini-1.5-flash') + url = f"https://generativelanguage.googleapis.com/v1beta/models/{model_name}:generateContent?key={api_key}" data = { "contents": [ @@ -275,6 +327,86 @@ class LLMConfig: except Exception as e: return False, f"錯誤: {str(e)}" + def generate_text_ollama(self, prompt: str, max_tokens: int = 2000, model: str = None) -> Tuple[bool, str]: + """Generate text using Ollama API + + Args: + prompt: The prompt text + max_tokens: Maximum tokens to generate (not used by Ollama but kept for compatibility) + model: The model to use. If None, uses the default from config. + """ + try: + endpoint = self.apis['ollama']['endpoint'] + # 使用傳入的 model 參數,如果沒有則使用設定檔中的預設值 + if model is None: + model = self.apis['ollama']['model'] + + url = f"{endpoint}/v1/chat/completions" + headers = { + 'Content-Type': 'application/json' + } + + data = { + "model": model, + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": prompt} + ], + "temperature": 0.7 + } + + response = requests.post(url, json=data, headers=headers, timeout=60, verify=False) + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + return True, text + else: + return False, f"生成失敗 (HTTP {response.status_code}): {response.text}" + + except Exception as e: + return False, f"錯誤: {str(e)}" + + def generate_text_gptoss(self, prompt: str, max_tokens: int = 2000, model: str = None) -> Tuple[bool, str]: + """Generate text using GPT-OSS API (120B model via Ollama interface) + + Args: + prompt: The prompt text + max_tokens: Maximum tokens to generate (not used by Ollama but kept for compatibility) + model: The model to use. If None, uses the default from config. + """ + try: + endpoint = self.apis['gptoss']['endpoint'] + # 使用傳入的 model 參數,如果沒有則使用設定檔中的預設值 + if model is None: + model = self.apis['gptoss']['model'] + + url = f"{endpoint}/v1/chat/completions" + headers = { + 'Content-Type': 'application/json' + } + + data = { + "model": model, + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": prompt} + ], + "temperature": 0.7 + } + + response = requests.post(url, json=data, headers=headers, timeout=60, verify=False) + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + return True, text + else: + return False, f"生成失敗 (HTTP {response.status_code}): {response.text}" + + except Exception as e: + return False, f"錯誤: {str(e)}" + def main(): """Test script""" diff --git a/login.html b/login.html new file mode 100644 index 0000000..c3748e3 --- /dev/null +++ b/login.html @@ -0,0 +1,471 @@ + + + + + + 那都AI寫的,不要問我 - 登入 + + + +
+
+
+ System Logo +
+

那都AI寫的,不要問我

+

HR Position Management System

+
+ +
+
+
+ + +
+ +
+ + +
+ + +
+ +
+ 或使用測試帳號快速登入 +
+ + + + +
+
+ + + + diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..e505c2c --- /dev/null +++ b/logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? + ? + + + AI + \ No newline at end of file diff --git a/ollama_response.txt b/ollama_response.txt new file mode 100644 index 0000000..04237fe --- /dev/null +++ b/ollama_response.txt @@ -0,0 +1 @@ +你好!謝謝你的問候。作為一個人工智能助手,我沒有情緒或身體感受,但我的程式運行得很順利,隨時準備為你提供幫助~ 你呢?今天過得如何?有什麼我可以為你解答的嗎? 😊 \ No newline at end of file diff --git a/prompt.md b/prompt.md new file mode 100644 index 0000000..a211837 --- /dev/null +++ b/prompt.md @@ -0,0 +1,758 @@ +# HR 崗位管理系統 - AI 生成功能 Prompt 說明文件 + +> **文件版本**: v1.0 +> **最後更新**: 2024-12-04 +> **維護者**: AI(所以有問題真的不要問我) + +--- + +## 📋 目錄 + +1. [總覽](#總覽) +2. [頁籤 1: 崗位基礎資料維護](#頁籤-1-崗位基礎資料維護) +3. [頁籤 2: 崗位招聘要求](#頁籤-2-崗位招聘要求) +4. [頁籤 3: 職務基礎資料](#頁籤-3-職務基礎資料) +5. [頁籤 4: 部門職責維護](#頁籤-4-部門職責維護) +6. [頁籤 5: 崗位描述 (JD)](#頁籤-5-崗位描述-jd) +7. [如何修改 Prompt](#如何修改-prompt) +8. [Prompt 設計原則](#prompt-設計原則) + +--- + +## 總覽 + +系統中共有 **5 個頁籤**提供 AI 自動生成功能,每個頁籤都有一個 "✨ I'm feeling lucky" 按鈕。 + +### 🎯 核心運作原理 + +1. **智能空白檢測**: 系統會檢測哪些欄位是空白的 +2. **上下文感知**: 將已填寫的欄位作為上下文傳給 LLM +3. **精準生成**: 只生成尚未填寫的欄位 +4. **JSON 格式回傳**: 要求 LLM 返回結構化的 JSON 資料 +5. **自動填充**: 解析 JSON 並填入對應欄位 + +### 🔗 對應函式與程式碼位置 + +| 頁籤名稱 | 函式名稱 | 程式碼位置 | 按鈕 ID/onclick | +|---------|---------|-----------|----------------| +| 崗位基礎資料維護 | `generatePositionBasic()` | [index.html:2179](index.html#L2179) | `onclick="generatePositionBasic()"` | +| 崗位招聘要求 | `generatePositionRecruit()` | [index.html:2253](index.html#L2253) | `onclick="generatePositionRecruit()"` | +| 職務基礎資料 | `generateJobBasic()` | [index.html:2330](index.html#L2330) | `onclick="generateJobBasic()"` | +| 部門職責維護 | `generateDeptFunction()` | [index.html:3778](index.html#L3778) | `onclick="generateDeptFunction()"` | +| 崗位描述 (JD) | `generateJobDesc()` | [index.html:2425](index.html#L2425) | `onclick="generateJobDesc()"` | + +--- + +## 頁籤 1: 崗位基礎資料維護 + +### 📍 函式位置 +- **檔案**: `index.html` +- **行數**: 2179-2251 +- **函式**: `async function generatePositionBasic()` + +### 📝 完整 Prompt + +``` +請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 + +[如果有已填寫的資料,會附加此段] +已填寫的資料(請參考這些內容來生成相關的資料): +{JSON格式的已填寫資料} + +請「只生成」以下這些尚未填寫的欄位:[動態欄位列表] + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001, MGR-002, SAL-003) +- positionName: 崗位名稱 +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +- positionNature: 崗位性質代碼(FT=全職, PT=兼職, CT=約聘, IN=實習) +- headcount: 編制人數(1-10之間的數字字串) +- positionLevel: 崗位級別(L1到L7) +- positionDesc: 崗位描述(2-3句話描述工作內容) +- positionRemark: 崗位備注(可選的補充說明) + +請直接返回JSON格式,只包含需要生成的欄位,不要有任何其他文字: +{ + "positionCode": "...", + "positionName": "...", + ... +} +``` + +### 🎯 Prompt 設計依據 + +1. **上下文感知**: 如果使用者已填寫部分欄位,這些資料會被傳入作為參考 +2. **精準指令**: 明確告知只生成「尚未填寫」的欄位,避免覆蓋已有資料 +3. **格式規範**: 提供詳細的欄位格式說明和代碼對照表 +4. **結構化輸出**: 要求返回純 JSON,方便程式解析 + +### 📦 處理的欄位 + +```javascript +const allFields = [ + 'positionCode', // 崗位編號 + 'positionName', // 崗位名稱 + 'positionCategory', // 崗位類別代碼 + 'positionNature', // 崗位性質代碼 + 'headcount', // 編制人數 + 'positionLevel', // 崗位級別 + 'positionDesc', // 崗位描述 + 'positionRemark' // 崗位備注 +]; +``` + +### 🔧 如何修改此 Prompt + +在 [index.html:2205-2223](index.html#L2205) 找到以下程式碼: + +```javascript +const prompt = `請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 +${contextInfo} + +請「只生成」以下這些尚未填寫的欄位:${emptyFields.join(', ')} + +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001, MGR-002, SAL-003) +... +`; +``` + +**修改建議**: +- 如果要改變生成風格:修改第一句的指令(例如:「請以專業正式的語氣生成...」) +- 如果要新增欄位規則:在「欄位說明」中添加新的規範 +- 如果要調整格式:修改格式範例(如改變編號規則) + +--- + +## 頁籤 2: 崗位招聘要求 + +### 📍 函式位置 +- **檔案**: `index.html` +- **行數**: 2253-2328 +- **函式**: `async function generatePositionRecruit()` + +### 📝 完整 Prompt + +``` +請為HR崗位管理系統生成「{崗位名稱}」的招聘要求資料。請用繁體中文回覆。 + +已填寫的資料(請參考這些內容來生成相關的資料): +{JSON格式的已填寫資料,包含 positionName} + +請「只生成」以下這些尚未填寫的欄位:[動態欄位列表] + +欄位說明: +- minEducation: 最低學歷代碼(HS=高中職, JC=專科, BA=大學, MA=碩士, PHD=博士) +- requiredGender: 要求性別(空字串=不限, M=男, F=女) +- salaryRange: 薪酬范圍代碼(A=30000以下, B=30000-50000, C=50000-80000, D=80000-120000, E=120000以上, N=面議) +- workExperience: 工作經驗年數(0=不限, 1, 3, 5, 10) +- minAge: 最小年齡(18-30之間的數字字串) +- maxAge: 最大年齡(35-55之間的數字字串) +- jobType: 工作性質代碼(FT=全職, PT=兼職, CT=約聘, DP=派遣) +- recruitPosition: 招聘職位代碼(ENG=工程師, MGR=經理, AST=助理, OP=作業員, SAL=業務) +- jobTitle: 職位名稱 +- jobDesc: 職位描述(2-3句話) +- positionReq: 崗位要求(條列式,用換行分隔) +- skillReq: 技能要求(用逗號分隔) +- langReq: 語言要求 +- otherReq: 其他要求 + +請直接返回JSON格式,只包含需要生成的欄位: +{ + "minEducation": "...", + ... +} +``` + +### 🎯 Prompt 設計依據 + +1. **職位名稱作為核心上下文**: 使用第一個頁籤的崗位名稱作為生成依據 +2. **跨頁籤資料引用**: 會從「崗位基礎資料」頁籤讀取 `positionName` +3. **招聘專用代碼**: 提供完整的學歷、薪資、經驗等代碼對照 + +### 📦 處理的欄位 + +```javascript +const allFields = [ + 'minEducation', // 最低學歷 + 'requiredGender', // 要求性別 + 'salaryRange', // 薪酬范圍 + 'workExperience', // 工作經驗年數 + 'minAge', // 最小年齡 + 'maxAge', // 最大年齡 + 'jobType', // 工作性質 + 'recruitPosition', // 招聘職位 + 'jobTitle', // 職位名稱 + 'jobDesc', // 職位描述 + 'positionReq', // 崗位要求 + 'skillReq', // 技能要求 + 'langReq', // 語言要求 + 'otherReq' // 其他要求 +]; +``` + +### 🔧 如何修改此 Prompt + +在 [index.html:2275-2301](index.html#L2275) 找到程式碼。 + +**修改建議**: +- **調整薪資範圍**: 修改 `salaryRange` 的代碼對照(例如增加更高薪資級別) +- **新增性別選項**: 如果需要更多性別選項,在 `requiredGender` 中添加 +- **調整經驗年限**: 修改 `workExperience` 的可用選項 + +--- + +## 頁籤 3: 職務基礎資料 + +### 📍 函式位置 +- **檔案**: `index.html` +- **行數**: 2330-2423 +- **函式**: `async function generateJobBasic()` + +### 📝 完整 Prompt + +``` +請為HR職務管理系統生成職務基礎資料。請用繁體中文回覆。 + +[如果有已填寫的資料,會附加此段] +已填寫的資料(請參考這些內容來生成相關的資料): +{JSON格式的已填寫資料} + +請「只生成」以下這些尚未填寫的欄位:[動態欄位列表,可能包含 checkbox] + +欄位說明: +- jobCategoryCode: 職務類別代碼(MGR=管理職, TECH=技術職, SALE=業務職, ADMIN=行政職, RD=研發職, PROD=生產職) +- jobCode: 職務編號(格式如 MGR-001, TECH-002) +- jobName: 職務名稱 +- jobNameEn: 職務英文名稱 +- jobHeadcount: 編制人數(1-20之間的數字字串) +- jobSortOrder: 排列順序(10, 20, 30...的數字字串) +- jobRemark: 備注說明 +- jobLevel: 職務層級(可以是 *保密* 或具體層級) +- hasAttendanceBonus: 是否有全勤(true/false) +- hasHousingAllowance: 是否住房補貼(true/false) + +請直接返回JSON格式,只包含需要生成的欄位: +{ + "jobCategoryCode": "...", + ... +} +``` + +### 🎯 Prompt 設計依據 + +1. **職務 vs 崗位**: 這個頁籤處理的是「職務」(Job),與「崗位」(Position)不同 +2. **Checkbox 處理**: 特殊處理 `hasAttendanceBonus` 和 `hasHousingAllowance` 兩個布林值欄位 +3. **排序欄位**: `jobSortOrder` 使用 10 的倍數,方便後續插入新職務 + +### 📦 處理的欄位 + +```javascript +const allFields = [ + 'jobCategoryCode', // 職務類別代碼 + 'jobCode', // 職務編號 + 'jobName', // 職務名稱 + 'jobNameEn', // 職務英文名稱 + 'jobHeadcount', // 編制人數 + 'jobSortOrder', // 排列順序 + 'jobRemark', // 備注說明 + 'jobLevel' // 職務層級 +]; + +// 額外處理的 checkbox +const checkboxes = [ + 'hasAttendanceBonus', // 是否有全勤 + 'hasHousingAllowance' // 是否住房補貼 +]; +``` + +### 🔧 如何修改此 Prompt + +在 [index.html:2362-2382](index.html#L2362) 找到程式碼。 + +**修改建議**: +- **新增職務類別**: 在 `jobCategoryCode` 中添加新的類別代碼 +- **調整編號格式**: 修改 `jobCode` 的格式範例 +- **修改保密設定**: 調整 `jobLevel` 的說明(如不允許保密) + +--- + +## 頁籤 4: 部門職責維護 + +### 📍 函式位置 +- **檔案**: `index.html` +- **行數**: 3778-3839 +- **函式**: `function generateDeptFunction()` + +### 📝 完整 Prompt + +``` +請為HR部門職責管理系統生成部門職責資料。請用繁體中文回覆。 + +[如果有已填寫的資料,會附加此段] +已填寫的資料(請參考這些內容來生成相關的資料): +{JSON格式的已填寫資料} + +請「只生成」以下這些尚未填寫的欄位:[動態欄位列表] + +欄位說明: +- deptFunctionCode: 部門職責編號(格式如 DF-001, DF-002) +- deptFunctionName: 部門職責名稱(例如:軟體研發部職責) +- deptFunctionBU: 事業體代碼(SBU/MBU/HQBU/ITBU/HRBU/ACCBU 之一) +- deptFunctionDept: 部門名稱 +- deptManager: 部門主管職稱 +- deptMission: 部門使命(使用「•」開頭的條列式,2-3項) +- deptVision: 部門願景(使用「•」開頭的條列式,1-2項) +- deptCoreFunctions: 核心職責(使用「•」開頭的條列式,4-6項) +- deptKPIs: 關鍵績效指標(使用「•」開頭的條列式,3-4項) + +請直接返回JSON格式,只包含需要生成的欄位,不要有任何其他文字: +{ + "deptFunctionCode": "...", + ... +} +``` + +### 🎯 Prompt 設計依據 + +1. **條列式格式**: 特別要求使用 `•` 開頭的條列式,符合部門職責文件慣例 +2. **數量控制**: 明確指定每個欄位的條列項目數量(例如使命 2-3 項) +3. **事業體代碼**: 提供固定的事業體代碼選項 +4. **管理導向**: 專注於部門管理層面的使命、願景、職責、KPI + +### 📦 處理的欄位 + +```javascript +const allFields = [ + 'deptFunctionCode', // 部門職責編號 + 'deptFunctionName', // 部門職責名稱 + 'deptFunctionBU', // 事業體代碼 + 'deptFunctionDept', // 部門名稱 + 'deptManager', // 部門主管職稱 + 'deptMission', // 部門使命(條列式) + 'deptVision', // 部門願景(條列式) + 'deptCoreFunctions', // 核心職責(條列式) + 'deptKPIs' // 關鍵績效指標(條列式) +]; +``` + +### 🔧 如何修改此 Prompt + +在 [index.html:3800-3819](index.html#L3800) 找到程式碼。 + +**修改建議**: +- **新增事業體**: 在 `deptFunctionBU` 中添加新的事業體代碼 +- **調整條列數量**: 修改各欄位的條列項目數量要求 +- **改變條列符號**: 將 `•` 改為其他符號(如 `1.`, `-`, `★`) + +--- + +## 頁籤 5: 崗位描述 (JD) + +### 📍 函式位置 +- **檔案**: `index.html` +- **行數**: 2425-2541 +- **函式**: `async function generateJobDesc()` + +### 📝 完整 Prompt + +``` +請為HR崗位描述管理系統生成崗位描述資料。請用繁體中文回覆。 + +[如果有已填寫的資料,會附加此段] +已填寫的資料(請參考這些內容來生成相關的資料): +{JSON格式的已填寫資料,欄位名稱已移除 jd_ 前綴} + +請「只生成」以下這些尚未填寫的欄位:[動態欄位列表] + +欄位說明: +- empNo: 工號(格式如 A001234) +- empName: 員工姓名 +- positionCode: 崗位代碼 +- versionDate: 版本日期(YYYY-MM-DD格式) +- positionName: 崗位名稱 +- department: 所屬部門 +- positionEffectiveDate: 崗位生效日期(YYYY-MM-DD格式) +- directSupervisor: 直接領導職務 +- directReports: 直接下級(格式如「工程師 x 5人」) +- workLocation: 任職地點代碼(HQ=總部, TPE=台北, TYC=桃園, KHH=高雄, SH=上海, SZ=深圳) +- empAttribute: 員工屬性代碼(FT=正式員工, CT=約聘, PT=兼職, IN=實習, DP=派遣) +- positionPurpose: 崗位設置目的(1句話說明) +- mainResponsibilities: 主要崗位職責(用「1、」「2、」「3、」「4、」「5、」格式,每項換行,用\n分隔) +- education: 教育程度要求 +- basicSkills: 基本技能要求 +- professionalKnowledge: 專業知識要求 +- workExperienceReq: 工作經驗要求 +- otherRequirements: 其他要求 + +請直接返回JSON格式,只包含需要生成的欄位: +{ + "empNo": "...", + ... +} +``` + +### 🎯 Prompt 設計依據 + +1. **最複雜的表單**: 包含最多欄位(18 個),涵蓋完整的 JD 內容 +2. **日期格式規範**: 明確要求 YYYY-MM-DD 格式 +3. **職責編號格式**: 特別指定使用「1、」「2、」格式,並用 `\n` 換行 +4. **地點代碼對照**: 提供台灣與中國大陸的辦公室代碼 +5. **欄位名稱映射**: 程式中會將 `jd_` 前綴移除後再傳給 API + +### 📦 處理的欄位 + +```javascript +const allFields = [ + 'jd_empNo', // 工號 + 'jd_empName', // 員工姓名 + 'jd_positionCode', // 崗位代碼 + 'jd_versionDate', // 版本日期 + 'jd_positionName', // 崗位名稱 + 'jd_department', // 所屬部門 + 'jd_positionEffectiveDate', // 崗位生效日期 + 'jd_directSupervisor', // 直接領導職務 + 'jd_directReports', // 直接下級 + 'jd_workLocation', // 任職地點 + 'jd_empAttribute', // 員工屬性 + 'jd_positionPurpose', // 崗位設置目的 + 'jd_mainResponsibilities', // 主要崗位職責 + 'jd_education', // 教育程度要求 + 'jd_basicSkills', // 基本技能要求 + 'jd_professionalKnowledge', // 專業知識要求 + 'jd_workExperienceReq', // 工作經驗要求 + 'jd_otherRequirements' // 其他要求 +]; +``` + +### 🔧 如何修改此 Prompt + +在 [index.html:2464-2492](index.html#L2464) 找到程式碼。 + +**特別注意**: 這個模組有欄位名稱映射機制([index.html:2499-2518](index.html#L2499)),修改欄位時需要同時更新 `fieldMapping` 物件。 + +**修改建議**: +- **新增辦公室地點**: 在 `workLocation` 中添加新的辦公室代碼 +- **調整職責數量**: 修改 `mainResponsibilities` 的編號範圍(如改為 1-10) +- **新增員工屬性**: 在 `empAttribute` 中添加新的員工類型 + +--- + +## 如何修改 Prompt + +### 📝 通用修改步驟 + +所有 "I'm Feeling Lucky" 按鈕的 Prompt 都遵循相同的修改流程: + +#### 步驟 1: 找到對應函式 + +使用上方表格找到要修改的函式位置,例如: +``` +崗位基礎資料維護 → index.html:2179 +``` + +#### 步驟 2: 找到 prompt 變數 + +在函式中搜尋 `const prompt =` 或 `const prompt = \``: +```javascript +const prompt = `請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 +... +`; +``` + +#### 步驟 3: 修改 Prompt 內容 + +根據需求修改: + +**A. 修改生成風格** +```javascript +// 修改前 +const prompt = `請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 + +// 修改後(加入語氣要求) +const prompt = `請以專業正式且友善的語氣,為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 +``` + +**B. 修改欄位說明** +```javascript +// 修改前 +- positionCode: 崗位編號(格式如 ENG-001, MGR-002, SAL-003) + +// 修改後(改變編號規則) +- positionCode: 崗位編號(格式:部門縮寫-年份-流水號,如 ENG-2024-001) +``` + +**C. 新增欄位規則** +```javascript +// 在「欄位說明」區塊新增 +- positionPriority: 優先級(HIGH=高, MID=中, LOW=低) +``` + +**D. 調整輸出格式** +```javascript +// 修改前 +請直接返回JSON格式,只包含需要生成的欄位,不要有任何其他文字: + +// 修改後(要求更多資訊) +請直接返回JSON格式,只包含需要生成的欄位。每個欄位請加上「_note」後綴提供生成理由: +{ + "positionCode": "ENG-001", + "positionCode_note": "根據技術職的慣例生成", + ... +} +``` + +#### 步驟 4: 測試修改結果 + +1. 儲存 `index.html` 檔案 +2. 重新整理瀏覽器頁面(Ctrl+F5 強制重新整理) +3. 點擊對應頁籤的 "✨ I'm feeling lucky" 按鈕 +4. 檢查生成的內容是否符合預期 + +### ⚠️ 修改時的注意事項 + +1. **保持 JSON 格式要求**: 必須要求 LLM 返回純 JSON,否則程式解析會失敗 +2. **不要移除欄位動態列表**: `${emptyFields.join(', ')}` 這段必須保留 +3. **維持上下文機制**: `${contextInfo}` 這段是自動填入已有資料的機制,不要刪除 +4. **注意反引號**: Prompt 使用反引號 `` ` `` 包裹,內部不可再使用反引號 +5. **測試跨欄位引用**: 有些頁籤會引用其他頁籤的資料(如招聘要求引用崗位名稱) + +--- + +## Prompt 設計原則 + +### 🎨 系統採用的 Prompt 設計原則 + +#### 1. **智能空白檢測** +```javascript +const emptyFields = getEmptyFields(allFields); +``` +- 只生成尚未填寫的欄位 +- 避免覆蓋使用者已輸入的資料 +- 提升生成效率 + +#### 2. **上下文感知生成** +```javascript +const contextInfo = Object.keys(existingData).length > 0 + ? `\n\n已填寫的資料(請參考這些內容來生成相關的資料):\n${JSON.stringify(existingData, null, 2)}` + : ''; +``` +- 將已填寫的資料作為上下文 +- 讓 LLM 生成與現有資料一致的內容 +- 提升資料連貫性 + +#### 3. **結構化輸出** +```javascript +const prompt = `... +請直接返回JSON格式,只包含需要生成的欄位,不要有任何其他文字: +{ + ${emptyFields.map(f => `"${f}": "..."`).join(',\n ')} +}`; +``` +- 要求 LLM 返回純 JSON +- 提供 JSON 格式範本 +- 方便程式解析 + +#### 4. **詳細的欄位說明** +```javascript +欄位說明: +- positionCode: 崗位編號(格式如 ENG-001, MGR-002, SAL-003) +- positionCategory: 崗位類別代碼(01=技術職, 02=管理職, 03=業務職, 04=行政職) +``` +- 提供完整的代碼對照表 +- 說明格式規範和範例 +- 減少生成錯誤 + +#### 5. **繁體中文優先** +```javascript +const prompt = `請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 +``` +- 明確要求使用繁體中文 +- 避免出現簡體字或英文 + +### 🚀 進階 Prompt 技巧 + +#### 技巧 1: 加入企業特色 +```javascript +// 在 prompt 開頭加入 +const prompt = `你是一位專業的HR顧問,熟悉台灣半導體產業的人力資源管理。 +請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。 +``` + +#### 技巧 2: 加入範例 +```javascript +// 在欄位說明後加入 +生成範例: +{ + "positionCode": "ENG-001", + "positionName": "前端工程師", + "positionDesc": "負責開發和維護公司網站前端功能,提升使用者體驗。" +} + +請參考以上範例,生成類似格式的資料。 +``` + +#### 技巧 3: 加入條件邏輯 +```javascript +// 根據職位類型調整 prompt +const isManagerPosition = existingData.positionCategory === '02'; +const extraInstruction = isManagerPosition + ? '\n特別注意:這是管理職,請強調領導能力和團隊管理經驗。' + : ''; + +const prompt = `請為HR崗位管理系統生成崗位基礎資料。請用繁體中文回覆。${extraInstruction} +``` + +#### 技巧 4: 加入驗證規則 +```javascript +const prompt = `... +請確保生成的資料符合以下規則: +1. 崗位編號必須以部門代碼開頭 +2. 編制人數必須為正整數 +3. 崗位描述長度在 20-100 字之間 +4. 所有代碼必須從提供的選項中選擇 +...`; +``` + +--- + +## 🔍 偵錯與問題排查 + +### 常見問題 1: LLM 返回格式錯誤 + +**現象**: 點擊按鈕後出現「生成失敗,請稍後再試」 + +**可能原因**: +- LLM 返回的不是純 JSON 格式 +- JSON 中包含多餘的文字說明 +- JSON 格式不正確(缺少逗號、括號等) + +**解決方法**: +在 Prompt 中加強格式要求: +```javascript +const prompt = `... +請直接返回JSON格式,不要包含任何markdown標記(如 \`\`\`json),不要有任何其他文字說明: +{ + ${emptyFields.map(f => `"${f}": "..."`).join(',\n ')} +}`; +``` + +### 常見問題 2: 生成內容不符合預期 + +**現象**: 生成的內容格式正確,但內容不理想 + +**解決方法**: +1. 檢查上下文資料是否正確傳遞 +2. 增加更詳細的欄位說明 +3. 提供具體範例 +4. 調整 Prompt 語氣和指令 + +### 常見問題 3: 部分欄位未填充 + +**現象**: 只填充了部分欄位,其他欄位仍為空 + +**可能原因**: +- LLM 返回的 JSON 缺少某些欄位 +- 欄位名稱不匹配(大小寫、前綴問題) + +**解決方法**: +檢查欄位映射邏輯,特別是 `generateJobDesc()` 函式中的 `fieldMapping`: +```javascript +const fieldMapping = { + 'empNo': 'jd_empNo', + 'empName': 'jd_empName', + ... +}; +``` + +--- + +## 📚 參考資源 + +### 相關檔案 + +- **主程式**: [index.html](index.html) - 包含所有 AI 生成函式 +- **LLM API 配置**: [llm_config.py](llm_config.py) - LLM 模型設定 +- **環境變數**: [.env](.env) - API Key 和模型設定 + +### 相關函式 + +- **`callClaudeAPI(prompt)`**: 呼叫 LLM API 的核心函式 +- **`getEmptyFields(allFields)`**: 檢測空白欄位 +- **`fillIfEmpty(fieldId, value)`**: 只填充空白欄位 +- **`setButtonLoading(btn, isLoading)`**: 設定按鈕載入狀態 + +### LLM 模型設定 + +系統支援多種 LLM 模型,在 `.env` 檔案中設定: + +```env +# Gemini API Configuration +GEMINI_API_KEY=your_api_key +GEMINI_MODEL=gemini-1.5-flash + +# DeepSeek API Configuration +DEEPSEEK_API_KEY=your_deepseek_api_key +DEEPSEEK_API_URL=https://api.deepseek.com/v1 + +# OpenAI API Configuration +OPENAI_API_KEY=your_openai_api_key +OPENAI_API_URL=https://api.openai.com/v1 + +# Ollama API Configuration +OLLAMA_API_URL=https://ollama_pjapi.theaken.com +OLLAMA_MODEL=deepseek-reasoner +``` + +--- + +## ✅ 最佳實踐 + +### ✨ 撰寫好的 Prompt 的建議 + +1. **明確的指令**: 清楚說明要生成什麼類型的資料 +2. **詳細的格式說明**: 提供完整的代碼對照表和格式範例 +3. **上下文資訊**: 包含已填寫的資料作為參考 +4. **結構化輸出**: 要求返回 JSON 格式,方便解析 +5. **語言偏好**: 明確指定使用繁體中文 +6. **錯誤處理**: 加入驗證規則,減少生成錯誤 + +### 📝 Prompt 維護建議 + +1. **版本控制**: 重大修改前先備份原 Prompt +2. **測試驗證**: 每次修改後都要測試所有情境 +3. **文件更新**: 修改後同步更新此說明文件 +4. **使用者回饋**: 根據實際使用情況調整 Prompt + +--- + +## 🎯 總結 + +### 快速參考表 + +| 頁籤 | 函式 | 程式碼行數 | 主要用途 | 欄位數量 | +|-----|------|-----------|---------|---------| +| 崗位基礎資料 | `generatePositionBasic()` | 2179-2251 | 生成崗位基本資訊 | 8 | +| 崗位招聘要求 | `generatePositionRecruit()` | 2253-2328 | 生成招聘需求 | 14 | +| 職務基礎資料 | `generateJobBasic()` | 2330-2423 | 生成職務資訊 | 8+2 checkbox | +| 部門職責維護 | `generateDeptFunction()` | 3778-3839 | 生成部門職責 | 9 | +| 崗位描述 (JD) | `generateJobDesc()` | 2425-2541 | 生成完整JD | 18 | + +### 核心機制 + +1. **智能檢測**: 自動識別空白欄位 +2. **上下文感知**: 參考已填寫資料生成 +3. **結構化輸出**: JSON 格式便於解析 +4. **安全填充**: 只填充空白欄位,不覆蓋現有資料 + +--- + +> **維護提醒**: 當系統新增或修改欄位時,記得同步更新: +> 1. HTML 表單欄位 +> 2. JavaScript 函式中的 `allFields` 陣列 +> 3. Prompt 中的欄位說明 +> 4. 此說明文件 + +--- + +**文件結束** | 有問題請找 AI,不要找我 ¯\\_(ツ)_/¯ diff --git a/review.html b/review.html new file mode 100644 index 0000000..73f151c --- /dev/null +++ b/review.html @@ -0,0 +1,2215 @@ + + + + + + 組織架構預覽 + + + +
+

📊 公司組織架構預覽

+
總計: 313 筆資料
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事業體處級單位部級單位崗位名稱
半導體事業群半導體事業群營運長
半導體事業群半導體事業群營運長助理
汽車事業體汽車事業體副總經理
汽車事業體汽車事業體專案經理
法務室法務室經副理
法務室法務室法務專員
法務室法務室專利工程師
岡山製造事業體生產處處長
岡山製造事業體生產處專員
岡山製造事業體生產處生產部經副理
岡山製造事業體生產處生產部課長
岡山製造事業體生產處生產部組長
岡山製造事業體生產處生產部班長
岡山製造事業體生產處生產部副班長
岡山製造事業體生產處生產部作業員
岡山製造事業體生產處生產企劃部經副理
岡山製造事業體生產處生產企劃部課長
岡山製造事業體生產處生產企劃部專員
岡山製造事業體生產處生產企劃部工程師
岡山製造事業體岡山製造事業體岡山品質管制部經副理
岡山製造事業體岡山製造事業體岡山品質管制部課長
岡山製造事業體岡山製造事業體岡山品質管制部工程師
岡山製造事業體岡山製造事業體岡山品質管制部組長
岡山製造事業體岡山製造事業體岡山品質管制部班長
岡山製造事業體岡山製造事業體岡山品質管制部副班長
岡山製造事業體岡山製造事業體岡山品質管制部作業員
岡山製造事業體岡山製造事業體岡山品質管制部課長
岡山製造事業體岡山製造事業體岡山品質管制部工程師
岡山製造事業體岡山製造事業體岡山品質管制部副總經理
岡山製造事業體岡山製造事業體岡山品質管制部副總經理助理
岡山製造事業體封裝工程處處長
岡山製造事業體封裝工程處專員
岡山製造事業體封裝工程處工程師
岡山製造事業體封裝工程處製程工程一部經副理
岡山製造事業體封裝工程處製程工程二部經副理
岡山製造事業體封裝工程處製程工程二部課長
岡山製造事業體封裝工程處製程工程二部工程師
岡山製造事業體封裝工程處製程工程二部課長
岡山製造事業體封裝工程處製程工程二部工程師
岡山製造事業體封裝工程處製程工程二部課長
岡山製造事業體封裝工程處製程工程二部工程師
岡山製造事業體封裝工程處製程工程二部課長
岡山製造事業體封裝工程處製程工程二部工程師
岡山製造事業體封裝工程處設備一部經副理
岡山製造事業體封裝工程處設備二部經副理
岡山製造事業體封裝工程處設備二部課長
岡山製造事業體封裝工程處設備二部工程師
岡山製造事業體封裝工程處設備二部課長
岡山製造事業體封裝工程處設備二部工程師
岡山製造事業體封裝工程處設備二部課長
岡山製造事業體封裝工程處設備二部工程師
岡山製造事業體副總辦公室工業工程部經副理
岡山製造事業體副總辦公室工業工程部工程師
岡山製造事業體副總辦公室工業工程部課長
岡山製造事業體副總辦公室工業工程部工程師
岡山製造事業體副總辦公室工業工程部副理
岡山製造事業體副總辦公室工業工程部工程師
岡山製造事業體測試工程與研發處處長
岡山製造事業體測試工程與研發處專員
岡山製造事業體測試工程與研發處測試工程部經副理
岡山製造事業體測試工程與研發處測試工程部課長
岡山製造事業體測試工程與研發處測試工程部工程師
岡山製造事業體測試工程與研發處測試工程部課長
岡山製造事業體測試工程與研發處測試工程部工程師
岡山製造事業體測試工程與研發處新產品導入部經副理
岡山製造事業體測試工程與研發處新產品導入部專員
岡山製造事業體測試工程與研發處新產品導入部工程師
岡山製造事業體測試工程與研發處研發部經副理
岡山製造事業體測試工程與研發處研發部課長
岡山製造事業體測試工程與研發處研發部工程師
岡山製造事業體測試工程與研發處研發部課長
岡山製造事業體測試工程與研發處研發部工程師
岡山製造事業體測試工程與研發處研發部專員
岡山製造事業體資材處處長
岡山製造事業體資材處採購部經副理
岡山製造事業體資材處採購部課長
岡山製造事業體資材處採購部專員
岡山製造事業體資材處採購部課長
岡山製造事業體資材處採購部專員
岡山製造事業體資材處外部資源部專員
岡山製造事業體資材處生管部經副理
岡山製造事業體資材處生管部課長
岡山製造事業體資材處生管部專員
岡山製造事業體資材處生管部課長
岡山製造事業體資材處生管部班長
岡山製造事業體資材處生管部副班長
岡山製造事業體資材處生管部作業員
岡山製造事業體資材處原物料控制部經副理
岡山製造事業體資材處原物料控制部課長
岡山製造事業體資材處原物料控制部專員
岡山製造事業體資材處原物料控制部班長
岡山製造事業體資材處原物料控制部副班長
岡山製造事業體資材處原物料控制部作業員
岡山製造事業體廠務與環安衛管理處處長
岡山製造事業體廠務與環安衛管理處工程師
岡山製造事業體廠務與環安衛管理處廠務部經副理
岡山製造事業體廠務與環安衛管理處廠務部課長
岡山製造事業體廠務與環安衛管理處廠務部工程師
岡山製造事業體廠務與環安衛管理處廠務部課長
岡山製造事業體廠務與環安衛管理處廠務部工程師
岡山製造事業體廠務與環安衛管理處廠務部專員
岡山製造事業體廠務與環安衛管理處廠務部課長
岡山製造事業體廠務與環安衛管理處廠務部工程師
產品事業體產品事業體廠務部處長
產品事業體先進產品事業處處長
產品事業體先進產品事業處產品管理部(APD)經副理
產品事業體先進產品事業處產品管理部(APD)經副理
產品事業體先進產品事業處產品管理部(APD)工程師
產品事業體先進產品事業處產品管理部(APD)經副理
產品事業體先進產品事業處產品管理部(APD)工程師
產品事業體成熟產品事業處處長
產品事業體成熟產品事業處產品管理部(MPD)經副理
產品事業體成熟產品事業處產品管理部(MPD)經副理
產品事業體成熟產品事業處產品管理部(MPD)專案經副理
產品事業體成熟產品事業處產品管理部(MPD)工程師
產品事業體成熟產品事業處產品管理部(MPD)經副理
產品事業體成熟產品事業處產品管理部(MPD)專案經副理
產品事業體成熟產品事業處產品管理部(MPD)工程師
晶圓三廠晶圓三廠產品管理部(MPD)顧問
晶圓三廠晶圓三廠產品管理部(MPD)專員
晶圓三廠晶圓三廠品質部經副理
晶圓三廠晶圓三廠品質部工程師
晶圓三廠晶圓三廠品質部作業員
晶圓三廠晶圓三廠製造部經副理
晶圓三廠晶圓三廠製造部課長
晶圓三廠晶圓三廠製造部班長
晶圓三廠晶圓三廠製造部副班長
晶圓三廠晶圓三廠製造部作業員
晶圓三廠晶圓三廠廠務部(Fab3)經副理
晶圓三廠晶圓三廠廠務部(Fab3)工程師
晶圓三廠製程工程處工程一部經副理
晶圓三廠製程工程處工程一部工程師
晶圓三廠製程工程處工程二部經副理
晶圓三廠製程工程處工程二部工程師
晶圓三廠製程工程處工程三部經副理
晶圓三廠製程工程處工程三部工程師
晶圓三廠製程工程處製程整合部(Fab3)經副理
晶圓三廠製程工程處製程整合部(Fab3)工程師
集團人資行政事業體集團人資行政事業體製程整合部(Fab3)人資長
集團人資行政事業體集團人資行政事業體行政總務管理部經副理
集團人資行政事業體集團人資行政事業體行政總務管理部專員
集團人資行政事業體集團人資行政事業體行政總務管理部助理
集團人資行政事業體集團人資行政事業體招募任用部經副理
集團人資行政事業體集團人資行政事業體招募任用部專員
集團人資行政事業體集團人資行政事業體訓練發展部經副理
集團人資行政事業體集團人資行政事業體訓練發展部專員
集團人資行政事業體集團人資行政事業體薪酬管理部經副理
集團人資行政事業體集團人資行政事業體薪酬管理部專員
集團財務事業體集團財務事業體薪酬管理部財務長
集團財務事業體岡山強茂財務處處長
集團財務事業體岡山強茂財務處岡山強茂財務部經副理
集團財務事業體岡山強茂財務處岡山強茂財務部課長
集團財務事業體岡山強茂財務處岡山強茂財務部專員
集團財務事業體集團財務事業體岡山強茂財務部專案副理
集團會計事業體集團會計事業體岡山強茂財務部會計長
集團會計事業體岡山會計處處長
集團會計事業體岡山會計處會計部經副理
集團會計事業體岡山會計處會計部課長
集團會計事業體岡山會計處會計部專員
集團會計事業體岡山會計處會計部課長
集團會計事業體岡山會計處會計部專員
集團會計事業體岡山會計處管理會計部經副理
集團會計事業體岡山會計處管理會計部課長
集團會計事業體岡山會計處管理會計部專員
集團會計事業體岡山會計處管理會計部課長
集團會計事業體岡山會計處管理會計部專員
集團會計事業體集團會計處處長
集團會計事業體集團會計處集團合併報表部經副理
集團會計事業體集團會計處集團合併報表部專員
集團資訊事業體集團資訊事業體集團合併報表部資訊長
集團資訊事業體資安行動小組集團合併報表部課長
集團資訊事業體資訊一處應用系統部經副理
集團資訊事業體資訊一處應用系統部工程師
集團資訊事業體資訊一處電腦整合製造部經副理
集團資訊事業體資訊一處電腦整合製造部工程師
集團資訊事業體資訊一處系統網路服務部經副理
集團資訊事業體資訊一處系統網路服務部工程師
集團資訊事業體資訊二處處長
新創事業體新創事業體處長
新創事業體新創事業體資源管理部經副理
新創事業體新創事業體資源管理部專員
新創事業體中低壓產品研發處經副理
新創事業體研發中心工程師
新創事業體高壓產品研發處經副理
新創事業體研發中心工程師
稽核室稽核室主任
稽核室稽核室專員
總經理室總經理室總裁
總經理室總經理室總經理
總經理室ESG專案辦公室經副理
總經理室ESG專案辦公室課長
總經理室ESG專案辦公室專員/工程師
總經理室ESG專案辦公室課長
總經理室ESG專案辦公室專員/工程師
總經理室ESG專案辦公室課長
總經理室ESG專案辦公室專員/工程師
總經理室專案管理室副總經理
總經理室專案管理室經副理
總經理室專案管理室專員/工程師
總經理室專案管理室專員/工程師
總品質事業體總品質事業體處長
總品質事業體總品質事業體客戶品質管理部經副理
總品質事業體總品質事業體客戶品質管理部課長
總品質事業體總品質事業體客戶品質管理部工程師
總品質事業體總品質事業體客戶品質管理部專員
總品質事業體總品質事業體客戶品質管理部課長
總品質事業體總品質事業體客戶品質管理部工程師
總品質事業體總品質事業體產品品質管理部經副理
總品質事業體總品質事業體產品品質管理部課長
總品質事業體總品質事業體產品品質管理部工程師
總品質事業體總品質事業體產品品質管理部課長
總品質事業體總品質事業體產品品質管理部工程師
總品質事業體總品質事業體產品品質管理部課長
總品質事業體總品質事業體產品品質管理部工程師
總品質事業體總品質事業體產品品質管理部班長
總品質事業體總品質事業體產品品質管理部作業員
總品質事業體總品質事業體品質系統及客戶工程整合部經副理
總品質事業體總品質事業體品質系統及客戶工程整合部課長
總品質事業體總品質事業體品質系統及客戶工程整合部工程師
總品質事業體總品質事業體品質系統及客戶工程整合部課長
總品質事業體總品質事業體品質系統及客戶工程整合部工程師
總品質事業體總品質事業體封測外包品質管理部經副理
總品質事業體總品質事業體封測外包品質管理部課長
總品質事業體總品質事業體封測外包品質管理部工程師
總品質事業體總品質事業體品質保證部經副理
總品質事業體總品質事業體品質保證部課長
總品質事業體總品質事業體品質保證部工程師
總品質事業體總品質事業體品質保證部課長
總品質事業體總品質事業體品質保證部工程師
總品質事業體總品質事業體品質保證部班長
總品質事業體總品質事業體品質保證部副班長
總品質事業體總品質事業體品質保證部作業員
總品質事業體總品質事業體品質保證部課長
總品質事業體總品質事業體品質保證部工程師
總品質事業體總品質事業體品質保證部班長
總品質事業體總品質事業體品質保證部副班長
總品質事業體總品質事業體品質保證部作業員
總品質事業體總品質事業體品質保證部課長
總品質事業體總品質事業體品質保證部工程師
營業事業體營業事業體品質保證部副總經理
營業事業體營業事業體品質保證部副總經理助理
營業事業體商業開發暨市場應用處處長
營業事業體商業開發暨市場應用處經理
營業事業體商業開發暨市場應用處工程師
營業事業體海外銷售事業處處長
營業事業體海外銷售事業處日本區暨代工業務部經副理
營業事業體海外銷售事業處日本區暨代工業務部課長
營業事業體海外銷售事業處日本區暨代工業務部專員
營業事業體海外銷售事業處日本區暨代工業務部助理
營業事業體海外銷售事業處日本區暨代工業務部課長
營業事業體海外銷售事業處日本區暨代工業務部專員
營業事業體海外銷售事業處日本區暨代工業務部助理
營業事業體海外銷售事業處歐亞區業務部經副理
營業事業體海外銷售事業處歐亞區業務部助理
營業事業體海外銷售事業處歐亞區業務部課長
營業事業體海外銷售事業處歐亞區業務部專員
營業事業體海外銷售事業處歐亞區業務部助理
營業事業體海外銷售事業處歐亞區業務部課長
營業事業體海外銷售事業處歐亞區業務部專員
營業事業體海外銷售事業處歐亞區業務部助理
營業事業體海外銷售事業處歐亞區業務部課長
營業事業體海外銷售事業處歐亞區業務部專員
營業事業體海外銷售事業處歐亞區業務部助理
營業事業體海外銷售事業處韓國區業務部-韓國區經副理
營業事業體海外銷售事業處韓國區業務部-韓國區課長
營業事業體海外銷售事業處韓國區業務部-韓國區專員
營業事業體海外銷售事業處韓國區業務部-韓國區助理
營業事業體海外銷售事業處韓國區業務部-韓國區專案經理
營業事業體海外銷售事業處韓國區業務部-韓國區經副理
營業事業體海外銷售事業處美洲區業務部經副理
營業事業體海外銷售事業處美洲區業務部課長
營業事業體海外銷售事業處美洲區業務部專員
營業事業體海外銷售事業處美洲區業務部助理
營業事業體全球技術服務處處長
營業事業體全球技術服務處工程師
營業事業體全球技術服務處助理
營業事業體全球技術服務處應用工程部(GTS)經副理
營業事業體全球技術服務處應用工程部(GTS)專案經副理
營業事業體全球技術服務處應用工程部(GTS)技術經副理
營業事業體全球技術服務處應用工程部(GTS)工程師
營業事業體全球技術服務處系統工程部經副理
營業事業體全球技術服務處系統工程部工程師
營業事業體全球技術服務處特性測試部經副理
營業事業體全球技術服務處特性測試部課長
營業事業體全球技術服務處特性測試部工程師
營業事業體全球行銷暨業務支援處副總經理
營業事業體全球行銷暨業務支援處業務生管部經副理
營業事業體全球行銷暨業務支援處業務生管部課長
營業事業體全球行銷暨業務支援處業務生管部專員
營業事業體全球行銷暨業務支援處業務生管部課長
營業事業體全球行銷暨業務支援處業務生管部專員
營業事業體全球行銷暨業務支援處市場行銷企劃部處長
營業事業體全球行銷暨業務支援處市場行銷企劃部經理
營業事業體全球行銷暨業務支援處市場行銷企劃部專員
營業事業體全球行銷暨業務支援處市場行銷企劃部專員
營業事業體全球行銷暨業務支援處市場行銷企劃部專員
營業事業體全球行銷暨業務支援處MOSFET晶圓採購部經副理
營業事業體全球行銷暨業務支援處MOSFET晶圓採購部課長
營業事業體全球行銷暨業務支援處MOSFET晶圓採購部專員
營業事業體大中華區銷售事業處處長
營業事業體大中華區銷售事業處台灣區業務部專員
營業事業體大中華區銷售事業處台灣區業務部助理
營業事業體大中華區銷售事業處業務一部處長/資深經理
營業事業體大中華區銷售事業處業務一部經副理
營業事業體大中華區銷售事業處業務一部專員
營業事業體大中華區銷售事業處業務一部助理
營業事業體大中華區銷售事業處業務二部處長/資深經理
營業事業體大中華區銷售事業處業務二部經副理
營業事業體大中華區銷售事業處業務二部專員
營業事業體大中華區銷售事業處業務二部助理
營業事業體大中華區銷售事業處業務二部經副理
營業事業體大中華區銷售事業處業務二部專員
營業事業體大中華區銷售事業處業務二部助理
+
+ + + + + + \ No newline at end of file diff --git a/test_deepseek_reasoner.py b/test_deepseek_reasoner.py new file mode 100644 index 0000000..1912314 --- /dev/null +++ b/test_deepseek_reasoner.py @@ -0,0 +1,62 @@ +""" +Test deepseek-reasoner model on Ollama API +""" +import requests +import json +import urllib3 +import sys +import codecs + +# Set UTF-8 encoding for output +if sys.platform == 'win32': + sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict') + +# Disable SSL warnings +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +API_URL = "https://ollama_pjapi.theaken.com" + +print("=" * 60) +print("Testing deepseek-reasoner model") +print("=" * 60) +print() + +# Test chat completion with deepseek-reasoner +print("Sending test prompt to deepseek-reasoner...") +try: + chat_request = { + "model": "deepseek-reasoner", + "messages": [ + {"role": "user", "content": "請用中文簡單地說明什麼是人工智慧"} + ] + } + + response = requests.post( + f"{API_URL}/v1/chat/completions", + json=chat_request, + headers={'Content-Type': 'application/json'}, + timeout=60, + verify=False + ) + + print(f"Status Code: {response.status_code}") + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + print("\nResponse:") + print("-" * 60) + print(text) + print("-" * 60) + + # Save to file + with open('deepseek_reasoner_output.txt', 'w', encoding='utf-8') as f: + f.write(text) + print("\n✓ Response saved to: deepseek_reasoner_output.txt") + else: + print(f"Error: {response.text}") +except Exception as e: + print(f"Error: {str(e)}") + +print() +print("=" * 60) diff --git a/test_ollama.py b/test_ollama.py new file mode 100644 index 0000000..04b5929 --- /dev/null +++ b/test_ollama.py @@ -0,0 +1,70 @@ +""" +Test Ollama API integration +""" +import requests +import json +import urllib3 + +# Disable SSL warnings +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +API_URL = "https://ollama_pjapi.theaken.com" + +print("=" * 60) +print("Testing Ollama API Connection") +print("=" * 60) +print() + +# Test 1: List models +print("Test 1: Listing available models...") +try: + response = requests.get(f"{API_URL}/v1/models", timeout=10, verify=False) + print(f"Status Code: {response.status_code}") + + if response.status_code == 200: + data = response.json() + models = data.get('data', []) + print(f"Found {len(models)} models:") + for model in models[:5]: + print(f" - {model.get('id', 'Unknown')}") + else: + print(f"Error: {response.text}") +except Exception as e: + print(f"Error: {str(e)}") + +print() + +# Test 2: Chat completion +print("Test 2: Testing chat completion...") +try: + chat_request = { + "model": "qwen2.5:3b", + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Say hello in Chinese."} + ], + "temperature": 0.7, + "max_tokens": 50 + } + + response = requests.post( + f"{API_URL}/v1/chat/completions", + json=chat_request, + headers={'Content-Type': 'application/json'}, + timeout=60, + verify=False + ) + + print(f"Status Code: {response.status_code}") + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + print(f"Response: {text}") + else: + print(f"Error: {response.text}") +except Exception as e: + print(f"Error: {str(e)}") + +print() +print("=" * 60) diff --git a/test_ollama2.py b/test_ollama2.py new file mode 100644 index 0000000..474cb6b --- /dev/null +++ b/test_ollama2.py @@ -0,0 +1,79 @@ +""" +Test Ollama API with different parameters +""" +import requests +import json +import urllib3 + +# Disable SSL warnings +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +API_URL = "https://ollama_pjapi.theaken.com" + +print("=" * 60) +print("Testing Ollama Chat Completion - Variant Tests") +print("=" * 60) +print() + +# Test 1: Using qwen2.5:72b (actual available model) +print("Test 1: Using qwen2.5:72b model...") +try: + chat_request = { + "model": "qwen2.5:72b", + "messages": [ + {"role": "user", "content": "Say hello in Chinese."} + ] + } + + response = requests.post( + f"{API_URL}/v1/chat/completions", + json=chat_request, + headers={'Content-Type': 'application/json'}, + timeout=60, + verify=False + ) + + print(f"Status Code: {response.status_code}") + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + print(f"Success! Response: {text}") + else: + print(f"Error: {response.text}") +except Exception as e: + print(f"Error: {str(e)}") + +print() + +# Test 2: Try deepseek-chat model +print("Test 2: Using deepseek-chat model...") +try: + chat_request = { + "model": "deepseek-chat", + "messages": [ + {"role": "user", "content": "Say hello in Chinese."} + ] + } + + response = requests.post( + f"{API_URL}/v1/chat/completions", + json=chat_request, + headers={'Content-Type': 'application/json'}, + timeout=60, + verify=False + ) + + print(f"Status Code: {response.status_code}") + + if response.status_code == 200: + result = response.json() + text = result['choices'][0]['message']['content'] + print(f"Success! Response: {text}") + else: + print(f"Error: {response.text}") +except Exception as e: + print(f"Error: {str(e)}") + +print() +print("=" * 60) diff --git a/test_ollama_final.py b/test_ollama_final.py new file mode 100644 index 0000000..7980932 --- /dev/null +++ b/test_ollama_final.py @@ -0,0 +1,110 @@ +""" +Final Ollama API Integration Test +Tests the integration with the Flask app +""" +import requests +import json +import sys + +# Set UTF-8 encoding for output +if sys.platform == 'win32': + import codecs + sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict') + +print("=" * 60) +print("Ollama API Integration Test (via Flask App)") +print("=" * 60) +print() + +# Test 1: Test Ollama connection status +print("Test 1: Checking Ollama API configuration...") +try: + response = requests.get("http://localhost:5000/api/llm/config", timeout=10) + if response.status_code == 200: + config = response.json() + ollama_config = config.get('ollama', {}) + print(f" Name: {ollama_config.get('name', 'N/A')}") + print(f" Enabled: {ollama_config.get('enabled', False)}") + print(f" Endpoint: {ollama_config.get('endpoint', 'N/A')}") + print(" Status: ✓ Configuration OK") + else: + print(f" Status: ✗ Error {response.status_code}") +except Exception as e: + print(f" Status: ✗ Error: {str(e)}") + +print() + +# Test 2: Generate text using Ollama +print("Test 2: Testing text generation with Ollama...") +try: + payload = { + "api": "ollama", + "prompt": "請用中文回答:你好嗎?", + "max_tokens": 100 + } + + response = requests.post( + "http://localhost:5000/api/llm/generate", + json=payload, + headers={'Content-Type': 'application/json'}, + timeout=60 + ) + + print(f" Status Code: {response.status_code}") + + result = response.json() + + if result.get('success'): + text = result.get('text', '') + print(f" Status: ✓ Generation successful") + print(f" Response length: {len(text)} characters") + print(f" Response preview: {text[:100]}...") + + # Save full response to file + with open('ollama_response.txt', 'w', encoding='utf-8') as f: + f.write(text) + print(f" Full response saved to: ollama_response.txt") + else: + error = result.get('error', 'Unknown error') + print(f" Status: ✗ Generation failed") + print(f" Error: {error}") + +except Exception as e: + print(f" Status: ✗ Error: {str(e)}") + +print() + +# Test 3: Test with English prompt +print("Test 3: Testing with English prompt...") +try: + payload = { + "api": "ollama", + "prompt": "Write a haiku about coding.", + "max_tokens": 100 + } + + response = requests.post( + "http://localhost:5000/api/llm/generate", + json=payload, + headers={'Content-Type': 'application/json'}, + timeout=60 + ) + + result = response.json() + + if result.get('success'): + text = result.get('text', '') + print(f" Status: ✓ Generation successful") + print(f" Response:\n{text}") + else: + error = result.get('error', 'Unknown error') + print(f" Status: ✗ Generation failed") + print(f" Error: {error}") + +except Exception as e: + print(f" Status: ✗ Error: {str(e)}") + +print() +print("=" * 60) +print("Integration test completed!") +print("=" * 60) diff --git a/權限矩陣.md b/權限矩陣.md new file mode 100644 index 0000000..2c86eb0 --- /dev/null +++ b/權限矩陣.md @@ -0,0 +1,236 @@ +# 系統權限矩陣 - 那都AI寫的,不要問我 + +## 系統概述 +本系統為「人力資源崗位管理系統」(HR Position Management System),採用三級權限架構設計,確保資料安全性與操作權限的合理分配。 + +--- + +## 角色定義 + +### 1. 一般使用者 (User) +- **測試帳號**: A003 / employee +- **使用對象**: 一般員工、HR專員 +- **主要職責**: 查詢崗位資訊、建立崗位描述、查看部門職責 + +### 2. 管理者 (Admin) +- **測試帳號**: A002 / hr_manager +- **使用對象**: 部門主管、HR經理 +- **主要職責**: 管理部門職責、審核崗位資料、匯出報表 + +### 3. 最高管理者 (Super Admin) +- **測試帳號**: A001 / admin +- **使用對象**: 系統管理員、HR總監 +- **主要職責**: 系統設定、使用者管理、完整權限控制 + +--- + +## 功能權限矩陣 + +| 功能模組 | 功能項目 | 一般使用者 | 管理者 | 最高管理者 | 說明 | +|---------|---------|:---------:|:-----:|:---------:|------| +| **崗位管理** | 查看崗位清單 | ✅ | ✅ | ✅ | 所有角色可查看 | +| | 搜尋/篩選崗位 | ✅ | ✅ | ✅ | 所有角色可搜尋 | +| | 查看崗位詳情 | ✅ | ✅ | ✅ | 所有角色可查看詳情 | +| | 建立新崗位 | ❌ | ✅ | ✅ | 需要管理權限 | +| | 編輯崗位資訊 | ❌ | ✅ | ✅ | 需要管理權限 | +| | 刪除崗位 | ❌ | ❌ | ✅ | 僅最高管理者 | +| **職位描述 (JD)** | 查看 JD | ✅ | ✅ | ✅ | 所有角色可查看 | +| | 建立 JD | ✅ | ✅ | ✅ | 所有角色可建立 | +| | 編輯自己的 JD | ✅ | ✅ | ✅ | 可編輯自己建立的 | +| | 編輯所有 JD | ❌ | ✅ | ✅ | 管理者以上 | +| | 刪除 JD | ❌ | ✅ | ✅ | 管理者以上 | +| | 使用 AI 生成 JD | ✅ | ✅ | ✅ | 所有角色可使用 AI | +| **部門職責** | 查看部門職責 | ✅ | ✅ | ✅ | 所有角色可查看 | +| | 建立部門職責 | ❌ | ✅ | ✅ | 管理者以上 | +| | 編輯部門職責 | ❌ | ✅ | ✅ | 管理者以上 | +| | 刪除部門職責 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 匯出部門職責 | ✅ | ✅ | ✅ | 所有角色可匯出 | +| **崗位清單** | 查看清單 | ✅ | ✅ | ✅ | 所有角色可查看 | +| | 篩選/排序 | ✅ | ✅ | ✅ | 所有角色可使用 | +| | 匯出 CSV | ✅ | ✅ | ✅ | 所有角色可匯出 | +| | 批量操作 | ❌ | ✅ | ✅ | 管理者以上 | +| **報表匯出** | 匯出基本報表 | ✅ | ✅ | ✅ | 所有角色可匯出 | +| | 匯出完整資料 | ❌ | ✅ | ✅ | 管理者以上 | +| | 匯出統計報表 | ❌ | ✅ | ✅ | 管理者以上 | +| **系統管理** | 查看系統設定 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 修改系統設定 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | LLM 模型設定 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 測試 API 連線 | ❌ | ❌ | ✅ | 僅最高管理者 | +| **使用者管理** | 查看使用者清單 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 新增使用者 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 編輯使用者 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 刪除使用者 | ❌ | ❌ | ✅ | 僅最高管理者 | +| | 修改權限 | ❌ | ❌ | ✅ | 僅最高管理者 | +| **AI 功能** | 使用 AI 生成 | ✅ | ✅ | ✅ | 所有角色可使用 | +| | 選擇 AI 模型 | ❌ | ❌ | ✅ | 僅最高管理者設定 | +| | 查看 AI 使用記錄 | ❌ | ✅ | ✅ | 管理者以上 | + +--- + +## 資料訪問權限 + +### 資料可見性 + +| 資料類型 | 一般使用者 | 管理者 | 最高管理者 | +|---------|:---------:|:-----:|:---------:| +| 所有崗位資料 | ✅ 唯讀 | ✅ 可編輯 | ✅ 完全控制 | +| 部門職責資料 | ✅ 唯讀 | ✅ 可編輯 | ✅ 完全控制 | +| 自己建立的 JD | ✅ 可編輯 | ✅ 可編輯 | ✅ 可編輯 | +| 他人建立的 JD | ✅ 唯讀 | ✅ 可編輯 | ✅ 可編輯 | +| 使用者資料 | ❌ | ❌ | ✅ 完全控制 | +| 系統設定 | ❌ | ❌ | ✅ 完全控制 | +| 操作日誌 | ❌ | ✅ 唯讀 | ✅ 完全控制 | + +### 資料操作權限 + +| 操作類型 | 一般使用者 | 管理者 | 最高管理者 | +|---------|:---------:|:-----:|:---------:| +| **C**reate (新增) | 僅 JD | 崗位、部門職責、JD | 所有資料 | +| **R**ead (讀取) | 基本資料 | 包含統計資料 | 所有資料 | +| **U**pdate (更新) | 僅自己的 JD | 大部分資料 | 所有資料 | +| **D**elete (刪除) | ❌ | 部分資料 | 所有資料 | + +--- + +## 頁面/模組訪問權限 + +| 頁面模組 | 一般使用者 | 管理者 | 最高管理者 | +|---------|:---------:|:-----:|:---------:| +| 🏠 首頁 (登入頁) | ✅ | ✅ | ✅ | +| 📝 崗位說明書管理 | ✅ | ✅ | ✅ | +| 🎯 部門職責管理 | ✅ 唯讀 | ✅ | ✅ | +| 📋 崗位清單 | ✅ | ✅ | ✅ | +| ⚙️ 管理者頁面 | ❌ | ⚠️ 部分功能 | ✅ | + +### 管理者頁面功能細分 + +| 管理者頁面功能 | 一般使用者 | 管理者 | 最高管理者 | +|--------------|:---------:|:-----:|:---------:| +| 使用者管理 | ❌ | ❌ | ✅ | +| LLM 模型設定 | ❌ | ❌ | ✅ | +| 崗位資料管理 | ❌ | ✅ 唯讀 | ✅ | +| 匯出完整資料 | ❌ | ✅ | ✅ | +| 查看統計資訊 | ❌ | ✅ | ✅ | + +--- + +## 特殊權限說明 + +### 1. AI 功能使用 + +所有角色都可以使用 AI 生成功能,但有以下限制: + +- **一般使用者**: 可使用 AI 生成 JD,但每日限額 50 次 +- **管理者**: 可使用 AI 生成,每日限額 200 次 +- **最高管理者**: 無限制,且可設定使用的 AI 模型 + +### 2. 匯出功能 + +| 匯出類型 | 一般使用者 | 管理者 | 最高管理者 | +|---------|:---------:|:-----:|:---------:| +| 基本 CSV 匯出 | ✅ | ✅ | ✅ | +| 完整資料匯出 | ❌ | ✅ | ✅ | +| 含敏感資訊匯出 | ❌ | ❌ | ✅ | + +### 3. 批量操作 + +- **一般使用者**: 無批量操作權限 +- **管理者**: 可批量編輯崗位狀態、部門歸屬 +- **最高管理者**: 可批量刪除、批量匯入 + +--- + +## 權限繼承規則 + +``` +最高管理者 (Super Admin) + ↓ 繼承所有權限 +管理者 (Admin) + ↓ 繼承所有權限 +一般使用者 (User) +``` + +**規則說明**: +- 高階角色自動繼承低階角色的所有權限 +- 最高管理者擁有系統所有功能的完整權限 +- 權限提升需要最高管理者審核批准 + +--- + +## 安全性措施 + +### 1. 登入安全 +- ✅ 密碼加密儲存 (bcrypt) +- ✅ 登入失敗次數限制 (5次鎖定30分鐘) +- ✅ Session 逾時自動登出 (30分鐘無操作) +- ✅ IP 白名單 (可選) + +### 2. 操作追蹤 +- ✅ 所有資料修改記錄操作者 +- ✅ 關鍵操作留存日誌 (刪除、權限變更) +- ✅ 管理者以上角色操作全程記錄 + +### 3. 資料保護 +- ✅ 敏感資料加密儲存 +- ✅ API 呼叫需要認證 Token +- ✅ CORS 限制來源 +- ✅ SQL Injection 防護 +- ✅ XSS 防護 + +--- + +## 權限變更流程 + +### 申請權限提升 + +```mermaid +graph LR + A[使用者提出申請] --> B[直屬主管審核] + B --> C[HR部門審核] + C --> D[最高管理者核准] + D --> E[權限變更] + E --> F[通知使用者] +``` + +### 權限審核週期 + +- **一般使用者**: 無需定期審核 +- **管理者**: 每季審核一次 +- **最高管理者**: 每半年審核一次 + +--- + +## 測試帳號資訊 + +| 角色 | 工號 | 密碼 | 姓名 | 權限等級 | +|-----|------|------|------|---------| +| 一般使用者 | A003 | employee | 一般員工 | ★☆☆ | +| 管理者 | A002 | hr_manager | 人資主管 | ★★☆ | +| 最高管理者 | A001 | admin | 系統管理員 | ★★★ | + +--- + +## 附註 + +- ✅ = 有權限 +- ❌ = 無權限 +- ⚠️ = 部分權限 + +**最後更新**: 2024-12-04 +**文件版本**: v1.0 +**維護者**: AI (所以有問題不要問我) + +--- + +## 權限擴充建議 + +未來可考慮新增以下角色: + +1. **部門管理者**: 僅能管理自己部門的崗位 +2. **唯讀管理者**: 可查看所有資料但無編輯權限 +3. **稽核員**: 專門查看操作日誌和系統使用情況 +4. **外部顧問**: 有時效性的臨時訪問權限 + +--- + +> **免責聲明**: 本權限矩陣由 AI 自動生成,如有疏漏或不合理之處,請找開發 AI 的公司,不要找我。¯\\\_(ツ)\_/¯