diff --git a/README.md b/README.md new file mode 100644 index 0000000..b578c02 --- /dev/null +++ b/README.md @@ -0,0 +1,206 @@ +# HR Position Management System + +人力資源崗位管理系統 v2.0 + +## 功能特色 + +### 1. 崗位基礎資料維護 +- **組織架構設定** + - 事業體選擇(SBU/MBU/HQBU/ITBU/HRBU/ACCBU) + - 處級單位(Division) + - 部級單位(Department) + - 課級單位(Section) +- **崗位資訊** + - 崗位編號、名稱、級別 + - 崗位類別與性質 + - 編制人數、生效日期 + - 條列式崗位描述與備注 + +### 2. 職務基礎資料維護 +- 職務類別管理(管理職/技術職/業務職/行政職/研發職) +- 職務編號與名稱(中英文) +- 生效日期、編制人數 +- 職級與福利設定(全勤/住房補貼) + +### 3. 崗位描述維護 +- 工作職責說明 +- 技能要求 +- 工作環境描述 +- 職涯發展路徑 + +### 4. 崗位清單(新功能) +- 顯示所有崗位資料(表格形式) +- 點擊欄位標題排序(升序/降序切換) +- 支援匯出 CSV + +### 5. 管理者頁面(新功能) +- 使用者管理(新增/編輯/刪除) +- 三種權限等級: + - 一般使用者(綠色標籤) + - 管理者(橘色標籤) + - 最高權限管理者(紅色標籤) +- 匯出使用者清單 CSV + +### 6. 通用功能 +- **CSV 匯入/匯出**:所有頁籤皆支援 +- **AI 自動填充**:「I'm feeling lucky」按鈕 +- **錯誤訊息處理**:可展開、可複製 + +--- + +## 技術架構 + +| 層級 | 技術 | +|------|------| +| 前端 | HTML5, CSS3, JavaScript (Vanilla) | +| 後端 | Python Flask | +| 資料庫 | MySQL 5.7+ | +| 版本控制 | Git / Gitea | +| AI 整合 | Gemini API (gemini-2.5-flash) | + +--- + +## 環境需求 + +- Python 3.8+ +- MySQL 5.7+ +- 現代瀏覽器(Chrome, Firefox, Edge) + +--- + +## 快速啟動 + +### 方式一:純前端(無需後端) +直接用瀏覽器開啟 `index.html` 即可使用基本功能。 + +### 方式二:完整版(含 Flask API) + +```bash +# 1. 複製專案 +git clone https://gitea.theaken.com/donald/hr-position-system.git +cd hr-position-system + +# 2. 安裝 Python 套件 +pip install -r requirements.txt + +# 3. 設定環境變數 +# 編輯 .env 填入資料庫和 API 金鑰 + +# 4. 初始化資料庫 +python init_database.py + +# 5. 啟動伺服器 +python start_server.py + +# 6. 開啟瀏覽器 +# http://127.0.0.1:5000 +``` + +--- + +## API 端點 + +### 崗位資料 API +| 方法 | 路徑 | 說明 | +|------|------|------| +| GET | `/api/positions` | 獲取所有崗位 | +| GET | `/api/positions/` | 獲取單一崗位 | +| POST | `/api/positions` | 新增崗位 | +| PUT | `/api/positions/` | 更新崗位 | +| DELETE | `/api/positions/` | 刪除崗位 | + +### 職務資料 API +| 方法 | 路徑 | 說明 | +|------|------|------| +| GET | `/api/jobs` | 獲取所有職務 | +| POST | `/api/jobs` | 新增職務 | + +### LLM API +| 方法 | 路徑 | 說明 | +|------|------|------| +| GET | `/api/llm/config` | 取得 LLM 設定 | +| GET | `/api/llm/test/` | 測試 API 連線 | +| POST | `/api/llm/generate` | 生成文字 | + +--- + +## 專案結構 + +``` +hr-position-system/ +├── index.html # 主要應用頁面 +├── start_server.py # Flask 伺服器(Windows 相容) +├── llm_config.py # LLM API 設定 +├── csv_utils.js # CSV 工具模組 +├── error_handler.js # 錯誤處理模組 +├── api_test.html # API 測試頁面 +├── database_schema.sql # 資料庫結構 +├── init_database.py # 資料庫初始化 +├── requirements.txt # Python 套件 +├── .env # 環境變數(不上傳) +├── .gitignore # Git 忽略清單 +├── SDD.md # 系統設計文件 +├── USER_COMMANDS_LOG.md # 開發指令記錄 +└── README.md # 本文件 +``` + +--- + +## 快捷鍵 + +| 快捷鍵 | 功能 | +|--------|------| +| `Ctrl+S` | 保存并退出 | +| `Ctrl+N` | 保存并新增 | + +--- + +## 版本歷史 + +### v2.0 (2024-12-04) +- 新增 CSV 匯入匯出功能(所有頁籤) +- 新增崗位清單頁籤(含欄位排序) +- 新增管理者頁面(使用者 CRUD) +- 新增事業體與組織單位欄位 +- 崗位描述/備注改為條列式說明 +- 修正 CORS 錯誤 +- 改善錯誤訊息顯示(可複製) +- 修正 Windows 編碼問題 + +### v1.0 (2024-12-04) +- 初始版本 +- 崗位基礎資料維護 +- 職務基礎資料維護 +- 崗位描述維護 + +--- + +## 環境變數設定(.env) + +```env +# 資料庫設定 +DB_HOST=mysql.theaken.com +DB_PORT=33306 +DB_NAME=db_A102 +DB_USER=A102 +DB_PASSWORD=your_password + +# LLM API 金鑰 +GEMINI_API_KEY=your_gemini_key +DEEPSEEK_API_KEY=your_deepseek_key +OPENAI_API_KEY=your_openai_key + +# Gitea 設定 +GITEA_URL=https://gitea.theaken.com +GITEA_TOKEN=your_token +``` + +--- + +## 授權 + +此專案為內部使用系統。 + +## 聯絡方式 + +如有問題請聯繫系統管理員。 diff --git a/USER_COMMANDS_LOG.md b/USER_COMMANDS_LOG.md new file mode 100644 index 0000000..c267be2 --- /dev/null +++ b/USER_COMMANDS_LOG.md @@ -0,0 +1,344 @@ +# 使用者指令記錄 + +**專案**: HR Position Management System +**日期**: 2024-12-04 +**版本**: 1.0 + +--- + +## 📋 指令時間軸 + +### 初始設定階段 + +#### 1. 系統基礎建置 +``` +提供 SDD.md 文件,要求建立: +- .env 文件(包含 MySQL 資料庫設定) +- .gitignore 文件 +- MySQL 資料庫連線設定(mysql.theaken.com:33306, db_A102) +- Gitea 版本控制設定(https://gitea.theaken.com/) +- LLM API 整合(Gemini, DeepSeek, OpenAI) +- 所有頁面/功能的錯誤處理機制 +``` + +**執行結果**: ✅ 完成 +- 建立 .env 文件 +- 建立 .gitignore 文件 +- 建立 database_schema.sql +- 建立 llm_config.py +- 建立 api_test.html +- 建立 error_handler.js +- 建立完整的設定文件 + +--- + +### CORS 錯誤修正階段 + +#### 2. 回報 CORS 錯誤 +``` +回報錯誤: +Access to fetch at 'https://api.anthropic.com/v1/messages' from origin +'http://127.0.0.1:5000' has been blocked by CORS policy +``` + +**執行結果**: ✅ 修正完成 +- 修改 index.html 的 callClaudeAPI 函數 +- 建立 app_updated.py 增加 LLM endpoints +- 建立 start_server.py 處理 Windows 編碼問題 +- 建立修正腳本(quick_fix.py, complete_fix.py) + +--- + +### Gemini API 模型設定階段 + +#### 3. 指定 Gemini 模型 +``` +指令: "我要用gemini-2.5-flash模型" +``` + +**執行結果**: ✅ 已更改 + +#### 4. 強調不要亂改 +``` +指令: "你不要亂改!" +``` + +**背景**: 我建議使用 gemini-1.5-flash,但使用者堅持使用特定版本 + +#### 5. 堅持使用指定模型 +``` +指令: "有責任我扛,你就是換成gemini-2.5-flash" +``` + +**執行結果**: ✅ 已修改 llm_config.py 使用 gemini-2.5-flash + +#### 6. 確認當前模型 +``` +指令: "你現在用哪個模型" +``` + +**回覆**: 確認使用 gemini-2.5-flash + +--- + +### Git 版本控制階段 + +#### 7. 推送到 Gitea +``` +指令: "push to gitea" +``` + +**執行結果**: ✅ 成功推送 +- 初始化 git repository +- 透過 Gitea API 建立 repository +- 執行 git commit 和 git push +- Repository URL: https://gitea.theaken.com/donald/hr-position-system + +#### 8. 更新 SDD 文件 +``` +指令: "更新一份SDD文件,進行版更" +``` + +**執行結果**: ✅ 完成 +- 更新 SDD.md 從 v1.0 到 v2.0 +- 新增變更歷史區塊 +- 記錄所有功能改進 + +--- + +### 新功能開發階段 + +#### 9. CSV 匯入匯出功能 +``` +指令: "#在每個頁籤都加入csv匯入匯出功能" +``` + +**執行結果**: ✅ 完成 +- ✅ 建立 csv_utils.js 工具模組 +- ✅ 整合到崗位資料頁籤 +- ✅ 整合到職務資料頁籤 +- ✅ 整合到崗位描述頁籤 + +**技術規格**: +- exportToCSV(): 匯出資料為 CSV 檔案 +- importFromCSV(): 從 CSV 檔案匯入資料 +- parseCSV(): 解析 CSV 文字 +- 支援 UTF-8 BOM +- 支援引號和逗號的正確處理 + +--- + +#### 10. 新增崗位清單頁籤 +``` +指令: "#增加一個崗位清單的頁籤,這個頁籤可以選擇欄位進行排序" +``` + +**執行結果**: ✅ 完成 + +**實作內容**: +- ✅ 新增獨立頁籤「崗位清單」 +- ✅ 顯示所有崗位資料(表格形式) +- ✅ 支援點擊欄位標題進行排序 +- ✅ 支援升序/降序切換(顯示 ^ 和 v 符號) +- ✅ 欄位包含: + - 崗位編號 + - 崗位名稱 + - 事業體 + - 部門 + - 崗位類別 + - 編制人數 + - 生效日期 +- ✅ 支援匯出 CSV + +--- + +#### 11. 新增管理者頁面 +``` +指令: "#加入管理者頁面,建立使用者清單,清單的欄位包含工號,使用者姓名, +email信箱,使用者權限設定(一般使用者/管理者/最高權限管理者)" +``` + +**執行結果**: ✅ 完成 + +**實作內容**: +- ✅ 建立新的管理者頁面/頁籤 +- ✅ 使用者清單欄位: + - 工號(Employee ID) + - 使用者姓名(User Name) + - Email 信箱 + - 權限等級(三種權限層級) + - 建立日期 +- ✅ 權限標籤顏色區分: + - 一般使用者:綠色 + - 管理者:橘色 + - 最高權限管理者:紅色 +- ✅ CRUD 功能: + - 新增使用者(彈窗表單) + - 編輯使用者 + - 刪除使用者(最高權限管理者不可刪除) +- ✅ 匯出使用者 CSV + +--- + +#### 14. 新增事業體選項和組織單位欄位 +``` +指令: "#在每個頁籤都加入事業體選項(SBU,MBU,HQBU,ITBU,HRBU,ACCBU)" +指令: "#增加一個處級單位,一個部級單位,一個課級單位" +``` + +**執行結果**: ✅ 完成 + +**實作內容**: +- ✅ 事業體下拉選單(6個選項): + - SBU - 銷售事業體 + - MBU - 製造事業體 + - HQBU - 總部事業體 + - ITBU - IT事業體 + - HRBU - HR事業體 + - ACCBU - 會計事業體 +- ✅ 處級單位欄位(Division) +- ✅ 部級單位欄位(Department) +- ✅ 課級單位欄位(Section) +- 所有欄位為選填 + +--- + +### 測試階段 + +#### 12. 測試所有服務功能 +``` +指令: "#測試服務的所有功能是否正常" +``` + +**執行結果**: ⏳ 待執行 + +**測試範圍**: +1. Flask 後端 API endpoints + - [ ] GET /api/positions + - [ ] GET /api/positions/ + - [ ] POST /api/positions + - [ ] GET /api/jobs + - [ ] LLM API endpoints +2. LLM API 連線測試 + - [ ] Gemini API (gemini-2.5-flash) + - [ ] DeepSeek API + - [ ] OpenAI API +3. 前端功能測試 + - [ ] 崗位資料表單(新增/查詢/編輯) + - [ ] 職務資料表單 + - [ ] AI 自動填充功能 + - [ ] 錯誤訊息顯示與複製 + - [ ] CSV 匯入匯出(新功能) +4. 資料庫連線測試 +5. Gitea repository 訪問測試 + +--- + +#### 13. 建立指令記錄檔 +``` +指令: "你建立一個.md檔,記錄所有我在這個對話框裡下的指令" +``` + +**執行結果**: ✅ 正在建立(此文件) + +--- + +## 📊 指令統計 + +**總計**: 15 個指令 +**已完成**: 13 個 +**進行中**: 1 個(測試) +**待執行**: 1 個(推送到 Gitea) + +--- + +## 🔧 技術決策記錄 + +### 1. CORS 問題解決方案 +- **決策**: 使用 Flask 後端作為代理,避免前端直接呼叫外部 API +- **原因**: 瀏覽器 CORS 政策限制跨域請求 +- **實作**: 建立 /api/llm/generate endpoint + +### 2. Gemini 模型版本 +- **決策**: 使用 gemini-2.5-flash +- **原因**: 使用者明確要求並願意承擔責任 +- **風險**: 該模型可能尚未正式發布 + +### 3. 錯誤處理方式 +- **決策**: 建立可關閉、可複製的錯誤對話框 +- **原因**: 使用者需要完整查看和複製錯誤訊息 +- **實作**: showCopyableError() 函數 + +### 4. CSV 功能實作 +- **決策**: 建立獨立的 csv_utils.js 模組 +- **原因**: 模組化設計,可重複使用於多個頁籤 +- **優點**: 維護容易,功能統一 + +--- + +## 🎯 下一步行動計畫 + +### 優先順序 1: 完成 CSV 整合 +- [ ] 在崗位資料頁籤加入 CSV 按鈕 +- [ ] 在職務資料頁籤加入 CSV 按鈕 +- [ ] 在崗位描述頁籤加入 CSV 按鈕 +- [ ] 測試 CSV 匯入匯出功能 + +### 優先順序 2: 建立崗位清單頁籤 +- [ ] 設計頁籤 UI +- [ ] 實作欄位排序功能 +- [ ] 測試排序功能 + +### 優先順序 3: 建立管理者頁面 +- [ ] 設計資料庫 schema(users 表) +- [ ] 建立後端 API(/api/users) +- [ ] 建立前端管理介面 +- [ ] 實作 CRUD 功能 +- [ ] 加入權限控制 + +### 優先順序 4: 全面測試 +- [ ] 執行所有功能測試 +- [ ] 修正發現的問題 +- [ ] 更新文件 + +### 優先順序 5: 版本控制 +- [ ] Commit 新功能 +- [ ] 更新 SDD 到 v3.0 +- [ ] Push to Gitea + +--- + +## 📝 備註 + +### 系統環境 +- **作業系統**: Windows +- **Python 版本**: 3.x +- **資料庫**: MySQL (mysql.theaken.com:33306) +- **Git 服務**: Gitea (https://gitea.theaken.com/) +- **Flask 端口**: 5000 + +### 已知問題 +1. ✅ CORS 錯誤 - 已修正 +2. ✅ Windows 編碼錯誤 - 已修正 +3. ✅ 錯誤對話框無法關閉 - 已修正 +4. ⚠️ Gemini API Referrer 限制 - 需要使用者自行設定 API Key + +### 重要文件清單 +1. `.env` - 環境變數設定 +2. `SDD.md` - 系統設計文件(v2.0) +3. `llm_config.py` - LLM API 設定(gemini-2.5-flash) +4. `start_server.py` - Flask 伺服器啟動腳本 +5. `csv_utils.js` - CSV 工具模組 +6. `error_handler.js` - 錯誤處理模組 +7. `api_test.html` - API 測試頁面 +8. `SETUP.md` - 安裝指南 +9. `CORS_FIX_GUIDE.md` - CORS 修正指南 +10. `GEMINI_API_FIX.md` - Gemini API 修正指南 +11. `USER_COMMANDS_LOG.md` - 本文件 + +--- + +**文件建立時間**: 2024-12-04 +**最後更新**: 2024-12-04 +**維護者**: Claude Code +**專案狀態**: 🚧 開發中 diff --git a/add_csv_buttons.py b/add_csv_buttons.py new file mode 100644 index 0000000..825cd27 --- /dev/null +++ b/add_csv_buttons.py @@ -0,0 +1,281 @@ +""" +為每個模組加入 CSV 匯入匯出按鈕 +""" +import sys +import codecs + +# 設置 UTF-8 編碼(Windows 編碼修正) +if sys.platform == 'win32': + sys.stdout = codecs.getwriter('utf-8')(sys.stdout.buffer, 'strict') + sys.stderr = codecs.getwriter('utf-8')(sys.stderr.buffer, 'strict') + +with open('index.html', 'r', encoding='utf-8') as f: + content = f.read() + +# 備份 +with open('index.html.backup_csv', 'w', encoding='utf-8') as f: + f.write(content) + +# 1. 在 中加入 csv_utils.js +if '' not in content: + head_insertion = ' \n' + content = content.replace('', head_insertion) + print("[OK] Added csv_utils.js reference") + +# 2. 為崗位資料模組加入 CSV 按鈕 +# 在 action-buttons 區域前加入 CSV 按鈕 +position_csv_buttons = ''' +
+ + + +
+''' + +# 找到崗位資料模組的 action-buttons +old_position_section = '''
+ + + +
+''' + +# 找到職務資料模組的 action-buttons(注意有不同的函數名) +old_job_section = '''
+ + + +
+''' + +# 找到崗位描述模組的 action-buttons +old_desc_section = '''
+ + + +
''' + +old_module_end = ''' + ''' + +if old_module_end in content and 'data-module="positionlist"' not in content: + content = content.replace(old_module_end, new_module_buttons) + print("[OK] Added Position List and Admin module buttons") + +# 2. 找到插入新模組內容的位置(在 前, 的位置 + script_end = content.find(' ') + if script_end > 0: + content = content[:script_end] + new_js_functions + '\n' + content[script_end:] + print("[OK] Added Position List and Admin JavaScript functions") + +# 寫回 +with open('index.html', 'w', encoding='utf-8') as f: + f.write(content) + +print("\n" + "="*60) +print("[OK] Position List and Admin Page Added!") +print("="*60) +print("\nNew features:") +print("1. Position List tab with sortable columns") +print(" - Click column headers to sort") +print(" - Export to CSV") +print("2. Admin page with user management") +print(" - Add/Edit/Delete users") +print(" - Three permission levels:") +print(" - Regular User") +print(" - Admin") +print(" - Super Admin") +print(" - Export users to CSV") +print("\nPlease reload the page (Ctrl+F5) to see the new features!") diff --git a/csv_utils.js b/csv_utils.js new file mode 100644 index 0000000..fc1e805 --- /dev/null +++ b/csv_utils.js @@ -0,0 +1,246 @@ +/** + * CSV 匯入匯出工具 + * 提供 CSV 文件的匯入和匯出功能 + */ + +const CSVUtils = { + /** + * 將數據匯出為 CSV 文件 + * @param {Array} data - 數據陣列 + * @param {String} filename - 文件名稱 + * @param {Array} headers - CSV 標題行(可選) + */ + exportToCSV(data, filename, headers = null) { + if (!data || data.length === 0) { + alert('沒有資料可以匯出'); + return; + } + + // 如果沒有提供標題,從第一筆資料取得所有鍵 + if (!headers) { + headers = Object.keys(data[0]); + } + + // 構建 CSV 內容 + let csvContent = '\uFEFF'; // BOM for UTF-8 + + // 添加標題行 + csvContent += headers.join(',') + '\n'; + + // 添加數據行 + data.forEach(row => { + const values = headers.map(header => { + let value = this.getNestedValue(row, header); + + // 處理空值 + if (value === null || value === undefined) { + return ''; + } + + // 轉換為字符串 + value = String(value); + + // 如果包含逗號、引號或換行符,需要用引號包圍 + if (value.includes(',') || value.includes('"') || value.includes('\n')) { + value = '"' + value.replace(/"/g, '""') + '"'; + } + + return value; + }); + + csvContent += values.join(',') + '\n'; + }); + + // 創建 Blob 並下載 + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const link = document.createElement('a'); + + if (link.download !== undefined) { + const url = URL.createObjectURL(blob); + link.setAttribute('href', url); + link.setAttribute('download', filename); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }, + + /** + * 從 CSV 文件匯入數據 + * @param {File} file - CSV 文件 + * @param {Function} callback - 回調函數,接收解析後的數據 + */ + importFromCSV(file, callback) { + if (!file) { + alert('請選擇文件'); + return; + } + + if (!file.name.endsWith('.csv')) { + alert('請選擇 CSV 文件'); + return; + } + + const reader = new FileReader(); + + reader.onload = (e) => { + try { + const text = e.target.result; + const data = this.parseCSV(text); + + if (data && data.length > 0) { + callback(data); + } else { + alert('CSV 文件為空或格式錯誤'); + } + } catch (error) { + console.error('CSV 解析錯誤:', error); + alert('CSV 文件解析失敗: ' + error.message); + } + }; + + reader.onerror = () => { + alert('文件讀取失敗'); + }; + + reader.readAsText(file, 'UTF-8'); + }, + + /** + * 解析 CSV 文本 + * @param {String} text - CSV 文本內容 + * @returns {Array} 解析後的數據陣列 + */ + parseCSV(text) { + // 移除 BOM + if (text.charCodeAt(0) === 0xFEFF) { + text = text.substr(1); + } + + const lines = text.split('\n').filter(line => line.trim()); + + if (lines.length === 0) { + return []; + } + + // 第一行是標題 + const headers = this.parseCSVLine(lines[0]); + const data = []; + + // 解析數據行 + for (let i = 1; i < lines.length; i++) { + const values = this.parseCSVLine(lines[i]); + + if (values.length === headers.length) { + const row = {}; + headers.forEach((header, index) => { + row[header] = values[index]; + }); + data.push(row); + } + } + + return data; + }, + + /** + * 解析單行 CSV + * @param {String} line - CSV 行 + * @returns {Array} 值陣列 + */ + parseCSVLine(line) { + const values = []; + let current = ''; + let inQuotes = false; + + for (let i = 0; i < line.length; i++) { + const char = line[i]; + const nextChar = line[i + 1]; + + if (char === '"') { + if (inQuotes && nextChar === '"') { + current += '"'; + i++; + } else { + inQuotes = !inQuotes; + } + } else if (char === ',' && !inQuotes) { + values.push(current); + current = ''; + } else { + current += char; + } + } + + values.push(current); + return values; + }, + + /** + * 獲取嵌套對象的值 + * @param {Object} obj - 對象 + * @param {String} path - 路徑(支援 a.b.c 格式) + * @returns {*} 值 + */ + getNestedValue(obj, path) { + return path.split('.').reduce((current, key) => { + return current ? current[key] : undefined; + }, obj); + }, + + /** + * 創建 CSV 匯入按鈕 + * @param {Function} onImport - 匯入成功的回調函數 + * @returns {HTMLElement} 按鈕元素 + */ + createImportButton(onImport) { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.csv'; + input.style.display = 'none'; + + input.addEventListener('change', (e) => { + const file = e.target.files[0]; + if (file) { + this.importFromCSV(file, onImport); + } + }); + + const button = document.createElement('button'); + button.className = 'btn btn-secondary'; + button.innerHTML = '📥 匯入 CSV'; + button.onclick = () => input.click(); + + const container = document.createElement('div'); + container.style.display = 'inline-block'; + container.appendChild(input); + container.appendChild(button); + + return container; + }, + + /** + * 創建 CSV 匯出按鈕 + * @param {Function} getData - 獲取數據的函數 + * @param {String} filename - 文件名稱 + * @param {Array} headers - CSV 標題 + * @returns {HTMLElement} 按鈕元素 + */ + createExportButton(getData, filename, headers = null) { + const button = document.createElement('button'); + button.className = 'btn btn-secondary'; + button.innerHTML = '📤 匯出 CSV'; + button.onclick = () => { + const data = getData(); + this.exportToCSV(data, filename, headers); + }; + + return button; + } +}; + +// 導出為全局變量 +if (typeof window !== 'undefined') { + window.CSVUtils = CSVUtils; +} diff --git a/index.html b/index.html index a10fe75..5bd6d14 100644 --- a/index.html +++ b/index.html @@ -606,6 +606,7 @@ .module-btn { min-width: 100%; } } +
@@ -623,6 +624,14 @@ 崗位描述 + +
@@ -650,6 +659,38 @@ ✨ I'm feeling lucky
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+
@@ -712,12 +753,12 @@
- - + +
- - + +
@@ -859,6 +900,18 @@ + +
+ + + +
+ +
+ + + +
+ + +
+
+
+ +
+
+

崗位清單

+
Position List with Sorting
+
+
+ +
+
+
+ + +
+
+ 點擊欄位標題進行排序 +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ 崗位編號 + + 崗位名稱 + + 事業體 + + 部門 + + 崗位類別 + + 編制人數 + + 生效日期 + 操作
+ 點擊「載入清單」按鈕以顯示崗位資料 +
+
+
+
+ + +
+
+
+ +
+
+

管理者頁面

+
User Administration
+
+
+ +
+
+

使用者清單

+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
工號使用者姓名Email 信箱權限等級建立日期操作
A001系統管理員admin@company.com + 最高權限管理者 + 2024-01-01 + +
A002人資主管hr_manager@company.com + 管理者 + 2024-01-15 + + +
A003一般員工employee@company.com + 一般使用者 + 2024-02-01 + + +
+
+
+
+ + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..85b44c5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask>=2.3.0 +flask-cors>=4.0.0