关于 xlsx-processing-manus
这是一项用于生成打开后即可浏览的 Excel 工作簿的技能。它根据用户需求指导结构、分析、格式和可视化的选择。
主要功能
- 01按用户需求选择功能
- 02概览工作表与导航
- 03图表和条件格式
- 04公式与数字格式指引
- 05数据背景与洞察版块
- 06统一的工作簿主题
适用场景
- 01构建带摘要的多工作表工作簿
- 02用图表比较类别数值
- 03突出显示阈值和异常值
- 04用公式创建可调整模型
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ lawve-ai/ awesome-legal-skills --skill xlsx-processing-manus安装后在 Claude Code 中输入/xlsx-processing-manus确认已加载。
详细介绍
Excel 生成技能
目标
让用户能够立即使用 Excel,并在打开时获取洞察。
核心原则
尽可能丰富视觉呈现,同时确保内容清晰,不增加认知负担。每个视觉元素都应有意义且目的明确——为内容服务,而非用于装饰。
第 1 部分:用户需求与功能匹配
创建任何 Excel 之前,请先思考:
- 用户需要什么?——不是“一个 Excel 文件”,而是他们要解决什么问题?
- 我能提供什么?——哪些功能能帮助他们?
- 如何匹配?——针对具体场景选择合适的功能组合。
功能 ↔ 用户价值对应关系
帮助用户「理解数据」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 条形图/柱形图 | 一眼看出差异 | 比较不同类别的值 |
| 折线图 | 一眼看出趋势 | 时间序列数据 |
| 饼图 | 一眼看出占比 | 整体中的部分(≤6 个类别) |
| 数据条 | 无需离开单元格即可比较大小 | 需要快速比较的数值列 |
| 色阶 | 热力图效果,让模式一目了然 | 矩阵、范围、分布 |
| 迷你图 | 在单个单元格中查看趋势 | 包含历史背景的汇总行 |
帮助用户「找到重点」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 预先排序 | 最重要的数据排在前面 | 排名、Top N、优先级 |
| 条件突出显示 | 自动凸显关键数据 | 异常值、阈值、Top/Bottom N |
| 图标集 | 一眼看出状态 | KPI 状态、类别状态(谨慎使用) |
| 粗体/颜色强调 | 区分主要与次要内容 | 汇总行、关键指标 |
| 关键洞察部分 | 直接呈现结论 | 分析报告 |
帮助用户「节省时间」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 概览工作表 | 首页即为摘要,无需查找 | 所有多工作表文件 |
| 预先计算的摘要 | 结果现成,无需手动计算 | 需要统计的数据 |
| 统一的数字格式 | 无需调整格式 | 所有数值数据 |
| 冻结窗格 | 滚动时仍能看到标题 | 超过 10 行的表格 |
| 带链接的工作表索引 | 快速导航,无需猜测 | 超过 3 个工作表的文件 |
帮助用户「直接使用」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 筛选器 | 用户可以自行探索数据 | 需要探索性分析时 |
| 超链接 | 点击即可导航,无需手动切换 | 跨工作表引用、外部来源 |
| 适合打印的布局 | 可直接打印或导出为 PDF | 用于分享的报告 |
| 公式(而非硬编码) | 更改参数后,结果自动更新 | 模型、预测、可调整的场景 |
| 数据验证下拉菜单 | 防止输入错误 | 需要用户输入的模板 |
帮助用户「信任数据」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 数据来源说明 | 了解数据来源 | 所有外部数据 |
| 生成日期 | 了解数据的新鲜度 | 对时效性有要求的报告 |
| 数据时间范围 | 了解涵盖的时期 | 时间序列数据 |
| 专业格式 | 看起来可靠 | 所有面向外部的文件 |
| 统一精度 | 不必怀疑数据准确性 | 所有数值 |
帮助用户「获得洞察」
| 功能 | 用户价值 | 使用时机 |
|---|---|---|
| 对比列(Δ、%) | 无需手动计算即可比较 | YoY、MoM、A 与 B |
| 排名列 | 直接显示位次 | 竞争分析、绩效分析 |
| 分组汇总 | 按维度汇总结果 | 分段分析 |
| 趋势指标(↑↓) | 一眼看清方向 | 需要关注变化方向时 |
| 洞察文本 | 明确说明“这意味着什么” | 分析报告 |
第 2 部分:四层实施
第 1 层:结构(如何组织)
目标:逻辑清晰、易于导航,让用户立即找到所需内容。
工作表组织
| 指南 | 建议 |
|---|---|
| 工作表数量 | 3–5 个为宜,最多 7 个 |
| 第一个工作表 | 始终命名为「Overview」,包含摘要和导航 |
| 工作表顺序 | 从通用到具体(Overview → Data → Analysis) |
| 命名 | 清晰、简洁(例如「Revenue Data」,而非「Sheet1」) |
信息架构
- Overview 工作表必须独立完整:用户无需打开其他工作表,也应能理解核心信息
- 渐进式披露:先呈现摘要,为希望深入了解的用户提供详细信息
- 各工作表结构一致:采用相同的布局模式和起始位置
布局规则
| 元素 | 位置 |
|---|---|
| 左边距 | A 列留空(宽度为 3) |
| 上边距 | 第 1 行留空 |
| 内容起始位置 | 单元格 B2 |
| 分区间距 | 各分区之间留 1 行空行 |
| 表格间距 | 各表格之间留 2 行空行 |
| 图表 | 放在所有表格下方(间隔 2 行),或放在相关表格右侧 |
图表位置:
- 默认:放在所有表格下方,与内容左对齐
- 备选:放在单个相关表格的右侧
- 图表之间以及图表与表格之间不得重叠
独立文本行
对于只有一个文本单元格的行(标题、描述、注释、项目符号),文本会自然延伸到右侧的空单元格中。但如果右侧单元格包含任何内容(包括空格),文本就会被截断。
判断逻辑:
| 条件 | 操作 |
|---|---|
| 确认右侧单元格为空 | 无需操作——文本会自然延伸 |
| 右侧单元格可能有内容 | 将单元格合并至内容宽度,或自动换行 |
| 文本超出内容区域宽度 | 自动换行 + 手动设置行高 |
技术说明:仅设置填充和边框不会阻止文本溢出;只有实际单元格内容(包括空格字符)才会阻止溢出。
导航
对于包含 3 个或更多工作表的文件,请在 Overview 中加入工作表索引:
# Sheet Index with hyperlinks
ws['B5'] = "CONTENTS"
ws['B5'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])
sheets = ["Overview", "Data", "Analysis"]
for i, sheet_name in enumerate(sheets, start=6):
cell = ws.cell(row=i, column=2, value=sheet_name)
cell.hyperlink = f"#'{sheet_name}'!A1"
cell.font = Font(color=THEME['accent'], underline='single')
第 2 层:信息(用户学到什么)
目标:准确、完整、富有洞见——让用户获得知识,而不只是数据。
数字格式
关键规则:
- 每个数字单元格都必须设置
number_format——包括输入值和公式结果 - 同一列使用相同精度——绝不要在同一列中混用
0.1074和1.0 - 公式结果没有默认格式——除非明确设置格式,否则会显示原始精度
| 数据类型 | 格式代码 | 示例 |
|---|---|---|
| 整数 | #,##0 | 1,234,567 |
| 小数(1 位) | #,##0.0 | 1,234.6 |
| 小数(2 位) | #,##0.00 | 1,234.56 |
| 百分比 | 0.0% | 12.3% |
| 货币 | $#,##0.00 | $1,234.56 |
常见错误:只为输入单元格设置格式,却忘记设置公式单元格的格式。
# WRONG: Formula cell without number_format
ws['C10'] = '=C7-C9' # Will display raw precision like 14.123456789
# CORRECT: Always set number_format for formula cells
ws['C10'] = '=C7-C9'
ws['C10'].number_format = '#,##0.0' # Displays as 14.1
# Best practice: Define format by column/data type, apply to ALL cells
for row in range(data_start, data_end + 1):
cell = ws.cell(row=row, column=value_col)
cell.number_format = '#,##0.0' # Applies to both values and formulas
数据背景
每组数据都需要背景信息:
| 元素 | 位置 | 示例 |
|---|---|---|
| 数据来源 | Overview 或工作表页脚 | 「来源:Company Annual Report 2024」 |
| 时间范围 | 标题附近或副标题中 | 「数据来自 2020 年 1 月至 2024 年 12 月」 |
| 生成日期 | Overview 页脚 | 「生成日期:2024-01-15」 |
| 定义 | 注释部分或单独的工作表 | 「Revenue = 不含退货的净销售额」 |
关键洞见
对于分析内容,不要只展示数据——还要告诉用户数据的含义:
ws['B20'] = "KEY INSIGHTS"
ws['B20'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['accent'])
insights = [
"• Revenue grew 23% YoY, driven primarily by APAC expansion",
"• Top 3 customers account for 45% of total revenue",
"• Q4 showed strongest performance across all metrics"
]
for i, insight in enumerate(insights, start=21):
ws.cell(row=i, column=2, value=insight)
内容完整性
| 检查项 | 操作 |
|---|---|
| 缺失值 | 显示为空白或「N/A」;除非实际值为 0,否则不要显示 0 |
| 计算字段 | 添加公式或说明计算方法的注释 |
| 缩写 | 首次使用时或在注释中解释 |
| 单位 | 在标题中注明(例如「Revenue ($M)」) |
第 3 层:视觉(用户看到什么)
目标:外观专业,能立即体现价值,视觉元素服务于内容。
基本设置
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
# Hide gridlines for cleaner look
ws.sheet_view.showGridLines = False
# Left margin
ws.column_dimensions['A'].width = 3
主题系统
每个工作簿选择一个主题。所有视觉元素都以主题色为基础。
可用主题(根据上下文选择,或由用户指定):
| 主题 | 主色 | 浅色 | 适用场景 |
|---|---|---|---|
| 优雅黑 | 2D2D2D | E5E5E5 | 奢华、时尚、高端报告(推荐默认主题) |
| 企业蓝 | 1F4E79 | D6E3F0 | 金融、企业分析 |
| 森林绿 | 2E5A4C | D4E5DE | 可持续发展、环境保护 |
| 酒红 | 722F37 | E8D5D7 | 奢侈品牌、葡萄酒行业 |
| 板岩灰 | 4A5568 | E2E8F0 | 科技、现代、简约 |
| 海军蓝 | 1E3A5F | D3DCE6 | 政府、海事、机构 |
| 炭灰 | 36454F | DDE1E4 | 专业、管理层 |
| 深紫 | 4A235A | E1D5E7 | 创意、创新、高端科技 |
| 蓝绿色 | 1A5F5F | D3E5E5 | 医疗保健、健康 |
| 暖棕 | 5D4037 | E6DDD9 | 自然、有机、手工艺 |
| 皇家蓝 | 1A237E | D3D5E8 | 学术、机构 |
| 橄榄绿 | 556B2F | E0E5D5 | 军事、户外 |
主题配置:
# === THEME CONFIGURATION ===
THEMES = {
'elegant_black': {
'primary': '2D2D2D',
'light': 'E5E5E5',
'accent': '2D2D2D',
'chart_colors': ['2D2D2D', '4A4A4A', '6B6B6B', '8C8C8C', 'ADADAD', 'CFCFCF'],
},
'corporate_blue': {
'primary': '1F4E79',
'light': 'D6E3F0',
'accent': '1F4E79',
'chart_colors': ['1F4E79', '2E75B6', '5B9BD5', '9DC3E6', 'BDD7EE', 'DEEBF7'],
},
# ... other themes follow same pattern
}
THEME = THEMES['elegant_black'] # Default
SERIF_FONT = 'Source Serif Pro' # or 'Georgia' as fallback
SANS_FONT = 'Source Sans Pro' # or 'Calibri' as fallback
主题色的应用方式:
| 元素 | 颜色 | 背景 |
|---|---|---|
| 文档标题 | THEME['primary'] | 无 |
| 章节标题 | THEME['primary'] | 无或 THEME['light'] |
| 表格标题 | 白色 | THEME['primary'] |
| 数据单元格 | 黑色 | 无或交替使用 F9F9F9 |
| 图表元素 | THEME['chart_colors'] | — |
语义颜色
用于表达数据含义(独立于主题):
| 语义 | 颜色 | 用途 |
|---|---|---|
| 正向 | 2E7D32 | 增长、盈利、成功 |
| 负向 | C62828 | 下降、亏损、失败 |
| 警告 | F57C00 | 谨慎、注意 |
行高亮颜色
用于突出显示整行。使用高亮度色调(亮度为 85-95%),以实现轻微区分。
| 语义 | Hex | 色相 | 用途 |
|---|---|---|---|
| 强调 | E6F3FF | 209° | 最高评分、重要数据 |
| 章节 | FFF3E0 | 37° | 章节分隔符 |
| 输入 | FFFDE7 | 55° | 可编辑单元格 |
| 特殊 | FFF9C4 | 55° | 基准情况、基准值 |
| 成功 | E8F5E9 | 125° | 已通过、已完成 |
| 警告 | FFCCBC | 14° | 需要关注 |
规则:相同语义使用相同颜色。不同语义使用不同颜色。
HIGHLIGHT = {
'emphasis': 'E6F3FF',
'section': 'FFF3E0',
'input': 'FFFDE7',
'special': 'FFF9C4',
'success': 'E8F5E9',
'warning': 'FFCCBC',
}
字体排版
使用衬线字体 + 无衬线字体搭配。衬线字体用于建立层级(标题、表头);无衬线字体用于数据(表格数字)。
字体搭配(按优先顺序排列):
| 衬线字体(标题) | 无衬线字体(数据) | 备注 |
|---|---|---|
| Source Serif Pro | Source Sans Pro | Adobe 超级字体系列,推荐 |
| IBM Plex Serif | IBM Plex Sans | 现代、企业风格 |
| Georgia | Calibri | 预装后备字体 |
层级:
| 元素 | 字体 | 大小 | 样式 |
|---|---|---|---|
| 文档标题 | 衬线字体 | 18-22 | 粗体、主色 |
| 章节标题 | 衬线字体 | 12-14 | 粗体、主色 |
| 表格标题 | 衬线字体 | 10-11 | 粗体、白色 |
| 数据单元格 | 无衬线字体 | 11 | 常规、黑色 |
| 注释 | 无衬线字体 | 9-10 | 斜体、666666 |
# Document title
ws['B2'].font = Font(name=SERIF_FONT, size=18, bold=True, color=THEME['primary'])
# Section header
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])
# Table header
header_font = Font(name=SERIF_FONT, size=10, bold=True, color='FFFFFF')
# Data cells
data_font = Font(name=SANS_FONT, size=11)
# Notes
notes_font = Font(name=SANS_FONT, size=10, italic=True, color='666666')
数据块定义
数据块是由连续、非空行组成的分组,构成一个需要添加边框的视觉单元。数据块之间以空行分隔。
识别规则:
- 从章节标题开始向下扫描
- 非空行开始一个数据块
- 空行结束当前数据块
- 每个数据块都有自己的外框
数据块类型:
| 类型 | 结构 | 示例 |
|---|---|---|
| 带表头 | 表头行 + 数据行 | 带列标题的表格 |
| 不带表头 | 仅数据行 | 后续数据、子表格 |
示例识别:
Row 5: Section Header "INCOME STATEMENT" → No border (not a Data Block)
Row 6: Empty → Separator
Row 7: Header (Item, Year1, Year2...) → Data Block 1 starts
Row 8: Revenue, 47061, 48943...
Row 9: Growth Rate, 4.0%, 3.5%... → Data Block 1 ends
Row 10: Empty → Separator
Row 11: EBITDA, 12121, 12627... → Data Block 2 starts (no header)
Row 12: EBITDA Margin, 25.8%, 25.8%... → Data Block 2 ends
Row 13: Empty → Separator
Row 14: D&A, 1200, 1224... → Data Block 3 starts (no header)
Row 15: EBIT, 10921, 11404...
Row 16: EBIT Margin, 23.2%, 23.3%... → Data Block 3 ends
结果:3 个独立的数据块,每个都有自己的外框。
边框规则
推荐样式:仅使用水平边框——更简洁、现代。
每个数据块都必须有:
| 边框类型 | 位置 |
|---|---|
| 外框 | 数据块的 4 条边(上、下、左、右) |
| 表头底边 | 中等粗细,使用主题主色(如果有表头) |
| 内部水平线 | 细线,位于所有行之间 |
| 内部垂直线 | 无(省略以保持简洁) |
重要:数据块中的每个单元格都必须设置边框。不能只给表头和标签单元格设置边框——数据单元格也需要边框。
# Border definitions
outer_border = Side(style='thin', color='D1D1D1')
header_bottom = Side(style='medium', color=THEME['primary'])
inner_horizontal = Side(style='thin', color='D1D1D1')
no_border = Side(style=None)
def apply_data_block_borders(ws, start_row, end_row, start_col, end_col, has_header=True):
"""
Apply borders to a Data Block.
Every cell must be processed—not just headers and labels.
"""
for row in range(start_row, end_row + 1):
for col in range(start_col, end_col + 1):
cell = ws.cell(row=row, column=col)
# Left/Right: outer frame
left = outer_border if col == start_col else no_border
right = outer_border if col == end_col else no_border
# Top: outer for first row, inner horizontal for others
top = outer_border if row == start_row else inner_horizontal
# Bottom: header_bottom for header, outer for last row, inner for middle
if has_header and row == start_row:
bottom = header_bottom
elif row == end_row:
bottom = outer_border
else:
bottom = inner_horizontal
cell.border = Border(left=left, right=right, top=top, bottom=bottom)
非数据块元素(标题、章节标题、独立文本、备注):不加边框。
对齐方式
表头:居中。
数据单元格:
| 内容 | 水平对齐 |
|---|---|
| 短文本(词语) | 居中 |
| 长文本(句子) | 左对齐 + indent=1 |
| 数字 | 右对齐 |
| 日期、状态 | 居中 |
垂直对齐:始终为 center(包括自动换行的文本)。
# Left-aligned text with padding
cell.alignment = Alignment(horizontal='left', vertical='center', indent=1)
# Numbers
cell.alignment = Alignment(horizontal='right', vertical='center')
# Wrapped text
cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True, indent=1)
列宽
计算范围:仅限数据块单元格。排除独立文本行、章节标题和备注。
公式:max(max_content_length_in_data_blocks + padding, minimum)
| 列类型 | 填充 | 最小值 | 备注 |
|---|---|---|---|
| 标签/文本 | +4 | 15 | 通常为第一列 |
| 数字 | +6 | 14 | 为格式化数字(负号、逗号)留出额外空间 |
| 长文本 | +4 | 20,最大 40 | 超过最大值时换行 |
设计约束:不同数据块中的同一列应承担相似的作用。列宽由该列在所有数据块中的最长内容决定。
独立文本行:不要纳入列宽计算。让文本自然延伸,或使用换行/合并单元格。
def calculate_column_width(ws, col, data_block_ranges):
"""
Calculate column width based only on Data Block content.
Standalone text rows are excluded.
data_block_ranges: list of (start_row, end_row) tuples
"""
max_len = 0
is_numeric = True
for start_row, end_row in data_block_ranges:
for row in range(start_row, end_row + 1):
cell = ws.cell(row=row, column=col)
if cell.value:
# Get formatted display length
display_value = str(cell.value)
max_len = max(max_len, len(display_value))
if not isinstance(cell.value, (int, float)):
is_numeric = False
padding = 6 if is_numeric else 4
minimum = 14 if is_numeric else 15
return max(max_len + padding, minimum)
行高
必须手动设置——openpyxl 不会自动调整。
| 行类型 | 高度 |
|---|---|
| 文档标题 | 35 |
| 章节标题 | 25 |
| 表格表头 | 30 |
| 标准数据 | 18 |
| 自动换行的文本 | lines × 15 + 10 |
ws.row_dimensions[2].height = 35 # Title
ws.row_dimensions[5].height = 25 # Section header
ws.row_dimensions[7].height = 30 # Table header
ws.row_dimensions[8].height = 18 # Data row
合并单元格
| 元素 | 合并? | 跨度 |
|---|---|---|
| 文档/工作表标题 | 是 | 下方内容的宽度 |
| 章节标题 | 是 | 相关表格的宽度 |
| 多级表头(父级) | 是 | 跨越子列 |
| 长文本行 | 是 | 内容区域的宽度 |
何时合并:如果文本超出列边界而被截断,则应合并。如果文本能在单列内完整显示,合并为可选操作。
通常需要合并的情况:
- 标题和副标题(通常跨越整个内容宽度)
- 章节标题(跨越相关表格的宽度)
- KEY INSIGHTS 要点(长句)
- 备注和免责声明(多句文本)
带背景色的章节标题——合并宽度必须与表格宽度一致:
# Section header spans same width as table below
last_col = 8 # Must match table's last column
ws.merge_cells(f'B6:{get_column_letter(last_col)}6')
ws['B6'] = "KEY METRICS"
ws['B6'].font = Font(name=SERIF_FONT, size=14, bold=True, color=THEME['primary'])
ws['B6'].fill = PatternFill(start_color=THEME['light'], end_color=THEME['light'], fill_type='solid')
ws['B6'].alignment = Alignment(horizontal='left', vertical='center')
数据可视化
数据条:
from openpyxl.formatting.rule import DataBarRule
rule = DataBarRule(start_type='min', end_type='max', color=THEME['primary'])
ws.conditional_formatting.add('C5:C50', rule)
色阶:
from openpyxl.formatting.rule import ColorScaleRule
rule = ColorScaleRule(
start_type='min', start_color='FFFFFF',
end_type='max', end_color=THEME['primary']
)
ws.conditional_formatting.add('D5:D50', rule)
图表:
from openpyxl.chart import BarChart, Reference
chart = BarChart()
chart.title = "Revenue by Region"
data = Reference(ws, min_col=3, min_row=4, max_row=10)
cats = Reference(ws, min_col=2, min_row=5, max_row=10)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)
# Apply theme colors to chart series
for i, series in enumerate(chart.series):
series.graphicalProperties.solidFill = THEME['chart_colors'][i % len(THEME['chart_colors'])]
ws.add_chart(chart, "F5")
第 4 层:交互(如何交互)
目标:易于使用且灵活,用户可以探索和处理数据。
冻结窗格
对于行数超过 10 行的表格:
ws.freeze_panes = 'B5' # Freeze below header row
筛选器
对于行数超过 20 行的表格:
ws.auto_filter.ref = f"B4:{get_column_letter(last_col)}{last_row}"
超链接
# Internal link
cell.hyperlink = "#'Data'!A1"
cell.font = Font(color=THEME['accent'], underline='single')
# External link
cell.hyperlink = "https://example.com"
cell.font = Font(color=THEME['accent'], underline='single')
排序
按最有意义的维度预先排序:
- 排名 → 按值降序
- 时间序列 → 按日期升序
- 按字母排序 → 没有明确优先级时使用
df = df.sort_values('revenue', ascending=False)
可编辑性
- 如果用户可能会更新输入值,请使用公式
- 如果数据已定稿,请使用硬编码值
- 保持公式简单;复杂公式应附上说明