开发日志251211-15

date
Dec 11, 2025
slug
开发日志251211-15
status
Published
tags
AI
计算机
summary
type
Post
昨天研究了一下架构 … 发现要实现我的复杂功能的最好方法是

重构

有点恐怖
问了下AI 给出了以下架构:
multi-control-system/           # 项目根目录
├── backend/                   # Node.js 后端服务(大脑)
│   ├── src/
│   │   ├── core/             # 核心调度模块
│   │   │   ├── Scheduler.js  # 任务调度器(核心)
│   │   │   ├── DeviceManager.js # 设备管理器
│   │   │   └── TaskChainEngine.js # 任务链引擎
│   │   ├── adapters/         # 适配器层(对接不同执行端)
│   │   │   └── DeviceControlAdapter.js # 统一设备控制适配器
│   │   ├── services/         # 业务服务
│   │   │   ├── AIService.js  # AI服务封装
│   │   │   └── StorageService.js # 存储服务
│   │   ├── websocket/        # WebSocket 服务
│   │   │   ├── WSServer.js   # WebSocket 服务器
│   │   │   └── WSClient.js   # 连接闭源WS的客户端
│   │   ├── routes/           # HTTP API 路由
│   │   └── app.js            # Express 主应用
│   ├── package.json
│   └── server.js             # 服务入口文件
│
├── frontend/                  # Vue 3 前端控制台
│   ├── src/
│   │   ├── views/
│   │   │   ├── Dashboard.vue # 主控制台
│   │   │   ├── TaskEditor.vue # 任务链编辑器
│   │   │   └── DeviceMonitor.vue # 设备监控
│   │   ├── components/       # 通用组件
│   │   ├── stores/           # Pinia 状态管理
│   │   ├── api/              # API 封装
│   │   └── App.vue
│   ├── package.json
│   └── vite.config.js        # Vite 配置
│
└── shared/                   # 共享定义(前后端通用)
    └── types.js              # TypeScript/JS类型定义
🔧 核心设计要点
他给出的代码:
你说得对,仅靠几个核心类确实无法运行。我将为你提供一个完整的、可立即运行的基础项目框架,包含所有必需的文件、配置和基础通信链路。

🚀 完整可运行代码

1. 后端完整配置

