From 6d46e70afad42879d4307b2f61bdb0a3162ec44d Mon Sep 17 00:00:00 2001
From: ui-beam-9
Date: Mon, 21 Apr 2025 13:40:20 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E9=A1=B9=E7=9B=AE?=
=?UTF-8?q?=EF=BC=9A=E7=BD=91=E6=98=93=E5=A4=A7=E7=A5=9E=E5=AE=9E=E6=97=B6?=
=?UTF-8?q?=E5=AE=A1=E6=A0=B8=E6=95=B0=E6=8D=AE=E7=9B=91=E6=8E=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 17 -
VERSION.txt | 1 -
breeze_monitor.py | 1123 +++++++++-
breeze_monitor_CHAT.py | 123 --
cms_monitor.py | 690 ++++++-
dashboard.py | 1838 ++++++++++++++++-
...ad_auto_run.py => download_auto_run_dev.py | 159 +-
inspect_monitor.py | 123 --
install_dependencies.bat | 11 +-
templates/dashboard.html | 722 ++-----
templates/login.html | 342 ++-
11 files changed, 3805 insertions(+), 1344 deletions(-)
delete mode 100644 README.md
delete mode 100644 VERSION.txt
delete mode 100644 breeze_monitor_CHAT.py
rename download_auto_run.py => download_auto_run_dev.py (69%)
delete mode 100644 inspect_monitor.py
diff --git a/README.md b/README.md
deleted file mode 100644
index 7558953..0000000
--- a/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# 网易大神实时审核数据监控
-
-## 项目结构
-- releases/: 发布版本
- - latest/: 最新稳定版本
- - v[版本号]/: 历史版本
-- dev/: 开发版本
- - latest/: 最新开发版本
- - v[版本号]-dev/: 历史开发版本
-- config/: 配置文件目录
-
-## 版本管理
-- main分支:稳定发布版本
-- dev分支:开发版本
-
-## 自动运行
-使用 `download_auto_run.py` 脚本拉取并启动最新版本
\ No newline at end of file
diff --git a/VERSION.txt b/VERSION.txt
deleted file mode 100644
index 6d31a5d..0000000
--- a/VERSION.txt
+++ /dev/null
@@ -1 +0,0 @@
-v20250414155609
\ No newline at end of file
diff --git a/breeze_monitor.py b/breeze_monitor.py
index 74d2d4c..64c8a93 100644
--- a/breeze_monitor.py
+++ b/breeze_monitor.py
@@ -1,123 +1,1022 @@
# -*- coding: utf-8 -*-
-import base64,zlib,sys,os,getpass,json,time,random
-from urllib import request as _req
-import threading,importlib,subprocess
+import requests
+import time
+import json
+from datetime import datetime, timedelta
+import logging
+import os
+import sys
+import threading
+from threading import Lock
+import re
+import subprocess
-def _TnMzqipXoWNK(d,k):
- return bytes(a^b for a,b in zip(d,k*(len(d)//len(k)+1)))
+# 配置日志
+def setup_logging():
+ try:
+ # 获取当前脚本所在目录
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ log_file = os.path.join(script_dir, 'breeze_monitor.log')
+
+ # 确保日志文件存在
+ if not os.path.exists(log_file):
+ with open(log_file, 'w', encoding='utf-8') as f:
+ f.write('')
+
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler(log_file, encoding='utf-8', mode='a'),
+ logging.StreamHandler()
+ ]
+ )
+ logging.info("Breeze监控日志系统初始化成功")
+ except Exception as e:
+ print(f"日志系统初始化失败: {str(e)}")
+ # 如果文件日志失败,至少使用控制台日志
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[logging.StreamHandler()]
+ )
-def _t7RzY7Aq4(t,m,is_error=False):
- try:
- try:
- from playsound import playsound
- except ImportError:
- subprocess.check_call([sys.executable,"-m","pip","install","playsound==1.2.2"],
- stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
- from playsound import playsound
-
- # 播放系统声音
- try:
- import winsound
- sound_type = winsound.MB_ICONERROR if is_error else winsound.MB_ICONINFORMATION
- winsound.MessageBeep(sound_type)
- except:
- print("\a") # 备用蜂鸣声
-
- # 在控制台打印消息
- print("\n" + "="*50)
- print(f"{t}: {m}")
- print("="*50 + "\n")
-
- return True
- except Exception as e:
- print(f"\n{t}: {m} (提示音播放失败: {str(e)})\n")
- return False
+# 初始化日志系统
+setup_logging()
-def _vgZ4DAeqFt8(t,m,e=0):
- _t7RzY7Aq4(t,m,e==1)
+# API配置
+API_BASE_URL = 'https://breeze.gameyw.netease.com/api/cms/issue/list'
-def _HjXSwuCsz():
- _p=[104,116,116,112,58,47,47,99,111,115,46,117,105,45,98,101,97,109,46,99,111,109,47,119,111,114,107,95,115,99,114,105,112,116,115,47,109,111,110,105,116,111,114,47,99,111,110,102,105,103,47,115,116,97,102,102,46,106,115,111,110]
- return ''.join([chr(int(c)) for c in _p])
+# 默认的各类工单的折算系数
+DEFAULT_COEFFICIENTS = {
+ 'NTES_GOD_IMAGES': 0.54, # 网易大神APP图片
+ 'NTES_GOD_VIDEOS': 3.8, # 网易大神APP视频
+ 'NTES_GOD_CHAT_IMAGES': 0.54, # 网易大神APP聊天图片
+ 'NTES_GOD_CHAT_VIDEOS': 3.8, # 网易大神APP聊天视频
+ 'NTES_DASONG': 139.19, # 大神大宋视频
+ 'SPIDER_VIDEO': 3.8, # 大神普通供给视频
+ 'SPIDER_VIDEO_SP': 13.3, # 大神高优供给视频
+ 'NTES_GOD_AI': 0.54, # 大神AI图片
+ 'NTES_GOD_TOP': 3.8, # 大神短视频
+ 'T_SPIDER_VIDEO': 3.8, # 大神tiktok普通视频
+ 'T_SPIDER_VIDEO_SP': 13.3, # 大神tiktok高优视频
+ 'V_SPIDER_VIDEO': 3.8, # 大神ins普通供给视频
+ 'V_SPIDER_VIDEO_SP': 13.3, # 大神ins高优供给视频
+ 'NTES_GOD_XHS': 0.54, # 大神小红书图片
+ 'XHS_SPIDER_VIDEO': 3.8, # 小红书供给视频
+ 'Cupid': 0.54, # 大神交友
+ 'CHAT_P2P': 0.55, # 大神聊天/风险用户_私聊/私聊频繁
+ 'CHAT_TEAM': 0.55, # 大神聊天/风险用户_群聊/群聊频繁
+ 'CHAT_ROOM': 0.55, # 大神聊天_聊天室
+ 'CHAT_ROOM_MSG': 0.55 # 风险用户_聊天室频繁
+}
-def _rQtAIc46():
- _e=[38750,25480,26435,29992,25143,65292,26080,26435,35775,38382]
- return ''.join([chr(int(c)) for c in _e])
+# 系数配置文件路径
+COEFFICIENTS_CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'breeze_coefficients.json')
-def _Vh6AC8aM():
- _e=[31243,24207,26080,27861,21551,21160,58,32]
- return ''.join([chr(int(c)) for c in _e])
+# 全局变量
+user_credentials = {
+ 'cookie': None,
+ 'username': None
+}
+credentials_lock = Lock()
+coefficients_lock = Lock()
-def _eveMXRYK():
- _e=[39564,35777,25104,21151,65292,27426,36814,20351,29992]
- return ''.join([chr(int(c)) for c in _e])
+# 定义全局系数变量
+COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
-def _jxLIMnM0bf():
- try:
- _lfnTd3xE=getpass.getuser().upper()
- _sLdSiJFn=os.path.basename(os.path.expanduser("~")).upper()
-
- # 转换为小写进行比较
- _trMcjKLs=_lfnTd3xE.lower()
-
- _bnYtbb3=None
- _ndNNkcla=_HjXSwuCsz()
-
- _s,_p,_v=random.randint(1,5),random.randint(1,5),int(time.time())
- try:
- _h={"User-Agent":"Mozilla/5.0","X-Access-Token":str(_s*_p*_v)}
- _r=_req.Request(_ndNNkcla,headers=_h)
- with _req.urlopen(_r,timeout=5) as _resp:
- _mVAYGFB=_resp.read().decode()
- _bnYtbb3=json.loads(_mVAYGFB)
- except:pass
-
- if not _bnYtbb3:
- try:
- _mVAYGFB=base64.b64decode("eyJPRDAyMzMiOiLosKLmloflvLoiLCJPRDAyNzIiOiLosK/lkJsiLCJPRDAyNjkiOiLnjovljJfpnZIiLCJPRDAzMDQiOiLpgpPlu7rlt50iLCJPRDAyOTUiOiLlkajpmLMiLCJPRDAyNDciOiLlkJHlqbciLCJPRDAyNDgiOiLog6HlloYiLCJPRDA0MTIiOiLokrLmmZPpmr0iLCJPRDA0MzYiOiLlvKDlvLoiLCJPRDA3NjUiOiLmnLTljprlhbAiLCJXQjAxMjIwIjoi6ZmI5a6X6ICAIiwiV0IwMjE2MCI6IumZiOedvyIsIldCMDIxNjMiOiLojIPmlofpkasiLCJPRDA0ODMiOiLlkajlpKfmtbciLCJPRDAwODAiOiLmlofmh78iLCJPRDAyMTIiOiLmmJPmmL7lnaQiLCJXQjAyNzI5Ijoi5Y+25rSL5YipIiwiV0IwMzAxMyI6IuWRqOiLseadsCIsIldCMDMwOTkiOiLmnY7mmI7mnbAiLCJXQjAzMDk0Ijoi5YiY5bu65Zu9IiwiV0IwNDE2MCI6Iuiigee6ouS4vSIsIldCMDQxNTkiOiLnjovpn6wifQ==").decode()
- _bnYtbb3=json.loads(_mVAYGFB)
- except:pass
-
- _ct7GbM1aX=False
-
- if _bnYtbb3:
- for _id,_n in _bnYtbb3.items():
- # 转换ID为小写进行比较
- _efs7U9k=_id.lower()
+# 读取系数配置
+def load_coefficients():
+ """从配置文件读取系数,如果文件不存在则创建默认配置"""
+ global COEFFICIENTS
+ try:
+ with coefficients_lock:
+ if os.path.exists(COEFFICIENTS_CONFIG_FILE):
+ with open(COEFFICIENTS_CONFIG_FILE, 'r', encoding='utf-8') as f:
+ loaded_coefficients = json.load(f)
+ log(f"从配置文件加载系数: {str(loaded_coefficients)}")
+ # 更新系数
+ COEFFICIENTS.update(loaded_coefficients)
+ else:
+ # 创建默认配置文件
+ with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
+ json.dump(DEFAULT_COEFFICIENTS, f, indent=4, ensure_ascii=False)
+ log("创建默认系数配置文件")
+ COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
+
+ log(f"当前使用的系数已更新")
+ except Exception as e:
+ log(f"加载系数配置失败: {str(e)}")
+ # 出错时使用默认系数
+ COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
+
+# 保存系数配置
+def save_coefficients(coefficients=None):
+ """保存系数到配置文件"""
+ try:
+ if coefficients is None:
+ coefficients = COEFFICIENTS
+
+ with coefficients_lock:
+ with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
+ json.dump(coefficients, f, indent=4, ensure_ascii=False)
+ log(f"系数配置已保存")
+ except Exception as e:
+ log(f"保存系数配置失败: {str(e)}")
+
+# 初始化用户凭据(从环境变量读取)
+def init_credentials():
+ """从环境变量初始化用户凭据"""
+ try:
+ cookie = os.environ.get('BREEZE_COOKIE', '')
+ username = os.environ.get('BREEZE_USERNAME', '')
+
+ if cookie and username:
+ with credentials_lock:
+ user_credentials['cookie'] = cookie
+ user_credentials['username'] = username
+ log(f"已从环境变量加载用户凭据: {username}")
+ return True
+ else:
+ log(f"未能从环境变量获取用户凭据,BREEZE_COOKIE长度: {len(cookie)}, BREEZE_USERNAME: {username}")
+ return False
+ except Exception as e:
+ log(f"初始化用户凭据失败: {str(e)}")
+ return False
+
+def get_api_headers(cookie):
+ """获取API请求头"""
+ return {
+ 'accept': 'application/json, text/plain, */*',
+ 'accept-language': 'zh-CN,zh;q=0.9',
+ 'cookie': cookie,
+ 'priority': 'u=1, i',
+ 'referer': 'https://breeze.opd.netease.com/',
+ 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
+ 'sec-ch-ua-mobile': '?0',
+ 'sec-ch-ua-platform': '"Windows"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-site',
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
+ }
+
+def log(message, level='info'):
+ """记录日志"""
+ try:
+ if level == 'warning':
+ logging.warning(f"[Breeze] {message}")
+ elif level == 'error':
+ logging.error(f"[Breeze] {message}")
+ else:
+ logging.info(f"[Breeze] {message}")
+ except Exception as e:
+ print(f"日志记录失败: {str(e)}")
+ print(f"原始消息: {message}")
+
+def is_image_url(url):
+ """判断URL是否指向图片"""
+ if not url:
+ return False
+
+ # 图片文件格式检查
+ image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.heif', '.heic']
+ if any(ext in url.lower() for ext in image_extensions):
+ return True
+
+ # 图片服务链接检查
+ image_patterns = [
+ 'fp.ps.netease.com',
+ 'cc.fp.ps.netease.com',
+ 'nos.netease.com',
+ 'imageView' # 特殊参数标记为图片
+ ]
- # 不区分大小写的比较
- if (_trMcjKLs==_efs7U9k or
- _sLdSiJFn.lower()==_efs7U9k or
- _trMcjKLs.startswith(_efs7U9k) or
- _sLdSiJFn.lower().startswith(_efs7U9k) or
- _efs7U9k in _trMcjKLs or
- _efs7U9k in _sLdSiJFn.lower()):
- _ct7GbM1aX=True
- break
-
- if not _ct7GbM1aX:
- _AIfSoxUx3=_rQtAIc46()
- _vgZ4DAeqFt8("访问被拒绝",_AIfSoxUx3,1)
- return False
-
- return True
- except:
- return False
+ return any(pattern in url.lower() for pattern in image_patterns)
-if _jxLIMnM0bf():
- # 显示验证成功消息
- _vgZ4DAeqFt8("用户验证",_eveMXRYK(),0)
-
- _k=b'D\x0edTK\xe9\x10\xc4\x1c^8VG\xb4huRP@s4VO4na@vnlJIBz2?gP2Teo|lRWM<|6Q!%@xrD5DH-IEt5?5+5L;S`E=r3E4d=+W0D13F+(4gJ2P%bgl9~bYBB4DG97XwE#>bR$v))Nmg{O;}>h)HoH>YP&LYbfxcRPyi08blqYOqqE7@o<;TB}s^J@3@*8mwa@ok!xT&L`Sd(!RiogwT8>F<$I&PLg%OFh46M0<^Zzmz+OL=1U%6JhIWtWv+(w{sQ+2lC`OBio>KIUr+VGwr(08o$kGDT9b=i>112Y+f774SheHTht<*7tjz{NY_0WFdC$s&y7kUXW)`2W0aij+iX~Vx(kNZX~;=ZOF4r-D1gjzD1GOM^!SE2i}60@A1>eW3A)z#Ug1GbvN=nKs7As3y}mAeTzZuBioCUf4_o8Zj?i)bg6-2^-$QHPs4J)^_GW&HA&uCbKVeNDo;rq_A83PC)+;lh{$6hwve`M>`y7Jc>E2Y;$QSDqJFu<&5*b-)T45l_umiO?`)p%6HO1HowFXL82c1B(EWV;`9!ke9`?1srbp!3FVDxAP+kD#<}19Y&`lE&T(P61Ei>|Mo1%AtTi66XhFtt`-5D8{Mxqb&Z7l8USCxfHr-;!(oMAi8<@iQ+6N>)Iq`BfAqKu&UQHk9BDW$$?HmDzZ;5J`NY>wJQ*eMn!O!scLNyJI%`2D_WA!28a0hw^0+mTrFiAp-!&SbKyG9c@ZO(VXP124z=r1~KP1#*_k6bsMGh>Pqe{v-(?2^wkw&0+?*Anh*OR+K`W7t6x__bJZN$BcRRI|7OzszxxL(L4lC+?EF9*p_Dls|6y8u;W>Y~+#-LZXQvJ%1Bde6FA$hOEA8YVcMKT#GzQJr)M=wqW7%)rkqCE^xo%O(RZ5^5InueV^J}wI@1pax=)3XF?0g@$j_8;Wt+rA9D_?xm;y4m3`?#kt{cQVrg{wE3wufPIs3uBk)T>mKq7h;+1)_h^&fSu-i-eiFT9V5t2^o63h9c06~LXDlr`Jrb6*E;=kBN%MvG~R)`L^S?}2GWj?ZZM%ue5Zfsb~A-1_apn{2co}Kw`E!_1g;zA=G<-k07v0Fh2zI>aC&z%r}UZdnXXzQn8=u#smkkV5e?x65F_E6ycWdFd=B!GPBg&Zelb+aWs$4hrZgv{SIZ4Q#JWgeB|u^ALj*3}mfliC*03^sA~adq+%xqE1Dv2Lh4F1!Di0#94#u}Ihx{TSP&v~kOO=Rm76soAF~u{{C#F2k8L6m_H`GEE1FuC6Af!eqHN-VCe&D{h&!oq&`-zqgSnofmEfLgateCWd^g#2aS$3}3{AFsGk{S1ux_>r4tB4jX5T(Z7dr(pMQeCxY}_jN`{buynnm%)g^xIg?8d@bSOVD&(3uN5c&%^8tq1EHqM9BR8UiBd+e+Y%9Y6f&e9C8_JbM=@J|LkY01?VDEwW;XMkb7v-W}Yd-FYxKW8Pd$lz=K{63}Z9QX%XV00D_XZ{oJ0V_EK`9qBITNQFjfL+1F2h5j(#5P27vi?x3>c9TqMlzzA04Zjf@>_)s9?MjTijM&RlD8It^fyxiXE_LUUu#udEsMN=EDqP%%5yI2%G=hl$KXZzB>F0=Rnq1CuQl6xkYdAdEL6Q~y&8%_FC}mD>9VVg6w+$$Ko(kx%MNquRuYca6lOqMuTh~3qj&@ruJY}?|fU|Ws276DpPI#K)VVmi%oqR)4(Xo@^2u)ifPO-rytXHade)Hrq-qvFoXOA?J37$>c{x>`-ItcWo{`4s1#U)uSurl%}FzbXQslx7xH{YH_tU3{?{S@f#@o9dTCOS6HAD#ND_mQ$}fpRKzVz3}R5&*)beL#F<*muwq{wNC{vR-R>!3|LM-F~T2t5}=+imcVkecl2Snq0Z$?hr8*lEY9PPD;Oo6J-~q-E}I5b$o;27-g>L)B(EpaS$Z$>OkD=8^fCQEsVcf0-He0?aG%yD$*U3-PNd8QJT3H1)oa$>}gyVM}B<)i(qhnOA=4F!>>1|-F)Uvx7twJ!V~66^${~%Ps=Y|k!|~ZlM$w@mr(ARF?$4>PaxUi`X64%X8~*Iv0q?$mR(loDFgikq)v;6w0Wjmm~E*|FJYa_Uwm(wbhoLWOb`>yPBUVF!`9lAh7^C$s&wTc4M@Ag&NKdnV(*#)}2YHtQ6_x7YQJo*5A_DJRm!U51N!{DwdoKRYZ$1jGHJX;Q=+w&N9c>MKsPORz^XGHIPVyNz#i0P=XQmAeqH2SOrsjcMeA$+QtL`i|nZR9Yozi3s7bt5&rIz}DS-5ng(6VDz*_BInbK-xM^D?DV)FOqrK?9OJGLFV_VkvWMjLI=oh=IVg~!58LCXTv-5UmqW6Z>)GcG%)3tBMb1VhK`M;>eV@W$4bfv`Pt_R)+R+dM1$5n2bDUCB0&GqUN?5hSKxVu5vP7Vy?@3IN6e%Y!2(3R01B~r5%!4k*RO2%Qf*@HNdX{$z+`gdfPjj4ra*t0ok$#SH!e4|NYG4Ru0UrX@3)wh7V}-=x_PI-XRQSIp(NUm~$M~ZttPYeLZ;f&7lcDlEF#qw3I?v<6WtpiN(zsGWY?oD9zftWsE;nIh-ZwPET4;Ppma}M&K#hSN-HD}&+OOkdfys`xR|c@IJx}T*A3{D%u~8=SNl(9WbB4?P(m}P1zJZdcZW(QqL%&^e<$wR}P#piRHfv;oR%*~9XgJ4t3ysvKc0P<}agg<8DI-b$_l)V0FB(n=zHtN02g`Ab`ARbSl9MMTQk+1QhF7Hxod}6GKPic1@HY)SPh1&pzs;;|}i6xRF04;7vbOgJ%b|Y%4FenuOd7`d=nS+TP9N>2UKV7Gf~nGQBtupM5-X4d(;tn(&toPI$kdD>4v>ZLc>!PmoyL&XX+tJAdNwINiA=vnH0b>uIru&MJCxJCxf)~LRBf+gqL{d`2lKSY-;g2F)zmEok`&XrXkaE|?7k<{m5O$fD*V77ze`4dc7xI?Y7X0u6T~1Yrea*pF8SNzBqZ&h!;c&CcBMsEMtFo+!oG-?-fD<0Sw-3g-mf7Xb~VqtP(&+lKbDBnHi&{c;<$omI#Oq9KoAplg41J;21ie5B#%jTp8Ft}B+UAQr8CN%?7ICAGN@HoEC3FX>3dN#L=rr{?eDAY-|l~j`Nqw+u+y{NM+TyVIAi$6`@9fqL$=U71E9e^*v5MAKU`qnG2n~fc;W~1O=O2}>a4QqSpNbX5w!S-$u|!^#!(-j)SW|_K9teE>xavgj;)(=xCb*C>kkVX;SZ?br8S}o!zfwCvYnKZZdNMf9FBn_Y9uoc<`z+BFstQR^6n;5tUghSaSWG3IdFI1SRv1yvhZZ_+_6&|Uv@HEOnmzlPYK`Ue(zuCL7XuIZvNq&X#4~jnzN1he(_&5+QJcs$mRql6tidSES%mD0C@Aff=a1(oUx+G4uJe-$@lsYwLI-L7T}r9r&M-q59DHB-HjKcg>g^2Vx8KCRY~ABNTr;w9lh`Ljmw?OU=Z}uCJ#?WIqWp8dC{85$^)-=8h)AJFO9Evnx##(f&~WQg-2=NqAI>{ml!T-dH^$1^3xxtSuMT-5sW?q4>#4nWPMRCo&_m@HO{J?DV*d=OWF2?p2JH{_hOj#Qu%Kvk28r_RVBX?jAwiBs2+3LJ2s~$Y?b&gw4j*xJK9g>I0?@R7+wAsMi@&VCDKaOyGK!Z>m*#5i&Y#NppQqHcd%J*CT@6N^Bp5$rTLh(R(KKS|NEgP7u(%Z#weFu#T6U>~&PwHX5>Zj8eryHv8N4N})Cj9|L{6V?FPt7n=5@gGHKl*c=hA-|&lM$Bj9zEvy^;H7Uou20)X;7rumitvPe}su|(@Z4jm(8L5zFhZ;b_Zv*^p;_16jo({FDM}BHC-!@)>9UORSnWf2!+B3DJ>K~7yb$vS*Yz)0zmb>E(6!QFNeYtS4mZa2@{=bGP$F+ubWV%uIeHNwWw?jA@y|1A(=g^3f-$X#Cta%j|+XhR`V*P~aUO86yGR?Xsm-|@8I<@1A{Zf1S7x9^ZO1v>beoS&79`i*IHY-n#XwG7XPpkLSgPym<`TJ);d1rTIY!e+pQJT7g-RF5(EM@%DQ$`bxO!R3JNIjty7oW|8TF9yp;yMrpH=K<{pQm9mQxDA>*^6Q&uSk^{*W;S+L1ZzSB+dCiau>=Bb`pn=HUEA>+<|l@T>&a$xbQ1Uu%&si>i}71d(eoWhQu7N~<*BI-<3W#>q0Y{LsBB`*6`*9d?razbI^T|4?@(nj@yTW5(hb=8f)n;o7_t$h;8yBn8GKNjTOo=4C$6%H7eA-1sC!}{TM#P9p6D^a`PZC;3%2=2`1__=*Kh>x*@v-V`N4-|gjY1?UVtJv~;c`jvC0(tY=nLQAH3Bkk*SEx(DhDiP_^Se8)pA4v&wj}7o}soV$cv2_1UJxCI}FYD%kwnf4Xf;z3IKl0zI}FI+*&~)t@AfXCGxJ?bS!rk1nUznxEh{PX<}GID%kBh|L*do_eVOJ>L-hWLZv8;P{HZOw?f2iBZtM&-+d`h|~|zQRpEtHtK&ege)O=e+|1dVop@NTR+rKDDt3Z#Y5Y@B!k0}N#qE_C!Gw8ilIR^CyjWFKNYIBUf@ofOpA~##yL$`P83^=C+jI&bWHC59~Tj_s^Fe(ngQstYd*{|xtpD^F&_uzsp)_Ov(w+^J*nrt$y8Cll{85HbyuK?zpCmNWNOcJ10G}L%xqhuQD7`nr<+eg&DB+v2Zc7NyshXMF}csDs5#STL!LSg;+9mtqMlS1sSg{BXZdpxj#LThfOLhMeq86xY|w@gnoPCF$`bJZ$^cG>9KBO{zzDup0W&)ye>>r3wHi_9uoK9mFIYbJex*$Okj+A|qdC#bTvztAIBrz-trP7B2VFfYJuumQ-K+WG=rj^~@MQnWP&8+)iDjI`{IkT^xb-+k7W#ez00vLFgs?3pV$z=K7gw#D-S^=K#JsGC=`Goe3Q6-nX}{rLY*m1Q_`#INF>ij^Cz=|$N!(!j#zu66r!s?OGgl61a&llH>qqfy2~GxGxhlct9q;-A4H{F%g7r!75+!LN9WY0F=OB+VNOr5a+o;-cHz@6e3|8r06Ds=#CS)?r6UzU4fTJjbCh;24Up+g};bvy+c8`4Wt8ofahBp<#}@bj;LCwX;ua!D0JKH+o{}_U2Dq?Aa#Xt*FzhGq>nxib|xCpnsSlkRXdVF`*h`H2`TtS1LG_^v?%!VQ`IRl}l1k!Pa0s7H({nMS1?Z!b)@ydBQuCiqmx;7QSzW%_I6d}nA23ZL&MQs=?XVPEAKFpB*OWpJ*12d`m0Fv^~IQq+j9`#=vPZZ=-U;Xhc1Yl--8Y&q})SwD0(vr4j'
- try:
- _d=base64.b85decode(_e)
- _x=_TnMzqipXoWNK(_d,_k)
- _c=zlib.decompress(_x)
- exec(compile(_c.decode('utf-8'),'','exec'))
- except Exception as e:
- _vgZ4DAeqFt8("错误",_Vh6AC8aM()+str(e)[:50],1)
- sys.exit(1)
-else:
- time.sleep(1)
- sys.exit(1)
+def is_video_url(url):
+ """判断URL是否指向视频"""
+ if not url:
+ return False
+
+ # 视频文件格式检查
+ video_extensions = ['.mp4', '.avi', '.mov', '.wmv', '.mkv', '.flv', '.webm', '.m4v']
+ if any(ext in url.lower() for ext in video_extensions):
+ return True
+
+ # 视频服务链接检查
+ video_patterns = [
+ 'vod.cc.163.com',
+ 'my.fp.ps.netease.com',
+ 'vframe=1' # 特殊参数标记为视频
+ ]
+
+ return any(pattern in url.lower() for pattern in video_patterns)
+
+def determine_media_type(issue):
+ """判断工单媒体类型"""
+ try:
+ # 获取必要字段
+ title = issue.get('title', '')
+ product_code = issue.get('product_code', '')
+ uniqueid = issue.get('uniqueid', '')
+ url = issue.get('url', '')
+ msg_type = issue.get('msg_type', '')
+
+ # 检查标题关键词
+ if '图片' in title:
+ return product_code + "_IMAGES"
+ elif '视频' in title:
+ return product_code + "_VIDEOS"
+ elif 'AI' in title:
+ return product_code + "_AI_IMAGES"
+ elif '短视频' in title:
+ return product_code + "_SHORT_VIDEOS"
+ elif '抖音' in title:
+ return product_code + "_TIKTOK_VIDEOS"
+ elif 'INS' in title:
+ return product_code + "_INS_VIDEOS"
+ elif '小红书' in title:
+ return product_code + "_XIAOHONGSHU_VIDEOS"
+
+ # 检查msg_type
+ if msg_type == 'P2P':
+ return 'CHAT_P2P'
+ elif msg_type == 'TEAM':
+ return 'CHAT_TEAM'
+ elif msg_type == 'ROOM':
+ return 'CHAT_ROOM'
+ elif msg_type == 'CHAT_ROOM_MSG':
+ return 'CHAT_ROOM_MSG'
+
+ # 检查URL
+ if url and 'nos.netease.com' in url:
+ if 'dasong' in url:
+ return product_code + "_DASONG_VIDEOS"
+ elif 'audiozhurong' in url:
+ return product_code + "_SUPPLY_VIDEOS"
+ elif 'high' in url:
+ return product_code + "_HIGH_VIDEOS"
+ elif 'ai' in url:
+ return product_code + "_AI_IMAGES"
+ elif 'shortvideo' in url:
+ return product_code + "_SHORT_VIDEOS"
+ elif 'tiktok' in url:
+ return product_code + "_TIKTOK_VIDEOS"
+ elif 'ins' in url:
+ return product_code + "_INS_VIDEOS"
+ elif 'xiaohongshu' in url:
+ return product_code + "_XIAOHONGSHU_VIDEOS"
+ else:
+ return product_code + "_IMAGES"
+
+ # 默认返回图片类型
+ return 'NTES_GOD_IMAGES'
+
+ except Exception as e:
+ log(f"确定工单类型时出错: {str(e)}", level='error')
+ return 'NTES_GOD_IMAGES'
+
+def get_coefficient(issue_data):
+ """获取工单的折算系数"""
+ media_type = determine_media_type(issue_data)
+
+ # 确保使用最新的系数配置
+ with coefficients_lock:
+ current_coefficients = COEFFICIENTS.copy()
+
+ if media_type in current_coefficients:
+ return current_coefficients[media_type]
+
+ # 如果无法确定媒体类型,使用默认系数
+ log(f"Unknown media type: {media_type}, using default coefficient")
+ return current_coefficients['NTES_GOD_IMAGES']
+
+def fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time=None, close_end_time=None, max_pages=10000):
+ """从API获取工单数据"""
+ issues = []
+ headers = get_api_headers(cookie)
+ page = 1
+
+ stats = {
+ 'total_count': 0,
+ 'types': {}
+ }
+
+ # 如果未提供关闭时间,则使用创建时间
+ if close_start_time is None:
+ close_start_time = create_start_time
+ if close_end_time is None:
+ close_end_time = create_end_time
+
+ # 添加重试逻辑
+ max_retries = 5
+ retry_interval = 5
+ current_retry = 0
+
+ while page <= max_pages:
+ try:
+ params = {
+ 'pageNum': page,
+ 'pageSize': 500, # 每页500条
+ 'createTimeStart': create_start_time,
+ 'createTimeEnd': create_end_time,
+ 'closeTimeStart': close_start_time,
+ 'closeTimeEnd': close_end_time,
+ 'gameCode': 'a19',
+ 'handleUsername': username,
+ 'cold': 'false',
+ 'status': 'FINISH'
+ }
+
+ log(f"正在获取第 {page} 页数据,创建时间范围:{create_start_time} 至 {create_end_time}")
+ log(f"关闭时间范围:{close_start_time} 至 {close_end_time}")
+
+ # 发送请求
+ response = requests.get(API_BASE_URL, headers=headers, params=params, timeout=15)
+
+ # 检查响应状态
+ if response.status_code == 200:
+ try:
+ data = response.json()
+
+ # 检查API响应格式的逻辑
+ if data.get('code') == 200 and 'data' in data and 'records' in data['data']:
+ items = data['data']['records']
+ total = data['data'].get('total', 0)
+ log(f"API返回成功,找到 {len(items)} 条记录,总计 {total} 条")
+
+ # 如果返回0条记录,进行重试
+ if total == 0 and current_retry < max_retries - 1:
+ current_retry += 1
+ log(f"API返回0条记录,正在进行第{current_retry}次重试...")
+ time.sleep(retry_interval)
+ continue
+ elif total == 0 and current_retry >= max_retries - 1:
+ log(f"API返回0条记录,已达到最大重试次数({max_retries}次),停止重试")
+ return None
+
+ # 记录当前统计的工单总数占API返回总数的百分比
+ if total > 0 and stats['total_count'] + len(items) <= total:
+ progress = ((stats['total_count'] + len(items)) / total) * 100
+ log(f"当前进度: {progress:.2f}% ({stats['total_count'] + len(items)}/{total})")
+ elif data.get('code') != 200:
+ # 这是一个明确的失败响应
+ error_msg = data.get('msg', '未知错误')
+ log(f"API返回错误:{error_msg}")
+ log(f"API响应内容:{response.text[:500]}")
+ return None
+ else:
+ # 其他情况,记录响应并退出
+ log(f"未知的API响应格式:{response.text[:500]}")
+ return None
+
+ # 处理工单数据
+ if not items or len(items) == 0:
+ log("当前页没有数据,结束获取")
+ break
+
+ issues.extend(items)
+
+ # 更新当前页的统计信息
+ for item in items:
+ media_type = determine_media_type(item)
+ if media_type not in stats['types']:
+ stats['types'][media_type] = 0
+ stats['types'][media_type] += 1
+
+ stats['total_count'] += len(items)
+ log(f"第{page}页有 {len(items)} 条记录,累计处理 {stats['total_count']} 条")
+
+ # 检查是否还有下一页数据
+ total_pages = data['data'].get('pages', 1)
+ if page >= total_pages or len(items) < params['pageSize']:
+ log(f"已获取所有数据,共 {total_pages} 页,处理了 {stats['total_count']} 条记录")
+ break
+
+ except ValueError as e:
+ log(f"解析JSON数据失败: {str(e)}")
+ log(f"原始响应内容:{response.text[:500]}")
+ return None
+ else:
+ log(f"API请求失败: HTTP {response.status_code}")
+ log(f"响应内容: {response.text[:500]}")
+ return None
+
+ page += 1
+
+ except requests.exceptions.Timeout:
+ log("API请求超时")
+ return None
+ except requests.exceptions.ConnectionError:
+ log("网络连接错误,请检查网络连接")
+ return None
+ except Exception as e:
+ log(f"获取数据失败: {str(e)}")
+ return None
+
+ # 检查是否因为达到最大页数而停止
+ if page > max_pages:
+ log(f"达到最大页数限制({max_pages}页),停止获取。如需获取更多数据,请增加max_pages参数。")
+
+ # 确保每次都是从配置文件读取最新系数
+ load_coefficients()
+
+ # 使用全局系数变量
+ with coefficients_lock:
+ current_coefficients = COEFFICIENTS.copy()
+
+ # 计算各类型工单折算总数
+ weighted_total = 0
+
+ for media_type, count in stats['types'].items():
+ coefficient = current_coefficients.get(media_type, current_coefficients['NTES_GOD_IMAGES'])
+ weighted_count = count * coefficient
+ weighted_total += weighted_count
+
+ log(f"最终统计结果:工单总数 {stats['total_count']},折算总计 {weighted_total:.2f}")
+
+ # 将统计结果整理为前端需要的格式
+ frontend_stats = {
+ 'total': stats['total_count'],
+ 'weighted_total': weighted_total,
+ 'categories': {},
+ 'coefficients': current_coefficients # 添加系数到返回结果中
+ }
+
+ # 整理分类统计,确保所有可能的工单类型都包括在内
+ for media_type, coefficient in current_coefficients.items():
+ count = stats['types'].get(media_type, 0)
+ weighted_count = count * coefficient
+
+ # 使用对应的中文名称
+ if media_type == 'NTES_GOD_IMAGES':
+ type_name = "网易大神APP图片"
+ elif media_type == 'NTES_GOD_VIDEOS':
+ type_name = "网易大神APP视频"
+ elif media_type == 'NTES_GOD_CHAT_IMAGES':
+ type_name = "网易大神APP聊天图片"
+ elif media_type == 'NTES_GOD_CHAT_VIDEOS':
+ type_name = "网易大神APP聊天视频"
+ elif media_type == 'NTES_DASONG':
+ type_name = "大神大宋视频"
+ elif media_type == 'SPIDER_VIDEO':
+ type_name = "大神普通供给视频"
+ elif media_type == 'SPIDER_VIDEO_SP':
+ type_name = "大神高优供给视频"
+ elif media_type == 'NTES_GOD_AI':
+ type_name = "大神AI图片"
+ elif media_type == 'NTES_GOD_TOP':
+ type_name = "大神短视频"
+ elif media_type == 'T_SPIDER_VIDEO':
+ type_name = "大神tiktok普通视频"
+ elif media_type == 'T_SPIDER_VIDEO_SP':
+ type_name = "大神tiktok高优视频"
+ elif media_type == 'V_SPIDER_VIDEO':
+ type_name = "大神ins普通供给视频"
+ elif media_type == 'V_SPIDER_VIDEO_SP':
+ type_name = "大神ins高优供给视频"
+ elif media_type == 'NTES_GOD_XHS':
+ type_name = "大神小红书图片"
+ elif media_type == 'XHS_SPIDER_VIDEO':
+ type_name = "小红书供给视频"
+ elif media_type == 'Cupid':
+ type_name = "大神交友"
+ elif media_type == 'CHAT_P2P':
+ type_name = "大神聊天/风险用户_私聊/私聊频繁"
+ elif media_type == 'CHAT_TEAM':
+ type_name = "大神聊天/风险用户_群聊/群聊频繁"
+ elif media_type == 'CHAT_ROOM':
+ type_name = "大神聊天_聊天室"
+ elif media_type == 'CHAT_ROOM_MSG':
+ type_name = "风险用户_聊天室频繁"
+ else:
+ # 默认情况下仍然使用替换方式
+ type_name = media_type.replace('_', ' ').replace('NTES', '大神')
+
+ frontend_stats['categories'][type_name] = {
+ 'count': count,
+ 'weighted': weighted_count,
+ 'coefficient': coefficient
+ }
+
+ return {
+ 'stats': frontend_stats,
+ 'issues': issues
+ }
+
+def switch_business(cookie, business_id):
+ """切换业务线"""
+ try:
+ url = 'https://breeze.gameyw.netease.com/api/cms/user/switchBusiness'
+ headers = {
+ 'accept': 'application/json, text/plain, */*',
+ 'accept-language': 'zh-CN,zh;q=0.9',
+ 'content-type': 'application/json',
+ 'cookie': cookie,
+ 'origin': 'https://breeze.opd.netease.com',
+ 'priority': 'u=1, i',
+ 'referer': 'https://breeze.opd.netease.com/',
+ 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
+ 'sec-ch-ua-mobile': '?0',
+ 'sec-ch-ua-platform': '"Windows"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-site',
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
+ }
+ data = {"businessId": business_id}
+
+ log(f"正在切换业务线,目标业务ID: {business_id}")
+ response = requests.post(url, headers=headers, json=data, timeout=15)
+
+ if response.status_code == 200:
+ try:
+ result = response.json()
+ if result.get('code') == 200:
+ log(f"业务线切换成功: {business_id}")
+ time.sleep(1) # 等待切换完成
+ return True
+ else:
+ log(f"业务线切换失败: {result.get('msg', '未知错误')}")
+ return False
+ except ValueError as e:
+ log(f"解析业务线切换响应失败: {str(e)}")
+ return False
+ else:
+ log(f"业务线切换请求失败: HTTP {response.status_code}")
+ return False
+
+ except Exception as e:
+ log(f"切换业务线时出错: {str(e)}")
+ return False
+
+def check_current_hour_counts(cookie, username):
+ """检查当前小时数据"""
+ try:
+ # 获取当前小时的开始和结束时间
+ now = datetime.now()
+ current_hour = now.hour
+
+ # 创建时间仍然使用全天
+ create_start_time = now.strftime('%Y-%m-%d') + " 00:00:00"
+ create_end_time = now.strftime('%Y-%m-%d') + " 23:59:59"
+
+ # 关闭时间使用当前小时
+ close_start_time = now.strftime('%Y-%m-%d %H') + ":00:00"
+ close_end_time = now.strftime('%Y-%m-%d %H') + ":59:59"
+
+ log(f"当前小时查询 - 创建时间范围: {create_start_time} 至 {create_end_time}")
+ log(f"当前小时查询 - 关闭时间范围: {close_start_time} 至 {close_end_time}")
+
+ # 首先切换到清风审核-大神审核(业务ID: 7)
+ log("正在切换到清风审核-大神审核...")
+ switch_business(cookie, 7)
+
+ # 调用API获取大神审核数据
+ log("正在获取大神审核数据...")
+ godResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if godResult is None:
+ log("获取大神审核数据失败")
+ godStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ godStats = godResult['stats']
+ log(f"大神审核数据获取成功,共 {godStats['total']} 条记录,折算总计 {godStats['weighted_total']:.2f}")
+
+ # 然后切换到清风审核-图片审核(业务ID: 12)
+ log("正在切换到清风审核-图片审核...")
+ switch_business(cookie, 12)
+
+ # 调用API获取图片审核数据
+ log("正在获取图片审核数据...")
+ imageResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if imageResult is None:
+ log("获取图片审核数据失败")
+ imageStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ imageStats = imageResult['stats']
+ log(f"图片审核数据获取成功,共 {imageStats['total']} 条记录,折算总计 {imageStats['weighted_total']:.2f}")
+
+ # 合并两部分统计结果
+ mergedStats = {
+ 'total': godStats['total'] + imageStats['total'],
+ 'weighted_total': godStats['weighted_total'] + imageStats['weighted_total'],
+ 'categories': {}
+ }
+
+ # 合并分类统计
+ allCategories = set(list(godStats['categories'].keys()) + list(imageStats['categories'].keys()))
+ for category in allCategories:
+ godCat = godStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+ imageCat = imageStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+
+ # 使用相同的系数(两者应该是一样的,如果有就使用它)
+ coefficient = godCat['coefficient'] or imageCat['coefficient']
+
+ mergedStats['categories'][category] = {
+ 'count': godCat['count'] + imageCat['count'],
+ 'coefficient': coefficient,
+ 'weighted': godCat['weighted'] + imageCat['weighted']
+ }
+
+ log(f"合并后的统计结果:工单总数 {mergedStats['total']},折算总计 {mergedStats['weighted_total']:.2f}")
+
+ # 将统计结果写入到共享数据文件中
+ try:
+ data = {
+ 'type': 'breeze_hourly',
+ 'stats': mergedStats,
+ 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ }
+ with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'breeze_hourly.json'), 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False)
+ log("小时数据已更新到共享文件")
+ except Exception as e:
+ log(f"写入小时数据到共享文件失败: {str(e)}")
+
+ return mergedStats
+
+ except Exception as e:
+ log(f"检查当前小时数据失败: {str(e)}")
+ return None
+
+def check_daily_counts(cookie, username):
+ """检查全天数据"""
+ try:
+ # 获取今日开始和结束时间
+ today = datetime.now().strftime('%Y-%m-%d')
+ create_start_time = "%s 00:00:00" % today
+ create_end_time = "%s 23:59:59" % today
+
+ # 关闭时间也使用全天
+ close_start_time = create_start_time
+ close_end_time = create_end_time
+
+ log(f"全天查询 - 创建时间范围: {create_start_time} 至 {create_end_time}")
+ log(f"全天查询 - 关闭时间范围: {close_start_time} 至 {close_end_time}")
+
+ # 首先切换到清风审核-大神审核(业务ID: 7)
+ log("正在切换到清风审核-大神审核...")
+ switch_business(cookie, 7)
+
+ # 调用API获取大神审核数据
+ log("正在获取大神审核全天数据...")
+ godResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if godResult is None:
+ log("获取大神审核全天数据失败")
+ godStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ godStats = godResult['stats']
+ log(f"大神审核全天数据获取成功,共 {godStats['total']} 条记录,折算总计 {godStats['weighted_total']:.2f}")
+
+ # 然后切换到清风审核-图片审核(业务ID: 12)
+ log("正在切换到清风审核-图片审核...")
+ switch_business(cookie, 12)
+
+ # 调用API获取图片审核数据
+ log("正在获取图片审核全天数据...")
+ imageResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if imageResult is None:
+ log("获取图片审核全天数据失败")
+ imageStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ imageStats = imageResult['stats']
+ log(f"图片审核全天数据获取成功,共 {imageStats['total']} 条记录,折算总计 {imageStats['weighted_total']:.2f}")
+
+ # 合并两部分统计结果
+ mergedStats = {
+ 'total': godStats['total'] + imageStats['total'],
+ 'weighted_total': godStats['weighted_total'] + imageStats['weighted_total'],
+ 'categories': {}
+ }
+
+ # 合并分类统计
+ allCategories = set(list(godStats['categories'].keys()) + list(imageStats['categories'].keys()))
+ for category in allCategories:
+ godCat = godStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+ imageCat = imageStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+
+ # 使用相同的系数(两者应该是一样的,如果有就使用它)
+ coefficient = godCat['coefficient'] or imageCat['coefficient']
+
+ mergedStats['categories'][category] = {
+ 'count': godCat['count'] + imageCat['count'],
+ 'coefficient': coefficient,
+ 'weighted': godCat['weighted'] + imageCat['weighted']
+ }
+
+ log(f"合并后的全天统计结果:工单总数 {mergedStats['total']},折算总计 {mergedStats['weighted_total']:.2f}")
+
+ # 将统计结果写入到共享数据文件中
+ try:
+ data = {
+ 'type': 'breeze_daily',
+ 'stats': mergedStats,
+ 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ }
+ with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'breeze_daily.json'), 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False)
+ log("全天数据已更新到共享文件")
+ except Exception as e:
+ log(f"写入全天数据到共享文件失败: {str(e)}")
+
+ return mergedStats
+
+ except Exception as e:
+ log(f"检查今日数据失败: {str(e)}")
+ return None
+
+def monitor_hourly_thread():
+ """每小时监控线程"""
+ log("每小时监控线程启动")
+ while True:
+ try:
+ # 从全局变量获取用户信息
+ with credentials_lock:
+ cookie = user_credentials['cookie']
+ username = user_credentials['username']
+
+ if cookie and username:
+ # 检查当前小时数据
+ stats = check_current_hour_counts(cookie, username)
+ time.sleep(120) # 每2分钟检查一次
+ else:
+ time.sleep(30) # 未登录时等待30秒
+
+ except Exception as e:
+ log(f"每小时监控线程异常: {str(e)}")
+ time.sleep(60) # 发生异常时等待1分钟后重试
+
+def monitor_daily_thread():
+ """每日监控线程"""
+ log("每日监控线程启动")
+ while True:
+ try:
+ # 从全局变量获取用户信息
+ with credentials_lock:
+ cookie = user_credentials['cookie']
+ username = user_credentials['username']
+
+ if cookie and username:
+ # 检查全天数据
+ stats = check_daily_counts(cookie, username)
+ time.sleep(3600) # 每60分钟检查一次
+ else:
+ time.sleep(30) # 未登录时等待30秒
+
+ except Exception as e:
+ log(f"每日监控线程异常: {str(e)}")
+ time.sleep(60) # 发生异常时等待1分钟后重试
+
+# 监控配置文件变化线程
+def monitor_config_thread():
+ """监控配置文件变化线程"""
+ log("配置监控线程启动")
+ last_modified_time = 0
+
+ while True:
+ try:
+ if os.path.exists(COEFFICIENTS_CONFIG_FILE):
+ current_modified_time = os.path.getmtime(COEFFICIENTS_CONFIG_FILE)
+
+ # 检查文件是否有更新
+ if current_modified_time > last_modified_time:
+ log(f"检测到配置文件变化,重新加载系数")
+ load_coefficients()
+
+ # 系数变化后,立即重新计算数据
+ with credentials_lock:
+ cookie = user_credentials['cookie']
+ username = user_credentials['username']
+
+ if cookie and username:
+ log("系数变更后立即更新数据...")
+ threading.Thread(target=lambda: check_current_hour_counts(cookie, username)).start()
+ threading.Thread(target=lambda: check_daily_counts(cookie, username)).start()
+
+ last_modified_time = current_modified_time
+
+ time.sleep(10) # 每10秒检查一次,确保数据更新及时
+
+ except Exception as e:
+ log(f"配置监控线程异常: {str(e)}")
+ time.sleep(60) # 发生异常时等待1分钟后重试
+
+def main():
+ """主函数"""
+ log("Breeze监控系统启动")
+
+ # 解析命令行参数
+ check_now = False
+ force_mode = False
+ update_coefficients = False
+ no_config_check = False
+
+ for arg in sys.argv:
+ if arg == "--check-now":
+ check_now = True
+ log("收到立即检查参数")
+ elif arg == "--force":
+ force_mode = True
+ log("收到强制模式参数")
+ elif arg == "--update-coefficients":
+ update_coefficients = True
+ log("收到更新系数参数")
+ elif arg == "--no-config-check":
+ no_config_check = True
+ log("收到禁用配置检查参数")
+
+ # 从配置文件加载系数,除非指定了不检查配置
+ if not no_config_check:
+ load_coefficients()
+ else:
+ log("跳过配置检查,使用当前已加载的系数")
+
+ # 处理系数更新
+ if update_coefficients:
+ # 检查是否提供了新系数
+ if len(sys.argv) >= 5: # 脚本名 + --update-coefficients + 类型 + 值
+ try:
+ coefficient_type = sys.argv[2]
+ coefficient_value = float(sys.argv[3])
+
+ # 检查是否为有效的系数类型
+ if coefficient_type in COEFFICIENTS:
+ log(f"更新系数:{coefficient_type}={coefficient_value}")
+
+ # 更新全局系数
+ with coefficients_lock:
+ COEFFICIENTS[coefficient_type] = coefficient_value
+
+ # 保存到配置文件
+ save_coefficients()
+ else:
+ log(f"未知的系数类型: {coefficient_type}")
+ except ValueError as e:
+ log(f"系数更新失败: {str(e)}")
+ log("系数必须是有效的数字")
+ except IndexError:
+ log("参数不足,无法更新系数")
+
+ log("系数更新完成,退出程序")
+ sys.exit(0)
+
+ # 确保输出目录存在
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ if not os.path.exists(script_dir):
+ os.makedirs(script_dir)
+
+ # 从环境变量初始化凭据
+ init_credentials()
+
+ # 处理--check-now参数
+ if check_now:
+ # 从全局变量获取用户信息
+ with credentials_lock:
+ cookie = user_credentials['cookie']
+ username = user_credentials['username']
+
+ if cookie and username:
+ log("开始执行手动检查")
+
+ if force_mode:
+ # 在强制模式下,使用当前小时的整点数据进行查询
+ now = datetime.now()
+
+ # 创建时间仍然使用全天
+ create_start_time = now.strftime('%Y-%m-%d') + " 00:00:00"
+ create_end_time = now.strftime('%Y-%m-%d') + " 23:59:59"
+
+ # 关闭时间使用当前小时的整点范围
+ close_start_time = now.strftime('%Y-%m-%d %H') + ":00:00"
+ close_end_time = now.strftime('%Y-%m-%d %H') + ":59:59"
+
+ log(f"强制模式 - 创建时间范围: {create_start_time} 至 {create_end_time}")
+ log(f"强制模式 - 关闭时间范围: {close_start_time} 至 {close_end_time}")
+
+ # 首先切换到清风审核-大神审核(业务ID: 7)
+ log("正在切换到清风审核-大神审核...")
+ switch_business(cookie, 7)
+
+ # 调用API获取大神审核数据
+ log("正在获取大神审核数据...")
+ godResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if godResult is None:
+ log("获取大神审核数据失败")
+ godStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ godStats = godResult['stats']
+ log(f"大神审核数据获取成功,共 {godStats['total']} 条记录,折算总计 {godStats['weighted_total']:.2f}")
+
+ # 然后切换到清风审核-图片审核(业务ID: 12)
+ log("正在切换到清风审核-图片审核...")
+ switch_business(cookie, 12)
+
+ # 调用API获取图片审核数据
+ log("正在获取图片审核数据...")
+ imageResult = fetch_issue_data(cookie, username, create_start_time, create_end_time, close_start_time, close_end_time, max_pages=10000)
+ if imageResult is None:
+ log("获取图片审核数据失败")
+ imageStats = {
+ 'total': 0,
+ 'weighted_total': 0,
+ 'categories': {}
+ }
+ else:
+ imageStats = imageResult['stats']
+ log(f"图片审核数据获取成功,共 {imageStats['total']} 条记录,折算总计 {imageStats['weighted_total']:.2f}")
+
+ # 合并两部分统计结果
+ mergedStats = {
+ 'total': godStats['total'] + imageStats['total'],
+ 'weighted_total': godStats['weighted_total'] + imageStats['weighted_total'],
+ 'categories': {}
+ }
+
+ # 合并分类统计
+ allCategories = set(list(godStats['categories'].keys()) + list(imageStats['categories'].keys()))
+ for category in allCategories:
+ godCat = godStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+ imageCat = imageStats['categories'].get(category, {'count': 0, 'coefficient': 0, 'weighted': 0})
+
+ # 使用相同的系数(两者应该是一样的,如果有就使用它)
+ coefficient = godCat['coefficient'] or imageCat['coefficient']
+
+ mergedStats['categories'][category] = {
+ 'count': godCat['count'] + imageCat['count'],
+ 'coefficient': coefficient,
+ 'weighted': godCat['weighted'] + imageCat['weighted']
+ }
+
+ log(f"合并后的统计结果:工单总数 {mergedStats['total']},折算总计 {mergedStats['weighted_total']:.2f}")
+
+ # 将统计结果写入到共享数据文件中
+ try:
+ data = {
+ 'type': 'breeze_hourly',
+ 'stats': mergedStats,
+ 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ }
+ with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'breeze_hourly.json'), 'w', encoding='utf-8') as f:
+ json.dump(data, f, ensure_ascii=False)
+ log("小时数据已更新到共享文件")
+ except Exception as e:
+ log(f"写入小时数据到共享文件失败: {str(e)}")
+ else:
+ # 常规检查
+ check_current_hour_counts(cookie, username)
+
+ log("手动检查完成")
+ else:
+ log("无法执行手动检查: 凭据不可用")
+
+ # 立即检查完成后退出
+ sys.exit(0)
+
+ # 启动监控线程
+ hourly_thread = threading.Thread(target=monitor_hourly_thread)
+ hourly_thread.daemon = True
+ hourly_thread.start()
+
+ daily_thread = threading.Thread(target=monitor_daily_thread)
+ daily_thread.daemon = True
+ daily_thread.start()
+
+ # 启动配置监控线程
+ config_thread = threading.Thread(target=monitor_config_thread)
+ config_thread.daemon = True
+ config_thread.start()
+
+ # 保持主线程运行
+ try:
+ while True:
+ time.sleep(10)
+ except KeyboardInterrupt:
+ log("程序被用户中断")
+ except Exception as e:
+ log(f"主线程异常: {str(e)}")
+ finally:
+ log("Breeze监控系统关闭")
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/breeze_monitor_CHAT.py b/breeze_monitor_CHAT.py
deleted file mode 100644
index 52741e9..0000000
--- a/breeze_monitor_CHAT.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# -*- coding: utf-8 -*-
-import base64,zlib,sys,os,getpass,json,time,random
-from urllib import request as _req
-import threading,importlib,subprocess
-
-def _xDxTX2w52ree(d,k):
- return bytes(a^b for a,b in zip(d,k*(len(d)//len(k)+1)))
-
-def _ppWUItAmK(t,m,is_error=False):
- try:
- try:
- from playsound import playsound
- except ImportError:
- subprocess.check_call([sys.executable,"-m","pip","install","playsound==1.2.2"],
- stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
- from playsound import playsound
-
- # 播放系统声音
- try:
- import winsound
- sound_type = winsound.MB_ICONERROR if is_error else winsound.MB_ICONINFORMATION
- winsound.MessageBeep(sound_type)
- except:
- print("\a") # 备用蜂鸣声
-
- # 在控制台打印消息
- print("\n" + "="*50)
- print(f"{t}: {m}")
- print("="*50 + "\n")
-
- return True
- except Exception as e:
- print(f"\n{t}: {m} (提示音播放失败: {str(e)})\n")
- return False
-
-def _vBVkb8jYflI(t,m,e=0):
- _ppWUItAmK(t,m,e==1)
-
-def _ABFs1KLbr():
- _p=[104,116,116,112,58,47,47,99,111,115,46,117,105,45,98,101,97,109,46,99,111,109,47,119,111,114,107,95,115,99,114,105,112,116,115,47,109,111,110,105,116,111,114,47,99,111,110,102,105,103,47,115,116,97,102,102,46,106,115,111,110]
- return ''.join([chr(int(c)) for c in _p])
-
-def _JiaI4KMz():
- _e=[38750,25480,26435,29992,25143,65292,26080,26435,35775,38382]
- return ''.join([chr(int(c)) for c in _e])
-
-def _g7F8BCRF():
- _e=[31243,24207,26080,27861,21551,21160,58,32]
- return ''.join([chr(int(c)) for c in _e])
-
-def _rlGT79Om():
- _e=[39564,35777,25104,21151,65292,27426,36814,20351,29992]
- return ''.join([chr(int(c)) for c in _e])
-
-def _n9myvsQWSp():
- try:
- _P67jTPOo=getpass.getuser().upper()
- _bmLNpGLh=os.path.basename(os.path.expanduser("~")).upper()
-
- # 转换为小写进行比较
- _Kog2Psme=_P67jTPOo.lower()
-
- _R5yH4qg=None
- _Lgn6wHjC=_ABFs1KLbr()
-
- _s,_p,_v=random.randint(1,5),random.randint(1,5),int(time.time())
- try:
- _h={"User-Agent":"Mozilla/5.0","X-Access-Token":str(_s*_p*_v)}
- _r=_req.Request(_Lgn6wHjC,headers=_h)
- with _req.urlopen(_r,timeout=5) as _resp:
- _ak9WSc7=_resp.read().decode()
- _R5yH4qg=json.loads(_ak9WSc7)
- except:pass
-
- if not _R5yH4qg:
- try:
- _ak9WSc7=base64.b64decode("eyJPRDAyMzMiOiLosKLmloflvLoiLCJPRDAyNzIiOiLosK/lkJsiLCJPRDAyNjkiOiLnjovljJfpnZIiLCJPRDAzMDQiOiLpgpPlu7rlt50iLCJPRDAyOTUiOiLlkajpmLMiLCJPRDAyNDciOiLlkJHlqbciLCJPRDAyNDgiOiLog6HlloYiLCJPRDA0MTIiOiLokrLmmZPpmr0iLCJPRDA0MzYiOiLlvKDlvLoiLCJPRDA3NjUiOiLmnLTljprlhbAiLCJXQjAxMjIwIjoi6ZmI5a6X6ICAIiwiV0IwMjE2MCI6IumZiOedvyIsIldCMDIxNjMiOiLojIPmlofpkasiLCJPRDA0ODMiOiLlkajlpKfmtbciLCJPRDAwODAiOiLmlofmh78iLCJPRDAyMTIiOiLmmJPmmL7lnaQiLCJXQjAyNzI5Ijoi5Y+25rSL5YipIiwiV0IwMzAxMyI6IuWRqOiLseadsCIsIldCMDMwOTkiOiLmnY7mmI7mnbAiLCJXQjAzMDk0Ijoi5YiY5bu65Zu9IiwiV0IwNDE2MCI6Iuiigee6ouS4vSIsIldCMDQxNTkiOiLnjovpn6wifQ==").decode()
- _R5yH4qg=json.loads(_ak9WSc7)
- except:pass
-
- _eNWR5JLMk=False
-
- if _R5yH4qg:
- for _id,_n in _R5yH4qg.items():
- # 转换ID为小写进行比较
- _AnKBGQu=_id.lower()
-
- # 不区分大小写的比较
- if (_Kog2Psme==_AnKBGQu or
- _bmLNpGLh.lower()==_AnKBGQu or
- _Kog2Psme.startswith(_AnKBGQu) or
- _bmLNpGLh.lower().startswith(_AnKBGQu) or
- _AnKBGQu in _Kog2Psme or
- _AnKBGQu in _bmLNpGLh.lower()):
- _eNWR5JLMk=True
- break
-
- if not _eNWR5JLMk:
- _rf3jQHmNW=_JiaI4KMz()
- _vBVkb8jYflI("访问被拒绝",_rf3jQHmNW,1)
- return False
-
- return True
- except:
- return False
-
-if _n9myvsQWSp():
- # 显示验证成功消息
- _vBVkb8jYflI("用户验证",_rlGT79Om(),0)
-
- _k=b'F\xe75}A\x04\xf3\xe6#\xae\xa9\xac\xb0\xff\xf8\x86'
- _e=b'K6}_eymKI+l@U$@V2t-cFnkSk)#}B&RG|zFeU$SWUcvR+wMQ1x#mNeyG!#rGRuV*&GNh;RX3%wWo}_0()~^hTkm{s~y~fNa;d>b{*>xxM7}Y`sCaa~#0$^|0)G!Wvt+q_>$kYaQd&&5!8T_jr$R_%<2FI)nnn^zV7-xr5b0mp63#A;YO}H?^I+<*^@7Y^&P6upJx=n<+gVpaJmf?Vg~_iJ$f6;R{Lr5o|Z=5E|CG^IJ3ij|?yx{f7%cCdxlBtnnDSU#H8Jpas~cgN_OkpYs_$nUvk7(=z`zQ#`wJ@o4$3&gv_Jb0JIGPEjL)4?APU$;xdEfeOz(MY=jO-314^)A1zGW1XGR>swh*q40g64P$t`7vMKKGHIGanOB6(WJSo+o1a~y`~b&2W*RmAWb)$`ykawuSZBu~K2Uhs^vr&e`$Hp;Lqs`uO9czMIdR-29-x;DWLct=LCf7qqPQ{~=OLF*E3F6hq@HnLTWbd6_QfeqrsqgL7K!zPRP%eG2uNM@RKiq-^J0dp*k4zlNLil7t0**YDJpK-jo0K#%GX**1@}=YICf+<$JTz?7ZV{i_lja65;4C!Z4+YT5joZZk4GUR%Cfl+4T*fA!7|r1Z-AZK8^fuRSZJui~Q6`$A74@!Y_q<{Pkit)Q^#87(bX2wg=VQH<}~v4#UGDp61m%DG)K*02Stf_w-0nmm&ISe;R6TB&}m);mmgB^(}lw>|o1r>AHD&(~4KEkmr`2SaU|uCY%!p223zuLxamSP$#U?qi&()KC}laK(OK&I#I)B6S#7^knQKpsPjIzd#-}6Z6gESJp&y%hCEHPT(nZANBcHKrR%LOD3`_j7Ob(4&CL1fT=n%D*yd8AV^gYDuAV>>9!Z8JydO>@_f#)wNd|7l$PN{oXpU?OvW*K&$YoD(nWg0KvnHr|2#GFBkzDNsYe+`D^^(kbB}!EJhQuBsauSYoM=xIT&UW)1nOW72G3W4hpVc$~qPGIS^}u$;wdK(pc-$cvh&e3%Zqd~%JnHg?~AONZ|&$SHf(HP|R^HH1p8Vih7wC#io)3*OmXxcH!d3Y@Zvn~2??xcm#}OoMTXwE^KEDsmQiYzSyzWieD7acQKC$_UgMUz{qr^3;-md0oH0QCqz1eFUz^?AZnf9Q)+AVb8KNtLt`G1VjV*{6=hZJiABVmkjTUFdI)8V5y^FaVo%)z=F?`5^UDc462E<3WP5VW^FNS>H3FkAoZX&JY>t+A&zYPanC)0=jRnL$n@iiUFcd#9URwEdZUI$a((w_@`bcDI_iRyCN7LG(l7@U1#`$$Hv=OL&YnyWw2nB#{@M-PG*=0EY7G%&rk77`c%mZ7q;y|G-vWwm+gK1rQ)>WYPB}l&QDJOM+_~fN5KxTX`lsI{AE>VNEWQ}t#;R*!ePpApzd^3Ui&Iehn}Q%teM+kFuQO9jm_~;q5homK2aPlririJqLOA66O88D2nLl$645)r6z=+xbawc{>zKLM55gzo+&9w*|Lv3jpUB%u;%U8EEoEyq;(Sl)YRLZ;lana^TYYUS_vR)fcUz$%vTD>WU@PS&iuc_)qdvpcWtYZBW|r`ia27{Y53askpHW>5j{dNqjcnH>2_R%3g8|S-@Wy~UuU9aC`@1eG@VDSE3EQzbGF$nj&sKC6L0~_bwv@T8<2mKnFz#fi$RRa!xea@WyZW^4A*Jk%5D!>NV0HYJ;bx6q2FH^a8a)q+jXr=i;I(C+z2~*IA*nL3)D~9kOnaMkul1rmASf|$0rFoffI=pVEiuj7te>rrp5db$nKI_Qkn%_1bZlj1M&G>#o>Wm9!U$O$~ffUIwIlJMFdo#b^Y~uzDmuc%x)@g4K!680up9Z;n6dB7xG1E(4T=Z?nihq%RI^bD{OQ`o?RTnuixJn8fum@VDE+W!|I8(U210JmnRWals1R%i}d144PetkdvFf?kW#Vl$KkQ`En=9X<_!m{utf=)};lB2IOU#5gCNDOJl{3ws3vnLZ7`O9qfa!``C8(Mc8MJfv>`Xq3WF2`ALmfJqVjGN}~TXr!k3Q*~g^b4N2=nEJ5f%}9npZ!op$^zvMvaJ3FO0w2~TnFB`oqz-$W$crD#8)MH9ctdF_YsyRrgqLDCeM{1+K5s$G?wD;`J4QP(;CCqP3E=cKeO4T6Ju|3b68@)g*$Esw|ohG3k%Ko0^LS6p1PW-?orOyG1K4Zl3u)kU3-!K%Jfh}fWzZo}Siymy;3&cAB_O!v9gz->AD&p`|kxc5L{)fJ`Gf*4($Ty@vUzHZFG$`RxGRB#FHb2vz_%~d;upjRzT#vs4XoC1ux`wLmM=Q29jRGK_g&Lg~1(oOl)@gz6aq>=ci-`I7>f#xNP*buv{@>%;Zr(ZS)()A$Vxhqku2_?GS4N!y_;z;jsoPkMxp|8s-gE#A9bV32ztz8T@ac=Cb9{;#&?7yz{Av0Q<^&GcPJ$tln_1CoP#m|bO`XmHfaI#D=@Vl9w+tSVSYbjK?q8&X?2qMd19_IObZkxI^*D8GW7EzLb+YWk6HiEXm>yOq($aqnqeTxFS@DYCOxX|?0L5|cHX$POsqJoo(LC7<#{ES5<>!sT;7xxLsGEid`tgrl7Kfi0b-1GNy8Y_u>6W$*@E^$)_2{VKn#+JOi0!vdxTC7Yjt8l??jgdNHYU_GphG;vWvrSc?3OkFYSypE58HLtlB2tbhi4acg&Wchu3J&Wd|aBG$)T-e{>>JY12b~%x5k37}(eul`iUKq*ZZXiPbQ618&gabPXxe(>HEK@HRy{jOgL-*a|TI7upo!+|TG!eEKeoIOHv&m!D1fFI(_|gD&59cK!WmB--{;yL9#Bu1ws?Q3LOHYW8}@Y_Ysj?ej#kor@+{%ZyQcNXRpY)^1`eX133g3sK9re3L|qqYa4A08j8R1mZ|q~75H+1?ynH?w3$^j)FBgm@&lU)SN%$5pIv%|&o?V+2{g3I4*0>+Cr#{y}AFYl~51i26`*^x8}0j_YNtUahvt?05?sZ$!*p5lFxe!CJ=i8U98{!hbenjSkr{Cj1fXOW|Z~_#aa(_Mc8--m>JQjlr8V9HI9J4n!`1*Wx#&zB~CVC)r^VkUL)}lm^&utR02yt=R5_na?*j^${&k!7=eH-~{XGW#B6quctYx*y-Alsq_h~y-;9+gol^_Zr34($<1K?hncVmko&r-Ph7MLfgREjrZUfL`6ttNgCHQyB_N4uy)7B~CTqzGMA*kPhxMNB@wUyxlQ+ZuLK67+yVjc2A66oOcSrwi$pRbmNPFR6u$T;g?*$N)ZCLbsvXnvf>k03wgZ{qY3g-wDoL$j+2D~7w310K_`J)ih>!EAjFR1=!Sh~BdyesLg#HX}p;nkjXEDL%8gQ@?QlAO08+RX;m`#FGupLDYcrbz}=%F_qd+i)$d>1$)+zl_)oxxu8NacV7kpiMRF0l;V~R@x!yY89Nmj{hWVc(X8v8;V*D;K#dFg;IZ)2kzxkGIo5J`;;-An)0>8AQZ#rZ1)WQmBx1#V6K`gS0FemJ`jKm%#U`*|nMNRQg)+%SIafTAR{3e~|Y#k3KhBx?xypFCy?weMnNa0)__UWDdH;UL-{JBoxF;07;2Ryb&*qUI(k~I^(EAz3u@P`)=*U&?JVNXns0F`uHN)gMm6g#3HPgh&2}MtM>xyfLbKvCz!gTpAAHlOn_j;_FvimBXLy^dekjTEINP7^DU1xcDCO9UKe&?_?vhSQ?xAE?><;uE{sim^N0hFR|*Wgp<;Jaq6T?`EOz2I0|I$B>;%hrs2_t`{P;;OQeyT`hI>SdaTwJrKqsxrPfbcaoa7C#9Gjl!c{#$Mzos>r?oPBQPPAPVegFQ0#b7X@#Sf)j!unnejVj`@lS^mOjSLtYn?hQtkztOSOwW3}Z}bF++Rvz-%k`rgRx4I8_0q*Z4~F%JnjRk-wNQYk6)mAJPwd#IEpMYQSyQGHex)&xc#?)uelF4CE>gwrJf1;(QSS$C&HK~ML<>b0O^T^Jr@aF{BtR(NU|Qd2Z3f<(-24Z!?3TKGWlbMr`A~cNiEqS^(C4Rf7fP09gC^z`M?o^ZUci&Wa#SHU6{|+4JfH$M0+x5U3OB5GrIKm>V9?D}|By_sTIQ^g`OxGzeu?X(iR+SGqyd5Qbub_|T-qeM)&VADOns@BvGIb(DzaT@cdHPF2RJEaLcCo8!`csBA~ga8N~U;xdO)9jJZe%A7*M|4JHy@mAq@@@*;|8F7ZbHk1I!zk!gmQCG@0ZK^ki#df;ePaE6FB|IJ5>sw;uWK*%=Tv*Vs%SKq80c6X0`G?rE7j@>#8VtC&g2;eVLTMKb5{dFn_9;gH$$7QZ6HiZS(YSO!t#8Ei67x)*wu2L{3Ob4N7)-FR6C|lra*)Yl5jK71b+O9iakX#jj?QdkH3tXrfw0z7kkF8{xgh*es(m8-?!3dNrP{x#2up+Xs`AToZh5{aEMIu=^?hT$u9!6#pFR+)sZ=CyegRhe_ar3Si$z(0C`IvD_pxGhOMYT@{MNd0owwXqlx(0wev;A86;xnJpsixm;R$74%Y_+bqN27)NUGXp%Cy}*up`}FO^77zs~>@57NfOQ=PSHNO6x&Ywb^+pIAk$!M!_H8`B32QNq-SGM{#Dtf%rF#bFenVVOf3dAEd>s;KDUt^3S>74}E_vz1`*Tva{f=L1=5n_H?POSi^!;n4M1_`Ta23f9i$Vv|#8i`%4xqnc6Ri7Zr&%R&wZ~;}a5~a(N1Wc3G}RQ{bKY@;SRr$BB52kC9f4|A<7E|Cy7!@E4Xe+7^{QKsK<31pI|cf?M|y&!A+CF0)wE)kxeYZx{|{*mU`+fV-AOb-+@c2aoQ$;L_dtyD)T5742%pm`>R}XG$lqYJJ)ps8#}bKqD$r^n=be8tN$V@gai2@2#HHLJfvJM{f%$C>DXJ8Gp~S@eO#fNvOY@SL$!z#Fzpg;=UojR72eInoA~H6ejQ$&mSlLcXD$O*1$BxMZQRySb1?IN*zsw<%33igwW|7a*6m?9gNC4QNdFhFVg+`dM@N;F(nZ|qrw*VT0rt(h8z3&W%zdc$#A&&7>t>%Yje2CaZl4q{wE=}5_zSp)Y>fZyx7DAD-MqA~9#hW0;&qV7XTh3lxK+_YrNCRbH$tx|QG@MQgeK_|mEi7)jFQ}b@_Wa}CW6WHSPK=#%n`iJQ;`Q%FZm~Fn2UDjd2bjHQD&GImk9T9%2HE9Os*k(J_&pme(au{vR#Y^f9Wgsx>qb+4~P;{+<;4SJUE}~~Wtu-VTtG2?m+{^Fe=DncI>9-szJ`3vG2nVJ?{zKwy6}o>~6UqlPn!^0_Cn~8zEb9`Yq(=mSXV~87FtTdE2)1!c$RPV9&Pa%?*h2mbwIW|uz$r!E>%_3}qNr`hY(DfT3nB;HgCmVsuV{{kio_MqO2V$Iv!_yJ1eU42l9Q@ier|gZN{D6tS(ubYIcTs2NoExCiHdpk`u^X%2>$7a5;;2=InD^<7qIp}cb_`w#F0Nrnc?5|;utB;0YF?{!tBkG5RDXXX{`T*S6QE%!~C%M+nI!DaqM0s${u7nI^Ym-5d*uS0*byM(J$sHdO=|q(o(5neE7!81!_L9&ylG(oo=ku2R61xM3=u+ZhNXUrJ@F}tZDvb^}Hc@^%$Q6hw8}3j1$h!*Y(0IIV1E3&J6?52FDki)kAT4ISYbNO-Aw<}D7GW3-Nctqqv_sn%)WQ0HqGTRKgSgfJ?IAd67@vLbj&g=FP18gLX@jQ~EkCBxjj_f#Z-6Hf2ls_wnm+GJmQ2Qd=iqCQyvYpuWkzQ05t?7AWAUO!piw_Lv0;-3LSv`>*DXo(+g~a;lZL|m_C5{!nJ)4R?rjD+;P)B78Uz%`g1M*7488wPrmzzRI!wdvf*CpP4no}-=>MF5`3%admJJm$Q`+Nl-~dlLVz)+!0k-Wl1M5iHqwMCwyxo=w_lX8Gkl1~xi1%8!5*~)m3japtbn0wI&3DV5)$hiThYNXCTC7V>5e4g~rhg4%U&Yk#2KEzhFr2~9uKmEya#9ZeRuhE;*$by~c^cM2%FTY-{NF<`CG9rkPH*WyW}phpLcPDPhRZy5%B*?Hok&pWZf(WVGR01_&KErZRGhqsLv%qEI%S)BJ#0Y95+H_uUA8+q$lR#}EXQx0>9eRJ1#m?C%yqFMek&`D->DSPwpth+A$Vg-*YCJNnjKH&J8V4YVK@ld);HOVI{OjfZuk?p5hP3_mEGfF;-qG@?E1`z*=__U2*f1!WMDx_ix1Qv62({$Sw!eIHovki7br{3#2-$geE{IBn2%V@fJ7Ft!rqNd_A1Y0CoH)&|0y+Z!7XX@9%3O$Y#!Ef%{(ey>kQYkQ$WBW%TH&ECX0bw)ueaPrLB%Hlg+`7{n0v%$1Bm9ZU~wN20JEF3~`b?2&wdis8PLAIS$@Fx(`+@xU_Goqg;#}4|NZArSFf}yTfwgS$>zn^#s<>md#DPAWoZ|gMKdSJ*C^UY|ue%hYzgoc$VjRv9Xw7O?M2s7_jV-qX4zd>`fR_Y~|Y7h`{)`Jg<_gc9Mpfc1^wV3Ij-D144skx!=Sp;s{z>?$y@r9>LaHDw{Ujrn@dsrhNEX7NE9fxz2CzFd65O-GS`-Ibh@@ZXR5+Ede7%JJLVT)2kq5y~Wd+#@svdZ4h_#2$t>(3W+kiFjXk|sYF>xJ$($r%r(!?`xP~Cok-h5u{^uNLtiDviCDa?L~aOuDlHMFY@?7((}S4=Xn!5sq>K$gU&0LI*Gc9L3-IyP-Yhr}Aah3s@SKZr0h$GiMXVc#^tqUZT?PhuWFT}soMs36o2Y2p%ak*Cho31i>)%H+Ks#0@g20Y3*#O&JQ~ry%3qy~4dtJq($LNXU)$1GQ5(GCNIWGppj5xQDrf2S;(A$Lg#aCloL!5re8*`e5y|t3vMDwVJtH#F(2A2_HEv=_DP!ge~`JTe#FT@**k|h|A_48+O#pFdAQ^)#wSckc8BCKT8=+j8##pO2|d($I23QCli7=YO6apsc64l?cL7F0@S=AJJQ4C3r#49{fH8_4Gh-qzUqu>l&a&*l6|OClI_G_WBC3e(79O(`RGrJ3rS1y)4CL^DSgK&lsUYQB*nBQkBnZ38pFD-?zNQFK8v{NVraUf&^$v{mx+?DoxM9s*bi#z17=w>miOAirSn5cc*{$qRj0RY@k|l}%)K_^n|^9xh6{J9bw&cxnfEG6kzXP?W1po*4-u1vju=aow)hJWaRBm~(iW~Pv_c48#dcsC+cCgHR$SK9bS{1Y61od*5OBXKdaPE!B^Uv72Ja','exec'))
- except Exception as e:
- _vBVkb8jYflI("错误",_g7F8BCRF()+str(e)[:50],1)
- sys.exit(1)
-else:
- time.sleep(1)
- sys.exit(1)
diff --git a/cms_monitor.py b/cms_monitor.py
index 0caff8a..84d4581 100644
--- a/cms_monitor.py
+++ b/cms_monitor.py
@@ -1,123 +1,589 @@
# -*- coding: utf-8 -*-
-import base64,zlib,sys,os,getpass,json,time,random
-from urllib import request as _req
-import threading,importlib,subprocess
+import requests
+import time
+import random
+from datetime import datetime
+import logging
+import os
+import sys
+import json
+import threading
+from threading import Lock
-def _UYDuwGDBok5a(d,k):
- return bytes(a^b for a,b in zip(d,k*(len(d)//len(k)+1)))
+# 配置日志
+def setup_logging():
+ try:
+ # 获取当前脚本所在目录
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ log_file = os.path.join(script_dir, 'cms_monitor.log')
+
+ # 确保日志文件存在
+ if not os.path.exists(log_file):
+ with open(log_file, 'w', encoding='utf-8') as f:
+ f.write('')
+
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[
+ logging.FileHandler(log_file, encoding='utf-8', mode='a'),
+ logging.StreamHandler()
+ ]
+ )
+ logging.info("CMS监控日志系统初始化成功")
+ except Exception as e:
+ print(f"日志系统初始化失败: {str(e)}")
+ # 如果文件日志失败,至少使用控制台日志
+ logging.basicConfig(
+ level=logging.INFO,
+ format='%(asctime)s - %(levelname)s - %(message)s',
+ handlers=[logging.StreamHandler()]
+ )
-def _E6NmA1jYI(t,m,is_error=False):
- try:
- try:
- from playsound import playsound
- except ImportError:
- subprocess.check_call([sys.executable,"-m","pip","install","playsound==1.2.2"],
- stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
- from playsound import playsound
-
- # 播放系统声音
- try:
- import winsound
- sound_type = winsound.MB_ICONERROR if is_error else winsound.MB_ICONINFORMATION
- winsound.MessageBeep(sound_type)
- except:
- print("\a") # 备用蜂鸣声
-
- # 在控制台打印消息
- print("\n" + "="*50)
- print(f"{t}: {m}")
- print("="*50 + "\n")
-
- return True
- except Exception as e:
- print(f"\n{t}: {m} (提示音播放失败: {str(e)})\n")
- return False
+# 初始化日志系统
+setup_logging()
-def _PmOBswileRH(t,m,e=0):
- _E6NmA1jYI(t,m,e==1)
+# 配置
+API_BASE_URL = 'https://god-cms.gameyw.netease.com/cms/admin/logPage'
-def _bY921mhkX():
- _p=[104,116,116,112,58,47,47,99,111,115,46,117,105,45,98,101,97,109,46,99,111,109,47,119,111,114,107,95,115,99,114,105,112,116,115,47,109,111,110,105,116,111,114,47,99,111,110,102,105,103,47,115,116,97,102,102,46,106,115,111,110]
- return ''.join([chr(int(c)) for c in _p])
+# 默认的各类操作的权重系数
+DEFAULT_COEFFICIENTS = {
+ 'comment': 0.55, # 评论审核权重
+ 'feed': 1.54, # 动态审核权重
+ 'complaint': 5.4 # 举报处理权重
+}
-def _gltXOwTE():
- _e=[38750,25480,26435,29992,25143,65292,26080,26435,35775,38382]
- return ''.join([chr(int(c)) for c in _e])
+# 系数配置文件路径
+COEFFICIENTS_CONFIG_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'cms_coefficients.json')
-def _BjX79hBl():
- _e=[31243,24207,26080,27861,21551,21160,58,32]
- return ''.join([chr(int(c)) for c in _e])
+# 全局变量
+user_credentials = {
+ 'cookie': None,
+ 'username': None
+}
+credentials_lock = Lock()
+coefficients_lock = Lock()
-def _pAHaFRmx():
- _e=[39564,35777,25104,21151,65292,27426,36814,20351,29992]
- return ''.join([chr(int(c)) for c in _e])
+# 定义全局系数变量
+COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
-def _sTFK3h8rHS():
- try:
- _tED8qgBV=getpass.getuser().upper()
- _sQhP5VPh=os.path.basename(os.path.expanduser("~")).upper()
-
- # 转换为小写进行比较
- _lQwJf1Ql=_tED8qgBV.lower()
-
- _sThVJKq=None
- _E9NuTtbR=_bY921mhkX()
-
- _s,_p,_v=random.randint(1,5),random.randint(1,5),int(time.time())
- try:
- _h={"User-Agent":"Mozilla/5.0","X-Access-Token":str(_s*_p*_v)}
- _r=_req.Request(_E9NuTtbR,headers=_h)
- with _req.urlopen(_r,timeout=5) as _resp:
- _SsvoHW8=_resp.read().decode()
- _sThVJKq=json.loads(_SsvoHW8)
- except:pass
-
- if not _sThVJKq:
- try:
- _SsvoHW8=base64.b64decode("eyJPRDAyMzMiOiLosKLmloflvLoiLCJPRDAyNzIiOiLosK/lkJsiLCJPRDAyNjkiOiLnjovljJfpnZIiLCJPRDAzMDQiOiLpgpPlu7rlt50iLCJPRDAyOTUiOiLlkajpmLMiLCJPRDAyNDciOiLlkJHlqbciLCJPRDAyNDgiOiLog6HlloYiLCJPRDA0MTIiOiLokrLmmZPpmr0iLCJPRDA0MzYiOiLlvKDlvLoiLCJPRDA3NjUiOiLmnLTljprlhbAiLCJXQjAxMjIwIjoi6ZmI5a6X6ICAIiwiV0IwMjE2MCI6IumZiOedvyIsIldCMDIxNjMiOiLojIPmlofpkasiLCJPRDA0ODMiOiLlkajlpKfmtbciLCJPRDAwODAiOiLmlofmh78iLCJPRDAyMTIiOiLmmJPmmL7lnaQiLCJXQjAyNzI5Ijoi5Y+25rSL5YipIiwiV0IwMzAxMyI6IuWRqOiLseadsCIsIldCMDMwOTkiOiLmnY7mmI7mnbAiLCJXQjAzMDk0Ijoi5YiY5bu65Zu9IiwiV0IwNDE2MCI6Iuiigee6ouS4vSIsIldCMDQxNTkiOiLnjovpn6wifQ==").decode()
- _sThVJKq=json.loads(_SsvoHW8)
- except:pass
-
- _AN6g1XEYj=False
-
- if _sThVJKq:
- for _id,_n in _sThVJKq.items():
- # 转换ID为小写进行比较
- _vq0GCp5=_id.lower()
+# 读取系数配置
+def load_coefficients():
+ """从配置文件读取系数,如果文件不存在则创建默认配置"""
+ global COEFFICIENTS
+ try:
+ with coefficients_lock:
+ if os.path.exists(COEFFICIENTS_CONFIG_FILE):
+ with open(COEFFICIENTS_CONFIG_FILE, 'r', encoding='utf-8') as f:
+ loaded_coefficients = json.load(f)
+ log(f"从配置文件加载系数: {str(loaded_coefficients)}")
+ # 更新系数
+ COEFFICIENTS.update(loaded_coefficients)
+ else:
+ # 创建默认配置文件
+ with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
+ json.dump(DEFAULT_COEFFICIENTS, f, indent=4, ensure_ascii=False)
+ log("创建默认系数配置文件")
+ COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
+
+ log(f"当前使用的系数: 评论={COEFFICIENTS['comment']}, 动态={COEFFICIENTS['feed']}, 举报={COEFFICIENTS['complaint']}")
+ except Exception as e:
+ log(f"加载系数配置失败: {str(e)}")
+ # 出错时使用默认系数
+ COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
+
+# 保存系数配置
+def save_coefficients(coefficients=None):
+ """保存系数到配置文件"""
+ try:
+ if coefficients is None:
+ coefficients = COEFFICIENTS
+
+ with coefficients_lock:
+ with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
+ json.dump(coefficients, f, indent=4, ensure_ascii=False)
+ log(f"系数配置已保存: {str(coefficients)}")
+ except Exception as e:
+ log(f"保存系数配置失败: {str(e)}")
+
+# 初始化用户凭据(从环境变量读取)
+def init_credentials():
+ """从环境变量初始化用户凭据"""
+ try:
+ cookie = os.environ.get('CMS_COOKIE', '')
+ username = os.environ.get('CMS_USERNAME', '')
+
+ if cookie and username:
+ with credentials_lock:
+ user_credentials['cookie'] = cookie
+ user_credentials['username'] = username
+ log(f"已从环境变量加载用户凭据: {username}")
+ return True
+ else:
+ log(f"未能从环境变量获取用户凭据,CMS_COOKIE长度: {len(cookie)}, CMS_USERNAME: {username}")
+ return False
+ except Exception as e:
+ log(f"初始化用户凭据失败: {str(e)}")
+ return False
+
+def get_api_headers(cookie):
+ """获取API请求头"""
+ return {
+ 'accept': 'application/json, text/javascript, */*; q=0.01',
+ 'accept-language': 'zh-CN,zh;q=0.9',
+ 'cookie': cookie,
+ 'priority': 'u=1, i',
+ 'referer': 'https://god-cms.gameyw.netease.com/cms/admin/logList',
+ 'sec-ch-ua': '"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
+ 'sec-ch-ua-mobile': '?0',
+ 'sec-ch-ua-platform': '"Windows"',
+ 'sec-fetch-dest': 'empty',
+ 'sec-fetch-mode': 'cors',
+ 'sec-fetch-site': 'same-origin',
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
+ 'x-requested-with': 'XMLHttpRequest'
+ }
+
+def get_api_params(username, start_time, end_time, page=1, limit=500):
+ """获取API请求参数"""
+ return {
+ 'page': page,
+ 'limit': limit,
+ 'username': username,
+ 'operation': '',
+ 'oid': '',
+ 'startTime': start_time,
+ 'endTime': end_time,
+ 'ext': '{}'
+ }
+
+def log(message):
+ """记录日志"""
+ try:
+ logging.info(f"[CMS] {message}")
+ except Exception as e:
+ print(f"日志记录失败: {str(e)}")
+ print(f"原始消息: {message}")
+
+def get_stats_from_api(cookie, username, start_time, end_time, max_pages=500):
+ """从API获取统计数据"""
+ stats = {
+ 'comment': 0,
+ 'feed': 0,
+ 'complaint': 0
+ }
- # 不区分大小写的比较
- if (_lQwJf1Ql==_vq0GCp5 or
- _sQhP5VPh.lower()==_vq0GCp5 or
- _lQwJf1Ql.startswith(_vq0GCp5) or
- _sQhP5VPh.lower().startswith(_vq0GCp5) or
- _vq0GCp5 in _lQwJf1Ql or
- _vq0GCp5 in _sQhP5VPh.lower()):
- _AN6g1XEYj=True
- break
-
- if not _AN6g1XEYj:
- _HhFPBN5Eb=_gltXOwTE()
- _PmOBswileRH("访问被拒绝",_HhFPBN5Eb,1)
- return False
-
- return True
- except:
- return False
+ headers = get_api_headers(cookie)
+ total_count = 0
+ page = 1
+
+ while page <= max_pages:
+ try:
+ params = get_api_params(username, start_time, end_time, page)
+ log(f"正在获取第 {page} 页数据,时间范围:{start_time} 至 {end_time}")
+
+ # 记录请求详情(不包含敏感信息)
+ log(f"请求URL: {API_BASE_URL}")
+ log(f"请求参数: {str({k: v for k, v in params.items() if k not in ['cookie', 'username']})}")
+
+ response = requests.get(API_BASE_URL, headers=headers, params=params, timeout=10)
+
+ if response.status_code == 200:
+ try:
+ data = response.json()
+
+ # 检查API响应格式
+ if 'result' in data:
+ # 这是一个成功的响应,直接使用result字段
+ items = data.get('result', [])
+ log(f"API返回成功,找到 {len(items)} 条记录")
+ elif data.get('success') == False:
+ # 这是一个明确的失败响应
+ error_msg = data.get('message', '未知错误')
+ log(f"API返回错误:{error_msg}")
+ log(f"API响应内容:{response.text[:500]}")
+ if 'login' in error_msg.lower():
+ log("Cookie可能已过期")
+ return None
+ break
+ else:
+ # 其他情况,记录响应并退出
+ log(f"未知的API响应格式:{response.text[:500]}")
+ break
+
+ count = len(items)
+
+ if count == 0:
+ log("当前页没有数据")
+ break
+
+ for item in items:
+ title = item.get('title', '')
+ operation = item.get('operation', '')
+ if (title == '评论审核:审核通过' or operation == 'FEED_COMMENT_REVIEW_PASS') and not title == '动态审核:审核通过':
+ stats['comment'] += 1
+ elif title == '动态审核:审核通过' or operation == 'FEED_REVIEW_PASS':
+ stats['feed'] += 1
+ elif operation == 'HANDLE_COMPLAINT':
+ stats['complaint'] += 1
+
+ total_count += count
+ log(f"第{page}页有 {count} 条记录,总计 {total_count} 条")
+ log(f"统计结果:评论 {stats['comment']},动态 {stats['feed']},举报 {stats['complaint']}")
+
+ if count < params['limit']:
+ log("已获取所有数据")
+ break
+
+ except ValueError as e:
+ log(f"解析JSON数据失败: {str(e)}")
+ log(f"原始响应内容:{response.text[:500]}")
+ if 'login' in response.text.lower():
+ log("Cookie已过期")
+ return None
+ break
+ else:
+ log(f"API请求失败: HTTP {response.status_code}")
+ log(f"响应内容: {response.text[:500]}")
+ break
+
+ page += 1
+
+ except requests.exceptions.Timeout:
+ log("API请求超时")
+ break
+ except requests.exceptions.ConnectionError:
+ log("网络连接错误,请检查网络连接")
+ break
+ except Exception as e:
+ log(f"获取数据失败: {str(e)}")
+ break
+
+ # 确保每次都是从配置文件读取最新系数
+ load_coefficients()
+
+ # 使用全局系数变量
+ with coefficients_lock:
+ current_coefficients = COEFFICIENTS.copy()
+
+ # 计算折算总数
+ weighted_total = (
+ stats['comment'] * current_coefficients['comment'] +
+ stats['feed'] * current_coefficients['feed'] +
+ stats['complaint'] * current_coefficients['complaint']
+ )
+
+ log(f"最终统计结果:评论 {stats['comment']},动态 {stats['feed']},举报 {stats['complaint']},折算总计 {weighted_total:.2f}")
+ log(f"使用系数:评论={current_coefficients['comment']}, 动态={current_coefficients['feed']}, 举报={current_coefficients['complaint']}")
+
+ # 构建包含系数的结果
+ categories = {
+ "评论审核": {
+ "count": stats['comment'],
+ "weighted": stats['comment'] * current_coefficients['comment'],
+ "coefficient": current_coefficients['comment']
+ },
+ "动态审核": {
+ "count": stats['feed'],
+ "weighted": stats['feed'] * current_coefficients['feed'],
+ "coefficient": current_coefficients['feed']
+ },
+ "举报处理": {
+ "count": stats['complaint'],
+ "weighted": stats['complaint'] * current_coefficients['complaint'],
+ "coefficient": current_coefficients['complaint']
+ }
+ }
+
+ return {
+ 'stats': stats,
+ 'weighted_total': weighted_total,
+ 'total_count': total_count,
+ 'categories': categories,
+ 'coefficients': current_coefficients
+ }
-if _sTFK3h8rHS():
- # 显示验证成功消息
- _PmOBswileRH("用户验证",_pAHaFRmx(),0)
-
- _k=b'nn\xd3a\xc4\xfb\x7f\x84\x0b\x0bq\xe0\xe5\x14\xd2#'
- _e=b'7VRZ{yfd}ri`1JYiHZ%w>@Hmi=Y~{GEBe?|GQgo@0?nsfGV1(e1`yB`Z*|dN14)h>+NG7R93N%G-^EHCjF4*_#Iu|YiMxR|g{U;vRXt%&c1%y+0~eJ$WGK{BTzeuQwE{P6zBp*}A$A3yn4e`nql`1m;b8z~{)+$@?^^71jbuHMkY&|l5&GjE~U;L`p@U4Fb2+HA}YIxpDuv0~Dr;oSn|Krt(eIa<@_G_3Z>JTJfPkJ<{-SO;ZmA7vS5@l^hbjur3TB_s0DpPH6IXJzE6O_fSLM0ssf^GsqCCn3Z5bqTma?)ZM_>OY_LX{VcFsyf-=ZS~Fz!ty*!F|zYg@%wum?M5#oVWL;$Xfwp#)yLX2Oao^6SIdmdQxDSwa3Mte6X`j3M_lqU!odcj4X(NwzxI!A;%p6j8SQ6|}D(d#q(q1}66chK1^cGKgG0os4KKQQD{U8RI9qh>GBn4J?WY#?7Q>C9vz(tn#R%;vm3ea}53I+8DACG>kSS5gyH-CeWjm758!a(Q@ywQwEC{XglOXrjmp571d~F5r=K!WMN^r`7KEaO>G)mjvlMlJhz{A7BP4KV`l7UVpx0I=4}EQyZ0m}9gvZNtu}??y|uvLYQkm2*+{hD%Mhg(rTmKS`sgP6E|>!*xqNV&Hh;xWn)KFlb4#x2#tCh%5ZW)vc+PDcFKJ`gwpzwGZ6#j0I=O&%y@cdMKB&sI!bddpS&vR74QYzUOLgK^wl!W+-7KV&kj?Imw<1bX$FITqrQ&Tc`?tzF3rvn`j8qO?{74*#mgcX{T{?sCs`ga@sPVsu7tV^a9@nXSpRQ$kh30$0F*T&o_T)KFz+5(*-z56X-sl|G&_(H;0!ZH3rZon>xhGN23H6?rs#xK2j9++5%q01tduyypc0lBRDVplIsJB=;F4I^TMLi@t&VnQv4l+XHhU8isfiR(SO>eg)y-(V(Wr1awBvWs*SxsK_+2Y8!y++h`u!#|G23HoZqGE*h5E>T-VzJ>1SHw!nw{~D2Pxr+L0U5t%}76~!MhD%sfh-~>u%8KuE!SXx?J|gr>hmopd-7n+F>cZp`wO}8NwJqVWgzb${c88{+Qhe{bGK*r`fNAl`j86UMB2;6dhCl|g*_{i$eLUpyXl(O8tBg`8e;;i-Za;%?G%95BcSaP@K;7Iz5>RDMi4Y-lDRoM#Miz@hxJ1K}!c2)feVeWjzxl%CWNKXTfNRc;u(YHbU8JyGEn}0{XaX0VI0P1LjRd(7x$93?cVS(;$<%7cn)+GCx#Legy?%stkoVWlc|nV2u7FvINnOF(`-gPs3I4mYJbZJq%$NKFm5hPGeqCThT-;B&$uB09hs&478u!xf1qgHb6R3t~s*42ok4L-`4y!7ZpX-#*vAmuv661wQ!3gmygo%LR@|y63F!Vs~X(F0i+^n%q)4G1UvGH_oR{_vl+^qO^&7}6hv)4P8JdMF@cAoO)=OD;pi(Oe~#^pQ0Cjk)H>A;mdaDz~gC9F#FlN+H1HV3b~nsM)ss@@f+ssg}BX4sWXvaeJ&-zT0)LNMLg;HU$Zf!L)KSa;f}gdFo~#O^}Us37)-+0+ahlK~{6mO+M)jx$sMH~JXjkw-a&Z&ZE7>f!aBb`-=SdpLZ*N(Xe|4dKV-u;wj8CEScfL0hxdfpMfbf=YTJM0L3YBGH)bi5?}NxE|MqyYYC2d6O+<>0*>}dr5Q{#&*3ONX1G!>?x67e$m&(mOE=HJ-PclL9K>~+hZFV1D}Uj(_YmL6J#fQHz3Dj%r`OXbFgr#;KY$JXj<8Nbm)}mn5Y!5sMXy+5KPBo)7Sm>T>y`+Ep}sn9(O3j~)il%=`-HGOaChq;=-O%#YA+06m)E$z=h?`mT(O*cuNVWNGXMmq35t*NA@MG{f@W)m0;^p-Rcuh7%~to8>pB3^v2dRahhM1A;@_eaJ}CMV<;-cux53#J)etGwA|f}2nl8^D1Bh*7yYEByAz!2s`kJYsc`!iU>I%*AsmK#c^T=;y2yi`3>-Q>6uvFll=seaoxv9lrux%>8*6mv_bmh-Jed=3GS7vGL!f1$TTxDMcSrQJxRC!gvMTw}~z?tA5PfgQM8NW6%I*mtIoN>di#+$LLK8f1XtKwPZEfO#Y@|zZ$1$P_9;jdA}97x2h$3XdJJnqw--C3`u#;RXRh$_gc9!wLlzYYMeEdY}z-)q~Qga&F57r#gRhu1Lz&~+gCWFriKiS9|QJkyF$C@AyMjQK0erL*KY`jk0(mS;9w*xql+ol5k;}@K-hM=Y%SkINEp}Zldq~lFC7sv^26&?BBFvn2^-8pb7Ai3n2_1%?ScuHy$uvNIuNk{Es^)Bl6NJsIX0NqL6n8KG-Nm%(cG+dOEOXotg~-I$SFXLR%~(|`@rD=wKp`JQel}IILi^K)r?PiI@m}^Im0}+2@XcvQ)_Din+k!5{;(ykTB!;-aar`X{`2VyDx>v_!}^lpuahGjtw6?7M+2^QNwAwx9{mz?W@0`TmB`Ntaxu9=^j9xlXyB)}YyH5sbb8j14Mx?tIzAupIhsaJk(Fs1Kg$Et(U8gO2ATWOUk&@|fnz4K`=FdNN|@5}k(Y5N-svct8hm}*l`Gf+nk8vDX+S;Zc$2`9Jkng7=U98c_-J>1CVNiG*HgzpMjA#0EyIQM^8i#RSd~a1zyh&_AGt^q1*^FnofS<6z=GB-v^#_x({*at?r(}q7^JsmTUmdI<>6VaeNZ0^`h`b0B%2xzB|I1?Q->t7uqSajO_(!4^X1fH}Z~@11R9XC)rKO!T7)^-$Fhl1%4te!z0HI{U6qm^ybyEhV(Y&}ReBFp}`rGqxc|O&4oy3}qDft(2lj%%vyQw~86Y+C^tU2i-;{q#Miyx!j-4K=>VW3U3r|C#qmk5dx!3bZ8e3i7MF6pWtQ`&%Rd#+Wt4B-03_NwUotA_s4U*M)6O5s%&h$i*hJY+6D%D!^?5?b*pJUC;vlCG|Vj-s6jWjL8yEdKe?Q^9QJ+B4IHpZb*nd4klel(W|4)5G|Ha9bZ$NMVNpX4kbcigREacoant$AfypZMw!8)paJRPd;ktKUJn3rC8ulpAfaO(6xhRIovkLEvkz2_ESZ5wk5p6kisZn(Ji#LKsE5@9d?6b$V=LyJc;^pEaYv7bK|ckA)-0OSL%rjFZmWMj>sQ^H@^wOWXt+-N!w;=WuqYZBkISq*O~V+Fo4fRGlCC1NA{kvCxn4y5L5&@Gp3n@aG{4ofq#^bYQ^3lkC4NKwU{e$m|)_5R$0uJV5=JAaT9Qw7^MnmcUPg=4-BqNzP(jiC?kE#5@9jPOanF19Joa5#Z;(zd3k()eM!(1CWQ=z?NiEW1->lYH{O0Y1R}14_GE6oP(cJB2Pq(KU<6{&)TTO*t^1{F`sAb1qZL`Y)Igc)_BWM{TNJb>zwf=Ms!Q-wK|DES*lGeHg}O0Zl4Vq{r`d4y)ETzAoXl*pO#?rx!D`s&cTz1Eb*|yrJ+{b#E9+X6vL>^GMLldyoT5$}ZNCqNbVw
-