Skill: chengyusheng188/lingji-yunying-gongdan (version 1.0.1)

# Lingji-YunYing-Gongdan # LingJi运营工单分析Skill > Lingji工单数据分析与运营监控 | 支持PDF报告生成 **作者**: ChengYusheng **版本**: 1.0.0 **标签**: 运维, 工单分析, 数据报表, PDF生成 --- ## 技能简介 本技能对Lingji平台的运维工单数据进行全方位分析，自动生成专业的运营分析报告。支持终端直接输出和PDF报告两种形式，方便发送和存档。 ### 核心功能 - 📊 工单总量与分布统计 - ⏱️ 处理时效分析（平均时长、超时监控） - 👥 支撑人员工作量与质量评估 - ⭐ 满意度分析（含有效评价过滤） - 🔥 热点问题智能识别 - 📑 一键生成PDF分析报告 --- ## 数据结构 ### 输入格式 原始Excel工单包含24个字段： | 字段类别 | 包含字段 | |---------|---------| | 基本信息 | 提单人、提单人所属公司、工单单号、工单类型 | | 时间信息 | 创建时间、认领时间、响应时间、归档时间、处理时长 | | 状态信息 | 工单状态、菜单、模块、归属域 | | 内容信息 | 工单内容描述、处理人归属公司、开发域版本 | | 流转信息 | 处理工作组、当前处理人、历史处理人 | | 处理信息 | 红军处理意见描述 | | 评价信息 | 满意度选项、满意度分值 | | 超时信息 | 响应超期信息、响应超时状态 | ### 关键字段枚举 **工单状态：** - `红军已完成` - 处理人已回复，等待用户确认 - `待用户确认` - 用户尚未确认解决方案 - `蓝军已完成` - 二线已复核 - `待蓝军处理` - 需要二线介入 **工单类型：** - 问题咨询（最多） - 普通投诉 - 意见反馈 - 升级投诉 **满意度分值：** | 评价 | 分值 | |-----|-----| | 非常满意 | 10分 | | 满意 | 8分 | | 一般 | 6分 | | 不满意 | 4分 | | 非常不满意 | 2分 | | 未评价 | 0分 | --- ## 分析维度 ### 1. 整体运营概览 - 工单总量与类型分布 - 工单状态分布（已完成/待确认） - 归属域分布（管理域/开发域） - 满意度分布与平均分 ### 2. 时效性分析 - 平均处理时长（含中位数） - 处理时长分位数统计 - 响应超时工单数量与占比 - 超期工单明细清单 ### 3. 支撑人员分析 按处理工作组和具体处理人统计： - 处理工单数量 - 已完成率 - 满意度评分（仅计算有效评分） - 平均处理时长 - 响应超时情况 ### 4. 热点问题分析 通过对工单内容描述的文本分析，自动识别问题类型： | 问题类型 | 占比 | 典型场景 | |---------|-----|---------| | 流程审批 | 4.5% | 审批流、流程节点、流程配置 | | 需求管理 | 2.4% | 需求创建、需求变更、需求查询 | | 系统报错 | 1.4% | 各类系统错误提示 | | 立项/需求关联 | 9% | 项目立项、需求挂载、关联配置 | | 权限问题 | 8.8% | 权限不足、无法查看、访问受限 | | 数据问题 | 7.7% | 数据错误、数据缺失、数据不同步 | | 删除问题 | 6.7% | 无法删除、删除报错 | | 制品/仓库 | 6.4% | 制品上传、仓库管理 | | 建议/优化需求 | 6.4% | 功能建议、系统优化 | | 研发计划 | 4.8% | 计划填报、计划下达 | | 成果管理 | 4.3% | 成果申报、成果转化 | | 预算问题 | 2.4% | 预算配置、预算调整 | | 登录问题 | 2.2% | 登录异常、登录失败 | | 证书问题 | 1.2% | CA证书、安装配置 | ### 5. 质量专项分析 - 回复内容长度分析 - 标准化回复检查 - 复杂问题处理时效 --- ## 使用方法 ### 环境准备 ```bash # 激活虚拟环境 source ~/.openclaw/workspace/.venv/bin/activate # 安装依赖 pip install pandas openpyxl playwright playwright install chromium ``` ### 生成PDF报告（推荐） ```bash # 使用Playwright生成PDF（中文显示最佳） python3 scripts/generate_pdf.py <Excel文件> <输出PDF文件> # 示例 python3 scripts/generate_pdf.py 全量工单导出.xlsx 工单分析报告.pdf ``` ### 终端直接分析 ```bash # 完整分析报告（终端输出） python3 scripts/lingji_gongdan.py report <excel文件> ``` --- ## 输出格式 | 格式 | 说明 | |-----|------| | **PDF报告** | ⭐ 推荐，支持中文显示，自动分页，适合存档和分享 | | 终端输出 | 默认模式，快速查看关键指标 | | 文本格式 | 可重定向到文件保存 | --- ## 示例输出 ### 终端输出示例 ``` === Lingji工单运营分析报告 === 📊 整体概况 - 工单总量：xxx - 问题咨询：xxx (84.5%) - 普通投诉：xx (7.6%) - 意见反馈：78 (7.5%) ⏱️ 时效指标 - 平均处理时长：13分钟 - 中位数处理时长：6分钟 - 响应超时：9件 (0.9%) 👥 TOP5处理人 1. 赵xx：57件，平均满意度1.6分 2. 刘xx：56件，平均满意度1.8分 3. 王xx：28件，平均满意度2.3分 ``` ### PDF报告示例 生成的PDF报告包含： - 封面（报告标题、生成时间） - 目录 - 各分析维度独立章节 - 图表展示 - 详细数据表格 --- ## 注意事项 1. **数据格式**：输入文件应为Excel格式(.xlsx) 2. **字段校验**：确保字段名称与模板一致 3. **满意度计算**：自动过滤未评价（0分）的数据 4. **时间单位**：处理时长单位为分钟 5. **PDF依赖**：首次使用需运行 `playwright install chromium` --- ## 维护建议 - **定期分析**：建议每月导出数据后进行分析 - **重点关注**：满意度持续低于均值的处理人 - **超时跟进**：识别超时工单并及时跟进处理 - **产品反馈**：热点问题汇总后反馈产品改进 - **报告存档**：PDF报告可直接通过微信/WhatsApp发送 --- ## 技术栈 - Python 3.x - pandas - 数据处理 - openpyxl - Excel读取 - Playwright - PDF生成 --- ## 许可协议 MIT License