backend/package.json
{
  "name": "multi-control-backend",
  "version": "1.0.0",
  "description": "群控系统后端",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "ws": "^8.14.0",
    "socket.io": "^4.7.2",
    "cors": "^2.8.5",
    "dotenv": "^16.3.1",
    "winston": "^3.11.0",
    "bull": "^4.11.5",
    "redis": "^4.6.10",
    "uuid": "^9.0.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}
backend/.env
NODE_ENV=development
PORT=3000
FRONTEND_URL=http://localhost:5173
DEVICE_CONTROL_WS_URL=ws://192.168.11.199:22221
REDIS_URL=redis://localhost:6379
backend/server.js - 程序入口
require('dotenv').config();
const app = require('./src/app');
const WSServer = require('./src/websocket/WSServer');
const WSClient = require('./src/websocket/WSClient');

const PORT = process.env.PORT || 3000;

// 启动HTTP服务器
const server = app.listen(PORT, () => {
    console.log(`🚀 后端服务运行在: <http://localhost>:${PORT}`);
    console.log(`📡 WebSocket端点: ws://localhost:${PORT}`);
});

// 启动WebSocket服务器(供前端连接)
const wsServer = new WSServer(server);

// 连接设备控制WebSocket(作为客户端)
const deviceControlWS = new WSClient(process.env.DEVICE_CONTROL_WS_URL);
deviceControlWS.connect();

// 优雅关闭
process.on('SIGTERM', () => {
    console.log('收到关闭信号,优雅关闭服务...');
    server.close(() => {
        console.log('HTTP服务已关闭');
        process.exit(0);
    });
});
backend/src/app.js - Express主应用
const express = require('express');
const cors = require('cors');
const path = require('path');
const logger = require('./middleware/logger');

// 导入路由
const apiRoutes = require('./routes/api');
const taskChainRoutes = require('./routes/taskChains');

const app = express();

// 中间件
app.use(cors({
    origin: process.env.FRONTEND_URL,
    credentials: true
}));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
app.use(logger);

// 静态文件(可选,用于托管前端)
// app.use(express.static(path.join(__dirname, '../../frontend/dist')));

// 路由
app.use('/api', apiRoutes);
app.use('/api/task-chains', taskChainRoutes);

// 健康检查
app.get('/health', (req, res) => {
    res.json({
        status: 'healthy',
        timestamp: new Date().toISOString(),
        service: 'multi-control-backend'
    });
});

// 404处理
app.use((req, res) => {
    res.status(404).json({ error: 'Not Found' });
});

// 错误处理
app.use((err, req, res, next) => {
    console.error('全局错误:', err.stack);
    res.status(500).json({
        error: 'Internal Server Error',
        message: process.env.NODE_ENV === 'development' ? err.message : undefined
    });
});

module.exports = app;
backend/src/websocket/WSServer.js - WebSocket服务器
const { Server } = require('socket.io');
const { v4: uuidv4 } = require('uuid');
const DeviceService = require('../services/DeviceService');

class WSServer {
    constructor(httpServer) {
        this.io = new Server(httpServer, {
            cors: {
                origin: process.env.FRONTEND_URL,
                methods: ["GET", "POST"]
            }
        });

        this.deviceService = new DeviceService();
        this.clients = new Map(); // clientId -> socket
        this.deviceSubscriptions = new Map(); // deviceId -> [clientId1, clientId2]

        this.setupEventHandlers();
        console.log('✅ WebSocket服务器已启动');
    }

    setupEventHandlers() {
        this.io.on('connection', (socket) => {
            const clientId = uuidv4();
            this.clients.set(clientId, socket);
            console.log(`🔗 客户端连接: ${clientId} (总计: ${this.clients.size})`);

            // 客户端订阅设备状态
            socket.on('subscribe_device', (deviceId) => {
                this.subscribeToDevice(clientId, deviceId);
                socket.emit('device_status', {
                    deviceId,
                    status: this.deviceService.getDeviceStatus(deviceId)
                });
            });

            // 客户端发送控制指令
            socket.on('control_device', async ({ deviceId, command, params }) => {
                console.log(`📤 控制指令: ${deviceId} -> ${command}`);
                const result = await this.deviceService.sendCommand(deviceId, command, params);
                socket.emit('command_result', { deviceId, command, result });
            });

            // 客户端请求设备列表
            socket.on('get_devices', () => {
                const devices = this.deviceService.getAllDevices();
                socket.emit('device_list', devices);
            });

            // 断开连接
            socket.on('disconnect', () => {
                this.clients.delete(clientId);
                this.cleanupSubscriptions(clientId);
                console.log(`🔌 客户端断开: ${clientId} (剩余: ${this.clients.size})`);
            });
        });
    }

    subscribeToDevice(clientId, deviceId) {
        if (!this.deviceSubscriptions.has(deviceId)) {
            this.deviceSubscriptions.set(deviceId, new Set());
        }
        this.deviceSubscriptions.get(deviceId).add(clientId);
    }

    // 向所有订阅了该设备的客户端推送状态更新
    broadcastDeviceUpdate(deviceId, data) {
        const subscribers = this.deviceSubscriptions.get(deviceId);
        if (subscribers) {
            subscribers.forEach(clientId => {
                const socket = this.clients.get(clientId);
                if (socket) {
                    socket.emit('device_update', { deviceId, ...data });
                }
            });
        }
    }

    cleanupSubscriptions(clientId) {
        for (const [deviceId, subscribers] of this.deviceSubscriptions) {
            subscribers.delete(clientId);
            if (subscribers.size === 0) {
                this.deviceSubscriptions.delete(deviceId);
            }
        }
    }
}

module.exports = WSServer;
backend/src/services/DeviceService.js - 设备管理服务
const EventEmitter = require('events');

class DeviceService extends EventEmitter {
    constructor() {
        super();
        this.devices = new Map(); // deviceId -> deviceData
        this.initializeMockDevices(); // 开发阶段用模拟数据
    }

    initializeMockDevices() {
        // 模拟3台设备,实际应从数据库或设备控制WS获取
        const mockDevices = [
            { id: 'device_001', name: '测试机1', status: 'idle', type: 'android', ip: '192.168.1.101' },
            { id: 'device_002', name: '测试机2', status: 'busy', type: 'android', ip: '192.168.1.102' },
            { id: 'device_003', name: '测试机3', status: 'offline', type: 'android', ip: '192.168.1.103' }
        ];

        mockDevices.forEach(device => {
            this.devices.set(device.id, {
                ...device,
                lastSeen: new Date().toISOString(),
                battery: Math.floor(Math.random() * 100),
                currentTask: null
            });
        });
    }

    getAllDevices() {
        return Array.from(this.devices.values());
    }

    getDeviceStatus(deviceId) {
        const device = this.devices.get(deviceId);
        return device ? device.status : 'not_found';
    }

    async sendCommand(deviceId, command, params = {}) {
        const device = this.devices.get(deviceId);
        if (!device) {
            throw new Error(`设备不存在: ${deviceId}`);
        }

        // 这里应该调用实际的设备控制WS
        console.log(`发送指令到设备 ${deviceId}: ${command}`, params);

        // 模拟执行成功
        const result = {
            success: true,
            command,
            deviceId,
            timestamp: new Date().toISOString(),
            data: { mock: '这是模拟响应,实际应连接设备控制WS' }
        };

        // 更新设备状态
        this.updateDeviceStatus(deviceId, 'busy', { currentCommand: command });

        // 模拟延迟后返回空闲
        setTimeout(() => {
            this.updateDeviceStatus(deviceId, 'idle', { currentCommand: null });
        }, 2000);

        return result;
    }

    updateDeviceStatus(deviceId, status, extraData = {}) {
        const device = this.devices.get(deviceId);
        if (device) {
            device.status = status;
            device.lastSeen = new Date().toISOString();
            Object.assign(device, extraData);

            // 触发事件,让WebSocket服务器广播更新
            this.emit('device_updated', { deviceId, status, device });
        }
    }
}

module.exports = DeviceService;

2. 前端完整配置

frontend/package.json
{
  "name": "multi-control-frontend",
  "version": "1.0.0",
  "description": "群控系统前端",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.3.8",
    "vue-router": "^4.2.5",
    "pinia": "^2.1.7",
    "socket.io-client": "^4.7.2",
    "axios": "^1.6.2",
    "element-plus": "^2.4.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.5.0",
    "vite": "^5.0.0"
  }
}
frontend/vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 5173,
    proxy: {
      '/api': {
        target: '<http://localhost:3000>',
        changeOrigin: true
      },
      '/ws': {
        target: 'ws://localhost:3000',
        ws: true
      }
    }
  }
})
frontend/src/main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(ElementPlus)
app.use(router)

