课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(class_name))\nmajor = match.group(1).strip() if match else '' # 如 \"计算机\" 或 \"软工\"\n\n\n# 获取学生信息\nstudents = df[['学号', '姓名']].copy()\nprint(f\"学生人数: {len(students)}\")\n```\n\n### 步骤2:复制模板并打开\n\n```python\ntemplate_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-模版.docx'\noutput_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-23级计算机.docx'\n\nshutil.copy(template_path, output_path)\ndoc = Document(output_path)\n```\n\n### 步骤3:通用文本替换\n\n**⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式**\n\n```python\ndef replace_text_preserve_format(para, replacements):\n \"\"\"替换段落文本但保留格式\"\"\"\n # 先收集所有run的文本\n full_text = ''.join(run.text for run in para.runs if run.text)\n \n # 检查是否有占位符\n has_placeholder = any(old in full_text for old, _ in replacements)\n if not has_placeholder:\n return\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 获取第一个run的格式作为基准\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 清空并用新文本创建单一run,保留格式\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return para\n\ndef replace_text_in_table_cell(cell, replacements):\n \"\"\"替换表格单元格中的文本(处理单元格内换行的情况)\"\"\"\n # 遍历单元格中的所有段落\n for para in cell.paragraphs:\n full_text = ''.join(run.text for run in para.runs if run.text)\n has_placeholder = any(old in full_text for old, _ in replacements)\n \n if has_placeholder:\n # 获取格式\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 清空并重新设置\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return cell\n\n# 替换配置\nreplacements = [\n ('$acyear

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, academic_year),\n ('$semester

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, semester),\n ('$g

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, grade),\n ('$major

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, major),\n ('$total

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, f'{len(students)}人'),\n ('$year

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(year)),\n ('$month

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(month)),\n ('$day

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(day)),\n]\n\n# 替换表格中的文本\nfor table in doc.tables:\n for row in table.rows:\n for cell in row.cells:\n replace_text_in_cell(cell, replacements)\n\n# 替换段落中的文本(处理被拆分的情况,保留格式)\nfor para in doc.paragraphs:\n replace_text_preserve_format(para, replacements)\n```\n\n### 步骤4:更新表8 - 课程目标个体达成情况明细\n\n**重要**:\n1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据\n2. 根据Excel学生数动态调整表格行数\n3. **在最后一行(平均值行)之前插入新行**\n4. 所有达成值用**百分比**表示(如 66%)\n\n**表格索引**: 8\n\n**表头结构**(前2行):\n- 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4\n- 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值\n\n**数据列对应关系**:\n| 列索引 | 内容 |\n|--------|------|\n| 0 | 序号 |\n| 1 | 学号 |\n| 2 | 姓名 |\n| 3 | 随机值 a (10-24),课程目标1得分 |\n| 4 | a/25*100%,课程目标1达成值(百分比) |\n| 5 | 随机值 b (20-28),课程目标2得分 |\n| 6 | b/30*100%,课程目标2达成值(百分比) |\n| 7 | 随机值 c (20-25),课程目标3得分 |\n| 8 | c/26.5*100%,课程目标3达成值(百分比) |\n| 9 | 随机值 d (15-18),课程目标4得分 |\n| 10 | d/18.5*100%,课程目标4达成值(百分比) |\n\n```python\n# 步骤4.1: 动态调整表格行数(在平均值行之前插入)\ntable = doc.tables[8]\ncurrent_rows = len(table.rows)\n# 当前模板可以容纳的学生数(去掉2行表头和1行平均值)\ntemplate_capacity = current_rows - 3\n\n# 调整行数:在倒数第2行(平均值行之前)插入\nif len(students) > template_capacity:\n # 需要插入行,在平均值行之前插入\n for i in range(len(students) - template_capacity):\n # 在倒数第2行之前插入(即平均值行之前)\n new_row = table.add_row()\n # 将新行移动到平均值行之前\n # 由于add_row()是添加到末尾,需要交换位置\n # 获取平均值行索引\n avg_idx = len(table.rows) - 1\n # 将新插入的行移到平均值行之前\n table._element.remove(new_row._element)\n table._element.insert(len(table.rows) - 2, new_row._element)\nelif len(students) \u003c template_capacity:\n # 需要删除多余行(从数据区域末尾开始删,保留平均值行)\n for i in range(template_capacity - len(students)):\n # 删除倒数第2行(最后一个数据行)\n delete_idx = 2 + len(students)\n if delete_idx \u003c len(table.rows) - 1:\n table._element.remove(table.rows[delete_idx]._element)\n\n# 步骤4.2: 清理数据行(保留前2行表头和最后1行平均值)\nfor row_idx in range(2, len(table.rows) - 1):\n for cell in table.rows[row_idx].cells:\n cell.text = ''\n\n# 步骤4.3: 填入学生数据(达成值用百分比)\nall_a, all_b, all_c, all_d = [], [], [], []\nstudent_data = []\n\nfor i, (_, student) in enumerate(students.iterrows()):\n row_idx = i + 2\n if row_idx >= len(table.rows) - 1:\n break\n \n row = table.rows[row_idx]\n a = random.randint(10, 24)\n b = random.randint(20, 28)\n c = random.randint(20, 25)\n d = random.randint(15, 18)\n \n all_a.append(a)\n all_b.append(b)\n all_c.append(c)\n all_d.append(d)\n \n # 转为百分比\n v1, v2, v3, v4 = a/25*100, b/30*100, c/26.5*100, d/18.5*100\n student_data.append({'v1': v1, 'v2': v2, 'v3': v3, 'v4': v4})\n \n row.cells[0].text = str(i + 1)\n row.cells[1].text = str(student['学号'])\n row.cells[2].text = student['姓名']\n row.cells[3].text = f\"{a:.2f}\"\n row.cells[4].text = f\"{v1:.0f}%\" # 百分比\n row.cells[5].text = f\"{b:.2f}\"\n row.cells[6].text = f\"{v2:.0f}%\" # 百分比\n row.cells[7].text = f\"{c:.2f}\"\n row.cells[8].text = f\"{v3:.0f}%\" # 百分比\n row.cells[9].text = f\"{d:.2f}\"\n row.cells[10].text = f\"{v4:.0f}%\" # 百分比\n\nn = len(student_data)\n\n# 步骤4.4: 最后一行填写平均值(百分比)\navg_row = table.rows[-1]\navg_a = sum(all_a) / n\navg_b = sum(all_b) / n\navg_c = sum(all_c) / n\navg_d = sum(all_d) / n\navg_v1 = sum(s['v1'] for s in student_data) / n\navg_v2 = sum(s['v2'] for s in student_data) / n\navg_v3 = sum(s['v3'] for s in student_data) / n\navg_v4 = sum(s['v4'] for s in student_data) / n\n\navg_row.cells[0].text = \"平均值\"\navg_row.cells[3].text = f\"{avg_a:.2f}\"\navg_row.cells[4].text = f\"{avg_v1:.0f}%\"\navg_row.cells[5].text = f\"{avg_b:.2f}\"\navg_row.cells[6].text = f\"{avg_v2:.0f}%\"\navg_row.cells[7].text = f\"{avg_c:.2f}\"\navg_row.cells[8].text = f\"{avg_v3:.0f}%\"\navg_row.cells[9].text = f\"{avg_d:.2f}\"\navg_row.cells[10].text = f\"{avg_v4:.0f}%\"\n```\n\n### 步骤5:更新表7汇总数据(百分比)\n\n```python\ntable7 = doc.tables[7]\ntable7.rows[5].cells[7].text = f\"{avg_v1:.0f}%\"\ntable7.rows[8].cells[7].text = f\"{avg_v2:.0f}%\"\ntable7.rows[11].cells[7].text = f\"{avg_v3:.0f}%\"\ntable7.rows[14].cells[7].text = f\"{avg_v4:.0f}%\"\n```\n\n### 步骤6:更新课程目标分析段落(百分比)\n\n```python\n# 计算统计数据\nmax_v1 = max(s['v1'] for s in student_data)\nmin_v1 = min(s['v1'] for s in student_data)\n# ... 其他目标类似\n\n# 计算满足百分比阈值的学生比例\ncount_v1_80 = sum(1 for s in student_data if s['v1'] >= 80)\ncount_v1_60 = sum(1 for s in student_data if s['v1'] >= 60)\n# ... 其他类似\n\npct_v1_80 = count_v1_80 / n * 100\npct_v1_60 = count_v1_60 / n * 100\n# ... 其他类似\n\n# 更新段落\nnew_texts = {\n 1: f\"课程目标1的平均达成值为{avg_v1:.0f}%,最高达成值为{max_v1:.0f}%,最低达成值为{min_v1:.0f}%。其中{pct_v1_80:.1f}%的学生达成值在80%以上,{pct_v1_60:.1f}%的学生达成值在60%以上,说明...\",\n # ... 其他目标\n}\n\n# 找到并更新段落\nfor i, para in enumerate(doc.paragraphs):\n if '课程目标1的平均达成值为' in para.text:\n # 更新段落文本\n break\n```\n\n### 步骤7:保存\n\n```python\ndoc.save(output_path)\nprint(f\"文件已保存至: {output_path}\")\n```\n\n---\n\n## 完整代码示例\n\n```python\nimport pandas as pd\nimport shutil\nimport random\nfrom docx import Document\nfrom datetime import datetime\n\nrandom.seed(42) # 可选:固定随机种子\n\ndef replace_text_preserve_format(para, replacements):\n \"\"\"替换段落文本但保留格式\"\"\"\n # 先收集所有run的文本\n full_text = ''.join(run.text for run in para.runs if run.text)\n \n # 检查是否有占位符\n has_placeholder = any(old in full_text for old, _ in replacements)\n if not has_placeholder:\n return\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 获取第一个run的格式作为基准\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 清空并用新文本创建单一run,保留格式\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return para\n\ndef replace_text_in_table_cell(cell, replacements):\n \"\"\"替换表格单元格中的文本(处理单元格内换行的情况)\"\"\"\n for para in cell.paragraphs:\n full_text = ''.join(run.text for run in para.runs if run.text)\n has_placeholder = any(old in full_text for old, _ in replacements)\n \n if has_placeholder:\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return cell\n\ndef generate_achievement_analysis():\n # 1. 读取Excel\n df = pd.read_excel('/Users/qztcm09/Desktop/temp/数据可视化技术23级计算机.xls')\n df = df[df['备注'] != '旷考'].reset_index(drop=True)\n students = df[['学号', '姓名']].copy()\n print(f\"学生人数: {len(students)}\")\n \n # 2. 复制模板\n template_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-模版.docx'\n output_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-23级计算机.docx'\n shutil.copy(template_path, output_path)\n doc = Document(output_path)\n \n # 3. 通用文本替换\n now = datetime.now()\n year, month, day = now.year, now.month, now.day\n \n # 根据班级提取专业信息(支持两种情况)\n # 情况1: \"23级计算机\" → 专业=\"计算机\"\n # 情况2: \"23级软工2班\" → 专业=\"软工\"\n import re\n class_name = df['班级'].iloc[0] if '班级' in df.columns else ''\n match = re.search(r'(\\d+)级', str(class_name))\n grade = match.group(1) if match else ''\n match = re.search(r'\\d+级(.+?)(?:\\d+班)?

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(class_name))\n major = match.group(1).strip() if match else ''\n \n if 1 \u003c= month \u003c= 6:\n academic_year = f\"{year-1} - {year}\"\n semester = \"一\"\n else:\n academic_year = f\"{year-1} - {year}\"\n semester = \"二\"\n \n replacements = [\n ('$acyear

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, academic_year),\n ('$semester

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, semester),\n ('$g

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, grade),\n ('$major

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, major),\n ('$total

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, f'{len(students)}人'),\n ('$year

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(year)),\n ('$month

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(month)),\n ('$day

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(day)),\n ]\n \n # 替换表格中的文本(使用新的函数处理换行)\n for table in doc.tables:\n for row in table.rows:\n for cell in row.cells:\n replace_text_in_table_cell(cell, replacements)\n \n # 替换段落中的文本(保留格式)\n for para in doc.paragraphs:\n replace_text_preserve_format(para, replacements)\n \n # 4. 更新表8\n table = doc.tables[8]\n current_rows = len(table.rows)\n template_capacity = current_rows - 3\n \n # 调整行数\n if len(students) > template_capacity:\n # 需要插入行,在平均值行之前插入\n rows_to_add = len(students) - template_capacity\n for i in range(rows_to_add):\n # 在倒数第2行(平均值行之前)插入新行\n new_row = table.add_row()\n # 将新行从末尾移到平均值行之前\n avg_idx = len(table.rows) - 1\n # 获取新行的tr元素\n new_tr = new_row._element\n # 移除\n table._element.remove(new_tr)\n # 在平均值行之前插入\n table._element.insert(avg_idx, new_tr)\n print(f\"插入{rows_to_add}行\")\n elif len(students) \u003c template_capacity:\n # 需要删除多余行\n rows_to_remove = template_capacity - len(students)\n for i in range(rows_to_remove):\n delete_idx = 2 + len(students)\n if delete_idx \u003c len(table.rows) - 1:\n table._element.remove(table.rows[delete_idx]._element)\n print(f\"删除{rows_to_remove}行\")\n \n # 清理数据行\n for row_idx in range(2, len(table.rows) - 1):\n for cell in table.rows[row_idx].cells:\n cell.text = ''\n \n # 填入数据\n all_a, all_b, all_c, all_d = [], [], [], []\n student_data = []\n \n for i, (_, student) in enumerate(students.iterrows()):\n row_idx = i + 2\n if row_idx >= len(table.rows) - 1:\n break\n \n row = table.rows[row_idx]\n a = random.randint(10, 24)\n b = random.randint(20, 28)\n c = random.randint(20, 25)\n d = random.randint(15, 18)\n \n all_a.append(a)\n all_b.append(b)\n all_c.append(c)\n all_d.append(d)\n \n v1, v2, v3, v4 = a/25*100, b/30*100, c/26.5*100, d/18.5*100\n student_data.append({'v1': v1, 'v2': v2, 'v3': v3, 'v4': v4})\n \n row.cells[0].text = str(i + 1)\n row.cells[1].text = str(student['学号'])\n row.cells[2].text = student['姓名']\n row.cells[3].text = f\"{a:.2f}\"\n row.cells[4].text = f\"{v1:.0f}%\"\n row.cells[5].text = f\"{b:.2f}\"\n row.cells[6].text = f\"{v2:.0f}%\"\n row.cells[7].text = f\"{c:.2f}\"\n row.cells[8].text = f\"{v3:.0f}%\"\n row.cells[9].text = f\"{d:.2f}\"\n row.cells[10].text = f\"{v4:.0f}%\"\n \n n = len(student_data)\n \n # 平均值(最后一行)\n avg_row = table.rows[-1]\n avg_a = sum(all_a) / n\n avg_b = sum(all_b) / n\n avg_c = sum(all_c) / n\n avg_d = sum(all_d) / n\n avg_v1 = sum(s['v1'] for s in student_data) / n\n avg_v2 = sum(s['v2'] for s in student_data) / n\n avg_v3 = sum(s['v3'] for s in student_data) / n\n avg_v4 = sum(s['v4'] for s in student_data) / n\n \n avg_row.cells[0].text = \"平均值\"\n avg_row.cells[1].text = \"\"\n avg_row.cells[2].text = \"\"\n avg_row.cells[3].text = f\"{avg_a:.2f}\"\n avg_row.cells[4].text = f\"{avg_v1:.0f}%\"\n avg_row.cells[5].text = f\"{avg_b:.2f}\"\n avg_row.cells[6].text = f\"{avg_v2:.0f}%\"\n avg_row.cells[7].text = f\"{avg_c:.2f}\"\n avg_row.cells[8].text = f\"{avg_v3:.0f}%\"\n avg_row.cells[9].text = f\"{avg_d:.2f}\"\n avg_row.cells[10].text = f\"{avg_v4:.0f}%\"\n \n # 5. 更新表7\n table7 = doc.tables[7]\n table7.rows[5].cells[7].text = f\"{avg_v1:.0f}%\"\n table7.rows[8].cells[7].text = f\"{avg_v2:.0f}%\"\n table7.rows[11].cells[7].text = f\"{avg_v3:.0f}%\"\n table7.rows[14].cells[7].text = f\"{avg_v4:.0f}%\"\n \n # 6. 统计并更新段落(见步骤6)\n # ...\n \n # 7. 保存\n doc.save(output_path)\n print(f\"完成!文件已保存至: {output_path}\")\n\nif __name__ == '__main__':\n generate_achievement_analysis()\n```\n\n---\n\n## ⚠️ 注意事项\n\n### 1. 达成值格式\n- 所有达成值使用**百分比**表示(如 66%、85%)\n- 得分保持原始数值(如 16.50)\n\n### 2. 表格行数调整\n- 模板容量 = 表格总行数 - 2(表头)- 1(平均值)\n- **学生数多:在平均值行之前插入新行**\n- 学生数少:删除多余的数据行\n\n### 3. 随机成绩范围\n| 课程目标 | 得分范围 | 满分 | 达成值计算 |\n|----------|----------|------|------------|\n| 目标1 | 10-24 | 25| a/25*100% |\n| 目标2 | 20-29 | 30 | b/30*100% |\n| 目标3 | 20-25 | 26.5 | c/26.5*100% |\n| 目标4 | 15-18 | 18.5 | d/18.5*100% |\n\n### 4. 模板预处理\n使用前确保模板已修正:\n- 去除黄色高亮\n- 修正占位符(如 major$ → $major$)\n- 扩展表8容量(如需要)\n---","attachment_filenames":["_meta.json"],"attachments":[{"filename":"_meta.json","content":"{\n \"owner\": \"alukardo\",\n \"slug\": \"achievement-qztc\",\n \"displayName\": \"Achievement Qztc\",\n \"latest\": {\n \"version\": \"1.0.0\",\n \"publishedAt\": 1773748029589,\n \"commit\": \"https://github.com/openclaw/skills/commit/8d66c893350a064137bf8ca350286ed4fe7afdee\"\n },\n \"history\": []\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":286,"content_sha256":"c9aba9d7d8428b071d612543e49ddd58078762c3770c36fdd4499078f9d1ad63"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"课程目标达成情况分析表生成工具(QZTC版)","type":"text"}]},{"type":"paragraph","content":[{"text":"根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"适用场景","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"根据Excel学生名单生成课程目标达成情况分析表","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"自动计算各课程目标的达成值(随机生成成绩,百分比表示)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"文件路径","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"模板文件","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"/Volumes/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-模版.docx","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Excel数据","type":"text","marks":[{"type":"strong"}]},{"text":": ","type":"text"},{"text":"/Volumes/qztcm09/Desktop/temp/数据可视化技术23级计算机.xls","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"使用步骤","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤1:读取Excel数据","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"import pandas as pd\nimport shutil\nimport random\nfrom docx import Document\nfrom datetime import datetime\n\n# 读取Excel\ndf = pd.read_excel('/Users/qztcm09/Desktop/temp/数据可视化技术23级计算机.xls')\n\n# 排除旷考学生\ndf = df[df['备注'] != '旷考'].reset_index(drop=True)\n\n# 自动判断当前学年和学期\nnow = datetime.now()\nyear = now.year\nmonth = now.month\nday= now.day\n\nif 1 \u003c= month \u003c= 6:\n # 1-6月:第一学期(上学年)\n academic_year = f\"{year-1} - {year}\"\n semester = \"一\"\nelse:\n # 7-12月:第二学期(上学年)\n academic_year = f\"{year-1} - {year}\"\n semester = \"二\"\n\nprint(f\"当前学年: {academic_year}, 学期: {semester}学期\")\n\n# 从\"班级\"字段提取年级、班级、专业信息\n# 专业名称提取支持两种情况:\n# 情况1: \"23级计算机\" → 年级=23, 专业=计算机\n# 情况2: \"23级软工2班\" → 年级=23, 专业=软工\nimport re\nclass_name = df['班级'].iloc[0] if '班级' in df.columns else ''\nmatch = re.search(r'(\\d+)级', str(class_name))\ngrade = match.group(1) if match else '' # 如 \"23\"\n# 提取专业:匹配 \"XX级\" 后面到 \"XX班\" 或结尾的部分\nmatch = re.search(r'\\d+级(.+?)(?:\\d+班)?

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(class_name))\nmajor = match.group(1).strip() if match else '' # 如 \"计算机\" 或 \"软工\"\n\n\n# 获取学生信息\nstudents = df[['学号', '姓名']].copy()\nprint(f\"学生人数: {len(students)}\")","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤2:复制模板并打开","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"template_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-模版.docx'\noutput_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-23级计算机.docx'\n\nshutil.copy(template_path, output_path)\ndoc = Document(output_path)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤3:通用文本替换","type":"text"}]},{"type":"paragraph","content":[{"text":"⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"def replace_text_preserve_format(para, replacements):\n \"\"\"替换段落文本但保留格式\"\"\"\n # 先收集所有run的文本\n full_text = ''.join(run.text for run in para.runs if run.text)\n \n # 检查是否有占位符\n has_placeholder = any(old in full_text for old, _ in replacements)\n if not has_placeholder:\n return\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 获取第一个run的格式作为基准\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 清空并用新文本创建单一run,保留格式\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return para\n\ndef replace_text_in_table_cell(cell, replacements):\n \"\"\"替换表格单元格中的文本(处理单元格内换行的情况)\"\"\"\n # 遍历单元格中的所有段落\n for para in cell.paragraphs:\n full_text = ''.join(run.text for run in para.runs if run.text)\n has_placeholder = any(old in full_text for old, _ in replacements)\n \n if has_placeholder:\n # 获取格式\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 清空并重新设置\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return cell\n\n# 替换配置\nreplacements = [\n ('$acyear

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, academic_year),\n ('$semester

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, semester),\n ('$g

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, grade),\n ('$major

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, major),\n ('$total

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, f'{len(students)}人'),\n ('$year

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(year)),\n ('$month

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(month)),\n ('$day

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(day)),\n]\n\n# 替换表格中的文本\nfor table in doc.tables:\n for row in table.rows:\n for cell in row.cells:\n replace_text_in_cell(cell, replacements)\n\n# 替换段落中的文本(处理被拆分的情况,保留格式)\nfor para in doc.paragraphs:\n replace_text_preserve_format(para, replacements)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤4:更新表8 - 课程目标个体达成情况明细","type":"text"}]},{"type":"paragraph","content":[{"text":"重要","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"先清理除表头(2行)和最后一行(平均值)外的所有学生数据","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"根据Excel学生数动态调整表格行数","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"在最后一行(平均值行)之前插入新行","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"所有达成值用","type":"text"},{"text":"百分比","type":"text","marks":[{"type":"strong"}]},{"text":"表示(如 66%)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"表格索引","type":"text","marks":[{"type":"strong"}]},{"text":": 8","type":"text"}]},{"type":"paragraph","content":[{"text":"表头结构","type":"text","marks":[{"type":"strong"}]},{"text":"(前2行):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"数据列对应关系","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"列索引","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"内容","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"序号","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"学号","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"姓名","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"随机值 a (10-24),课程目标1得分","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"a/25*100%,课程目标1达成值(百分比)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"随机值 b (20-28),课程目标2得分","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"6","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"b/30*100%,课程目标2达成值(百分比)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"7","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"随机值 c (20-25),课程目标3得分","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"8","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"c/26.5*100%,课程目标3达成值(百分比)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"9","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"随机值 d (15-18),课程目标4得分","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"d/18.5*100%,课程目标4达成值(百分比)","type":"text"}]}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# 步骤4.1: 动态调整表格行数(在平均值行之前插入)\ntable = doc.tables[8]\ncurrent_rows = len(table.rows)\n# 当前模板可以容纳的学生数(去掉2行表头和1行平均值)\ntemplate_capacity = current_rows - 3\n\n# 调整行数:在倒数第2行(平均值行之前)插入\nif len(students) > template_capacity:\n # 需要插入行,在平均值行之前插入\n for i in range(len(students) - template_capacity):\n # 在倒数第2行之前插入(即平均值行之前)\n new_row = table.add_row()\n # 将新行移动到平均值行之前\n # 由于add_row()是添加到末尾,需要交换位置\n # 获取平均值行索引\n avg_idx = len(table.rows) - 1\n # 将新插入的行移到平均值行之前\n table._element.remove(new_row._element)\n table._element.insert(len(table.rows) - 2, new_row._element)\nelif len(students) \u003c template_capacity:\n # 需要删除多余行(从数据区域末尾开始删,保留平均值行)\n for i in range(template_capacity - len(students)):\n # 删除倒数第2行(最后一个数据行)\n delete_idx = 2 + len(students)\n if delete_idx \u003c len(table.rows) - 1:\n table._element.remove(table.rows[delete_idx]._element)\n\n# 步骤4.2: 清理数据行(保留前2行表头和最后1行平均值)\nfor row_idx in range(2, len(table.rows) - 1):\n for cell in table.rows[row_idx].cells:\n cell.text = ''\n\n# 步骤4.3: 填入学生数据(达成值用百分比)\nall_a, all_b, all_c, all_d = [], [], [], []\nstudent_data = []\n\nfor i, (_, student) in enumerate(students.iterrows()):\n row_idx = i + 2\n if row_idx >= len(table.rows) - 1:\n break\n \n row = table.rows[row_idx]\n a = random.randint(10, 24)\n b = random.randint(20, 28)\n c = random.randint(20, 25)\n d = random.randint(15, 18)\n \n all_a.append(a)\n all_b.append(b)\n all_c.append(c)\n all_d.append(d)\n \n # 转为百分比\n v1, v2, v3, v4 = a/25*100, b/30*100, c/26.5*100, d/18.5*100\n student_data.append({'v1': v1, 'v2': v2, 'v3': v3, 'v4': v4})\n \n row.cells[0].text = str(i + 1)\n row.cells[1].text = str(student['学号'])\n row.cells[2].text = student['姓名']\n row.cells[3].text = f\"{a:.2f}\"\n row.cells[4].text = f\"{v1:.0f}%\" # 百分比\n row.cells[5].text = f\"{b:.2f}\"\n row.cells[6].text = f\"{v2:.0f}%\" # 百分比\n row.cells[7].text = f\"{c:.2f}\"\n row.cells[8].text = f\"{v3:.0f}%\" # 百分比\n row.cells[9].text = f\"{d:.2f}\"\n row.cells[10].text = f\"{v4:.0f}%\" # 百分比\n\nn = len(student_data)\n\n# 步骤4.4: 最后一行填写平均值(百分比)\navg_row = table.rows[-1]\navg_a = sum(all_a) / n\navg_b = sum(all_b) / n\navg_c = sum(all_c) / n\navg_d = sum(all_d) / n\navg_v1 = sum(s['v1'] for s in student_data) / n\navg_v2 = sum(s['v2'] for s in student_data) / n\navg_v3 = sum(s['v3'] for s in student_data) / n\navg_v4 = sum(s['v4'] for s in student_data) / n\n\navg_row.cells[0].text = \"平均值\"\navg_row.cells[3].text = f\"{avg_a:.2f}\"\navg_row.cells[4].text = f\"{avg_v1:.0f}%\"\navg_row.cells[5].text = f\"{avg_b:.2f}\"\navg_row.cells[6].text = f\"{avg_v2:.0f}%\"\navg_row.cells[7].text = f\"{avg_c:.2f}\"\navg_row.cells[8].text = f\"{avg_v3:.0f}%\"\navg_row.cells[9].text = f\"{avg_d:.2f}\"\navg_row.cells[10].text = f\"{avg_v4:.0f}%\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤5:更新表7汇总数据(百分比)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"table7 = doc.tables[7]\ntable7.rows[5].cells[7].text = f\"{avg_v1:.0f}%\"\ntable7.rows[8].cells[7].text = f\"{avg_v2:.0f}%\"\ntable7.rows[11].cells[7].text = f\"{avg_v3:.0f}%\"\ntable7.rows[14].cells[7].text = f\"{avg_v4:.0f}%\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤6:更新课程目标分析段落(百分比)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# 计算统计数据\nmax_v1 = max(s['v1'] for s in student_data)\nmin_v1 = min(s['v1'] for s in student_data)\n# ... 其他目标类似\n\n# 计算满足百分比阈值的学生比例\ncount_v1_80 = sum(1 for s in student_data if s['v1'] >= 80)\ncount_v1_60 = sum(1 for s in student_data if s['v1'] >= 60)\n# ... 其他类似\n\npct_v1_80 = count_v1_80 / n * 100\npct_v1_60 = count_v1_60 / n * 100\n# ... 其他类似\n\n# 更新段落\nnew_texts = {\n 1: f\"课程目标1的平均达成值为{avg_v1:.0f}%,最高达成值为{max_v1:.0f}%,最低达成值为{min_v1:.0f}%。其中{pct_v1_80:.1f}%的学生达成值在80%以上,{pct_v1_60:.1f}%的学生达成值在60%以上,说明...\",\n # ... 其他目标\n}\n\n# 找到并更新段落\nfor i, para in enumerate(doc.paragraphs):\n if '课程目标1的平均达成值为' in para.text:\n # 更新段落文本\n break","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"步骤7:保存","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"doc.save(output_path)\nprint(f\"文件已保存至: {output_path}\")","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"完整代码示例","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"import pandas as pd\nimport shutil\nimport random\nfrom docx import Document\nfrom datetime import datetime\n\nrandom.seed(42) # 可选:固定随机种子\n\ndef replace_text_preserve_format(para, replacements):\n \"\"\"替换段落文本但保留格式\"\"\"\n # 先收集所有run的文本\n full_text = ''.join(run.text for run in para.runs if run.text)\n \n # 检查是否有占位符\n has_placeholder = any(old in full_text for old, _ in replacements)\n if not has_placeholder:\n return\n \n # 执行替换\n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n # 获取第一个run的格式作为基准\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n # 清空并用新文本创建单一run,保留格式\n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return para\n\ndef replace_text_in_table_cell(cell, replacements):\n \"\"\"替换表格单元格中的文本(处理单元格内换行的情况)\"\"\"\n for para in cell.paragraphs:\n full_text = ''.join(run.text for run in para.runs if run.text)\n has_placeholder = any(old in full_text for old, _ in replacements)\n \n if has_placeholder:\n if para.runs:\n first_run = para.runs[0]\n font_name = first_run.font.name\n font_size = first_run.font.size\n font_bold = first_run.font.bold\n font_italic = first_run.font.italic\n else:\n font_name, font_size, font_bold, font_italic = None, None, None, None\n \n for old, new in replacements:\n full_text = full_text.replace(old, new)\n \n para.clear()\n run = para.add_run(full_text)\n if font_name:\n run.font.name = font_name\n if font_size:\n run.font.size = font_size\n if font_bold is not None:\n run.font.bold = font_bold\n if font_italic is not None:\n run.font.italic = font_italic\n \n return cell\n\ndef generate_achievement_analysis():\n # 1. 读取Excel\n df = pd.read_excel('/Users/qztcm09/Desktop/temp/数据可视化技术23级计算机.xls')\n df = df[df['备注'] != '旷考'].reset_index(drop=True)\n students = df[['学号', '姓名']].copy()\n print(f\"学生人数: {len(students)}\")\n \n # 2. 复制模板\n template_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-模版.docx'\n output_path = '/Users/qztcm09/Desktop/temp/课程目标达成情况分析表-数据可视化-23级计算机.docx'\n shutil.copy(template_path, output_path)\n doc = Document(output_path)\n \n # 3. 通用文本替换\n now = datetime.now()\n year, month, day = now.year, now.month, now.day\n \n # 根据班级提取专业信息(支持两种情况)\n # 情况1: \"23级计算机\" → 专业=\"计算机\"\n # 情况2: \"23级软工2班\" → 专业=\"软工\"\n import re\n class_name = df['班级'].iloc[0] if '班级' in df.columns else ''\n match = re.search(r'(\\d+)级', str(class_name))\n grade = match.group(1) if match else ''\n match = re.search(r'\\d+级(.+?)(?:\\d+班)?

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(class_name))\n major = match.group(1).strip() if match else ''\n \n if 1 \u003c= month \u003c= 6:\n academic_year = f\"{year-1} - {year}\"\n semester = \"一\"\n else:\n academic_year = f\"{year-1} - {year}\"\n semester = \"二\"\n \n replacements = [\n ('$acyear

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, academic_year),\n ('$semester

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, semester),\n ('$g

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, grade),\n ('$major

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, major),\n ('$total

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, f'{len(students)}人'),\n ('$year

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(year)),\n ('$month

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(month)),\n ('$day

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…

, str(day)),\n ]\n \n # 替换表格中的文本(使用新的函数处理换行)\n for table in doc.tables:\n for row in table.rows:\n for cell in row.cells:\n replace_text_in_table_cell(cell, replacements)\n \n # 替换段落中的文本(保留格式)\n for para in doc.paragraphs:\n replace_text_preserve_format(para, replacements)\n \n # 4. 更新表8\n table = doc.tables[8]\n current_rows = len(table.rows)\n template_capacity = current_rows - 3\n \n # 调整行数\n if len(students) > template_capacity:\n # 需要插入行,在平均值行之前插入\n rows_to_add = len(students) - template_capacity\n for i in range(rows_to_add):\n # 在倒数第2行(平均值行之前)插入新行\n new_row = table.add_row()\n # 将新行从末尾移到平均值行之前\n avg_idx = len(table.rows) - 1\n # 获取新行的tr元素\n new_tr = new_row._element\n # 移除\n table._element.remove(new_tr)\n # 在平均值行之前插入\n table._element.insert(avg_idx, new_tr)\n print(f\"插入{rows_to_add}行\")\n elif len(students) \u003c template_capacity:\n # 需要删除多余行\n rows_to_remove = template_capacity - len(students)\n for i in range(rows_to_remove):\n delete_idx = 2 + len(students)\n if delete_idx \u003c len(table.rows) - 1:\n table._element.remove(table.rows[delete_idx]._element)\n print(f\"删除{rows_to_remove}行\")\n \n # 清理数据行\n for row_idx in range(2, len(table.rows) - 1):\n for cell in table.rows[row_idx].cells:\n cell.text = ''\n \n # 填入数据\n all_a, all_b, all_c, all_d = [], [], [], []\n student_data = []\n \n for i, (_, student) in enumerate(students.iterrows()):\n row_idx = i + 2\n if row_idx >= len(table.rows) - 1:\n break\n \n row = table.rows[row_idx]\n a = random.randint(10, 24)\n b = random.randint(20, 28)\n c = random.randint(20, 25)\n d = random.randint(15, 18)\n \n all_a.append(a)\n all_b.append(b)\n all_c.append(c)\n all_d.append(d)\n \n v1, v2, v3, v4 = a/25*100, b/30*100, c/26.5*100, d/18.5*100\n student_data.append({'v1': v1, 'v2': v2, 'v3': v3, 'v4': v4})\n \n row.cells[0].text = str(i + 1)\n row.cells[1].text = str(student['学号'])\n row.cells[2].text = student['姓名']\n row.cells[3].text = f\"{a:.2f}\"\n row.cells[4].text = f\"{v1:.0f}%\"\n row.cells[5].text = f\"{b:.2f}\"\n row.cells[6].text = f\"{v2:.0f}%\"\n row.cells[7].text = f\"{c:.2f}\"\n row.cells[8].text = f\"{v3:.0f}%\"\n row.cells[9].text = f\"{d:.2f}\"\n row.cells[10].text = f\"{v4:.0f}%\"\n \n n = len(student_data)\n \n # 平均值(最后一行)\n avg_row = table.rows[-1]\n avg_a = sum(all_a) / n\n avg_b = sum(all_b) / n\n avg_c = sum(all_c) / n\n avg_d = sum(all_d) / n\n avg_v1 = sum(s['v1'] for s in student_data) / n\n avg_v2 = sum(s['v2'] for s in student_data) / n\n avg_v3 = sum(s['v3'] for s in student_data) / n\n avg_v4 = sum(s['v4'] for s in student_data) / n\n \n avg_row.cells[0].text = \"平均值\"\n avg_row.cells[1].text = \"\"\n avg_row.cells[2].text = \"\"\n avg_row.cells[3].text = f\"{avg_a:.2f}\"\n avg_row.cells[4].text = f\"{avg_v1:.0f}%\"\n avg_row.cells[5].text = f\"{avg_b:.2f}\"\n avg_row.cells[6].text = f\"{avg_v2:.0f}%\"\n avg_row.cells[7].text = f\"{avg_c:.2f}\"\n avg_row.cells[8].text = f\"{avg_v3:.0f}%\"\n avg_row.cells[9].text = f\"{avg_d:.2f}\"\n avg_row.cells[10].text = f\"{avg_v4:.0f}%\"\n \n # 5. 更新表7\n table7 = doc.tables[7]\n table7.rows[5].cells[7].text = f\"{avg_v1:.0f}%\"\n table7.rows[8].cells[7].text = f\"{avg_v2:.0f}%\"\n table7.rows[11].cells[7].text = f\"{avg_v3:.0f}%\"\n table7.rows[14].cells[7].text = f\"{avg_v4:.0f}%\"\n \n # 6. 统计并更新段落(见步骤6)\n # ...\n \n # 7. 保存\n doc.save(output_path)\n print(f\"完成!文件已保存至: {output_path}\")\n\nif __name__ == '__main__':\n generate_achievement_analysis()","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"⚠️ 注意事项","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. 达成值格式","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"所有达成值使用","type":"text"},{"text":"百分比","type":"text","marks":[{"type":"strong"}]},{"text":"表示(如 66%、85%)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"得分保持原始数值(如 16.50)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. 表格行数调整","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"模板容量 = 表格总行数 - 2(表头)- 1(平均值)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"学生数多:在平均值行之前插入新行","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"学生数少:删除多余的数据行","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. 随机成绩范围","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"课程目标","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"得分范围","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"满分","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"达成值计算","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"目标1","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"10-24","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"25","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"a/25*100%","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"目标2","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"20-29","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"30","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"b/30*100%","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"目标3","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"20-25","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"26.5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"c/26.5*100%","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"目标4","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"15-18","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"18.5","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"d/18.5*100%","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. 模板预处理","type":"text"}]},{"type":"paragraph","content":[{"text":"使用前确保模板已修正:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"去除黄色高亮","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"修正占位符(如 major$ → ","type":"text"},{"type":"math_inline","content":[{"text":"major","type":"text"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"扩展表8容量(如需要)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"achievement-qztc","author":"@skillopedia","source":{"stars":2012,"repo_name":"openclaw-master-skills","origin_url":"https://github.com/leoyeai/openclaw-master-skills/blob/HEAD/skills/achievement-qztc/SKILL.md","repo_owner":"leoyeai","body_sha256":"7b4ab5ffd5e54cc0cdaea0ca44beda7c8930b5c2ef34c6edb377d9f9f77a487c","cluster_key":"bd0807933e2ad222d37d6962037ceb3422250cc7cc39e0070c137f7e6b9d9186","clean_bundle":{"format":"clean-skill-bundle-v1","source":"leoyeai/openclaw-master-skills/skills/achievement-qztc/SKILL.md","attachments":[{"id":"d9fb4553-606b-56e2-83af-cabb46be65dd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d9fb4553-606b-56e2-83af-cabb46be65dd/attachment.json","path":"_meta.json","size":286,"sha256":"c9aba9d7d8428b071d612543e49ddd58078762c3770c36fdd4499078f9d1ad63","contentType":"application/json; charset=utf-8"}],"bundle_sha256":"9ad7e237b970d3928b487985f34355303c8001f344c01195f4f0e50c5d834588","attachment_count":1,"text_attachments":1,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/achievement-qztc/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"documents-office","category_label":"Documents"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"documents-office","import_tag":"clean-skills-v1","description":"课程目标达成情况分析表生成工具。根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。"}},"renderedAt":1782981887626}