path: scripts/generate_pdf.py
content: #!/usr/bin/env python3
"""
灵畿运营工单分析 - PDF报告生成（使用Playwright）
"""
import sys
import pandas as pd
import re
import os
from collections import Counter
from datetime import datetime
from playwright.sync_api import sync_playwright

def parse_duration(s):
    """解析处理时长，返回分钟数"""
    if pd.isna(s):
        return None
    s = str(s)
    days = re.search(r'(\d+)天', s)
    hours = re.search(r'(\d+)小时', s)
    minutes = re.search(r'(\d+)分', s)
    seconds = re.search(r'(\d+)秒', s)
    total_minutes = 0
    if days: total_minutes += int(days.group(1)) * 24 * 60
    if hours: total_minutes += int(hours.group(1)) * 60
    if minutes: total_minutes += int(minutes.group(1))
    if seconds: total_minutes += int(seconds.group(1)) / 60
    return total_minutes

def classify_issue(desc):
    """问题分类"""
    if pd.isna(desc):
        return []
    desc = str(desc)
    issues = []
    
    if '权限' in desc or '看不了' in desc or '看不到' in desc or '无法查看' in desc:
        issues.append('权限问题')
    if '查询不到' in desc or '看不到项目' in desc or '找不到项目' in desc or '搜索不到' in desc:
        issues.append('项目查询不到')
    if '立项' in desc or '挂载' in desc or '关联需求' in desc:
        issues.append('立项/需求关联')
    if '报错' in desc or '异常' in desc or '失败' in desc:
        if '上传失败' in desc or '导入失败' in desc:
            issues.append('上传/导入失败')
        elif '服务器异常' in desc or '系统异常' in desc:
            issues.append('服务器异常')
        else:
            issues.append('系统报错')
    if '审批' in desc or '流程' in desc:
        issues.append('流程审批')
    if '数据' in desc or '金额不对' in desc or '金额有误' in desc:
        issues.append('数据问题')
    if '预算' in desc:
        issues.append('预算问题')
    if '登录' in desc or '登陆' in desc:
        issues.append('登录问题')
    if '证书' in desc:
        issues.append('证书问题')
    if '删除' in desc:
        issues.append('删除问题')
    if '修改' in desc or '编辑' in desc:
        if '无法编辑' in desc or '编辑不了' in desc:
            issues.append('编辑保存问题')
    if '建议' in desc or '优化' in desc:
        issues.append('建议/优化需求')
    if '需求' in desc:
        issues.append('需求管理')
    if '成果' in desc:
        issues.append('成果管理')
    if '研发计划' in desc:
        issues.append('研发计划')
    if '制品' in desc or '仓库' in desc:
        issues.append('制品/仓库')
    
    return issues if issues else ['其他问题']