app.mount('#app')
frontend/src/App.vue
<template>
  <div id="app">
    <header class="app-header">
      <h1>群控系统控制台</h1>
      <div class="status-indicator">
        <span :class="['status-dot', connectionStatus]"></span>
        <span>{{ connectionText }}</span>
      </div>
    </header>

    <main class="app-main">
      <router-view />
    </main>

    <footer class="app-footer">
      <p>设备总数: {{ deviceCount }} | 在线: {{ onlineCount }} | 版本: v1.0.0</p>
    </footer>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useDeviceStore } from './stores/deviceStore'

const deviceStore = useDeviceStore()
const connectionStatus = ref('disconnected') // connected, connecting, disconnected

const connectionText = computed(() => {
  const texts = {
    connected: '已连接',
    connecting: '连接中...',
    disconnected: '未连接'
  }
  return texts[connectionStatus.value]
})

const deviceCount = computed(() => deviceStore.devices.length)
const onlineCount = computed(() =>
  deviceStore.devices.filter(d => d.status === 'idle' || d.status === 'busy').length
)

onMounted(async () => {
  connectionStatus.value = 'connecting'
  try {
    await deviceStore.connectWebSocket()
    connectionStatus.value = 'connected'
    await deviceStore.fetchDevices()
  } catch (error) {
    console.error('连接失败:', error)
    connectionStatus.value = 'disconnected'
  }
})
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

#app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: #f5f7fa;
  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}

