feat: 通用步骤新增动作(屏幕控制/按键/滑动直到元素/点击坐标/长按/等待元素/输入前清空)
This commit is contained in:
+57
-6
@@ -744,7 +744,16 @@ function onTaskTypeChange(){
|
||||
// ================== 步骤编辑器 ==================
|
||||
var STEP_LIB=[
|
||||
{type:'open_app',label:'打开App',icon:'▶',params:{package:'',wait_home:false,home_feature:''}},
|
||||
{type:'stop_app',label:'结束App',icon:'⏹',params:{package:''}},
|
||||
{type:'screen_on',label:'亮屏',icon:'💡',params:{}},
|
||||
{type:'screen_off',label:'息屏',icon:'🌙',params:{}},
|
||||
{type:'keep_screen',label:'保持亮屏',icon:'🔆',params:{mode:'on'}},
|
||||
{type:'key_event',label:'按键',icon:'⌨️',params:{key:'back'}},
|
||||
{type:'swipe',label:'滑动',icon:'↕',params:{direction:'up',duration_min:0.25,duration_max:0.50}},
|
||||
{type:'swipe_until',label:'滑动直到元素',icon:'🔍',params:{selector_type:'xpath',selector_value:'',direction:'up',max_swipes:8,click_when_found:true}},
|
||||
{type:'click_xy',label:'点击坐标',icon:'🎯',params:{x:50,y:50}},
|
||||
{type:'long_click',label:'长按元素',icon:'👆',params:{selector_type:'xpath',selector_value:'',duration:1.0,wait_timeout:2}},
|
||||
{type:'wait_el',label:'等待元素',icon:'⏳',params:{selector_type:'xpath',selector_value:'',timeout:10}},
|
||||
{type:'click',label:'点击元素',icon:'✦',params:{selector_type:'xpath',selector_value:'',wait_timeout:2}},
|
||||
{type:'input_text',label:'输入文字',icon:'⌨',params:{mode:'random',texts:'你好\n有趣\n支持',fixed_text:''}},
|
||||
{type:'wait',label:'等待',icon:'⏱',params:{min:1.0,max:3.0}},
|
||||
@@ -975,16 +984,48 @@ var _stepEditor={
|
||||
h+='<div class="form-group"><label>包名</label><input type="text" class="form-control" data-key="package" value="'+esc(p.package||'')+'" placeholder="如 com.ss.android.ugc.aweme"></div>';
|
||||
h+='<div class="form-row"><div class="form-group form-check"><input type="checkbox" data-key="wait_home" '+(p.wait_home?'checked':'')+'><label>等待进入首页</label></div>';
|
||||
h+='<div class="form-group"><label>首页特征词</label><input type="text" class="form-control" data-key="home_feature" value="'+esc(p.home_feature||'')+'" placeholder="如 拍摄"></div></div>';
|
||||
}else if(step.type==='stop_app'){
|
||||
h+='<div class="form-group"><label>包名</label><input type="text" class="form-control" data-key="package" value="'+esc(p.package||'')+'" placeholder="如 com.ss.android.ugc.aweme"></div>';
|
||||
h+='<div class="help">强制结束该 App(am force-stop),清除后台进程,下次打开为冷启动。常配合"打开App"使用:结束→重新打开</div>';
|
||||
}else if(step.type==='screen_on'){
|
||||
h+='<div class="help">亮屏(息屏时唤醒并滑动解锁)。任务执行前用——息屏状态下 u2 无法点击操作</div>';
|
||||
}else if(step.type==='screen_off'){
|
||||
h+='<div class="help">息屏。任务结束后用,避免长时间亮屏导致烧屏/发热</div>';
|
||||
}else if(step.type==='keep_screen'){
|
||||
h+='<div class="form-group"><label>模式</label><select class="form-control" data-key="mode">'+
|
||||
'<option value="on"'+(p.mode!=='off'?' selected':'')+'>保持亮屏(充电时屏幕常亮)</option>'+
|
||||
'<option value="off"'+(p.mode==='off'?' selected':'')+'>恢复自动息屏</option></select></div>';
|
||||
h+='<div class="help">长任务(如养号看视频几小时)放"保持亮屏"防屏幕超时熄灭;任务结束前放"恢复自动息屏"</div>';
|
||||
}else if(step.type==='swipe'){
|
||||
h+='<div class="form-row"><div class="form-group"><label>方向</label><select class="form-control" data-key="direction">'+
|
||||
['up','down','left','right'].map(function(d){return '<option value="'+d+'"'+(p.direction===d?' selected':'')+'>'+d+'</option>';}).join('')+'</select></div>';
|
||||
h+='<div class="form-group"><label>最短时长(秒)</label><input type="number" class="form-control" data-key="duration_min" value="'+(p.duration_min||0.25)+'" step="0.05" min="0.05"></div>';
|
||||
h+='<div class="form-group"><label>最长时长(秒)</label><input type="number" class="form-control" data-key="duration_max" value="'+(p.duration_max||0.50)+'" step="0.05" min="0.05"></div></div>';
|
||||
}else if(step.type==='click'){
|
||||
h+='<div class="form-row"><div class="form-group"><label>选择器类型</label><select class="form-control" data-key="selector_type">'+
|
||||
['xpath','description','text','resourceId','descriptionContains','className'].map(function(d){return '<option value="'+d+'"'+(p.selector_type===d?' selected':'')+'>'+d+'</option>';}).join('')+'</select></div>';
|
||||
h+='<div class="form-group" style="grid-column:span 2"><label>选择器值</label><div class="sel-picker"><input type="text" class="form-control" data-key="selector_value" value="'+esc(p.selector_value||'')+'" placeholder="如 点赞"><button class="btn btn-xs btn-pick" onclick="_stepEditor.openPicker(this)">抓取元素</button></div></div></div>';
|
||||
h+='<div class="form-group"><label>等待超时(秒)</label><input type="number" class="form-control" data-key="wait_timeout" value="'+(p.wait_timeout||2)+'" step="0.5" min="0.5"></div>';
|
||||
h+=_selRowHtml(p,'<div class="form-group"><label>等待超时(秒)</label><input type="number" class="form-control" data-key="wait_timeout" value="'+(p.wait_timeout||2)+'" step="0.5" min="0.5"></div>');
|
||||
}else if(step.type==='long_click'){
|
||||
h+=_selRowHtml(p,'<div class="form-row"><div class="form-group"><label>长按时长(秒)</label><input type="number" class="form-control" data-key="duration" value="'+(p.duration||1.0)+'" step="0.5" min="0.3"></div>'+
|
||||
'<div class="form-group"><label>等待超时(秒)</label><input type="number" class="form-control" data-key="wait_timeout" value="'+(p.wait_timeout||2)+'" step="0.5" min="0.5"></div></div>');
|
||||
}else if(step.type==='swipe_until'){
|
||||
h+=_selRowHtml(p,'<div class="form-row"><div class="form-group"><label>方向</label><select class="form-control" data-key="direction">'+
|
||||
'<option value="up"'+(p.direction!=='down'?' selected':'')+'>上滑</option>'+
|
||||
'<option value="down"'+(p.direction==='down'?' selected':'')+'>下滑</option></select></div>'+
|
||||
'<div class="form-group"><label>最多滑动次数</label><input type="number" class="form-control" data-key="max_swipes" value="'+(p.max_swipes||8)+'" min="1" max="50"></div></div>'+
|
||||
'<div class="form-group form-check"><input type="checkbox" data-key="click_when_found" '+(p.click_when_found!==false?'checked':'')+'><label>找到后点击</label></div>'+
|
||||
'<div class="help">上滑/下滑直到目标元素出现(每次滑动后检查一次),找不到则跳过继续</div>');
|
||||
}else if(step.type==='wait_el'){
|
||||
h+=_selRowHtml(p,'<div class="form-group"><label>最长等待(秒)</label><input type="number" class="form-control" data-key="timeout" value="'+(p.timeout||10)+'" min="1" max="120"></div>'+
|
||||
'<div class="help">等待目标元素出现(替代固定秒数等待),超时则继续</div>');
|
||||
}else if(step.type==='click_xy'){
|
||||
h+='<div class="form-row"><div class="form-group"><label>X(屏幕% )</label><input type="number" class="form-control" data-key="x" value="'+(p.x||50)+'" min="0" max="100"></div>'+
|
||||
'<div class="form-group"><label>Y(屏幕% )</label><input type="number" class="form-control" data-key="y" value="'+(p.y||50)+'" min="0" max="100"></div></div>'+
|
||||
'<div class="help">屏幕百分比坐标,50/50=屏幕中心。无选择器时的兜底点击</div>';
|
||||
}else if(step.type==='key_event'){
|
||||
h+='<div class="form-group"><label>按键</label><select class="form-control" data-key="key">'+
|
||||
[['back','返回键'],['home','Home键'],['enter','回车键'],['menu','菜单键'],['recent','最近任务'],['delete','删除键']].map(function(k){
|
||||
return '<option value="'+k[0]+'"'+(p.key===k[0]?' selected':'')+'>'+k[1]+'</option>';
|
||||
}).join('')+'</select></div>';
|
||||
h+='<div class="help">返回键用于退出评论/返回上一页,比结束App轻量</div>';
|
||||
}else if(step.type==='wait'){
|
||||
h+='<div class="form-row"><div class="form-group"><label>最短(秒)</label><input type="number" class="form-control" data-key="min" value="'+(p.min||1.0)+'" step="0.5" min="0.1"></div>';
|
||||
h+='<div class="form-group"><label>最长(秒)</label><input type="number" class="form-control" data-key="max" value="'+(p.max||3.0)+'" step="0.5" min="0.1"></div></div>';
|
||||
@@ -995,6 +1036,7 @@ var _stepEditor={
|
||||
'<option value="fixed"'+(im==='fixed'?' selected':'')+'>指定文字</option></select></div>';
|
||||
h+='<div class="form-group" data-mode="random" style="display:'+(im==='random'?'block':'none')+'"><label>候选文字(每行一个,随机选一条)</label><textarea class="form-control" data-key="texts" rows="4" style="font-family:monospace;min-height:80px">'+esc(p.texts||'你好\n有趣\n支持')+'</textarea></div>';
|
||||
h+='<div class="form-group" data-mode="fixed" style="display:'+(im==='fixed'?'block':'none')+'"><label>指定文字</label><input type="text" class="form-control" data-key="fixed_text" value="'+esc(p.fixed_text||'')+'"></div>';
|
||||
h+='<div class="form-group form-check"><input type="checkbox" data-key="clear_first" '+(p.clear_first!==false?'checked':'')+'><label>输入前先清空</label></div>';
|
||||
h+='<div class="help">需先用"点击元素"步骤定位到输入框,本步骤只负责输入文字</div>';
|
||||
}else if(step.type==='loop'){
|
||||
const lm=p.loop_mode==='time'?'time':'rounds';
|
||||
@@ -1295,9 +1337,18 @@ var _stepEditor={
|
||||
if(!s.params.selector_value){
|
||||
warnings.push(name+' "'+label+'": 选择器值为空,点击步骤会跳过。请用"抓取元素"按钮选择目标。');
|
||||
}
|
||||
}else if(s.type==='open_app'){
|
||||
}else if(s.type==='long_click'||s.type==='swipe_until'||s.type==='wait_el'){
|
||||
if(!s.params.selector_value){
|
||||
warnings.push(name+' "'+label+'": 选择器值为空,该步骤会跳过。请用"抓取元素"或"测试"按钮选择目标。');
|
||||
}
|
||||
}else if(s.type==='click_xy'){
|
||||
const x=parseFloat(s.params.x), y=parseFloat(s.params.y);
|
||||
if(isNaN(x)||isNaN(y)||x<0||x>100||y<0||y>100){
|
||||
warnings.push(name+' "'+label+'": 坐标需在 0-100 之间(屏幕百分比)。');
|
||||
}
|
||||
}else if(s.type==='open_app'||s.type==='stop_app'){
|
||||
if(!s.params.package){
|
||||
warnings.push(name+' "'+label+'": 包名为空,无法启动App');
|
||||
warnings.push(name+' "'+label+'": 包名为空,无法'+(s.type==='open_app'?'启动':'结束')+'App');
|
||||
}
|
||||
}else if(s.type==='input_text'){
|
||||
if(s.params.mode==='fixed'&&!s.params.fixed_text){
|
||||
|
||||
Reference in New Issue
Block a user