#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 欄位 ID 自動重命名腳本 根據 ID重命名對照表.md 批量替換 HTML 和 JavaScript 中的欄位 ID """ import re import os from pathlib import Path # ID 重命名對照表 ID_MAPPINGS = { # 模組 1: 崗位基礎資料 - 基礎資料頁籤 (15個) 'businessUnit': 'pos_businessUnit', 'division': 'pos_division', 'department': 'pos_department', 'section': 'pos_section', 'positionCode': 'pos_code', 'effectiveDate': 'pos_effectiveDate', 'positionName': 'pos_name', 'positionLevel': 'pos_level', 'positionCategory': 'pos_category', 'positionCategoryName': 'pos_categoryName', 'positionNature': 'pos_type', 'positionNatureName': 'pos_typeName', 'headcount': 'pos_headcount', 'positionDesc': 'pos_desc', 'positionRemark': 'pos_remark', # 模組 2: 崗位基礎資料 - 招聘要求頁籤 (18個) 'minEducation': 'rec_eduLevel', 'requiredGender': 'rec_gender', 'salaryRange': 'rec_salaryRange', 'workExperience': 'rec_expYears', 'minAge': 'rec_minAge', 'maxAge': 'rec_maxAge', 'jobType': 'rec_jobType', 'recruitPosition': 'rec_position', 'jobTitle': 'rec_jobTitle', 'superiorPosition': 'rec_superiorCode', 'jobDesc': 'rec_jobDesc', 'positionReq': 'rec_positionReq', 'titleReq': 'rec_certReq', 'majorReq': 'rec_majorReq', 'skillReq': 'rec_skillReq', 'langReq': 'rec_langReq', 'otherReq': 'rec_otherReq', 'recruitRemark': 'rec_remark', # 模組 3: 職務基礎資料 (12個) 'jobCategoryCode': 'job_category', 'jobCategoryName': 'job_categoryName', 'jobCode': 'job_code', 'jobName': 'job_name', 'jobNameEn': 'job_nameEn', 'jobEffectiveDate': 'job_effectiveDate', 'jobLevel': 'job_level', 'jobHeadcount': 'job_headcount', 'jobSortOrder': 'job_sortOrder', 'hasAttendanceBonus': 'job_hasAttBonus', 'hasHousingAllowance': 'job_hasHouseAllow', 'jobRemark': 'job_remark', # 模組 4: 部門職責 (19個 - 包含合併重複欄位) 'deptFunctionCode': 'df_code', 'deptFunctionName': 'df_name', 'deptFunctionBU': 'df_businessUnit', 'deptFunc_businessUnit': 'df_businessUnit', # 合併 'deptFunc_division': 'df_division', 'deptFunc_department': 'df_department', 'deptFunc_section': 'df_section', 'deptFunc_positionTitle': 'df_posTitle', 'deptFunc_positionLevel': 'df_posLevel', 'deptManager': 'df_managerTitle', 'deptFunctionEffectiveDate': 'df_effectiveDate', 'deptHeadcount': 'df_headcountLimit', 'deptStatus': 'df_status', 'deptMission': 'df_mission', 'deptVision': 'df_vision', 'deptCoreFunctions': 'df_coreFunc', 'deptKPIs': 'df_kpis', 'deptCollaboration': 'df_collab', 'deptFunctionRemark': 'df_remark', # 模組 5: 崗位描述 (8個需要變更的) 'jd_positionCode': 'jd_posCode', 'jd_positionName': 'jd_posName', 'jd_positionLevel': 'jd_posLevel', 'jd_positionEffectiveDate': 'jd_posEffDate', 'jd_directSupervisor': 'jd_supervisor', 'jd_positionGradeJob': 'jd_gradeJob', 'jd_workLocation': 'jd_location', 'jd_empAttribute': 'jd_empAttr', 'jd_deptFunctionCode': 'jd_dfCode', 'jd_positionPurpose': 'jd_purpose', 'jd_mainResponsibilities': 'jd_mainResp', 'jd_education': 'jd_eduLevel', 'jd_basicSkills': 'jd_basicSkills', 'jd_professionalKnowledge': 'jd_proKnowledge', 'jd_workExperienceReq': 'jd_expReq', 'jd_otherRequirements': 'jd_otherReq', } # 需要特殊處理的函數名映射(onchange事件等) FUNCTION_MAPPINGS = { 'updateCategoryName': 'updateCategoryName', # 保持不變,但內部需要更新 'updateNatureName': 'updateTypeName', # positionNature -> pos_type 'updateJobCategoryName': 'updateJobCategoryName', # 保持不變 } def replace_in_file(file_path, dry_run=False): """ 在文件中替換所有匹配的 ID Args: file_path: 文件路徑 dry_run: 如果為 True,只輸出變更不實際修改 Returns: (總替換次數, 變更詳情列表) """ with open(file_path, 'r', encoding='utf-8') as f: content = f.read() original_content = content changes = [] total_replacements = 0 # 排序:按舊ID長度降序,避免短ID誤替換長ID sorted_mappings = sorted(ID_MAPPINGS.items(), key=lambda x: len(x[0]), reverse=True) for old_id, new_id in sorted_mappings: if old_id == new_id: continue # 匹配模式: # 1. HTML id="oldId" # 2. JavaScript getElementById('oldId') 或 getElementById("oldId") # 3. HTML for="oldId" # 4. HTML name="oldId" # 5. 對象屬性 {oldId: ...} 或 data.oldId patterns = [ # HTML id 屬性 (rf'\bid=["\']({re.escape(old_id)})["\']', rf'id="\1"', lambda m: f'id="{new_id}"'), # HTML for 屬性 (rf'\bfor=["\']({re.escape(old_id)})["\']', rf'for="\1"', lambda m: f'for="{new_id}"'), # HTML name 屬性 (rf'\bname=["\']({re.escape(old_id)})["\']', rf'name="\1"', lambda m: f'name="{new_id}"'), # getElementById (rf'getElementById\(["\']({re.escape(old_id)})["\']', rf'getElementById("\1")', lambda m: f'getElementById("{new_id}")'), # 對象屬性訪問 .oldId (謹慎使用,確保前面是合理的對象) (rf'\.({re.escape(old_id)})\b', rf'.\1', lambda m: f'.{new_id}'), # 對象字面量屬性 oldId: 或 "oldId": (rf'\b({re.escape(old_id)}):', rf'\1:', lambda m: f'{new_id}:'), ] for pattern, _, replacement_func in patterns: matches = list(re.finditer(pattern, content)) if matches: # 從後往前替換,避免索引偏移 for match in reversed(matches): start, end = match.span() old_text = content[start:end] new_text = replacement_func(match) if old_text != new_text: content = content[:start] + new_text + content[end:] changes.append({ 'old': old_text, 'new': new_text, 'line': content[:start].count('\n') + 1 }) total_replacements += 1 # 如果有變更且非 dry run,寫回文件 if content != original_content and not dry_run: with open(file_path, 'w', encoding='utf-8', newline='') as f: f.write(content) return total_replacements, changes def main(): """主函數""" base_dir = Path(__file__).parent # 需要處理的文件列表 files_to_process = [ base_dir / 'index.html', base_dir / 'js' / 'ui.js', base_dir / 'js' / 'ai-bags.js', base_dir / 'js' / 'main.js', ] print("=" * 80) print("欄位 ID 重命名工具") print("=" * 80) print(f"\n📋 總計需要重命名:{len(ID_MAPPINGS)} 個 ID") print(f"📂 需要處理:{len(files_to_process)} 個文件\n") # 先 dry run 顯示變更 print("🔍 掃描變更(Dry Run)...") print("-" * 80) total_changes = 0 for file_path in files_to_process: if not file_path.exists(): print(f"⚠️ 文件不存在:{file_path.name}") continue count, changes = replace_in_file(file_path, dry_run=True) total_changes += count if count > 0: print(f"\n📄 {file_path.name}: {count} 處變更") # 顯示前 5 個變更示例 for i, change in enumerate(changes[:5]): print(f" L{change['line']}: {change['old']} → {change['new']}") if len(changes) > 5: print(f" ... 還有 {len(changes) - 5} 處變更") print("\n" + "=" * 80) print(f"📊 總計:{total_changes} 處需要替換") print("=" * 80) # 詢問是否執行 response = input("\n是否執行替換?(y/n): ").strip().lower() if response == 'y': print("\n🚀 開始執行替換...") print("-" * 80) for file_path in files_to_process: if not file_path.exists(): continue count, _ = replace_in_file(file_path, dry_run=False) if count > 0: print(f"✅ {file_path.name}: 已替換 {count} 處") print("\n✨ 替換完成!") print("\n⚠️ 請執行以下步驟:") print(" 1. 測試所有表單功能") print(" 2. 檢查瀏覽器控制台是否有錯誤") print(" 3. 使用 git diff 檢查變更") print(" 4. 提交變更:git add -A && git commit -m 'refactor: 標準化欄位 ID 命名'") else: print("\n❌ 已取消執行") if __name__ == '__main__': main()