.app-header {
  background: linear-gradient(135deg, #1e3c72, #2a2a68);
  color: white;
  padding: 1rem 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.app-main {
  flex: 1;
  padding: 1.5rem;
  overflow-y: auto;
}

.app-footer {
  background: #2d3748;
  color: #a0aec0;
  text-align: center;
  padding: 0.75rem;
  font-size: 0.875rem;
}

.status-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
}

.status-dot.connected {
  background-color: #48bb78;
  box-shadow: 0 0 10px #48bb78;
}

.status-dot.connecting {
  background-color: #ed8936;
  box-shadow: 0 0 10px #ed8936;
}

.status-dot.disconnected {
  background-color: #f56565;
  box-shadow: 0 0 10px #f56565;
}
</style>
frontend/src/stores/deviceStore.js - Pinia状态管理
import { defineStore } from 'pinia'
import { io } from 'socket.io-client'
import { ref, computed } from 'vue'

export const useDeviceStore = defineStore('device', () => {
  const devices = ref([])
  const socket = ref(null)
  const connected = ref(false)

  const apiBaseUrl = import.meta.env.VITE_API_URL || '<http://localhost:3000>'
  const wsUrl = import.meta.env.VITE_WS_URL || '<http://localhost:3000>'

  // 连接WebSocket
  async function connectWebSocket() {
    return new Promise((resolve, reject) => {
      socket.value = io(wsUrl, {
        transports: ['websocket'],
        reconnection: true,
        reconnectionAttempts: 5,
        reconnectionDelay: 1000
      })

      socket.value.on('connect', () => {
        connected.value = true
        console.log('✅ WebSocket已连接')
        resolve()
      })

      socket.value.on('connect_error', (error) => {
        console.error('WebSocket连接错误:', error)
        reject(error)
      })

      socket.value.on('device_list', (deviceList) => {
        devices.value = deviceList
      })

      socket.value.on('device_update', (update) => {
        const index = devices.value.findIndex(d => d.id === update.deviceId)
        if (index !== -1) {
          devices.value[index] = { ...devices.value[index], ...update }
        }
      })

      socket.value.on('command_result', (result) => {
        console.log('命令执行结果:', result)
        // 可以在这里显示通知
      })
    })
  }

  // 获取设备列表
  async function fetchDevices() {
    if (socket.value?.connected) {
      socket.value.emit('get_devices')
    } else {
      try {
        const response = await fetch(`${apiBaseUrl}/api/devices`)
        devices.value = await response.json()
      } catch (error) {
        console.error('获取设备列表失败:', error)
      }
    }
  }

  // 订阅设备状态
  function subscribeToDevice(deviceId) {
    if (socket.value?.connected) {
      socket.value.emit('subscribe_device', deviceId)
    }
  }

  // 发送控制指令
  async function sendCommand(deviceId, command, params = {}) {
    if (socket.value?.connected) {
      socket.value.emit('control_device', { deviceId, command, params })
      return true
    } else {
      try {
        const response = await fetch(`${apiBaseUrl}/api/devices/${deviceId}/command`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ command, params })
        })
        return await response.json()
      } catch (error) {
        console.error('发送命令失败:', error)
        return { success: false, error: error.message }
      }
    }
  }

  // 按状态筛选设备
  const idleDevices = computed(() =>
    devices.value.filter(d => d.status === 'idle')
  )

  const busyDevices = computed(() =>
    devices.value.filter(d => d.status === 'busy')
  )

  const offlineDevices = computed(() =>
    devices.value.filter(d => d.status === 'offline')
  )

  return {
    devices,
    connected,
    idleDevices,
    busyDevices,
    offlineDevices,
    connectWebSocket,
    fetchDevices,
    subscribeToDevice,
    sendCommand
  }
})
frontend/src/views/Dashboard.vue - 主控制面板
<template>
  <div class="dashboard">
    <div class="dashboard-header">
      <h2>设备控制面板</h2>
      <div class="header-actions">
        <el-button type="primary" @click="refreshDevices">刷新</el-button>
        <el-button @click="showAddDevice = true">添加设备</el-button>
      </div>
    </div>

    <div class="stats-cards">
      <el-card class="stat-card">
        <template #header>
          <span>总设备数</span>
        </template>
        <div class="stat-value">{{ deviceStore.devices.length }}</div>
      </el-card>

      <el-card class="stat-card">
        <template #header>
          <span>在线设备</span>
        </template>
        <div class="stat-value">{{ deviceStore.idleDevices.length + deviceStore.busyDevices.length }}</div>
      </el-card>

      <el-card class="stat-card">
        <template #header>
          <span>空闲设备</span>
        </template>
        <div class="stat-value">{{ deviceStore.idleDevices.length }}</div>
      </el-card>

      <el-card class="stat-card">
        <template #header>
          <span>运行中</span>
        </template>
        <div class="stat-value">{{ deviceStore.busyDevices.length }}</div>
      </el-card>
    </div>

    <div class="device-grid">
      <DeviceCard
        v-for="device in deviceStore.devices"
        :key="device.id"
        :device="device"
        @command="handleDeviceCommand"
      />
    </div>

    <!-- 添加设备对话框 -->
    <el-dialog v-model="showAddDevice" title="添加设备" width="400px">
      <el-form :model="newDeviceForm">
        <el-form-item label="设备ID">
          <el-input v-model="newDeviceForm.id" placeholder="如: device_001" />
        </el-form-item>
        <el-form-item label="设备名称">
          <el-input v-model="newDeviceForm.name" placeholder="如: 测试机1" />
        </el-form-item>
        <el-form-item label="设备IP">
          <el-input v-model="newDeviceForm.ip" placeholder="如: 192.168.1.100" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showAddDevice = false">取消</el-button>
        <el-button type="primary" @click="addDevice">确认</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useDeviceStore } from '../stores/deviceStore'