课程目标达成情况分析表生成工具(QZTC版) 根据Excel学生数据替换Word模板中的课程目标达成情况,生成新的分析表。 适用场景 - 根据Excel学生名单生成课程目标达成情况分析表 - 自动计算各课程目标的达成值(随机生成成绩,百分比表示) --- 文件路径 - 模板文件 : - Excel数据 : --- 使用步骤 步骤1:读取Excel数据 步骤2:复制模板并打开 步骤3:通用文本替换 ⚠️ 重要:Word占位符可能被拆分成多个run,且表格单元格中可能有换行,需要特殊处理,保留原格式 步骤4:更新表8 - 课程目标个体达成情况明细 重要 : 1. 先清理除表头(2行)和最后一行(平均值)外的所有学生数据 2. 根据Excel学生数动态调整表格行数 3. 在最后一行(平均值行)之前插入新行 4. 所有达成值用 百分比 表示(如 66%) 表格索引 : 8 表头结构 (前2行): - 行0: 序号 | 学号 | 姓名 | 课程目标1(25分) | 课程目标1 | 课程目标2(30分) | 课程目标2 | 课程目标3(26.5分) | 课程目标3 | 课程目标4(18.5分) | 课程目标4 - 行1: 序号 | 学号 | 姓名 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 | 得分 | 达成值 数据列对应关系 : | 列索引 | 内容 | |-----…