ascript 1.3.27__py3-none-win_amd64.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.
Files changed (177) hide show
  1. ascript/__init__.py +8 -0
  2. ascript/hooks/__init__.py +0 -0
  3. ascript/hooks/hook-ascript.py +2 -0
  4. ascript/windows/__init__.py +29 -0
  5. ascript/windows/daos/__init__.py +0 -0
  6. ascript/windows/daos/screen.py +143 -0
  7. ascript/windows/hardware/__init__.py +5 -0
  8. ascript/windows/hardware/keyboard.py +279 -0
  9. ascript/windows/hardware/logitech_driver.py +179 -0
  10. ascript/windows/hardware/mouse.py +308 -0
  11. ascript/windows/license/__init__.py +16 -0
  12. ascript/windows/license/achttp.cp310-win_amd64.pyd +0 -0
  13. ascript/windows/license/achttp.cp311-win_amd64.pyd +0 -0
  14. ascript/windows/license/achttp.cp312-win_amd64.pyd +0 -0
  15. ascript/windows/license/achttp.cp313-win_amd64.pyd +0 -0
  16. ascript/windows/license/achttp.cp314-win_amd64.pyd +0 -0
  17. ascript/windows/license/achttp.cp38-win_amd64.pyd +0 -0
  18. ascript/windows/license/achttp.cp39-win_amd64.pyd +0 -0
  19. ascript/windows/media/__init__.py +0 -0
  20. ascript/windows/resources/__init__.py +0 -0
  21. ascript/windows/resources/libs/logitech/x64/LogitechGkeyEnginesWrapper.dll +0 -0
  22. ascript/windows/resources/libs/logitech/x86/LogitechGkeyEnginesWrapper.dll +0 -0
  23. ascript/windows/resources/templates/__init__.py +0 -0
  24. ascript/windows/resources/templates/__init__py.win.template +51 -0
  25. ascript/windows/resources/templates/build.as.win.template +14 -0
  26. ascript/windows/resources/templates/build.py +71 -0
  27. ascript/windows/resources/templates/logo_windows.ico +0 -0
  28. ascript/windows/resources/templates/windows/main.py +50 -0
  29. ascript/windows/resources/templates/windows/pyproject.toml +44 -0
  30. ascript/windows/resources/templates/windows/res/img/logo.ico +0 -0
  31. ascript/windows/screen/__init__.py +13 -0
  32. ascript/windows/screen/as_cv.py +382 -0
  33. ascript/windows/screen/canny.py +128 -0
  34. ascript/windows/screen/code_scanner.py +72 -0
  35. ascript/windows/screen/color_algorithms.py +277 -0
  36. ascript/windows/screen/find_colors.py +251 -0
  37. ascript/windows/screen/find_images.py +217 -0
  38. ascript/windows/screen/ocr/__init__.py +4 -0
  39. ascript/windows/screen/ocr/ocr.py +223 -0
  40. ascript/windows/screen/ocr/rapidocr_hook.py +301 -0
  41. ascript/windows/screen/ocrx.py +169 -0
  42. ascript/windows/screen/screen_core.py +139 -0
  43. ascript/windows/store/__init__.py +21 -0
  44. ascript/windows/system/__init__.py +8 -0
  45. ascript/windows/system/device.py +355 -0
  46. ascript/windows/system/easy_print.py +115 -0
  47. ascript/windows/system/env.py +492 -0
  48. ascript/windows/system/exception/__init__.py +1 -0
  49. ascript/windows/system/key_value.py +145 -0
  50. ascript/windows/system/pip.py +175 -0
  51. ascript/windows/system/r.py +165 -0
  52. ascript/windows/system/runtime.py +62 -0
  53. ascript/windows/tools/__init__.py +27 -0
  54. ascript/windows/tools/__main__.py +21 -0
  55. ascript/windows/tools/action.json +33 -0
  56. ascript/windows/tools/action.py +168 -0
  57. ascript/windows/tools/colors_tool.py +391 -0
  58. ascript/windows/tools/config.py +26 -0
  59. ascript/windows/tools/dumptool.py +18 -0
  60. ascript/windows/tools/eel_api.py +495 -0
  61. ascript/windows/tools/gpplug/__init__.py +0 -0
  62. ascript/windows/tools/gpplug/plug.py +70 -0
  63. ascript/windows/tools/mouse_catch.py +168 -0
  64. ascript/windows/tools/plug_manager.py +38 -0
  65. ascript/windows/tools/tool_api.py +906 -0
  66. ascript/windows/tools/tool_window.py +56 -0
  67. ascript/windows/tools/uia_worker.py +365 -0
  68. ascript/windows/tools/web/app_store_window.html +481 -0
  69. ascript/windows/tools/web/colors.html +532 -0
  70. ascript/windows/tools/web/css/screen.css +1342 -0
  71. ascript/windows/tools/web/css/viewtree.css +357 -0
  72. ascript/windows/tools/web/flot_control.html +195 -0
  73. ascript/windows/tools/web/img/ico/favicon.png +0 -0
  74. ascript/windows/tools/web/img/ico/paintpalette.png +0 -0
  75. ascript/windows/tools/web/img/svg/find_colors.svg +1 -0
  76. ascript/windows/tools/web/img/svg/find_images.svg +1 -0
  77. ascript/windows/tools/web/img/svg/illustration-6.svg +89 -0
  78. ascript/windows/tools/web/img/svg/img_default.svg +1 -0
  79. ascript/windows/tools/web/img/svg/ocr.svg +1 -0
  80. ascript/windows/tools/web/js/screen/colors.js +466 -0
  81. ascript/windows/tools/web/js/screen/gp_plug.js +108 -0
  82. ascript/windows/tools/web/js/screen/image_mouse.js +464 -0
  83. ascript/windows/tools/web/js/screen/img_view.js +558 -0
  84. ascript/windows/tools/web/js/screen/plug.js +246 -0
  85. ascript/windows/tools/web/js/screen/screen.js +690 -0
  86. ascript/windows/tools/web/js/screen/screen_api.js +778 -0
  87. ascript/windows/tools/web/js/screen/screen_maker.js +10 -0
  88. ascript/windows/tools/web/js/utils/map.js +73 -0
  89. ascript/windows/tools/web/js/utils/upload.js +157 -0
  90. ascript/windows/tools/web/js/viewtree/niv_js.js +27 -0
  91. ascript/windows/tools/web/js/viewtree/vtree.js +1510 -0
  92. ascript/windows/tools/web/libs/bootstrap/css/bootstrap.min.css +6 -0
  93. ascript/windows/tools/web/libs/bootstrap/js/bootstrap.bundle.min.js +7 -0
  94. ascript/windows/tools/web/libs/bootstrap-icons/0-circle.svg +4 -0
  95. ascript/windows/tools/web/libs/bootstrap-icons/0-square.svg +4 -0
  96. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.css +2078 -0
  97. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.json +2052 -0
  98. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.min.css +5 -0
  99. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.scss +2090 -0
  100. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  101. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  102. ascript/windows/tools/web/libs/feather-icons/dist/feather.min.js +13 -0
  103. ascript/windows/tools/web/libs/feather-icons/dist/icons.json +1 -0
  104. ascript/windows/tools/web/libs/jquery/core.js +399 -0
  105. ascript/windows/tools/web/libs/jquery/jquery.js +10598 -0
  106. ascript/windows/tools/web/libs/jquery/jquery.min.js +4 -0
  107. ascript/windows/tools/web/libs/jquery/jquery.min.js.zip +0 -0
  108. ascript/windows/tools/web/libs/jquery/jquery.slim.js +8495 -0
  109. ascript/windows/tools/web/libs/jquery/jquery.slim.min.js +2 -0
  110. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.js +2134 -0
  111. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.min.css +16 -0
  112. ascript/windows/tools/web/libs/jquery-zTree/css/zTreeStyle.css +97 -0
  113. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_close.png +0 -0
  114. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_open.png +0 -0
  115. ascript/windows/tools/web/libs/jquery-zTree/img/diy/2.png +0 -0
  116. ascript/windows/tools/web/libs/jquery-zTree/img/diy/3.png +0 -0
  117. ascript/windows/tools/web/libs/jquery-zTree/img/diy/4.png +0 -0
  118. ascript/windows/tools/web/libs/jquery-zTree/img/diy/5.png +0 -0
  119. ascript/windows/tools/web/libs/jquery-zTree/img/diy/6.png +0 -0
  120. ascript/windows/tools/web/libs/jquery-zTree/img/diy/7.png +0 -0
  121. ascript/windows/tools/web/libs/jquery-zTree/img/diy/8.png +0 -0
  122. ascript/windows/tools/web/libs/jquery-zTree/img/diy/9.png +0 -0
  123. ascript/windows/tools/web/libs/jquery-zTree/img/line_conn.gif +0 -0
  124. ascript/windows/tools/web/libs/jquery-zTree/img/loading.gif +0 -0
  125. ascript/windows/tools/web/libs/jquery-zTree/img/tree-node-btn.png +0 -0
  126. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.gif +0 -0
  127. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.png +0 -0
  128. ascript/windows/tools/web/libs/jquery-zTree/js/jquery.ztree.all.min.js +3 -0
  129. ascript/windows/tools/web/libs/treeview/css/jquery.treeview.css +79 -0
  130. ascript/windows/tools/web/libs/treeview/img/file.png +0 -0
  131. ascript/windows/tools/web/libs/treeview/img/ico_loading.png +0 -0
  132. ascript/windows/tools/web/libs/treeview/img/icon4.png +0 -0
  133. ascript/windows/tools/web/libs/treeview/img/icon5.png +0 -0
  134. ascript/windows/tools/web/libs/treeview/img/icon6.png +0 -0
  135. ascript/windows/tools/web/libs/treeview/img/py.png +0 -0
  136. ascript/windows/tools/web/libs/treeview/img/treeview-black-line.gif +0 -0
  137. ascript/windows/tools/web/libs/treeview/img/treeview-black.gif +0 -0
  138. ascript/windows/tools/web/libs/treeview/img/treeview-default-line.gif +0 -0
  139. ascript/windows/tools/web/libs/treeview/img/treeview-default.gif +0 -0
  140. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam-line.gif +0 -0
  141. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam.gif +0 -0
  142. ascript/windows/tools/web/libs/treeview/img/treeview-gray-line.gif +0 -0
  143. ascript/windows/tools/web/libs/treeview/img/treeview-gray.gif +0 -0
  144. ascript/windows/tools/web/libs/treeview/img/treeview-red-line.gif +0 -0
  145. ascript/windows/tools/web/libs/treeview/img/treeview-red.gif +0 -0
  146. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.edit.js +37 -0
  147. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.js +250 -0
  148. ascript/windows/tools/web/license_window.html +255 -0
  149. ascript/windows/tools/web/plugs/a.html +653 -0
  150. ascript/windows/tools/web/plugs/demo.html +52 -0
  151. ascript/windows/tools/web/plugs/find_colors.html +629 -0
  152. ascript/windows/tools/web/plugs/find_images.html +699 -0
  153. ascript/windows/tools/web/plugs/rapidocr.html +954 -0
  154. ascript/windows/tools/web/vtree.html +496 -0
  155. ascript/windows/tools/webview/assets/index-HymBPl-I.css +1 -0
  156. ascript/windows/tools/webview/assets/index-PqA_m8tL.js +17 -0
  157. ascript/windows/tools/webview/index.html +13 -0
  158. ascript/windows/ui/__init__.py +6 -0
  159. ascript/windows/ui/app_store_window.py +272 -0
  160. ascript/windows/ui/draw_window.py +231 -0
  161. ascript/windows/ui/flot_test.py +297 -0
  162. ascript/windows/ui/flot_window.py +488 -0
  163. ascript/windows/ui/license_window.py +111 -0
  164. ascript/windows/ui/web_window.py +466 -0
  165. ascript/windows/utils/__init__.py +0 -0
  166. ascript/windows/utils/node_utils.py +20 -0
  167. ascript/windows/utils/screen_utils.py +280 -0
  168. ascript/windows/window/Selector.py +1015 -0
  169. ascript/windows/window/Window.py +747 -0
  170. ascript/windows/window/__init__.py +5 -0
  171. ascript/windows/window/launcher.py +213 -0
  172. ascript/windows/window/uia_runtime.py +26 -0
  173. ascript-1.3.27.dist-info/METADATA +41 -0
  174. ascript-1.3.27.dist-info/RECORD +177 -0
  175. ascript-1.3.27.dist-info/WHEEL +5 -0
  176. ascript-1.3.27.dist-info/entry_points.txt +2 -0
  177. ascript-1.3.27.dist-info/top_level.txt +1 -0
