非故工单管控小助手:全模块技术报告与二次开发指导
本文系统性解构针对国家电网营销 2.0 业务场景打造的“95598 非故工单管控小助手”桌面端轻量工具。从 ISC SSO 统一身份认证、国密算法(SM2/SM3/SM4)双向安全通信、本地 SQLite WAL 存储与风控锁定,到三维规则调度引擎、Tkinter 线程安全事件驱动,以及 Windows 7 x64 极端无网环境离线打包全流程,提供深度的技术剖析与全模块开发指引。
📑 本文目录
- 系统总体架构与业务全景
- config_store.py:配置管理与持久化模块
- storage.py:本地 SQLite 数据存储与风控模块
- integrations.py:外部系统集成与国密通信中枢
- vendor 目录:加密算法与易协作自动化底层
- monitor.py:监控调度与规则判定引擎
- app.py:Tkinter 图形用户界面与线程驱动
- build_win7.ps1 与 Spec:Win7 离线打包全流程解析
- 实战排错与二次开发指导
1. 系统总体架构与业务全景
1.1 业务背景
“95598 非故工单管控小助手”源于国家电网营销 2.0 业务场景。传统业务人员需要全天候手动刷新营销 2.0 待办工作台,极易漏看紧急诉求、客户多次反映的敏感投诉工单或临近办理红线的超时工单。
本系统定位于纯只读的辅助管控提醒工具:
- 安全红线:仅调取待办工单列表与详情接口,绝不调用签收、派单、转派、回单等生产写接口,规避生产事故风险;
- 三维监控模型:
- 全部工单:新工单进入待办工作台立即提醒;
- 敏感工单:工单内容命中预设敏感词库立即报警;
- 超时工单:依据受理时间与时限配置,提前进入预警窗口时报警。
- 双通道触达:短信系统(国网短信平台直发)+ 易协作(国网协同办公平台,支持私聊与群聊)。
1.2 系统架构拓扑图
graph TB
subgraph 表现层 Presentation
APP["app.py<br/>Tkinter + ttk 界面"]
CFG_STORE["config_store.py<br/>配置管理"]
end
subgraph 业务逻辑层 Logic
MONITOR["monitor.py<br/>ReminderEngine 轮询调度器"]
RULES["规则匹配引擎<br/>全部 / 敏感词 / 超时计算"]
PARSER["_ticket_view<br/>工单数据清洗标准化"]
end
subgraph 数据持久层 Persistence
STORAGE["storage.py<br/>SQLite WAL 模式"]
DB[("reminder.db<br/>工单 / 队列 / 风控")]
CONFIG_JSON[("config.json<br/>用户配置")]
end
subgraph 通信与集成层 Integration
INTEGRATION["integrations.py<br/>客户端封装"]
MKT["MarketingClient<br/>营销 2.0 接口"]
SMS["SmsClient<br/>短信平台接口"]
YXZ["YiXieZuoClient<br/>易协作 Playwright 客户端"]
CRYPTO["vendor 目录<br/>SM2 / SM3 / SM4 / RSA"]
end
APP --> MONITOR
APP --> CFG_STORE
CFG_STORE --> CONFIG_JSON
MONITOR --> RULES
MONITOR --> STORAGE
STORAGE --> DB
MONITOR --> INTEGRATION
INTEGRATION --> MKT
INTEGRATION --> SMS
INTEGRATION --> YXZ
INTEGRATION --> CRYPTO
2. config_store.py:配置管理与持久化模块
2.1 模块定位
作为系统的集中配置管理器,负责加载、校验、合并与持久化用户配置,隔离底层文件 IO 与业务逻辑。
2.2 核心设计与技术点
- 可执行文件运行目录自适应:
通过判定sys.frozen状态识别当前运行于源码调试态还是 PyInstaller 单文件/单目录打包态:1
BASE_DIR = Path(sys.executable).resolve().parent if getattr(sys, "frozen", False) else Path(__file__).resolve().parent - 两级配置合并机制(Default Fallback):
系统维护一套硬编码的完整DEFAULT_CONFIG模板。当本地config.json缺少某项键值时(如低版本配置文件升级),通过深度递归合并策略保留默认缺省值,防止发生KeyError异常; - 敏感信息内存隔离与日志安全:
对外输出配置时提供mask_sensitive=True选项,将营销系统与短信平台的密码自动脱敏为******,防止明文配置在日志或错误弹窗中外泄; - 配置项完整性校验:
在保存前对轮询周期(poll_interval_seconds >= 10)、超时阈值(remind_before_hours >= 0.5)进行范围约束校验。
3. storage.py:本地 SQLite 数据存储与风控模块
3.1 模块定位
基于本地轻量级 SQLite 数据库,负责核心告警记录的去重判定、待发送消息持久化队列(Message Queue)以及接口连续失败锁定的防封风控。
3.2 数据库 Schema 架构
erDiagram
ticket_alerts {
TEXT ticket_id PK "工单编号"
TEXT category PK "提醒类别"
TEXT ticket_type "工单类型"
TEXT summary "摘要描述"
TEXT details_json "完整明细JSON"
TEXT created_at "创建时间"
}
delivery_queue {
INTEGER id PK "自增主键"
TEXT dedupe_key "唯一去重键"
TEXT ticket_id "关联工单号"
TEXT category "类别"
TEXT channel "发送通道: sms 或 yxz"
TEXT target_type "目标类型: 手机号_人员_群聊"
TEXT target "具体接收目标"
TEXT content "完整发送报文"
TEXT status "状态: pending 或 sent"
INTEGER attempts "重试次数"
TEXT last_error "末次异常信息"
TEXT created_at "入队时间"
TEXT updated_at "更新时间"
TEXT sent_at "成功发送时间"
}
login_guard {
TEXT system_name PK "系统代号: marketing_sms_yxz"
INTEGER failure_count "连续失败次数"
TEXT locked_until "锁定截至时间"
TEXT last_error "最后一次错误信息"
TEXT updated_at "更新时间"
}
核心数据库表结构明细
| 数据表名称 | 核心字段说明 | 索引与约束 | 业务作用 |
|---|---|---|---|
ticket_alerts |
ticket_id, category, ticket_type, summary, details_json, created_at |
联合主键 (ticket_id, category) |
记录某张工单在特定规则下是否已生成过提醒,防止同一张工单被多次重复认领。 |
delivery_queue |
id, dedupe_key, ticket_id, category, channel, target_type, target, content, status, attempts, last_error, created_at, updated_at, sent_at |
唯一约束 dedupe_key UNIQUE状态索引 idx_status |
异步投递消息队列。任何待发通知必须先持久化入队,由后台投递线程消费,保证消息不丢不重。 |
login_guard |
system_name, failure_count, locked_until, last_error, updated_at |
主键 system_name |
账号保护计数器。一旦某系统连续认证失败达阈值,自动触发熔断冷却,防止内网账号被锁定。 |
3.3 关键机制解析
- SQLite WAL 并发模式与 Busy Timeout:
为了应对 GUI 界面展示与后台轮询线程同时读写本地数据库,初始化时强制开启预写日志(WAL)模式,并将锁超时时间设置为 30 秒,彻底杜绝database is locked异常:1
2connection.execute("PRAGMA journal_mode=WAL")
connection.execute("PRAGMA busy_timeout=30000") - 精细化去重键(Dedupe Key)算法:
为避免跨模块重复发送,入队前由以下维度通过分隔符连接生成全局唯一哈希键:依赖数据库底层的1
dedupe_key = ticket_id | category | channel | target_type | targetINSERT OR IGNORE语法实现天然原子级幂等。 - 接口风控熔断机制(Login Guard):
针对营销系统账号在内网连续输错 3 次自动锁定的安全策略,系统设计了熔断保护机制:- 当
failure_count >= max_failures(默认 3 次)时,设置locked_until = now + lock_minutes(默认冷却 30 分钟); - 在冷却期未过前,跳过该接口请求,避免被动封禁生产账号。
- 当
4. integrations.py:外部系统集成与国密通信中枢
4.1 模块定位
负责与电网内网 3 套独立系统进行网络通信、身份认证、协议编解码及数据提取。
4.2 营销 2.0 系统端到端国密安全通信
营销 2.0 前后端交互全面采用了我国国家商用密码标准体系(SM2、SM3、SM4):
sequenceDiagram
autonumber
participant Client as 客户端 MarketingClient
participant SSO as 统一认证 ISC-SSO
participant EPM2 as 营销2.0系统 epm2-scp
Note over Client,SSO: 阶段一:ISC SSO 认证与 Token 获取
Client->>SSO: GET /isc_sso/login 请求登录页
SSO-->>Client: 200 OK 返回 HTML (含 hidden execution 凭证)
Note over Client: 使用 vendor/rsa.js 加密用户密码
Client->>SSO: POST /isc_sso/login 提交凭证与 RSA 密码密文
SSO-->>Client: 302 重定向 (Location 带有认证票据)
Client->>SSO: GET 跟随重定向
SSO-->>Client: 302 重定向 (返回包含 auth_token 的业务网址)
Note over Client,EPM2: 阶段二:国密加解密与业务数据交互
Note over Client: 1. 序列化 JSON 参数并 SM3 计算摘要<br/>2. SM4-CBC 加密摘要与明文<br/>3. SM2 公钥加密 SM4 密钥
Client->>EPM2: POST /getWorkOrderToDoList (附带 Token 与国密密文)
EPM2-->>Client: 200 OK 返回待办工单列表 JSON
国密加密实现函数 encrypt_payload 解析
1 | |
4.3 核心业务接口对照表
| 接口名称 | 请求方式与 URL | 核心报文参数 | 业务说明 |
|---|---|---|---|
| 待办工单查询 | POST /emss-cmnf-common-front/member/workOrderQuery/getWorkOrderToDoList |
pageNo, pageSize: 100, wkOrderType: "00", excludeType: "00" |
分页拉取该营销账号名下所有待办记录,自动循环翻页直至拉全。 |
| 通用工单详情 | GET /emss-cssrvf-cstservicesrv-front/member/csWkOrder/queryWkOrder |
signParams: encrypt_payload({"appNo": ticket_id}) |
获取标准客户服务工单详情(户号、户名、诉求、地址、联系方式)。 |
| 催办工单详情 | GET /emss-cssrvf-cstservicesrv-front/member/csOverseeWholeWkOrder/queryOverseeWholeWkOrder |
signParams, Header 注入 businessEnv |
专用于“客户电力服务催办”工单,解析提取关联主单号 sufUrgeWkOrderNo。 |
| 营配校核详情 | GET /emss-cssrvf-cstservicesrv-front/member/AcptAsgnController/infoAbnorChkInit |
signParams |
专用于“信息校核异常”工单,提取其嵌套子对象 csInfoChkVO 与 elecConsCustVO。 |
| 短信平台发送 | POST http://smsapp.zj.sgcc.com.cn/ums-webapi/msg/sendMsg |
recvId: [{bussId: phone}], content, appId: "5555", identity: "P" |
批量下发工单短信通知,返回 code == 0 代表进入运营商下发流程。 |
5. vendor 目录:加密算法与易协作自动化底层
5.1 文件构成及作用
- **
rsa.js**:由营销系统前端提取的 RSA 加密库,包含标准公钥模数计算。在 Python 中通过py_mini_racer.MiniRacer()虚拟机加载并执行getEncryptPwd(password); - **
sm2.py/sm3.py/sm4.py**:基于纯 Python 实现的国密标准算法包,提供 SM3 杂凑算法、SM4-CBC 分组密码以及 SM2 椭圆曲线加密; - **
yxz_sender.py**:基于 Playwright 的易协作桌面网页端驱动模块:- 加载 Chromium 浏览器并保持用户持久化会话目录(
.yxz_sender_profile); - 自动寻找全局搜索框、定位接收人面板、注入富文本消息框并点击“发送”按钮;
- 针对群聊发送支持屏蔽艾特(不 @ 全员)。
- 加载 Chromium 浏览器并保持用户持久化会话目录(
6. monitor.py:监控调度与规则判定引擎
6.1 模块定位
系统的调度核心大脑,负责协调定时轮询周期、工单字段标准化、三维告警规则判定以及多通道异步投递。
6.2 工单字段标准化模型(_ticket_view)
不同工单类型(常规、催办、校核)返回的 JSON 键名存在差异,_ticket_view 通过优先级回退映射为统一定义:
1 | |
6.3 三大告警评估逻辑(_evaluate)
1 | |
6.4 标准短信/易协作消息模板格式
1 | |
7. app.py:Tkinter 图形用户界面与线程驱动
7.1 模块定位
基于 Python 内置 Tkinter/ttk 开发的桌面 GUI 界面,兼顾 Win7 经典界面与 Win10/Win11 渲染,包含多选项卡管理、运行仪表盘、日志流展示与数据交互。
7.2 线程安全事件驱动模型
后台服务 ReminderEngine 在独立的守护线程(Daemon Thread)中循环运行,绝不允许直接操作 UI 组件(会导致 Tkinter 发生崩溃或无响应)。
本项目通过线程安全的 FIFO 事件队列解耦:
sequenceDiagram
autonumber
participant Engine as 后台轮询线程 ReminderEngine
participant Queue as 线程安全队列 events.Queue
participant Main as 前台GUI主线程 Tkinter
Engine->>Queue: 发送状态事件: emit("state", "服务运行中")
Engine->>Queue: 发送日志事件: emit("info", "本轮读取待办 3 条")
Note over Main: 前台定时器每 250ms 执行 _drain_events()
Main->>Queue: get_nowait() 消费事件
Queue-->>Main: 返回 level, message
Main->>Main: 追加日志文本至控制台窗口
Main->>Main: 动态刷新统计卡片与工单表格
7.3 主要选项卡职责划分
| 选项卡 | 核心组件与功能 |
|---|---|
| 运行控制台 | 服务启停大按钮、轮询倒计时进度条、当日告警数与待办总数统计卡片、实时滚动富文本日志流窗口。 |
| 基础配置 | 营销 2.0 用户名/密码输入、短信网关地址与 AppID、易协作接收人/群聊名称。 |
| 规则设定 | 全部工单开关、敏感词标签式增删面板、分类超时时限矩阵表。 |
| 历史告警 | 树状表格(Treeview)查看已识别的预警工单,支持快捷复制工单号与详情弹窗。 |
8. build_win7.ps1 与 Spec:Win7 离线打包全流程解析
8.1 打包挑战与特殊约束
基层供电所办公环境复杂,存在大量 Windows 7 64 位 SP1 专业版/旗舰版操作系统,且内网终端处于物理隔离或严格受限的无网状态:
- 挑战 1:Python 3.9+ 官方已不再支持 Windows 7;
- 挑战 2:内网环境缺乏通用 C 运行时库(Universal C Runtime, UCRT)与 Visual C++ 2015-2022 Redistributable,易出现
api-ms-win-crt-runtime-l1-1-0.dll is missing弹窗; - 挑战 3:Playwright 默认会下载最新版本 Chromium,而现代 Chromium 内核早已停止对 Win7 的支持。
8.2 关键打包技术方案
- 基准运行环境固定:
统一锁定在可在 Windows 7 上稳定运行的最高官方版本 Python 3.8.10 x64 独立虚拟环境; - UCRT 与 VC 运行库静态注入:
在打包脚本build_win7.ps1中,显式将目标系统必需的底层依赖全量复制注入至打包输出目录根部:- Universal C Runtime (
api-ms-win-*.dll共约 40 个支持库); - Microsoft Visual C++ 核心动态链接库 (
vcruntime140.dll、vcruntime140_1.dll、msvcp140.dll、msvcp140_1.dll)。
- Universal C Runtime (
- PE 二进制机器码强校验:借助
1
2
3
4
5
6def compatible(entry):
name, source, kind = entry
...
machine = pefile.PE(source, fast_load=True).FILE_HEADER.Machine
if machine != 0x8664: # 强校验 x64 架构
return Falsepefile分析所有打包进来的.dll和.pyd,直接剔除任何残留的 32 位二进制,杜绝Bad Image / 0xc000007b报错; - MiniRacer 与离线 Chromium 打包:
- MiniRacer 的
mini_racer.dll被强制绑定至打包根目录; - 内置 Win7 兼容的 Chromium 96 浏览器内核放置于
playwright/driver/package/.local-browsers,确保无网环境下易协作浏览器组件即开即用。
- MiniRacer 的
9. 实战排错与二次开发指导
9.1 常见运维故障与排查路线
- 营销 2.0 登录失败提示“账号或密码错误” / 触发风控锁定:
- 检查内网账号是否已被在其他终端连续输错锁定,确认是否处于
login_guard冷却期; - 确认
vendor/rsa.js执行是否正常,检查MiniRacer运行时是否缺失底层依赖。
- 检查内网账号是否已被在其他终端连续输错锁定,确认是否处于
- 易协作消息发送超时或失败:
- 检查当前用户是否有权向目标群聊发送消息;
- 确认
.yxz_sender_profile会话是否过期,若过期需在弹出的浏览器中重新扫码或登录一次。
- **数据库出现
database is locked**:- 确保外部没有第三方 SQLite 查看工具以独占方式打开了
reminder.db。
- 确保外部没有第三方 SQLite 查看工具以独占方式打开了
9.2 二次开发与代码扩展建议
- 新增待办工单过滤维度:
在_ticket_view中已清洗提取了address(用电地址)与customer_no(用户户号),可在monitor.py的_evaluate中扩展“重点保供电线路”、“大客户专线”、“重复报修黑名单”等自定义匹配规则; - 新增提醒通道(如企业微信、钉钉机器人、飞书 Webhook):
- 在
integrations.py中新增对应的客户端类; - 在
config_store.py的配置模板中追加 Webhook URL 配置; - 在
storage.py中直接复用delivery_queue队列,系统会自动按通道类型轮询消费并异步下发。
- 在