backup: 完成 HR_position_ 表格前綴重命名與欄位對照表整理
變更內容: - 所有資料表加上 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>
This commit is contained in:
212
js/ui.js
212
js/ui.js
@@ -49,22 +49,51 @@ export function getPositionFormData() {
|
||||
const formData = new FormData(form);
|
||||
const data = { basicInfo: {}, recruitInfo: {} };
|
||||
|
||||
const basicFields = ['positionCode', 'positionName', 'positionCategory', 'positionCategoryName',
|
||||
'positionNature', 'positionNatureName', 'headcount', 'positionLevel',
|
||||
'effectiveDate', 'positionDesc', 'positionRemark'];
|
||||
const recruitFields = ['minEducation', 'requiredGender', 'salaryRange', 'workExperience',
|
||||
'minAge', 'maxAge', 'jobType', 'recruitPosition', 'jobTitle', 'jobDesc',
|
||||
'positionReq', 'titleReq', 'majorReq', 'skillReq', 'langReq', 'otherReq',
|
||||
'superiorPosition', 'recruitRemark'];
|
||||
// 使用新的 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'
|
||||
};
|
||||
|
||||
basicFields.forEach(field => {
|
||||
const value = formData.get(field);
|
||||
if (value) data.basicInfo[field] = value;
|
||||
// 使用新的 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;
|
||||
});
|
||||
|
||||
recruitFields.forEach(field => {
|
||||
const value = formData.get(field);
|
||||
if (value) data.recruitInfo[field] = value;
|
||||
Object.entries(recruitFieldMapping).forEach(([htmlId, dataKey]) => {
|
||||
const el = document.getElementById(htmlId);
|
||||
if (el && el.value) data.recruitInfo[dataKey] = el.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
@@ -76,19 +105,31 @@ export function getPositionFormData() {
|
||||
*/
|
||||
export function getJobFormData() {
|
||||
const form = document.getElementById('jobForm');
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
|
||||
const fields = ['jobCategoryCode', 'jobCategoryName', 'jobCode', 'jobName', 'jobNameEn',
|
||||
'jobEffectiveDate', 'jobHeadcount', 'jobSortOrder', 'jobRemark', 'jobLevel'];
|
||||
// 使用新的 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'
|
||||
};
|
||||
|
||||
fields.forEach(field => {
|
||||
const value = formData.get(field);
|
||||
if (value) data[field] = value;
|
||||
Object.entries(fieldMapping).forEach(([htmlId, dataKey]) => {
|
||||
const el = document.getElementById(htmlId);
|
||||
if (el && el.value) data[dataKey] = el.value;
|
||||
});
|
||||
|
||||
data.hasAttendanceBonus = document.getElementById('hasAttendanceBonus').checked;
|
||||
data.hasHousingAllowance = document.getElementById('hasHousingAllowance').checked;
|
||||
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;
|
||||
}
|
||||
@@ -101,33 +142,59 @@ export function getJobDescFormData() {
|
||||
const form = document.getElementById('jobDescForm');
|
||||
if (!form) return {};
|
||||
|
||||
const formData = new FormData(form);
|
||||
const data = { basicInfo: {}, positionInfo: {}, responsibilities: {}, requirements: {} };
|
||||
|
||||
// Basic Info
|
||||
['empNo', 'empName', 'positionCode', 'versionDate'].forEach(field => {
|
||||
const el = document.getElementById('jd_' + field);
|
||||
if (el && el.value) data.basicInfo[field] = el.value;
|
||||
// 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
|
||||
['positionName', 'department', 'positionEffectiveDate', 'directSupervisor',
|
||||
'positionGradeJob', 'reportTo', 'directReports', 'workLocation', 'empAttribute'].forEach(field => {
|
||||
const el = document.getElementById('jd_' + field);
|
||||
if (el && el.value) data.positionInfo[field] = el.value;
|
||||
// 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
|
||||
const purpose = document.getElementById('jd_positionPurpose');
|
||||
// Purpose & Responsibilities - 使用新的 jd_ prefix
|
||||
const purpose = document.getElementById('jd_purpose');
|
||||
if (purpose && purpose.value) data.responsibilities.positionPurpose = purpose.value;
|
||||
|
||||
const mainResp = document.getElementById('jd_mainResponsibilities');
|
||||
const mainResp = document.getElementById('jd_mainResp');
|
||||
if (mainResp && mainResp.value) data.responsibilities.mainResponsibilities = mainResp.value;
|
||||
|
||||
// Requirements
|
||||
['education', 'basicSkills', 'professionalKnowledge', 'workExperienceReq', 'otherRequirements'].forEach(field => {
|
||||
const el = document.getElementById('jd_' + field);
|
||||
if (el && el.value) data.requirements[field] = el.value;
|
||||
// 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;
|
||||
@@ -141,16 +208,33 @@ export function getDeptFunctionFormData() {
|
||||
const form = document.getElementById('deptFunctionForm');
|
||||
if (!form) return {};
|
||||
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
|
||||
const fields = ['deptFunctionCode', 'deptFunctionName', 'deptFunctionBU',
|
||||
'deptFunctionDept', 'deptManager', 'deptMission', 'deptVision',
|
||||
'deptCoreFunctions', 'deptKPIs'];
|
||||
// 使用新的 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'
|
||||
};
|
||||
|
||||
fields.forEach(field => {
|
||||
const value = formData.get(field);
|
||||
if (value) data[field] = value;
|
||||
Object.entries(fieldMapping).forEach(([htmlId, dataKey]) => {
|
||||
const el = document.getElementById(htmlId);
|
||||
if (el && el.value) data[dataKey] = el.value;
|
||||
});
|
||||
|
||||
return data;
|
||||
@@ -192,8 +276,11 @@ export function updatePreview() {
|
||||
* 更新崗位類別中文名稱
|
||||
*/
|
||||
export function updateCategoryName() {
|
||||
const category = document.getElementById('positionCategory').value;
|
||||
document.getElementById('positionCategoryName').value = categoryMap[category] || '';
|
||||
const categoryEl = document.getElementById('pos_category');
|
||||
const categoryNameEl = document.getElementById('pos_categoryName');
|
||||
if (categoryEl && categoryNameEl) {
|
||||
categoryNameEl.value = categoryMap[categoryEl.value] || '';
|
||||
}
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
@@ -201,8 +288,11 @@ export function updateCategoryName() {
|
||||
* 更新崗位性質中文名稱
|
||||
*/
|
||||
export function updateNatureName() {
|
||||
const nature = document.getElementById('positionNature').value;
|
||||
document.getElementById('positionNatureName').value = natureMap[nature] || '';
|
||||
const typeEl = document.getElementById('pos_type');
|
||||
const typeNameEl = document.getElementById('pos_typeName');
|
||||
if (typeEl && typeNameEl) {
|
||||
typeNameEl.value = natureMap[typeEl.value] || '';
|
||||
}
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
@@ -210,8 +300,11 @@ export function updateNatureName() {
|
||||
* 更新職務類別中文名稱
|
||||
*/
|
||||
export function updateJobCategoryName() {
|
||||
const category = document.getElementById('jobCategoryCode').value;
|
||||
document.getElementById('jobCategoryName').value = jobCategoryMap[category] || '';
|
||||
const categoryEl = document.getElementById('job_category');
|
||||
const categoryNameEl = document.getElementById('job_categoryName');
|
||||
if (categoryEl && categoryNameEl) {
|
||||
categoryNameEl.value = jobCategoryMap[categoryEl.value] || '';
|
||||
}
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
@@ -219,10 +312,12 @@ export function updateJobCategoryName() {
|
||||
* 修改崗位編號
|
||||
*/
|
||||
export function changePositionCode() {
|
||||
const currentCode = document.getElementById('positionCode').value;
|
||||
const codeEl = document.getElementById('pos_code');
|
||||
if (!codeEl) return;
|
||||
const currentCode = codeEl.value;
|
||||
const newCode = prompt('請輸入新的崗位編號:', currentCode);
|
||||
if (newCode && newCode !== currentCode) {
|
||||
document.getElementById('positionCode').value = newCode;
|
||||
codeEl.value = newCode;
|
||||
showToast('崗位編號已更改!');
|
||||
updatePreview();
|
||||
}
|
||||
@@ -232,10 +327,12 @@ export function changePositionCode() {
|
||||
* 修改職務編號
|
||||
*/
|
||||
export function changeJobCode() {
|
||||
const currentCode = document.getElementById('jobCode').value;
|
||||
const codeEl = document.getElementById('job_code');
|
||||
if (!codeEl) return;
|
||||
const currentCode = codeEl.value;
|
||||
const newCode = prompt('請輸入新的職務編號:', currentCode);
|
||||
if (newCode && newCode !== currentCode) {
|
||||
document.getElementById('jobCode').value = newCode;
|
||||
codeEl.value = newCode;
|
||||
showToast('職務編號已更改!');
|
||||
updatePreview();
|
||||
}
|
||||
@@ -271,7 +368,10 @@ export function confirmMajor() {
|
||||
document.querySelectorAll('#majorModal input[type="checkbox"]:checked').forEach(cb => {
|
||||
selected.push(cb.value);
|
||||
});
|
||||
document.getElementById('majorReq').value = selected.join(', ');
|
||||
const majorReqEl = document.getElementById('rec_majorReq');
|
||||
if (majorReqEl) {
|
||||
majorReqEl.value = selected.join(', ');
|
||||
}
|
||||
closeMajorModal();
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user