fix: 账号页闪烁/浏览类型/截图复制/时区统一

This commit is contained in:
2025-12-14 11:30:49 +08:00
parent 2ec88eac3b
commit a9c8aac48f
59 changed files with 685 additions and 339 deletions

85
app.py
View File

@@ -76,6 +76,34 @@ def get_beijing_now():
"""获取北京时间的当前时间(统一时区处理)"""
return datetime.now(BEIJING_TZ)
# ========== 浏览类型规范化 ==========
# 当前页面仅保留:应读、注册前未读;默认应读
BROWSE_TYPE_SHOULD_READ = "应读"
BROWSE_TYPE_PRE_REG_UNREAD = "注册前未读"
_BROWSE_TYPES_ALLOWED_INPUT = {
BROWSE_TYPE_SHOULD_READ,
BROWSE_TYPE_PRE_REG_UNREAD,
}
def normalize_browse_type(value, default=BROWSE_TYPE_SHOULD_READ):
"""规范化浏览类型(非法值回退到默认)。"""
text = str(value or "").strip()
if text == BROWSE_TYPE_PRE_REG_UNREAD:
return BROWSE_TYPE_PRE_REG_UNREAD
if text == BROWSE_TYPE_SHOULD_READ:
return BROWSE_TYPE_SHOULD_READ
return default
def validate_browse_type(value, default=BROWSE_TYPE_SHOULD_READ):
"""校验并返回规范化浏览类型非法值返回None。"""
text = str(value if value is not None else default).strip()
if text not in _BROWSE_TYPES_ALLOWED_INPUT:
return None
return normalize_browse_type(text, default=default)
# ========== 初始化配置 ==========
config = get_config()
@@ -868,7 +896,7 @@ class Account:
self.total_items = 0
self.total_attachments = 0
self.automation = None
self.last_browse_type = "注册前未读"
self.last_browse_type = BROWSE_TYPE_SHOULD_READ
self.proxy_config = None # 保存代理配置,浏览和截图共用
@property
@@ -2678,8 +2706,10 @@ def start_account(account_id):
if account.is_running:
return jsonify({"error": "任务已在运行中"}), 400
data = request.json
browse_type = data.get('browse_type', '应读')
data = request.json or {}
browse_type = validate_browse_type(data.get('browse_type'), default=BROWSE_TYPE_SHOULD_READ)
if not browse_type:
return jsonify({"error": "浏览类型无效"}), 400
enable_screenshot = data.get('enable_screenshot', True) # 默认启用截图
# 确保浏览器管理器已初始化
@@ -3278,10 +3308,8 @@ def take_screenshot_for_account(user_id, account_id, browse_type="应读", sourc
base = f"{parsed.scheme}://{parsed.netloc}"
if '注册前' in str(browse_type):
bz = 0
elif str(browse_type) == '已读':
bz = 1
else:
bz = 2 # 应读/未读
bz = 2 # 应读
target_url = f"{base}/admin/center.aspx?bz={bz}"
automation.main_page.goto(target_url, timeout=60000)
current_url = getattr(automation.main_page, "url", "") or ""
@@ -3461,7 +3489,14 @@ def manual_screenshot(account_id):
return jsonify({"error": "任务运行中,无法截图"}), 400
data = request.json or {}
browse_type = data.get('browse_type', account.last_browse_type)
requested_browse_type = data.get('browse_type', None)
if requested_browse_type is None:
# 兼容历史遗留值:内存中的 last_browse_type 可能为旧枚举,直接规范化回退到默认(应读)
browse_type = normalize_browse_type(account.last_browse_type)
else:
browse_type = validate_browse_type(requested_browse_type, default=BROWSE_TYPE_SHOULD_READ)
if not browse_type:
return jsonify({"error": "浏览类型无效"}), 400
account.last_browse_type = browse_type
@@ -3911,10 +3946,12 @@ def get_run_stats():
# 获取今日任务统计
stats = database.get_user_run_stats(user_id)
# 计算当前正在运行的账号数
# 计算当前正在执行”的账号数(排队中的不计入)
current_running = 0
if user_id in user_accounts:
current_running = sum(1 for acc in user_accounts[user_id].values() if acc.is_running)
with task_status_lock:
for info in task_status.values():
if info.get('user_id') == user_id and info.get('status') == '运行中':
current_running += 1
return jsonify({
'today_completed': stats.get('completed', 0),
@@ -3973,8 +4010,10 @@ def update_system_config_api():
return jsonify({"error": "时间格式错误,应为 HH:MM"}), 400
if schedule_browse_type is not None:
if schedule_browse_type not in ['注册前未读', '应读', '未读']:
normalized = validate_browse_type(schedule_browse_type, default=BROWSE_TYPE_SHOULD_READ)
if not normalized:
return jsonify({"error": "浏览类型无效"}), 400
schedule_browse_type = normalized
if schedule_weekdays is not None:
# 验证星期格式,应该是逗号分隔的数字字符串 "1,2,3,4,5,6,7"
@@ -4341,7 +4380,7 @@ def run_scheduled_task(skip_weekday_check=False):
"""
try:
config = database.get_system_config()
browse_type = config.get('schedule_browse_type', '应读')
browse_type = normalize_browse_type(config.get('schedule_browse_type', BROWSE_TYPE_SHOULD_READ))
# 检查今天是否在允许执行的星期列表中(立即执行时跳过此检查)
if not skip_weekday_check:
@@ -4445,6 +4484,9 @@ def status_push_worker():
with task_status_lock:
status_items = list(task_status.items())
for account_id, status_info in status_items:
# 无任务执行时不推送;排队中的状态已通过事件推送过一次,无需周期性推送
if status_info.get('status') != '运行中':
continue
user_id = status_info.get('user_id')
if user_id:
# 获取账号对象
@@ -4618,7 +4660,7 @@ def scheduled_task_worker():
# 执行用户定时任务
user_id = schedule_config['user_id']
schedule_id = schedule_config['id']
browse_type = schedule_config.get('browse_type', '应读')
browse_type = normalize_browse_type(schedule_config.get('browse_type', BROWSE_TYPE_SHOULD_READ))
enable_screenshot = schedule_config.get('enable_screenshot', 1)
try:
@@ -5109,7 +5151,9 @@ def create_user_schedule_api():
name = data.get('name', '我的定时任务')
schedule_time = data.get('schedule_time', '08:00')
weekdays = data.get('weekdays', '1,2,3,4,5')
browse_type = data.get('browse_type', '应读')
browse_type = validate_browse_type(data.get('browse_type', BROWSE_TYPE_SHOULD_READ), default=BROWSE_TYPE_SHOULD_READ)
if not browse_type:
return jsonify({"error": "浏览类型无效"}), 400
enable_screenshot = data.get('enable_screenshot', 1)
account_ids = data.get('account_ids', [])
@@ -5170,6 +5214,11 @@ def update_schedule_api(schedule_id):
import re
if not re.match(r'^\d{2}:\d{2}$', update_data['schedule_time']):
return jsonify({"error": "时间格式不正确"}), 400
if 'browse_type' in update_data:
normalized = validate_browse_type(update_data.get('browse_type'), default=BROWSE_TYPE_SHOULD_READ)
if not normalized:
return jsonify({"error": "浏览类型无效"}), 400
update_data['browse_type'] = normalized
success = database.update_user_schedule(schedule_id, **update_data)
if success:
@@ -5232,7 +5281,7 @@ def run_schedule_now_api(schedule_id):
return jsonify({"error": "没有配置账号"}), 400
user_id = current_user.id
browse_type = schedule['browse_type']
browse_type = normalize_browse_type(schedule.get('browse_type', BROWSE_TYPE_SHOULD_READ))
enable_screenshot = schedule['enable_screenshot']
started = []
@@ -5304,10 +5353,12 @@ def delete_schedule_logs_api(schedule_id):
def batch_start_accounts():
"""批量启动账号"""
user_id = current_user.id
data = request.json
data = request.json or {}
account_ids = data.get('account_ids', [])
browse_type = data.get('browse_type', '应读')
browse_type = validate_browse_type(data.get('browse_type', BROWSE_TYPE_SHOULD_READ), default=BROWSE_TYPE_SHOULD_READ)
if not browse_type:
return jsonify({"error": "浏览类型无效"}), 400
enable_screenshot = data.get('enable_screenshot', True)
if not account_ids: