Files
jdy_fastapi/app/module/module.py
T
2025-11-14 11:04:01 +08:00

322 lines
12 KiB
Python

"""
F6 系统模块
本模块提供 F6 系统相关的功能,包括:
- 登录和认证
- 验证码识别
- 公司信息获取
- 门店信息获取
- 保持连接
依赖:
- requests: HTTP 请求
- PIL: 图像处理
- pytesseract: OCR 识别
"""
import requests
import hashlib
from urllib.parse import quote
from datetime import datetime
from app.api import API
from typing import Optional, Dict, AnyStr
from PIL import Image, ImageEnhance
import pytesseract
import logging
# 简道云 API 实例,用于调用简道云 API
api_instance = API()
# 日志记录器
logger = logging.getLogger('app')
class F6Module:
"""
F6 系统模块类
提供 F6 系统相关的所有功能,包括登录、信息获取等。
"""
@staticmethod
def get_captcha() -> AnyStr:
"""
获取并识别验证码
从 F6 系统获取验证码图片,使用 OCR 识别验证码文本。
Returns:
AnyStr: 识别出的验证码文本
注意:
需要系统安装 Tesseract OCR 才能正常工作
"""
captcha_url = 'https://yunxiu.f6car.cn/kzf6/login/captcha-image'
response = requests.get(captcha_url)
with open('captcha.png', 'wb') as f:
f.write(response.content)
image = Image.open('captcha.png')
enhancer = ImageEnhance.Contrast(image)
image = enhancer.enhance(2.0)
enhancer = ImageEnhance.Brightness(image)
image = enhancer.enhance(1.5)
image = image.convert('L')
image = image.point(lambda x: 0 if x < 128 else 255, '1')
image.save('preprocessed_captcha.png')
captcha_text = pytesseract.image_to_string(image)
print(f"识别的验证码为: {captcha_text}")
return captcha_text
@staticmethod
def login_in(username: str, password: str, company_name: str = '默认门店',) -> Optional[requests.Response]:
"""
F6 系统登录
使用用户名和密码登录 F6 系统,并选择指定的公司。
如果触发验证码,会自动识别并重试登录。
Args:
username: 用户名
password: 密码(明文,方法内部会进行 MD5 加密)
company_name: 公司名称,默认为'默认门店'
Returns:
Optional[requests.Response]: 登录响应对象,登录失败返回 None
注意:
密码会在方法内部进行 MD5 加密处理
"""
url = "https://yunxiu.f6car.com/kzf6/login/confirm"
session = requests.Session()
header = {
'Referer': url,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/130.0.0.0 Safari/537.36 Edg/129.0.0.0'
}
data = {
'username': username,
'password': hashlib.md5(password.encode('utf-8')).hexdigest(),
}
try:
res = session.post(url=url, headers=header, data=data)
res_json = res.json()
if res_json.get('message') == '请输入图形验证码':
logger.warning("触发图形验证码")
captcha_text = F6Module.get_captcha()
data.update({'imageCode': captcha_text})
res = session.post(url=url, headers=header, data=data)
res_json = res.json()
if res_json.get("data") is None:
return res
else:
group_id = ''
for group in res_json.get('data', []):
if group.get("groupName") == company_name:
group_id = group.get("groupId")
break
if not group_id:
logger.error(f"未找到公司名称: {company_name}")
return None
token = quote(res_json['token']) # URL 编码
url = (f'https://yunxiu.f6car.cn/kzf6/user/loginAfterChooseGroup?'
f'token={token}&groupId={group_id}&macAddress=')
res1 = session.get(url, cookies=res.cookies)
return res1
except Exception as e:
print(f"Error during login: {e}")
return None
def accept_login_message(self, data: Dict[str, str]) -> Dict[str, str]:
"""
接受登录消息并处理
处理简道云插件发送的登录请求,执行登录并返回结果。
Args:
data: 包含用户名、密码、公司名称的字典
Returns:
Dict[str, str]: 登录结果,包含状态信息
"""
username = data['username']
password = data['password']
company_name = data['company_name']
res = self.login_in(username, password, company_name)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
json = res.json()
url = 'https://yunxiu.f6car.cn/hive/company/getGroupName'
res1 = requests.get(url=url, cookies=cookies)
data1 = res1.json()
if data1['code'] == 200:
if data1['data'] == company_name:
if json['status'] == 'success':
json['status'] = '登录成功'
elif json['status'] == 'Error':
json['status'] = '登录失败,请检查账号密码'
else:
json['status'] = '公司名称不正确或未选择公司名称,请重试'
else:
json['status'] = '请输入正确的账号密码并选择公司名称'
return json
else:
return {"status": "登录失败,请检查公司名称"}
def get_company_information(self, data: Dict[str, str]) -> Dict[str, str]:
"""
获取公司信息
根据用户名和密码获取 F6 系统中的公司信息,并将结果保存到简道云。
Args:
data: 包含用户名、密码的字典
Returns:
Dict[str, str]: 包含时间戳的消息,用于后续查询
"""
username = data['username']
password = data['password']
timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
print(username)
url = "https://yunxiu.f6car.com/kzf6/login/confirm"
session = requests.Session()
header = {
'Referer': url,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
}
data = {
'username': username,
'password': hashlib.md5(password.encode('utf-8')).hexdigest(),
}
try:
res = session.post(url=url, headers=header, data=data)
res_json = res.json()
if res_json.get('message') == '请输入图形验证码':
pass
jiandaoyun_data = {'api_key': '6694d3c4fcb69ca9a111a6c4', 'entry_id': '6736e2112ad50045f041a827'}
if res_json.get("data") is None:
print('单店')
res = self.login_in(username, password)
if res is not None:
cookies = requests.utils.dict_from_cookiejar(res.cookies)
url = 'https://yunxiu.f6car.cn/hive/company/getGroupName'
res = requests.get(url=url, cookies=cookies)
data = res.json()
store_name = data['data']
jiandaoyun_data['data_list'] = [
{"_widget_1731650067055": {"value": f'{username}{password}{timestamp}'},
"_widget_1731650067056": {"value": f"{store_name}"}}]
api_instance.entry_data_batch_create(jiandaoyun_data)
res = {'msg': f'{username}{password}{timestamp}'}
else:
jiandaoyun_data_list = []
for group in res_json.get('data', []):
append_data = {"_widget_1731650067055": {"value": f'{username}{password}{timestamp}'},
"_widget_1731650067056": {"value": f"{group['groupName']}"}}
jiandaoyun_data_list.append(append_data)
jiandaoyun_data['data_list'] = jiandaoyun_data_list
res = api_instance.entry_data_batch_create(jiandaoyun_data)
print(res)
res = {'msg': f'{username}{password}{timestamp}'}
return res
except Exception as e:
print(f"获取公司名称失败: {e}")
res = {'msg': '获取公司名称失败,请重新获取'}
return res
def get_store_information(self, data: Dict[str, str]) -> Dict[str, dict[str, str]]:
"""
获取门店信息
根据用户名、密码和公司名称获取 F6 系统中的门店信息,
包括门店列表、客户车辆数量、客户数量等。
Args:
data: 包含用户名、密码、公司名称的字典
Returns:
Dict[str, dict[str, str]]: 包含时间戳、门店信息、统计数据的结果
"""
username = data['username']
password = data['password']
company_name = data['company_name']
timestamp = datetime.now().strftime("%Y-%m-%d %H-%M-%S")
login_response = self.login_in(username, password, company_name)
if login_response is None:
return {"msg": {'msg': '未执行', 'msg_details': '登录失败'}}
cookies = requests.utils.dict_from_cookiejar(login_response.cookies)
url = 'https://yunxiu.f6car.cn/hive/org/getPageOrgGroupMembers?currentPage=1&pageSize=100&name='
res = requests.get(url=url, cookies=cookies)
data = res.json()
org_lists = data['data']['list']
url = 'https://yunxiu.f6car.cn/member/car/carListForPermission'
json = {"pageSize": 10, "pageNo": 1}
car_res = requests.post(url=url, json=json, cookies=cookies)
total_cars_data = car_res.json()
total_cars = total_cars_data['data']['total']
url = 'https://yunxiu.f6car.cn/member/customer/listForPermission?pageSize=10&pageNo=1'
customer_res = requests.get(url=url, cookies=cookies)
total_customer_data = customer_res.json()
total_customer = total_customer_data['data']['total']
jiandaoyun_data = {'api_key': '6694d3c4fcb69ca9a111a6c4',
'entry_id': '673c38ccca57a5cf266eb18c'}
jiandaoyun_data_list = []
for org in org_lists:
append_data = {"_widget_1731999948708": {"value": f'{username}{password}{company_name}{timestamp}'},
"_widget_1731999948709": {"value": f"{org['orgName']}"}}
jiandaoyun_data_list.append(append_data)
jiandaoyun_data['data_list'] = jiandaoyun_data_list
api_instance.entry_data_batch_create(jiandaoyun_data)
res = {'msg': {"msg": f'{username}{password}{company_name}{timestamp}',
"total_cars": f"{total_cars}条客户车辆",
"total_customer": f"{total_customer}条客户"}}
return res
@staticmethod
def get_keep_heart(data: Dict[str, str]) -> Dict[str, str]:
"""
保持连接
用于保持连接的心跳检测,直接返回接收到的数据。
Args:
data: 接收到的数据字典
Returns:
Dict[str, str]: 原样返回接收到的数据
"""
return data