import DeviceCard from '../components/DeviceCard.vue'

const deviceStore = useDeviceStore()
const showAddDevice = ref(false)
const newDeviceForm = ref({
  id: '',
  name: '',
  ip: ''
})

onMounted(() => {
  deviceStore.fetchDevices()
})

function refreshDevices() {
  deviceStore.fetchDevices()
}

function handleDeviceCommand(deviceId, command) {
  deviceStore.sendCommand(deviceId, command)
}

function addDevice() {
  // 这里应该调用API添加设备
  console.log('添加设备:', newDeviceForm.value)
  showAddDevice.value = false
  newDeviceForm.value = { id: '', name: '', ip: '' }
}
</script>

<style scoped>
.dashboard {
  padding: 1rem;
}

.dashboard-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
}

.stats-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1rem;
  margin-bottom: 2rem;
}

.stat-card {
  text-align: center;
}

.stat-value {
  font-size: 2rem;
  font-weight: bold;
  color: #2d3748;
}

.device-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1rem;
}
</style>

🏃 如何运行这个完整系统

第一步:启动后端服务

cd backend
npm install
npm run dev
# 服务运行在: <http://localhost:3000>
# WebSocket运行在: ws://localhost:3000

第二步:启动前端服务

cd frontend
npm install
npm run dev
# 前端运行在: <http://localhost:5173>

第三步:访问系统

  1. 打开浏览器访问 http://localhost:5173
  1. 你会看到一个现代化的控制台界面
  1. 设备列表会显示3台模拟设备
  1. 可以点击设备卡片发送控制指令

🔧 如何添加实际功能

1. 连接真实的设备控制WS

修改 backend/src/websocket/WSClient.js
const WebSocket = require('ws');

class WSClient {
    constructor(url) {
        this.url = url;
        this.ws = null;
        this.reconnectInterval = 5000;
    }

    connect() {
        this.ws = new WebSocket(this.url);

        this.ws.on('open', () => {
            console.log('✅ 已连接到设备控制服务器');
            // 发送身份验证或初始化指令
            this.send({ action: 'handshake', version: '1.0' });
        });

        this.ws.on('message', (data) => {
            this.handleMessage(data);
        });

        this.ws.on('error', (error) => {
            console.error('设备WS连接错误:', error);
        });

        this.ws.on('close', () => {
            console.log('设备WS连接断开,尝试重连...');
            setTimeout(() => this.connect(), this.reconnectInterval);
        });
    }

