|
|
@@ -14,7 +14,7 @@ async function executeActionSequence(
|
|
|
depth,
|
|
|
ctx
|
|
|
) {
|
|
|
- const { executeAction, logMessage, evaluateCondition, getActionName, parseDelayString, calculateWaitTime, state } = ctx
|
|
|
+ const { executeAction, logMessage, evaluateCondition, getActionName, parseDelayString, calculateWaitTime, replaceVariablesInString, state } = ctx
|
|
|
const variableContext = state.variableContext
|
|
|
const DEFAULT_STEP_INTERVAL = ctx.DEFAULT_STEP_INTERVAL ?? 1000
|
|
|
|
|
|
@@ -22,7 +22,6 @@ async function executeActionSequence(
|
|
|
state.globalStepCounter = 0
|
|
|
state.variableContextInitialized = false
|
|
|
state.currentWorkflowFolderPath = folderPath
|
|
|
- await logMessage('========================', folderPath)
|
|
|
}
|
|
|
|
|
|
let completedSteps = 0
|
|
|
@@ -34,8 +33,16 @@ async function executeActionSequence(
|
|
|
|
|
|
if (action.type === 'schedule') {
|
|
|
const condition = action.condition || {}
|
|
|
- const intervalStr = condition.interval || '0s'
|
|
|
- const repeat = condition.repeat !== undefined ? condition.repeat : 1
|
|
|
+ let intervalStr = condition.interval || '0s'
|
|
|
+ if (replaceVariablesInString && typeof intervalStr === 'string') {
|
|
|
+ intervalStr = replaceVariablesInString(intervalStr, variableContext)
|
|
|
+ }
|
|
|
+ let repeat = condition.repeat !== undefined ? condition.repeat : 1
|
|
|
+ if (typeof repeat === 'string' && variableContext) {
|
|
|
+ const varName = repeat.replace(/^\{|\}$/g, '').trim()
|
|
|
+ const resolved = variableContext[varName]
|
|
|
+ repeat = resolved !== undefined && resolved !== null && resolved !== '' ? (parseInt(resolved, 10) || 1) : 1
|
|
|
+ }
|
|
|
const actionsToExecute = action.interval || []
|
|
|
const intervalMs = parseDelayString(intervalStr) || 0
|
|
|
const maxIterations = repeat === -1 ? Infinity : (typeof repeat === 'number' ? repeat : 1)
|
|
|
@@ -75,14 +82,33 @@ async function executeActionSequence(
|
|
|
}
|
|
|
|
|
|
if (action.type === 'for') {
|
|
|
- const items = Array.isArray(action.items) ? action.items : []
|
|
|
- for (const item of items) {
|
|
|
- if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
|
|
|
- if (action.variable) variableContext[action.variable] = item
|
|
|
- if (action.body && action.body.length > 0) {
|
|
|
- const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
- if (!result.success) return result
|
|
|
- completedSteps += result.completedSteps || 0
|
|
|
+ if (action.times != null) {
|
|
|
+ let count = action.times
|
|
|
+ if (typeof count === 'string') {
|
|
|
+ const varName = count.replace(/^\{|\}$/g, '').trim()
|
|
|
+ count = Math.max(0, parseInt(variableContext[varName], 10) || 0)
|
|
|
+ } else {
|
|
|
+ count = Math.max(0, parseInt(count, 10) || 0)
|
|
|
+ }
|
|
|
+ for (let i = 0; i < count; i++) {
|
|
|
+ if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
|
|
|
+ if (action.variable) variableContext[action.variable.replace(/^\{|\}$/g, '').trim()] = i
|
|
|
+ if (action.body && action.body.length > 0) {
|
|
|
+ const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
+ if (!result.success) return result
|
|
|
+ completedSteps += result.completedSteps || 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const items = Array.isArray(action.items) ? action.items : []
|
|
|
+ for (const item of items) {
|
|
|
+ if (shouldStop && shouldStop()) return { success: false, error: '执行被停止', completedSteps }
|
|
|
+ if (action.variable) variableContext[action.variable.replace(/^\{|\}$/g, '').trim()] = item
|
|
|
+ if (action.body && action.body.length > 0) {
|
|
|
+ const result = await executeActionSequence(action.body, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
+ if (!result.success) return result
|
|
|
+ completedSteps += result.completedSteps || 0
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
continue
|
|
|
@@ -100,6 +126,34 @@ async function executeActionSequence(
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
+ if (action.type === 'try') {
|
|
|
+ const tryActions = action.try || action.body || []
|
|
|
+ const successActions = action.success || []
|
|
|
+ const failActions = action.fail || action.catch || []
|
|
|
+ const result = tryActions.length > 0
|
|
|
+ ? await executeActionSequence(tryActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
+ : { success: true, completedSteps: 0 }
|
|
|
+ if (result.success && successActions.length > 0) {
|
|
|
+ const successResult = await executeActionSequence(successActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
+ if (!successResult.success) return successResult
|
|
|
+ completedSteps += (result.completedSteps || 0) + (successResult.completedSteps || 0)
|
|
|
+ } else if (result.success) {
|
|
|
+ completedSteps += result.completedSteps || 0
|
|
|
+ } else {
|
|
|
+ const errMsg = result.error || '未知错误'
|
|
|
+ const timeStr = new Date().toISOString().replace('T', ' ').slice(0, 19)
|
|
|
+ await logMessage(`[try 失败] ${timeStr} ${errMsg}`, folderPath).catch(() => {})
|
|
|
+ if (failActions.length > 0) {
|
|
|
+ const failResult = await executeActionSequence(failActions, device, folderPath, resolution, interval, onStepComplete, shouldStop, depth + 1, ctx)
|
|
|
+ if (!failResult.success) return failResult
|
|
|
+ completedSteps += (result.completedSteps || 0) + (failResult.completedSteps || 0)
|
|
|
+ } else {
|
|
|
+ return result
|
|
|
+ }
|
|
|
+ }
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
const times = action.times || 1
|
|
|
if (onStepComplete) onStepComplete(i + 1, actions.length, getActionName(action), 0, times, 0)
|
|
|
|
|
|
@@ -123,11 +177,10 @@ async function executeActionSequence(
|
|
|
|
|
|
state.globalStepCounter++
|
|
|
const typeName = getActionName(action)
|
|
|
- await logMessage(`[步骤] 开始: ${typeName}`, folderPath).catch(() => {})
|
|
|
|
|
|
const result = await executeAction(action, device, folderPath, resolution)
|
|
|
|
|
|
- if (result.success && result.skipped) await logMessage(`[提示] 步骤已跳过(条件不满足): ${typeName}`, folderPath).catch(() => {})
|
|
|
+ if (result.success && result.skipped) { /* 步骤跳过不写 log */ }
|
|
|
|
|
|
if (!result.success) {
|
|
|
const now = new Date()
|