陪玩接单.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. import tkinter as tk
  2. from tkinter import scrolledtext, messagebox
  3. import threading
  4. import time
  5. import json
  6. import requests
  7. import base64
  8. from datetime import datetime
  9. class OrderMonitorApp:
  10. def __init__(self, root):
  11. self.root = root
  12. self.root.title("订单监控系统")
  13. self.root.geometry("900x600")
  14. self.root.resizable(True, True)
  15. # 运行标志
  16. self.running = False
  17. self.thread = None
  18. # 创建界面组件
  19. self.create_widgets()
  20. # 默认关闭时停止
  21. self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
  22. def create_widgets(self):
  23. # 顶部控制面板
  24. control_frame = tk.Frame(self.root)
  25. control_frame.pack(pady=10, padx=10, fill=tk.X)
  26. # 请求间隔
  27. tk.Label(control_frame, text="请求间隔(秒):", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
  28. self.interval_var = tk.StringVar(value="5")
  29. self.interval_entry = tk.Entry(control_frame, textvariable=self.interval_var, width=8, font=("Arial", 12))
  30. self.interval_entry.pack(side=tk.LEFT, padx=5)
  31. # 抢单价格
  32. tk.Label(control_frame, text="抢单价格(大于):", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
  33. self.buyPrice = tk.StringVar(value="180")
  34. self.interval_entry = tk.Entry(control_frame, textvariable=self.buyPrice, width=8, font=("Arial", 12))
  35. self.interval_entry.pack(side=tk.LEFT, padx=5)
  36. # 备注过滤
  37. tk.Label(control_frame, text="备注过滤(@隔开多个词):", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
  38. self.remarkIgnore = tk.StringVar(value="双女@单女")
  39. self.interval_entry = tk.Entry(control_frame, textvariable=self.remarkIgnore, width=24, font=("Arial", 12))
  40. self.interval_entry.pack(side=tk.LEFT, padx=5)
  41. control_frame2 = tk.Frame(self.root)
  42. control_frame2.pack(pady=10, padx=10, fill=tk.X)
  43. # 启动按钮
  44. self.start_button = tk.Button(control_frame2, text="启动监控", command=self.start_monitor, bg="green", fg="white", font=("Arial", 12), width=12)
  45. self.start_button.pack(side=tk.LEFT, padx=5)
  46. # 停止按钮
  47. self.stop_button = tk.Button(control_frame2, text="停止监控", command=self.stop_monitor, bg="red", fg="white", font=("Arial", 12), width=12, state=tk.DISABLED)
  48. self.stop_button.pack(side=tk.LEFT, padx=5)
  49. # 清空日志按钮
  50. clear_button = tk.Button(control_frame2, text="清空日志", command=self.clear_log, bg="gray", fg="white", font=("Arial", 12), width=10)
  51. clear_button.pack(side=tk.LEFT, padx=5)
  52. # 日志框架
  53. log_frame = tk.Frame(self.root)
  54. log_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
  55. tk.Label(log_frame, text="监控日志:", font=("Arial", 12), anchor="w").pack(anchor="w")
  56. self.log_text = scrolledtext.ScrolledText(log_frame, wrap=tk.WORD, font=("Consolas", 10), height=25)
  57. self.log_text.pack(fill=tk.BOTH, expand=True)
  58. # 验证输入只能为整数
  59. vcmd = (self.root.register(self.validate_int), '%P')
  60. self.interval_entry.config(validate="key", validatecommand=vcmd)
  61. def validate_int(self, new_value):
  62. """验证输入是否为整数"""
  63. if new_value == "":
  64. return True
  65. try:
  66. int(new_value)
  67. return True
  68. except ValueError:
  69. return False
  70. def get_captcha(self):
  71. try:
  72. # 发送GET请求获取图片
  73. response = requests.get("https://jiechidj.haiqigame.com/api/common/captcha?type=1&id=421052&timestamp=" + str(int(time.time() * 1000)), timeout=10)
  74. # 检查请求是否成功
  75. response.raise_for_status()
  76. # 获取图片的二进制内容
  77. image_data = response.content
  78. # 转换为base64编码
  79. base64_str = base64.b64encode(image_data).decode('utf-8')
  80. # 如果需要带前缀的完整格式(用于HTML img标签)
  81. # 根据响应的Content-Type判断图片类型
  82. content_type = response.headers.get('content-type', 'image/png')
  83. full_base64 = f"data:{content_type};base64,{base64_str}"
  84. return full_base64 # 或返回 base64_str,根据需求选择
  85. except requests.exceptions.RequestException as e:
  86. print(f"请求图片失败: {e}")
  87. return None
  88. except Exception as e:
  89. print(f"转换失败: {e}")
  90. return None
  91. def log_message(self, msg, level="INFO"):
  92. """在日志框中添加消息"""
  93. timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  94. formatted_msg = f"[{timestamp}] [{level}] {msg}\n"
  95. self.log_text.insert(tk.END, formatted_msg)
  96. self.log_text.see(tk.END) # 自动滚动到底部
  97. self.root.update_idletasks()
  98. def clear_log(self):
  99. """清空日志"""
  100. self.log_text.delete(1.0, tk.END)
  101. def ttshitu(self, imgBase64):
  102. url = "https://api.ttshitu.com/predict"
  103. payload = {"username": "puge","password": "mmit7750","typeid": 11,"remark": "测试","image": imgBase64}
  104. headers = {
  105. "Accept": "*/*",
  106. "Accept-Encoding": "gzip, deflate, br",
  107. "User-Agent": "PostmanRuntime-ApipostRuntime/1.1.0",
  108. "Connection": "keep-alive",
  109. "Content-Type": "application/json"
  110. }
  111. response = requests.request("POST", url, data=json.dumps(payload), headers=headers)
  112. jsonData = json.loads(response.text)
  113. print('验证码识别结果:' + jsonData['data']['result'])
  114. return jsonData['data']['result']
  115. def sendConnect(self, order_sn, captcha):
  116. """请求订单API"""
  117. url = "https://jiechidj.haiqigame.com/addons/shop/api.order/sendConnect"
  118. headers = {
  119. "Host": "jiechidj.haiqigame.com",
  120. "Connection": "keep-alive",
  121. "content-type": "application/json",
  122. "uid": "421052",
  123. "platform": "ios",
  124. "model": "iPhone 15<iPhone15,4>",
  125. "sid": "u0N8lossMZs5qbOvEPY0wsQyF5Z39D79",
  126. "token": "5a7d869c-c91b-4833-b252-aee0796a0822",
  127. "brand": "iPhone",
  128. "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 26_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.71(0x1800472b) NetType/WIFI Language/zh_CN",
  129. "Accept": "*/*",
  130. "Accept-Encoding": "gzip, deflate, br"
  131. }
  132. try:
  133. response = requests.post(url, headers=headers, data=json.dumps({"order_sn":order_sn,"captcha":captcha,"__token__":"5c8f6680ff6a1732b42ed36ebed7d1d2"}), timeout=10)
  134. response.raise_for_status()
  135. print(response.json())
  136. return response.json()
  137. except requests.exceptions.RequestException as e:
  138. self.log_message(f"请求失败: {str(e)}", "ERROR")
  139. return None
  140. except ValueError as e:
  141. self.log_message(f"解析JSON失败: {str(e)}", "ERROR")
  142. return None
  143. def fetch_orders(self):
  144. """请求订单API"""
  145. url = "https://jiechidj.haiqigame.com/addons/shop/api.order/index"
  146. querystring = {
  147. "connect": "true",
  148. "company_id": "131",
  149. "page": "1",
  150. "orderstate": "0",
  151. "paystate": "1",
  152. "shippingstate": "0"
  153. }
  154. headers = {
  155. "Host": "jiechidj.haiqigame.com",
  156. "Connection": "keep-alive",
  157. "content-type": "application/json",
  158. "uid": "421052",
  159. "platform": "ios",
  160. "model": "iPhone 15<iPhone15,4>",
  161. "sid": "u0N8lossMZs5qbOvEPY0wsQyF5Z39D79",
  162. "token": "5a7d869c-c91b-4833-b252-aee0796a0822",
  163. "brand": "iPhone",
  164. "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 26_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.71(0x1800472b) NetType/WIFI Language/zh_CN",
  165. "Accept": "*/*",
  166. "Accept-Encoding": "gzip, deflate, br"
  167. }
  168. try:
  169. response = requests.get(url, headers=headers, params=querystring, timeout=10)
  170. response.raise_for_status()
  171. return response.json()
  172. except requests.exceptions.RequestException as e:
  173. self.log_message(f"请求失败: {str(e)}", "ERROR")
  174. return None
  175. except ValueError as e:
  176. self.log_message(f"解析JSON失败: {str(e)}", "ERROR")
  177. return None
  178. def process_orders(self, data):
  179. """处理订单数据并显示关键信息"""
  180. if not data or data.get("code") != 1:
  181. self.log_message("API返回错误: " + str(data.get("msg", "未知错误")), "WARNING")
  182. return
  183. orders = data.get("data", {}).get("data", [])
  184. if not orders:
  185. self.log_message("当前无新订单", "INFO")
  186. return
  187. self.log_message(f"获取到 {len(orders)} 个订单", "INFO")
  188. for order in orders:
  189. # 提取订单基本信息
  190. order_sn = order.get("order_sn", "未知订单号")
  191. client = order.get("client", "未知")
  192. self.log_message(f"--- 订单号: {order_sn} (客户端: {client}) ---", "INFO")
  193. # 提取 order_goods 中的 title, attrdata, price
  194. order_goods = order.get("order_goods", [])
  195. for goods in order_goods:
  196. title = goods.get("title", "无标题")
  197. attrdata = goods.get("attrdata", "无规格")
  198. price = goods.get("price", "0.00")
  199. self.log_message(f" 商品: {title}", "INFO")
  200. self.log_message(f" 规格: {attrdata}", "INFO")
  201. self.log_message(f" 价格: ¥{price}", "INFO")
  202. # 提取接单要求 (order_desc 中 title="接单要求" 的 content)
  203. game_type = order.get("client", "未指定")
  204. self.log_message(f" 接单要求(端游/手游): {game_type}", "INFO")
  205. # 提取订单备注 (order_desc 中其他备注内容)
  206. remark_content = order.get("memo", "无备注")
  207. self.log_message(f" 订单备注: {remark_content}", "INFO")
  208. self.log_message("-" * 50, "INFO")
  209. # 抢单
  210. # 判断备注里面有没有关键词
  211. remarkGood = True
  212. remarkText = self.remarkIgnore.get()
  213. for item in remarkText.split('@'):
  214. if (item in remark_content):
  215. print('备注不符合!')
  216. remarkGood = False
  217. if (remarkGood):
  218. print('订单价格:' + price + ' 设置价格:' + self.buyPrice.get())
  219. if (float(price) > float(self.buyPrice.get())):
  220. print('定单价格符合!')
  221. yzmImg = self.get_captcha()
  222. yzmCode = self.ttshitu(yzmImg.split(',')[1])
  223. self.sendConnect(order_sn, yzmCode)
  224. break
  225. def monitor_loop(self):
  226. """监控循环,在后台线程中运行"""
  227. while self.running:
  228. try:
  229. interval = int(self.interval_var.get())
  230. if interval <= 0:
  231. interval = 5
  232. except ValueError:
  233. interval = 5
  234. self.log_message("正在请求订单数据...", "INFO")
  235. data = self.fetch_orders()
  236. if data:
  237. self.process_orders(data)
  238. else:
  239. self.log_message("请求失败,请检查网络或API配置", "ERROR")
  240. # 等待间隔时间,但需要检查运行标志
  241. for _ in range(interval):
  242. if not self.running:
  243. break
  244. time.sleep(1)
  245. def start_monitor(self):
  246. """启动监控线程"""
  247. # 验证间隔输入
  248. try:
  249. interval = int(self.interval_var.get())
  250. if interval <= 0:
  251. raise ValueError
  252. except ValueError:
  253. messagebox.showerror("错误", "请求间隔必须是正整数!")
  254. return
  255. if self.running:
  256. messagebox.showwarning("警告", "监控已在运行中")
  257. return
  258. self.running = True
  259. self.thread = threading.Thread(target=self.monitor_loop, daemon=True)
  260. self.thread.start()
  261. self.start_button.config(state=tk.DISABLED)
  262. self.stop_button.config(state=tk.NORMAL)
  263. self.log_message("监控已启动", "SUCCESS")
  264. def stop_monitor(self):
  265. """停止监控"""
  266. if not self.running:
  267. return
  268. self.running = False
  269. if self.thread and self.thread.is_alive():
  270. self.thread.join(timeout=2)
  271. self.start_button.config(state=tk.NORMAL)
  272. self.stop_button.config(state=tk.DISABLED)
  273. self.log_message("监控已停止", "SUCCESS")
  274. def on_closing(self):
  275. """关闭窗口时的清理"""
  276. if self.running:
  277. self.stop_monitor()
  278. self.root.destroy()
  279. def main():
  280. root = tk.Tk()
  281. app = OrderMonitorApp(root)
  282. root.mainloop()
  283. if __name__ == "__main__":
  284. main()