'phase7'
This commit is contained in:
parent
9c448ed206
commit
3aeb65233d
@ -1,5 +1,7 @@
|
||||
# autoTAPD 配置文件
|
||||
|
||||
[wework]
|
||||
agentid = 1000615
|
||||
receivers = 046364
|
||||
[TAPD]
|
||||
# TAPD项目ID
|
||||
workspace_id = 58335167
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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):
|
||||
|
||||
22
src/main.py
22
src/main.py
@ -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
147
src/wework_notifier.py
Normal 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
|
||||
38
开发路线.md
38
开发路线.md
@ -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
|
||||
- 频率控制:时间窗口、消息合并
|
||||
|
||||
**潜在问题记录:**
|
||||
- 推送频率限制
|
||||
- 消息长度限制
|
||||
- 用户未关注应用时的处理
|
||||
|
||||
---
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user