Ethscriptions commited on
Commit
e00dc2a
·
verified ·
1 Parent(s): 46057b5

Update pages/monitor.py

Browse files
Files changed (1) hide show
  1. pages/monitor.py +59 -30
pages/monitor.py CHANGED
@@ -5,13 +5,17 @@ import json
5
  import os
6
  import threading
7
  import re
 
8
  from datetime import datetime, timedelta, timezone, time as dt_time
9
  from collections import deque
10
  from dotenv import load_dotenv
11
 
12
- # --- 0. 必须最先执行 ---
13
  st.set_page_config(page_title="影城防撤场监控系统", page_icon="🛡️", layout="wide")
14
 
 
 
 
15
  # 尝试导入自动刷新组件
16
  try:
17
  from streamlit_autorefresh import st_autorefresh
@@ -84,7 +88,7 @@ def simplify_hall_name(raw_name):
84
  return raw_name
85
 
86
 
87
- # --- 3. 微信推送模块 ---
88
  class WeChatPusher:
89
  def __init__(self, app_id, app_secret):
90
  self.app_id = app_id
@@ -92,9 +96,11 @@ class WeChatPusher:
92
  self.token = None
93
  self.token_expires_time = 0
94
 
95
- def get_access_token(self):
96
- """获取并缓存微信 Access Token"""
97
- if self.token and datetime.now().timestamp() < self.token_expires_time:
 
 
98
  return self.token
99
 
100
  if not self.app_id or not self.app_secret:
@@ -116,42 +122,64 @@ class WeChatPusher:
116
  return None
117
 
118
  def send_template_message(self, user_ids, template_id, data_map):
119
- """发送模板消息给多个用户"""
120
- token = self.get_access_token()
121
- if not token:
122
- return False
123
-
124
- url = f"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={token}"
125
 
126
  # 组装微信数据格式
127
  formatted_data = {}
128
  for key, value in data_map.items():
129
- # 默认深蓝色
130
  formatted_data[key] = {"value": value, "color": "#173177"}
131
 
132
  # 清洗 user_ids
133
  valid_ids = [uid.strip() for uid in user_ids if uid and uid.strip()]
134
- success_flag = True
 
 
 
 
135
 
136
  for user_id in valid_ids:
137
- payload = {
138
- "touser": user_id,
139
- "template_id": template_id,
140
- "data": formatted_data
141
- }
142
- try:
143
- resp = requests.post(url, json=payload, timeout=10)
144
- result = resp.json()
145
- if result.get("errcode") != 0:
146
- print(f"❌ 微信发送失败 [{user_id}]: {result}")
147
- success_flag = False
148
- else:
149
- print(f" 微信发送成功 [{user_id}]")
150
- except Exception as e:
151
- print(f"❌ 微信发送异常 [{user_id}]: {e}")
152
- success_flag = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
- return success_flag
155
 
156
 
157
  # --- 4. API 管理模块 ---
@@ -323,6 +351,7 @@ class CinemaMonitor:
323
  "keyword4": f"{ticket_count} 张",
324
  "remark": "\n请尽快处理。"
325
  }
 
326
  if not self.wx_pusher.send_template_message(WX_USER_OPEN_IDS, WX_TEMPLATE_ID_TICKET, data):
327
  self.stats["notify_fails"] += 1
328
 
 
5
  import os
6
  import threading
7
  import re
8
+ import urllib3
9
  from datetime import datetime, timedelta, timezone, time as dt_time
10
  from collections import deque
11
  from dotenv import load_dotenv
12
 
13
+ # --- 0. 基础配置 ---
14
  st.set_page_config(page_title="影城防撤场监控系统", page_icon="🛡️", layout="wide")
15
 
16
+ # 屏蔽 HTTPS 证书警告
17
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
18
+
19
  # 尝试导入自动刷新组件
20
  try:
21
  from streamlit_autorefresh import st_autorefresh
 
88
  return raw_name
89
 
90
 
91
+ # --- 3. 微信推送模块 (含自动重试) ---
92
  class WeChatPusher:
93
  def __init__(self, app_id, app_secret):
94
  self.app_id = app_id
 
96
  self.token = None
97
  self.token_expires_time = 0
98
 
99
+ def get_access_token(self, force_refresh=False):
100
+ """获取并缓存微信 Access Token
101
+ :param force_refresh: 是否强制刷新 Token
102
+ """
103
+ if not force_refresh and self.token and datetime.now().timestamp() < self.token_expires_time:
104
  return self.token
105
 
106
  if not self.app_id or not self.app_secret:
 
122
  return None
123
 
124
  def send_template_message(self, user_ids, template_id, data_map):
125
+ """发送模板消息给多个用户 (带 40001 错误重试机制)"""
 
 
 
 
 
126
 
127
  # 组装微信数据格式
128
  formatted_data = {}
129
  for key, value in data_map.items():
 
130
  formatted_data[key] = {"value": value, "color": "#173177"}
131
 
132
  # 清洗 user_ids
133
  valid_ids = [uid.strip() for uid in user_ids if uid and uid.strip()]
134
+
135
+ if not valid_ids:
136
+ return False
137
+
138
+ success_any = False
139
 
140
  for user_id in valid_ids:
141
+ # 每个用户最多尝试 2 次(1次正常,1次刷新 Token 后重试)
142
+ for attempt in range(2):
143
+ # 如果是重试(attempt > 0),强制刷新 Token
144
+ token = self.get_access_token(force_refresh=(attempt > 0))
145
+
146
+ if not token:
147
+ break # Token 都拿不到,不用重试了
148
+
149
+ url = f"https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={token}"
150
+ payload = {
151
+ "touser": user_id,
152
+ "template_id": template_id,
153
+ "data": formatted_data
154
+ }
155
+
156
+ try:
157
+ resp = requests.post(url, json=payload, timeout=10)
158
+ result = resp.json()
159
+ errcode = result.get("errcode")
160
+
161
+ if errcode == 0:
162
+ # 发送成功
163
+ # print(f"✅ 微信发送成功 [{user_id}]")
164
+ success_any = True
165
+ break # 跳出重试循环,处理下一个用户
166
+
167
+ # 40001: Token 无效
168
+ # 40014: Token 不合法
169
+ # 42001: Token 过期
170
+ elif errcode in [40001, 40014, 42001]:
171
+ print(f"🔄 微信 Token 失效 ({errcode}),正在刷新重试 [{user_id}]...")
172
+ continue # 进入下一次循环,强制刷新 Token
173
+
174
+ else:
175
+ print(f"❌ 微信发送失败 [{user_id}]: {result}")
176
+ break # 其他错误,不重试
177
+
178
+ except Exception as e:
179
+ print(f"❌ 微信发送异常 [{user_id}]: {e}")
180
+ break
181
 
182
+ return success_any
183
 
184
 
185
  # --- 4. API 管理模块 ---
 
351
  "keyword4": f"{ticket_count} 张",
352
  "remark": "\n请尽快处理。"
353
  }
354
+ # 如果所有用户发送都失败才算失败
355
  if not self.wx_pusher.send_template_message(WX_USER_OPEN_IDS, WX_TEMPLATE_ID_TICKET, data):
356
  self.stats["notify_fails"] += 1
357