android-midscene-automation 0.1.0

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 (78) hide show
  1. package/README.md +160 -0
  2. package/bin/android-midscene-automation.js +27 -0
  3. package/index.html +12 -0
  4. package/package.json +49 -0
  5. package/remote-agent/index.ts +206 -0
  6. package/server/appium-recorder/appium-runner.ts +427 -0
  7. package/server/appium-recorder/repository.ts +228 -0
  8. package/server/appium-recorder/routes.ts +219 -0
  9. package/server/config-store.ts +167 -0
  10. package/server/config.ts +130 -0
  11. package/server/device-locks/repository.ts +147 -0
  12. package/server/device-locks/service.ts +72 -0
  13. package/server/device-locks/types.ts +22 -0
  14. package/server/device-sessions/repository.ts +169 -0
  15. package/server/device-sessions/service.ts +59 -0
  16. package/server/device-sessions/types.ts +24 -0
  17. package/server/http-api.ts +1389 -0
  18. package/server/model-call-usage-importer.ts +108 -0
  19. package/server/model-tester.ts +104 -0
  20. package/server/model-usage-repository.ts +131 -0
  21. package/server/operations/repository.ts +218 -0
  22. package/server/operations/service.ts +84 -0
  23. package/server/operations/types.ts +27 -0
  24. package/server/paths.ts +27 -0
  25. package/server/remote-agents/protocol.ts +38 -0
  26. package/server/remote-agents/registry.ts +136 -0
  27. package/server/remote-agents/routes.ts +89 -0
  28. package/server/script-agent.ts +284 -0
  29. package/server/script-db.ts +281 -0
  30. package/server/script-runner.ts +551 -0
  31. package/server/storage/sqlite.ts +49 -0
  32. package/server/test-case-import/formatter.ts +28 -0
  33. package/server/test-case-import/parsers/excel.ts +69 -0
  34. package/server/test-case-import/parsers/txt.ts +11 -0
  35. package/server/test-case-import/parsers/word.ts +9 -0
  36. package/server/test-case-import/service.ts +58 -0
  37. package/server/test-case-import/text-normalizer.ts +98 -0
  38. package/server/test-case-import/types.ts +24 -0
  39. package/server/test-case-import/validator.ts +34 -0
  40. package/src/App.vue +1450 -0
  41. package/src/api.ts +290 -0
  42. package/src/appium-recorder/AppiumPage.vue +894 -0
  43. package/src/appium-recorder/api.ts +64 -0
  44. package/src/appium-recorder/components/ComponentTree.vue +44 -0
  45. package/src/appium-recorder/components/NodeDetail.vue +152 -0
  46. package/src/appium-recorder/components/RecordedSteps.vue +79 -0
  47. package/src/appium-recorder/tree.ts +129 -0
  48. package/src/appium-recorder/types.ts +88 -0
  49. package/src/assets/device-actions/back.svg +5 -0
  50. package/src/assets/device-actions/home.svg +3 -0
  51. package/src/assets/device-actions/power.svg +5 -0
  52. package/src/assets/device-actions/tasks.svg +3 -0
  53. package/src/assets/device-actions/volume-down.svg +3 -0
  54. package/src/assets/device-actions/volume-up.svg +3 -0
  55. package/src/components/config/ModelUsageChart.vue +188 -0
  56. package/src/components/device/DevicePreviewPanel.vue +266 -0
  57. package/src/components/generator/GeneratedCodePanel.vue +70 -0
  58. package/src/components/generator/TestCaseFileUpload.vue +97 -0
  59. package/src/config/midscene-model-presets.ts +75 -0
  60. package/src/config/prompt-example.ts +6 -0
  61. package/src/main.ts +7 -0
  62. package/src/pages/AiGeneratorPage.vue +90 -0
  63. package/src/pages/AutomationPage.vue +161 -0
  64. package/src/pages/ConfigPage.vue +273 -0
  65. package/src/pages/GeneratorPage.vue +97 -0
  66. package/src/pages/ManualStepsPage.vue +179 -0
  67. package/src/script-generator/codegen.ts +126 -0
  68. package/src/script-generator/index.ts +4 -0
  69. package/src/script-generator/presets.ts +37 -0
  70. package/src/script-generator/step-options.ts +52 -0
  71. package/src/script-generator/types.ts +27 -0
  72. package/src/style.css +1983 -0
  73. package/src/types.ts +157 -0
  74. package/src/vite-env.d.ts +1 -0
  75. package/tsconfig.app.json +8 -0
  76. package/tsconfig.json +11 -0
  77. package/tsconfig.node.json +16 -0
  78. package/vite.config.ts +28 -0
