从人员花名册 Excel 到可交互 HTML 人才盘点报告的全流程自动化技能。
Excel花名册 → Python解析/增强 → JSON数据 → Python构建 → HTML报告 → 部署分享
Excel 花名册(.xlsx),需包含以下标准字段(列名):
| 字段 | 说明 | 示例 |
|---|---|---|
| ------ | ------ | ------ |
| 序号 | 编号 | 1 |
| 二级单位 | 如"华南大区" | 华南大区 |
| 三级单位 | 如"华南钢结构公司" | 华南钢结构公司 |
| 部门/项目 | 项目或部门名称 | 深圳前海项目 |
| 姓名 | 人员姓名 | 张三 |
| 性别 | 男/女 | 男 |
| 出生日期 | YYYY-MM-DD | 1990-05-15 |
| 政治面貌 | 中共党员/共青团员/群众 | 中共党员 |
| 参加工作时间 | YYYY-MM-DD | 2012-07-01 |
| 入职科工时间 | YYYY-MM-DD | 2012-07-01 |
| 职级 | 数值或文本 | 23 |
| 主任职 | 如"项目经理" | 项目经理 |
| 第一学历 | 学历 | 大学本科 |
| 最高学历 | 最高学历 | 大学本科 |
| 职称 | 正高级/副高级/中级/初级/无职称 | 中级 |
| 职业资格 | 资格名称 | 一级建造师-建筑工程 |
| 2023/2024/2025年考核 | A/B+/B/C | A |
| 人员标签 | 如"管理人员" | 管理人员 |
| 项目分类 | 如"房建""桥梁""总部" | 房建 |
| 项目状态 | 在施阶段/准备阶段/完工阶段等 | 在施阶段 |
用 Python 解析 Excel,生成 people_data_enhanced.json:
import openpyxl, json, re
from datetime import date, datetime
from collections import Counter
AGE_BANDS = [(25, '25岁以下'), (30, '26-30岁'), (35, '31-35岁'),
(40, '36-40岁'), (45, '41-45岁'), (50, '46-50岁'),
(55, '51-55岁'), (999, '55岁以上')]
def parse_date(val):
"""解析各种格式的日期"""
if isinstance(val, (date, datetime)):
d = val if isinstance(val, date) else val.date()
return d.strftime('%Y-%m-%d')
if isinstance(val, str):
for fmt in ['%Y-%m-%d', '%Y/%m/%d', '%Y.%m.%d', '%Y%m%d']:
try: return datetime.strptime(val.strip(), fmt).strftime('%Y-%m-%d')
except: pass
m = re.match(r'^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})$', val)
if m: return f'{m.group(1)}-{m.group(2).zfill(2)}-{m.group(3).zfill(2)}'
return None
def calc_age(dob_str, ref=date(2025,5,1)):
"""根据出生日期计算年龄"""
if not dob_str: return None
try:
parts = dob_str.split('-')
yr, mo, dy = int(parts[0]), int(parts[1]), int(parts[2])
age = ref.year - yr - ((ref.month, ref.day) < (mo, dy))
return age
except: return None
def calc_years(start_str, ref=date(2025,5,1)):
"""计算参加工作/司龄年限"""
if not start_str: return None
try:
parts = start_str.split('-')
yr, mo, dy = int(parts[0]), int(parts[1]), int(parts[2])
return round((ref - date(yr, mo, dy)).days / 365.25, 1)
except: return None
def get_age_band(age):
"""获取年龄段"""
if age is None: return '未知'
for max_age, band in AGE_BANDS:
if age <= max_age: return band
return '55岁以上'
def normalize_title(raw):
"""规范化职级(提取数字)"""
if not raw: return None
m = re.search(r'(\d+)', str(raw))
return int(m.group(1)) if m else None
FIELD_MAP = {
'序号': 'seq', '二级单位': 'unit2', '三级单位': 'unit3',
'部门/项目': 'dept', '部门': 'dept', '姓名': 'name',
'性别': 'gender', '出生日期': 'dob', '政治面貌': 'political',
'参加工作时间': 'work_start', '入职科工时间': 'join_gjkg',
'职级': 'level_raw', '主任职': 'title_post',
'第一学历': 'edu1', '最高学历': 'edu_high',
'职称': 'title', '职业资格': 'cert_raw',
'2023年考核': 'assess_2023', '2024年考核': 'assess_2024',
'2025年考核': 'assess_2025',
'人员标签': 'person_tag', '项目分类': 'project_cat',
'项目状态': 'project_status', '部门属性': 'dept_attr',
'身份证号': 'id_no',
}
关键技术要点:
YYYY-MM-DD, YYYY/MM/DD, YYYY.MM.DD, 等)在HTML报告中,后台数据页面提供模板下载,包含所有列名和示例数据:
build_report_v3.py 从 people_data_enhanced.json 读取数据,计算所有统计指标,嵌入完整的HTML模板。
统计计算模块:
| 标签页 | 内容 |
|---|---|
| -------- | ------ |
| 总览 | KPI卡片(6个核心指标)、年龄/学历/职称/政治面貌图表、三级单位排名 |
| 年龄与性别 | 年龄段柱状图+性别饼图、各单位年龄结构对比、核心发现+风险提示 |
| 学历与职称 | 学历分布+职称饼图、各单位本科率/职称率对比、紧迫建议 |
| 执业资格 | TOP15持证人数柱状图、各单位持证率、证书人才名单 |
| 考核成绩 | 🔒近三年考核对比、各层级趋势、各单位A级占比(管理员密码talent2025) |
| 三级单位分析 | 单位卡片网格(6维指标)、综合雷达图、全员名单 |
| 项目分类 | 三大板块饼图、TOP12条形图、分类卡片、年龄/学历对比、施工状态分布 |
| 关键岗位 | 项目经理/项目班子/车间主任概览卡片+分别的年龄/学历/职称图表 |
| 项目经理档案 | 档案概览、人才梯队九宫格、考核趋势、荣誉/资质图表、个人履历详情 |
| 后备人才库 | 添加/编辑/删除/导入/导出(localStorage持久化)、CSV/JSON互转 |
| 人员查询 | 10维多选筛选+姓名搜索、敏感信息🔒模糊、Excel/CSV导出 |
| 后台数据 | Excel花名册导入(拖拽上传)、在线采集表(二维码/腾讯文档/表单)、模板下载 |
filter:blur(4px))默认管理员密码:talent2025(SHA-256哈希:5145aaca59e842d7b6d27cf7bb583bc69e5cec322fde3da496041c2fe9a9b065)
登录后解锁:
# 1. 确保HTML文件在部署目录
mkdir -p /tmp/talent-report-deploy
cp /path/to/人才盘点分析报告V3.html /tmp/talent-report-deploy/index.html
# 2. 部署
cd /tmp/talent-report-deploy && \
PAGES_SOURCE=skills \
/Users/macbook/.workbuddy/binaries/node/versions/22.12.0/bin/node \
/Users/macbook/.workbuddy/binaries/node/workspace/node_modules/edgeone/edgeone-bin/edgeone.js \
pages deploy -n talent-report
⚠️ 注意:
npm install edgeone@latesteo_token 鉴权参数*.edgeone.cool 域名未ICP备案,微信内需申请域名恢复(1-3个工作日)# 上传并设置Content-Disposition为inline
python3 /path/to/cos_upload.py /path/to/report.html talent-report/v3.html
⚠️ COS直链和cos-website域名在微信内均会触发下载,需配合EdgeOne CDN加速使用。
使用 html-deploy 技能快速部署到公网分享链接。
如需项目经理个人档案信息(工作履历、业绩亮点、荣誉获奖、资格证书),需要额外处理:
extract_resumes.py 解析简历resume_data.jsonpeople_data_enhanced.json 中的 _resume 字段# 简历字段结构
_resume = {
"name": "张三",
"gender": "男",
"dob": "1985-03-15",
"political": "中共党员",
"phone": "13800138000",
"work_start": "2008-07-01",
"join_gjkg": "2008-07-01",
"title": "高级工程师",
"level_raw": "Z5",
"positions": [], # 历任职务
"edu1": "大学本科",
"edu_high": "硕士研究生",
"work_history": [{"dates": ["2010","至今"], "desc": "..."}],
"achievements": [{"year": "2024", "content": "..."}],
"honors": [{"name": "优秀项目管理者", "level": "公司级", "date": "2024"}],
"cert_abc": ["一级建造师-建筑工程"], # 注册类
"cert_pro": [], # 专业类
"cert_qual": [] # 岗位类
}
| 问题 | 原因 | 解决方案 |
|---|---|---|
| ------ | ------ | ---------- |
| 微信打开显示下载 | Content-Disposition未设inline | 通过EdgeOne Pages部署 |
| 微信显示"申请恢复访问" | 域名未备案 | 绑定已备案自定义域名 |
| 页面加载后图表空白 | Chart.js CDN加载失败 | 检查网络/改用国内CDN |
| Excel导入后字段为空 | 列名不匹配 | 按模板调整Excel表头 |
| 中文路径npm报错 | Node.js对中文路径支持差 | 将脚本和依赖放/tmp/ |
| 年龄计算不准确 | 基准日期固定 | 修改ref=date(2025,5,1) |
共 1 个版本