This commit is contained in:
zelong 2025-12-24 19:41:56 +08:00
parent 9c448ed206
commit 3aeb65233d
6 changed files with 227 additions and 18 deletions

View File

@ -1,5 +1,7 @@
# autoTAPD 配置文件
[wework]
agentid = 1000615
receivers = 046364
[TAPD]
# TAPD项目ID
workspace_id = 58335167

View File

@ -1,4 +1,4 @@
{
"access_token": "CH7CGXX75TWdZ-Bge7VmA2KNDc4d4ujSgTzVvUNwUIgj9DJjLY97BlJzjDSLowblIUQP1F1XMLivWGIb8i07FBhczNoNSUM8C8b5AdLEWvpe1vHvMy2gjI9EnhjFoQ3a_7iTxzt4VIK07IduDlEFAM7O14ZGoGrwE13qIxlttf-vcuk4eF3IZiOs0dPLz5fwWzmLccBl8a1_c-J_weTQ4QS8TZaghmGyRHSEPYbJLiM",
"fetch_time": 1766129638.0076234
"access_token": "t7JYQBuy7p3Wg_hRj6xSchih9NRzuactFsxY7U3CMJG3Tkt5cm-BUvO0-e74oMUbZG5s4ouahAdB-AHT2eSljlrD1YzjOnxAvzbOjBFrGT-yEArT9fU6mli8uhBmBk7BteKfHZStZ7d3cs1bGSTnjkNS5vVpyxUu4gcLT8Ya1S9DcMdCBrKnBwmLDcoI2_TkLvKhW67b_zo2EVa0erZhHlL2klT0ajyVhwfB0aeXhF8",
"fetch_time": 1766572400.099746
}

View File

