Commit 07a54ea1 authored by wushanjing's avatar wushanjing

补齐智能接单页面支持

parent 98fbb8ed
......@@ -43,6 +43,7 @@ class ManualOrderData:
dispatch_price: str = "70"
dispatch_price_mode: str = "percent"
dispatch_price_percent: str = "90"
sub_order_title: str = ""
service_hours: str = "14"
boss_phone: str = "13800138000"
contact_phone: str = "13800138000"
......@@ -4155,7 +4156,7 @@ class WanzhangguiOrderPage(TenantAuthPage):
except Exception as exc:
raise AssertionError(f"未找到可填写的子单信息行;modal_fields={self.modal_field_values(frame)}") from exc
self.fill_row_input(row, "请输入订单标题", order.order_title)
self.fill_row_input(row, "请输入订单标题", order.sub_order_title or order.order_title)
if price_mode == "percent":
self.fill_row_input_any(row, ["请输入价格百分比", "价格百分比", "请输入百分比", "百分比"], price_value)
else:
......@@ -4383,7 +4384,7 @@ class WanzhangguiOrderPage(TenantAuthPage):
};
}""",
{
"orderTitle": order.order_title,
"orderTitle": order.sub_order_title or order.order_title,
"strategyName": order.strategy_name,
"priceMode": price_mode,
"priceLabel": "百分比发单价" if price_mode == "percent" else "固定发单价",
......@@ -9219,6 +9220,156 @@ class WanyoujiFulfillmentPage(TenantAuthPage):
)
return frame
def ensure_auto_accept_assignment(self, merchant_name: str, enabled: bool) -> str:
frame = self.open_auto_accept_assignment_config()
self.search_auto_accept_assignment(frame, merchant_name)
row_text = self.auto_accept_assignment_row_text(frame, merchant_name)
if self.auto_accept_assignment_enabled_from_row(row_text) == enabled:
return row_text
action_texts = ["开启自动接单", "开启智能接单", "开启接单", "启用"] if enabled else [
"关闭自动接单",
"关闭智能接单",
"关闭接单",
"停用",
]
clicked = self.click_auto_accept_assignment_action(frame, merchant_name, action_texts)
assert clicked, (
f"智能接单配置列表未找到切换操作;merchant={merchant_name}; expected_enabled={enabled}; "
f"row_text={row_text}; text={frame.locator('body').inner_text(timeout=5000)[:1500]}"
)
self.confirm_open_dialog(frame)
self.page.wait_for_timeout(2500)
self.search_auto_accept_assignment(frame, merchant_name)
row_text = self.auto_accept_assignment_row_text(frame, merchant_name)
assert self.auto_accept_assignment_enabled_from_row(row_text) == enabled, (
f"智能接单开关切换后不符合预期;merchant={merchant_name}; expected={enabled}; row_text={row_text}"
)
return row_text
def open_auto_accept_assignment_config(self) -> Frame:
self.goto(WANYOUJI_CONSOLE_URL)
self.wait_for_enterprise_console_shell()
menu_paths = [
("工作室履约应用", "智能接单配置"),
("工作室履约应用", "自动接单配置"),
("工作室履约应用", "接单配置"),
("工作室履约应用", "接单设置"),
("工作室管理", "智能接单配置"),
("工作室管理", "自动接单配置"),
("工作室管理", "接单配置"),
]
for parent_text, child_text in menu_paths:
try:
self.click_sidebar_text(parent_text, right_edge=True)
except AssertionError:
self.click_sidebar_visible_text(parent_text, right_edge=True) or self.click_left_sidebar_text_contains(parent_text, right_edge=True)
self.page.wait_for_timeout(700)
if self.click_sidebar_visible_text(child_text) or self.click_left_sidebar_text_contains(child_text):
self.page.wait_for_timeout(2500)
self.retry_if_app_load_timeout()
return self.best_wanyouji_frame(["自动接单", "智能接单", "接单配置", "商家", "工作室"])
page_text = self.page.locator("body").inner_text(timeout=5000)
raise AssertionError(f"未找到丸友集智能接单配置入口;text={page_text[:1500]}")
def search_auto_accept_assignment(self, frame: Frame, merchant_name: str) -> None:
last_text = ""
for attempt in range(4):
if attempt:
self.click_optional_text(frame, "重 置") or self.click_optional_text(frame, "重置")
self.page.wait_for_timeout(800)
filled = False
for label in ["商家名称", "上游商家", "店铺名称", "工作室名称", "供应链名称", "关键字"]:
if self.fill_input_near_label(frame, label, merchant_name):
filled = True
break
if not filled:
inputs = frame.locator("input:visible")
if inputs.count():
inputs.first.fill(merchant_name)
filled = True
if filled and not (self.click_optional_text(frame, "查 询") or self.click_optional_text(frame, "查询")):
frame.locator("input:visible").first.press("Enter")
self.page.wait_for_timeout(1800 + attempt * 600)
last_text = frame.locator("body").inner_text(timeout=5000)
if merchant_name in last_text:
return
raise AssertionError(f"智能接单配置搜索后未找到商家:{merchant_name};text={last_text[:1500]}")
def auto_accept_assignment_row_text(self, frame: Frame, merchant_name: str) -> str:
for _ in range(4):
row_text = str(
frame.evaluate(
"""merchantName => {
const rows = Array.from(document.querySelectorAll('tbody tr, .ant-table-row, [class*="table"] [class*="row"]'))
.map(row => ({ text: (row.innerText || row.textContent || '').trim(), r: row.getBoundingClientRect() }))
.filter(item => item.r.width > 0 && item.r.height > 0)
.filter(item => item.text.includes(merchantName));
return rows[0]?.text || '';
}""",
merchant_name,
)
)
if row_text:
return row_text
self.page.wait_for_timeout(1000)
raise AssertionError(
f"智能接单配置列表未找到商家:{merchant_name};text={frame.locator('body').inner_text(timeout=5000)[:1500]}"
)
@staticmethod
def auto_accept_assignment_enabled_from_row(row_text: str) -> bool:
compact = re.sub(r"\s+", "", row_text or "")
if any(key in compact for key in ["关闭自动接单", "关闭智能接单", "关闭接单", "已开启", "开启中"]):
return True
if any(key in compact for key in ["开启自动接单", "开启智能接单", "开启接单", "已关闭", "未开启"]):
return False
lines = [line.strip() for line in row_text.splitlines() if line.strip()]
for index, line in enumerate(lines):
if any(key in line for key in ["自动接单", "智能接单", "是否开启"]):
nearby = "".join(lines[index : index + 3])
if "是" in nearby or "开启" in nearby:
return True
if "否" in nearby or "关闭" in nearby:
return False
return False
def click_auto_accept_assignment_action(self, frame: Frame, merchant_name: str, action_texts: list[str]) -> bool:
clicked = frame.evaluate(
"""({ merchantName, actionTexts }) => {
const visible = el => {
const r = el.getBoundingClientRect();
return r.width > 0 && r.height > 0;
};
const rows = Array.from(document.querySelectorAll('tbody tr, .ant-table-row, [class*="table"] [class*="row"]'))
.map(row => ({ row, text: (row.innerText || row.textContent || '').trim(), r: row.getBoundingClientRect() }))
.filter(item => item.r.width > 0 && item.r.height > 0)
.filter(item => item.text.includes(merchantName));
const row = rows[0]?.row;
if (!row) return false;
const nodes = Array.from(row.querySelectorAll('button, a, span, [role="button"]'))
.map(el => ({ el, text: (el.innerText || el.textContent || '').trim(), r: el.getBoundingClientRect() }))
.filter(item => visible(item.el));
for (const actionText of actionTexts) {
const target = nodes.find(item => item.text === actionText) ||
nodes.find(item => item.text.includes(actionText));
if (!target) continue;
const clickable = target.el.closest('button, a, [role="button"]') || target.el;
const r = target.r;
clickable.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, clientX: r.x + r.width / 2, clientY: r.y + r.height / 2 }));
clickable.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, clientX: r.x + r.width / 2, clientY: r.y + r.height / 2 }));
clickable.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, clientX: r.x + r.width / 2, clientY: r.y + r.height / 2 }));
clickable.click();
return true;
}
return false;
}""",
{"merchantName": merchant_name, "actionTexts": action_texts},
)
self.page.wait_for_timeout(1000)
return bool(clicked)
def open_workshop_appeal_work_order(self) -> Frame:
self.goto(WANYOUJI_CONSOLE_URL)
self.wait_for_enterprise_console_shell()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment