kdtest-pw 2.0.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.
- kdtest_pw/__init__.py +50 -0
- kdtest_pw/action/__init__.py +7 -0
- kdtest_pw/action/base_keyword.py +292 -0
- kdtest_pw/action/element_plus/__init__.py +23 -0
- kdtest_pw/action/element_plus/el_cascader.py +263 -0
- kdtest_pw/action/element_plus/el_datepicker.py +324 -0
- kdtest_pw/action/element_plus/el_dialog.py +317 -0
- kdtest_pw/action/element_plus/el_form.py +443 -0
- kdtest_pw/action/element_plus/el_menu.py +456 -0
- kdtest_pw/action/element_plus/el_select.py +268 -0
- kdtest_pw/action/element_plus/el_table.py +442 -0
- kdtest_pw/action/element_plus/el_tree.py +364 -0
- kdtest_pw/action/element_plus/el_upload.py +313 -0
- kdtest_pw/action/key_retrieval.py +311 -0
- kdtest_pw/action/page_action.py +1129 -0
- kdtest_pw/api/__init__.py +6 -0
- kdtest_pw/api/api_keyword.py +251 -0
- kdtest_pw/api/request_handler.py +232 -0
- kdtest_pw/cases/__init__.py +6 -0
- kdtest_pw/cases/case_collector.py +182 -0
- kdtest_pw/cases/case_executor.py +359 -0
- kdtest_pw/cases/read/__init__.py +6 -0
- kdtest_pw/cases/read/cell_handler.py +305 -0
- kdtest_pw/cases/read/excel_reader.py +223 -0
- kdtest_pw/cli/__init__.py +5 -0
- kdtest_pw/cli/run.py +318 -0
- kdtest_pw/common.py +106 -0
- kdtest_pw/core/__init__.py +7 -0
- kdtest_pw/core/browser_manager.py +196 -0
- kdtest_pw/core/config_loader.py +235 -0
- kdtest_pw/core/page_context.py +228 -0
- kdtest_pw/data/__init__.py +5 -0
- kdtest_pw/data/init_data.py +105 -0
- kdtest_pw/data/static/elementData.yaml +59 -0
- kdtest_pw/data/static/parameters.json +24 -0
- kdtest_pw/plugins/__init__.py +6 -0
- kdtest_pw/plugins/element_plus_plugin/__init__.py +5 -0
- kdtest_pw/plugins/element_plus_plugin/elementData/elementData.yaml +144 -0
- kdtest_pw/plugins/element_plus_plugin/element_plus_plugin.py +237 -0
- kdtest_pw/plugins/element_plus_plugin/my.ini +23 -0
- kdtest_pw/plugins/plugin_base.py +180 -0
- kdtest_pw/plugins/plugin_loader.py +260 -0
- kdtest_pw/product.py +5 -0
- kdtest_pw/reference.py +99 -0
- kdtest_pw/utils/__init__.py +13 -0
- kdtest_pw/utils/built_in_function.py +376 -0
- kdtest_pw/utils/decorator.py +211 -0
- kdtest_pw/utils/log/__init__.py +6 -0
- kdtest_pw/utils/log/html_report.py +336 -0
- kdtest_pw/utils/log/logger.py +123 -0
- kdtest_pw/utils/public_script.py +366 -0
- kdtest_pw-2.0.0.dist-info/METADATA +169 -0
- kdtest_pw-2.0.0.dist-info/RECORD +57 -0
- kdtest_pw-2.0.0.dist-info/WHEEL +5 -0
- kdtest_pw-2.0.0.dist-info/entry_points.txt +2 -0
- kdtest_pw-2.0.0.dist-info/licenses/LICENSE +21 -0
- kdtest_pw-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
"""菜单导航关键字 - 支持多级菜单结构"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from playwright.sync_api import Page, Locator
|
|
5
|
+
from typing import Optional, Dict, Any, List
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ..base_keyword import BaseKeyword
|
|
9
|
+
from ...reference import INFO, MODULEDATA, set_element_value
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ElMenuKeyword(BaseKeyword):
|
|
13
|
+
"""多级菜单导航关键字
|
|
14
|
+
|
|
15
|
+
支持 modularInformation.json 格式的菜单配置:
|
|
16
|
+
{
|
|
17
|
+
"一级菜单": {
|
|
18
|
+
"selfLocatin": ["xpath", "定位表达式"],
|
|
19
|
+
"subordinate": {
|
|
20
|
+
"二级菜单": {
|
|
21
|
+
"iframe": "iframe名称",
|
|
22
|
+
"locatingNodes": ["xpath", "定位表达式"],
|
|
23
|
+
"submodule": {...}, // 三级菜单
|
|
24
|
+
"tagPage": [...] // 页签
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, page: Page):
|
|
32
|
+
super().__init__(page)
|
|
33
|
+
self._menu_data: Dict[str, Any] = {}
|
|
34
|
+
self._current_iframe: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
def load_menu_data(self, file_path: str = None, *, content: str = None) -> None:
|
|
37
|
+
"""加载菜单配置文件
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
file_path: modularInformation.json 文件路径
|
|
41
|
+
content: 文件路径 (关键字调用时使用)
|
|
42
|
+
"""
|
|
43
|
+
# 支持两种调用方式
|
|
44
|
+
path_str = content or file_path
|
|
45
|
+
if not path_str:
|
|
46
|
+
INFO("未指定菜单配置文件路径", "ERROR")
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
path = Path(path_str)
|
|
50
|
+
if not path.exists():
|
|
51
|
+
INFO(f"菜单配置文件不存在: {path_str}", "ERROR")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
with open(path, 'r', encoding='utf-8') as f:
|
|
55
|
+
self._menu_data = json.load(f)
|
|
56
|
+
|
|
57
|
+
MODULEDATA['menuData'] = self._menu_data
|
|
58
|
+
INFO(f"加载菜单配置: {len(self._menu_data)} 个一级菜单")
|
|
59
|
+
|
|
60
|
+
def set_menu_data(self, menu_data: Dict[str, Any]) -> None:
|
|
61
|
+
"""直接设置菜单数据
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
menu_data: 菜单数据字典
|
|
65
|
+
"""
|
|
66
|
+
self._menu_data = menu_data
|
|
67
|
+
MODULEDATA['menuData'] = self._menu_data
|
|
68
|
+
|
|
69
|
+
# ==================== 菜单导航关键字 ====================
|
|
70
|
+
|
|
71
|
+
def menu_navigate(
|
|
72
|
+
self,
|
|
73
|
+
targeting: str = None,
|
|
74
|
+
element: str = None,
|
|
75
|
+
index: Optional[int] = None,
|
|
76
|
+
*,
|
|
77
|
+
content: str
|
|
78
|
+
) -> None:
|
|
79
|
+
"""导航到指定菜单
|
|
80
|
+
|
|
81
|
+
支持多种格式:
|
|
82
|
+
- "一级菜单" - 只点击一级菜单
|
|
83
|
+
- "一级菜单/二级菜单" - 导航到二级菜单
|
|
84
|
+
- "一级菜单/二级菜单/三级菜单" - 导航到三级菜单
|
|
85
|
+
- "一级菜单/二级菜单#页签索引" - 导航到二级菜单并点击页签
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
targeting: 未使用
|
|
89
|
+
element: 未使用
|
|
90
|
+
index: 未使用
|
|
91
|
+
content: 菜单路径
|
|
92
|
+
"""
|
|
93
|
+
menu_path = str(content)
|
|
94
|
+
INFO(f"菜单导航: {menu_path}")
|
|
95
|
+
|
|
96
|
+
# 解析页签
|
|
97
|
+
tag_index = None
|
|
98
|
+
if '#' in menu_path:
|
|
99
|
+
menu_path, tag_str = menu_path.rsplit('#', 1)
|
|
100
|
+
tag_index = int(tag_str)
|
|
101
|
+
|
|
102
|
+
# 解析菜单层级
|
|
103
|
+
levels = [level.strip() for level in menu_path.split('/')]
|
|
104
|
+
|
|
105
|
+
if len(levels) >= 1:
|
|
106
|
+
# 点击一级菜单
|
|
107
|
+
self._click_first_level_menu(levels[0])
|
|
108
|
+
|
|
109
|
+
if len(levels) >= 2:
|
|
110
|
+
# 点击二级菜单
|
|
111
|
+
self._click_second_level_menu(levels[0], levels[1])
|
|
112
|
+
|
|
113
|
+
if len(levels) >= 3:
|
|
114
|
+
# 点击三级菜单
|
|
115
|
+
self._click_third_level_menu(levels[0], levels[1], levels[2])
|
|
116
|
+
|
|
117
|
+
# 点击页签
|
|
118
|
+
if tag_index is not None and len(levels) >= 2:
|
|
119
|
+
self._click_tag_page(levels[0], levels[1], tag_index)
|
|
120
|
+
|
|
121
|
+
def menu_click_first(self, *, content: str) -> None:
|
|
122
|
+
"""点击一级菜单
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
content: 一级菜单名称
|
|
126
|
+
"""
|
|
127
|
+
self._click_first_level_menu(content)
|
|
128
|
+
|
|
129
|
+
def menu_click_second(self, *, content: str) -> None:
|
|
130
|
+
"""点击二级菜单
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
content: 格式 "一级菜单/二级菜单"
|
|
134
|
+
"""
|
|
135
|
+
levels = [level.strip() for level in content.split('/')]
|
|
136
|
+
if len(levels) < 2:
|
|
137
|
+
INFO(f"二级菜单格式错误: {content}", "ERROR")
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
self._click_first_level_menu(levels[0])
|
|
141
|
+
self._click_second_level_menu(levels[0], levels[1])
|
|
142
|
+
|
|
143
|
+
def menu_click_third(self, *, content: str) -> None:
|
|
144
|
+
"""点击三级菜单
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
content: 格式 "一级菜单/二级菜单/三级菜单"
|
|
148
|
+
"""
|
|
149
|
+
levels = [level.strip() for level in content.split('/')]
|
|
150
|
+
if len(levels) < 3:
|
|
151
|
+
INFO(f"三级菜单格式错误: {content}", "ERROR")
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
self._click_first_level_menu(levels[0])
|
|
155
|
+
self._click_second_level_menu(levels[0], levels[1])
|
|
156
|
+
self._click_third_level_menu(levels[0], levels[1], levels[2])
|
|
157
|
+
|
|
158
|
+
def menu_click_tag(self, *, content: str, tag_index: int = 0) -> None:
|
|
159
|
+
"""点击页签
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
content: 格式 "一级菜单/二级菜单"
|
|
163
|
+
tag_index: 页签索引 (从0开始)
|
|
164
|
+
"""
|
|
165
|
+
levels = [level.strip() for level in content.split('/')]
|
|
166
|
+
if len(levels) < 2:
|
|
167
|
+
INFO(f"菜单格式错误: {content}", "ERROR")
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
self._click_tag_page(levels[0], levels[1], tag_index)
|
|
171
|
+
|
|
172
|
+
def menu_switch_iframe(self, *, content: str) -> None:
|
|
173
|
+
"""切换到菜单对应的 iframe
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
content: 格式 "一级菜单/二级菜单"
|
|
177
|
+
"""
|
|
178
|
+
levels = [level.strip() for level in content.split('/')]
|
|
179
|
+
if len(levels) < 2:
|
|
180
|
+
INFO(f"菜单格式错误: {content}", "ERROR")
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
first_menu = levels[0]
|
|
184
|
+
second_menu = levels[1]
|
|
185
|
+
|
|
186
|
+
menu_info = self._get_second_menu_info(first_menu, second_menu)
|
|
187
|
+
if not menu_info:
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
iframe_name = menu_info.get('iframe', '')
|
|
191
|
+
if iframe_name:
|
|
192
|
+
self._switch_to_iframe(iframe_name)
|
|
193
|
+
else:
|
|
194
|
+
INFO(f"菜单 {content} 没有 iframe 配置")
|
|
195
|
+
|
|
196
|
+
def menu_exit_iframe(self) -> None:
|
|
197
|
+
"""退出当前 iframe,返回主文档"""
|
|
198
|
+
self.frame_default()
|
|
199
|
+
self._current_iframe = None
|
|
200
|
+
INFO("退出 iframe,返回主文档")
|
|
201
|
+
|
|
202
|
+
# ==================== 内部方法 ====================
|
|
203
|
+
|
|
204
|
+
def _click_first_level_menu(self, menu_name: str) -> None:
|
|
205
|
+
"""点击一级菜单
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
menu_name: 一级菜单名称
|
|
209
|
+
"""
|
|
210
|
+
if menu_name not in self._menu_data:
|
|
211
|
+
INFO(f"一级菜单不存在: {menu_name}", "ERROR")
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
menu_config = self._menu_data[menu_name]
|
|
215
|
+
locator_info = menu_config.get('selfLocatin', [])
|
|
216
|
+
|
|
217
|
+
if len(locator_info) >= 2:
|
|
218
|
+
targeting = locator_info[0]
|
|
219
|
+
element = locator_info[1]
|
|
220
|
+
|
|
221
|
+
# 确保在主文档中
|
|
222
|
+
self.frame_default()
|
|
223
|
+
|
|
224
|
+
loc = self.locator(targeting, element)
|
|
225
|
+
loc.click()
|
|
226
|
+
self.page.wait_for_timeout(300)
|
|
227
|
+
INFO(f"点击一级菜单: {menu_name}")
|
|
228
|
+
else:
|
|
229
|
+
INFO(f"一级菜单 {menu_name} 缺少定位信息", "ERROR")
|
|
230
|
+
|
|
231
|
+
def _click_second_level_menu(self, first_menu: str, second_menu: str) -> None:
|
|
232
|
+
"""点击二级菜单
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
first_menu: 一级菜单名称
|
|
236
|
+
second_menu: 二级菜单名称
|
|
237
|
+
"""
|
|
238
|
+
menu_info = self._get_second_menu_info(first_menu, second_menu)
|
|
239
|
+
if not menu_info:
|
|
240
|
+
return
|
|
241
|
+
|
|
242
|
+
locator_info = menu_info.get('locatingNodes', [])
|
|
243
|
+
|
|
244
|
+
if len(locator_info) >= 2:
|
|
245
|
+
targeting = locator_info[0]
|
|
246
|
+
element = locator_info[1]
|
|
247
|
+
|
|
248
|
+
# 确保在主文档中(二级菜单通常在主文档)
|
|
249
|
+
self.frame_default()
|
|
250
|
+
|
|
251
|
+
loc = self.locator(targeting, element)
|
|
252
|
+
loc.click()
|
|
253
|
+
self.page.wait_for_timeout(500)
|
|
254
|
+
INFO(f"点击二级菜单: {first_menu}/{second_menu}")
|
|
255
|
+
|
|
256
|
+
# 自动切换到 iframe(如果配置了)
|
|
257
|
+
iframe_name = menu_info.get('iframe', '')
|
|
258
|
+
if iframe_name:
|
|
259
|
+
self._switch_to_iframe(iframe_name)
|
|
260
|
+
else:
|
|
261
|
+
INFO(f"二级菜单 {first_menu}/{second_menu} 缺少定位信息", "ERROR")
|
|
262
|
+
|
|
263
|
+
def _click_third_level_menu(self, first_menu: str, second_menu: str, third_menu: str) -> None:
|
|
264
|
+
"""点击三级菜单
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
first_menu: 一级菜单名称
|
|
268
|
+
second_menu: 二级菜单名称
|
|
269
|
+
third_menu: 三级菜单名称
|
|
270
|
+
"""
|
|
271
|
+
menu_info = self._get_second_menu_info(first_menu, second_menu)
|
|
272
|
+
if not menu_info:
|
|
273
|
+
return
|
|
274
|
+
|
|
275
|
+
submodule = menu_info.get('submodule')
|
|
276
|
+
if not submodule or third_menu not in submodule:
|
|
277
|
+
INFO(f"三级菜单不存在: {first_menu}/{second_menu}/{third_menu}", "ERROR")
|
|
278
|
+
return
|
|
279
|
+
|
|
280
|
+
third_menu_info = submodule[third_menu]
|
|
281
|
+
locator_info = third_menu_info.get('locatingNodes', [])
|
|
282
|
+
|
|
283
|
+
if len(locator_info) >= 2:
|
|
284
|
+
targeting = locator_info[0]
|
|
285
|
+
element = locator_info[1]
|
|
286
|
+
|
|
287
|
+
loc = self.locator(targeting, element)
|
|
288
|
+
loc.click()
|
|
289
|
+
self.page.wait_for_timeout(300)
|
|
290
|
+
INFO(f"点击三级菜单: {first_menu}/{second_menu}/{third_menu}")
|
|
291
|
+
|
|
292
|
+
# 三级菜单可能也有自己的 iframe
|
|
293
|
+
iframe_name = third_menu_info.get('iframe', '')
|
|
294
|
+
if iframe_name:
|
|
295
|
+
self._switch_to_iframe(iframe_name)
|
|
296
|
+
else:
|
|
297
|
+
INFO(f"三级菜单 {third_menu} 缺少定位信息", "ERROR")
|
|
298
|
+
|
|
299
|
+
def _click_tag_page(self, first_menu: str, second_menu: str, tag_index: int) -> None:
|
|
300
|
+
"""点击页签
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
first_menu: 一级菜单名称
|
|
304
|
+
second_menu: 二级菜单名称
|
|
305
|
+
tag_index: 页签索引
|
|
306
|
+
"""
|
|
307
|
+
menu_info = self._get_second_menu_info(first_menu, second_menu)
|
|
308
|
+
if not menu_info:
|
|
309
|
+
return
|
|
310
|
+
|
|
311
|
+
tag_pages = menu_info.get('tagPage')
|
|
312
|
+
if not tag_pages:
|
|
313
|
+
INFO(f"菜单 {first_menu}/{second_menu} 没有页签配置", "WARNING")
|
|
314
|
+
return
|
|
315
|
+
|
|
316
|
+
if tag_index >= len(tag_pages):
|
|
317
|
+
INFO(f"页签索引超出范围: {tag_index} (共 {len(tag_pages)} 个页签)", "ERROR")
|
|
318
|
+
return
|
|
319
|
+
|
|
320
|
+
locator_info = tag_pages[tag_index]
|
|
321
|
+
if len(locator_info) >= 2:
|
|
322
|
+
targeting = locator_info[0]
|
|
323
|
+
element = locator_info[1]
|
|
324
|
+
|
|
325
|
+
loc = self.locator(targeting, element)
|
|
326
|
+
loc.click()
|
|
327
|
+
self.page.wait_for_timeout(300)
|
|
328
|
+
INFO(f"点击页签 [{tag_index}]: {first_menu}/{second_menu}")
|
|
329
|
+
else:
|
|
330
|
+
INFO(f"页签 {tag_index} 缺少定位信息", "ERROR")
|
|
331
|
+
|
|
332
|
+
def _get_second_menu_info(self, first_menu: str, second_menu: str) -> Optional[Dict[str, Any]]:
|
|
333
|
+
"""获取二级菜单配置
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
first_menu: 一级菜单名称
|
|
337
|
+
second_menu: 二级菜单名称
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
二级菜单配置字典
|
|
341
|
+
"""
|
|
342
|
+
if first_menu not in self._menu_data:
|
|
343
|
+
INFO(f"一级菜单不存在: {first_menu}", "ERROR")
|
|
344
|
+
return None
|
|
345
|
+
|
|
346
|
+
subordinate = self._menu_data[first_menu].get('subordinate', {})
|
|
347
|
+
if second_menu not in subordinate:
|
|
348
|
+
INFO(f"二级菜单不存在: {first_menu}/{second_menu}", "ERROR")
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
return subordinate[second_menu]
|
|
352
|
+
|
|
353
|
+
def _switch_to_iframe(self, iframe_name: str) -> None:
|
|
354
|
+
"""切换到指定 iframe
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
iframe_name: iframe 名称或 ID
|
|
358
|
+
"""
|
|
359
|
+
if not iframe_name:
|
|
360
|
+
return
|
|
361
|
+
|
|
362
|
+
# 先回到主文档
|
|
363
|
+
self.frame_default()
|
|
364
|
+
|
|
365
|
+
# 切换到目标 iframe
|
|
366
|
+
try:
|
|
367
|
+
# 尝试通过 name 或 id 定位
|
|
368
|
+
frame_locator = self.page.frame_locator(f'iframe[name="{iframe_name}"], iframe#{iframe_name}, #{iframe_name}')
|
|
369
|
+
self._current_frame = frame_locator
|
|
370
|
+
self._current_iframe = iframe_name
|
|
371
|
+
INFO(f"切换到 iframe: {iframe_name}")
|
|
372
|
+
except Exception as e:
|
|
373
|
+
INFO(f"切换 iframe 失败: {iframe_name} - {e}", "ERROR")
|
|
374
|
+
|
|
375
|
+
# ==================== 辅助方法 ====================
|
|
376
|
+
|
|
377
|
+
def menu_get_first_menus(self) -> List[str]:
|
|
378
|
+
"""获取所有一级菜单名称
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
List[str]: 一级菜单名称列表
|
|
382
|
+
"""
|
|
383
|
+
return list(self._menu_data.keys())
|
|
384
|
+
|
|
385
|
+
def menu_get_second_menus(self, *, content: str) -> List[str]:
|
|
386
|
+
"""获取指定一级菜单下的所有二级菜单
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
content: 一级菜单名称
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
List[str]: 二级菜单名称列表
|
|
393
|
+
"""
|
|
394
|
+
if content not in self._menu_data:
|
|
395
|
+
return []
|
|
396
|
+
|
|
397
|
+
subordinate = self._menu_data[content].get('subordinate', {})
|
|
398
|
+
return list(subordinate.keys())
|
|
399
|
+
|
|
400
|
+
def menu_get_tag_count(self, *, content: str) -> int:
|
|
401
|
+
"""获取菜单的页签数量
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
content: 格式 "一级菜单/二级菜单"
|
|
405
|
+
|
|
406
|
+
Returns:
|
|
407
|
+
int: 页签数量
|
|
408
|
+
"""
|
|
409
|
+
levels = [level.strip() for level in content.split('/')]
|
|
410
|
+
if len(levels) < 2:
|
|
411
|
+
return 0
|
|
412
|
+
|
|
413
|
+
menu_info = self._get_second_menu_info(levels[0], levels[1])
|
|
414
|
+
if not menu_info:
|
|
415
|
+
return 0
|
|
416
|
+
|
|
417
|
+
tag_pages = menu_info.get('tagPage')
|
|
418
|
+
return len(tag_pages) if tag_pages else 0
|
|
419
|
+
|
|
420
|
+
def menu_has_iframe(self, *, content: str) -> bool:
|
|
421
|
+
"""检查菜单是否有 iframe
|
|
422
|
+
|
|
423
|
+
Args:
|
|
424
|
+
content: 格式 "一级菜单/二级菜单"
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
bool: 是否有 iframe
|
|
428
|
+
"""
|
|
429
|
+
levels = [level.strip() for level in content.split('/')]
|
|
430
|
+
if len(levels) < 2:
|
|
431
|
+
return False
|
|
432
|
+
|
|
433
|
+
menu_info = self._get_second_menu_info(levels[0], levels[1])
|
|
434
|
+
if not menu_info:
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
return bool(menu_info.get('iframe'))
|
|
438
|
+
|
|
439
|
+
def menu_get_iframe_name(self, *, content: str) -> str:
|
|
440
|
+
"""获取菜单的 iframe 名称
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
content: 格式 "一级菜单/二级菜单"
|
|
444
|
+
|
|
445
|
+
Returns:
|
|
446
|
+
str: iframe 名称
|
|
447
|
+
"""
|
|
448
|
+
levels = [level.strip() for level in content.split('/')]
|
|
449
|
+
if len(levels) < 2:
|
|
450
|
+
return ''
|
|
451
|
+
|
|
452
|
+
menu_info = self._get_second_menu_info(levels[0], levels[1])
|
|
453
|
+
if not menu_info:
|
|
454
|
+
return ''
|
|
455
|
+
|
|
456
|
+
return menu_info.get('iframe', '')
|