python-qlv-helper 0.2.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,275 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ # ---------------------------------------------------------------------------------------------------------
4
+ # ProjectName: qlv-helper
5
+ # FileName: order_detail_page.py
6
+ # Description: 订单详情页面对象
7
+ # Author: ASUS
8
+ # CreateDate: 2025/12/16
9
+ # Copyright ©2011-2025. Hunan xxxxxxx Company limited. All rights reserved.
10
+ # ---------------------------------------------------------------------------------------------------------
11
+ """
12
+ from typing import Dict, Any, List, Tuple
13
+ from playwright.async_api import Page, Locator
14
+ from playwright_helper.libs.base_po import BasePo
15
+ from qlv_helper.config.url_const import order_detail_url
16
+
17
+
18
+ class OrderDetailPage(BasePo):
19
+ url: str = order_detail_url
20
+ __page: Page
21
+
22
+ def __init__(self, page: Page, url: str = order_detail_url) -> None:
23
+ super().__init__(page, url)
24
+ self.url = url
25
+ self.__page = page
26
+
27
+ async def get_order_lock_state_btn(self, timeout: float = 5.0) -> Tuple[str, Locator]:
28
+ """
29
+ 订单详情页面,获取订单锁单状态按钮
30
+ :param timeout: 超时时间(秒)
31
+ :return: (是否存在, 错误信息|元素对象)
32
+ """
33
+ selector: str = '//div[@class="order_information "]//a[(@class="view_detail_red" and contains(text(), "强制解锁")) or (@class="view_detail_green" and (contains(text(), "锁定") or contains(text(), "解锁返回") or contains(text(), "操作")))]'
34
+ locator: Locator = await self.get_locator(selector=selector, timeout=timeout)
35
+ text: str = (await locator.inner_text()).strip()
36
+ return text, locator
37
+
38
+ async def get_out_ticket_platform_type_dropdown(self, timeout: float = 5.0) -> Locator:
39
+ """
40
+ 订单详情页面,采购信息栏,获取出票地类型下拉菜单按钮
41
+ :param timeout: 超时时间(秒)
42
+ :return: (是否存在, 错误信息|元素对象)
43
+ """
44
+ selector: str = '//table[@id="PurchaseInfos"]//select[@id="OutTktPFTypeID"]'
45
+ return await self.get_locator(selector=selector, timeout=timeout)
46
+
47
+ async def get_out_ticket_platform_type_select_option(self, select_option: str, timeout: float = 5.0) -> Locator:
48
+ """
49
+ 订单详情页面,采购信息栏,获取出票地类型下拉菜单选项
50
+ :param select_option: 要获取的选项
51
+ :param timeout: 超时时间(秒)
52
+ :return: (是否存在, 错误信息|元素对象)
53
+ """
54
+ selector: str = f'//table[@id="PurchaseInfos"]//select[@id="OutTktPFTypeID"]/option[contains(text(), "{select_option}")]'
55
+ return await self.get_locator(selector=selector, timeout=timeout)
56
+
57
+ async def get_out_ticket_platform_dropdown(self, timeout: float = 5.0) -> Locator:
58
+ """
59
+ 订单详情页面,采购信息栏,获取出票平台下拉菜单按钮
60
+ :param timeout: 超时时间(秒)
61
+ :return: (是否存在, 错误信息|元素对象)
62
+ """
63
+ selector: str = '//table[@id="PurchaseInfos"]//select[@id="OutTktPF"]'
64
+ return await self.get_locator(selector=selector, timeout=timeout)
65
+
66
+ async def get_out_ticket_platform_select_option(self, select_option: str, timeout: float = 5.0) -> Locator:
67
+ """
68
+ 订单详情页面,采购信息栏,获取出票平台下拉菜单选项
69
+ :param select_option: 要获取的选项
70
+ :param timeout: 超时时间(秒)
71
+ :return: (是否存在, 错误信息|元素对象)
72
+ """
73
+ selector: str = f'//table[@id="PurchaseInfos"]//select[@id="OutTktPF"]/option[contains(text(), "{select_option}")]'
74
+ return await self.get_locator(selector=selector, timeout=timeout)
75
+
76
+ async def get_out_ticket_account_dropdown(self, timeout: float = 5.0) -> Locator:
77
+ """
78
+ 订单详情页面,采购信息栏,获取出票账号下拉菜单按钮
79
+ :param timeout: 超时时间(秒)
80
+ :return: (是否存在, 错误信息|元素对象)
81
+ """
82
+ selector: str = '//table[@id="PurchaseInfos"]//select[@id="AccountNumber"]'
83
+ return await self.get_locator(selector=selector, timeout=timeout)
84
+
85
+ async def get_out_ticket_account_select_option(self, select_option: str, timeout: float = 5.0) -> Locator:
86
+ """
87
+ 订单详情页面,采购信息栏,获取出票账号下拉菜单选项
88
+ :param select_option: 要获取的选项
89
+ :param timeout: 超时时间(秒)
90
+ :return: (是否存在, 错误信息|元素对象)
91
+ """
92
+ selector: str = f'//table[@id="PurchaseInfos"]//select[@id="AccountNumber"]/option[contains(text(), "{select_option}")]'
93
+ return await self.get_locator(selector=selector, timeout=timeout)
94
+
95
+ async def get_purchase_account_type_dropdown(self, timeout: float = 5.0) -> Locator:
96
+ """
97
+ 订单详情页面,采购信息栏,获取采购账号类型下拉菜单按钮
98
+ :param timeout: 超时时间(秒)
99
+ :return: (是否存在, 错误信息|元素对象)
100
+ """
101
+ selector: str = '//table[@id="PurchaseInfos"]//select[@id="TypeName"]'
102
+ return await self.get_locator(selector=selector, timeout=timeout)
103
+
104
+ async def get_purchase_account_type_select_option(self, select_option: str, timeout: float = 5.0) -> Locator:
105
+ """
106
+ 订单详情页面,采购信息栏,获取采购账号类型下拉菜单选项
107
+ :param select_option: 要获取的选项
108
+ :param timeout: 超时时间(秒)
109
+ :return: (是否存在, 错误信息|元素对象)
110
+ """
111
+ selector: str = f'//table[@id="PurchaseInfos"]//select[@id="TypeName"]/option[contains(text(), "{select_option}")]'
112
+ return await self.get_locator(selector=selector, timeout=timeout)
113
+
114
+ async def get_purchase_account_dropdown(self, timeout: float = 5.0) -> Locator:
115
+ """
116
+ 订单详情页面,采购信息栏,获取采购账号下拉菜单按钮
117
+ :param timeout: 超时时间(秒)
118
+ :return: (是否存在, 错误信息|元素对象)
119
+ """
120
+ selector: str = '//table[@id="PurchaseInfos"]//select[@id="PurchaseAccount"]'
121
+ return await self.get_locator(selector=selector, timeout=timeout)
122
+
123
+ async def get_purchase_account_select_option(self, select_option: str, timeout: float = 5.0) -> Locator:
124
+ """
125
+ 订单详情页面,采购信息栏,获取采购账号下拉菜单选项
126
+ :param select_option: 要获取的选项
127
+ :param timeout: 超时时间(秒)
128
+ :return: (是否存在, 错误信息|元素对象)
129
+ """
130
+ selector: str = f'//table[@id="PurchaseInfos"]//select[@id="PurchaseAccount"]/option[contains(text(), "{select_option}")]'
131
+ return await self.get_locator(selector=selector, timeout=timeout)
132
+
133
+ async def get_purchase_amount_input(self, timeout: float = 5.0) -> Locator:
134
+ """
135
+ 订单详情页面,采购信息栏,获取采购金额输入框
136
+ :param timeout: 超时时间(秒)
137
+ :return: (是否存在, 错误信息|元素对象)
138
+ """
139
+ selector: str = '//table[@id="PurchaseInfos"]//input[@id="TransactionAmount"]'
140
+ return await self.get_locator(selector=selector, timeout=timeout)
141
+
142
+ async def get_remark_input(self, timeout: float = 5.0) -> Locator:
143
+ """
144
+ 订单详情页面,采购信息栏,获取备注输入框,一般输入登录官网的"账号/密码"
145
+ :param timeout: 超时时间(秒)
146
+ :return: (是否存在, 错误信息|元素对象)
147
+ """
148
+ selector: str = '//table[@id="PurchaseInfos"]//input[@id="Remark"]'
149
+ return await self.get_locator(selector=selector, timeout=timeout)
150
+
151
+ async def get_main_check_input(self, timeout: float = 5.0) -> Locator:
152
+ """
153
+ 订单详情页面,采购信息栏,获取对账标识输入框,一般输入虚拟卡的card_id
154
+ :param timeout: 超时时间(秒)
155
+ :return: (是否存在, 错误信息|元素对象)
156
+ """
157
+ selector: str = '//table[@id="PurchaseInfos"]//input[@id="MainCheckNumber"]'
158
+ return await self.get_locator(selector=selector, timeout=timeout)
159
+
160
+ async def get_air_comp_order_id_input(self, timeout: float = 5.0) -> Locator:
161
+ """
162
+ 订单详情页面,采购信息栏,获取官网订单号输入框
163
+ :param timeout: 超时时间(秒)
164
+ :return: (是否存在, 错误信息|元素对象)
165
+ """
166
+ selector: str = '//table[@id="PurchaseInfos"]//input[@id="AirCoOrderID"]'
167
+ return await self.get_locator(selector=selector, timeout=timeout)
168
+
169
+ async def get_procurement_info_save_btn(self, timeout: float = 5.0) -> Locator:
170
+ """
171
+ 订单详情页面,采购信息栏,获取【保存采购】按钮
172
+ :param timeout: 超时时间(秒)
173
+ :return: (是否存在, 错误信息|元素对象)
174
+ """
175
+ selector: str = '//table[@id="PurchaseInfos"]//input[@id="submit"]'
176
+ return await self.get_locator(selector=selector, timeout=timeout)
177
+
178
+ async def get_passenger_itinerary_locators(self, timeout: float = 5.0) -> List[Dict[str, Any]]:
179
+ """
180
+ 订单详情页面,乘客信息栏,获取票号输入框
181
+ :param timeout:超时时间(秒)
182
+ :return: List[{
183
+ "username": str,
184
+ "id_number": str,
185
+ "locator": Locator # 指向 <input name="ticketNo">
186
+ }]
187
+ """
188
+ results = list()
189
+ tbody_selector: str = '(//div[@class="order_information"]//table[@class="table table_border table_center"]/tbody)[3]'
190
+ tbody_locator: Locator = await self.get_locator(selector=tbody_selector, timeout=timeout)
191
+ # 只选真正的数据行(有 pid / ticketNo 的 tr)
192
+ rows = tbody_locator.locator("tr[pid]")
193
+ row_count = await rows.count()
194
+ for i in range(row_count):
195
+ row = rows.nth(i)
196
+
197
+ out_ticket_state: Locator = await self.get_sub_locator(
198
+ locator=row, selector='xpath=(.//td)[1]', timeout=timeout
199
+ )
200
+ out_ticket_state_text = (await out_ticket_state.inner_text()).strip()
201
+ if "已出票" in out_ticket_state_text:
202
+ continue
203
+
204
+ # 1️⃣ 用户名
205
+ name_locator = await self.get_sub_locator(
206
+ locator=row, selector='xpath=.//span[@name="pname"]', timeout=timeout
207
+ )
208
+ username = (await name_locator.first.inner_text()).strip()
209
+
210
+ # 2️⃣ 身份证号
211
+ # a 标签里:javascript:showIDNo('身份证号', ...)
212
+ id_link = await self.get_sub_locator(locator=row, selector='xpath=.//a[starts-with(@id, "IDNo_")]',
213
+ timeout=timeout)
214
+
215
+ href = await id_link.first.get_attribute("href")
216
+ # href 示例:
217
+ # javascript:showIDNo('320324198511254466','175687',...)
218
+
219
+ id_number = None
220
+ if href:
221
+ # 非正则版本,更安全
222
+ start = href.find("'") + 1
223
+ end = href.find("'", start)
224
+ id_number = href[start:end]
225
+
226
+ # 3️⃣ ticketNo 输入框 locator
227
+ ticket_input = await self.get_sub_locator(locator=row, selector='xpath=.//input[@name="ticketNo"]',
228
+ timeout=timeout)
229
+
230
+ # 防御性校验(可选)
231
+ if await ticket_input.count() == 0:
232
+ continue
233
+
234
+ results.append({
235
+ "username": username,
236
+ "id_number": id_number,
237
+ "locator": ticket_input # Playwright Locator 对象
238
+ })
239
+ return results
240
+
241
+ async def get_custom_remark_input(self, timeout: float = 5.0) -> Locator:
242
+ """
243
+ 订单详情页面,日志记录栏,获取自定义备注输入框
244
+ :param timeout: 超时时间(秒)
245
+ :return: (是否存在, 错误信息|元素对象)
246
+ """
247
+ selector: str = '//input[@id="rmk"]'
248
+ return await self.get_locator(selector=selector, timeout=timeout)
249
+
250
+ async def get_custom_remark_save_btn(self, timeout: float = 5.0) -> Locator:
251
+ """
252
+ 订单详情页面,日志记录栏,获取【保存备注】按钮
253
+ :param timeout: 超时时间(秒)
254
+ :return: (是否存在, 错误信息|元素对象)
255
+ """
256
+ selector: str = '//a[@href="javascript:fnSaveRemark()"]'
257
+ return await self.get_locator(selector=selector, timeout=timeout)
258
+
259
+ async def get_message_notice_dialog_confirm_btn(self, timeout: float = 5.0) -> Locator:
260
+ """
261
+ 订单详情页面,消息提醒弹框,获取【确认】按钮
262
+ :param timeout: 超时时间(秒)
263
+ :return: (是否存在, 错误信息|元素对象)
264
+ """
265
+ selector: str = '//a[@id="alertMsg_btnConfirm"]/cite'
266
+ return await self.get_locator(selector=selector, timeout=timeout)
267
+
268
+ async def get_policy_input(self, timeout: float = 5.0) -> Locator:
269
+ """
270
+ 订单详情页面,获取政策代码输入框
271
+ :param timeout:
272
+ :return:
273
+ """
274
+ selector: str = '//legend//input[@name="PolicyName"]'
275
+ return await self.get_locator(selector=selector, timeout=timeout)
@@ -12,7 +12,7 @@
12
12
  import os
13
13
  import asyncio
14
14
  from typing import Tuple, Union
15
- from qlv_helper.po.base_po import BasePo
15
+ from playwright_helper.libs.base_po import BasePo
16
16
  from qlv_helper.utils.file_handle import get_caller_dir
17
17
  from qlv_helper.utils.windows_utils import gen_allow_btn_image, windows_on_click
18
18
  from playwright.async_api import Page, TimeoutError as PlaywrightTimeoutError, Locator
qlv_helper/po/base_po.py DELETED
@@ -1,40 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- # ---------------------------------------------------------------------------------------------------------
4
- # ProjectName: qlv-helper
5
- # FileName: base_po.py
6
- # Description: po对象基础类
7
- # Author: ASUS
8
- # CreateDate: 2025/11/25
9
- # Copyright ©2011-2025. Hunan xxxxxxx Company limited. All rights reserved.
10
- # ---------------------------------------------------------------------------------------------------------
11
- """
12
- from typing import List
13
- from playwright.async_api import Page
14
-
15
-
16
- class BasePo(object):
17
- __page: Page
18
-
19
- def __init__(self, page: Page, url: str):
20
- self.url = url
21
- self.__page = page
22
- if self.is_current_page() is False:
23
- raise ValueError("page参数值无效")
24
-
25
- def get_page(self) -> Page:
26
- return self.__page
27
-
28
- def is_current_page(self) -> bool:
29
- url = self.__page.url.split("?")[0]
30
- if isinstance(self.__page, Page) and url.endswith(self.url):
31
- return True
32
- else:
33
- return False
34
-
35
- def get_url_domain(self) -> str:
36
- if isinstance(self.__page, Page):
37
- page_slice: List[str] = self.__page.url.split("/")
38
- return f"{page_slice[0]}://{page_slice[2]}"
39
- else:
40
- raise AttributeError("PO对象中的page属性未被初始化")