變更內容: - 所有資料表加上 HR_position_ 前綴 - 整理完整欄位顯示名稱與 ID 對照表 - 模組化 JS 檔案 (admin.js, ai.js, csv.js 等) - 專案結構優化 (docs/, scripts/, tests/ 等) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1516 lines
102 KiB
HTML
1516 lines
102 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-TW">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>那都AI寫的,不要問我 - HR 基礎資料維護系統</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||
|
||
<!-- 外部 CSS 樣式 -->
|
||
<link rel="stylesheet" href="styles/base.css">
|
||
<link rel="stylesheet" href="styles/layout.css">
|
||
<link rel="stylesheet" href="styles/components.css">
|
||
<link rel="stylesheet" href="styles/modules.css">
|
||
<link rel="stylesheet" href="styles/utilities.css">
|
||
|
||
<!-- 登入檢查 -->
|
||
<script>
|
||
// 檢查登入狀態
|
||
(function() {
|
||
const currentUser = localStorage.getItem('currentUser');
|
||
if (!currentUser) {
|
||
// 如果未登入,跳轉到登入頁面
|
||
window.location.href = 'login.html';
|
||
}
|
||
})();
|
||
</script>
|
||
|
||
<!-- 外部 JavaScript 模組 (ES6 Modules) -->
|
||
<script type="module" src="js/main.js"></script>
|
||
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<!-- ==================== 左側導航欄 (Sidebar) ==================== -->
|
||
<aside class="sidebar">
|
||
<!-- User Info Bar -->
|
||
<div class="user-info-bar">
|
||
<div class="user-info">
|
||
<div class="user-avatar" id="userAvatar">U</div>
|
||
<div class="user-details">
|
||
<div class="user-name" id="userName">使用者</div>
|
||
<div class="user-role" id="userRole">一般使用者</div>
|
||
</div>
|
||
</div>
|
||
<button class="logout-btn" onclick="logout()">
|
||
<svg viewBox="0 0 24 24">
|
||
<path d="M17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5zM4 5h8V3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8v-2H4V5z"/>
|
||
</svg>
|
||
<span>登出</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Module Selector (垂直導航選單) -->
|
||
<nav class="module-selector">
|
||
<button class="module-btn active" data-module="position">
|
||
<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
|
||
<span>崗位基礎資料</span>
|
||
</button>
|
||
<button class="module-btn" data-module="job">
|
||
<svg viewBox="0 0 24 24"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"/></svg>
|
||
<span>職務基礎資料</span>
|
||
</button>
|
||
<button class="module-btn" data-module="deptfunction">
|
||
<svg viewBox="0 0 24 24"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></svg>
|
||
<span>部門職責</span>
|
||
</button>
|
||
<button class="module-btn" data-module="jobdesc">
|
||
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>
|
||
<span>崗位描述</span>
|
||
</button>
|
||
<button class="module-btn" data-module="positionlist">
|
||
<svg viewBox="0 0 24 24"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg>
|
||
<span>崗位清單</span>
|
||
</button>
|
||
<button class="module-btn" data-module="admin">
|
||
<svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.31,0.06-0.63,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>
|
||
<span>管理者頁面</span>
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- Sidebar Footer -->
|
||
<div class="sidebar-footer">
|
||
HR 基礎資料維護系統 v3.0
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ==================== 右側主內容區 (Main Content) ==================== -->
|
||
<main class="main-content">
|
||
<!-- ==================== 崗位基礎資料模組 ==================== -->
|
||
<div class="module-content active" id="module-position">
|
||
<header class="app-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>崗位基礎資料維護</h1>
|
||
<div class="subtitle">Position Master Data Management</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<div class="tabs">
|
||
<button class="tab-btn active" data-tab="position-basic">基礎資料</button>
|
||
<button class="tab-btn" data-tab="position-recruit">招聘要求資料</button>
|
||
</div>
|
||
|
||
<form id="positionForm">
|
||
<div class="tab-content active" id="tab-position-basic">
|
||
<!-- AI 幫我想:單一 AI 生成按鈕 + 可編輯 prompt -->
|
||
<div class="ai-helper-container" data-module="positionBasic">
|
||
<button type="button" class="ai-helper-btn" onclick="executeAIHelper('positionBasic')">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
AI 幫我想
|
||
</button>
|
||
<div class="ai-prompt-editor">
|
||
<div class="prompt-header">
|
||
<span class="prompt-label">Prompt 指令</span>
|
||
<button type="button" class="prompt-reset-btn" onclick="resetPromptToDefault('positionBasic')" title="重置為預設">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<textarea class="prompt-textarea" id="prompt_positionBasic" rows="4" placeholder="輸入 AI 生成指令..."></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<!-- [組織定義] -->
|
||
<div class="form-group">
|
||
<label>事業體 (Business Unit)</label>
|
||
<select id="pos_businessUnit" name="businessUnit">
|
||
<option value="">請選擇</option>
|
||
<option value="SBU">SBU - 銷售事業體</option>
|
||
<option value="MBU">MBU - 製造事業體</option>
|
||
<option value="HQBU">HQBU - 總部事業體</option>
|
||
<option value="ITBU">ITBU - IT事業體</option>
|
||
<option value="HRBU">HRBU - HR事業體</option>
|
||
<option value="ACCBU">ACCBU - 會計事業體</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>處級單位 (Division)</label>
|
||
<select id="pos_division" name="division">
|
||
<option value="">請選擇</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>部級單位 (Department)</label>
|
||
<select id="pos_department" name="department">
|
||
<option value="">請選擇</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>課級單位 (Section)</label>
|
||
<input type="text" id="pos_section" name="section" placeholder="選填">
|
||
</div>
|
||
|
||
<!-- [核心識別] -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 崗位編號</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="pos_code" name="positionCode" required placeholder="請輸入崗位編號">
|
||
<button type="button" class="btn-lookup" onclick="changePositionCode()">更改崗位編號</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 崗位名稱</label>
|
||
<input type="text" id="pos_name" name="positionName" required placeholder="請輸入崗位名稱">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>生效日期</label>
|
||
<input type="date" id="pos_effectiveDate" name="effectiveDate">
|
||
</div>
|
||
|
||
<!-- [分類屬性] -->
|
||
<div class="form-group">
|
||
<label>崗位級別</label>
|
||
<select id="pos_level" name="positionLevel">
|
||
<option value="">請選擇</option>
|
||
<option value="L1">L1 - 基層員工</option>
|
||
<option value="L2">L2 - 資深員工</option>
|
||
<option value="L3">L3 - 主管</option>
|
||
<option value="L4">L4 - 經理</option>
|
||
<option value="L5">L5 - 總監</option>
|
||
<option value="L6">L6 - 副總</option>
|
||
<option value="L7">L7 - 總經理</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位類別</label>
|
||
<select id="pos_category" name="positionCategory" onchange="updateCategoryName()">
|
||
<option value="">請選擇</option>
|
||
<option value="01">01</option>
|
||
<option value="02">02</option>
|
||
<option value="03">03</option>
|
||
<option value="04">04</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位類別名稱</label>
|
||
<input type="text" id="pos_categoryName" name="positionCategoryName" readonly placeholder="自動帶出">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位性質</label>
|
||
<select id="pos_type" name="positionType" onchange="updateNatureName()">
|
||
<option value="">請選擇</option>
|
||
<option value="FT">全職</option>
|
||
<option value="PT">兼職</option>
|
||
<option value="CT">約聘</option>
|
||
<option value="IN">實習</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位性質名稱</label>
|
||
<input type="text" id="pos_typeName" name="positionTypeName" readonly placeholder="自動帶出">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>編制人數</label>
|
||
<input type="number" id="pos_headcount" name="headcount" min="0" placeholder="請輸入編制人數">
|
||
</div>
|
||
|
||
<!-- [詳細描述] -->
|
||
<div class="form-group full-width">
|
||
<label>崗位描述(條列式說明)</label>
|
||
<textarea id="pos_desc" name="description" placeholder="請以條列式輸入崗位描述,例如: 1. 負責系統開發與維護 2. 撰寫技術文件 3. 參與專案規劃與執行" rows="6"></textarea>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>崗位備注(條列式說明)</label>
|
||
<textarea id="pos_remark" name="remark" placeholder="請以條列式輸入備注說明,例如: 1. 需具備良好溝通能力 2. 可配合加班 3. 其他注意事項" rows="4"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tab-content" id="tab-position-recruit">
|
||
<!-- AI 幫我想:單一 AI 生成按鈕 + 可編輯 prompt -->
|
||
<div class="ai-helper-container" data-module="positionRecruit">
|
||
<button type="button" class="ai-helper-btn" onclick="executeAIHelper('positionRecruit')">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
AI 幫我想
|
||
</button>
|
||
<div class="ai-prompt-editor">
|
||
<div class="prompt-header">
|
||
<span class="prompt-label">Prompt 指令</span>
|
||
<button type="button" class="prompt-reset-btn" onclick="resetPromptToDefault('positionRecruit')" title="重置為預設">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<textarea class="prompt-textarea" id="prompt_positionRecruit" rows="4" placeholder="輸入 AI 生成指令..."></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<!-- [招聘職位定義] -->
|
||
<div class="form-group">
|
||
<label>招聘職位代碼</label>
|
||
<select id="rec_position" name="recruitPosition">
|
||
<option value="">請選擇</option>
|
||
<option value="ENG">ENG - 工程師</option>
|
||
<option value="MGR">MGR - 經理</option>
|
||
<option value="AST">AST - 助理</option>
|
||
<option value="OP">OP - 作業員</option>
|
||
<option value="SAL">SAL - 業務</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>對外職稱</label>
|
||
<input type="text" id="rec_jobTitle" name="jobTitle" placeholder="顯示在招聘網的名稱">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>上級崗位編號</label>
|
||
<input type="text" id="rec_superiorCode" name="superiorPositionCode" placeholder="請輸入上級崗位編號">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>工作性質</label>
|
||
<select id="rec_jobType" name="jobType">
|
||
<option value="">請選擇</option>
|
||
<option value="FT">全職</option>
|
||
<option value="PT">兼職</option>
|
||
<option value="CT">約聘</option>
|
||
<option value="DP">派遣</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- [硬性資格] -->
|
||
<div class="form-group">
|
||
<label>最低學歷</label>
|
||
<select id="rec_eduLevel" name="educationLevel">
|
||
<option value="">請選擇</option>
|
||
<option value="HS">高中/職</option>
|
||
<option value="JC">專科</option>
|
||
<option value="BA">大學</option>
|
||
<option value="MA">碩士</option>
|
||
<option value="PHD">博士</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>專業要求</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="rec_majorReq" name="majorRequirements" readonly placeholder="點擊選擇專業">
|
||
<button type="button" class="btn-lookup" onclick="openMajorModal()">專業要求</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>工作經驗</label>
|
||
<select id="rec_expYears" name="experienceYears">
|
||
<option value="">請選擇</option>
|
||
<option value="0">不限</option>
|
||
<option value="1">1年以上</option>
|
||
<option value="3">3年以上</option>
|
||
<option value="5">5年以上</option>
|
||
<option value="10">10年以上</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>薪酬范圍</label>
|
||
<select id="rec_salaryRange" name="salaryRange">
|
||
<option value="">請選擇</option>
|
||
<option value="A">30,000 以下</option>
|
||
<option value="B">30,000 - 50,000</option>
|
||
<option value="C">50,000 - 80,000</option>
|
||
<option value="D">80,000 - 120,000</option>
|
||
<option value="E">120,000 以上</option>
|
||
<option value="N">面議</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>要求性別</label>
|
||
<select id="rec_gender" name="requiredGender">
|
||
<option value="">不限</option>
|
||
<option value="M">男</option>
|
||
<option value="F">女</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>年齡限制 (Min)</label>
|
||
<input type="number" id="rec_minAge" name="minAge" min="18" max="65" placeholder="歲">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>年齡限制 (Max)</label>
|
||
<input type="number" id="rec_maxAge" name="maxAge" min="18" max="65" placeholder="歲">
|
||
</div>
|
||
|
||
<!-- [技能與證照] -->
|
||
<div class="form-group">
|
||
<label>語言要求</label>
|
||
<input type="text" id="rec_langReq" name="langRequirements" placeholder="如:英文中級、日文N2...">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>證照要求</label>
|
||
<select id="rec_certReq" name="certRequirements">
|
||
<option value="">請選擇</option>
|
||
<option value="NONE">不限</option>
|
||
<option value="CERT">相關證照</option>
|
||
<option value="LIC">專業執照</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>技能要求</label>
|
||
<input type="text" id="rec_skillReq" name="skillRequirements" placeholder="如:Excel, Python, SAP...">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>其他要求</label>
|
||
<input type="text" id="rec_otherReq" name="otherRequirements" placeholder="請輸入其他要求">
|
||
</div>
|
||
|
||
<!-- [文案描述] -->
|
||
<div class="form-group full-width">
|
||
<label>職位描述 (JD)</label>
|
||
<textarea id="rec_jobDesc" name="recruitJobDesc" placeholder="廣告用職位描述..." rows="3"></textarea>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>崗位要求 (Req)</label>
|
||
<textarea id="rec_positionReq" name="recruitRequirements" placeholder="廣告用崗位要求..." rows="3"></textarea>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>招聘備注</label>
|
||
<textarea id="rec_remark" name="recruitRemark" placeholder="內部用備注說明..." rows="4"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<div class="form-actions">
|
||
<div class="nav-buttons">
|
||
<button class="nav-btn" title="第一筆"><svg viewBox="0 0 24 24"><path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6 1.41-1.41zM6 6h2v12H6V6z"/></svg></button>
|
||
<button class="nav-btn" title="上一筆"><svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg></button>
|
||
<button class="nav-btn" title="下一筆"><svg viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg></button>
|
||
<button class="nav-btn" title="最後一筆"><svg viewBox="0 0 24 24"><path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6-1.41 1.41zM16 6h2v12h-2V6z"/></svg></button>
|
||
</div>
|
||
<!-- CSV 匯入匯出按鈕 -->
|
||
<div class="csv-buttons" style="margin-bottom: 15px; display: flex; gap: 10px;">
|
||
<button type="button" class="btn btn-secondary" onclick="downloadPositionCSVTemplate()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>
|
||
下載範本
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="exportPositionsCSV()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></svg>
|
||
匯出 CSV
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="importPositionsCSV()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/></svg>
|
||
匯入 CSV
|
||
</button>
|
||
<input type="file" id="positionCSVInput" accept=".csv" style="display: none;" onchange="handlePositionCSVImport(event)">
|
||
</div>
|
||
<div class="action-buttons">
|
||
<button type="button" class="btn btn-gradient-purple" onclick="saveToPositionList()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
儲存至崗位清單
|
||
</button>
|
||
<button type="button" class="btn btn-primary" onclick="savePositionAndExit()">
|
||
<svg viewBox="0 0 24 24"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>
|
||
保存并退出(S)
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="savePositionAndNew()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
保存并新增(N)
|
||
</button>
|
||
<button type="button" class="btn btn-cancel" onclick="cancelPositionForm()">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 職務基礎資料模組 ==================== -->
|
||
<div class="module-content" id="module-job">
|
||
<header class="app-header job-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>職務基礎資料維護</h1>
|
||
<div class="subtitle">Job Title Master Data Management</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<div class="tabs">
|
||
<button class="tab-btn active" data-tab="job-basic">基礎資料</button>
|
||
</div>
|
||
|
||
<form id="jobForm">
|
||
<div class="tab-content active" id="tab-job-basic">
|
||
<!-- AI 幫我想:單一 AI 生成按鈕 + 可編輯 prompt -->
|
||
<div class="ai-helper-container" data-module="jobBasic">
|
||
<button type="button" class="ai-helper-btn" onclick="executeAIHelper('jobBasic')">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
AI 幫我想
|
||
</button>
|
||
<div class="ai-prompt-editor">
|
||
<div class="prompt-header">
|
||
<span class="prompt-label">Prompt 指令</span>
|
||
<button type="button" class="prompt-reset-btn" onclick="resetPromptToDefault('jobBasic')" title="重置為預設">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<textarea class="prompt-textarea" id="prompt_jobBasic" rows="4" placeholder="輸入 AI 生成指令..."></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="form-grid">
|
||
<!-- [分類與識別] -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 職務類別</label>
|
||
<select id="job_category" name="jobCategoryCode" required onchange="updateJobCategoryName()">
|
||
<option value="">請選擇</option>
|
||
<option value="MGR">管理職</option>
|
||
<option value="TECH">技術職</option>
|
||
<option value="SALE">業務職</option>
|
||
<option value="ADMIN">行政職</option>
|
||
<option value="RD">研發職</option>
|
||
<option value="PROD">生產職</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>職務類別名稱</label>
|
||
<input type="text" id="job_categoryName" name="jobCategoryName" readonly placeholder="自動帶出">
|
||
</div>
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 職務編號</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="job_code" name="jobCode" required placeholder="請輸入職務編號">
|
||
<button type="button" class="btn-lookup" onclick="changeJobCode()">更改職務編號</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 職務名稱</label>
|
||
<input type="text" id="job_name" name="jobName" required placeholder="請輸入職務名稱">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>職務英文名稱</label>
|
||
<input type="text" id="job_nameEn" name="jobNameEn" placeholder="請輸入職務英文名稱">
|
||
</div>
|
||
|
||
<!-- [屬性設定] -->
|
||
<div class="form-group">
|
||
<label>職務層級</label>
|
||
<div class="confidential-field">
|
||
<input type="text" id="job_level" name="jobLevel" placeholder="敏感欄位">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>生效日期</label>
|
||
<input type="date" id="job_effectiveDate" name="effectiveDate">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>排列順序</label>
|
||
<input type="number" id="job_sortOrder" name="sortOrder" min="0" placeholder="請輸入排序">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>預算編制人數</label>
|
||
<input type="number" id="job_headcount" name="headcount" min="0" placeholder="請輸入人數">
|
||
</div>
|
||
|
||
<!-- [福利開關] -->
|
||
<div class="form-group">
|
||
<label>全勤獎金</label>
|
||
<div class="toggle-group">
|
||
<label class="toggle-switch">
|
||
<input type="checkbox" id="job_hasAttBonus" name="hasAttendanceBonus">
|
||
<span class="toggle-slider"></span>
|
||
</label>
|
||
<span class="toggle-label" id="attendanceLabel">否</span>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>住房補貼</label>
|
||
<div class="toggle-group">
|
||
<label class="toggle-switch">
|
||
<input type="checkbox" id="job_hasHouseAllow" name="hasHousingAllowance">
|
||
<span class="toggle-slider"></span>
|
||
</label>
|
||
<span class="toggle-label" id="housingLabel">否</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- [備註] -->
|
||
<div class="form-group full-width">
|
||
<label>職務備注</label>
|
||
<textarea id="job_remark" name="remark" placeholder="請輸入備注說明..." rows="4"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<div class="form-actions">
|
||
<div class="nav-buttons">
|
||
<button class="nav-btn" title="第一筆"><svg viewBox="0 0 24 24"><path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6 1.41-1.41zM6 6h2v12H6V6z"/></svg></button>
|
||
<button class="nav-btn" title="上一筆"><svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg></button>
|
||
<button class="nav-btn" title="下一筆"><svg viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg></button>
|
||
<button class="nav-btn" title="最後一筆"><svg viewBox="0 0 24 24"><path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6-1.41 1.41zM16 6h2v12h-2V6z"/></svg></button>
|
||
</div>
|
||
<!-- CSV 匯入匯出按鈕 -->
|
||
<div class="csv-buttons" style="margin-bottom: 15px; display: flex; gap: 10px;">
|
||
<button type="button" class="btn btn-secondary" onclick="downloadJobCSVTemplate()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>
|
||
下載範本
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="exportJobsCSV()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></svg>
|
||
匯出 CSV
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="importJobsCSV()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/></svg>
|
||
匯入 CSV
|
||
</button>
|
||
<input type="file" id="jobCSVInput" accept=".csv" style="display: none;" onchange="handleJobCSVImport(event)">
|
||
</div>
|
||
<div class="action-buttons">
|
||
<button type="button" class="btn btn-gradient-purple" onclick="saveJobToPositionList()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
儲存至崗位清單
|
||
</button>
|
||
<button type="button" class="btn btn-primary" onclick="saveJobAndExit()">
|
||
<svg viewBox="0 0 24 24"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>
|
||
保存并退出(S)
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="saveJobAndNew()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
保存并新增(N)
|
||
</button>
|
||
<button type="button" class="btn btn-cancel" onclick="cancelJobForm()">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ==================== 部門職責模組 ==================== -->
|
||
<div class="module-content" id="module-deptfunction">
|
||
<header class="app-header deptfunc-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>部門職責維護</h1>
|
||
<div class="subtitle">Department Function Management</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<form id="deptFunctionForm">
|
||
<div class="tab-content active">
|
||
<!-- AI 幫我想:單一 AI 生成按鈕 + 可編輯 prompt -->
|
||
<div class="ai-helper-container" data-module="deptFunction">
|
||
<button type="button" class="ai-helper-btn" onclick="executeAIHelper('deptFunction')">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
AI 幫我想
|
||
</button>
|
||
<div class="ai-prompt-editor">
|
||
<div class="prompt-header">
|
||
<span class="prompt-label">Prompt 指令</span>
|
||
<button type="button" class="prompt-reset-btn" onclick="resetPromptToDefault('deptFunction')" title="重置為預設">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<textarea class="prompt-textarea" id="prompt_deptFunction" rows="4" placeholder="輸入 AI 生成指令..."></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="csv-buttons">
|
||
<button type="button" class="btn btn-secondary" onclick="importDeptFunctionCSV()">匯入 CSV</button>
|
||
<button type="button" class="btn btn-secondary" onclick="exportDeptFunctionCSV()">匯出 CSV</button>
|
||
<input type="file" id="deptFunctionCsvInput" accept=".csv" style="display: none;" onchange="handleDeptFunctionCSVImport(event)">
|
||
</div>
|
||
|
||
<div class="form-grid">
|
||
<!-- 職責編號 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 職責編號</label>
|
||
<input type="text" id="df_code" name="dfCode" required placeholder="例如: DF-001">
|
||
</div>
|
||
<!-- 職責名稱 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 職責名稱</label>
|
||
<input type="text" id="df_name" name="dfName" required placeholder="例如: 軟體研發部職責">
|
||
</div>
|
||
|
||
<!-- 事業體 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 事業體 (Business Unit)</label>
|
||
<select id="df_businessUnit" name="businessUnit" onchange="onDeptFuncBusinessUnitChange(event)" required>
|
||
<option value="">請選擇</option>
|
||
</select>
|
||
</div>
|
||
<!-- 處級單位 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 處級單位 (Division)</label>
|
||
<select id="df_division" name="division" onchange="onDeptFuncDivisionChange(event)" required>
|
||
<option value="">請先選擇事業體</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 部級單位 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 部級單位 (Department)</label>
|
||
<select id="df_department" name="department" onchange="onDeptFuncDepartmentChange(event)" required>
|
||
<option value="">請先選擇處級單位</option>
|
||
</select>
|
||
</div>
|
||
<!-- 課級單位 -->
|
||
<div class="form-group">
|
||
<label>課級單位 (Section)</label>
|
||
<input type="text" id="df_section" name="section" placeholder="請輸入課級單位(選填)">
|
||
</div>
|
||
|
||
<!-- 對應崗位 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 對應崗位</label>
|
||
<select id="df_posTitle" name="positionTitle" required>
|
||
<option value="">請先選擇部級單位</option>
|
||
</select>
|
||
</div>
|
||
<!-- 崗位級別 -->
|
||
<div class="form-group">
|
||
<label>崗位級別</label>
|
||
<select id="df_posLevel" name="positionLevel">
|
||
<option value="">請選擇</option>
|
||
<option value="E">E - 執行級</option>
|
||
<option value="M">M - 管理級</option>
|
||
<option value="S">S - 監督級</option>
|
||
<option value="D">D - 總監級</option>
|
||
<option value="VP">VP - 副總裁級</option>
|
||
<option value="C">C - 高階主管</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 部門主管職稱 -->
|
||
<div class="form-group">
|
||
<label>部門主管職稱</label>
|
||
<input type="text" id="df_managerTitle" name="managerTitle" placeholder="例如: 部門經理">
|
||
</div>
|
||
<!-- 生效日期 -->
|
||
<div class="form-group">
|
||
<label><span class="required">*</span> 生效日期</label>
|
||
<input type="date" id="df_effectiveDate" name="effectiveDate" required>
|
||
</div>
|
||
|
||
<!-- 人數上限 -->
|
||
<div class="form-group">
|
||
<label>人數上限</label>
|
||
<input type="number" id="df_headcountLimit" name="headcountLimit" min="1" placeholder="例如: 50">
|
||
</div>
|
||
<!-- 狀態 -->
|
||
<div class="form-group">
|
||
<label>狀態</label>
|
||
<select id="df_status" name="status">
|
||
<option value="active">啟用中</option>
|
||
<option value="inactive">停用</option>
|
||
<option value="planning">規劃中</option>
|
||
</select>
|
||
</div>
|
||
|
||
<!-- 部門使命 -->
|
||
<div class="form-group full-width">
|
||
<label>部門使命 (Mission)</label>
|
||
<textarea id="df_mission" name="mission" placeholder="• 請描述部門的核心使命..." rows="3"></textarea>
|
||
</div>
|
||
|
||
<!-- 部門願景 -->
|
||
<div class="form-group full-width">
|
||
<label>部門願景 (Vision)</label>
|
||
<textarea id="df_vision" name="vision" placeholder="• 請描述部門的長期願景..." rows="3"></textarea>
|
||
</div>
|
||
|
||
<!-- 核心職責 -->
|
||
<div class="form-group full-width">
|
||
<label><span class="required">*</span> 核心職責 (Core Functions)</label>
|
||
<textarea id="df_coreFunc" name="coreFunctions" required placeholder="• 職責一:... • 職責二:... • 職責三:..." rows="6"></textarea>
|
||
</div>
|
||
|
||
<!-- 關鍵績效指標 -->
|
||
<div class="form-group full-width">
|
||
<label>關鍵績效指標 (KPIs)</label>
|
||
<textarea id="df_kpis" name="kpis" placeholder="• KPI 1:... • KPI 2:... • KPI 3:..." rows="4"></textarea>
|
||
</div>
|
||
|
||
<!-- 協作部門 -->
|
||
<div class="form-group full-width">
|
||
<label>協作部門</label>
|
||
<textarea id="df_collab" name="collaboration" placeholder="• 與XX部門協作進行... • 與YY部門共同負責..." rows="3"></textarea>
|
||
</div>
|
||
|
||
<!-- 備注 -->
|
||
<div class="form-group full-width">
|
||
<label>備注</label>
|
||
<textarea id="df_remark" name="remark" placeholder="請輸入其他補充說明..." rows="3"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="action-bar">
|
||
<div class="nav-buttons">
|
||
<button class="nav-btn" title="第一筆"><svg viewBox="0 0 24 24"><path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6 1.41-1.41zM6 6h2v12H6V6z"/></svg></button>
|
||
<button class="nav-btn" title="上一筆"><svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg></button>
|
||
<button class="nav-btn" title="下一筆"><svg viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg></button>
|
||
<button class="nav-btn" title="最後一筆"><svg viewBox="0 0 24 24"><path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6-1.41 1.41zM16 6h2v12h-2V6z"/></svg></button>
|
||
</div>
|
||
<div class="action-buttons">
|
||
<button type="button" class="btn btn-gradient-purple" onclick="saveDeptFunctionToPositionList()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
儲存至崗位清單
|
||
</button>
|
||
<button class="btn btn-secondary" onclick="clearDeptFunctionForm()">清除</button>
|
||
<button class="btn btn-cancel" onclick="cancelDeptFunction()">取消</button>
|
||
<button class="btn btn-primary" onclick="saveDeptFunctionAndNew()">存檔續建</button>
|
||
<button class="btn btn-primary" onclick="saveDeptFunctionAndExit()">存檔離開</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 崗位描述模組 ==================== -->
|
||
<div class="module-content" id="module-jobdesc">
|
||
<header class="app-header desc-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>崗位描述維護 (新增)</h1>
|
||
<div class="subtitle">Job Description Management</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<div class="tabs">
|
||
<button class="tab-btn active" data-tab="jobdesc-basic">基礎資料</button>
|
||
</div>
|
||
|
||
<form id="jobDescForm">
|
||
<div class="tab-content active" id="tab-jobdesc-basic">
|
||
<!-- AI 幫我想:單一 AI 生成按鈕 + 可編輯 prompt -->
|
||
<div class="ai-helper-container" data-module="jobDesc">
|
||
<button type="button" class="ai-helper-btn" onclick="executeAIHelper('jobDesc')">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
AI 幫我想
|
||
</button>
|
||
<div class="ai-prompt-editor">
|
||
<div class="prompt-header">
|
||
<span class="prompt-label">Prompt 指令</span>
|
||
<button type="button" class="prompt-reset-btn" onclick="resetPromptToDefault('jobDesc')" title="重置為預設">
|
||
<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<textarea class="prompt-textarea" id="prompt_jobDesc" rows="4" placeholder="輸入 AI 生成指令..."></textarea>
|
||
</div>
|
||
</div>
|
||
<!-- 頂部區域 -->
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>工號</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="jd_empNo" name="empNo" placeholder="請輸入工號">
|
||
<button type="button" class="btn-icon" onclick="openEmpSearchModal()" title="選擇員工">
|
||
<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
|
||
</button>
|
||
<button type="button" class="btn-icon" onclick="openOrgSearchModal()" title="選擇組織">
|
||
<svg viewBox="0 0 24 24"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>姓名</label>
|
||
<input type="text" id="jd_empName" name="empName" readonly placeholder="自動帶出">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位代碼</label>
|
||
<input type="text" id="jd_posCode" name="positionCode" placeholder="請輸入崗位代碼">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>版本更新日期</label>
|
||
<input type="date" id="jd_versionDate" name="versionDate">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 崗位基本信息 Section -->
|
||
<div class="section-box" style="margin-top: 24px;">
|
||
<div class="section-header green">崗位基本信息</div>
|
||
<div class="section-body">
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>崗位名稱</label>
|
||
<input type="text" id="jd_posName" name="positionName" placeholder="請輸入崗位名稱">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>事業體 (Business Unit)</label>
|
||
<select id="jd_businessUnit" name="businessUnit" onchange="onJobDescBusinessUnitChange(event)">
|
||
<option value="">請選擇</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>處級單位 (Division)</label>
|
||
<select id="jd_division" name="division" onchange="onJobDescDivisionChange(event)">
|
||
<option value="">請先選擇事業體</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>部級單位 (Department)</label>
|
||
<select id="jd_department" name="department" onchange="onJobDescDepartmentChange(event)">
|
||
<option value="">請先選擇處級單位</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>課級單位 (Section)</label>
|
||
<input type="text" id="jd_section" name="section" placeholder="請輸入課級單位(選填)">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位級別</label>
|
||
<select id="jd_posLevel" name="positionLevel">
|
||
<option value="">請選擇</option>
|
||
<option value="E">E - 執行級</option>
|
||
<option value="M">M - 管理級</option>
|
||
<option value="S">S - 監督級</option>
|
||
<option value="D">D - 總監級</option>
|
||
<option value="VP">VP - 副總裁級</option>
|
||
<option value="C">C - 高階主管</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>崗位生效日期</label>
|
||
<input type="date" id="jd_posEffDate" name="positionEffectiveDate">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>直接主管</label>
|
||
<input type="text" id="jd_supervisor" name="directSupervisor" placeholder="請輸入直接主管職務">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>職等&職務</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="jd_gradeJob" name="positionGradeJob" readonly placeholder="點擊選擇">
|
||
<button type="button" class="btn-icon" onclick="openGradeJobModal()" title="選擇職等職務">
|
||
<svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>匯報對象</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="jd_reportTo" name="reportTo" readonly placeholder="點擊選擇">
|
||
<button type="button" class="btn-icon" onclick="openReportToModal()" title="選擇匯報對象">
|
||
<svg viewBox="0 0 24 24"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>直接下屬</label>
|
||
<input type="text" id="jd_directReports" name="directReports" placeholder="如:工程師 × 5人">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>任職地點</label>
|
||
<select id="jd_location" name="workLocation">
|
||
<option value="">請選擇</option>
|
||
<option value="HQ">總部</option>
|
||
<option value="TPE">台北辦公室</option>
|
||
<option value="TYC">桃園廠區</option>
|
||
<option value="KHH">高雄廠區</option>
|
||
<option value="SH">上海辦公室</option>
|
||
<option value="SZ">深圳辦公室</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>員工屬性</label>
|
||
<select id="jd_empAttr" name="empAttribute">
|
||
<option value="">請選擇</option>
|
||
<option value="FT">正式員工</option>
|
||
<option value="CT">約聘人員</option>
|
||
<option value="PT">兼職人員</option>
|
||
<option value="IN">實習生</option>
|
||
<option value="DP">派遣人員</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 部門職責資訊 Section (關聯顯示) -->
|
||
<div class="section-box" id="deptFunctionInfoSection" style="margin-top: 24px; display: none;">
|
||
<div class="section-header" style="background: linear-gradient(135deg, #8e44ad 0%, #9b59b6 100%);">部門職責資訊 (自動帶入)</div>
|
||
<div class="section-body">
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>部門職責編號</label>
|
||
<input type="text" id="jd_dfCode" readonly style="background: #f8f9fa;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>事業體</label>
|
||
<input type="text" id="jd_dfBU" readonly style="background: #f8f9fa;">
|
||
</div>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>部門使命</label>
|
||
<textarea id="jd_deptMission" readonly rows="2" style="background: #f8f9fa;"></textarea>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>部門核心職責</label>
|
||
<textarea id="jd_deptCoreFunctions" readonly rows="4" style="background: #f8f9fa;"></textarea>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>部門 KPIs</label>
|
||
<textarea id="jd_deptKPIs" readonly rows="3" style="background: #f8f9fa;"></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 崗位設置目的 -->
|
||
<div class="form-group full-width" style="margin-bottom: 24px;">
|
||
<label>崗位設置目的</label>
|
||
<div class="input-wrapper">
|
||
<input type="text" id="jd_purpose" name="positionPurpose" placeholder="請輸入崗位設置目的" style="flex: 1;">
|
||
<button type="button" class="btn-icon" onclick="expandPurpose()" title="展開編輯">
|
||
<svg viewBox="0 0 24 24"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 職責描述 Section -->
|
||
<div class="section-box">
|
||
<div class="section-header green">職責描述</div>
|
||
<div class="section-body">
|
||
<div class="form-group full-width">
|
||
<label>主要職責</label>
|
||
<textarea id="jd_mainResp" name="mainResponsibilities" class="numbered-textarea" rows="8" placeholder="1、
|
||
2、
|
||
3、
|
||
4、
|
||
5、">1、
|
||
2、
|
||
3、
|
||
4、</textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 崗位要求 Section -->
|
||
<div class="section-box">
|
||
<div class="section-header green">崗位要求</div>
|
||
<div class="section-body">
|
||
<div class="form-grid">
|
||
<div class="form-group full-width">
|
||
<label>教育程度</label>
|
||
<input type="text" id="jd_eduLevel" name="educationLevel" placeholder="如:大學本科及以上學歷">
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>基本技能</label>
|
||
<div class="input-wrapper">
|
||
<textarea id="jd_basicSkills" name="basicSkills" rows="2" placeholder="請輸入基本技能要求..." style="flex: 1;"></textarea>
|
||
<button type="button" class="btn-icon" style="align-self: flex-start;" onclick="expandField('basicSkills')" title="展開">
|
||
<svg viewBox="0 0 24 24"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>專業知識</label>
|
||
<div class="input-wrapper">
|
||
<textarea id="jd_proKnowledge" name="professionalKnowledge" rows="2" placeholder="請輸入專業知識要求..." style="flex: 1;"></textarea>
|
||
<button type="button" class="btn-icon" style="align-self: flex-start;" onclick="expandField('proKnowledge')" title="展開">
|
||
<svg viewBox="0 0 24 24"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>工作經驗</label>
|
||
<div class="input-wrapper">
|
||
<textarea id="jd_expReq" name="experienceRequirements" rows="2" placeholder="請輸入工作經驗要求..." style="flex: 1;"></textarea>
|
||
<button type="button" class="btn-icon" style="align-self: flex-start;" onclick="expandField('expReq')" title="展開">
|
||
<svg viewBox="0 0 24 24"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label>其他要求</label>
|
||
<textarea id="jd_otherReq" name="otherRequirements" rows="3" placeholder="請輸入其他要求..."></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<div class="form-actions">
|
||
<div class="nav-buttons">
|
||
<button class="nav-btn" title="第一筆"><svg viewBox="0 0 24 24"><path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6 1.41-1.41zM6 6h2v12H6V6z"/></svg></button>
|
||
<button class="nav-btn" title="上一筆"><svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg></button>
|
||
<button class="nav-btn" title="下一筆"><svg viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg></button>
|
||
<button class="nav-btn" title="最後一筆"><svg viewBox="0 0 24 24"><path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6-1.41 1.41zM16 6h2v12h-2V6z"/></svg></button>
|
||
</div>
|
||
<div class="action-buttons">
|
||
<button type="button" class="btn btn-gradient-purple" onclick="saveJobDescToPositionList()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
儲存至崗位清單
|
||
</button>
|
||
<button type="button" class="btn btn-primary" onclick="saveJobDescAndExit()">
|
||
<svg viewBox="0 0 24 24"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>
|
||
保存并退出(S)
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="saveJobDescAndNew()">
|
||
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||
保存并新增(N)
|
||
</button>
|
||
<button type="button" class="btn btn-cancel" onclick="cancelJobDescForm()">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- JSON Preview (崗位描述專用) -->
|
||
<div class="data-preview">
|
||
<h4>資料預覽 (JSON Format)</h4>
|
||
<pre id="jsonPreview">{}</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Major Modal -->
|
||
<div class="modal-overlay" id="majorModal">
|
||
<div class="modal">
|
||
<div class="modal-header">
|
||
<h3>選擇專業要求</h3>
|
||
<button class="modal-close" onclick="closeMajorModal()">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="checkbox-group">
|
||
<div class="checkbox-item"><input type="checkbox" id="major_cs" value="資訊工程"><label for="major_cs">資訊工程</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_ee" value="電機電子"><label for="major_ee">電機電子</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_me" value="機械工程"><label for="major_me">機械工程</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_ba" value="企業管理"><label for="major_ba">企業管理</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_acc" value="會計財務"><label for="major_acc">會計財務</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_hr" value="人力資源"><label for="major_hr">人力資源</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_mkt" value="行銷企劃"><label for="major_mkt">行銷企劃</label></div>
|
||
<div class="checkbox-item"><input type="checkbox" id="major_law" value="法律"><label for="major_law">法律</label></div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-cancel" onclick="closeMajorModal()">取消</button>
|
||
<button class="btn btn-primary" onclick="confirmMajor()">確認</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Toast -->
|
||
<div class="toast" id="toast">
|
||
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
|
||
<span id="toastMessage">保存成功!</span>
|
||
</div>
|
||
|
||
|
||
<!-- ==================== 崗位清單模組 ==================== -->
|
||
<div class="module-content position-list-module" id="module-positionlist">
|
||
<header class="app-header list-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>崗位清單</h1>
|
||
<div class="subtitle">Position List with Sorting</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<div class="module-toolbar">
|
||
<div class="module-toolbar-left">
|
||
<button type="button" class="btn btn-primary" onclick="loadPositionList()">
|
||
<svg viewBox="0 0 24 24"><path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/></svg>
|
||
載入清單
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="exportPositionListCSV()">
|
||
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></svg>
|
||
匯出 CSV
|
||
</button>
|
||
</div>
|
||
<div class="module-toolbar-right">
|
||
<span class="hint">點擊欄位標題進行排序</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="data-table-container">
|
||
<table id="positionListTable" class="data-table position-list-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="sortable" data-sort="positionCode" onclick="sortPositionList('positionCode')">
|
||
崗位編號 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable" data-sort="positionName" onclick="sortPositionList('positionName')">
|
||
崗位名稱 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable hide-mobile" data-sort="positionCategory" onclick="sortPositionList('positionCategory')">
|
||
崗位類別 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable hide-tablet" data-sort="positionNature" onclick="sortPositionList('positionNature')">
|
||
崗位性質 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable hide-tablet" data-sort="headcount" onclick="sortPositionList('headcount')">
|
||
編制人數 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable hide-mobile" data-sort="positionLevel" onclick="sortPositionList('positionLevel')">
|
||
崗位等級 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="sortable hide-tablet" data-sort="effectiveDate" onclick="sortPositionList('effectiveDate')">
|
||
生效日期 <span class="sort-icon"></span>
|
||
</th>
|
||
<th class="action-cell">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="positionListBody">
|
||
<tr class="empty-row">
|
||
<td colspan="8">
|
||
點擊「載入清單」按鈕以顯示崗位資料
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ==================== 管理者頁面模組 ==================== -->
|
||
<div class="module-content admin-module" id="module-admin">
|
||
<header class="app-header admin-header">
|
||
<div class="icon">
|
||
<svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.31,0.06-0.63,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h1>管理者頁面</h1>
|
||
<div class="subtitle">User Administration</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="form-card">
|
||
<div class="module-toolbar">
|
||
<div class="module-toolbar-left">
|
||
<h2>使用者清單</h2>
|
||
</div>
|
||
<div class="module-toolbar-right">
|
||
<button type="button" class="btn btn-primary" onclick="showAddUserModal()">
|
||
<svg viewBox="0 0 24 24"><path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
|
||
新增使用者
|
||
</button>
|
||
<button type="button" class="btn btn-secondary" onclick="exportUsersCSV()">
|
||
<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></svg>
|
||
匯出 CSV
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="data-table-container">
|
||
<table id="userListTable" class="data-table admin-table">
|
||
<thead>
|
||
<tr>
|
||
<th>工號</th>
|
||
<th>使用者姓名</th>
|
||
<th class="hide-mobile">Email 信箱</th>
|
||
<th>權限等級</th>
|
||
<th class="hide-tablet">建立日期</th>
|
||
<th class="action-cell">操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="userListBody">
|
||
<tr>
|
||
<td>A001</td>
|
||
<td>系統管理員</td>
|
||
<td class="hide-mobile">admin@company.com</td>
|
||
<td>
|
||
<span class="permission-badge admin-highest">最高權限管理者</span>
|
||
</td>
|
||
<td class="hide-tablet">2024-01-01</td>
|
||
<td class="action-cell">
|
||
<button class="btn btn-secondary" onclick="editUser('A001')">編輯</button>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>A002</td>
|
||
<td>人資主管</td>
|
||
<td class="hide-mobile">hr_manager@company.com</td>
|
||
<td>
|
||
<span class="permission-badge admin">管理者</span>
|
||
</td>
|
||
<td class="hide-tablet">2024-01-15</td>
|
||
<td class="action-cell">
|
||
<button class="btn btn-secondary" onclick="editUser('A002')">編輯</button>
|
||
<button class="btn btn-cancel" onclick="deleteUser('A002')">刪除</button>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>A003</td>
|
||
<td>一般員工</td>
|
||
<td class="hide-mobile">employee@company.com</td>
|
||
<td>
|
||
<span class="permission-badge user">一般使用者</span>
|
||
</td>
|
||
<td class="hide-tablet">2024-02-01</td>
|
||
<td class="action-cell">
|
||
<button class="btn btn-secondary" onclick="editUser('A003')">編輯</button>
|
||
<button class="btn btn-cancel" onclick="deleteUser('A003')">刪除</button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- LLM 模型設定 -->
|
||
<div class="form-card" style="margin-top: 30px;">
|
||
<div style="margin-bottom: 20px;">
|
||
<h2 style="color: var(--primary); margin: 0 0 10px 0;">LLM 模型設定</h2>
|
||
<p style="color: var(--text-secondary); font-size: 14px; margin: 0;">選擇 Ollama API 使用的模型</p>
|
||
</div>
|
||
|
||
<div style="border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; background: #f8f9fa;">
|
||
<div style="margin-bottom: 15px;">
|
||
<label style="display: block; margin-bottom: 10px; font-weight: 500; color: var(--text-primary);">
|
||
<svg viewBox="0 0 24 24" style="width: 20px; height: 20px; fill: var(--primary); vertical-align: middle; margin-right: 5px;">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
Ollama 模型選擇
|
||
</label>
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; padding: 10px 0;">
|
||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||
<input type="radio" name="ollamaModel" value="deepseek-reasoner" id="model-reasoner"
|
||
style="margin-right: 8px; width: 18px; height: 18px; cursor: pointer;"
|
||
onchange="saveOllamaModel()">
|
||
<span style="font-size: 14px;">deepseek-reasoner<br><small style="color: #666;">推理模型</small></span>
|
||
</label>
|
||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||
<input type="radio" name="ollamaModel" value="deepseek-chat" id="model-chat"
|
||
style="margin-right: 8px; width: 18px; height: 18px; cursor: pointer;"
|
||
onchange="saveOllamaModel()">
|
||
<span style="font-size: 14px;">deepseek-chat<br><small style="color: #666;">對話模型</small></span>
|
||
</label>
|
||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||
<input type="radio" name="ollamaModel" value="gpt-oss:120b" id="model-gptoss"
|
||
style="margin-right: 8px; width: 18px; height: 18px; cursor: pointer;"
|
||
onchange="saveOllamaModel()">
|
||
<span style="font-size: 14px;">GPT-OSS 120B<br><small style="color: #666;">大型語言模型</small></span>
|
||
</label>
|
||
</div>
|
||
<div style="margin-top: 10px; padding: 10px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px; font-size: 13px; color: #856404;">
|
||
<strong>說明:</strong>
|
||
<ul style="margin: 5px 0 0 20px; padding: 0;">
|
||
<li><strong>deepseek-reasoner</strong>:適合需要深度思考和推理的任務,如複雜問題分析、邏輯推導等</li>
|
||
<li><strong>deepseek-chat</strong>:適合一般對話和快速回應的場景,如文字生成、簡單問答等</li>
|
||
<li><strong>GPT-OSS 120B</strong>:超大型模型 (120B 參數),提供最佳的理解能力和生成品質,適合複雜任務</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 測試連線按鈕 -->
|
||
<div style="margin-top: 15px; display: flex; gap: 10px; align-items: center;">
|
||
<button type="button" class="btn btn-secondary" onclick="testOllamaConnection()" id="testConnectionBtn">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;">
|
||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||
</svg>
|
||
測試連線
|
||
</button>
|
||
<button type="button" class="btn btn-primary" onclick="saveOllamaModelWithConfirmation()" style="display: none;" id="saveModelBtn">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;">
|
||
<path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
|
||
</svg>
|
||
儲存變更
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 測試結果顯示 -->
|
||
<div style="margin-top: 15px; padding: 10px; background: #d4edda; border: 1px solid #28a745; border-radius: 4px; font-size: 13px; color: #155724; display: none;" id="connectionSuccess">
|
||
✓ 連線測試成功!模型回應正常
|
||
</div>
|
||
<div style="margin-top: 15px; padding: 10px; background: #f8d7da; border: 1px solid #dc3545; border-radius: 4px; font-size: 13px; color: #721c24; display: none;" id="connectionError">
|
||
✗ 連線測試失敗:<span id="connectionErrorMessage"></span>
|
||
</div>
|
||
<div style="margin-top: 15px; padding: 10px; background: #d4edda; border: 1px solid #28a745; border-radius: 4px; font-size: 13px; color: #155724; display: none;" id="modelSaveSuccess">
|
||
✓ 模型設定已儲存
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 崗位資料管理 -->
|
||
<div class="form-card" style="margin-top: 30px;">
|
||
<div style="margin-bottom: 20px;">
|
||
<h2 style="color: var(--primary); margin: 0 0 10px 0;">崗位資料管理</h2>
|
||
<p style="color: var(--text-secondary); font-size: 14px; margin: 0;">管理和匯出完整的崗位資料表</p>
|
||
</div>
|
||
|
||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
|
||
<!-- 匯出完整崗位資料 -->
|
||
<div style="border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; background: #f8f9fa;">
|
||
<div style="display: flex; align-items: center; margin-bottom: 15px;">
|
||
<svg viewBox="0 0 24 24" style="width: 24px; height: 24px; fill: var(--primary); margin-right: 10px;">
|
||
<path d="M19 12v7H5v-7H3v7c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-7h-2zm-6 .67l2.59-2.58L17 11.5l-5 5-5-5 1.41-1.41L11 12.67V3h2z"/>
|
||
</svg>
|
||
<h3 style="margin: 0; font-size: 16px; color: var(--text-primary);">匯出完整崗位資料</h3>
|
||
</div>
|
||
<p style="font-size: 14px; color: var(--text-secondary); margin-bottom: 15px;">
|
||
匯出所有崗位的完整資料,包含基本資料、描述、要求等所有欄位。
|
||
</p>
|
||
<button type="button" class="btn btn-primary" style="width: 100%;" onclick="exportCompletePositionData()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;">
|
||
<path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>
|
||
</svg>
|
||
匯出完整 CSV
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 統計資訊 -->
|
||
<div style="border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; background: #f8f9fa;">
|
||
<div style="display: flex; align-items: center; margin-bottom: 15px;">
|
||
<svg viewBox="0 0 24 24" style="width: 24px; height: 24px; fill: var(--success); margin-right: 10px;">
|
||
<path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>
|
||
</svg>
|
||
<h3 style="margin: 0; font-size: 16px; color: var(--text-primary);">資料統計</h3>
|
||
</div>
|
||
<div style="font-size: 14px; color: var(--text-secondary);">
|
||
<p style="margin: 5px 0;">崗位總數: <strong id="totalPositionsCount">-</strong></p>
|
||
<p style="margin: 5px 0;">已描述: <strong id="describedPositionsCount">-</strong></p>
|
||
<p style="margin: 5px 0;">未描述: <strong id="undescribedPositionsCount">-</strong></p>
|
||
</div>
|
||
<button type="button" class="btn btn-secondary" style="width: 100%; margin-top: 10px;" onclick="refreshPositionStats()">
|
||
<svg viewBox="0 0 24 24" style="width: 18px; height: 18px; fill: currentColor;">
|
||
<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
|
||
</svg>
|
||
更新統計
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新增/編輯使用者彈窗 -->
|
||
<div id="userModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; justify-content: center; align-items: center;">
|
||
<div style="background: white; border-radius: 8px; padding: 30px; max-width: 500px; width: 90%;">
|
||
<h3 id="userModalTitle" style="margin: 0 0 20px 0; color: var(--primary);">新增使用者</h3>
|
||
<form id="userForm">
|
||
<div style="margin-bottom: 15px;">
|
||
<label style="display: block; margin-bottom: 5px; font-weight: 500;">工號 <span style="color: red;">*</span></label>
|
||
<input type="text" id="userEmployeeId" required style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;">
|
||
</div>
|
||
<div style="margin-bottom: 15px;">
|
||
<label style="display: block; margin-bottom: 5px; font-weight: 500;">使用者姓名 <span style="color: red;">*</span></label>
|
||
<input type="text" id="userName" required style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;">
|
||
</div>
|
||
<div style="margin-bottom: 15px;">
|
||
<label style="display: block; margin-bottom: 5px; font-weight: 500;">Email 信箱 <span style="color: red;">*</span></label>
|
||
<input type="email" id="userEmail" required style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;">
|
||
</div>
|
||
<div style="margin-bottom: 20px;">
|
||
<label style="display: block; margin-bottom: 5px; font-weight: 500;">權限等級 <span style="color: red;">*</span></label>
|
||
<select id="userRole" required style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px;">
|
||
<option value="">請選擇</option>
|
||
<option value="user">一般使用者</option>
|
||
<option value="admin">管理者</option>
|
||
<option value="superadmin">最高權限管理者</option>
|
||
</select>
|
||
</div>
|
||
<div style="display: flex; justify-content: flex-end; gap: 10px;">
|
||
<button type="button" class="btn btn-cancel" onclick="closeUserModal()">取消</button>
|
||
<button type="submit" class="btn btn-primary" onclick="saveUser(event)">儲存</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
</main><!-- End Main Content -->
|
||
|
||
<!--
|
||
============================================================
|
||
內嵌 JavaScript 已模組化移至 js/ 資料夾
|
||
主要模組:
|
||
- js/data/hierarchy.js - 組織階層資料
|
||
- js/prompts.js - AI Prompt 模板
|
||
- js/ai.js - AI 生成功能
|
||
- js/forms.js - 表單邏輯
|
||
- js/dropdowns.js - 下拉選單連動
|
||
- js/csv.js - CSV 匯入匯出
|
||
- js/admin.js - 管理功能
|
||
- js/main.js - 主程式入口
|
||
============================================================
|
||
-->
|
||
|
||
<!-- 舊版內嵌腳本已移除,現在由 ES6 Modules 處理 -->
|
||
<!-- 以下為模組化後保留的最小化 script 區塊 -->
|
||
|
||
|
||
|
||
<!-- ==================== Prompt 編輯模態框 ==================== -->
|
||
<div class="modal-overlay" id="promptEditModal">
|
||
<div class="modal" style="max-width: 900px; max-height: 90vh; display: flex; flex-direction: column;">
|
||
<div class="modal-header">
|
||
<h3 id="promptModalTitle">編輯 Prompt</h3>
|
||
<button class="modal-close" onclick="closePromptEditModal()">✕</button>
|
||
</div>
|
||
<div class="modal-body" style="overflow-y: auto; flex: 1;">
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px;">
|
||
<div class="form-group">
|
||
<label>錦囊標題</label>
|
||
<input type="text" id="promptTitle" placeholder="例如:簡化版、標準版、詳細版">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>副標題(選填)</label>
|
||
<input type="text" id="promptSubtitle" placeholder="例如:僅必填欄位、常用欄位">
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label style="display: flex; justify-content: space-between; align-items: center;">
|
||
<span>Prompt 內容</span>
|
||
<span style="font-size: 0.75rem; color: #94a3b8; font-weight: normal;">支援變數:{existingData}, {positionName}</span>
|
||
</label>
|
||
<textarea id="promptContent" rows="16" style="font-family: 'Consolas', 'Monaco', monospace; font-size: 0.85rem; line-height: 1.6;" placeholder="請輸入 AI Prompt 內容... 範例: 你是專業人資顧問,請根據以下資料生成崗位描述: 已填寫的資料:{existingData} 崗位名稱:{positionName} 請用繁體中文,返回 JSON 格式。"></textarea>
|
||
</div>
|
||
<div style="margin-top: 12px; padding: 10px 12px; background: #eff6ff; border-left: 3px solid #3b82f6; border-radius: 4px; font-size: 0.8rem; color: #1e40af;">
|
||
<div style="font-weight: 600; margin-bottom: 4px;">💡 可用變數</div>
|
||
<div style="line-height: 1.6;">
|
||
• <code style="background: #dbeafe; padding: 2px 6px; border-radius: 3px;">{existingData}</code> 當前表單已填寫的資料(JSON 格式)<br>
|
||
• <code style="background: #dbeafe; padding: 2px 6px; border-radius: 3px;">{positionName}</code> 崗位名稱(用於招聘要求頁籤)
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer" style="flex-shrink: 0;">
|
||
<button class="btn btn-secondary" onclick="resetToDefaultPrompt()">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
|
||
<path d="M21 3v5h-5"/>
|
||
</svg>
|
||
重置為預設
|
||
</button>
|
||
<div style="flex: 1;"></div>
|
||
<button class="btn btn-cancel" onclick="closePromptEditModal()">取消</button>
|
||
<button class="btn btn-primary" onclick="savePromptEdit()">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
||
<polyline points="17 21 17 13 7 13 7 21"/>
|
||
<polyline points="7 3 7 8 15 8"/>
|
||
</svg>
|
||
保存
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div><!-- End app-container -->
|
||
|
||
</body>
|
||
</html>
|