wechat_service.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import httpx
  2. from typing import Dict, Any
  3. from app.core.biz_exception import BizLogicError
  4. from app.schemas.wechat import WechatIn
  5. class WechatService:
  6. @staticmethod
  7. async def _send_webhook(api_token: str, payload: Dict[str, Any]):
  8. """
  9. 内部私有方法:发送 HTTP 请求到企业微信 Webhook
  10. """
  11. url = f"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={api_token}"
  12. try:
  13. async with httpx.AsyncClient(timeout=10) as client:
  14. response = await client.post(url, json=payload)
  15. except httpx.RequestError as e:
  16. raise BizLogicError(f"Wechat push request error: {e}")
  17. if response.status_code != 200:
  18. raise BizLogicError(f"Wechat push failed, http_status={response.status_code}")
  19. data = response.json()
  20. if data.get("errcode") != 0:
  21. raise BizLogicError(
  22. f"Wechat push failed, errcode={data.get('errcode')}, errmsg={data.get('errmsg')}"
  23. )
  24. return True
  25. @staticmethod
  26. async def push_to_wechat(payload: WechatIn):
  27. """
  28. [保留原函数兼容] 发送纯文本消息
  29. """
  30. body = {
  31. "msgtype": "text",
  32. "text": {
  33. "content": payload.message
  34. # "mentioned_mobile_list":["13800006789","@all"] # 可选:如需艾特所有人
  35. }
  36. }
  37. return await WechatService._send_webhook(payload.api_token, body)
  38. @staticmethod
  39. async def push_markdown(api_token: str, content: str):
  40. """
  41. 发送 Markdown 消息 (支持标题、加粗、链接、颜色)
  42. """
  43. body = {
  44. "msgtype": "markdown",
  45. "markdown": {
  46. "content": content
  47. }
  48. }
  49. return await WechatService._send_webhook(api_token, body)
  50. @staticmethod
  51. async def push_payment_template(api_token: str, data: Dict[str, Any]):
  52. """
  53. 专门用于发送【支付确认】的模板消息
  54. 适配之前的业务逻辑,将其转换为 Webhook 支持的 Markdown 格式
  55. Args:
  56. api_token: Webhook Key
  57. data: 包含 order_id, amount, currency, user_email, confirm_url 等字段的字典
  58. """
  59. # 1. 格式化金额
  60. amount_fen = data.get('amount', 0)
  61. amount_str = f"{amount_fen / 100:,.2f}"
  62. currency = data.get('currency', 'CNY')
  63. # 2. 构造 Markdown 内容
  64. # <font color="warning"> 红色/橙色
  65. # <font color="info"> 绿色
  66. # <font color="comment"> 灰色
  67. markdown_content = f"""**💰 新增待确认支付**
  68. > 订单号:<font color="comment">{data.get('order_id', 'N/A')}</font>
  69. > 用户:<font color="comment">{data.get('user_email', 'Unknown')}</font>
  70. > 金额:<font color="warning">{amount_str} {currency}</font>
  71. > 渠道:{data.get('provider', 'Manual')}
  72. > 时间:{data.get('time_str', '')}
  73. 请核实资金到账情况。
  74. 👉 [点击此处进行系统确认]({data.get('confirm_url')})"""
  75. return await WechatService.push_markdown(api_token, markdown_content)