296 lines
11 KiB
Python
296 lines
11 KiB
Python
import os
|
|
import random
|
|
import time
|
|
|
|
import cv2
|
|
from loguru import *
|
|
from DrissionPage import *
|
|
|
|
|
|
class Acb:
|
|
def __init__(self, a=None):
|
|
self.local_port = 9999
|
|
self.tmp_path = "本田/tmp" # 临时文件存储路径
|
|
self.user_data_path = "本田/user_data" # 用户数据存储路径
|
|
self.cache_path = "本田/cache_path" # 存储数据路径
|
|
|
|
self.a = a # 数据
|
|
|
|
def take_over_browser(self):
|
|
try:
|
|
self.options = ChromiumOptions()
|
|
|
|
self.options.set_local_port(self.local_port)
|
|
self.options.set_tmp_path(self.tmp_path)
|
|
self.options.set_cache_path(self.cache_path)
|
|
self.options.set_user_data_path(self.user_data_path)
|
|
|
|
self.page = ChromiumPage(addr_or_opts=self.options)
|
|
|
|
self.page.set.window.max()
|
|
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
def get_size(self):
|
|
# 定义图片文件路径
|
|
bg_file_path = './0.jpg'
|
|
tp_file_path = './1.jpg'
|
|
|
|
# 检查背景图片文件是否存在
|
|
if not os.path.exists(bg_file_path):
|
|
print(f"背景图片文件 {bg_file_path} 不存在,请检查文件路径。")
|
|
else:
|
|
# 读取背景图片
|
|
bg_img = cv2.imread(bg_file_path)
|
|
if bg_img is None:
|
|
print(f"无法读取背景图片文件 {bg_file_path},请检查文件完整性。")
|
|
else:
|
|
# 检查缺口图片文件是否存在
|
|
if not os.path.exists(tp_file_path):
|
|
print(f"缺口图片文件 {tp_file_path} 不存在,请检查文件路径。")
|
|
else:
|
|
# 读取缺口图片
|
|
tp_img = cv2.imread(tp_file_path)
|
|
if tp_img is None:
|
|
print(f"无法读取缺口图片文件 {tp_file_path},请检查文件完整性。")
|
|
else:
|
|
# 识别图片边缘
|
|
bg_edge = cv2.Canny(bg_img, 100, 200)
|
|
tp_edge = cv2.Canny(tp_img, 100, 200)
|
|
|
|
# 转换图片格式
|
|
bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
|
|
tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)
|
|
|
|
# 缺口匹配
|
|
res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
|
|
# 寻找最优匹配
|
|
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
|
|
# 左上角点的坐标
|
|
tl = max_loc
|
|
return tl[0]
|
|
|
|
# ---------- 工具函数 ----------
|
|
|
|
def safe_click(self, xpath: str, timeout: float = 10):
|
|
ele = self.tab.ele(xpath, timeout=timeout)
|
|
if ele:
|
|
ele.click()
|
|
else:
|
|
logger.warning(f"元素未找到:{xpath}")
|
|
|
|
def safe_input(self, xpath: str, value: str, clear=True, timeout: float = 10):
|
|
ele = self.tab.ele(xpath, timeout=timeout)
|
|
if ele:
|
|
ele.input(value, clear=clear)
|
|
else:
|
|
logger.warning(f"输入框未找到:{xpath}")
|
|
|
|
def click_label(self, label: str):
|
|
self.safe_click(f'x:(//div[@labelname="{label}"])[last()]')
|
|
|
|
def select_option(self, label: str, text: str):
|
|
self.click_label(label)
|
|
self.safe_click(f'x:(//span[normalize-space(text()) = "{text}"])[last()]')
|
|
|
|
# ---------- 表单填写 ----------
|
|
|
|
def fill_basic_info(self):
|
|
d = self.a
|
|
logger.info("开始填写基础字段...")
|
|
|
|
# 统一定义要循环处理的字段:类型 + 操作方式
|
|
option_fields = [
|
|
("工单类型", "工单类型"),
|
|
("维修类型", "维修类型"),
|
|
("二级维修类型", "二级维修类型"),
|
|
("送修保险公司", "送修保险公司"),
|
|
("是否全钣喷", "是否全钣喷"),
|
|
("三日电访时间", "三日电访时间")
|
|
]
|
|
input_fields = [
|
|
("进厂行驶里程", "进厂行驶里程"),
|
|
("出厂行驶里程", "出厂行驶里程"),
|
|
("报案号", "报案号")
|
|
]
|
|
|
|
# 循环选择项
|
|
for label, key in option_fields:
|
|
if key in d:
|
|
self.select_option(label, d[key])
|
|
logger.debug(f"选择 {label} → {d[key]}")
|
|
|
|
# 循环输入项
|
|
for label, key in input_fields:
|
|
if key in d:
|
|
self.safe_input(f'x:(//input[@labelname="{label}"])[last()]', d[key])
|
|
logger.debug(f"输入 {label} → {d[key]}")
|
|
|
|
# 预计交车时间特殊处理
|
|
if "预计交车时间" in d:
|
|
self.safe_click('x:(//div[@labelname="预计交车时间"])')
|
|
date, t = d["预计交车时间"].split()
|
|
self.safe_input('x:(//input[@placeholder="选择日期"])', date)
|
|
self.safe_input('x:(//input[@placeholder="选择时间"])', t)
|
|
self.safe_click('x:(//span[normalize-space(text()) = "确定"])[last()]')
|
|
logger.debug(f"设置预计交车时间 → {d['预计交车时间']}")
|
|
|
|
# ---------- 添加项目 ----------
|
|
|
|
def add_projects(self):
|
|
logger.info("开始添加维修项目...")
|
|
for i, proj in enumerate(self.a.get("项目", []), start=1):
|
|
if proj["项目类型"] == "工时":
|
|
self.add_work_project(i, proj)
|
|
else:
|
|
self.add_part_project(i, proj)
|
|
|
|
def add_work_project(self, idx, data):
|
|
tab = self.tab
|
|
logger.info(f"添加工时项目:{data['维修项目']}")
|
|
self.safe_click('x:(//span[text() = "维修项目"])[last()]')
|
|
self.safe_input('x:(//input[@labelname="维修项目名称"])', data["维修项目"])
|
|
self.safe_input('x:(//input[@labelname="车型组"])', "", clear=True)
|
|
self.safe_click('x:(//span[normalize-space(text()) = "查询"])[last()]')
|
|
self.safe_click(f'x:(//span[normalize-space(text()) = "{data["车型分组代码"]}"])[last()]')
|
|
self.safe_click('x:(//span[normalize-space(text()) = "确认"])[last()]')
|
|
|
|
row = tab.ele(f'x://*[@id="MicroAppMain"]/div/div[1]/div[7]/div[3]/table/tbody/tr[{idx}]')
|
|
if row:
|
|
row.ele('x:./td[8]/div/div/input').input(data["数量"], clear=True)
|
|
row.ele('x:./td[10]/div/div/div/input').click()
|
|
self.safe_click(f'x:(//span[normalize-space(text()) = "{data["工时单价"]}"])[last()]')
|
|
else:
|
|
logger.warning(f"未找到第 {idx} 行工时项目")
|
|
|
|
def add_part_project(self, idx, data):
|
|
tab = self.tab
|
|
logger.info(f"添加零部件项目:{data['维修项目']}")
|
|
self.safe_click('x:(//span[text() = "手动选择零部件"])[last()]')
|
|
self.safe_input(
|
|
'x://*[@id="app"]/div[4]/div/div[2]/div/div/div[1]/div/section/form/div/div/div[4]/div/div/section/div/div/div/div[1]/input',
|
|
data["维修项目"]
|
|
)
|
|
self.safe_click('x:(//span[normalize-space(text()) = "查询"])[last()]')
|
|
self.safe_click(f'x:(//span[normalize-space(text()) = "{data["零部件代码"]}"])[last()]')
|
|
self.safe_click('x://*[@id="app"]/div[4]/div/div[2]/div/div/div[2]/button[1]')
|
|
self.safe_click('x:(//span[normalize-space(text()) = "确认"])[last()]')
|
|
|
|
row = tab.ele(f'x://*[@id="MicroAppMain"]/div/div[1]/div[7]/div[3]/table/tbody/tr[{idx}]')
|
|
if row:
|
|
row.ele('x:./td[8]/div/div/input').input(data["数量"], clear=True)
|
|
else:
|
|
logger.warning(f"未找到第 {idx} 行零部件项目")
|
|
|
|
def action(self):
|
|
|
|
# 接管浏览器
|
|
if self.take_over_browser():
|
|
logger.info("接管浏览器浏览器成功!!!")
|
|
else:
|
|
logger.error("接管浏览器失败!!!")
|
|
return
|
|
|
|
self.tab = self.page.new_tab(
|
|
url="https://bcp.dongfeng-honda.com/#/dop/dop/partsStorage/serviceReception/customerReception")
|
|
dl_ele = self.tab.ele('x:(//span[normalize-space(text()) = "登录"])[last()]', timeout=10)
|
|
if dl_ele:
|
|
self.tab.listen.start(targets="data:image/jpg;base64") # 抓包图片
|
|
|
|
self.tab.ele('x:(//input[@placeholder="用户名/手机号"])[last()]').input(vals="WD20098746", clear=True)
|
|
time.sleep(1)
|
|
self.tab.ele('x:(//input[@placeholder="密码"])[last()]').input(vals="", clear=True)
|
|
self.tab.ele('x:(//input[@placeholder="密码"])[last()]').input(vals="Zhengxifeng12")
|
|
time.sleep(3)
|
|
|
|
dl_ele.click()
|
|
|
|
for _, i in enumerate(self.tab.listen.wait(count=2)):
|
|
with open(f'./{_}.jpg', 'wb') as f:
|
|
f.write(i.response.body)
|
|
|
|
AA = self.get_size()
|
|
|
|
# 左键按住 滑标 元素
|
|
self.tab.actions.hold('@id=cutImage')
|
|
AA = AA + 5
|
|
self.tab.actions.right(AA)
|
|
# 模拟人的行为 移动过去,再移动回来
|
|
self.tab.actions.right(5)
|
|
time.sleep(random.randint(1, 3))
|
|
self.tab.actions.left(5)
|
|
time.sleep(random.randint(1, 3))
|
|
# 释放左键
|
|
self.tab.actions.release()
|
|
|
|
# 查询
|
|
self.tab = self.page.new_tab(
|
|
url="https://bcp.dongfeng-honda.com/#/dop/dop/partsStorage/serviceReception/customerReception")
|
|
time.sleep(5)
|
|
self.tab.ele('x://span[text()="新建"]', timeout=15).click()
|
|
time.sleep(1)
|
|
|
|
self.tab.ele('x:(//input[@labelname="VIN码"])[last()]').input("LVHCU8610S5010882")
|
|
time.sleep(1)
|
|
self.tab.ele('x:(//span[text()="查询"])[last()]').click()
|
|
time.sleep(3)
|
|
xx_ele = self.tab.ele('x:(//span[normalize-space(text()) = "选择"])[last()]', timeout=10)
|
|
if xx_ele:
|
|
xx_ele.click()
|
|
else:
|
|
logger.error("车辆不存在!!!")
|
|
return
|
|
|
|
try:
|
|
self.fill_basic_info()
|
|
self.add_projects()
|
|
logger.success("✅ 工单填写完成")
|
|
except Exception as e:
|
|
logger.exception(f"工单填写失败:{e}")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
a = {
|
|
"工单类型": "保修",
|
|
"VIN码": "LVHCU8610S5010882",
|
|
"维修类型": "PDI",
|
|
"二级维修类型": "检查",
|
|
"进厂行驶里程": 154546,
|
|
"出厂行驶里程": 1578164,
|
|
"预计交车时间": "2025-11-05 15:35",
|
|
"送修保险公司": "太平财险",
|
|
"报案号": "r5hrhjththtth",
|
|
"是否全钣喷": "是",
|
|
"三日电访时间": "上午",
|
|
"项目": [
|
|
{
|
|
"项目类型": "工时",
|
|
"维修项目/零部件名称": "更换手变速箱油",
|
|
"数量/工时": 4.5,
|
|
"工时单价": 80,
|
|
"车型分组代码": "FA1",
|
|
},
|
|
{
|
|
"项目类型": "工时",
|
|
"维修项目/零部件名称": "燃油滤清器-更换",
|
|
"数量/工时": 4.5,
|
|
"工时单价": 80,
|
|
"车型分组代码": "QTCX",
|
|
},
|
|
{
|
|
"项目类型": "材料",
|
|
"维修项目/零部件名称": "后装饰件卡扣",
|
|
"数量/工时": 4.5,
|
|
"工时单价": 80,
|
|
"车型分组代码": "QTCX",
|
|
"零部件代码": "91561-TA5-A11",
|
|
}
|
|
]
|
|
}
|
|
|
|
Acb(
|
|
a=a,
|
|
).action()
|