assistsx-js 0.0.2040 → 0.0.2042

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.
package/src/Step.ts CHANGED
@@ -20,774 +20,811 @@ export type StepImpl = (step: Step) => Promise<StepResult>;
20
20
  export type StepInterceptor = (step: Step) => StepResult | Promise<StepResult>;
21
21
 
22
22
  export class Step {
23
- static delayMsDefault: number = 1000;
24
- static readonly repeatCountInfinite: number = -1;
25
- static repeatCountMaxDefault: number = Step.repeatCountInfinite;
26
- static showLog: boolean = false;
27
-
28
- /**
29
- * 当前执行步骤的ID
30
- */
31
- private static _stepId: string | undefined = undefined;
32
-
33
- /**
34
- * 步骤拦截器列表
35
- */
36
- private static _interceptors: StepInterceptor[] = [];
37
-
38
- /**
39
- * 运行步骤实现
40
- * @param impl 步骤实现函数
41
- * @param tag 步骤标签
42
- * @param data 步骤数据
43
- * @param delayMs 步骤延迟时间(毫秒)
44
- */
45
- static async run(
46
- impl: StepImpl,
47
- {
48
- tag,
49
- data,
50
- delayMs = Step.delayMsDefault,
51
- }: {
52
- tag?: string | undefined;
53
- data?: any | undefined;
54
- delayMs?: number;
55
- } = {}
56
- ): Promise<Step> {
57
- const stepStore = useStepStore();
58
- let implnName = impl.name;
59
- let currentStep: Step | undefined;
60
- let nextStep: Step | undefined;
61
- try {
62
- //步骤开始
63
- this._stepId = generateUUID();
64
-
65
- stepStore.startStep(this._stepId, tag, data);
66
- currentStep = new Step({
67
- stepId: this._stepId,
68
- impl,
69
- tag,
70
- data,
71
- delayMs,
72
- });
73
- while (true) {
74
- if (currentStep.delayMs) {
75
- if (Step.showLog) {
76
- console.log(`延迟${currentStep.delayMs}毫秒`);
77
- }
78
- await currentStep.delay(currentStep.delayMs);
79
- Step.assert(currentStep.stepId);
80
- }
81
- //执行步骤
82
- implnName = currentStep.impl.name;
83
- if (Step.showLog) {
84
- console.log(
85
- `执行步骤${implnName},重复次数${currentStep.repeatCount}`
86
- );
23
+ static delayMsDefault: number = 1000;
24
+ static readonly repeatCountInfinite: number = -1;
25
+ static repeatCountMaxDefault: number = Step.repeatCountInfinite;
26
+ static showLog: boolean = false;
27
+
28
+ /**
29
+ * 当前执行步骤的ID
30
+ */
31
+ private static _stepId: string | undefined = undefined;
32
+
33
+ /**
34
+ * 步骤拦截器列表
35
+ */
36
+ private static _interceptors: StepInterceptor[] = [];
37
+
38
+ /**
39
+ * 运行步骤实现
40
+ * @param impl 步骤实现函数
41
+ * @param tag 步骤标签
42
+ * @param data 步骤数据
43
+ * @param delayMs 步骤延迟时间(毫秒)
44
+ */
45
+ static async run(
46
+ impl: StepImpl,
47
+ {
48
+ tag,
49
+ data,
50
+ delayMs = Step.delayMsDefault,
51
+ }: {
52
+ tag?: string | undefined;
53
+ data?: any | undefined;
54
+ delayMs?: number;
55
+ } = {}
56
+ ): Promise<Step> {
57
+ const stepStore = useStepStore();
58
+ let implnName = impl.name;
59
+ let currentStep: Step | undefined;
60
+ let nextStep: Step | undefined;
61
+ try {
62
+ //步骤开始
63
+ this._stepId = generateUUID();
64
+
65
+ stepStore.startStep(this._stepId, tag, data);
66
+ currentStep = new Step({
67
+ stepId: this._stepId,
68
+ impl,
69
+ tag,
70
+ data,
71
+ delayMs,
72
+ });
73
+ while (true) {
74
+ if (currentStep.delayMs) {
75
+ if (Step.showLog) {
76
+ console.log(`延迟${currentStep.delayMs}毫秒`);
77
+ }
78
+ await currentStep.delay(currentStep.delayMs);
79
+ Step.assert(currentStep.stepId);
80
+ }
81
+ //执行步骤
82
+ implnName = currentStep.impl?.name ?? "undefined";
83
+ if (Step.showLog) {
84
+ console.log(
85
+ `执行步骤${implnName},重复次数${currentStep.repeatCount}`
86
+ );
87
+ }
88
+
89
+ // 执行拦截器
90
+ let interceptedStep: StepResult = undefined;
91
+ for (const interceptor of this._interceptors) {
92
+ try {
93
+ const result = await interceptor(currentStep);
94
+ if (result) {
95
+ interceptedStep = result;
96
+ if (Step.showLog) {
97
+ console.log(`步骤${implnName}被拦截器拦截,执行拦截后的步骤`);
98
+ }
99
+ break;
100
+ }
101
+ } catch (e: any) {
102
+ if (Step.showLog) {
103
+ console.error(`拦截器执行出错`, e);
104
+ }
105
+ // 拦截器出错不影响主流程,继续执行原步骤
106
+ }
107
+ }
108
+
109
+ // 如果被拦截,执行拦截后的步骤,否则执行原步骤
110
+ if (interceptedStep !== undefined) {
111
+ // 执行拦截后的步骤,需要处理延迟和重复次数
112
+ const stepToExecute = interceptedStep;
113
+
114
+ // 如果拦截后的步骤有延迟时间,先执行延迟
115
+ if (stepToExecute.delayMs) {
116
+ if (Step.showLog) {
117
+ console.log(`拦截步骤延迟${stepToExecute.delayMs}毫秒`);
118
+ }
119
+ await stepToExecute.delay(stepToExecute.delayMs);
120
+ Step.assert(stepToExecute.stepId);
121
+ }
122
+
123
+ // 打印拦截步骤的执行信息
124
+ const interceptedImplName = stepToExecute.impl?.name;
125
+ if (Step.showLog) {
126
+ console.log(
127
+ `执行拦截步骤${interceptedImplName},重复次数${stepToExecute.repeatCount}`
128
+ );
129
+ }
130
+
131
+ // 执行拦截后的步骤
132
+ nextStep = await stepToExecute.impl?.(stepToExecute);
133
+ } else {
134
+ nextStep = await currentStep.impl?.(currentStep);
135
+ }
136
+ if (
137
+ currentStep.repeatCountMax > Step.repeatCountInfinite &&
138
+ currentStep.repeatCount > currentStep.repeatCountMax
139
+ ) {
140
+ if (Step.showLog) {
141
+ console.log(
142
+ `重复次数${currentStep.repeatCount}超过最大次数${currentStep.repeatCountMax},停止执行`
143
+ );
144
+ }
145
+ break;
146
+ }
147
+
148
+ Step.assert(currentStep.stepId);
149
+ if (nextStep) {
150
+ currentStep = nextStep;
151
+ if (currentStep.isEnd) {
152
+ if (Step.showLog) {
153
+ console.log(`步骤${implnName}结束`);
154
+ }
155
+ break;
156
+ }
157
+ } else {
158
+ break;
159
+ }
160
+ }
161
+ } catch (e: any) {
162
+ console.error(`步骤${implnName}执行出错`, e);
163
+ //步骤执行出错
164
+ const errorMsg = JSON.stringify({
165
+ impl: implnName,
166
+ tag: tag,
167
+ data: data,
168
+ error: e?.message ?? String(e),
169
+ });
170
+ stepStore.setError(errorMsg);
171
+ throw new StepError(
172
+ errorMsg,
173
+ implnName,
174
+ tag,
175
+ data,
176
+ e,
177
+ currentStep || undefined
178
+ );
87
179
  }
180
+ //步骤执行结束
181
+ stepStore.completeStep();
182
+ return currentStep;
183
+ }
88
184
 
89
- // 执行拦截器
90
- let interceptedStep: StepResult = undefined;
91
- for (const interceptor of this._interceptors) {
92
- try {
93
- const result = await interceptor(currentStep);
94
- if (result) {
95
- interceptedStep = result;
96
- if (Step.showLog) {
97
- console.log(`步骤${implnName}被拦截器拦截,执行拦截后的步骤`);
98
- }
99
- break;
100
- }
101
- } catch (e: any) {
102
- if (Step.showLog) {
103
- console.error(`拦截器执行出错`, e);
185
+ /**
186
+ * 获取当前步骤ID
187
+ */
188
+ static get stepId(): string | undefined {
189
+ return this._stepId;
190
+ }
191
+
192
+ /**
193
+ * 验证步骤ID是否匹配,如果不匹配则表示停止
194
+ * @param stepId 要验证的步骤ID
195
+ */
196
+ static assert(stepId: string | undefined) {
197
+ if (stepId && Step.stepId != stepId) {
198
+ if (Step.stepId === "STEP_STOP") {
199
+ throw new Error("主动中断步骤");
104
200
  }
105
- // 拦截器出错不影响主流程,继续执行原步骤
106
- }
201
+ throw new Error("StepId mismatch");
107
202
  }
203
+ }
108
204
 
109
- // 如果被拦截,执行拦截后的步骤,否则执行原步骤
110
- if (interceptedStep !== undefined) {
111
- // 执行拦截后的步骤,需要处理延迟和重复次数
112
- const stepToExecute = interceptedStep;
205
+ /**
206
+ * 为节点数组分配步骤ID
207
+ * @param nodes 节点数组
208
+ * @param stepId 步骤ID
209
+ */
210
+ static assignIdsToNodes(nodes: Node[], stepId: string | undefined): void {
211
+ if (stepId) {
212
+ nodes.forEach((node) => {
213
+ node.stepId = stepId;
214
+ });
215
+ }
216
+ }
113
217
 
114
- // 如果拦截后的步骤有延迟时间,先执行延迟
115
- if (stepToExecute.delayMs) {
116
- if (Step.showLog) {
117
- console.log(`拦截步骤延迟${stepToExecute.delayMs}毫秒`);
118
- }
119
- await stepToExecute.delay(stepToExecute.delayMs);
120
- Step.assert(stepToExecute.stepId);
121
- }
122
-
123
- // 打印拦截步骤的执行信息
124
- const interceptedImplName = stepToExecute.impl.name;
125
- if (Step.showLog) {
126
- console.log(
127
- `执行拦截步骤${interceptedImplName},重复次数${stepToExecute.repeatCount}`
128
- );
129
- }
218
+ /**
219
+ * 停止当前步骤执行
220
+ */
221
+ static stop(): void {
222
+ this._stepId = "STEP_STOP";
223
+ }
130
224
 
131
- // 执行拦截后的步骤
132
- nextStep = await stepToExecute.impl(stepToExecute);
133
- } else {
134
- nextStep = await currentStep.impl(currentStep);
225
+ /**
226
+ * 添加步骤拦截器
227
+ * @param interceptor 拦截器函数
228
+ */
229
+ static addInterceptor(interceptor: StepInterceptor): void {
230
+ this._interceptors.push(interceptor);
231
+ }
232
+
233
+ /**
234
+ * 移除步骤拦截器
235
+ * @param interceptor 要移除的拦截器函数
236
+ * @returns 是否成功删除
237
+ */
238
+ static removeInterceptor(interceptor: StepInterceptor): boolean {
239
+ const index = this._interceptors.indexOf(interceptor);
240
+ if (index > -1) {
241
+ this._interceptors.splice(index, 1);
242
+ return true;
135
243
  }
136
- if (
137
- currentStep.repeatCountMax > Step.repeatCountInfinite &&
138
- currentStep.repeatCount > currentStep.repeatCountMax
139
- ) {
140
- if (Step.showLog) {
141
- console.log(
142
- `重复次数${currentStep.repeatCount}超过最大次数${currentStep.repeatCountMax},停止执行`
143
- );
144
- }
145
- break;
244
+ return false;
245
+ }
246
+
247
+ /**
248
+ * 按索引移除步骤拦截器
249
+ * @param index 要移除的拦截器索引
250
+ * @returns 是否成功删除
251
+ */
252
+ static removeInterceptorByIndex(index: number): boolean {
253
+ if (index >= 0 && index < this._interceptors.length) {
254
+ this._interceptors.splice(index, 1);
255
+ return true;
146
256
  }
257
+ return false;
258
+ }
147
259
 
148
- Step.assert(currentStep.stepId);
149
- if (nextStep) {
150
- currentStep = nextStep;
151
- } else {
152
- break;
260
+ /**
261
+ * 移除所有匹配的步骤拦截器
262
+ * @param interceptor 要移除的拦截器函数
263
+ * @returns 删除的拦截器数量
264
+ */
265
+ static removeAllInterceptors(interceptor: StepInterceptor): number {
266
+ let removedCount = 0;
267
+ for (let i = this._interceptors.length - 1; i >= 0; i--) {
268
+ if (this._interceptors[i] === interceptor) {
269
+ this._interceptors.splice(i, 1);
270
+ removedCount++;
271
+ }
272
+ }
273
+ return removedCount;
274
+ }
275
+
276
+ /**
277
+ * 按条件移除步骤拦截器
278
+ * @param predicate 判断是否删除的条件函数
279
+ * @returns 删除的拦截器数量
280
+ */
281
+ static removeInterceptorByPredicate(
282
+ predicate: (interceptor: StepInterceptor, index: number) => boolean
283
+ ): number {
284
+ let removedCount = 0;
285
+ for (let i = this._interceptors.length - 1; i >= 0; i--) {
286
+ if (predicate(this._interceptors[i], i)) {
287
+ this._interceptors.splice(i, 1);
288
+ removedCount++;
289
+ }
153
290
  }
154
- }
155
- } catch (e: any) {
156
- console.error(`步骤${implnName}执行出错`, e);
157
- //步骤执行出错
158
- const errorMsg = JSON.stringify({
159
- impl: implnName,
160
- tag: tag,
161
- data: data,
162
- error: e?.message ?? String(e),
163
- });
164
- stepStore.setError(errorMsg);
165
- throw new StepError(
166
- errorMsg,
167
- implnName,
291
+ return removedCount;
292
+ }
293
+
294
+ /**
295
+ * 清空所有拦截器
296
+ */
297
+ static clearInterceptors(): void {
298
+ this._interceptors = [];
299
+ }
300
+
301
+ /**
302
+ * 获取所有拦截器
303
+ * @returns 拦截器数组
304
+ */
305
+ static getInterceptors(): StepInterceptor[] {
306
+ return [...this._interceptors];
307
+ }
308
+
309
+ /**
310
+ * 步骤ID
311
+ */
312
+ stepId: string = "";
313
+
314
+ /**
315
+ * 步骤重复执行次数
316
+ */
317
+ repeatCount: number = 0;
318
+
319
+ /**
320
+ * 步骤重复执行最大次数,默认不限制
321
+ */
322
+ repeatCountMax: number = Step.repeatCountMaxDefault;
323
+
324
+ /**
325
+ * 步骤标签
326
+ */
327
+ tag: string | undefined;
328
+ isEnd: boolean = false;
329
+
330
+ /**
331
+ * 步骤数据
332
+ */
333
+ data: any | undefined;
334
+
335
+ /**
336
+ * 步骤延迟时间(毫秒)
337
+ */
338
+ delayMs: number = Step.delayMsDefault;
339
+
340
+ /**
341
+ * 步骤实现函数
342
+ */
343
+ impl: StepImpl | undefined;
344
+
345
+ /**
346
+ * 构造函数
347
+ * @param stepId 步骤ID
348
+ * @param impl 步骤实现函数
349
+ * @param tag 步骤标签
350
+ * @param data 步骤数据
351
+ * @param delayMs 步骤延迟时间(毫秒)
352
+ */
353
+ constructor({
354
+ stepId,
355
+ impl,
168
356
  tag,
169
357
  data,
170
- e,
171
- currentStep || undefined
172
- );
173
- }
174
- //步骤执行结束
175
- stepStore.completeStep();
176
- return currentStep;
177
- }
178
-
179
- /**
180
- * 获取当前步骤ID
181
- */
182
- static get stepId(): string | undefined {
183
- return this._stepId;
184
- }
185
-
186
- /**
187
- * 验证步骤ID是否匹配,如果不匹配则表示停止
188
- * @param stepId 要验证的步骤ID
189
- */
190
- static assert(stepId: string | undefined) {
191
- if (stepId && Step.stepId != stepId) {
192
- throw new Error("StepId mismatch");
193
- }
194
- }
195
-
196
- /**
197
- * 为节点数组分配步骤ID
198
- * @param nodes 节点数组
199
- * @param stepId 步骤ID
200
- */
201
- static assignIdsToNodes(nodes: Node[], stepId: string | undefined): void {
202
- if (stepId) {
203
- nodes.forEach((node) => {
204
- node.stepId = stepId;
205
- });
206
- }
207
- }
208
-
209
- /**
210
- * 停止当前步骤执行
211
- */
212
- static stop(): void {
213
- this._stepId = undefined;
214
- }
215
-
216
- /**
217
- * 添加步骤拦截器
218
- * @param interceptor 拦截器函数
219
- */
220
- static addInterceptor(interceptor: StepInterceptor): void {
221
- this._interceptors.push(interceptor);
222
- }
223
-
224
- /**
225
- * 移除步骤拦截器
226
- * @param interceptor 要移除的拦截器函数
227
- * @returns 是否成功删除
228
- */
229
- static removeInterceptor(interceptor: StepInterceptor): boolean {
230
- const index = this._interceptors.indexOf(interceptor);
231
- if (index > -1) {
232
- this._interceptors.splice(index, 1);
233
- return true;
234
- }
235
- return false;
236
- }
237
-
238
- /**
239
- * 按索引移除步骤拦截器
240
- * @param index 要移除的拦截器索引
241
- * @returns 是否成功删除
242
- */
243
- static removeInterceptorByIndex(index: number): boolean {
244
- if (index >= 0 && index < this._interceptors.length) {
245
- this._interceptors.splice(index, 1);
246
- return true;
247
- }
248
- return false;
249
- }
250
-
251
- /**
252
- * 移除所有匹配的步骤拦截器
253
- * @param interceptor 要移除的拦截器函数
254
- * @returns 删除的拦截器数量
255
- */
256
- static removeAllInterceptors(interceptor: StepInterceptor): number {
257
- let removedCount = 0;
258
- for (let i = this._interceptors.length - 1; i >= 0; i--) {
259
- if (this._interceptors[i] === interceptor) {
260
- this._interceptors.splice(i, 1);
261
- removedCount++;
262
- }
263
- }
264
- return removedCount;
265
- }
266
-
267
- /**
268
- * 按条件移除步骤拦截器
269
- * @param predicate 判断是否删除的条件函数
270
- * @returns 删除的拦截器数量
271
- */
272
- static removeInterceptorByPredicate(
273
- predicate: (interceptor: StepInterceptor, index: number) => boolean
274
- ): number {
275
- let removedCount = 0;
276
- for (let i = this._interceptors.length - 1; i >= 0; i--) {
277
- if (predicate(this._interceptors[i], i)) {
278
- this._interceptors.splice(i, 1);
279
- removedCount++;
280
- }
281
- }
282
- return removedCount;
283
- }
284
-
285
- /**
286
- * 清空所有拦截器
287
- */
288
- static clearInterceptors(): void {
289
- this._interceptors = [];
290
- }
291
-
292
- /**
293
- * 获取所有拦截器
294
- * @returns 拦截器数组
295
- */
296
- static getInterceptors(): StepInterceptor[] {
297
- return [...this._interceptors];
298
- }
299
-
300
- /**
301
- * 步骤ID
302
- */
303
- stepId: string = "";
304
-
305
- /**
306
- * 步骤重复执行次数
307
- */
308
- repeatCount: number = 0;
309
-
310
- /**
311
- * 步骤重复执行最大次数,默认不限制
312
- */
313
- repeatCountMax: number = Step.repeatCountMaxDefault;
314
-
315
- /**
316
- * 步骤标签
317
- */
318
- tag: string | undefined;
319
-
320
- /**
321
- * 步骤数据
322
- */
323
- data: any | undefined;
324
-
325
- /**
326
- * 步骤延迟时间(毫秒)
327
- */
328
- delayMs: number = Step.delayMsDefault;
329
-
330
- /**
331
- * 步骤实现函数
332
- */
333
- impl: StepImpl;
334
-
335
- /**
336
- * 构造函数
337
- * @param stepId 步骤ID
338
- * @param impl 步骤实现函数
339
- * @param tag 步骤标签
340
- * @param data 步骤数据
341
- * @param delayMs 步骤延迟时间(毫秒)
342
- */
343
- constructor({
344
- stepId,
345
- impl,
346
- tag,
347
- data,
348
- delayMs = Step.delayMsDefault,
349
- repeatCountMax = Step.repeatCountMaxDefault,
350
- }: {
351
- stepId: string;
352
- impl: StepImpl;
353
- tag?: string | undefined;
354
- data?: any | undefined;
355
- delayMs?: number;
356
- repeatCountMax?: number;
357
- }) {
358
- this.tag = tag;
359
- this.stepId = stepId;
360
- this.data = data;
361
- this.impl = impl;
362
- this.delayMs = delayMs;
363
- this.repeatCountMax = repeatCountMax;
364
- }
365
-
366
- public get async(): StepAsync {
367
- return new StepAsync(this);
368
- }
369
- /**
370
- * 创建下一个步骤
371
- * @param impl 下一步骤实现函数
372
- * @param tag 步骤标签
373
- * @param data 步骤数据
374
- * @param delayMs 步骤延迟时间(毫秒)
375
- * @returns 新的步骤实例
376
- */
377
- next(
378
- impl: StepImpl,
379
- {
380
- tag,
381
- data,
382
- delayMs = Step.delayMsDefault,
383
- repeatCountMax = Step.repeatCountMaxDefault,
358
+ delayMs = Step.delayMsDefault,
359
+ repeatCountMax = Step.repeatCountMaxDefault,
360
+ isEnd = false,
384
361
  }: {
385
- tag?: string | undefined;
386
- data?: any | undefined;
387
- delayMs?: number;
388
- repeatCountMax?: number;
389
- } = {}
390
- ): Step {
391
- Step.assert(this.stepId);
392
- return new Step({
393
- stepId: this.stepId,
394
- impl,
395
- tag,
396
- data: data ?? this.data,
397
- delayMs,
398
- repeatCountMax,
399
- });
400
- }
401
-
402
- /**
403
- * 重复当前步骤
404
- * @param stepId 步骤ID
405
- * @param tag 步骤标签
406
- * @param data 步骤数据
407
- * @param delayMs 步骤延迟时间(毫秒)
408
- * @returns 当前步骤实例
409
- */
410
- repeat({
411
- stepId = this.stepId,
412
- tag = this.tag,
413
- data = this.data,
414
- delayMs = this.delayMs,
415
- repeatCountMax = this.repeatCountMax,
416
- }: {
417
- stepId?: string;
418
- tag?: string | undefined;
419
- data?: any | undefined;
420
- delayMs?: number;
421
- repeatCountMax?: number;
422
- } = {}): Step {
423
- Step.assert(this.stepId);
424
- this.repeatCount++;
425
- this.stepId = stepId;
426
- this.tag = tag;
427
- this.data = data;
428
- this.delayMs = delayMs;
429
- this.repeatCountMax = repeatCountMax;
430
- return this;
431
- }
432
-
433
- /**
434
- * 延迟执行
435
- * @param ms 延迟时间(毫秒)
436
- * @returns Promise
437
- */
438
- async delay(ms: number): Promise<void> {
439
- while (true) {
440
- ms -= 100;
441
- if (ms <= 0) {
442
- break;
443
- }
444
- await new Promise((resolve) => setTimeout(resolve, 100));
445
- Step.assert(this.stepId);
446
- }
447
- }
448
-
449
- /**
450
- * 等待异步方法执行完成
451
- * @param method 异步方法
452
- * @returns Promise<T>
453
- */
454
- async await<T>(method: () => Promise<T>): Promise<T> {
455
- Step.assert(this.stepId);
456
- const result = await method();
457
- Step.assert(this.stepId);
458
- return result;
459
- }
460
-
461
- /**
462
- * 对单个节点进行截图
463
- * @param node 目标节点
464
- * @param overlayHiddenScreenshotDelayMillis 截图延迟时间(毫秒)
465
- * @returns 截图路径
466
- */
467
- public async takeScreenshotByNode(
468
- node: Node,
469
- overlayHiddenScreenshotDelayMillis: number = 250
470
- ): Promise<string> {
471
- Step.assert(this.stepId);
472
- const result = await AssistsX.takeScreenshotNodes(
473
- [node],
474
- overlayHiddenScreenshotDelayMillis
475
- );
476
- Step.assert(this.stepId);
477
- return result[0];
478
- }
479
-
480
- /**
481
- * 对多个节点进行截图
482
- * @param nodes 目标节点数组
483
- * @param overlayHiddenScreenshotDelayMillis 截图延迟时间(毫秒)
484
- * @returns 截图路径数组
485
- */
486
- public async takeScreenshotNodes(
487
- nodes: Node[],
488
- overlayHiddenScreenshotDelayMillis: number = 250
489
- ): Promise<string[]> {
490
- Step.assert(this.stepId);
491
- const result = await AssistsX.takeScreenshotNodes(
492
- nodes,
493
- overlayHiddenScreenshotDelayMillis
494
- );
495
- Step.assert(this.stepId);
496
- return result;
497
- }
498
-
499
- /**
500
- * 获取所有符合条件的节点
501
- * @param filterClass 类名过滤
502
- * @param filterViewId 视图ID过滤
503
- * @param filterDes 描述过滤
504
- * @param filterText 文本过滤
505
- * @returns 节点数组
506
- */
507
- public getAllNodes({
508
- filterClass,
509
- filterViewId,
510
- filterDes,
511
- filterText,
512
- }: {
513
- filterClass?: string;
514
- filterViewId?: string;
515
- filterDes?: string;
516
- filterText?: string;
517
- } = {}): Node[] {
518
- Step.assert(this.stepId);
519
- const nodes = AssistsX.getAllNodes({
520
- filterClass,
521
- filterViewId,
522
- filterDes,
523
- filterText,
524
- });
525
- Step.assert(this.stepId);
526
- Step.assignIdsToNodes(nodes, this.stepId);
527
- return nodes;
528
- }
529
-
530
- /**
531
- * 启动应用
532
- * @param packageName 应用包名
533
- * @returns 是否启动成功
534
- */
535
- public launchApp(packageName: string): boolean {
536
- Step.assert(this.stepId);
537
- const result = AssistsX.launchApp(packageName);
538
- Step.assert(this.stepId);
539
- return result;
540
- }
541
-
542
- /**
543
- * 获取当前应用包名
544
- * @returns 包名
545
- */
546
- public getPackageName(): string {
547
- Step.assert(this.stepId);
548
- const result = AssistsX.getPackageName();
549
- Step.assert(this.stepId);
550
- return result;
551
- }
552
-
553
- /**
554
- * 通过ID查找节点
555
- * @param id 节点ID
556
- * @param filterClass 类名过滤
557
- * @param filterText 文本过滤
558
- * @param filterDes 描述过滤
559
- * @returns 节点数组
560
- */
561
- public findById(
562
- id: string,
563
- {
564
- filterClass,
565
- filterText,
566
- filterDes,
567
- }: { filterClass?: string; filterText?: string; filterDes?: string } = {}
568
- ): Node[] {
569
- Step.assert(this.stepId);
570
- const nodes = AssistsX.findById(id, { filterClass, filterText, filterDes });
571
- Step.assert(this.stepId);
572
- Step.assignIdsToNodes(nodes, this.stepId);
573
- return nodes;
574
- }
575
-
576
- /**
577
- * 通过文本查找节点
578
- * @param text 要查找的文本
579
- * @param filterClass 类名过滤
580
- * @param filterViewId 视图ID过滤
581
- * @param filterDes 描述过滤
582
- * @returns 节点数组
583
- */
584
- public findByText(
585
- text: string,
586
- {
587
- filterClass,
588
- filterViewId,
589
- filterDes,
590
- }: { filterClass?: string; filterViewId?: string; filterDes?: string } = {}
591
- ): Node[] {
592
- Step.assert(this.stepId);
593
- const nodes = AssistsX.findByText(text, {
594
- filterClass,
595
- filterViewId,
596
- filterDes,
597
- });
598
- Step.assert(this.stepId);
599
- Step.assignIdsToNodes(nodes, this.stepId);
600
- return nodes;
601
- }
602
-
603
- /**
604
- * 通过标签查找节点
605
- * @param className 类名
606
- * @param filterText 文本过滤
607
- * @param filterViewId 视图ID过滤
608
- * @param filterDes 描述过滤
609
- * @returns 节点数组
610
- */
611
- public findByTags(
612
- className: string,
613
- {
614
- filterText,
615
- filterViewId,
616
- filterDes,
617
- }: { filterText?: string; filterViewId?: string; filterDes?: string } = {}
618
- ): Node[] {
619
- Step.assert(this.stepId);
620
- const nodes = AssistsX.findByTags(className, {
621
- filterText,
622
- filterViewId,
623
- filterDes,
624
- });
625
- Step.assert(this.stepId);
626
- Step.assignIdsToNodes(nodes, this.stepId);
627
- return nodes;
628
- }
629
-
630
- /**
631
- * 查找所有匹配文本的节点
632
- * @param text 要查找的文本
633
- * @returns 节点数组
634
- */
635
- public findByTextAllMatch(text: string): Node[] {
636
- Step.assert(this.stepId);
637
- const nodes = AssistsX.findByTextAllMatch(text);
638
- Step.assert(this.stepId);
639
- Step.assignIdsToNodes(nodes, this.stepId);
640
- return nodes;
641
- }
642
-
643
- /**
644
- * 检查是否包含指定文本
645
- * @param text 要检查的文本
646
- * @returns 是否包含
647
- */
648
- public containsText(text: string): boolean {
649
- Step.assert(this.stepId);
650
- const result = AssistsX.containsText(text);
651
- Step.assert(this.stepId);
652
- return result;
653
- }
654
-
655
- /**
656
- * 获取所有文本
657
- * @returns 文本数组
658
- */
659
- public getAllText(): string[] {
660
- Step.assert(this.stepId);
661
- const texts = AssistsX.getAllText();
662
- Step.assert(this.stepId);
663
- return texts;
664
- }
665
-
666
- /**
667
- * 执行点击手势
668
- * @param x 横坐标
669
- * @param y 纵坐标
670
- * @param duration 持续时间(毫秒)
671
- * @returns 是否成功
672
- */
673
- public async clickByGesture(
674
- x: number,
675
- y: number,
676
- duration: number
677
- ): Promise<boolean> {
678
- Step.assert(this.stepId);
679
- const result = await AssistsX.clickByGesture(x, y, duration);
680
- Step.assert(this.stepId);
681
- return result;
682
- }
683
-
684
- public async longPressGestureAutoPaste(
685
- point: { x: number; y: number },
686
- text: string,
687
- {
688
- matchedPackageName,
689
- matchedText,
690
- timeoutMillis,
691
- longPressDuration,
362
+ stepId: string;
363
+ impl: StepImpl | undefined;
364
+ tag?: string | undefined;
365
+ data?: any | undefined;
366
+ delayMs?: number;
367
+ repeatCountMax?: number;
368
+ isEnd?: boolean;
369
+ }) {
370
+ this.tag = tag;
371
+ this.stepId = stepId;
372
+ this.data = data;
373
+ this.impl = impl;
374
+ this.delayMs = delayMs;
375
+ this.repeatCountMax = repeatCountMax;
376
+ this.isEnd = isEnd;
377
+ }
378
+
379
+ public get async(): StepAsync {
380
+ return new StepAsync(this);
381
+ }
382
+ /**
383
+ * 创建下一个步骤
384
+ * @param impl 下一步骤实现函数
385
+ * @param tag 步骤标签
386
+ * @param data 步骤数据
387
+ * @param delayMs 步骤延迟时间(毫秒)
388
+ * @returns 新的步骤实例
389
+ */
390
+ next(
391
+ impl: StepImpl,
392
+ {
393
+ tag,
394
+ data,
395
+ delayMs = Step.delayMsDefault,
396
+ repeatCountMax = Step.repeatCountMaxDefault,
397
+ }: {
398
+ tag?: string | undefined;
399
+ data?: any | undefined;
400
+ delayMs?: number;
401
+ repeatCountMax?: number;
402
+ } = {}
403
+ ): Step {
404
+ Step.assert(this.stepId);
405
+ return new Step({
406
+ stepId: this.stepId,
407
+ impl,
408
+ tag,
409
+ data: data ?? this.data,
410
+ delayMs,
411
+ repeatCountMax,
412
+ });
413
+ }
414
+ end(
415
+ {
416
+ tag,
417
+ data,
418
+ delayMs = Step.delayMsDefault,
419
+ repeatCountMax = Step.repeatCountMaxDefault,
420
+ }: {
421
+ tag?: string | undefined;
422
+ data?: any | undefined;
423
+ delayMs?: number;
424
+ repeatCountMax?: number;
425
+ } = {}
426
+ ): Step {
427
+ Step.assert(this.stepId);
428
+ return new Step({
429
+ stepId: this.stepId,
430
+ impl: undefined,
431
+ tag,
432
+ data: data ?? this.data,
433
+ delayMs,
434
+ repeatCountMax,
435
+ isEnd: true,
436
+ });
437
+ }
438
+
439
+ /**
440
+ * 重复当前步骤
441
+ * @param stepId 步骤ID
442
+ * @param tag 步骤标签
443
+ * @param data 步骤数据
444
+ * @param delayMs 步骤延迟时间(毫秒)
445
+ * @returns 当前步骤实例
446
+ */
447
+ repeat({
448
+ stepId = this.stepId,
449
+ tag = this.tag,
450
+ data = this.data,
451
+ delayMs = this.delayMs,
452
+ repeatCountMax = this.repeatCountMax,
692
453
  }: {
693
- matchedPackageName?: string;
694
- matchedText?: string;
695
- timeoutMillis?: number;
696
- longPressDuration?: number;
697
- } = { matchedText: "粘贴", timeoutMillis: 1500, longPressDuration: 600 }
698
- ): Promise<boolean> {
699
- Step.assert(this.stepId);
700
- const result = await AssistsX.longPressGestureAutoPaste(point, text, {
701
- matchedPackageName,
702
- matchedText,
703
- timeoutMillis,
704
- longPressDuration,
705
- });
706
- Step.assert(this.stepId);
707
- return result;
708
- }
709
- public async getAppInfo(packageName: string): Promise<any> {
710
- Step.assert(this.stepId);
711
- const result = await AssistsX.getAppInfo(packageName);
712
- Step.assert(this.stepId);
713
- return result;
714
- }
715
- public async performLinearGesture(
716
- startPoint: { x: number; y: number },
717
- endPoint: { x: number; y: number },
718
- { duration }: { duration?: number } = {}
719
- ): Promise<boolean> {
720
- Step.assert(this.stepId);
721
- const result = await AssistsX.performLinearGesture(startPoint, endPoint, {
722
- duration,
723
- });
724
- Step.assert(this.stepId);
725
- return result;
726
- }
727
-
728
- /**
729
- * 返回操作
730
- * @returns 是否成功
731
- */
732
- public back(): boolean {
733
- Step.assert(this.stepId);
734
- const result = AssistsX.back();
735
- Step.assert(this.stepId);
736
- return result;
737
- }
738
-
739
- /**
740
- * 回到主页
741
- * @returns 是否成功
742
- */
743
- public home(): boolean {
744
- Step.assert(this.stepId);
745
- const result = AssistsX.home();
746
- Step.assert(this.stepId);
747
- return result;
748
- }
749
-
750
- /**
751
- * 打开通知栏
752
- * @returns 是否成功
753
- */
754
- public notifications(): boolean {
755
- Step.assert(this.stepId);
756
- const result = AssistsX.notifications();
757
- Step.assert(this.stepId);
758
- return result;
759
- }
760
-
761
- /**
762
- * 显示最近应用
763
- * @returns 是否成功
764
- */
765
- public recentApps(): boolean {
766
- Step.assert(this.stepId);
767
- const result = AssistsX.recentApps();
768
- Step.assert(this.stepId);
769
- return result;
770
- }
771
-
772
- /**
773
- * 获取屏幕尺寸
774
- * @returns 屏幕尺寸对象
775
- */
776
- public getScreenSize(): any {
777
- Step.assert(this.stepId);
778
- const data = AssistsX.getScreenSize();
779
- Step.assert(this.stepId);
780
- return data;
781
- }
782
-
783
- /**
784
- * 获取应用窗口尺寸
785
- * @returns 应用窗口尺寸对象
786
- */
787
- public getAppScreenSize(): any {
788
- Step.assert(this.stepId);
789
- const data = AssistsX.getAppScreenSize();
790
- Step.assert(this.stepId);
791
- return data;
792
- }
454
+ stepId?: string;
455
+ tag?: string | undefined;
456
+ data?: any | undefined;
457
+ delayMs?: number;
458
+ repeatCountMax?: number;
459
+ } = {}): Step {
460
+ Step.assert(this.stepId);
461
+ this.repeatCount++;
462
+ this.stepId = stepId;
463
+ this.tag = tag;
464
+ this.data = data;
465
+ this.delayMs = delayMs;
466
+ this.repeatCountMax = repeatCountMax;
467
+ return this;
468
+ }
469
+
470
+ /**
471
+ * 延迟执行
472
+ * @param ms 延迟时间(毫秒)
473
+ * @returns Promise
474
+ */
475
+ async delay(ms: number): Promise<void> {
476
+ while (true) {
477
+ ms -= 100;
478
+ if (ms <= 0) {
479
+ break;
480
+ }
481
+ await new Promise((resolve) => setTimeout(resolve, 100));
482
+ Step.assert(this.stepId);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * 等待异步方法执行完成
488
+ * @param method 异步方法
489
+ * @returns Promise<T>
490
+ */
491
+ async await<T>(method: () => Promise<T>): Promise<T> {
492
+ Step.assert(this.stepId);
493
+ const result = await method();
494
+ Step.assert(this.stepId);
495
+ return result;
496
+ }
497
+
498
+ /**
499
+ * 对单个节点进行截图
500
+ * @param node 目标节点
501
+ * @param overlayHiddenScreenshotDelayMillis 截图延迟时间(毫秒)
502
+ * @returns 截图路径
503
+ */
504
+ public async takeScreenshotByNode(
505
+ node: Node,
506
+ overlayHiddenScreenshotDelayMillis: number = 250
507
+ ): Promise<string> {
508
+ Step.assert(this.stepId);
509
+ const result = await AssistsX.takeScreenshotNodes(
510
+ [node],
511
+ overlayHiddenScreenshotDelayMillis
512
+ );
513
+ Step.assert(this.stepId);
514
+ return result[0];
515
+ }
516
+
517
+ /**
518
+ * 对多个节点进行截图
519
+ * @param nodes 目标节点数组
520
+ * @param overlayHiddenScreenshotDelayMillis 截图延迟时间(毫秒)
521
+ * @returns 截图路径数组
522
+ */
523
+ public async takeScreenshotNodes(
524
+ nodes: Node[],
525
+ overlayHiddenScreenshotDelayMillis: number = 250
526
+ ): Promise<string[]> {
527
+ Step.assert(this.stepId);
528
+ const result = await AssistsX.takeScreenshotNodes(
529
+ nodes,
530
+ overlayHiddenScreenshotDelayMillis
531
+ );
532
+ Step.assert(this.stepId);
533
+ return result;
534
+ }
535
+
536
+ /**
537
+ * 获取所有符合条件的节点
538
+ * @param filterClass 类名过滤
539
+ * @param filterViewId 视图ID过滤
540
+ * @param filterDes 描述过滤
541
+ * @param filterText 文本过滤
542
+ * @returns 节点数组
543
+ */
544
+ public getAllNodes({
545
+ filterClass,
546
+ filterViewId,
547
+ filterDes,
548
+ filterText,
549
+ }: {
550
+ filterClass?: string;
551
+ filterViewId?: string;
552
+ filterDes?: string;
553
+ filterText?: string;
554
+ } = {}): Node[] {
555
+ Step.assert(this.stepId);
556
+ const nodes = AssistsX.getAllNodes({
557
+ filterClass,
558
+ filterViewId,
559
+ filterDes,
560
+ filterText,
561
+ });
562
+ Step.assert(this.stepId);
563
+ Step.assignIdsToNodes(nodes, this.stepId);
564
+ return nodes;
565
+ }
566
+
567
+ /**
568
+ * 启动应用
569
+ * @param packageName 应用包名
570
+ * @returns 是否启动成功
571
+ */
572
+ public launchApp(packageName: string): boolean {
573
+ Step.assert(this.stepId);
574
+ const result = AssistsX.launchApp(packageName);
575
+ Step.assert(this.stepId);
576
+ return result;
577
+ }
578
+
579
+ /**
580
+ * 获取当前应用包名
581
+ * @returns 包名
582
+ */
583
+ public getPackageName(): string {
584
+ Step.assert(this.stepId);
585
+ const result = AssistsX.getPackageName();
586
+ Step.assert(this.stepId);
587
+ return result;
588
+ }
589
+
590
+ /**
591
+ * 通过ID查找节点
592
+ * @param id 节点ID
593
+ * @param filterClass 类名过滤
594
+ * @param filterText 文本过滤
595
+ * @param filterDes 描述过滤
596
+ * @returns 节点数组
597
+ */
598
+ public findById(
599
+ id: string,
600
+ {
601
+ filterClass,
602
+ filterText,
603
+ filterDes,
604
+ }: { filterClass?: string; filterText?: string; filterDes?: string } = {}
605
+ ): Node[] {
606
+ Step.assert(this.stepId);
607
+ const nodes = AssistsX.findById(id, { filterClass, filterText, filterDes });
608
+ Step.assert(this.stepId);
609
+ Step.assignIdsToNodes(nodes, this.stepId);
610
+ return nodes;
611
+ }
612
+
613
+ /**
614
+ * 通过文本查找节点
615
+ * @param text 要查找的文本
616
+ * @param filterClass 类名过滤
617
+ * @param filterViewId 视图ID过滤
618
+ * @param filterDes 描述过滤
619
+ * @returns 节点数组
620
+ */
621
+ public findByText(
622
+ text: string,
623
+ {
624
+ filterClass,
625
+ filterViewId,
626
+ filterDes,
627
+ }: { filterClass?: string; filterViewId?: string; filterDes?: string } = {}
628
+ ): Node[] {
629
+ Step.assert(this.stepId);
630
+ const nodes = AssistsX.findByText(text, {
631
+ filterClass,
632
+ filterViewId,
633
+ filterDes,
634
+ });
635
+ Step.assert(this.stepId);
636
+ Step.assignIdsToNodes(nodes, this.stepId);
637
+ return nodes;
638
+ }
639
+
640
+ /**
641
+ * 通过标签查找节点
642
+ * @param className 类名
643
+ * @param filterText 文本过滤
644
+ * @param filterViewId 视图ID过滤
645
+ * @param filterDes 描述过滤
646
+ * @returns 节点数组
647
+ */
648
+ public findByTags(
649
+ className: string,
650
+ {
651
+ filterText,
652
+ filterViewId,
653
+ filterDes,
654
+ }: { filterText?: string; filterViewId?: string; filterDes?: string } = {}
655
+ ): Node[] {
656
+ Step.assert(this.stepId);
657
+ const nodes = AssistsX.findByTags(className, {
658
+ filterText,
659
+ filterViewId,
660
+ filterDes,
661
+ });
662
+ Step.assert(this.stepId);
663
+ Step.assignIdsToNodes(nodes, this.stepId);
664
+ return nodes;
665
+ }
666
+
667
+ /**
668
+ * 查找所有匹配文本的节点
669
+ * @param text 要查找的文本
670
+ * @returns 节点数组
671
+ */
672
+ public findByTextAllMatch(text: string): Node[] {
673
+ Step.assert(this.stepId);
674
+ const nodes = AssistsX.findByTextAllMatch(text);
675
+ Step.assert(this.stepId);
676
+ Step.assignIdsToNodes(nodes, this.stepId);
677
+ return nodes;
678
+ }
679
+
680
+ /**
681
+ * 检查是否包含指定文本
682
+ * @param text 要检查的文本
683
+ * @returns 是否包含
684
+ */
685
+ public containsText(text: string): boolean {
686
+ Step.assert(this.stepId);
687
+ const result = AssistsX.containsText(text);
688
+ Step.assert(this.stepId);
689
+ return result;
690
+ }
691
+
692
+ /**
693
+ * 获取所有文本
694
+ * @returns 文本数组
695
+ */
696
+ public getAllText(): string[] {
697
+ Step.assert(this.stepId);
698
+ const texts = AssistsX.getAllText();
699
+ Step.assert(this.stepId);
700
+ return texts;
701
+ }
702
+
703
+ /**
704
+ * 执行点击手势
705
+ * @param x 横坐标
706
+ * @param y 纵坐标
707
+ * @param duration 持续时间(毫秒)
708
+ * @returns 是否成功
709
+ */
710
+ public async clickByGesture(
711
+ x: number,
712
+ y: number,
713
+ duration: number
714
+ ): Promise<boolean> {
715
+ Step.assert(this.stepId);
716
+ const result = await AssistsX.clickByGesture(x, y, duration);
717
+ Step.assert(this.stepId);
718
+ return result;
719
+ }
720
+
721
+ public async longPressGestureAutoPaste(
722
+ point: { x: number; y: number },
723
+ text: string,
724
+ {
725
+ matchedPackageName,
726
+ matchedText,
727
+ timeoutMillis,
728
+ longPressDuration,
729
+ }: {
730
+ matchedPackageName?: string;
731
+ matchedText?: string;
732
+ timeoutMillis?: number;
733
+ longPressDuration?: number;
734
+ } = { matchedText: "粘贴", timeoutMillis: 1500, longPressDuration: 600 }
735
+ ): Promise<boolean> {
736
+ Step.assert(this.stepId);
737
+ const result = await AssistsX.longPressGestureAutoPaste(point, text, {
738
+ matchedPackageName,
739
+ matchedText,
740
+ timeoutMillis,
741
+ longPressDuration,
742
+ });
743
+ Step.assert(this.stepId);
744
+ return result;
745
+ }
746
+ public async getAppInfo(packageName: string): Promise<any> {
747
+ Step.assert(this.stepId);
748
+ const result = await AssistsX.getAppInfo(packageName);
749
+ Step.assert(this.stepId);
750
+ return result;
751
+ }
752
+ public async performLinearGesture(
753
+ startPoint: { x: number; y: number },
754
+ endPoint: { x: number; y: number },
755
+ { duration }: { duration?: number } = {}
756
+ ): Promise<boolean> {
757
+ Step.assert(this.stepId);
758
+ const result = await AssistsX.performLinearGesture(startPoint, endPoint, {
759
+ duration,
760
+ });
761
+ Step.assert(this.stepId);
762
+ return result;
763
+ }
764
+
765
+ /**
766
+ * 返回操作
767
+ * @returns 是否成功
768
+ */
769
+ public back(): boolean {
770
+ Step.assert(this.stepId);
771
+ const result = AssistsX.back();
772
+ Step.assert(this.stepId);
773
+ return result;
774
+ }
775
+
776
+ /**
777
+ * 回到主页
778
+ * @returns 是否成功
779
+ */
780
+ public home(): boolean {
781
+ Step.assert(this.stepId);
782
+ const result = AssistsX.home();
783
+ Step.assert(this.stepId);
784
+ return result;
785
+ }
786
+
787
+ /**
788
+ * 打开通知栏
789
+ * @returns 是否成功
790
+ */
791
+ public notifications(): boolean {
792
+ Step.assert(this.stepId);
793
+ const result = AssistsX.notifications();
794
+ Step.assert(this.stepId);
795
+ return result;
796
+ }
797
+
798
+ /**
799
+ * 显示最近应用
800
+ * @returns 是否成功
801
+ */
802
+ public recentApps(): boolean {
803
+ Step.assert(this.stepId);
804
+ const result = AssistsX.recentApps();
805
+ Step.assert(this.stepId);
806
+ return result;
807
+ }
808
+
809
+ /**
810
+ * 获取屏幕尺寸
811
+ * @returns 屏幕尺寸对象
812
+ */
813
+ public getScreenSize(): any {
814
+ Step.assert(this.stepId);
815
+ const data = AssistsX.getScreenSize();
816
+ Step.assert(this.stepId);
817
+ return data;
818
+ }
819
+
820
+ /**
821
+ * 获取应用窗口尺寸
822
+ * @returns 应用窗口尺寸对象
823
+ */
824
+ public getAppScreenSize(): any {
825
+ Step.assert(this.stepId);
826
+ const data = AssistsX.getAppScreenSize();
827
+ Step.assert(this.stepId);
828
+ return data;
829
+ }
793
830
  }