@@ -0,0 +1,954 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title>RapidOCR Visual Tool</title>
7
+ <link href="../libs/bootstrap/css/bootstrap.min.css" rel="stylesheet">
8
+ <link href="../libs/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
9
+
10
+ <style>
11
+ :root {
12
+ --editor-bg: #1e1e1e;
13
+ --panel-bg: #252526;
14
+ --border-color: #333333;
15
+ --accent-color: #007acc;
16
+ }
17
+
18
+ html,
19
+ body {
20
+ height: 100%;
21
+ margin: 0;
22
+ background: var(--editor-bg);
23
+ color: #ccc;
24
+ font-size: 13px;
25
+ overflow: hidden;
26
+ }
27
+
28
+ .main-layout {
29
+ display: flex;
30
+ height: 100vh;
31
+ width: 100vw;
32
+ }
33
+
34
+ /* ---------- 左侧面板 ---------- */
35
+ .settings-panel {
36
+ width: 320px;
37
+ background: var(--panel-bg);
38
+ border-right: 1px solid var(--border-color);
39
+ display: flex;
40
+ flex-direction: column;
41
+ padding: 12px;
42
+ overflow: hidden;
43
+ }
44
+
45
+ .section-title {
46
+ color: var(--accent-color);
47
+ font-size: 10px;
48
+ font-weight: bold;
49
+ margin: 14px 0 8px;
50
+ border-bottom: 1px solid #333;
51
+ text-transform: uppercase;
52
+ }
53
+
54
+ .form-label {
55
+ font-size: 11px;
56
+ color: #888;
57
+ }
58
+
59
+ .form-select {
60
+ background: #3c3c3c;
61
+ border: 1px solid #3c3c3c;
62
+ color: #eee;
63
+ font-size: 11px;
64
+ height: 26px;
65
+ }
66
+
67
+ /* ---------- 结果列表 ---------- */
68
+ .results-wrapper {
69
+ margin-top: 10px;
70
+ border: 1px solid #333;
71
+ display: flex;
72
+ flex-direction: column;
73
+ height: 100%;
74
+ overflow: hidden;
75
+ }
76
+
77
+ .results-header {
78
+ padding: 6px 8px;
79
+ font-size: 11px;
80
+ background: #1b1b1b;
81
+ border-bottom: 1px solid #333;
82
+ display: flex;
83
+ justify-content: space-between;
84
+ align-items: center;
85
+ }
86
+
87
+ .results-list {
88
+ flex: 1;
89
+ overflow-y: auto;
90
+ }
91
+
92
+ .ocr-item {
93
+ padding: 6px;
94
+ font-size: 11px;
95
+ display: flex;
96
+ gap: 6px;
97
+ border-bottom: 1px solid #333;
98
+ cursor: pointer;
99
+ }
100
+
101
+ .ocr-item:hover {
102
+ background: #2a2a2a;
103
+ }
104
+
105
+ /* ---------- 工作区 ---------- */
106
+ .workspace {
107
+ flex: 1;
108
+ display: flex;
109
+ flex-direction: column;
110
+ overflow: hidden;
111
+ }
112
+
113
+ .canvas-area {
114
+ flex: 1;
115
+ background: #111;
116
+ overflow: auto;
117
+ /* 允许滚动 */
118
+ display: flex;
119
+ justify-content: flex-start;
120
+ /* 左上角对齐 */
121
+ align-items: flex-start;
122
+ }
123
+
124
+ .img-viewport {
125
+ width: 100%;
126
+ height: 100%;
127
+ display: flex;
128
+ justify-content: center;
129
+ align-items: center;
130
+ background: #111;
131
+ overflow: hidden;
132
+ /* 不显示滚动条 */
133
+ }
134
+
135
+ .img-viewport img {
136
+ max-width: 100%;
137
+ max-height: 100%;
138
+ display: block;
139
+ cursor: pointer;
140
+ /* 鼠标悬浮显示可点击 */
141
+ }
142
+
143
+
144
+
145
+ .code-console {
146
+ height: 35%;
147
+ background: #000;
148
+ border-top: 1px solid #333;
149
+ display: flex;
150
+ flex-direction: column;
151
+ }
152
+
153
+ .code-display {
154
+ flex: 1;
155
+ padding: 10px;
156
+ font-family: Consolas, monospace;
157
+ font-size: 11px;
158
+ color: #9cdcfe;
159
+ overflow: auto;
160
+ white-space: pre;
161
+ }
162
+
163
+ /* ---------- 初始化遮罩 ---------- */
164
+ #init-overlay {
165
+ position: fixed;
166
+ inset: 0;
167
+ background: rgba(30, 30, 30, 0.98);
168
+ z-index: 9999;
169
+ display: flex;
170
+ flex-direction: column;
171
+ align-items: center;
172
+ justify-content: center;
173
+ }
174
+
175
+ #log-container {
176
+ width: 420px;
177
+ height: 160px;
178
+ background: #000;
179
+ color: #0f0;
180
+ font-family: monospace;
181
+ font-size: 11px;
182
+ padding: 8px;
183
+ border: 1px solid #444;
184
+ overflow-y: auto;
185
+ }
186
+
187
+ /* results-list 和 log-container 滚动条 */
188
+ .results-list::-webkit-scrollbar,
189
+ #log-container::-webkit-scrollbar {
190
+ width: 8px;
191
+ height: 8px;
192
+ }
193
+
194
+ .results-list::-webkit-scrollbar-track,
195
+ #log-container::-webkit-scrollbar-track {
196
+ background: #1b1b1b;
197
+ }
198
+
199
+ .results-list::-webkit-scrollbar-thumb,
200
+ #log-container::-webkit-scrollbar-thumb {
201
+ background-color: rgba(100, 100, 100, 0.6);
202
+ border-radius: 4px;
203
+ }
204
+
205
+ .results-list::-webkit-scrollbar-thumb:hover,
206
+ #log-container::-webkit-scrollbar-thumb:hover {
207
+ background-color: rgba(150, 150, 150, 0.8);
208
+ }
209
+
210
+ /* 优化滑块样式 */
211
+ .form-range::-webkit-slider-runnable-track {
212
+ background: #333;
213
+ height: 4px;
214
+ }
215
+
216
+ .form-range::-webkit-slider-thumb {
217
+ background: var(--accent-color);
218
+ margin-top: -6px;
219
+ /* 居中调节 */
220
+ }
221
+
222
+ /* 选项卡按钮微调 */
223
+ #search-tabs .nav-link {
224
+ color: #888;
225
+ border: 1px solid transparent;
226
+ margin-right: 4px;
227
+ }
228
+
229
+ #search-tabs .nav-link:hover {
230
+ color: #ccc;
231
+ }
232
+
233
+ #search-tabs .nav-link.active {
234
+ background: #3c3c3c !important;
235
+ border: 1px solid var(--border-color);
236
+ color: var(--accent-color) !important;
237
+ font-weight: bold;
238
+ }
239
+
240
+ /* 针对正则输入框的样式优化 */
241
+ #search-re::placeholder {
242
+ color: #888;
243
+ /* 提高占位符可见度 */
244
+ opacity: 1;
245
+ }
246
+
247
+ #search-re:focus {
248
+ background: #444;
249
+ border-color: var(--accent-color);
250
+ outline: none;
251
+ color: #fff;
252
+ }
253
+
254
+ /* 结果检索面板内部文字颜色 */
255
+ #search-config-panel .form-label {
256
+ color: #bbb;
257
+ /* 标签颜色稍亮一点 */
258
+ }
259
+ </style>
260
+ </head>
261
+
262
+ <body>
263
+
264
+ <div id="init-overlay">
265
+ <div class="spinner-border text-primary mb-2"></div>
266
+ <h6 id="init-text" class="mt-2 mb-2">RapidOCR 运行环境检查...</h6>
267
+ <div id="log-container">
268
+ <div>> 等待 Python 响应...</div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="main-layout">
273
+
274
+ <!-- 左侧 -->
275
+ <div class="settings-panel">
276
+
277
+ <!-- 引擎 / Det / Rec 面板保持原样 -->
278
+ <div class="section-title" style="margin-top:0">引擎配置</div>
279
+
280
+ <label class="form-label">推理引擎</label>
281
+ <select class="form-select mb-2" id="global-engine">
282
+ <option value="ONNXRUNTIME" selected>ONNXRuntime</option>
283
+ <option value="OPENVINO">OpenVINO</option>
284
+ <option value="PADDLE">Paddle</option>
285
+ </select>
286
+
287
+ <label class="form-label">识别语言 (Lang)</label>
288
+ <select class="form-select mb-2" id="rec-lang">
289
+ <optgroup label="常用 (v4/v5 通用)">
290
+ <option value="CH" selected>中英日混合 (CH)</option>
291
+ <option value="EN">纯英文 (EN)</option>
292
+ <option value="chinese_cht">中文繁体 (chinese_cht)</option>
293
+ </optgroup>
294
+ <optgroup label="亚洲语系">
295
+ <option value="japan">日文 (japan)</option>
296
+ <option value="korean">韩文 (korean)</option>
297
+ <option value="th">泰文 (th)</option>
298
+ <option value="devanagari">梵文 (devanagari)</option>
299
+ <option value="ta">泰米尔文 (ta)</option>
300
+ <option value="te">泰卢固文 (te)</option>
301
+ <option value="ka">卡纳达语 (ka)</option>
302
+ </optgroup>
303
+ <optgroup label="欧洲及其他">
304
+ <option value="cyrillic">俄罗斯文/斯拉夫 (cyrillic)</option>
305
+ <option value="el">希腊文 (el)</option>
306
+ <option value="latin">拉丁语种 (latin)</option>
307
+ <option value="arabic">阿拉伯文 (arabic)</option>
308
+ <option value="eslav">俄罗斯文/旧版 (eslav)</option>
309
+ </optgroup>
310
+ </select>
311
+
312
+ <div class="section-title">模型版本 (OCR Version)</div>
313
+ <div class="row g-2 mb-2">
314
+ <div class="col-4">
315
+ <label class="form-label">Det</label>
316
+ <select class="form-select" id="det-ver">
317
+ <option value="PPOCRV4" selected>v4</option>
318
+ <option value="PPOCRV5">v5</option>
319
+ </select>
320
+ </div>
321
+ <div class="col-4">
322
+ <label class="form-label">Cls</label>
323
+ <select class="form-select" id="cls-ver">
324
+ <option value="PPOCRV4" selected>v4</option>
325
+ <option value="PPOCRV5">v5</option>
326
+ </select>
327
+ </div>
328
+ <div class="col-4">
329
+ <label class="form-label">Rec</label>
330
+ <select class="form-select" id="rec-ver">
331
+ <option value="PPOCRV5" selected>v5</option>
332
+ <option value="PPOCRV4">v4</option>
333
+ </select>
334
+ </div>
335
+ </div>
336
+
337
+ <div class="section-title">功能开关</div>
338
+ <div class="d-flex flex-wrap gap-3 mb-2">
339
+ <div class="form-check">
340
+ <input class="form-check-input" type="checkbox" id="use-det" checked>
341
+ <label class="form-check-label" style="font-size:11px">文字检测(Det)</label>
342
+ </div>
343
+ <div class="form-check">
344
+ <input class="form-check-input" type="checkbox" id="use-cls" checked>
345
+ <label class="form-check-label" style="font-size:11px">方向分类(Cls)</label>
346
+ </div>
347
+ <div class="form-check">
348
+ <input class="form-check-input" type="checkbox" id="use-rec" checked>
349
+ <label class="form-check-label" style="font-size:11px">识别内容(Rec)</label>
350
+ </div>
351
+ </div>
352
+
353
+ <div class="section-title">结果检索 (Search)</div>
354
+ <ul class="nav nav-pills mb-2" id="search-tabs" style="font-size: 10px;">
355
+ <li class="nav-item">
356
+ <button class="nav-link active py-1 px-2" data-mode="default">全量输出</button>
357
+ </li>
358
+ <li class="nav-item">
359
+ <button class="nav-link py-1 px-2" data-mode="find">检索单个</button>
360
+ </li>
361
+ <li class="nav-item">
362
+ <button class="nav-link py-1 px-2" data-mode="find_all">检索所有</button>
363
+ </li>
364
+ </ul>
365
+
366
+ <div id="search-config-panel" class="p-2"
367
+ style="background: #1b1b1b; border: 1px solid var(--border-color); border-radius: 2px;">
368
+ <div id="search-params-content" style="display:none">
369
+ <div class="mb-2">
370
+ <label class="form-label d-block mb-1">文本正则 (text_re)</label>
371
+ <input type="text" id="search-re" class="form-control"
372
+ style="background:#3c3c3c; border:1px solid #3c3c3c; color:#eee; font-size:11px; height:26px;"
373
+ placeholder="输入正则或文本...">
374
+ </div>
375
+ <div class="mb-2">
376
+ <div class="d-flex justify-content-between">
377
+ <label class="form-label mb-1">得分阈值 (score)</label>
378
+ <span id="score-val" style="font-size:10px; color:var(--accent-color)">0.85</span>
379
+ </div>
380
+ <input type="range" id="search-score" class="form-range" min="0" max="1" step="0.01"
381
+ value="0.85">
382
+ </div>
383
+ <div id="single-only-params" class="form-check mt-1">
384
+ <input class="form-check-input" type="checkbox" id="append-click">
385
+ <label class="form-check-label" style="font-size:11px; color:#888">追加 .click()</label>
386
+ </div>
387
+ </div>
388
+ <div id="search-default-msg" style="font-size:11px; color:#666; text-align:center; padding:10px 0;">
389
+ <i class="bi bi-info-circle"></i> 当前模式将遍历并打印所有结果
390
+ </div>
391
+ </div>
392
+
393
+ <button class="btn btn-primary btn-sm mt-2" id="btn-run-ocr">
394
+ <i class="bi bi-cpu-fill"></i> 运行识别
395
+ </button>
396
+
397
+ <div class="results-wrapper mt-3">
398
+ <div class="results-header">
399
+ <span id="results-title">结果列表(0)</span>
400
+ <button class="btn btn-sm btn-link text-danger p-0" id="btn-clear-results" title="清空结果">
401
+ <i class="bi bi-trash"></i>
402
+ </button>
403
+ </div>
404
+ <div class="results-list" id="results-list"></div>
405
+ </div>
406
+ </div>
407
+
408
+ <!-- 工作区 -->
409
+ <div class="workspace">
410
+ <div class="canvas-area">
411
+ <div class="img-viewport">
412
+ <img id="preview-img" title="点击放大" src="../img/svg/img_default.svg" />
413
+ </div>
414
+ </div>
415
+
416
+
417
+ <div class="code-console">
418
+ <div class="p-2 border-bottom border-secondary d-flex justify-content-between">
419
+ <span style="font-size:10px;color:#888">PYTHON SCRIPT</span>
420
+ <button class="btn btn-sm btn-link text-white py-0" id="btn-copy-code">Copy</button>
421
+ </div>
422
+ <div class="code-display" id="python-code"></div>
423
+ </div>
424
+ </div>
425
+ </div>
426
+
427
+ <script src="../libs/jquery/jquery.min.js"></script>
428
+
429
+ <script>
430
+ function addLog(msg) {
431
+ $('#log-container').append(`<div>> ${msg}</div>`).scrollTop(999999);
432
+ }
433
+
434
+ window.on_image_loaded = (d) => { genCode(); };
435
+
436
+ $(function () {
437
+ // 保留原来的功能
438
+ checkEnvironment();
439
+ $('select').on('change', genCode);
440
+ // 监听开关变化,实时更新下方 Python 预览代码
441
+ $('#use-det, #use-cls, #use-rec').on('change', genCode);
442
+ genCode();
443
+
444
+ $('#btn-copy-code').click(function () {
445
+ const code = $('#python-code').text();
446
+ if (!code) return;
447
+
448
+ // 1. 执行复制逻辑
449
+ navigator.clipboard.writeText(code).then(() => {
450
+ // 2. 按钮效果反馈
451
+ const $btn = $(this);
452
+ const originalText = 'Copy'; // 恢复原本的文字
453
+
454
+ // 变成绿色勾选状态
455
+ $btn.html('<i class="bi bi-check-lg"></i> Copied!')
456
+ .removeClass('text-white')
457
+ .addClass('text-success')
458
+ .prop('disabled', true); // 暂时禁用防止重复点击
459
+
460
+ // 3. 1.5秒后恢复原样
461
+ setTimeout(() => {
462
+ $btn.text(originalText)
463
+ .removeClass('text-success')
464
+ .addClass('text-white')
465
+ .prop('disabled', false);
466
+ }, 1500);
467
+
468
+ window.parent.gp.info.noti(`${code} 已复制到剪贴板`);
469
+
470
+ }).catch(err => {
471
+ console.error('复制失败:', err);
472
+ });
473
+ });
474
+
475
+ // 清空结果按钮
476
+ $('#btn-clear-results').click(() => {
477
+ $('#results-list').empty();
478
+ $('#results-title').text('结果列表(0)');
479
+ $('#preview-img').attr('src', '../img/svg/img_default.svg');
480
+ window.parent.gp.marks?.clear?.();
481
+ });
482
+
483
+ // 注意:保留原 genTestCode 绑定
484
+ $("#btn-run-ocr").on('click', function () {
485
+
486
+ $("#btn-clear-results").click();
487
+
488
+ const btn = $(this);
489
+ btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm"></span> 识别中...');
490
+ const origText = '<i class="bi bi-cpu-fill"></i> 运行识别';
491
+
492
+ // 调用原来的 genTestCode
493
+ const promise = genTestCode();
494
+
495
+ promise.finally(() => {
496
+ btn.prop('disabled', false).html(origText);
497
+ });
498
+ });
499
+
500
+ $('#search-re, #search-score, #append-click').on('input change', genCode);
501
+
502
+ // 选项卡切换逻辑
503
+ $('#search-tabs .nav-link').on('click', function () {
504
+ $('#search-tabs .nav-link').removeClass('active');
505
+ $(this).addClass('active');
506
+
507
+ const mode = $(this).data('mode');
508
+ if (mode === 'default') {
509
+ $('#search-params-content').hide();
510
+ $('#search-default-msg').show();
511
+ } else {
512
+ $('#search-params-content').show();
513
+ $('#search-default-msg').hide();
514
+ // find_all 模式不显示点击开关
515
+ mode === 'find_all' ? $('#single-only-params').hide() : $('#single-only-params').show();
516
+ }
517
+ genCode();
518
+ });
519
+
520
+ $('#search-score').on('input', function () { $('#score-val').text($(this).val()); });
521
+ });
522
+
523
+ // 重写 renderOCRResults 只用于 UI/框/hover
524
+ function renderOCRResults(ocrData) {
525
+ const $list = $('#results-list').empty();
526
+ window.parent.gp.marks?.clear?.();
527
+
528
+ if (!ocrData) return;
529
+
530
+ // 官方返回格式:[dt_boxes, rec_res, cls_res, elapse]
531
+ // 这里根据你之前的解构逻辑,确保安全访问
532
+ const txts = ocrData.txts || [];
533
+ const boxes = ocrData.boxes || [];
534
+ const scores = ocrData.scores || [];
535
+
536
+ $('#results-title').text(`结果列表(${txts.length})`);
537
+
538
+ txts.forEach((text, i) => {
539
+ const label = i + 1;
540
+ const poly = boxes[i]; // 可能为 undefined
541
+
542
+ // --- 绘制逻辑判断 ---
543
+ // 只有当存在坐标信息(poly)且长度为 4 时才绘制矩形
544
+ if (poly && poly.length > 0) {
545
+ let l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
546
+ poly.forEach(pt => {
547
+ const [x, y] = pt;
548
+ l = Math.min(l, Math.floor(x));
549
+ t = Math.min(t, Math.floor(y));
550
+ r = Math.max(r, Math.floor(x));
551
+ b = Math.max(b, Math.floor(y));
552
+ });
553
+ window.parent.gp.marks.add_rect(String(label), l, t, r, b);
554
+ }
555
+
556
+ const score = scores[i] !== undefined ? (scores[i]).toFixed(2) : '--';
557
+
558
+ const $item = $(`
559
+ <div class="ocr-item">
560
+ <span style="width:28px;text-align:right;color:#666;">${label}</span>
561
+ <span style="flex:1;color:#eee;word-break:break-all;">${text || "(无文字)"}</span>
562
+ <span style="width:50px;color:#6fbfff;text-align:right;">${score}</span>
563
+ </div>
564
+ `);
565
+
566
+ // 只有有框的时候才绑定高亮事件
567
+ if (poly) {
568
+ $item.on('mouseenter', () => window.parent.gp.marks?.high_light(String(label)));
569
+ $item.on('mouseleave', () => window.parent.gp.marks?.high_light_clear());
570
+ }
571
+
572
+ $list.append($item);
573
+ });
574
+ }
575
+
576
+
577
+
578
+ // --- 环境检查逻辑 ---
579
+ async function checkEnvironment() {
580
+ addLog("开始检查本地 Python 环境...");
581
+
582
+ // 初始状态 UI:移除 spinner 标签
583
+ $('#init-text').text('正在初始化环境,请稍候...');
584
+
585
+ // 动态提示文案
586
+ const tips = [
587
+ "正在检测依赖项...",
588
+ "正在配置资源,首次运行请耐心等待...",
589
+ "正在下载或校验组件,请勿关闭...",
590
+ "即将完成,正在做最后的准备..."
591
+ ];
592
+
593
+ let tipIdx = 0;
594
+ const tipTimer = setInterval(() => {
595
+ const currentTip = tips[tipIdx % tips.length];
596
+ addLog(`<span style="color: #6c757d;">[进度] ${currentTip}</span>`);
597
+ // 仅更新纯文字内容
598
+ $('#init-text').text(currentTip);
599
+ tipIdx++;
600
+ }, 6000);
601
+
602
+ const checkCode = `
603
+ from ascript.windows.system import Pip
604
+ try:
605
+ # 这里会自动调用我们之前写的智能择源 Pip 类
606
+ Pip.ensure('rapidocr')
607
+ Pip.ensure('onnxruntime')
608
+ _result = True
609
+ except Exception as e:
610
+ _result = str(e)
611
+ `;
612
+
613
+ try {
614
+ const res = await window.parent.gp.call_python(checkCode);
615
+ clearInterval(tipTimer);
616
+
617
+ if (res === true) {
618
+ addLog("<span style='color:green'><b>环境就绪!</b></span>");
619
+ $('#init-text').text("加载成功")
620
+ .removeClass("text-danger")
621
+ .addClass("text-success");
622
+ // 稍作停顿后淡出遮罩层
623
+ setTimeout(() => $('#init-overlay').fadeOut(), 800);
624
+ } else {
625
+ addLog("<span style='color:red'>初始化失败: " + res + "</span>");
626
+ $('#init-text').text("配置失败").addClass("text-danger");
627
+ }
628
+ } catch (e) {
629
+ clearInterval(tipTimer);
630
+ addLog("<span style='color:red'>通信异常: 无法连接 Python 服务</span>");
631
+ $('#init-text').text("连接异常").addClass("text-danger");
632
+ }
633
+ }
634
+
635
+ async function genTestCode() {
636
+ // 1. 获取引擎基础配置
637
+ const engine = $('#global-engine').val();
638
+ const detVer = $('#det-ver').val();
639
+ const clsVer = $('#cls-ver').val();
640
+ const recVer = $('#rec-ver').val();
641
+ const recLang = $('#rec-lang').val();
642
+
643
+ // 2. 获取功能开关(对应 Python 的 use_det, use_cls, use_rec 参数)
644
+ const useDet = $('#use-det').is(':checked') ? "" : ", use_det=False";
645
+ const useCls = $('#use-cls').is(':checked') ? "" : ", use_cls=False";
646
+ const useRec = $('#use-rec').is(':checked') ? "" : ", use_rec=False";
647
+
648
+ // 3. 获取检索面板配置
649
+ const searchMode = $('#search-tabs .active').data('mode');
650
+ const textRe = $('#search-re').val().trim();
651
+ const scoreThreshold = $('#search-score').val();
652
+ const appendClick = $('#append-click').is(':checked');
653
+
654
+ // 4. 构建初始化参数和 Imports 列表
655
+ const defaults = { engine: "ONNXRUNTIME", detVer: "PPOCRV4", clsVer: "PPOCRV4", recVer: "PPOCRV5", recLang: "CH" };
656
+ let params = [];
657
+ let importList = ["RapidOCR"];
658
+
659
+ if (engine !== defaults.engine) {
660
+ importList.push("EngineType");
661
+ params.push(`"Det.engine_type": EngineType.${engine}`, `"Rec.engine_type": EngineType.${engine}`, `"Cls.engine_type": EngineType.${engine}`);
662
+ }
663
+ if (detVer !== defaults.detVer || clsVer !== defaults.clsVer || recVer !== defaults.recVer) {
664
+ importList.push("OCRVersion");
665
+ if (detVer !== defaults.detVer) params.push(`"Det.ocr_version": OCRVersion.${detVer}`);
666
+ if (clsVer !== defaults.clsVer) params.push(`"Cls.ocr_version": OCRVersion.${clsVer}`);
667
+ if (recVer !== defaults.recVer) params.push(`"Rec.ocr_version": OCRVersion.${recVer}`);
668
+ }
669
+ if (recLang !== defaults.recLang) {
670
+ importList.push("LangRec");
671
+ params.push(`"Rec.lang_type": LangRec.${recLang.toUpperCase()}`);
672
+ }
673
+
674
+ const uniqueImports = Array.from(new Set(importList)).sort().join(", ");
675
+
676
+ // 5. 组装 Python find/find_all 调用的参数字符串
677
+ let searchArgs = [];
678
+ if (textRe) {
679
+ searchArgs.push(`text_re=r"${textRe.replace(/"/g, '\\"')}"`);
680
+ }
681
+ if (parseFloat(scoreThreshold) !== 0.85) {
682
+ searchArgs.push(`score=${scoreThreshold}`);
683
+ }
684
+ const argStr = searchArgs.join(', ');
685
+
686
+ // 6. 编写完整的 Python 执行脚本
687
+ let pythonCode = `from rapidocr import ${uniqueImports}
688
+ import cv2, base64
689
+ from ascript.windows.screen.ocr import rapidocr_hook
690
+ # 注入 AScript 增强方法
691
+ rapidocr_hook.install()
692
+
693
+ params_dict = {
694
+ ${params.join(',\n ')}
695
+ }
696
+ engine = RapidOCR(params=params_dict if params_dict else None)
697
+ img_path = r"${window.parent.gp.image.path}"
698
+
699
+ # A. 执行 OCR 识别获取全量结果
700
+ full_result = engine(img_path${useDet}${useCls}${useRec})
701
+
702
+ # B. 逻辑处理:根据模式决定 final_data
703
+ logic_log = ""
704
+ final_data = None
705
+
706
+ # 定义内部 Mock 类,用于统一检索模式的返回格式
707
+ class MockResult:
708
+ def __init__(self, items):
709
+ # items 可能是单个对象也可能是列表
710
+ if not isinstance(items, list):
711
+ items = [items] if items else []
712
+
713
+ # 过滤掉 None 或 NullOCRItem
714
+ valid_items = [i for i in items if i]
715
+
716
+ self.txts = [i.txt for i in valid_items]
717
+ self.boxes = [i.box.tolist() if hasattr(i.box, "tolist") else i.box for i in valid_items]
718
+ self.scores = [float(i.score) for i in valid_items]
719
+
720
+ if "${searchMode}" == "find":
721
+ target = full_result.find(${argStr})
722
+ # 执行点击逻辑
723
+ if ${appendClick ? 'True' : 'False'} and target:
724
+ ${window.parent?.gp?.window?.title ?
725
+ 'from ascript.windows.window import Window\n win = Window.find("' + window.parent.gp.window.title.replace(/"/g, '\\"') + '")\n target.click(win)' :
726
+ 'target.click()'}
727
+
728
+ # 包装单条结果供渲染
729
+ final_data = MockResult(target)
730
+ logic_log = f"Find: {target}"
731
+
732
+ elif "${searchMode}" == "find_all":
733
+ targets = full_result.find_all(${argStr})
734
+ # 包装多条结果供渲染
735
+ final_data = MockResult(targets)
736
+ logic_log = f"FindAll: Found {len(targets)} items"
737
+
738
+ else:
739
+ # --- 全量显示模式 ---
740
+ # 直接返回原始的 RapidOCROutput 对象,避免迭代报错
741
+ final_data = full_result
742
+ logic_log = "Default mode: Showing all results"
743
+
744
+ # C. 生成可视化预览图(红框渲染)
745
+ success, buffer = cv2.imencode('.jpg', full_result.vis())
746
+ img_base64 = base64.b64encode(buffer).decode('utf-8')
747
+
748
+ # D. 构造最终返回给 Eel/JS 的结果元组
749
+ _result = (final_data, f"data:image/jpeg;base64,{img_base64}", logic_log)
750
+ `;
751
+
752
+ // 7. 调用 Python 并处理 UI 渲染回调
753
+ try {
754
+ const res = await window.parent.gp.call_python(pythonCode);
755
+ if (res) {
756
+ const [ocrData, imgBase64, logMsg] = res;
757
+
758
+ // 更新图片预览区域
759
+ $('#preview-img').attr('src', imgBase64);
760
+
761
+ // 渲染左侧结果列表
762
+ // 如果是全量,ocrData 是原始对象;如果是检索,ocrData 是 MockResult 对象
763
+ renderOCRResults(ocrData);
764
+
765
+ // 在控制台输出逻辑执行结果
766
+ console.log("Python Logic Output:", logMsg);
767
+ }
768
+ } catch (e) {
769
+ // 这里的 addLog 假设你有一个日志输出组件,如果没有可以注释掉
770
+ if (typeof addLog === 'function') {
771
+ addLog(`<span style="color:red">OCR 执行异常: ${e.message}</span>`);
772
+ }
773
+ console.error("OCR 执行失败:", e);
774
+ }
775
+ }
776
+
777
+ function genCode() {
778
+ // 1. 获取 UI 配置值
779
+ const engine = $('#global-engine').val();
780
+ const detVer = $('#det-ver').val();
781
+ const clsVer = $('#cls-ver').val();
782
+ const recVer = $('#rec-ver').val();
783
+ const recLang = $('#rec-lang').val();
784
+
785
+ // 2. 功能开关 (仅关闭时生成参数)
786
+ const useDetParam = $('#use-det').is(':checked') ? "" : ", use_det=False";
787
+ const useClsParam = $('#use-cls').is(':checked') ? "" : ", use_cls=False";
788
+ const useRecParam = $('#use-rec').is(':checked') ? "" : ", use_rec=False";
789
+
790
+ const winTitle = window.parent?.gp?.window?.title;
791
+ const hasWindowTitle = !!(winTitle && winTitle.trim());
792
+
793
+ // 3. 定义默认值 (用于差量生成)
794
+ const defaults = {
795
+ engine: "ONNXRUNTIME",
796
+ detVer: "PPOCRV4",
797
+ clsVer: "PPOCRV4",
798
+ recVer: "PPOCRV5",
799
+ recLang: "CH"
800
+ };
801
+
802
+ let params = [];
803
+ let rapidImports = new Set(["RapidOCR"]);
804
+
805
+ // ---------- 参数差量判断 ----------
806
+
807
+ // 引擎类型
808
+ if (engine !== defaults.engine) {
809
+ rapidImports.add("EngineType");
810
+ params.push(`"Det.engine_type": EngineType.${engine}`);
811
+ params.push(`"Rec.engine_type": EngineType.${engine}`);
812
+ params.push(`"Cls.engine_type": EngineType.${engine}`);
813
+ }
814
+
815
+ // 各模型版本
816
+ if (detVer !== defaults.detVer || clsVer !== defaults.clsVer || recVer !== defaults.recVer) {
817
+ rapidImports.add("OCRVersion");
818
+ if (detVer !== defaults.detVer) params.push(`"Det.ocr_version": OCRVersion.${detVer}`);
819
+ if (clsVer !== defaults.clsVer) params.push(`"Cls.ocr_version": OCRVersion.${clsVer}`);
820
+ if (recVer !== defaults.recVer) params.push(`"Rec.ocr_version": OCRVersion.${recVer}`);
821
+ }
822
+
823
+ // 识别语种
824
+ if (recLang !== defaults.recLang) {
825
+ rapidImports.add("LangRec");
826
+ params.push(`"Rec.lang_type": LangRec.${recLang.toUpperCase()}`);
827
+ }
828
+
829
+ // ---------- 拼接 Python 代码 ----------
830
+
831
+ // A. 导入区 (按字母排序更美观)
832
+ let pythonCode = `from rapidocr import ${Array.from(rapidImports).sort().join(", ")}\n`;
833
+ if (hasWindowTitle) {
834
+ pythonCode += `from ascript.windows.window import Window\n\n`;
835
+ } else {
836
+ pythonCode += `from ascript.windows.screen import Screen\n\n`;
837
+ }
838
+
839
+ // B. 实例化区
840
+ if (params.length > 0) {
841
+ pythonCode += `engine = RapidOCR(\n params={\n`;
842
+ pythonCode += params.map(p => ` ${p},`).join('\n');
843
+ pythonCode += `\n }\n)\n\n`;
844
+ } else {
845
+ pythonCode += `engine = RapidOCR()\n\n`;
846
+ }
847
+
848
+ // C. 图像获取区
849
+ if (hasWindowTitle) {
850
+ pythonCode += `img = Window.find("${winTitle.replace(/"/g, '\\"')}").capture()\n`;
851
+ } else {
852
+ pythonCode += `img = Screen.capture()\n`;
853
+ }
854
+
855
+ // 获取检索参数
856
+ const searchMode = $('#search-tabs .active').data('mode');
857
+ const textRe = $('#search-re').val().trim();
858
+ const scoreThreshold = $('#search-score').val();
859
+ const appendClick = $('#append-click').is(':checked');
860
+
861
+ // 组装检索参数字符串
862
+ let searchArgs = [];
863
+ if (textRe) searchArgs.push(`text_re=r"${textRe.replace(/"/g, '\\"')}"`);
864
+ if (parseFloat(scoreThreshold) !== 0.85) searchArgs.push(`score=${scoreThreshold}`);
865
+ const argStr = searchArgs.join(', ');
866
+
867
+ // D. 根据模式生成结果处理代码
868
+ let resultSection = "";
869
+
870
+ if (searchMode === 'default') {
871
+ // 默认遍历模式
872
+ resultSection = `result = engine(img${useDetParam}${useClsParam}${useRecParam})\n`;
873
+ resultSection += `for txt, box, score in zip(result.txts, result.boxes, result.scores):\n`;
874
+ resultSection += ` print(f"文本:{txt}, 区域:{box}, 得分:{score}")`;
875
+ }
876
+ // 修改 genCode 函数中的 find 分支逻辑
877
+ else if (searchMode === 'find') {
878
+ // 组装链式调用
879
+ let chain = `engine(img${useDetParam}${useClsParam}${useRecParam}).find(${argStr})`;
880
+
881
+ if (appendClick) {
882
+ // 直接在 find() 后面追加 .click()
883
+ const clickArgs = hasWindowTitle ? `win` : ``;
884
+ chain += `.click(${clickArgs})`;
885
+ }
886
+
887
+ resultSection = `item = ${chain}\n`;
888
+ resultSection += `print(item)`;
889
+ }
890
+ else if (searchMode === 'find_all') {
891
+ // 批量检索模式
892
+ resultSection = `items = engine(img${useDetParam}${useClsParam}${useRecParam}).find_all(${argStr})\n`;
893
+ resultSection += `for item in items:\n`;
894
+ resultSection += ` print(item)`;
895
+ }
896
+
897
+ pythonCode += resultSection;
898
+ $('#python-code').text(pythonCode.trim());
899
+ }
900
+
901
+ </script>
902
+
903
+ <script>
904
+ // 点击右侧图片打开新窗口预览
905
+ $('#preview-img').on('click', function () {
906
+ const src = $(this).attr('src');
907
+ if (!src) return;
908
+
909
+ // 打开新窗口
910
+ const win = window.open('', '_blank');
911
+
912
+ // 写入 HTML,只显示一张图片,最大边撑满窗口
913
+ const doc = win.document;
914
+ doc.open();
915
+ doc.write(`
916
+ <!DOCTYPE html>
917
+ <html>
918
+ <head>
919
+ <title>图片预览</title>
920
+ <style>
921
+ html, body {
922
+ margin: 0;
923
+ padding: 0;
924
+ width: 100%;
925
+ height: 100%;
926
+ background: #111;
927
+ display: flex;
928
+ justify-content: center;
929
+ align-items: center;
930
+ overflow: auto;
931
+ }
932
+ img {
933
+ max-width: 100%;
934
+ max-height: 100%;
935
+ }
936
+ </style>
937
+ </head>
938
+ <body>
939
+ <img src="${src}" alt="Preview">
940
+ </body>
941
+ </html>
942
+ `);
943
+ doc.close();
944
+ });
945
+
946
+
947
+
948
+
949
+
950
+ </script>
951
+
952
+ </body>
953
+
954
+ </html>