@ -158,6 +158,33 @@ class ConfigManager:
'sync_interval': sync_interval
}
def get_wework_config(self):
"""
获取企业微信配置
Returns:
dict: 包含agentid和receivers的字典如果配置不存在则返回空字典
"""
# 如果没有wework节返回空字典
if not self.config.has_section('wework'):
return {}
result = {}
# 读取agentid配置可选
if self.config.has_option('wework', 'agentid'):
agentid = self.config.get('wework', 'agentid').strip()
if agentid:
result['agentid'] = agentid
# 读取receivers配置可选
if self.config.has_option('wework', 'receivers'):
receivers = self.config.get('wework', 'receivers').strip()
if receivers:
result['receivers'] = receivers
return result
def get_all_config(self):
"""
获取所有配置
@ -168,7 +195,8 @@ class ConfigManager:
return {
'tapd': self.get_tapd_config(),
'smartsheet': self.get_smartsheet_config(),
'schedule': self.get_schedule_config()
'schedule': self.get_schedule_config(),
'wework': self.get_wework_config()
}
def print_config(self):

View File

@ -19,6 +19,7 @@ from src.tapd_api import TAPDApi
from src.mapper import FieldMapper, BugCreationResult
from src.token_manager import TokenManager
from src.status_mapper import BugStatusMapper
from src.wework_notifier import WeWorkNotifier
def parse_arguments():
@ -582,6 +583,27 @@ def run_once(config_manager: ConfigManager, access_token: str, verbose: bool = F
# 更新统计信息
result['writeback_success'] = writeback_result.get('success_count', 0) + writeback_result.get('failed_count', 0)
# 6. 发送企业微信推送通知(仅当有校验失败的记录时)
if len(validation_result['invalid_records']) > 0:
print("\n" + "=" * 60)
print("发送企业微信推送通知")
print("=" * 60)
try:
# 从配置文件读取企业微信推送配置
wework_config = all_config.get('wework', {})
agentid = wework_config.get('agentid')
receivers = wework_config.get('receivers')
if agentid and receivers:
notifier = WeWorkNotifier(access_token, agentid, receivers)
notifier.send_validation_failure_notification(validation_result['invalid_records'])
else:
print(" ⚠ 企业微信推送配置不完整,跳过推送")
print(" 请在config.ini的[wework]节中配置agentid和receivers")
except Exception as e:
print(f" ✗ 企业微信推送失败: {e}")
# 推送失败不影响主流程,继续执行
# 显示最终统计
print("\n" + "=" * 60)
print("执行完成")

147
src/wework_notifier.py Normal file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
企业微信消息推送模块
用于发送开单失败通知
"""
import requests
from typing import List, Dict
from datetime import datetime
class WeWorkNotifier:
"""企业微信消息推送类"""
def __init__(self, access_token: str, agentid: str, receivers: str):
"""
初始化企业微信消息推送器
Args:
access_token: 企业微信access_token
agentid: 应用ID
receivers: 接收人列表用户ID多个用|分隔@all表示全部成员
"""
self.access_token = access_token
self.agentid = agentid
self.receivers = receivers
self.base_url = "https://qyapi.weixin.qq.com/cgi-bin"
def send_validation_failure_notification(self, invalid_records: List[Dict]) -> bool:
"""
发送校验失败通知
Args:
invalid_records: 校验失败的记录列表每条记录包含
- record_data: 记录数据包含标题等信息
- missing_fields: 缺失的字段列表
Returns:
bool: 是否发送成功
"""
if not invalid_records:
return True
# 构造消息内容
content = self._build_failure_message(invalid_records)
# 发送消息
return self._send_text_message(content)
def _build_failure_message(self, invalid_records: List[Dict]) -> str:
"""
构造校验失败消息内容
Args:
invalid_records: 校验失败的记录列表
Returns:
str: 格式化的消息内容
"""
# 消息头部
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
lines = [
"【autoTAPD 开单失败通知】",
f"时间: {timestamp}",
f"失败数量: {len(invalid_records)}",
"",
"以下记录校验失败,请检查并补充缺失字段:",
"=" * 40
]
# 添加每条失败记录的详情
for idx, invalid_record in enumerate(invalid_records, 1):
record_data = invalid_record['record_data']
missing_fields = invalid_record['missing_fields']
# 获取记录标题(如果有)
title = record_data.get('标题', '(无标题)')
record_id = record_data.get('record_id', '未知')
lines.append(f"\n[{idx}] {title}")
lines.append(f"记录ID: {record_id}")
lines.append(f"缺失字段: {', '.join(missing_fields)}")
# 显示已有的字段值(用于参考)
available_fields = []
for field_name in ['标题', '详细描述', '优先级', '严重程度', '处理人', '验证人', '发现版本', '模块']:
if field_name not in missing_fields and record_data.get(field_name):
value = record_data.get(field_name)
# 截断过长的值
if isinstance(value, str) and len(value) > 20:
value = value[:20] + "..."
available_fields.append(f"{field_name}: {value}")
if available_fields:
lines.append(f"已有字段: {', '.join(available_fields[:3])}") # 只显示前3个
lines.append("")
lines.append("=" * 40)
lines.append("请前往智能表格补充缺失字段后,系统将自动重新开单。")
return "\n".join(lines)
def _send_text_message(self, content: str) -> bool:
"""
发送文本消息
Args:
content: 消息内容
Returns:
bool: 是否发送成功
"""
url = f"{self.base_url}/message/send"
params = {"access_token": self.access_token}
# 构造请求体
data = {
"touser": self.receivers,
"msgtype": "text",
"agentid": int(self.agentid),
"text": {
"content": content
},
"safe": 0,
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
try:
response = requests.post(url, params=params, json=data, timeout=10)
response_data = response.json()
# 检查返回结果
if response_data.get("errcode") == 0:
print(f" ✓ 企业微信消息发送成功")
return True
else:
print(f" ✗ 企业微信消息发送失败")
print(f" 错误码: {response_data.get('errcode')}")
print(f" 错误信息: {response_data.get('errmsg')}")
return False
except Exception as e:
print(f" ✗ 企业微信消息发送异常: {str(e)}")
return False

View File

@ -553,12 +553,12 @@
- 智能表格更新失败的处理
**验收标准:**
- [ ] 能正确查询已开单的记录
- [ ] 能正确过滤"完成"和"取消"状态的记录
- [ ] 能成功调用TAPD API获取bug状态
- [ ] 状态变化时能正确回写到智能表格
- [ ] 状态未变化时不进行更新减少API调用
- [ ] 能按配置的频率执行状态同步
- [x] 能正确查询已开单的记录
- [x] 能正确过滤"完成"和"取消"状态的记录
- [x] 能成功调用TAPD API获取bug状态
- [x] 状态变化时能正确回写到智能表格
- [x] 状态未变化时不进行更新减少API调用
- [x] 能按配置的频率执行状态同步
- [ ] 有清晰的同步统计信息检查X条更新Y条
**技术要点:**
@ -578,13 +578,25 @@
**目标:** 实现开单失败时的企业微信推送通知
**实现方式**:使用企微自带的消息推送功能。
假设webhook是https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa
以下是用curl工具往群组推送文本消息的示例注意要将url替换成你的消息推送webhook地址content必须是utf8编码
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=693axxx6-7aoc-4bc4-97a0-0ec2sifa5aaa' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype": "text",
"text": {
"content": "hello world"
}
}'
**任务清单:**
1. 实现企业微信消息推送API
- 调用发送应用消息接口
- 构造消息内容
2. 实现推送对象配置
- 配置接收推送的人员列表
- 支持按部门推送
1. 配置文件新增webhook地址
2. 实现开单失败时调用推送功能
3. 实现推送内容设计
- 失败原因
- 失败的记录信息
@ -606,13 +618,11 @@
**技术要点:**
- 企业微信消息推送API
- 消息格式文本、markdown等
- 推送对象userid、部门ID
- 频率控制:时间窗口、消息合并
**潜在问题记录:**
- 推送频率限制
- 消息长度限制
- 用户未关注应用时的处理
---