/** * 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: {} }; // 使用新的 pos_ prefix 欄位 const basicFieldMapping = { 'pos_code': 'positionCode', 'pos_name': 'positionName', 'pos_category': 'positionCategory', 'pos_categoryName': 'positionCategoryName', 'pos_type': 'positionType', 'pos_typeName': 'positionTypeName', 'pos_headcount': 'headcount', 'pos_level': 'positionLevel', 'pos_effectiveDate': 'effectiveDate', 'pos_desc': 'positionDesc', 'pos_remark': 'positionRemark' }; // 使用新的 rec_ prefix 欄位 const recruitFieldMapping = { 'rec_eduLevel': 'minEducation', 'rec_gender': 'requiredGender', 'rec_salaryRange': 'salaryRange', 'rec_expYears': 'workExperience', 'rec_minAge': 'minAge', 'rec_maxAge': 'maxAge', 'rec_jobType': 'jobType', 'rec_position': 'recruitPosition', 'rec_jobTitle': 'jobTitle', 'rec_jobDesc': 'jobDesc', 'rec_positionReq': 'positionReq', 'rec_certReq': 'certReq', 'rec_majorReq': 'majorReq', 'rec_skillReq': 'skillReq', 'rec_langReq': 'langReq', 'rec_otherReq': 'otherReq', 'rec_superiorCode': 'superiorPosition', 'rec_remark': 'recruitRemark' }; Object.entries(basicFieldMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data.basicInfo[dataKey] = el.value; }); Object.entries(recruitFieldMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data.recruitInfo[dataKey] = el.value; }); return data; } /** * 收集職務表單資料 * @returns {Object} - 職務資料 */ export function getJobFormData() { const form = document.getElementById('jobForm'); const data = {}; // 使用新的 job_ prefix 欄位 const fieldMapping = { 'job_category': 'jobCategoryCode', 'job_categoryName': 'jobCategoryName', 'job_code': 'jobCode', 'job_name': 'jobName', 'job_nameEn': 'jobNameEn', 'job_level': 'jobLevel', 'job_effectiveDate': 'jobEffectiveDate', 'job_sortOrder': 'jobSortOrder', 'job_headcount': 'jobHeadcount', 'job_remark': 'jobRemark' }; Object.entries(fieldMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data[dataKey] = el.value; }); const hasAttBonus = document.getElementById('job_hasAttBonus'); const hasHouseAllow = document.getElementById('job_hasHouseAllow'); data.hasAttendanceBonus = hasAttBonus ? hasAttBonus.checked : false; data.hasHousingAllowance = hasHouseAllow ? hasHouseAllow.checked : false; return data; } /** * 收集崗位描述表單資料 * @returns {Object} - 崗位描述資料 */ export function getJobDescFormData() { const form = document.getElementById('jobDescForm'); if (!form) return {}; const data = { basicInfo: {}, positionInfo: {}, responsibilities: {}, requirements: {} }; // Basic Info - 使用新的 jd_ prefix const basicMapping = { 'jd_empNo': 'empNo', 'jd_empName': 'empName', 'jd_posCode': 'positionCode', 'jd_versionDate': 'versionDate' }; Object.entries(basicMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data.basicInfo[dataKey] = el.value; }); // Position Info - 使用新的 jd_ prefix const posInfoMapping = { 'jd_posName': 'positionName', 'jd_department': 'department', 'jd_posLevel': 'positionLevel', 'jd_posEffDate': 'positionEffectiveDate', 'jd_supervisor': 'directSupervisor', 'jd_gradeJob': 'positionGradeJob', 'jd_reportTo': 'reportTo', 'jd_directReports': 'directReports', 'jd_location': 'workLocation', 'jd_empAttr': 'empAttribute' }; Object.entries(posInfoMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data.positionInfo[dataKey] = el.value; }); // Purpose & Responsibilities - 使用新的 jd_ prefix const purpose = document.getElementById('jd_purpose'); if (purpose && purpose.value) data.responsibilities.positionPurpose = purpose.value; const mainResp = document.getElementById('jd_mainResp'); if (mainResp && mainResp.value) data.responsibilities.mainResponsibilities = mainResp.value; // Requirements - 使用新的 jd_ prefix const reqMapping = { 'jd_eduLevel': 'education', 'jd_basicSkills': 'basicSkills', 'jd_proKnowledge': 'professionalKnowledge', 'jd_expReq': 'workExperienceReq', 'jd_otherReq': 'otherRequirements' }; Object.entries(reqMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data.requirements[dataKey] = el.value; }); return data; } /** * 收集部門職責表單資料 * @returns {Object} - 部門職責資料 */ export function getDeptFunctionFormData() { const form = document.getElementById('deptFunctionForm'); if (!form) return {}; const data = {}; // 使用新的 df_ prefix 欄位 const fieldMapping = { 'df_code': 'dfCode', 'df_name': 'dfName', 'df_businessUnit': 'businessUnit', 'df_division': 'division', 'df_department': 'department', 'df_section': 'section', 'df_posTitle': 'positionTitle', 'df_posLevel': 'positionLevel', 'df_managerTitle': 'managerTitle', 'df_effectiveDate': 'effectiveDate', 'df_headcountLimit': 'headcountLimit', 'df_status': 'status', 'df_mission': 'mission', 'df_vision': 'vision', 'df_coreFunc': 'coreFunctions', 'df_kpis': 'kpis', 'df_collab': 'collaboration', 'df_remark': 'remark' }; Object.entries(fieldMapping).forEach(([htmlId, dataKey]) => { const el = document.getElementById(htmlId); if (el && el.value) data[dataKey] = el.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 categoryEl = document.getElementById('pos_category'); const categoryNameEl = document.getElementById('pos_categoryName'); if (categoryEl && categoryNameEl) { categoryNameEl.value = categoryMap[categoryEl.value] || ''; } updatePreview(); } /** * 更新崗位性質中文名稱 */ export function updateNatureName() { const typeEl = document.getElementById('pos_type'); const typeNameEl = document.getElementById('pos_typeName'); if (typeEl && typeNameEl) { typeNameEl.value = natureMap[typeEl.value] || ''; } updatePreview(); } /** * 更新職務類別中文名稱 */ export function updateJobCategoryName() { const categoryEl = document.getElementById('job_category'); const categoryNameEl = document.getElementById('job_categoryName'); if (categoryEl && categoryNameEl) { categoryNameEl.value = jobCategoryMap[categoryEl.value] || ''; } updatePreview(); } /** * 修改崗位編號 */ export function changePositionCode() { const codeEl = document.getElementById('pos_code'); if (!codeEl) return; const currentCode = codeEl.value; const newCode = prompt('請輸入新的崗位編號:', currentCode); if (newCode && newCode !== currentCode) { codeEl.value = newCode; showToast('崗位編號已更改!'); updatePreview(); } } /** * 修改職務編號 */ export function changeJobCode() { const codeEl = document.getElementById('job_code'); if (!codeEl) return; const currentCode = codeEl.value; const newCode = prompt('請輸入新的職務編號:', currentCode); if (newCode && newCode !== currentCode) { codeEl.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); }); const majorReqEl = document.getElementById('rec_majorReq'); if (majorReqEl) { majorReqEl.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; }