def generate_html_report(df):
    """生成HTML报告内容"""
    total = len(df)
    
    # 时效数据
    df_copy = df.copy()
    df_copy['处理时长_分钟'] = df_copy['工单处理时长'].apply(parse_duration)
    valid_times = df_copy['处理时长_分钟'].dropna()
    
    # 问题分类
    all_issues = []
    for desc in df['工单内容描述']:
        all_issues.extend(classify_issue(desc))
    issue_counts = Counter(all_issues)
    
    # 满意度
    valid_sat = df[df['满意度分值'] > 0]
    
    # 处理人数据
    top_handlers = df['当前处理人'].value_counts().head(15).index.tolist()
    handler_rows = ""
    for handler in top_handlers:
        h_df = df[df['当前处理人'] == handler]
        h_total = len(h_df)
        completed = (h_df['工单状态'] == '红军已完成').sum()
        pending = (h_df['工单状态'] == '待用户确认').sum()
        very_sat = (h_df['满意度选项'] == '非常满意').sum()
        
        valid_satisfaction = h_df[h_df['满意度分值'] > 0]['满意度分值']
        avg_sat = valid_satisfaction.mean() if len(valid_satisfaction) > 0 else 0
        
        h_df_copy = h_df.copy()
        h_df_copy['时长_分钟'] = h_df_copy['工单处理时长'].apply(parse_duration)
        avg_time = h_df_copy['时长_分钟'].mean()
        
        handler_rows += f"""
        <tr>
            <td>{handler}</td>
            <td>{h_total}</td>
            <td>{completed}</td>
            <td>{pending}</td>
            <td>{very_sat}</td>
            <td>{avg_sat:.1f}</td>
            <td>{avg_time:.0f}分钟</td>
        </tr>
        """
    
    # 类型分布
    type_rows = ""
    for t, c in df['工单类型'].value_counts().items():
        type_rows += f"<tr><td>{t}</td><td>{c}</td><td>{c/total*100:.1f}%</td></tr>"
    
    # 状态分布
    status_rows = ""
    for s, c in df['工单状态'].value_counts().items():
        status_rows += f"<tr><td>{s}</td><td>{c}</td><td>{c/total*100:.1f}%</td></tr>"
    
    # 满意度分布
    sat_rows = ""
    for opt, cnt in df['满意度选项'].value_counts().items():
        sat_rows += f"<tr><td>{opt}</td><td>{cnt}</td><td>{cnt/total*100:.1f}%</td></tr>"
    
    # 热点问题
    issue_rows = ""
    for issue, cnt in issue_counts.most_common(15):
        issue_rows += f"<tr><td>{issue}</td><td>{cnt}</td><td>{cnt/total*100:.1f}%</td></tr>"
    
    # 模块
    module_rows = ""
    for module, cnt in df['模块'].value_counts().head(10).items():
        module_rows += f"<tr><td>{module}</td><td>{cnt}</td><td>{cnt/total*100:.1f}%</td></tr>"
    
    # 菜单
    menu_rows = ""
    for menu, cnt in df['菜单'].value_counts().head(10).items():
        menu_rows += f"<tr><td>{menu}</td><td>{cnt}</td><td>{cnt/total*100:.1f}%</td></tr>"
    
    # 工作组
    group_rows = ""
    for group, cnt in df['处理工作组'].value_counts().head(10).items():
        group_rows += f"<tr><td>{group}</td><td>{cnt}</td><td>{cnt/total*100:.1f}%</td></tr>"
    
    html = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>灵畿科研平台工单运营分析报告</title>
    <style>
        @page {{
            size: A4;
            margin: 15mm;
            margin-top: 20mm;
        }}
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }}
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "WenQuanYi Micro Hei", sans-serif;
            font-size: 10pt;
            line-height: 1.6;
            color: #333;
            padding: 20px;
        }}
        h1 {{
            text-align: center;
            font-size: 20pt;
            color: #1a4f7a;
            margin-bottom: 5px;
        }}
        .subtitle {{
            text-align: center;
            color: #666;
            font-size: 9pt;
            margin-bottom: 20px;
        }}
        h2 {{
            font-size: 14pt;
            color: #1a4f7a;
            border-bottom: 2px solid #1a4f7a;
            padding-bottom: 5px;
            margin-top: 25px;
            margin-bottom: 15px;
        }}
        h3 {{
            font-size: 11pt;
            color: #333;
            margin-top: 15px;
            margin-bottom: 10px;
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin: 10px 0;
            font-size: 9pt;
            page-break-inside: avoid;
        }}
        th {{
            background-color: #4472C4;
            color: white;
            padding: 8px;
            text-align: center;
            font-weight: normal;
        }}
        td {{
            padding: 6px 8px;
            border: 1px solid #ddd;
            text-align: center;
        }}
        tr:nth-child(even) {{
            background-color: #f9f9f9;
        }}
        .summary {{
            background-color: #e8f4f8;
            padding: 20px;
            border-radius: 8px;
            margin: 15px 0;
            display: flex;
            justify-content: space-around;
            flex-wrap: wrap;
        }}
        .summary-item {{
            text-align: center;
            padding: 10px 20px;
        }}
        .summary-value {{
            font-size: 22pt;
            font-weight: bold;
            color: #1a4f7a;
        }}
        .summary-label {{
            font-size: 9pt;
            color: #666;
            margin-top: 5px;
        }}
        .page-break {{
            page-break-after: always;
        }}
        .two-col {{
            display: flex;
            gap: 20px;
        }}
        .two-col > div {{
            flex: 1;
        }}
    </style>
