# -*- coding: utf-8 -*- """从新版考核方案 xlsx 生成 9 份绩效导出模版(单 sheet + 占位符)。 机制对齐 writeXlsx(IZtCountService.java):遍历单元格做 {key} 子串替换。 - F2 -> {name}(员工姓名后一格),H2 -> {date}(考核周期后一格) - 每个指标行:H 列(本期结果)-> {键名},G 列(绩效数据)-> {detail_键名} 或拆分占位,无则清空 - 合计行:H 列 -> {total} """ from copy import copy import openpyxl SRC = r'docs/信息技术部绩效考核标准-新版 - AI下的考核方案.xlsx' OUT_DIR = r'codes/zentao/src/main/resources/templates/scope' # (源 sheet 名, 输出文件名, 合计行号, {指标行号: 键名}, {指标行号: G列绩效数据占位}) SHEETS = [ ('项目经理', '项目经理考核.xlsx', 12, {4: 'workloadPrdScore', 5: 'workloadTeamScore', 6: 'versionPlanFinishedRate', 7: 'bugScore', 8: 'documentQualityScore', 9: 'developFeedbackStory', 10: 'systemStabilityScore', 11: 'professionalSkillEnhancementScore'}, {4: '{detail_workloadPrdScore}', 5: '{detail_workloadTeamScore}', 6: '{detail_versionPlanFinishedRate}', 7: '{detail_bugScore}', 8: '{detail_documentQualityScore}'}), ('项目经理(王宇航)', '项目经理考核-王宇航.xlsx', 11, {4: 'workloadTeamScore', 5: 'versionPlanFinishedRate', 6: 'bugScore', 7: 'documentQualityScore', 8: 'developFeedbackStory', 9: 'systemStabilityScore', 10: 'professionalSkillEnhancementScore'}, {4: '{detail_workloadTeamScore}', 5: '{detail_versionPlanFinishedRate}', 6: '{detail_bugScore}', 7: '{detail_documentQualityScore}'}), ('产品经理', '产品经理考核.xlsx', 10, {4: 'workloadPrdScore', 5: 'workloadTeamScore', 6: 'productProjectOnTimeRateScore', 7: 'productBugRate', 8: 'productProblemResponse', 9: 'productResponsibilityScore'}, {4: '{detail_workloadPrdScore}', 5: '{detail_workloadTeamScore}', 6: '{detail_productProjectOnTimeRateScore}', 7: '{detail_productBugRate}'}), ('产品助理', '项目助理考核.xlsx', 9, {4: 'workloadPrdScore', 5: 'releaseScore', 6: 'productBugRate', 7: 'productProblemResponse', 8: 'productResponsibilityScore'}, {4: '{detail_workloadPrdScore}', 6: '{detail_productBugRate}'}), ('后端开发工程师', '后端开发工程师.xlsx', 12, {4: 'punctualityScore', 5: 'bugScore', 6: 'codeQualityScore', 7: 'documentQualityScore', 8: 'saturationScore', 9: 'workAttitude', 10: 'excellentShare', 11: 'quality'}, {4: '{totalTask}/{delayTask}/{finishPunctuality}', 5: '{bugCount}/{bugDensity}', 8: '{workTime}/{examineTime}/{saturation}'}), ('前端开发工程师', '前端开发工程师.xlsx', 11, {4: 'punctualityScore', 5: 'bugScore', 6: 'codeQualityScore', 7: 'saturationScore', 8: 'workAttitude', 9: 'excellentShare', 10: 'quality'}, {4: '{totalTask}/{delayTask}/{finishPunctuality}', 5: '{bugCount}/{bugDensity}', 7: '{workTime}/{examineTime}/{saturation}'}), ('测试工程师', '测试工程师.xlsx', 11, {4: 'punctualityScore', 5: 'documentQualityScore', 6: 'bugFindScore', 7: 'bugScore', 8: 'workAttitude', 9: 'excellentShare', 10: 'quality'}, {4: '{totalTask}/{delayTask}/{finishPunctuality}', 6: '{devSlightBug}/{devSeriousBug}/{bugFindRate}', 7: '{slightBug}/{seriousBug}'}), ('UI工程师', 'UI工程师.xlsx', 9, {4: 'punctualityScore', 5: 'designScore', 6: 'workAttitude', 7: 'uiWorkScore', 8: 'excellentShare'}, {4: '{totalTask}/{delayTask}/{finishPunctuality}'}), ('运维工程师', '运维工程师.xlsx', 12, {4: 'opsMajorTaskScore', 5: 'opsMonitorScore', 6: 'opsInspectScore', 7: 'opsBackupScore', 8: 'otherOpsScore', 9: 'systemStabilityScore', 10: 'workAttitude', 11: 'excellentShare'}, {4: '{detail_opsMajorTaskScore}', 5: '{detail_opsMonitorScore}', 6: '{detail_opsInspectScore}', 7: '{detail_opsBackupScore}'}), ] def copy_sheet(src_ws, dst_ws): """整 sheet 拷贝:值 + 基础样式 + 合并单元格 + 列宽行高。""" for row in src_ws.iter_rows(): for cell in row: if cell.value is None and not cell.has_style: continue nc = dst_ws.cell(row=cell.row, column=cell.column) nc.value = cell.value if cell.has_style: nc.font = copy(cell.font) nc.fill = copy(cell.fill) nc.border = copy(cell.border) nc.alignment = copy(cell.alignment) nc.protection = copy(cell.protection) nc.number_format = cell.number_format for merged in src_ws.merged_cells.ranges: dst_ws.merge_cells(str(merged)) for key, dim in src_ws.column_dimensions.items(): if dim.width is not None: dst_ws.column_dimensions[key].width = dim.width for key, dim in src_ws.row_dimensions.items(): if dim.height is not None: dst_ws.row_dimensions[key].height = dim.height def main(): src_wb = openpyxl.load_workbook(SRC) for sheet_name, out_name, total_row, row_keys, row_details in SHEETS: src_ws = src_wb[sheet_name] wb = openpyxl.Workbook() ws = wb.active ws.title = sheet_name copy_sheet(src_ws, ws) # R2:员工姓名后一格 F2 -> {name},考核周期后一格 H2 -> {date} ws.cell(row=2, column=6).value = '{name}' ws.cell(row=2, column=8).value = '{date}' # 指标行:H 列本期结果 -> {键名};G 列绩效数据 -> 明细占位或清空 for r, key in row_keys.items(): ws.cell(row=r, column=8).value = '{%s}' % key ws.cell(row=r, column=7).value = row_details.get(r) # 合计行结果列 -> {total} assert ws.cell(row=total_row, column=1).value == '合计', (sheet_name, total_row) ws.cell(row=total_row, column=8).value = '{total}' out_path = '%s/%s' % (OUT_DIR, out_name) wb.save(out_path) print('OK %s <- %s' % (out_name, sheet_name)) print('done') if __name__ == '__main__': main()