package/src/style.css ADDED
@@ -0,0 +1,1983 @@
1
+ :root {
2
+ color: #303133;
3
+ background: #f5f7fa;
4
+ font-family:
5
+ "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif;
6
+ line-height: 1.5;
7
+ font-weight: 400;
8
+ }
9
+
10
+ * {
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ html,
15
+ body,
16
+ #app {
17
+ height: 100%;
18
+ overflow: hidden;
19
+ }
20
+
21
+ body {
22
+ margin: 0;
23
+ min-width: 1280px;
24
+ background: #f5f7fa;
25
+ }
26
+
27
+ button,
28
+ input,
29
+ textarea,
30
+ select {
31
+ font: inherit;
32
+ }
33
+
34
+ .layout {
35
+ display: grid;
36
+ grid-template-columns: 220px minmax(0, 1fr);
37
+ height: 100%;
38
+ min-height: 0;
39
+ overflow: hidden;
40
+ }
41
+
42
+ .layout-sidebar {
43
+ border-right: 1px solid #e4e7ed;
44
+ background: #001529;
45
+ }
46
+
47
+ .layout-sidebar__top {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ height: 60px;
52
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
53
+ }
54
+
55
+ .layout-sidebar__logo {
56
+ display: grid;
57
+ place-items: center;
58
+ width: 36px;
59
+ height: 36px;
60
+ border-radius: 8px;
61
+ background: #1677ff;
62
+ color: #fff;
63
+ font-weight: 700;
64
+ }
65
+
66
+ .layout-menu {
67
+ border-right: 0;
68
+ background: transparent;
69
+ }
70
+
71
+ .layout-menu.el-menu {
72
+ --el-menu-bg-color: #001529;
73
+ --el-menu-text-color: rgba(255, 255, 255, 0.85);
74
+ --el-menu-hover-bg-color: #0a2540;
75
+ --el-menu-active-color: #fff;
76
+ }
77
+
78
+ .layout-main {
79
+ display: grid;
80
+ grid-template-rows: 60px minmax(0, 1fr);
81
+ min-height: 0;
82
+ overflow: hidden;
83
+ }
84
+
85
+ .action-dialog__body {
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ gap: 8px;
90
+ min-height: 56px;
91
+ padding: 4px 0;
92
+ color: #303133;
93
+ font-size: 14px;
94
+ }
95
+
96
+ .action-dialog__spinner {
97
+ font-size: 16px;
98
+ animation: action-dialog-spin 1s linear infinite;
99
+ }
100
+
101
+ .action-dialog__error {
102
+ min-height: 0;
103
+ padding: 4px 0 2px;
104
+ color: #f56c6c;
105
+ font-size: 13px;
106
+ line-height: 1.6;
107
+ white-space: pre-wrap;
108
+ }
109
+
110
+ .action-dialog .el-dialog__header {
111
+ margin-right: 0;
112
+ padding: 14px 16px 6px;
113
+ }
114
+
115
+ .action-dialog .el-dialog__body {
116
+ padding: 8px 16px 6px;
117
+ }
118
+
119
+ .action-dialog .el-dialog__footer {
120
+ padding: 6px 16px 14px;
121
+ }
122
+
123
+ @keyframes action-dialog-spin {
124
+ from {
125
+ transform: rotate(0deg);
126
+ }
127
+
128
+ to {
129
+ transform: rotate(360deg);
130
+ }
131
+ }
132
+
133
+ .layout-header {
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: space-between;
137
+ padding: 0 24px;
138
+ border-bottom: 1px solid #e4e7ed;
139
+ background: #fff;
140
+ }
141
+
142
+ .layout-header__title {
143
+ font-size: 18px;
144
+ font-weight: 600;
145
+ }
146
+
147
+ .layout-header__actions {
148
+ display: flex;
149
+ gap: 12px;
150
+ }
151
+
152
+ .page-body {
153
+ height: 100%;
154
+ min-height: 0;
155
+ overflow: auto;
156
+ padding: 24px;
157
+ }
158
+
159
+ .page-body--fixed {
160
+ overflow: hidden;
161
+ }
162
+
163
+ .page-alert,
164
+ .page-section {
165
+ margin-bottom: 16px;
166
+ }
167
+
168
+ .appium-recorder-page {
169
+ display: flex;
170
+ flex-direction: column;
171
+ gap: 12px;
172
+ height: 100%;
173
+ min-height: 0;
174
+ }
175
+
176
+ .appium-header-actions {
177
+ position: fixed;
178
+ top: 0;
179
+ right: 24px;
180
+ z-index: 10;
181
+ display: flex;
182
+ align-items: center;
183
+ gap: 12px;
184
+ height: 60px;
185
+ min-width: 0;
186
+ }
187
+
188
+ .appium-header-actions__script {
189
+ width: 240px;
190
+ }
191
+
192
+ .appium-recorder-layout {
193
+ display: grid;
194
+ flex: 1 1 auto;
195
+ grid-template-columns: minmax(0, 4fr) minmax(320px, 3fr) minmax(0, 3fr);
196
+ gap: 12px;
197
+ align-items: stretch;
198
+ height: auto;
199
+ min-height: 0;
200
+ }
201
+
202
+ .appium-recorder-card.el-card {
203
+ display: flex;
204
+ min-height: 0;
205
+ flex-direction: column;
206
+ overflow: hidden;
207
+ }
208
+
209
+ .appium-recorder-card > .el-card__body {
210
+ flex: 1 1 auto;
211
+ min-height: 0;
212
+ overflow: auto;
213
+ }
214
+
215
+ .appium-recorder-layout > .device-preview-card.el-card {
216
+ display: flex;
217
+ min-height: 0;
218
+ flex-direction: column;
219
+ overflow: hidden;
220
+ }
221
+
222
+ .appium-recorder-layout > .device-preview-card > .el-card__body {
223
+ display: flex;
224
+ min-height: 0;
225
+ flex-direction: column;
226
+ overflow: hidden;
227
+ }
228
+
229
+ .appium-recorder-layout > .device-preview-card .device-toolbar,
230
+ .appium-recorder-layout > .device-preview-card .device-actions {
231
+ flex: 0 0 auto;
232
+ }
233
+
234
+ .appium-recorder-card--workbench > .el-card__body {
235
+ padding: 0;
236
+ }
237
+
238
+ .appium-workbench-tabs {
239
+ display: flex;
240
+ min-height: 0;
241
+ height: 100%;
242
+ flex-direction: column;
243
+ }
244
+
245
+ .appium-workbench-tabs > .el-tabs__header {
246
+ margin: 0;
247
+ padding: 0 16px;
248
+ }
249
+
250
+ .appium-workbench-tabs > .el-tabs__content {
251
+ flex: 1 1 auto;
252
+ min-height: 0;
253
+ overflow: auto;
254
+ }
255
+
256
+ .appium-workbench-tabs .el-tab-pane {
257
+ min-height: 0;
258
+ }
259
+
260
+ .appium-workbench {
261
+ display: grid;
262
+ gap: 16px;
263
+ padding: 16px;
264
+ }
265
+
266
+ .appium-workbench__section {
267
+ min-width: 0;
268
+ }
269
+
270
+ .appium-workbench__section h3 {
271
+ margin: 0 0 12px;
272
+ color: #303133;
273
+ font-size: 16px;
274
+ font-weight: 700;
275
+ }
276
+
277
+ .appium-tree {
278
+ height: 100%;
279
+ min-height: 0;
280
+ overflow: auto;
281
+ scrollbar-color: #c0c4cc transparent;
282
+ }
283
+
284
+ .appium-tree .el-tree {
285
+ min-width: max-content;
286
+ }
287
+
288
+ .appium-tree .el-tree-node__content {
289
+ white-space: nowrap;
290
+ }
291
+
292
+ .appium-tree::-webkit-scrollbar {
293
+ width: 8px;
294
+ height: 8px;
295
+ }
296
+
297
+ .appium-tree::-webkit-scrollbar-track,
298
+ .appium-tree::-webkit-scrollbar-corner {
299
+ background: transparent;
300
+ }
301
+
302
+ .appium-tree::-webkit-scrollbar-thumb {
303
+ border-radius: 4px;
304
+ background: #c0c4cc;
305
+ }
306
+
307
+ .appium-tree-panel {
308
+ display: grid;
309
+ grid-template-rows: minmax(0, 1fr) auto;
310
+ height: 100%;
311
+ min-height: 0;
312
+ }
313
+
314
+ .appium-current-activity {
315
+ display: grid;
316
+ grid-template-columns: auto minmax(0, 1fr);
317
+ align-items: center;
318
+ gap: 12px;
319
+ padding: 12px 0 0;
320
+ border-top: 1px solid #e4e7ed;
321
+ color: #606266;
322
+ font-size: 13px;
323
+ }
324
+
325
+ .appium-current-activity code {
326
+ overflow: hidden;
327
+ color: #303133;
328
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
329
+ text-overflow: ellipsis;
330
+ white-space: nowrap;
331
+ }
332
+
333
+ .appium-node-detail__title {
334
+ margin-bottom: 12px;
335
+ color: #303133;
336
+ font-weight: 700;
337
+ }
338
+
339
+ .appium-side-form {
340
+ display: grid;
341
+ gap: 8px;
342
+ margin-bottom: 12px;
343
+ }
344
+
345
+ .appium-script-list {
346
+ display: grid;
347
+ gap: 10px;
348
+ align-content: start;
349
+ min-height: 0;
350
+ padding: 16px;
351
+ }
352
+
353
+ .appium-script-list__item {
354
+ display: grid;
355
+ grid-template-columns: minmax(0, 1fr) auto;
356
+ gap: 8px;
357
+ align-items: center;
358
+ padding: 10px;
359
+ border: 1px solid #e4e7ed;
360
+ border-radius: 6px;
361
+ background: #fff;
362
+ }
363
+
364
+ .appium-script-list__item--active {
365
+ border-color: #409eff;
366
+ background: #f5f9ff;
367
+ }
368
+
369
+ .appium-script-list__main {
370
+ display: grid;
371
+ gap: 3px;
372
+ min-width: 0;
373
+ }
374
+
375
+ .appium-script-list__main strong,
376
+ .appium-script-list__main span,
377
+ .appium-script-list__main small {
378
+ overflow: hidden;
379
+ text-overflow: ellipsis;
380
+ white-space: nowrap;
381
+ }
382
+
383
+ .appium-script-list__main strong {
384
+ color: #303133;
385
+ font-size: 13px;
386
+ }
387
+
388
+ .appium-script-list__main span,
389
+ .appium-script-list__main small {
390
+ color: #64748b;
391
+ font-size: 12px;
392
+ }
393
+
394
+ .appium-script-list__actions {
395
+ display: flex;
396
+ gap: 6px;
397
+ align-items: center;
398
+ }
399
+
400
+ .appium-action-trigger {
401
+ width: 100%;
402
+ margin-top: 12px;
403
+ }
404
+
405
+ .appium-action-trigger__icon {
406
+ width: 14px;
407
+ height: 14px;
408
+ margin-right: 6px;
409
+ }
410
+
411
+ .appium-action-dropdown {
412
+ max-height: min(320px, calc(100vh - 96px));
413
+ overflow: hidden;
414
+ }
415
+
416
+ .appium-action-dropdown .el-scrollbar__wrap {
417
+ max-height: min(320px, calc(100vh - 96px));
418
+ }
419
+
420
+ .appium-action-dropdown__group {
421
+ padding: 6px 12px 4px;
422
+ color: #909399;
423
+ font-size: 12px;
424
+ line-height: 18px;
425
+ }
426
+
427
+ .appium-action-dropdown__item {
428
+ display: flex;
429
+ align-items: center;
430
+ gap: 8px;
431
+ min-width: 128px;
432
+ }
433
+
434
+ .appium-action-dropdown__item img {
435
+ width: 14px;
436
+ height: 14px;
437
+ flex: 0 0 auto;
438
+ }
439
+
440
+ .appium-recorded-steps-panel {
441
+ display: grid;
442
+ gap: 8px;
443
+ min-width: 0;
444
+ }
445
+
446
+ .appium-recorded-steps {
447
+ --appium-step-row-height: 88px;
448
+ --appium-step-insert-height: 26px;
449
+ display: grid;
450
+ gap: 8px;
451
+ align-content: start;
452
+ height: calc((var(--appium-step-row-height) + var(--appium-step-insert-height) + 8px) * 4);
453
+ min-width: 0;
454
+ max-width: 100%;
455
+ overflow-x: hidden;
456
+ overflow-y: auto;
457
+ padding-right: 4px;
458
+ scrollbar-color: #c0c4cc transparent;
459
+ }
460
+
461
+ .appium-recorded-steps::-webkit-scrollbar {
462
+ width: 6px;
463
+ }
464
+
465
+ .appium-recorded-steps::-webkit-scrollbar-track {
466
+ background: transparent;
467
+ }
468
+
469
+ .appium-recorded-steps::-webkit-scrollbar-thumb {
470
+ border-radius: 3px;
471
+ background: #c0c4cc;
472
+ }
473
+
474
+ .appium-step-item {
475
+ display: grid;
476
+ gap: 4px;
477
+ min-width: 0;
478
+ }
479
+
480
+ .appium-step-row {
481
+ display: grid;
482
+ grid-template-columns: 28px minmax(0, 1fr) 54px;
483
+ gap: 8px;
484
+ align-items: center;
485
+ padding: 8px;
486
+ border: 1px solid #e4e7ed;
487
+ border-radius: 6px;
488
+ background: #fff;
489
+ min-height: var(--appium-step-row-height);
490
+ min-width: 0;
491
+ max-width: 100%;
492
+ overflow: hidden;
493
+ }
494
+
495
+ .appium-step-row--delay {
496
+ border-style: dashed;
497
+ background: #f8fafc;
498
+ }
499
+
500
+ .appium-step-row__index {
501
+ display: grid;
502
+ place-items: center;
503
+ width: 24px;
504
+ height: 24px;
505
+ border-radius: 50%;
506
+ background: #eef2ff;
507
+ color: #475569;
508
+ font-size: 12px;
509
+ font-weight: 700;
510
+ }
511
+
512
+ .appium-step-row__main {
513
+ display: grid;
514
+ gap: 2px;
515
+ min-width: 0;
516
+ overflow: hidden;
517
+ }
518
+
519
+ .appium-step-row__main strong {
520
+ display: block;
521
+ min-width: 0;
522
+ font-size: 13px;
523
+ line-height: 1.4;
524
+ overflow-wrap: anywhere;
525
+ white-space: normal;
526
+ }
527
+
528
+ .appium-step-row__main small {
529
+ display: block;
530
+ min-width: 0;
531
+ color: #64748b;
532
+ font-size: 12px;
533
+ line-height: 1.4;
534
+ overflow-wrap: anywhere;
535
+ white-space: normal;
536
+ }
537
+
538
+ .appium-step-row__actions {
539
+ display: flex;
540
+ justify-content: flex-end;
541
+ gap: 2px;
542
+ }
543
+
544
+ .appium-step-row__actions .el-button {
545
+ width: 24px;
546
+ height: 24px;
547
+ margin: 0;
548
+ padding: 0;
549
+ }
550
+
551
+ .appium-step-insert-delay {
552
+ display: flex;
553
+ align-items: center;
554
+ justify-content: center;
555
+ gap: 4px;
556
+ height: var(--appium-step-insert-height);
557
+ border: 1px dashed #d6dde8;
558
+ border-radius: 6px;
559
+ background: #fff;
560
+ color: #64748b;
561
+ font-size: 12px;
562
+ cursor: pointer;
563
+ }
564
+
565
+ .appium-step-insert-delay:hover {
566
+ border-color: #409eff;
567
+ color: #409eff;
568
+ background: #f5f9ff;
569
+ }
570
+
571
+ .appium-step-insert-delay:disabled {
572
+ cursor: not-allowed;
573
+ opacity: 0.45;
574
+ }
575
+
576
+ .appium-replay-output {
577
+ min-height: 120px;
578
+ max-height: 260px;
579
+ margin: 0;
580
+ padding: 12px;
581
+ border: 1px solid #e4e7ed;
582
+ border-radius: 6px;
583
+ background: #fff;
584
+ color: #475569;
585
+ font-size: 12px;
586
+ line-height: 1.6;
587
+ overflow: auto;
588
+ white-space: pre;
589
+ }
590
+
591
+ .appium-navigation-dialog {
592
+ display: grid;
593
+ gap: 12px;
594
+ color: #475569;
595
+ font-size: 13px;
596
+ }
597
+
598
+ .appium-navigation-dialog p {
599
+ margin: 0;
600
+ }
601
+
602
+ .appium-navigation-dialog dl {
603
+ display: grid;
604
+ gap: 8px;
605
+ margin: 0;
606
+ }
607
+
608
+ .appium-navigation-dialog dl > div {
609
+ display: grid;
610
+ grid-template-columns: 64px minmax(0, 1fr);
611
+ gap: 10px;
612
+ align-items: start;
613
+ }
614
+
615
+ .appium-navigation-dialog dt {
616
+ color: #64748b;
617
+ font-weight: 700;
618
+ }
619
+
620
+ .appium-navigation-dialog dd {
621
+ min-width: 0;
622
+ margin: 0;
623
+ overflow-wrap: anywhere;
624
+ color: #303133;
625
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
626
+ }
627
+
628
+ .appium-navigation-footer {
629
+ display: flex;
630
+ justify-content: flex-end;
631
+ gap: 12px;
632
+ white-space: nowrap;
633
+ }
634
+
635
+ .appium-navigation-footer .el-button + .el-button {
636
+ margin-left: 0;
637
+ }
638
+
639
+ .subnav {
640
+ display: flex;
641
+ gap: 8px;
642
+ margin-bottom: 16px;
643
+ }
644
+
645
+ .subnav__item {
646
+ padding: 8px 14px;
647
+ border: 1px solid #dcdfe6;
648
+ border-radius: 4px;
649
+ background: #fff;
650
+ color: #606266;
651
+ cursor: pointer;
652
+ }
653
+
654
+ .subnav__item--active {
655
+ border-color: #409eff;
656
+ color: #409eff;
657
+ background: #ecf5ff;
658
+ }
659
+
660
+ .page-grid {
661
+ display: grid;
662
+ grid-template-columns: repeat(2, minmax(0, 1fr));
663
+ gap: 16px;
664
+ margin-bottom: 16px;
665
+ }
666
+
667
+ .page-grid--single {
668
+ grid-template-columns: 1fr;
669
+ }
670
+
671
+ .config-grid {
672
+ display: grid;
673
+ grid-template-columns: 1fr;
674
+ gap: 16px;
675
+ margin-bottom: 16px;
676
+ }
677
+
678
+ .generator-page {
679
+ min-height: 0;
680
+ }
681
+
682
+ .generator-page--ai {
683
+ display: grid;
684
+ grid-template-rows: auto auto minmax(0, 1fr);
685
+ gap: 16px;
686
+ height: 100%;
687
+ min-height: 0;
688
+ overflow: hidden;
689
+ }
690
+
691
+ .generator-page--manual {
692
+ display: block;
693
+ height: auto;
694
+ min-height: 100%;
695
+ overflow: visible;
696
+ }
697
+
698
+ .generator-page--ai .subnav,
699
+ .generator-page--ai .page-grid {
700
+ margin-bottom: 0;
701
+ }
702
+
703
+ .config-page {
704
+ height: 100%;
705
+ min-height: 0;
706
+ overflow: auto;
707
+ }
708
+
709
+ .prompt-card.el-card,
710
+ .manual-steps-card.el-card,
711
+ .generator-code-card.el-card {
712
+ min-height: 0;
713
+ overflow: hidden;
714
+ }
715
+
716
+ .prompt-card > .el-card__body,
717
+ .manual-steps-card > .el-card__body,
718
+ .generator-code-card > .el-card__body {
719
+ min-height: 0;
720
+ overflow: hidden;
721
+ }
722
+
723
+ .manual-steps-card.el-card,
724
+ .generator-code-card.el-card {
725
+ display: flex;
726
+ flex-direction: column;
727
+ }
728
+
729
+ .manual-steps-card > .el-card__body,
730
+ .generator-code-card > .el-card__body {
731
+ display: flex;
732
+ flex-direction: column;
733
+ }
734
+
735
+ .generator-code-card > .el-card__body {
736
+ flex: 1 1 auto;
737
+ height: 100%;
738
+ padding-bottom: 28px;
739
+ }
740
+
741
+ .source-prompt-input .el-textarea__inner {
742
+ height: 320px;
743
+ max-height: 320px;
744
+ overflow-y: auto;
745
+ resize: none;
746
+ }
747
+
748
+ .manual-steps-card .method-guide {
749
+ flex: 0 0 auto;
750
+ }
751
+
752
+ .manual-steps-card .step-list {
753
+ min-height: 0;
754
+ overflow: auto;
755
+ }
756
+
757
+ .manual-steps-card .step-list__footer {
758
+ flex: 0 0 auto;
759
+ }
760
+
761
+ .generator-page--manual .manual-steps-card.el-card {
762
+ display: block;
763
+ overflow: visible;
764
+ }
765
+
766
+ .generator-page--manual .manual-steps-card > .el-card__body {
767
+ display: block;
768
+ overflow: visible;
769
+ }
770
+
771
+ .generator-page--manual .manual-steps-card .step-list {
772
+ overflow: visible;
773
+ }
774
+
775
+ .panel-header {
776
+ display: flex;
777
+ align-items: center;
778
+ justify-content: space-between;
779
+ gap: 12px;
780
+ }
781
+
782
+ .panel-header__title {
783
+ display: flex;
784
+ align-items: center;
785
+ gap: 8px;
786
+ min-width: 0;
787
+ }
788
+
789
+ .panel-header--sub {
790
+ min-height: 32px;
791
+ margin-bottom: 12px;
792
+ }
793
+
794
+ .panel-header__actions {
795
+ display: flex;
796
+ gap: 8px;
797
+ }
798
+
799
+ .config-module-card {
800
+ min-width: 0;
801
+ }
802
+
803
+ .config-model-grid {
804
+ display: grid;
805
+ grid-template-columns: repeat(2, minmax(0, 1fr));
806
+ gap: 18px;
807
+ }
808
+
809
+ .model-usage-chart {
810
+ margin-top: 20px;
811
+ padding-top: 18px;
812
+ border-top: 1px solid #ebeef5;
813
+ }
814
+
815
+ .model-usage-chart__body {
816
+ display: grid;
817
+ gap: 10px;
818
+ }
819
+
820
+ .model-usage-chart__summary,
821
+ .model-usage-chart__legend,
822
+ .model-usage-chart__record {
823
+ display: flex;
824
+ align-items: center;
825
+ gap: 12px;
826
+ min-width: 0;
827
+ color: #64748b;
828
+ font-size: 12px;
829
+ }
830
+
831
+ .model-usage-chart__summary {
832
+ flex-wrap: wrap;
833
+ }
834
+
835
+ .model-usage-chart__svg {
836
+ width: 100%;
837
+ height: 180px;
838
+ display: block;
839
+ border: 1px solid #ebeef5;
840
+ border-radius: 6px;
841
+ background: #fbfdff;
842
+ }
843
+
844
+ .model-usage-chart__axis {
845
+ stroke: #d8dee9;
846
+ stroke-width: 1;
847
+ }
848
+
849
+ .model-usage-chart__line {
850
+ fill: none;
851
+ stroke-linecap: round;
852
+ stroke-linejoin: round;
853
+ stroke-width: 2.5;
854
+ }
855
+
856
+ .model-usage-chart__line--prompt,
857
+ .model-usage-chart__point--prompt {
858
+ stroke: #2563eb;
859
+ }
860
+
861
+ .model-usage-chart__line--completion,
862
+ .model-usage-chart__point--completion {
863
+ stroke: #d97706;
864
+ }
865
+
866
+ .model-usage-chart__line--duration,
867
+ .model-usage-chart__point--duration {
868
+ stroke: #16a34a;
869
+ }
870
+
871
+ .model-usage-chart__point {
872
+ fill: #fff;
873
+ stroke-width: 2;
874
+ }
875
+
876
+ .model-usage-chart__legend {
877
+ flex-wrap: wrap;
878
+ }
879
+
880
+ .model-usage-chart__legend span {
881
+ display: inline-flex;
882
+ align-items: center;
883
+ gap: 6px;
884
+ }
885
+
886
+ .model-usage-chart__swatch {
887
+ width: 18px;
888
+ height: 3px;
889
+ border-radius: 999px;
890
+ }
891
+
892
+ .model-usage-chart__swatch--prompt {
893
+ background: #2563eb;
894
+ }
895
+
896
+ .model-usage-chart__swatch--completion {
897
+ background: #d97706;
898
+ }
899
+
900
+ .model-usage-chart__swatch--duration {
901
+ background: #16a34a;
902
+ }
903
+
904
+ .model-usage-chart__records {
905
+ display: grid;
906
+ gap: 6px;
907
+ height: 220px;
908
+ align-content: start;
909
+ overflow-y: auto;
910
+ padding-right: 4px;
911
+ }
912
+
913
+ .model-usage-chart__record {
914
+ display: grid;
915
+ grid-template-columns: 86px 64px minmax(120px, 1fr) 84px 84px 84px 72px;
916
+ justify-content: initial;
917
+ min-height: 38px;
918
+ padding: 6px 8px;
919
+ border-radius: 6px;
920
+ background: #f8fafc;
921
+ }
922
+
923
+ .model-usage-chart__record--head {
924
+ position: sticky;
925
+ top: 0;
926
+ z-index: 1;
927
+ min-height: 30px;
928
+ background: #eef2f7;
929
+ color: #475569;
930
+ font-weight: 700;
931
+ }
932
+
933
+ .model-usage-chart__record span {
934
+ min-width: 0;
935
+ overflow: hidden;
936
+ text-overflow: ellipsis;
937
+ white-space: nowrap;
938
+ }
939
+
940
+ .app-preset-list {
941
+ display: grid;
942
+ gap: 8px;
943
+ margin-top: 16px;
944
+ max-height: 280px;
945
+ overflow-y: auto;
946
+ padding-right: 4px;
947
+ }
948
+
949
+ .app-preset-row {
950
+ display: flex;
951
+ align-items: center;
952
+ justify-content: space-between;
953
+ gap: 12px;
954
+ min-height: 62px;
955
+ padding: 10px 12px;
956
+ border: 1px solid #ebeef5;
957
+ border-radius: 6px;
958
+ background: #fff;
959
+ }
960
+
961
+ .app-preset-row__main {
962
+ display: grid;
963
+ gap: 4px;
964
+ min-width: 0;
965
+ }
966
+
967
+ .app-preset-row__main strong,
968
+ .app-preset-row__main span {
969
+ overflow: hidden;
970
+ text-overflow: ellipsis;
971
+ white-space: nowrap;
972
+ }
973
+
974
+ .app-preset-row__main span {
975
+ color: #64748b;
976
+ font-size: 12px;
977
+ }
978
+
979
+ .prompt-example {
980
+ max-height: min(62vh, 640px);
981
+ overflow: auto;
982
+ margin: 0;
983
+ padding: 14px;
984
+ border-radius: 6px;
985
+ background: #f8fafc;
986
+ color: #334155;
987
+ font-size: 13px;
988
+ line-height: 1.7;
989
+ white-space: pre-wrap;
990
+ }
991
+
992
+ .method-guide {
993
+ margin-bottom: 16px;
994
+ border: 1px solid #ebeef5;
995
+ border-radius: 6px;
996
+ background: #f4f8ff;
997
+ }
998
+
999
+ .method-guide__summary {
1000
+ padding: 12px 16px;
1001
+ cursor: pointer;
1002
+ color: #303133;
1003
+ font-weight: 500;
1004
+ user-select: none;
1005
+ }
1006
+
1007
+ .method-guide__content {
1008
+ padding: 0 16px 16px;
1009
+ border-top: 1px solid #f0f2f5;
1010
+ }
1011
+
1012
+ .method-guide__row {
1013
+ display: grid;
1014
+ grid-template-columns: 100px minmax(0, 1fr);
1015
+ gap: 12px;
1016
+ padding-top: 12px;
1017
+ color: #606266;
1018
+ font-size: 13px;
1019
+ line-height: 1.6;
1020
+ }
1021
+
1022
+ .method-guide__row strong {
1023
+ color: #303133;
1024
+ }
1025
+
1026
+ .method-guide__text {
1027
+ display: grid;
1028
+ gap: 4px;
1029
+ }
1030
+
1031
+ .method-guide__text code {
1032
+ color: #1d4ed8;
1033
+ font-size: 12px;
1034
+ white-space: pre-wrap;
1035
+ }
1036
+
1037
+ .method-guide__footer,
1038
+ .manual-steps-toolbar {
1039
+ display: flex;
1040
+ justify-content: flex-start;
1041
+ gap: 8px;
1042
+ padding-top: 12px;
1043
+ }
1044
+
1045
+ .manual-steps-toolbar {
1046
+ padding-top: 0;
1047
+ margin-bottom: 16px;
1048
+ }
1049
+
1050
+ .step-list {
1051
+ display: grid;
1052
+ gap: 12px;
1053
+ }
1054
+
1055
+ .step-list--dialog {
1056
+ max-height: min(58vh, 620px);
1057
+ overflow: auto;
1058
+ padding-right: 4px;
1059
+ }
1060
+
1061
+ .generator-page--manual .manual-steps-card .step-list.step-list--dialog,
1062
+ .steps-dialog .step-list.step-list--dialog {
1063
+ max-height: min(58vh, 620px);
1064
+ overflow-x: hidden;
1065
+ overflow-y: auto;
1066
+ overscroll-behavior: contain;
1067
+ }
1068
+
1069
+ .steps-dialog {
1070
+ max-width: calc(100vw - 48px);
1071
+ }
1072
+
1073
+ .steps-dialog.el-dialog,
1074
+ .steps-dialog .el-dialog {
1075
+ display: flex;
1076
+ flex-direction: column;
1077
+ max-height: calc(100vh - 72px);
1078
+ margin-top: 36px;
1079
+ margin-bottom: 36px;
1080
+ }
1081
+
1082
+ .steps-dialog.el-dialog .el-dialog__body,
1083
+ .steps-dialog .el-dialog__body {
1084
+ flex: 1;
1085
+ min-height: 0;
1086
+ overflow: hidden;
1087
+ padding-bottom: 12px;
1088
+ }
1089
+
1090
+ .steps-dialog.el-dialog .el-dialog__footer,
1091
+ .steps-dialog .el-dialog__footer {
1092
+ flex: 0 0 auto;
1093
+ }
1094
+
1095
+ .step-list__footer {
1096
+ display: flex;
1097
+ justify-content: center;
1098
+ margin-top: 16px;
1099
+ }
1100
+
1101
+ .step-item {
1102
+ padding: 16px;
1103
+ border: 1px solid #ebeef5;
1104
+ border-radius: 6px;
1105
+ background: #fafafa;
1106
+ }
1107
+
1108
+ .step-item--readonly {
1109
+ background: #fff;
1110
+ }
1111
+
1112
+ .step-example-code {
1113
+ margin: 10px 0 0;
1114
+ padding: 10px;
1115
+ border-radius: 4px;
1116
+ background: #f8fafc;
1117
+ color: #1d4ed8;
1118
+ font-size: 12px;
1119
+ line-height: 1.6;
1120
+ white-space: pre-wrap;
1121
+ }
1122
+
1123
+ .step-item__top {
1124
+ display: flex;
1125
+ justify-content: space-between;
1126
+ align-items: center;
1127
+ margin-bottom: 12px;
1128
+ }
1129
+
1130
+ .step-item__index {
1131
+ color: #606266;
1132
+ font-size: 13px;
1133
+ font-weight: 600;
1134
+ }
1135
+
1136
+ .step-item__actions {
1137
+ display: flex;
1138
+ align-items: center;
1139
+ gap: 8px;
1140
+ }
1141
+
1142
+ .step-grid {
1143
+ display: grid;
1144
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1145
+ gap: 12px 16px;
1146
+ align-items: start;
1147
+ }
1148
+
1149
+ .step-grid__wide {
1150
+ grid-column: 1 / -1;
1151
+ }
1152
+
1153
+ .step-form .el-form-item {
1154
+ margin-bottom: 0;
1155
+ }
1156
+
1157
+ .step-form .el-form-item__label {
1158
+ padding-bottom: 8px;
1159
+ line-height: 20px;
1160
+ }
1161
+
1162
+ .code-block,
1163
+ .terminal-block {
1164
+ overflow: auto;
1165
+ margin: 0;
1166
+ padding: 16px;
1167
+ border-radius: 6px;
1168
+ background: #0f172a;
1169
+ color: #e2e8f0;
1170
+ font-size: 13px;
1171
+ line-height: 1.6;
1172
+ white-space: pre-wrap;
1173
+ }
1174
+
1175
+ .code-block--small,
1176
+ .terminal-block {
1177
+ max-height: min(220px, 24vh);
1178
+ }
1179
+
1180
+ .generator-code-block {
1181
+ flex: 0 0 auto;
1182
+ height: clamp(240px, 34vh, 320px);
1183
+ min-height: 240px;
1184
+ max-height: 320px;
1185
+ overflow: auto;
1186
+ box-sizing: border-box;
1187
+ padding-bottom: 56px;
1188
+ scroll-padding-bottom: 56px;
1189
+ }
1190
+
1191
+ .generator-page--ai .generator-code-card {
1192
+ min-height: 0;
1193
+ }
1194
+
1195
+ .generator-page--ai .generator-code-block {
1196
+ flex: 1 1 auto;
1197
+ height: auto;
1198
+ min-height: 0;
1199
+ max-height: none;
1200
+ }
1201
+
1202
+ .generator-code-block code {
1203
+ display: block;
1204
+ min-height: 100%;
1205
+ padding-bottom: 24px;
1206
+ }
1207
+
1208
+ .generator-code-block code::after {
1209
+ display: block;
1210
+ height: 28px;
1211
+ content: "";
1212
+ }
1213
+
1214
+ .generator-code-editor {
1215
+ flex: 0 0 auto;
1216
+ height: clamp(240px, 34vh, 320px);
1217
+ min-height: 240px;
1218
+ max-height: 320px;
1219
+ }
1220
+
1221
+ .generator-page--ai .generator-code-editor {
1222
+ flex: 1 1 auto;
1223
+ height: auto;
1224
+ min-height: 0;
1225
+ max-height: none;
1226
+ }
1227
+
1228
+ .generator-code-editor .el-textarea__inner {
1229
+ height: 100%;
1230
+ min-height: 100% !important;
1231
+ overflow: auto;
1232
+ padding: 16px 16px 56px;
1233
+ border: 0;
1234
+ border-radius: 6px;
1235
+ background: #0f172a;
1236
+ color: #e2e8f0;
1237
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1238
+ font-size: 13px;
1239
+ line-height: 1.6;
1240
+ white-space: pre;
1241
+ }
1242
+
1243
+ .code-dialog__body {
1244
+ height: min(68vh, 720px);
1245
+ max-height: min(68vh, 720px);
1246
+ }
1247
+
1248
+ .code-dialog__toolbar {
1249
+ display: flex;
1250
+ justify-content: flex-end;
1251
+ gap: 8px;
1252
+ margin-bottom: 12px;
1253
+ }
1254
+
1255
+ .code-dialog__editor .el-textarea__inner {
1256
+ height: min(68vh, 720px);
1257
+ max-height: min(68vh, 720px);
1258
+ overflow: auto;
1259
+ border-radius: 6px;
1260
+ background: #0f172a;
1261
+ color: #e2e8f0;
1262
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1263
+ font-size: 13px;
1264
+ line-height: 1.6;
1265
+ white-space: pre;
1266
+ }
1267
+
1268
+ .code-empty {
1269
+ display: flex;
1270
+ align-items: center;
1271
+ gap: 8px;
1272
+ width: 100%;
1273
+ min-height: 48px;
1274
+ padding: 12px;
1275
+ border: 1px dashed #dcdfe6;
1276
+ border-radius: 6px;
1277
+ background: #f8fafc;
1278
+ color: #909399;
1279
+ font-size: 13px;
1280
+ }
1281
+
1282
+ .code-empty__dot {
1283
+ width: 8px;
1284
+ height: 8px;
1285
+ border-radius: 50%;
1286
+ background: #cbd5e1;
1287
+ }
1288
+
1289
+ .automation-layout {
1290
+ display: grid;
1291
+ grid-template-columns: 320px minmax(0, 1fr);
1292
+ gap: 16px;
1293
+ height: calc(100vh - 108px);
1294
+ min-height: 0;
1295
+ }
1296
+
1297
+ .automation-stage {
1298
+ display: grid;
1299
+ grid-template-columns: 420px minmax(0, 1fr);
1300
+ gap: 16px;
1301
+ min-height: 0;
1302
+ }
1303
+
1304
+ .automation-card {
1305
+ min-height: 0;
1306
+ overflow: hidden;
1307
+ }
1308
+
1309
+ .automation-card.el-card {
1310
+ display: flex;
1311
+ flex-direction: column;
1312
+ }
1313
+
1314
+ .automation-card > .el-card__body {
1315
+ min-height: 0;
1316
+ overflow: auto;
1317
+ }
1318
+
1319
+ .device-preview-card > .el-card__body,
1320
+ .execution-card > .el-card__body {
1321
+ overflow: hidden;
1322
+ }
1323
+
1324
+ .execution-card > .el-card__body {
1325
+ display: flex;
1326
+ }
1327
+
1328
+ .execution-card .el-form {
1329
+ display: flex;
1330
+ flex: 1;
1331
+ width: 100%;
1332
+ min-width: 0;
1333
+ min-height: 0;
1334
+ flex-direction: column;
1335
+ }
1336
+
1337
+ .execution-card .el-form-item {
1338
+ flex: 0 0 auto;
1339
+ }
1340
+
1341
+ .execution-card .execution-output-item {
1342
+ display: flex;
1343
+ flex-direction: column;
1344
+ align-items: stretch;
1345
+ flex: 1 1 auto;
1346
+ min-height: 0;
1347
+ }
1348
+
1349
+ .execution-card .execution-output-item .el-form-item__content {
1350
+ display: flex;
1351
+ flex-direction: column;
1352
+ flex: 1;
1353
+ width: 100%;
1354
+ min-width: 0;
1355
+ min-height: 0;
1356
+ overflow: hidden;
1357
+ }
1358
+
1359
+ .execution-card .execution-output-item .el-form-item__label {
1360
+ display: block;
1361
+ flex: 0 0 auto;
1362
+ width: 100%;
1363
+ padding-right: 0;
1364
+ overflow: visible;
1365
+ }
1366
+
1367
+ .execution-output-section {
1368
+ display: flex;
1369
+ flex: 1 1 auto;
1370
+ flex-direction: column;
1371
+ gap: 8px;
1372
+ width: 100%;
1373
+ min-width: 0;
1374
+ min-height: 0;
1375
+ padding-right: 0;
1376
+ box-sizing: border-box;
1377
+ }
1378
+
1379
+ .script-list {
1380
+ display: grid;
1381
+ gap: 8px;
1382
+ }
1383
+
1384
+ .script-row {
1385
+ display: flex;
1386
+ align-items: center;
1387
+ justify-content: space-between;
1388
+ width: 100%;
1389
+ padding: 12px;
1390
+ border: 1px solid #ebeef5;
1391
+ border-radius: 6px;
1392
+ background: #fff;
1393
+ text-align: left;
1394
+ cursor: pointer;
1395
+ }
1396
+
1397
+ .script-row--active {
1398
+ border-color: #409eff;
1399
+ background: #ecf5ff;
1400
+ }
1401
+
1402
+ .script-row__main {
1403
+ display: grid;
1404
+ gap: 4px;
1405
+ min-width: 0;
1406
+ }
1407
+
1408
+ .script-row__main strong {
1409
+ color: #303133;
1410
+ overflow: hidden;
1411
+ text-overflow: ellipsis;
1412
+ white-space: nowrap;
1413
+ }
1414
+
1415
+ .script-row__main span,
1416
+ .script-row__main small {
1417
+ color: #909399;
1418
+ font-size: 12px;
1419
+ overflow: hidden;
1420
+ text-overflow: ellipsis;
1421
+ white-space: nowrap;
1422
+ }
1423
+
1424
+ .script-row__main span {
1425
+ color: #475569;
1426
+ }
1427
+
1428
+ .script-row__actions {
1429
+ display: flex;
1430
+ align-items: center;
1431
+ gap: 2px;
1432
+ flex: 0 0 auto;
1433
+ }
1434
+
1435
+ .device-status {
1436
+ display: flex;
1437
+ align-items: center;
1438
+ gap: 8px;
1439
+ }
1440
+
1441
+ .device-toolbar {
1442
+ margin-bottom: 12px;
1443
+ }
1444
+
1445
+ .device-select {
1446
+ width: 100%;
1447
+ }
1448
+
1449
+ .device-actions {
1450
+ display: flex;
1451
+ align-items: center;
1452
+ gap: 6px;
1453
+ margin-bottom: 14px;
1454
+ }
1455
+
1456
+ .device-action-button {
1457
+ border: 0;
1458
+ background: transparent;
1459
+ color: #3f4752;
1460
+ width: 30px;
1461
+ height: 30px;
1462
+ padding: 0;
1463
+ display: grid;
1464
+ place-items: center;
1465
+ flex: 0 0 auto;
1466
+ border-radius: 8px;
1467
+ position: relative;
1468
+ cursor: pointer;
1469
+ }
1470
+
1471
+ .device-action-button:hover {
1472
+ background: #f5f7fb;
1473
+ }
1474
+
1475
+ .device-action-button:disabled {
1476
+ cursor: not-allowed;
1477
+ opacity: 0.45;
1478
+ }
1479
+
1480
+ .device-action-button:disabled:hover {
1481
+ background: transparent;
1482
+ }
1483
+
1484
+ .device-action-button__icon {
1485
+ width: 17px;
1486
+ height: 17px;
1487
+ display: block;
1488
+ color: inherit;
1489
+ }
1490
+
1491
+ .device-action-button__icon[alt='任务'] {
1492
+ width: 14px;
1493
+ height: 14px;
1494
+ }
1495
+
1496
+ .device-action-button__tooltip {
1497
+ position: absolute;
1498
+ left: 50%;
1499
+ top: -30px;
1500
+ transform: translateX(-50%);
1501
+ padding: 2px 8px;
1502
+ border-radius: 8px;
1503
+ background: rgba(255, 255, 255, 0.96);
1504
+ border: 1px solid #dbe3f0;
1505
+ color: #475569;
1506
+ font-size: 12px;
1507
+ line-height: 18px;
1508
+ white-space: nowrap;
1509
+ box-shadow: 0 6px 18px rgba(15, 23, 42, 0.08);
1510
+ opacity: 0;
1511
+ pointer-events: none;
1512
+ transition: opacity 0.16s ease;
1513
+ }
1514
+
1515
+ .device-action-button:hover .device-action-button__tooltip {
1516
+ opacity: 1;
1517
+ }
1518
+
1519
+ .device-actions::before {
1520
+ content: '';
1521
+ width: 1px;
1522
+ height: 20px;
1523
+ background: #d6dde8;
1524
+ order: 3;
1525
+ margin: 0 2px 0 4px;
1526
+ }
1527
+
1528
+ .device-actions > :nth-child(n + 4) {
1529
+ order: 4;
1530
+ }
1531
+
1532
+ .device-actions > :nth-child(-n + 3) {
1533
+ order: 2;
1534
+ }
1535
+
1536
+ .device-actions > :first-child {
1537
+ order: 1;
1538
+ }
1539
+
1540
+ .device-action-button {
1541
+ align-items: center;
1542
+ justify-content: center;
1543
+ }
1544
+
1545
+ .device-preview {
1546
+ flex: 1 1 auto;
1547
+ overflow: hidden;
1548
+ height: clamp(320px, calc(100vh - 300px), 680px);
1549
+ min-height: 0;
1550
+ background: #fff;
1551
+ position: relative;
1552
+ display: flex;
1553
+ align-items: center;
1554
+ justify-content: center;
1555
+ border-radius: 0;
1556
+ }
1557
+
1558
+ .device-preview--image {
1559
+ border-radius: 8px;
1560
+ background: #111827;
1561
+ }
1562
+
1563
+ .device-preview__interactive {
1564
+ width: 100%;
1565
+ height: 100%;
1566
+ display: block;
1567
+ padding: 0;
1568
+ position: relative;
1569
+ }
1570
+
1571
+ .device-preview__interactive--image {
1572
+ width: auto;
1573
+ max-width: 100%;
1574
+ height: 100%;
1575
+ }
1576
+
1577
+ .device-preview__surface {
1578
+ position: absolute;
1579
+ inset: 0;
1580
+ z-index: 2;
1581
+ touch-action: none;
1582
+ background: transparent;
1583
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'%3E%3Ccircle cx='14' cy='14' r='7' fill='none' stroke='%231f2937' stroke-width='2'/%3E%3Ccircle cx='14' cy='14' r='2' fill='%231f2937'/%3E%3C/svg%3E") 14 14, crosshair;
1584
+ }
1585
+
1586
+ .device-preview__frame {
1587
+ width: 100%;
1588
+ height: 100%;
1589
+ border: 0;
1590
+ display: block;
1591
+ background: #fff;
1592
+ pointer-events: none;
1593
+ }
1594
+
1595
+ .device-preview__image {
1596
+ object-fit: contain;
1597
+ }
1598
+
1599
+ .device-preview__overlay {
1600
+ position: absolute;
1601
+ inset: 0;
1602
+ z-index: 3;
1603
+ width: 100%;
1604
+ height: 100%;
1605
+ pointer-events: none;
1606
+ }
1607
+
1608
+ .device-preview__node-bound {
1609
+ fill: transparent;
1610
+ stroke: #35a853;
1611
+ stroke-width: 1;
1612
+ }
1613
+
1614
+ .device-preview__selected-bound {
1615
+ fill: rgba(147, 196, 125, 0.32);
1616
+ stroke: #35a853;
1617
+ stroke-width: 2;
1618
+ }
1619
+
1620
+ @media (max-width: 1200px) {
1621
+ .device-actions {
1622
+ flex-wrap: wrap;
1623
+ }
1624
+
1625
+ .device-actions::before {
1626
+ display: none;
1627
+ }
1628
+ }
1629
+
1630
+ .device-preview__empty {
1631
+ display: grid;
1632
+ place-items: center;
1633
+ height: 100%;
1634
+ color: #606266;
1635
+ text-align: center;
1636
+ padding: 24px;
1637
+ }
1638
+
1639
+ .device-preview__icon {
1640
+ width: 36px;
1641
+ height: 36px;
1642
+ margin-bottom: 12px;
1643
+ }
1644
+
1645
+ .device-preview__meta {
1646
+ margin: 0 0 8px;
1647
+ color: #303133;
1648
+ font-weight: 600;
1649
+ }
1650
+
1651
+ .run-result,
1652
+ .execution-output {
1653
+ display: flex;
1654
+ flex-direction: column;
1655
+ width: 100%;
1656
+ height: 100%;
1657
+ min-height: 0;
1658
+ padding: 12px;
1659
+ border: 1px solid #e4e7ed;
1660
+ border-radius: 6px;
1661
+ background: #f8fafc;
1662
+ }
1663
+
1664
+ .run-result--success,
1665
+ .execution-output--success {
1666
+ border-color: #b7ebc6;
1667
+ background: #f6ffed;
1668
+ }
1669
+
1670
+ .run-result--error,
1671
+ .execution-output--error {
1672
+ border-color: #fed7d7;
1673
+ background: #fff5f5;
1674
+ }
1675
+
1676
+ .run-result--running,
1677
+ .execution-output--running {
1678
+ border-color: #fde68a;
1679
+ background: #fffbeb;
1680
+ }
1681
+
1682
+ .run-result--stopped,
1683
+ .execution-output--stopped {
1684
+ border-color: #fde68a;
1685
+ background: #fffbeb;
1686
+ }
1687
+
1688
+ .run-result__header,
1689
+ .execution-output__header {
1690
+ display: flex;
1691
+ align-items: center;
1692
+ gap: 8px;
1693
+ min-height: 24px;
1694
+ }
1695
+
1696
+ .run-result__header strong,
1697
+ .execution-output__header strong {
1698
+ color: #303133;
1699
+ font-size: 13px;
1700
+ font-weight: 600;
1701
+ }
1702
+
1703
+ .run-result__dot,
1704
+ .execution-output__dot {
1705
+ width: 8px;
1706
+ height: 8px;
1707
+ border-radius: 50%;
1708
+ background: #cbd5e1;
1709
+ }
1710
+
1711
+ .run-result--success .run-result__dot,
1712
+ .execution-output--success .execution-output__dot {
1713
+ background: #22c55e;
1714
+ }
1715
+
1716
+ .run-result--error .run-result__dot,
1717
+ .execution-output--error .execution-output__dot {
1718
+ background: #ef4444;
1719
+ }
1720
+
1721
+ .run-result--running .run-result__dot,
1722
+ .execution-output--running .execution-output__dot {
1723
+ background: #f59e0b;
1724
+ }
1725
+
1726
+ .run-result--stopped .run-result__dot,
1727
+ .execution-output--stopped .execution-output__dot {
1728
+ background: #f59e0b;
1729
+ }
1730
+
1731
+ .run-result__empty,
1732
+ .execution-log__empty {
1733
+ display: block;
1734
+ margin-top: 8px;
1735
+ color: #909399;
1736
+ font-size: 12px;
1737
+ }
1738
+
1739
+ .run-result__output {
1740
+ flex: 1;
1741
+ min-height: 0;
1742
+ max-height: none;
1743
+ overflow: auto;
1744
+ margin: 10px 0 0;
1745
+ padding: 10px;
1746
+ border-radius: 4px;
1747
+ background: #fff;
1748
+ color: #475569;
1749
+ font-size: 12px;
1750
+ line-height: 1.6;
1751
+ white-space: pre-wrap;
1752
+ }
1753
+
1754
+ .execution-output__body {
1755
+ display: grid;
1756
+ grid-template-rows: minmax(0, 1fr) minmax(110px, 30%);
1757
+ gap: 10px;
1758
+ flex: 1;
1759
+ min-height: 0;
1760
+ margin-top: 10px;
1761
+ }
1762
+
1763
+ .execution-log {
1764
+ display: block;
1765
+ min-width: 0;
1766
+ min-height: 0;
1767
+ overflow: hidden;
1768
+ }
1769
+
1770
+ .execution-log--panel {
1771
+ flex: 1 1 auto;
1772
+ width: 100%;
1773
+ min-width: 0;
1774
+ height: auto;
1775
+ padding: 0;
1776
+ border: 1px solid #e4e7ed;
1777
+ border-radius: 6px;
1778
+ background: #fff;
1779
+ }
1780
+
1781
+ .execution-output-header {
1782
+ display: flex;
1783
+ align-items: center;
1784
+ justify-content: space-between;
1785
+ gap: 12px;
1786
+ width: 100%;
1787
+ min-width: 0;
1788
+ padding-right: 0;
1789
+ box-sizing: border-box;
1790
+ }
1791
+
1792
+ .execution-output-toolbar {
1793
+ display: flex;
1794
+ align-items: center;
1795
+ justify-content: flex-end;
1796
+ flex: 0 1 auto;
1797
+ flex-wrap: wrap;
1798
+ gap: 4px;
1799
+ min-width: 0;
1800
+ min-height: 24px;
1801
+ color: #64748b;
1802
+ font-size: 12px;
1803
+ font-weight: 600;
1804
+ }
1805
+
1806
+ .execution-output-duration {
1807
+ color: #64748b;
1808
+ font-variant-numeric: tabular-nums;
1809
+ line-height: 24px;
1810
+ }
1811
+
1812
+ .execution-log__output {
1813
+ display: block;
1814
+ width: 100%;
1815
+ height: 100%;
1816
+ min-height: 100%;
1817
+ margin: 0;
1818
+ padding: 10px;
1819
+ box-sizing: border-box;
1820
+ border: 0;
1821
+ outline: 0;
1822
+ resize: none;
1823
+ background: #fff;
1824
+ color: #475569;
1825
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
1826
+ font-size: 12px;
1827
+ line-height: 1.6;
1828
+ overflow: auto;
1829
+ white-space: pre;
1830
+ overflow-wrap: normal;
1831
+ word-break: normal;
1832
+ }
1833
+
1834
+ .execution-process {
1835
+ display: grid;
1836
+ align-content: start;
1837
+ gap: 10px;
1838
+ width: 100%;
1839
+ height: 100%;
1840
+ min-height: 0;
1841
+ max-height: none;
1842
+ overflow: auto;
1843
+ padding: 12px;
1844
+ border: 1px solid #e4e7ed;
1845
+ border-radius: 6px;
1846
+ background: #f8fafc;
1847
+ }
1848
+
1849
+ .execution-step {
1850
+ display: grid;
1851
+ grid-template-columns: 28px minmax(0, 1fr);
1852
+ gap: 10px;
1853
+ }
1854
+
1855
+ .execution-step__index {
1856
+ display: grid;
1857
+ place-items: center;
1858
+ width: 28px;
1859
+ height: 28px;
1860
+ border-radius: 50%;
1861
+ background: #dbe3ee;
1862
+ color: #475569;
1863
+ font-size: 12px;
1864
+ font-weight: 700;
1865
+ }
1866
+
1867
+ .execution-step--running .execution-step__index {
1868
+ background: #f59e0b;
1869
+ color: #fff;
1870
+ }
1871
+
1872
+ .execution-step--success .execution-step__index {
1873
+ background: #10b981;
1874
+ color: #fff;
1875
+ }
1876
+
1877
+ .execution-step--error .execution-step__index {
1878
+ background: #ef4444;
1879
+ color: #fff;
1880
+ }
1881
+
1882
+ .execution-step__body {
1883
+ min-width: 0;
1884
+ padding: 10px 12px;
1885
+ border: 1px solid #e2e8f0;
1886
+ border-radius: 6px;
1887
+ background: #fff;
1888
+ }
1889
+
1890
+ .execution-step__top {
1891
+ display: flex;
1892
+ align-items: center;
1893
+ justify-content: space-between;
1894
+ gap: 10px;
1895
+ }
1896
+
1897
+ .execution-step__top strong {
1898
+ min-width: 0;
1899
+ overflow: hidden;
1900
+ color: #1f2937;
1901
+ font-size: 13px;
1902
+ text-overflow: ellipsis;
1903
+ white-space: nowrap;
1904
+ }
1905
+
1906
+ .execution-step__meta {
1907
+ margin-top: 4px;
1908
+ color: #2563eb;
1909
+ font-size: 12px;
1910
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
1911
+ }
1912
+
1913
+ .execution-step p {
1914
+ margin: 6px 0 0;
1915
+ color: #475569;
1916
+ font-size: 12px;
1917
+ line-height: 1.5;
1918
+ }
1919
+
1920
+ .execution-step__detail,
1921
+ .execution-step__detail-text {
1922
+ display: block;
1923
+ margin-top: 8px;
1924
+ color: #64748b;
1925
+ font-size: 12px;
1926
+ }
1927
+
1928
+ .execution-step__detail {
1929
+ max-height: 120px;
1930
+ overflow: auto;
1931
+ padding: 8px;
1932
+ border-radius: 4px;
1933
+ background: #fff1f2;
1934
+ color: #be123c;
1935
+ white-space: pre-wrap;
1936
+ }
1937
+
1938
+ @media (max-width: 1440px) {
1939
+ body {
1940
+ min-width: 0;
1941
+ }
1942
+
1943
+ .automation-layout {
1944
+ height: auto;
1945
+ }
1946
+
1947
+ .automation-stage {
1948
+ grid-template-columns: 1fr;
1949
+ }
1950
+
1951
+ .appium-recorder-layout {
1952
+ grid-template-columns: 1fr;
1953
+ height: auto;
1954
+ }
1955
+
1956
+ .appium-recorder-layout > .appium-recorder-card > .el-card__body {
1957
+ height: min(640px, 58vh);
1958
+ }
1959
+
1960
+ .appium-recorder-layout > .device-preview-card.el-card {
1961
+ height: clamp(620px, calc(100vh - 100px), 820px);
1962
+ }
1963
+
1964
+ .device-preview {
1965
+ height: min(640px, 58vh);
1966
+ }
1967
+ }
1968
+
1969
+ @media (max-width: 1200px) {
1970
+ .layout {
1971
+ grid-template-columns: 1fr;
1972
+ }
1973
+
1974
+ .layout-sidebar {
1975
+ border-right: 0;
1976
+ }
1977
+
1978
+ .automation-layout,
1979
+ .page-grid,
1980
+ .config-grid {
1981
+ grid-template-columns: 1fr;
1982
+ }
1983
+ }