    send(data) {
        if (this.ws?.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(data));
        }
    }

    handleMessage(data) {
        try {
            const message = JSON.parse(data);
            console.log('收到设备消息:', message);

            // 处理设备消息,转发给前端或更新设备状态
        } catch (error) {
            console.error('解析设备消息失败:', error);
        }
    }
}

2. 添加任务链引擎

创建 backend/src/core/TaskChainEngine.js
class TaskChainEngine {
    constructor(stateRepository, deviceService) {
        this.stateRepo = stateRepository;
        this.deviceService = deviceService;
        this.activeChains = new Map();
    }

    async executeChain(deviceId, chainConfig) {
        const chainId = `chain_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

        const chain = {
            id: chainId,
            deviceId,
            config: chainConfig,
            currentStep: 0,
            status: 'running',
            results: [],
            context: {}
        };

        this.activeChains.set(chainId, chain);

        // 顺序执行每个步骤
        for (let i = 0; i < chainConfig.steps.length; i++) {
            const step = chainConfig.steps[i];
            chain.currentStep = i;

            // 检查步骤执行条件
            if (step.condition && !this.evaluateCondition(step.condition, chain.context)) {
                console.log(`步骤 ${step.name} 条件不满足,跳过`);
                continue;
            }

            // 执行步骤
            const result = await this.executeStep(deviceId, step, chain.context);
            chain.results.push(result);

            // 更新上下文
            if (result.data) {
                chain.context = { ...chain.context, ...result.data };
            }

            // 检查是否失败
            if (!result.success && step.critical) {
                chain.status = 'failed';
                break;
            }

            // 步骤间延迟
            if (step.delay) {
                await this.sleep(step.delay);
            }
        }

        chain.status = chain.status === 'running' ? 'completed' : chain.status;
        this.activeChains.delete(chainId);

        return chain;
    }

    async executeStep(deviceId, step, context) {
        switch (step.type) {
            case 'open_app':
                return await this.deviceService.sendCommand(deviceId, 'open_app', {
                    packageName: step.params.packageName
                });

            case 'swipe_video':
                return await this.deviceService.sendCommand(deviceId, 'swipe', {
                    direction: step.params.direction || 'up'
                });

            case 'extract_info':
                return await this.deviceService.sendCommand(deviceId, 'extract_info', step.params);

            case 'like_video':
                return await this.deviceService.sendCommand(deviceId, 'like', step.params);

            default:
                return {
                    success: false,
                    error: `未知步骤类型: ${step.type}`
                };
        }
    }

    evaluateCondition(condition, context) {
        // 简单的条件求值,可根据需要扩展
        try {
            // 例如: "context.videoInfo.likes > 100"
            const expr = condition.replace(/context\\./g, 'context.');
            // 实际实现需要更安全的求值器
            return true; // 简化实现
        } catch (error) {
            console.error('条件求值错误:', error);
            return false;
        }
    }

    sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

📈 下一步扩展建议

  1. 添加数据库:当设备超过20台时,考虑添加SQLite或PostgreSQL
  1. 实现任务链编辑器:基于之前提供的组件
  1. 添加用户认证:JWT token验证
  1. 完善日志系统:集成Winston进行结构化日志
  1. 添加监控面板:实时图表显示设备状态
这个完整框架已经包含了:
  • ✅ 前后端完整项目结构
  • ✅ WebSocket实时通信
  • ✅ 设备状态管理
  • ✅ 响应式前端界面
  • ✅ 错误处理和日志
  • ✅ 易于扩展的架构
你现在可以直接运行这个系统,然后在上面逐步添加你的业务逻辑。需要我详细解释某个特定部分,或者添加其他功能模块吗?
代码太多复杂了 我要慢慢啃 每行去做注释吧

1215

现在已经对系统的架构有了初步认知 经过一系列修改目前已经支持通过下面的路由发送单条指令: socket.on('control_device', ({ deviceId, command, params }) => {)}
后面就是实现 任务调度器任务执行器 两个模块了
任务调度器在收到前端的开始运行命令后决定执行哪个 任务链 任务执行器则 负责执行对应的任务链

© Dominic Hodpel 2022 - 2026