</head>
<body>
    <h1>灵畿科研平台工单运营分析报告</h1>
    <div class="subtitle">报告生成时间：{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</div>
    
    <div class="summary">
        <div class="summary-item">
            <div class="summary-value">{total}</div>
            <div class="summary-label">工单总量</div>
        </div>
        <div class="summary-item">
            <div class="summary-value">{valid_times.mean():.0f}</div>
            <div class="summary-label">平均处理时长(分钟)</div>
        </div>
        <div class="summary-item">
            <div class="summary-value">{len(valid_sat)/total*100:.0f}%</div>
            <div class="summary-label">满意度评价率</div>
        </div>
        <div class="summary-item">
            <div class="summary-value">{valid_sat['满意度分值'].mean():.1f}</div>
            <div class="summary-label">满意度均分</div>
        </div>
    </div>
    
    <h2>一、工单类型与状态分布</h2>
    <div class="two-col">
        <div>
            <h3>工单类型分布</h3>
            <table>
                <tr><th>工单类型</th><th>数量</th><th>占比</th></tr>
                {type_rows}
            </table>
        </div>
        <div>
            <h3>工单状态分布</h3>
            <table>
                <tr><th>工单状态</th><th>数量</th><th>占比</th></tr>
                {status_rows}
            </table>
        </div>
    </div>
    
    <h2>二、时效性分析</h2>
    <table>
        <tr><th>指标</th><th>数值</th></tr>
        <tr><td>平均处理时长</td><td>{valid_times.mean():.0f} 分钟</td></tr>
        <tr><td>中位数处理时长</td><td>{valid_times.median():.0f} 分钟</td></tr>
        <tr><td>最短处理时长</td><td>{valid_times.min():.0f} 分钟</td></tr>
        <tr><td>最长处理时长</td><td>{valid_times.max():.0f} 分钟</td></tr>
        <tr><td>90分位处理时长</td><td>{valid_times.quantile(0.9):.0f} 分钟</td></tr>
    </table>
    
    <h2>三、满意度分析</h2>
    <table>
        <tr><th>满意度选项</th><th>数量</th><th>占比</th></tr>
        {sat_rows}
    </table>
    
    <div class="page-break"></div>
    
    <h2>四、热点问题分析</h2>
    <table>
        <tr><th>问题类型</th><th>数量</th><th>占比</th></tr>
        {issue_rows}
    </table>
    
    <h2>五、支撑人员工作量排名（TOP15）</h2>
    <table>
        <tr><th>处理人</th><th>工单数</th><th>已完成</th><th>待确认</th><th>非常满意</th><th>平均满意度</th><th>平均处理时长</th></tr>
        {handler_rows}
    </table>
    
    <h2>六、处理工作组分布（TOP10）</h2>
    <table>
        <tr><th>工作组</th><th>工单数</th><th>占比</th></tr>
        {group_rows}
    </table>
    
    <h2>七、高频模块与菜单</h2>
    <div class="two-col">
        <div>
            <h3>高频模块TOP10</h3>
            <table>
                <tr><th>模块</th><th>数量</th><th>占比</th></tr>
                {module_rows}
            </table>
        </div>
        <div>
            <h3>高频菜单TOP10</h3>
            <table>
                <tr><th>菜单</th><th>数量</th><th>占比</th></tr>
                {menu_rows}
            </table>
        </div>
    </div>
</body>
</html>
"""
    return html

def main():
    if len(sys.argv) < 3:
        print("Usage: python3 generate_pdf.py <excel_file> <output_pdf>")
        sys.exit(1)
    
    file_path = sys.argv[1]
    output_path = sys.argv[2]
    
    print(f"Loading data from: {file_path}")
    df = pd.read_excel(file_path)
    print(f"Loaded {len(df)} records")
    
    html_content = generate_html_report(df)
    
    # 写入临时HTML文件
    html_path = "/tmp/lingji_report.html"
    with open(html_path, "w", encoding="utf-8") as f:
        f.write(html_content)
    
    print("Generating PDF with Playwright...")
    
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto(f"file://{html_path}")
        page.pdf(
            path=output_path,
            format="A4",
            margin={"top": "15mm", "bottom": "15mm", "left": "15mm", "right": "15mm"},
            print_background=True
        )
        browser.close()
    
    print(f"PDF generated: {output_path}")

if __name__ == "__main__":
    main()


path: scripts/lingji_gongdan.py
content: #!/usr/bin/env python3
"""
灵畿运营工单分析脚本
"""
import sys
import pandas as pd
import re
from pathlib import Path

def parse_duration(s):
    """解析处理时长，返回分钟数"""
    if pd.isna(s):
        return None
    s = str(s)
    days = re.search(r'(\d+)天', s)
    hours = re.search(r'(\d+)小时', s)
    minutes = re.search(r'(\d+)分', s)
    seconds = re.search(r'(\d+)秒', s)
    total_minutes = 0
    if days: total_minutes += int(days.group(1)) * 24 * 60
    if hours: total_minutes += int(hours.group(1)) * 60
    if minutes: total_minutes += int(minutes.group(1))
    if seconds: total_minutes += int(seconds.group(1)) / 60
    return total_minutes

def cmd_stats(df):
    """整体统计"""
    print("\n" + "="*50)
    print("📊 整体概况")
    print("="*50)
    print(f"工单总量：{len(df)}")
    print("\n📋 工单类型分布：")
    for t, c in df['工单类型'].value_counts().items():
        print(f"  {t}: {c} ({c/len(df)*100:.1f}%)")
    
    print("\n📋 工单状态分布：")
    for s, c in df['工单状态'].value_counts().items():
        print(f"  {s}: {c} ({c/len(df)*100:.1f}%)")
    
    print("\n📋 归属域分布：")
    for d, c in df['归属域'].value_counts().items():
        print(f"  {d}: {c} ({c/len(df)*100:.1f}%)")
    
    print("\n📋 满意度分布：")
    for sat, c in df['满意度选项'].value_counts().items():
        print(f"  {sat}: {c}")

def cmd_handlers(df):
    """处理人统计"""
    print("\n" + "="*50)
    print("👥 支撑人员分析（按处理量排名）")
    print("="*50)
    
    top_handlers = df['当前处理人'].value_counts().head(15).index.tolist()
    
    print(f"{'处理人':<10} {'工单数':>6} {'已完成':>6} {'待确认':>6} {'非常满意':>8} {'平均满意度':>10} {'平均处理时长':>12}")
    print("-"*70)
    
    for handler in top_handlers:
        h_df = df[df['当前处理人'] == handler]
        total = len(h_df)
        completed = (h_df['工单状态'] == '红军已完成').sum()
        pending = (h_df['工单状态'] == '待用户确认').sum()
        very_sat = (h_df['满意度选项'] == '非常满意').sum()
        
        # 只计算有效满意度（>0）
        valid_sat = h_df[h_df['满意度分值'] > 0]['满意度分值']
        avg_sat = valid_sat.mean() if len(valid_sat) > 0 else 0
        
        h_df_copy = h_df.copy()
        h_df_copy['时长_分钟'] = h_df_copy['工单处理时长'].apply(parse_duration)
        avg_time = h_df_copy['时长_分钟'].mean()
        
        print(f"{handler:<10} {total:>6} {completed:>6} {pending:>6} {very_sat:>8} {avg_sat:>10.1f} {avg_time:>10.0f}分钟")

def cmd_timing(df):
    """时效分析"""
    print("\n" + "="*50)
    print("⏱️ 时效性分析")
    print("="*50)
    
    df_copy = df.copy()
    df_copy['处理时长_分钟'] = df_copy['工单处理时长'].apply(parse_duration)
    
    valid_times = df_copy['处理时长_分钟'].dropna()
    print(f"平均处理时长: {valid_times.mean():.0f} 分钟")
    print(f"中位数处理时长: {valid_times.median():.0f} 分钟")
    print(f"最短处理时长: {valid_times.min():.0f} 分钟")
    print(f"最长处理时长: {valid_times.max():.0f} 分钟")
    print(f"90分位处理时长: {valid_times.quantile(0.9):.0f} 分钟")
    
    print("\n📋 响应超时状态：")
    for status, count in df['响应超时状态'].value_counts().items():
        print(f"  {status}: {count}")
    
    # 超时工单明细
    timeout_df = df[df['响应超时状态'] == '已超时']
    if len(timeout_df) > 0:
        print(f"\n⚠️ 超时工单明细（共{len(timeout_df)}条）：")
        for _, row in timeout_df.head(10).iterrows():
            print(f"  - {row['工单单号']} | {row['当前处理人']} | 超期: {row['响应超期信息']}")

def cmd_satisfaction(df):
    """满意度分析"""
    print("\n" + "="*50)
    print("😊 满意度分析")
    print("="*50)
    
    # 有效满意度
    valid_df = df[df['满意度分值'] > 0]
    print(f"有效满意度评价: {len(valid_df)}/{len(df)} ({len(valid_df)/len(df)*100:.1f}%)")
    
    print("\n📋 满意度分布：")
    for opt, cnt in df['满意度选项'].value_counts().items():
        pct = cnt / len(df) * 100
        print(f"  {opt}: {cnt} ({pct:.1f}%)")
    
    print(f"\n整体平均满意度分值: {df['满意度分值'].mean():.2f}")
    print(f"有效评价平均分: {valid_df['满意度分值'].mean():.2f}")
    
    # 处理人满意度排名
    print("\n📋 支撑人员满意度排名（处理量>5）：")
    handler_sat = df.groupby('当前处理人').agg({
        '满意度分值': lambda x: x[x > 0].mean(),
        '当前处理人': 'count'
    }).round(2)
    handler_sat.columns = ['平均分', '处理量']
    handler_sat = handler_sat[handler_sat['处理量'] > 5].sort_values('平均分', ascending=False)
    
    for handler, row in handler_sat.head(10).iterrows():
        print(f"  {handler}: {row['平均分']:.1f}分 ({row['处理量']:.0f}件)")

def cmd_hot(df):
    """热点问题分析"""
    import re
    from collections import Counter
    
    print("\n" + "="*50)
    print("🔥 热点问题分析")
    print("="*50)
    
    # 细粒度问题分类
    def classify_issue(desc):
        if pd.isna(desc):
            return []
        desc = str(desc)
        issues = []
        
        # 权限问题
        if '权限' in desc or '看不了' in desc or '看不到' in desc or '无法查看' in desc:
            issues.append('权限问题')
        
        # 项目查询/找不到
        if '查询不到' in desc or '看不到项目' in desc or '找不到项目' in desc or '搜索不到' in desc:
            issues.append('项目查询不到')
        
        # 立项/挂载问题
        if '立项' in desc or '挂载' in desc or '关联需求' in desc:
            issues.append('立项/需求关联')
        
        # 系统报错
        if '报错' in desc or '异常' in desc or '失败' in desc:
            if '上传失败' in desc or '导入失败' in desc:
                issues.append('上传/导入失败')
            elif '服务器异常' in desc or '系统异常' in desc:
                issues.append('服务器异常')
            else:
                issues.append('系统报错')
        
        # 流程审批
        if '审批' in desc or '流程' in desc:
            issues.append('流程审批')
        
        # 数据问题
        if '数据' in desc or '金额不对' in desc or '金额有误' in desc:
            issues.append('数据问题')
        
        # 预算问题
        if '预算' in desc:
            issues.append('预算问题')
        
        # 登录问题
        if '登录' in desc or '登陆' in desc:
            issues.append('登录问题')
        
        # 证书问题
        if '证书' in desc:
            issues.append('证书问题')
        
        # 删除问题
        if '删除' in desc:
            issues.append('删除问题')
        
        # 修改/编辑问题
        if '修改' in desc or '编辑' in desc:
            if '无法编辑' in desc or '编辑不了' in desc:
                issues.append('编辑保存问题')
        
        # 建议/优化
        if '建议' in desc or '优化' in desc:
            issues.append('建议/优化需求')
        
        # 需求管理
        if '需求' in desc:
            issues.append('需求管理')
        
        # 成果问题
        if '成果' in desc:
            issues.append('成果管理')
        
        # 研发计划
        if '研发计划' in desc:
            issues.append('研发计划')
        
        # 制品/仓库
        if '制品' in desc or '仓库' in desc:
            issues.append('制品/仓库')
        
        return issues if issues else ['其他问题']
    
    # 统计问题类型
    all_issues = []
    for desc in df['工单内容描述']:
        all_issues.extend(classify_issue(desc))
    
    issue_counts = Counter(all_issues)
    
    print("\n📋 细分问题类型TOP20：")
    for issue, cnt in issue_counts.most_common(20):
        pct = cnt / len(df) * 100
        print(f"  {issue}: {cnt} ({pct:.1f}%)")
    
    # 高频模块
    print("\n📋 高频模块TOP10：")
    for module, cnt in df['模块'].value_counts().head(10).items():
        print(f"  {module}: {cnt}")
    
    # 高频菜单
    print("\n📋 高频菜单TOP10：")
    for menu, cnt in df['菜单'].value_counts().head(10).items():
        print(f"  {menu}: {cnt}")
    
    print("\n📋 处理工作组TOP10：")
    for group, cnt in df['处理工作组'].value_counts().head(10).items():
        print(f"  {group}: {cnt}")

def cmd_full_report(df):
    """完整报告"""
    print("\n" + "="*60)
    print("       灵畿科研平台工单运营分析报告")
    print("="*60)
    
    cmd_stats(df)
    cmd_handlers(df)
    cmd_timing(df)
    cmd_satisfaction(df)
    cmd_hot(df)
    
    print("\n" + "="*60)
    print("                    报告生成完成")
    print("="*60)

def main():
    if len(sys.argv) < 3:
        print("Usage: python3 lingji_gongdan.py <command> <excel_file>")
        print("Commands: stats, handlers, timing, satisfaction, hot, report")
        sys.exit(1)
    
    command = sys.argv[1]
    file_path = sys.argv[2]
    
    print(f"Loading data from: {file_path}")
    df = pd.read_excel(file_path)
    print(f"Loaded {len(df)} records\n")
    
    if command == "stats":
        cmd_stats(df)
    elif command == "handlers":
        cmd_handlers(df)
    elif command == "timing":
        cmd_timing(df)
    elif command == "satisfaction":
        cmd_satisfaction(df)
    elif command == "hot":
        cmd_hot(df)
    elif command == "report":
        cmd_full_report(df)
    else:
        print(f"Unknown command: {command}")
        sys.exit(1)

if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)