3、食品包装控制系统 - /自动化与控制组件/food-packaging-control

发布于:2025-05-09 ⋅ 阅读:(13) ⋅ 点赞:(0)

76个工业组件库示例汇总

食品包装线控制系统

这是一个用于食品包装线控制系统的自定义组件,提供了食品包装生产线的可视化监控与控制界面。组件采用工业风格设计,包含生产流程控制、实时数据监控和逻辑编程三个主要功能区域。

功能特点

  1. 工业风格UI设计:深色主题,高对比度,符合工业控制系统的视觉风格
  2. 生产流程可视化:直观展示从上料到码垛的完整包装生产线工艺流程
  3. 实时数据监控:支持产量统计、质量数据和效率分析等多种数据可视化
  4. 逻辑控制编程:提供可视化编程、代码编辑和时序图三种逻辑开发方式
  5. 灵活的配置选项:可调整生产速度、包装规格等关键参数
  6. 告警系统:实时显示系统告警信息,支持告警确认和处理
  7. 系统状态监控:展示CPU负载、内存使用和通信状态等系统指标
  8. 响应式设计:适应不同屏幕尺寸,确保在各种设备上正常显示

主要区域说明

组件包含以下主要功能区域:

  1. 顶部控制栏:显示系统名称、状态和基本控制按钮(启动、停止、紧急停止)
  2. 生产流程控制区
    • 流程可视化:展示6个工站(上料、称重、包装、贴标、检测、码垛)的状态和连接
    • 生产参数控制:提供速度、包装规格和批次号等参数调整
  3. 实时数据监控区
    • 数据图表:多种图表类型,展示产量、质量和效率数据
    • 关键指标卡片:总产量、合格率、设备效率和运行时间等核心指标
  4. 逻辑编程控制区
    • 可视化编程:拖拽式逻辑流程创建
    • 代码编辑:支持梯形图、顺序功能图和结构化文本三种PLC编程语言
    • 时序图:工站操作的时序关系可视化
  5. 底部状态栏:显示告警信息、系统资源使用情况和当前时间

自定义选项

可以通过修改代码自定义以下内容:

  • 颜色主题:在CSS中修改:root中的颜色变量
  • 工站配置:在HTML的process-line区域添加或修改工站
  • 图表类型:在JavaScript的updateChart函数中修改图表样式和数据
  • 告警阈值:在JavaScript的checkAlarms函数中调整告警触发条件
  • 逻辑编程界面:修改工具箱中的逻辑元件和操作类型

连接实际设备

组件目前使用模拟数据进行演示。要连接实际的生产线设备,需要:

  1. 替换JavaScript中的数据模拟函数,连接到实际的数据源
  2. 调整控制按钮的事件处理函数,使其发送实际的控制命令
  3. 实现数据持久化存储,保存历史数据和生产记录

项目结构

在这里插入图片描述

效果展示

在这里插入图片描述

源码

index.html



<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>食品包装线控制系统</title>
  <link rel="stylesheet" href="styles.css">
  
</head>
<body>
  <div id="food-packaging-control">
    <!-- 顶部控制栏 -->
    <div class="control-header">
      <div class="logo-section">
        <div class="system-logo">食品包装线控制系统</div>
        <div class="system-version">v1.0</div>
      </div>
      <div class="control-status">
        <div class="status-item">
          <span class="status-label">系统状态:</span>
          <span class="status-value" id="system-status">运行中</span>
          <div class="status-indicator running"></div>
        </div>
        <div class="status-item">
          <span class="status-label">当前产量:</span>
          <span class="status-value" id="current-output">1,245/小时</span>
        </div>
        <div class="control-actions">
          <button class="control-btn start-btn" id="start-system">启动系统</button>
          <button class="control-btn stop-btn" id="stop-system">停止系统</button>
          <button class="control-btn emergency-btn" id="emergency-stop">紧急停止</button>
        </div>
      </div>
    </div>
  
    <!-- 主内容区域 -->
    <div class="main-content">
      <!-- 左侧:流程控制区 -->
      <div class="panel process-panel">
        <div class="panel-header">
          <h3>生产流程控制</h3>
          <div class="panel-actions">
            <button class="panel-btn" id="process-settings" title="流程设置">
              <i class="btn-icon"></i>
            </button>
            <button class="panel-btn" id="process-expand" title="展开视图">
              <i class="btn-icon"></i>
            </button>
          </div>
        </div>
        <div class="panel-body">
          <div class="process-visualization" id="process-visual">
            <!-- 包装流程可视化区域 -->
            <div class="process-line">
              <div class="process-station" id="station-1">
                <div class="station-icon feeding"></div>
                <div class="station-label">上料站</div>
                <div class="station-status active" id="station-1-status"></div>
              </div>
              <div class="process-connection">
                <div class="process-flow" id="flow-1-2"></div>
              </div>
              <div class="process-station" id="station-2">
                <div class="station-icon weighing"></div>
                <div class="station-label">称重站</div>
                <div class="station-status active" id="station-2-status"></div>
              </div>
              <div class="process-connection">
                <div class="process-flow" id="flow-2-3"></div>
              </div>
              <div class="process-station" id="station-3">
                <div class="station-icon packaging"></div>
                <div class="station-label">包装站</div>
                <div class="station-status active" id="station-3-status"></div>
              </div>
              <div class="process-connection">
                <div class="process-flow" id="flow-3-4"></div>
              </div>
              <div class="process-station" id="station-4">
                <div class="station-icon labeling"></div>
                <div class="station-label">贴标站</div>
                <div class="station-status active" id="station-4-status"></div>
              </div>
              <div class="process-connection">
                <div class="process-flow" id="flow-4-5"></div>
              </div>
              <div class="process-station" id="station-5">
                <div class="station-icon inspection"></div>
                <div class="station-label">检测站</div>
                <div class="station-status active" id="station-5-status"></div>
              </div>
              <div class="process-connection">
                <div class="process-flow" id="flow-5-6"></div>
              </div>
              <div class="process-station" id="station-6">
                <div class="station-icon palletizing"></div>
                <div class="station-label">码垛站</div>
                <div class="station-status active" id="station-6-status"></div>
              </div>
            </div>
          </div>
          <div class="process-controls">
            <div class="control-group">
              <div class="control-label">生产速度:</div>
              <div class="control-input">
                <input type="range" id="speed-control" min="50" max="150" value="100">
                <span id="speed-value">100%</span>
              </div>
            </div>
            <div class="control-group">
              <div class="control-label">包装规格:</div>
              <div class="control-input">
                <select id="package-type">
                  <option value="small">小包装 (100g)</option>
                  <option value="medium" selected>中包装 (250g)</option>
                  <option value="large">大包装 (500g)</option>
                  <option value="bulk">散装 (1kg)</option>
                </select>
              </div>
            </div>
            <div class="control-group">
              <div class="control-label">批次号:</div>
              <div class="control-input">
                <input type="text" id="batch-number" value="B202504091">
              </div>
            </div>
          </div>
        </div>
      </div>
  
      <!-- 中间:实时数据与监控 -->
      <div class="panel monitoring-panel">
        <div class="panel-header">
          <h3>实时数据监控</h3>
          <div class="panel-actions">
            <select id="chart-selector">
              <option value="production">产量统计</option>
              <option value="quality">质量数据</option>
              <option value="efficiency">效率分析</option>
            </select>
            <button class="panel-btn" id="export-data" title="导出数据">
              <i class="btn-icon"></i>
            </button>
          </div>
        </div>
        <div class="panel-body">
          <div class="chart-container">
            <div class="chart-header">
              <span id="chart-title">当日产量数据</span>
              <div class="chart-legend">
                <div class="legend-item">
                  <span class="legend-color" style="background-color: #2196F3;"></span>
                  <span class="legend-text">实际产量</span>
                </div>
                <div class="legend-item">
                  <span class="legend-color" style="background-color: #4CAF50;"></span>
                  <span class="legend-text">目标产量</span>
                </div>
                <div class="legend-item">
                  <span class="legend-color" style="background-color: #FF5722;"></span>
                  <span class="legend-text">不良品率</span>
                </div>
              </div>
            </div>
            <div class="chart-wrapper" id="chart-area">
              <!-- 图表将由JavaScript渲染 -->
            </div>
          </div>
          
          <div class="monitor-grid">
            <div class="monitor-card">
              <div class="card-label">总产量</div>
              <div class="card-value" id="total-output">24,589</div>
              <div class="card-unit">/</div>
            </div>
            <div class="monitor-card">
              <div class="card-label">合格率</div>
              <div class="card-value" id="quality-rate">99.7%</div>
              <div class="card-trend positive">0.2%</div>
            </div>
            <div class="monitor-card">
              <div class="card-label">设备效率</div>
              <div class="card-value" id="equipment-efficiency">94.3%</div>
              <div class="card-trend positive">1.5%</div>
            </div>
            <div class="monitor-card">
              <div class="card-label">运行时间</div>
              <div class="card-value" id="running-time">06:42:15</div>
              <div class="card-unit">::</div>
            </div>
          </div>
        </div>
      </div>
  
      <!-- 右侧:逻辑编程区 -->
      <div class="panel logic-panel">
        <div class="panel-header">
          <h3>逻辑控制编程</h3>
          <div class="panel-actions">
            <button class="panel-btn" id="new-logic" title="新建">
              <i class="btn-icon">+</i>
            </button>
            <button class="panel-btn" id="save-logic" title="保存">
              <i class="btn-icon"></i>
            </button>
            <button class="panel-btn" id="deploy-logic" title="部署">
              <i class="btn-icon"></i>
            </button>
          </div>
        </div>
        <div class="panel-body">
          <div class="tab-header">
            <div class="tab active" data-tab="visual-programming">可视化编程</div>
            <div class="tab" data-tab="code-editor">代码编辑</div>
            <div class="tab" data-tab="sequence">时序图</div>
          </div>
          <div class="tab-content">
            <div class="tab-pane active" id="visual-programming-pane">
              <div class="logic-toolbox">
                <div class="toolbox-section">
                  <div class="toolbox-title">控制元件</div>
                  <div class="toolbox-items">
                    <div class="logic-item" draggable="true" data-type="start">开始</div>
                    <div class="logic-item" draggable="true" data-type="decision">判断</div>
                    <div class="logic-item" draggable="true" data-type="action">动作</div>
                    <div class="logic-item" draggable="true" data-type="delay">延时</div>
                    <div class="logic-item" draggable="true" data-type="parallel">并行</div>
                    <div class="logic-item" draggable="true" data-type="end">结束</div>
                  </div>
                </div>
                <div class="toolbox-section">
                  <div class="toolbox-title">工站操作</div>
                  <div class="toolbox-items">
                    <div class="logic-item" draggable="true" data-type="feeding">上料</div>
                    <div class="logic-item" draggable="true" data-type="weighing">称重</div>
                    <div class="logic-item" draggable="true" data-type="packaging">包装</div>
                    <div class="logic-item" draggable="true" data-type="labeling">贴标</div>
                    <div class="logic-item" draggable="true" data-type="inspection">检测</div>
                    <div class="logic-item" draggable="true" data-type="palletizing">码垛</div>
                  </div>
                </div>
              </div>
              <div class="logic-canvas" id="logic-canvas">
                <!-- 逻辑流程图将由JavaScript渲染 -->
                <div class="placeholder-text">拖放控制元件到此区域创建逻辑流程</div>
                <div class="workflow-container" id="workflow-container">
                  <!-- 工作流将在这里动态创建 -->
                </div>
              </div>
            </div>
            <div class="tab-pane" id="code-editor-pane">
              <div class="editor-toolbar">
                <select id="language-selector">
                  <option value="ladder">梯形图</option>
                  <option value="sfc">顺序功能图</option>
                  <option value="st">结构化文本</option>
                </select>
                <button class="editor-btn" id="check-syntax">检查语法</button>
                <button class="editor-btn" id="format-code">格式化</button>
              </div>
              <div class="code-editor" id="code-editor">
                <pre class="code-content" id="code-content">
  // 食品包装线控制逻辑
  // 以下为示例梯形图代码
  
  PROGRAM PackagingControl
  VAR
    StartButton AT %I0.0: BOOL;
    StopButton AT %I0.1: BOOL;
    EmergencyStop AT %I0.2: BOOL;
    ConveyorRunning AT %Q0.0: BOOL;
    FeedingSystem AT %Q0.1: BOOL;
    WeighingSystem AT %Q0.2: BOOL;
    PackagingSystem AT %Q0.3: BOOL;
    LabelingSystem AT %Q0.4: BOOL;
    InspectionSystem AT %Q0.5: BOOL;
    PalletizingSystem AT %Q0.6: BOOL;
    SystemRunning: BOOL;
    ProductDetected AT %I0.3: BOOL;
    WeightOK AT %I0.4: BOOL;
    PackageSealed AT %I0.5: BOOL;
    LabelApplied AT %I0.6: BOOL;
    QualityCheck AT %I0.7: BOOL;
  END_VAR
  
  // 主控制逻辑
  SystemRunning := StartButton AND NOT StopButton AND NOT EmergencyStop;
  ConveyorRunning := SystemRunning;
  
  // 各工站控制逻辑
  FeedingSystem := SystemRunning AND (FeedingSystem OR NOT WeighingSystem);
  WeighingSystem := SystemRunning AND ProductDetected AND WeightOK;
  PackagingSystem := SystemRunning AND WeighingSystem AND WeightOK;
  LabelingSystem := SystemRunning AND PackageSealed;
  InspectionSystem := SystemRunning AND LabelApplied;
  PalletizingSystem := SystemRunning AND QualityCheck;
  
  END_PROGRAM
                </pre>
              </div>
            </div>
            <div class="tab-pane" id="sequence-pane">
              <div class="sequence-diagram" id="sequence-diagram">
                <!-- 时序图将由JavaScript渲染 -->
                <div class="placeholder-text">选择工站查看详细时序图</div>
              </div>
              <div class="sequence-controls">
                <div class="sequence-station-selector">
                  <label for="station-selector">选择工站:</label>
                  <select id="station-selector">
                    <option value="all">整体流程</option>
                    <option value="station-1">上料站</option>
                    <option value="station-2">称重站</option>
                    <option value="station-3">包装站</option>
                    <option value="station-4">贴标站</option>
                    <option value="station-5">检测站</option>
                    <option value="station-6">码垛站</option>
                  </select>
                </div>
                <div class="sequence-time-scale">
                  <label for="time-scale">时间尺度:</label>
                  <select id="time-scale">
                    <option value="1x">1x (实时)</option>
                    <option value="2x">2x (加速)</option>
                    <option value="0.5x">0.5x (减速)</option>
                  </select>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  
    <!-- 底部状态栏 -->
    <div class="footer-bar">
      <div class="alarm-section">
        <div class="alarm-icon" id="alarm-icon"></div>
        <div class="alarm-count" id="alarm-count">0</div>
        <div class="alarm-message" id="current-alarm">无告警信息</div>
      </div>
      <div class="system-metrics">
        <div class="metric">
          <span class="metric-label">CPU负载:</span>
          <span class="metric-value" id="cpu-load">32%</span>
        </div>
        <div class="metric">
          <span class="metric-label">内存使用:</span>
          <span class="metric-value" id="memory-usage">1.2GB/4GB</span>
        </div>
        <div class="metric">
          <span class="metric-label">通信状态:</span>
          <span class="metric-value connected" id="comm-status">已连接</span>
        </div>
      </div>
      <div class="system-time" id="system-time">2025-04-09 08:51:22</div>
    </div>
  
    <!-- 告警弹窗 -->
    <div class="alarm-modal" id="alarm-modal">
      <div class="alarm-modal-header">
        <div class="alarm-modal-title">系统告警</div>
        <div class="alarm-modal-close" id="close-alarm-modal">×</div>
      </div>
      <div class="alarm-modal-body">
        <div class="alarm-list" id="alarm-list">
          <!-- 告警列表将由JavaScript动态生成 -->
        </div>
      </div>
      <div class="alarm-modal-footer">
        <button class="alarm-btn" id="acknowledge-all">确认所有</button>
        <button class="alarm-btn" id="close-modal">关闭</button>
      </div>
    </div>
  </div> 
    <script src="script.js"></script>
</body>
</html> 

styles.css

/* 食品包装线控制系统 - 样式表 */
:root {
  /* 颜色变量 */
  --primary-dark: #1a2b42;  /* 主要深色背景 */
  --primary-medium: #253952; /* 次要深色背景 */
  --primary-light: #2d4263;  /* 浅色背景 */
  --accent-blue: #0288d1;    /* 蓝色强调 */
  --accent-green: #2e7d32;   /* 绿色强调 */
  --accent-red: #d32f2f;     /* 红色强调/告警 */
  --accent-orange: #f57c00;  /* 橙色强调/警告 */
  --text-primary: #ffffff;   /* 主要文本 */
  --text-secondary: #b0bec5; /* 次要文本 */
  --border-color: #37474f;   /* 边框颜色 */
  --hover-color: rgba(255, 255, 255, 0.08); /* 悬停效果 */
  
  /* 尺寸变量 */
  --header-height: 60px;
  --footer-height: 40px;
  --panel-gap: 12px;
  --border-radius: 4px;
}

/* 基础样式 */
#food-packaging-control {
  font-family: 'Roboto', 'Arial', sans-serif;
  color: var(--text-primary);
  background-color: var(--primary-dark);
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  user-select: none;
}

#food-packaging-control * {
  box-sizing: border-box;
}

/* 顶部控制栏 */
.control-header {
  height: var(--header-height);
  background-color: var(--primary-medium);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  z-index: 10;
}

.logo-section {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.system-logo {
  font-size: 1.2rem;
  font-weight: bold;
  letter-spacing: 0.5px;
}

.system-version {
  font-size: 0.7rem;
  color: var(--text-secondary);
}

.control-status {
  display: flex;
  align-items: center;
  gap: 24px;
}

.status-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.status-label {
  color: var(--text-secondary);
  font-size: 0.85rem;
}

.status-value {
  font-weight: bold;
  font-size: 0.9rem;
}

.status-indicator {
  width: 10px;
  height: 10px;
  border-radius: 50%;
}

.status-indicator.running {
  background-color: var(--accent-green);
  box-shadow: 0 0 8px var(--accent-green);
}

.status-indicator.warning {
  background-color: var(--accent-orange);
  box-shadow: 0 0 8px var(--accent-orange);
}

.status-indicator.error {
  background-color: var(--accent-red);
  box-shadow: 0 0 8px var(--accent-red);
}

.status-indicator.idle {
  background-color: var(--text-secondary);
}

.control-actions {
  display: flex;
  gap: 8px;
}

.control-btn {
  padding: 8px 12px;
  border: none;
  border-radius: var(--border-radius);
  font-weight: bold;
  font-size: 0.85rem;
  cursor: pointer;
  transition: all 0.2s;
}

.start-btn {
  background-color: var(--accent-green);
  color: white;
}

.start-btn:hover {
  background-color: #388e3c;
}

.stop-btn {
  background-color: #455a64;
  color: white;
}

.stop-btn:hover {
  background-color: #546e7a;
}

.emergency-btn {
  background-color: var(--accent-red);
  color: white;
}

.emergency-btn:hover {
  background-color: #e53935;
}

/* 主内容区域 */
.main-content {
  flex: 1;
  display: flex;
  gap: var(--panel-gap);
  padding: var(--panel-gap);
  height: calc(100vh - var(--header-height) - var(--footer-height));
  overflow: hidden;
}

/* 面板通用样式 */
.panel {
  background-color: var(--primary-medium);
  border-radius: var(--border-radius);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.process-panel {
  flex: 1;
}

.monitoring-panel {
  flex: 1.5;
}

.logic-panel {
  flex: 1.5;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background-color: var(--primary-light);
  border-bottom: 1px solid var(--border-color);
}

.panel-header h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0.5px;
}

.panel-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.panel-btn {
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 4px;
  background-color: var(--primary-medium);
  color: var(--text-primary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.2s;
}

.panel-btn:hover {
  background-color: var(--hover-color);
}

.btn-icon {
  font-style: normal;
}

.panel-body {
  flex: 1;
  overflow: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* 流程控制面板 */
.process-visualization {
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  padding: 16px;
  min-height: 180px;
  overflow: auto;
}

.process-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 0;
}

.process-station {
  position: relative;
  width: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  z-index: 2;
}

.station-icon {
  width: 50px;
  height: 50px;
  border-radius: 8px;
  background-color: var(--primary-light);
  border: 2px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  transition: all 0.3s;
}

.station-icon::before {
  font-family: Arial, sans-serif;
  font-size: 24px;
  font-weight: bold;
}

.station-icon.feeding::before { content: "F"; color: #64b5f6; }
.station-icon.weighing::before { content: "W"; color: #81c784; }
.station-icon.packaging::before { content: "P"; color: #ffb74d; }
.station-icon.labeling::before { content: "L"; color: #ba68c8; }
.station-icon.inspection::before { content: "I"; color: #4fc3f7; }
.station-icon.palletizing::before { content: "S"; color: #f06292; }

.station-label {
  font-size: 0.8rem;
  text-align: center;
}

.station-status {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  top: -5px;
  right: 12px;
}

.station-status.active {
  background-color: var(--accent-green);
  box-shadow: 0 0 5px var(--accent-green);
}

.station-status.warning {
  background-color: var(--accent-orange);
  box-shadow: 0 0 5px var(--accent-orange);
}

.station-status.error {
  background-color: var(--accent-red);
  box-shadow: 0 0 5px var(--accent-red);
}

.station-status.idle {
  background-color: var(--text-secondary);
}

.process-connection {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  z-index: 1;
}

.process-flow {
  height: 4px;
  background-color: var(--accent-blue);
  width: 100%;
  position: relative;
  overflow: hidden;
}

.process-flow.active::after {
  content: '';
  position: absolute;
  top: 0;
  left: -20%;
  height: 100%;
  width: 20%;
  background-color: rgba(255, 255, 255, 0.7);
  animation: flow 1.5s linear infinite;
}

@keyframes flow {
  0% { left: -20%; }
  100% { left: 100%; }
}

.process-controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 16px;
}

.control-group {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.control-label {
  font-size: 0.85rem;
  color: var(--text-secondary);
}

.control-input {
  flex: 1;
  max-width: 200px;
  display: flex;
  align-items: center;
  gap: 8px;
}

input[type="range"] {
  flex: 1;
  cursor: pointer;
}

input[type="text"], select {
  background-color: var(--primary-dark);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  color: var(--text-primary);
  padding: 6px 10px;
  width: 100%;
  font-size: 0.85rem;
}

select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23b0bec5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  padding-right: 30px;
}

/* 监控面板 */
.chart-container {
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  padding: 16px;
  min-height: 240px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

#chart-title {
  font-weight: 500;
  font-size: 0.9rem;
}

.chart-legend {
  display: flex;
  gap: 12px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8rem;
}

.legend-color {
  width: 12px;
  height: 12px;
  border-radius: 2px;
}

.chart-wrapper {
  flex: 1;
  min-height: 180px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.monitor-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

.monitor-card {
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.card-label {
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.card-value {
  font-size: 1.5rem;
  font-weight: bold;
  line-height: 1;
  margin-bottom: 4px;
}

.card-unit {
  font-size: 0.75rem;
  color: var(--text-secondary);
}

.card-trend {
  font-size: 0.75rem;
  font-weight: 500;
}

.card-trend.positive {
  color: var(--accent-green);
}

.card-trend.negative {
  color: var(--accent-red);
}

/* 逻辑编程面板 */
.tab-header {
  display: flex;
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 16px;
  margin-top: -8px;
}

.tab {
  padding: 8px 16px;
  font-size: 0.85rem;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.2s;
}

.tab:hover {
  background-color: var(--hover-color);
}

.tab.active {
  border-bottom: 2px solid var(--accent-blue);
  color: var(--accent-blue);
}

.tab-content {
  flex: 1;
  overflow: hidden;
  display: flex;
}

.tab-pane {
  flex: 1;
  display: none;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.tab-pane.active {
  display: flex;
}

/* 可视化编程区域 */
.logic-toolbox {
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  padding: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
}

.toolbox-section {
  flex: 1;
  min-width: 150px;
}

.toolbox-title {
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.toolbox-items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.logic-item {
  background-color: var(--primary-light);
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius);
  padding: 6px 10px;
  font-size: 0.85rem;
  cursor: grab;
  transition: all 0.2s;
}

.logic-item:hover {
  background-color: var(--hover-color);
  border-color: var(--accent-blue);
}

.logic-canvas {
  flex: 1;
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  overflow: auto;
  position: relative;
  min-height: 250px;
}

.placeholder-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: var(--text-secondary);
  font-size: 0.9rem;
  text-align: center;
  opacity: 0.7;
}

.workflow-container {
  padding: 20px;
  min-height: 100%;
  position: relative;
}

/* 代码编辑区 */
.editor-toolbar {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.editor-btn {
  padding: 6px 12px;
  font-size: 0.85rem;
  border: none;
  background-color: var(--primary-dark);
  color: var(--text-primary);
  border-radius: var(--border-radius);
  cursor: pointer;
  transition: all 0.2s;
}

.editor-btn:hover {
  background-color: var(--hover-color);
}

.code-editor {
  flex: 1;
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  overflow: auto;
}

.code-content {
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 0.9rem;
  line-height: 1.5;
  padding: 12px;
  margin: 0;
  color: var(--text-primary);
  overflow: auto;
  tab-size: 4;
}

/* 时序图区域 */
.sequence-diagram {
  flex: 1;
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
  overflow: auto;
  position: relative;
  min-height: 250px;
}

.sequence-controls {
  display: flex;
  justify-content: space-between;
  margin-top: 12px;
  padding: 8px 12px;
  background-color: var(--primary-dark);
  border-radius: var(--border-radius);
}

.sequence-station-selector,
.sequence-time-scale {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
}

.sequence-station-selector label,
.sequence-time-scale label {
  color: var(--text-secondary);
}

.sequence-station-selector select,
.sequence-time-scale select {
  width: auto;
}

/* 底部状态栏 */
.footer-bar {
  height: var(--footer-height);
  background-color: var(--primary-medium);
  border-top: 1px solid var(--border-color);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 16px;
  font-size: 0.8rem;
}

.alarm-section {
  display: flex;
  align-items: center;
  gap: 8px;
}

.alarm-icon {
  color: var(--accent-orange);
  font-size: 1rem;
}

.alarm-icon.active {
  animation: blink 1s infinite;
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.alarm-count {
  background-color: var(--accent-red);
  color: white;
  border-radius: 10px;
  padding: 0 6px;
  min-width: 18px;
  font-size: 0.7rem;
  text-align: center;
  display: inline-block;
}

.alarm-message {
  color: var(--text-secondary);
}

.system-metrics {
  display: flex;
  gap: 16px;
}

.metric {
  display: flex;
  align-items: center;
  gap: 4px;
}

.metric-label {
  color: var(--text-secondary);
}

.metric-value {
  font-weight: 500;
}

.connected {
  color: var(--accent-green);
}

.disconnected {
  color: var(--accent-red);
}

.system-time {
  color: var(--text-secondary);
}

/* 告警弹窗 */
.alarm-modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: var(--primary-medium);
  border-radius: var(--border-radius);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
  z-index: 1000;
  width: 500px;
  max-width: 90vw;
  max-height: 80vh;
  display: none;
  flex-direction: column;
}

.alarm-modal.show {
  display: flex;
}

.alarm-modal-header {
  padding: 12px 16px;
  background-color: var(--primary-light);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.alarm-modal-title {
  font-weight: 500;
  font-size: 1rem;
}

.alarm-modal-close {
  font-size: 1.2rem;
  cursor: pointer;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

.alarm-modal-close:hover {
  background-color: var(--hover-color);
}

.alarm-modal-body {
  padding: 16px;
  overflow-y: auto;
  flex: 1;
}

.alarm-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.alarm-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 8px;
  border-radius: var(--border-radius);
  background-color: var(--primary-dark);
}

.alarm-item-icon {
  font-size: 1.2rem;
  margin-top: 2px;
}

.alarm-item-icon.critical {
  color: var(--accent-red);
}

.alarm-item-icon.warning {
  color: var(--accent-orange);
}

.alarm-item-icon.info {
  color: var(--accent-blue);
}

.alarm-item-content {
  flex: 1;
}

.alarm-item-title {
  font-weight: 500;
  font-size: 0.9rem;
}

.alarm-item-desc {
  font-size: 0.8rem;
  color: var(--text-secondary);
  margin-top: 4px;
}

.alarm-item-time {
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-top: 4px;
}

.alarm-modal-footer {
  padding: 12px 16px;
  border-top: 1px solid var(--border-color);
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.alarm-btn {
  padding: 6px 12px;
  border: none;
  border-radius: var(--border-radius);
  font-size: 0.85rem;
  cursor: pointer;
  background-color: var(--primary-dark);
  color: var(--text-primary);
  transition: all 0.2s;
}

.alarm-btn:hover {
  background-color: var(--hover-color);
}

/* 响应式布局 */
@media (max-width: 1200px) {
  .main-content {
    flex-direction: column;
    overflow-y: auto;
    height: calc(100vh - var(--header-height) - var(--footer-height));
  }
  
  .process-panel, .monitoring-panel, .logic-panel {
    width: 100%;
    flex: none;
  }
  
  .panel {
    max-height: 600px;
  }
  
  .monitor-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .control-status {
    flex-wrap: wrap;
  }
}

@media (max-width: 768px) {
  .control-header {
    flex-direction: column;
    height: auto;
    padding: 12px;
    gap: 12px;
  }
  
  .logo-section {
    align-items: center;
  }
  
  .control-status {
    width: 100%;
    justify-content: center;
  }
  
  .footer-bar {
    flex-direction: column;
    height: auto;
    padding: 8px;
    gap: 8px;
    text-align: center;
  }
  
  .system-metrics {
    flex-wrap: wrap;
    justify-content: center;
  }
  
  .monitor-grid {
    grid-template-columns: 1fr;
  }
} 

script.js

/**
 * 食品包装线控制系统 - JavaScript控制逻辑
 * 本文件实现了食品包装线控制系统的各项功能,包括:
 * - 系统状态管理
 * - 工站控制和状态监控
 * - 实时数据可视化
 * - 逻辑编程界面交互
 * - 告警管理
 */

// 全局变量
let systemRunning = true;          // 系统运行状态
let productionSpeed = 100;         // 生产速度(%)
let currentPackageType = 'medium'; // 当前包装类型
let batchNumber = 'B202504091';    // 当前批次号
let runningTime = 0;               // 运行时间(秒)
let totalProduction = 24589;       // 总产量
let alarmCount = 0;                // 告警数量
let alarms = [];                   // 告警列表
let stationStatus = {              // 各工站状态
  'station-1': 'active',
  'station-2': 'active',
  'station-3': 'active',
  'station-4': 'active',
  'station-5': 'active',
  'station-6': 'active'
};
let flowStatus = {                 // 物料流状态
  'flow-1-2': true,
  'flow-2-3': true,
  'flow-3-4': true,
  'flow-4-5': true,
  'flow-5-6': true
};

// 计时器
let runningTimeInterval;
let dataUpdateInterval;
let chartUpdateInterval;
let flowAnimationInterval;
let systemMetricsInterval;

// 图表数据
let productionData = {
  labels: [...Array(12).keys()].map(i => `${8 + Math.floor(i/2)}:${i % 2 ? '30' : '00'}`),
  actual: [920, 1050, 1150, 1230, 1320, 1260, 1200, 1310, 1400, 1380, 1420, 1245],
  target: [1000, 1000, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400],
  defects: [2.1, 1.8, 1.9, 0.8, 0.5, 0.7, 0.9, 0.6, 0.4, 0.5, 0.3, 0.3]
};

let qualityData = {
  labels: ['100g', '250g', '500g', '1kg'],
  pass: [99.2, 99.7, 99.5, 99.1],
  weight: [99.5, 99.8, 99.6, 99.4],
  seal: [99.7, 99.9, 99.8, 99.5],
  label: [99.3, 99.6, 99.4, 99.2]
};

let efficiencyData = {
  labels: [...Array(8).keys()].map(i => `${i + 8}:00`),
  oee: [91.2, 92.5, 93.8, 94.2, 94.5, 94.7, 94.3, 93.6],
  uptime: [97.5, 98.2, 98.5, 98.7, 98.8, 98.5, 98.1, 97.8],
  performance: [94.5, 95.2, 96.1, 96.3, 96.5, 96.7, 96.3, 95.8]
};

// 工作流元素数据
let workflowElements = [];

/**
 * 初始化函数 - 页面加载完成后执行
 */
function initializeSystem() {
  // 绑定事件监听器
  bindEventListeners();
  
  // 启动系统模拟
  startSystemSimulation();
  
  // 初始化图表
  updateChart('production');
  
  // 初始化逻辑编程界面
  initializeLogicProgramming();
  
  // 更新系统时间
  updateSystemTime();
  
  console.log('食品包装线控制系统初始化完成');
}

/**
 * 绑定所有UI元素的事件监听器
 */
function bindEventListeners() {
  // 系统控制按钮
  document.getElementById('start-system').addEventListener('click', startSystem);
  document.getElementById('stop-system').addEventListener('click', stopSystem);
  document.getElementById('emergency-stop').addEventListener('click', emergencyStop);
  
  // 流程控制面板
  document.getElementById('process-settings').addEventListener('click', showProcessSettings);
  document.getElementById('process-expand').addEventListener('click', expandProcessView);
  document.getElementById('speed-control').addEventListener('input', updateSpeed);
  document.getElementById('package-type').addEventListener('change', updatePackageType);
  document.getElementById('batch-number').addEventListener('change', updateBatchNumber);
  
  // 监控面板
  document.getElementById('chart-selector').addEventListener('change', (e) => updateChart(e.target.value));
  document.getElementById('export-data').addEventListener('click', exportMonitoringData);
  
  // 逻辑编程面板
  document.querySelectorAll('.tab').forEach(tab => {
    tab.addEventListener('click', switchProgrammingTab);
  });
  
  document.getElementById('new-logic').addEventListener('click', createNewLogic);
  document.getElementById('save-logic').addEventListener('click', saveLogic);
  document.getElementById('deploy-logic').addEventListener('click', deployLogic);
  
  document.querySelectorAll('.logic-item').forEach(item => {
    item.addEventListener('dragstart', handleDragStart);
  });
  
  document.getElementById('logic-canvas').addEventListener('dragover', handleDragOver);
  document.getElementById('logic-canvas').addEventListener('drop', handleDrop);
  
  document.getElementById('check-syntax').addEventListener('click', checkCodeSyntax);
  document.getElementById('format-code').addEventListener('click', formatCode);
  
  document.getElementById('station-selector').addEventListener('change', updateSequenceDiagram);
  
  // 告警相关
  document.getElementById('alarm-icon').addEventListener('click', showAlarmModal);
  document.getElementById('close-alarm-modal').addEventListener('click', hideAlarmModal);
  document.getElementById('close-modal').addEventListener('click', hideAlarmModal);
  document.getElementById('acknowledge-all').addEventListener('click', acknowledgeAllAlarms);
}

/**
 * 启动系统模拟
 */
function startSystemSimulation() {
  // 设置运行时间计时器
  runningTimeInterval = setInterval(updateRunningTime, 1000);
  
  // 设置数据更新计时器
  dataUpdateInterval = setInterval(updateRealTimeData, 2000);
  
  // 设置图表更新计时器
  chartUpdateInterval = setInterval(() => {
    if (document.getElementById('chart-selector').value === 'production') {
      updateProductionData();
      updateChart('production');
    }
  }, 10000);
  
  // 设置流动动画
  flowAnimationInterval = setInterval(updateFlowAnimation, 5000);
  
  // 设置系统指标更新
  systemMetricsInterval = setInterval(updateSystemMetrics, 3000);
}

/**
 * 停止系统模拟
 */
function stopSystemSimulation() {
  clearInterval(runningTimeInterval);
  clearInterval(dataUpdateInterval);
  clearInterval(chartUpdateInterval);
  clearInterval(flowAnimationInterval);
  clearInterval(systemMetricsInterval);
}

/**
 * 启动系统
 */
function startSystem() {
  if (!systemRunning) {
    systemRunning = true;
    document.getElementById('system-status').textContent = '运行中';
    document.querySelector('.status-indicator').className = 'status-indicator running';
    
    startSystemSimulation();
    
    // 更新各工站状态
    Object.keys(stationStatus).forEach(station => {
      stationStatus[station] = 'active';
      document.getElementById(station + '-status').className = 'station-status active';
    });
    
    // 更新流动状态
    Object.keys(flowStatus).forEach(flow => {
      flowStatus[flow] = true;
      document.getElementById(flow).className = 'process-flow active';
    });
    
    addAlarm('info', '系统已启动', '操作员启动了系统');
  }
}

/**
 * 停止系统
 */
function stopSystem() {
  if (systemRunning) {
    systemRunning = false;
    document.getElementById('system-status').textContent = '已停止';
    document.querySelector('.status-indicator').className = 'status-indicator idle';
    
    stopSystemSimulation();
    
    // 更新各工站状态
    Object.keys(stationStatus).forEach(station => {
      stationStatus[station] = 'idle';
      document.getElementById(station + '-status').className = 'station-status idle';
    });
    
    // 更新流动状态
    Object.keys(flowStatus).forEach(flow => {
      flowStatus[flow] = false;
      document.getElementById(flow).className = 'process-flow';
    });
    
    addAlarm('info', '系统已停止', '操作员停止了系统');
  }
}

/**
 * 紧急停止
 */
function emergencyStop() {
  systemRunning = false;
  document.getElementById('system-status').textContent = '紧急停止';
  document.querySelector('.status-indicator').className = 'status-indicator error';
  
  stopSystemSimulation();
  
  // 更新各工站状态
  Object.keys(stationStatus).forEach(station => {
    stationStatus[station] = 'error';
    document.getElementById(station + '-status').className = 'station-status error';
  });
  
  // 更新流动状态
  Object.keys(flowStatus).forEach(flow => {
    flowStatus[flow] = false;
    document.getElementById(flow).className = 'process-flow';
  });
  
  addAlarm('critical', '系统紧急停止', '触发紧急停止按钮');
}

/**
 * 显示流程设置
 */
function showProcessSettings() {
  // 此处可实现流程设置弹窗
  console.log('显示流程设置');
}

/**
 * 展开流程视图
 */
function expandProcessView() {
  // 此处可实现流程图的全屏展示
  console.log('展开流程视图');
}

/**
 * 更新速度设置
 */
function updateSpeed(event) {
  productionSpeed = event.target.value;
  document.getElementById('speed-value').textContent = productionSpeed + '%';
  console.log('生产速度已更新:', productionSpeed + '%');
}

/**
 * 更新包装类型
 */
function updatePackageType(event) {
  currentPackageType = event.target.value;
  console.log('包装规格已更新:', currentPackageType);
}

/**
 * 更新批次号
 */
function updateBatchNumber(event) {
  batchNumber = event.target.value;
  console.log('批次号已更新:', batchNumber);
}

/**
 * 导出监控数据
 */
function exportMonitoringData() {
  console.log('导出监控数据');
  // 此处可实现数据导出功能
}

/**
 * 更新图表显示
 */
function updateChart(chartType) {
  const chartArea = document.getElementById('chart-area');
  let chartTitle = '';
  
  // 清空图表区域
  chartArea.innerHTML = '';
  
  // 根据图表类型显示不同的图表
  switch(chartType) {
    case 'production':
      chartTitle = '当日产量数据';
      renderProductionChart(chartArea);
      break;
    case 'quality':
      chartTitle = '产品质量数据';
      renderQualityChart(chartArea);
      break;
    case 'efficiency':
      chartTitle = '生产效率分析';
      renderEfficiencyChart(chartArea);
      break;
  }
  
  document.getElementById('chart-title').textContent = chartTitle;
}

/**
 * 渲染产量图表
 */
function renderProductionChart(container) {
  try {
    // 尝试使用Chart.js绘制图表
    if (typeof Chart !== 'undefined') {
      const canvas = document.createElement('canvas');
      container.appendChild(canvas);
      
      new Chart(canvas, {
        type: 'line',
        data: {
          labels: productionData.labels,
          datasets: [
            {
              label: '实际产量',
              data: productionData.actual,
              borderColor: '#2196F3',
              backgroundColor: 'rgba(33, 150, 243, 0.1)',
              tension: 0.3,
              fill: true
            },
            {
              label: '目标产量',
              data: productionData.target,
              borderColor: '#4CAF50',
              backgroundColor: 'transparent',
              borderDash: [5, 5],
              tension: 0.1
            },
            {
              label: '不良品率(%)',
              data: productionData.defects,
              borderColor: '#FF5722',
              backgroundColor: 'transparent',
              yAxisID: 'y1'
            }
          ]
        },
        options: {
          scales: {
            y: {
              beginAtZero: false,
              title: {
                display: true,
                text: '产量 (件/小时)'
              }
            },
            y1: {
              position: 'right',
              beginAtZero: true,
              max: 5,
              title: {
                display: true,
                text: '不良品率 (%)'
              }
            }
          }
        }
      });
    } else {
      // 使用简单SVG绘制图表
      renderSimpleProductionChart(container);
    }
  } catch (error) {
    console.error('图表渲染失败:', error);
    renderSimpleProductionChart(container);
  }
}

/**
 * 渲染简单SVG产量图表(当Chart.js不可用时)
 */
function renderSimpleProductionChart(container) {
  const svgNS = "http://www.w3.org/2000/svg";
  const width = container.clientWidth;
  const height = 250;
  
  const svg = document.createElementNS(svgNS, "svg");
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  svg.style.backgroundColor = "var(--primary-dark)";
  
  const maxValue = Math.max(...productionData.actual, ...productionData.target);
  const xStep = width / (productionData.labels.length - 1);
  const yScale = (height - 40) / maxValue;
  
  // 绘制坐标轴
  const axis = document.createElementNS(svgNS, "path");
  axis.setAttribute("d", `M 30 10 V ${height - 30} H ${width - 10}`);
  axis.setAttribute("stroke", "var(--border-color)");
  axis.setAttribute("fill", "none");
  svg.appendChild(axis);
  
  // 绘制实际产量线
  const actualLine = document.createElementNS(svgNS, "path");
  let path = `M ${30} ${height - 30 - productionData.actual[0] * yScale}`;
  
  for (let i = 1; i < productionData.actual.length; i++) {
    path += ` L ${30 + i * xStep} ${height - 30 - productionData.actual[i] * yScale}`;
  }
  
  actualLine.setAttribute("d", path);
  actualLine.setAttribute("stroke", "#2196F3");
  actualLine.setAttribute("stroke-width", "2");
  actualLine.setAttribute("fill", "none");
  svg.appendChild(actualLine);
  
  // 绘制目标产量线(虚线)
  const targetLine = document.createElementNS(svgNS, "path");
  path = `M ${30} ${height - 30 - productionData.target[0] * yScale}`;
  
  for (let i = 1; i < productionData.target.length; i++) {
    path += ` L ${30 + i * xStep} ${height - 30 - productionData.target[i] * yScale}`;
  }
  
  targetLine.setAttribute("d", path);
  targetLine.setAttribute("stroke", "#4CAF50");
  targetLine.setAttribute("stroke-width", "2");
  targetLine.setAttribute("stroke-dasharray", "5,5");
  targetLine.setAttribute("fill", "none");
  svg.appendChild(targetLine);
  
  container.appendChild(svg);
}

/**
 * 渲染质量图表
 */
function renderQualityChart(container) {
  try {
    // 尝试使用Chart.js绘制图表
    if (typeof Chart !== 'undefined') {
      const canvas = document.createElement('canvas');
      container.appendChild(canvas);
      
      new Chart(canvas, {
        type: 'bar',
        data: {
          labels: qualityData.labels,
          datasets: [
            {
              label: '合格率',
              data: qualityData.pass,
              backgroundColor: '#4CAF50'
            },
            {
              label: '重量合格',
              data: qualityData.weight,
              backgroundColor: '#2196F3'
            },
            {
              label: '密封合格',
              data: qualityData.seal,
              backgroundColor: '#FF9800'
            },
            {
              label: '标签合格',
              data: qualityData.label,
              backgroundColor: '#9C27B0'
            }
          ]
        },
        options: {
          scales: {
            y: {
              min: 95,
              max: 100,
              title: {
                display: true,
                text: '合格率 (%)'
              }
            }
          }
        }
      });
    } else {
      // 使用简单SVG绘制图表
      renderSimpleQualityChart(container);
    }
  } catch (error) {
    console.error('图表渲染失败:', error);
    renderSimpleQualityChart(container);
  }
}

/**
 * 渲染简单SVG质量图表(当Chart.js不可用时)
 */
function renderSimpleQualityChart(container) {
  const svgNS = "http://www.w3.org/2000/svg";
  const width = container.clientWidth;
  const height = 250;
  
  const svg = document.createElementNS(svgNS, "svg");
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  svg.style.backgroundColor = "var(--primary-dark)";
  
  const barWidth = 15;
  const groupWidth = barWidth * 4 + 20;
  const xStep = width / (qualityData.labels.length + 1);
  const yScale = (height - 40) / 5; // 5% scale (95-100%)
  
  // 绘制坐标轴
  const axis = document.createElementNS(svgNS, "path");
  axis.setAttribute("d", `M 30 10 V ${height - 30} H ${width - 10}`);
  axis.setAttribute("stroke", "var(--border-color)");
  axis.setAttribute("fill", "none");
  svg.appendChild(axis);
  
  // 绘制柱状图
  const colors = ['#4CAF50', '#2196F3', '#FF9800', '#9C27B0'];
  
  for (let i = 0; i < qualityData.labels.length; i++) {
    const x = 50 + i * xStep;
    
    // 绘制4种不同质量数据的柱状图
    for (let j = 0; j < 4; j++) {
      const dataKey = ['pass', 'weight', 'seal', 'label'][j];
      const value = qualityData[dataKey][i];
      const barHeight = (value - 95) * yScale;
      
      const bar = document.createElementNS(svgNS, "rect");
      bar.setAttribute("x", x + j * (barWidth + 5));
      bar.setAttribute("y", height - 30 - barHeight);
      bar.setAttribute("width", barWidth);
      bar.setAttribute("height", barHeight);
      bar.setAttribute("fill", colors[j]);
      svg.appendChild(bar);
    }
    
    // 绘制标签
    const text = document.createElementNS(svgNS, "text");
    text.setAttribute("x", x + groupWidth / 2 - 15);
    text.setAttribute("y", height - 10);
    text.setAttribute("fill", "var(--text-secondary)");
    text.setAttribute("font-size", "12");
    text.textContent = qualityData.labels[i];
    svg.appendChild(text);
  }
  
  container.appendChild(svg);
}

/**
 * 渲染效率图表
 */
function renderEfficiencyChart(container) {
  try {
    // 尝试使用Chart.js绘制图表
    if (typeof Chart !== 'undefined') {
      const canvas = document.createElement('canvas');
      container.appendChild(canvas);
      
      new Chart(canvas, {
        type: 'line',
        data: {
          labels: efficiencyData.labels,
          datasets: [
            {
              label: 'OEE',
              data: efficiencyData.oee,
              borderColor: '#2196F3',
              backgroundColor: 'rgba(33, 150, 243, 0.1)',
              tension: 0.3,
              fill: true
            },
            {
              label: '运行时间',
              data: efficiencyData.uptime,
              borderColor: '#4CAF50',
              backgroundColor: 'transparent',
              tension: 0.3
            },
            {
              label: '性能效率',
              data: efficiencyData.performance,
              borderColor: '#FF9800',
              backgroundColor: 'transparent',
              tension: 0.3
            }
          ]
        },
        options: {
          scales: {
            y: {
              min: 85,
              max: 100,
              title: {
                display: true,
                text: '效率 (%)'
              }
            }
          }
        }
      });
    } else {
      // 使用简单SVG绘制图表
      renderSimpleEfficiencyChart(container);
    }
  } catch (error) {
    console.error('图表渲染失败:', error);
    renderSimpleEfficiencyChart(container);
  }
}

/**
 * 渲染简单SVG效率图表(当Chart.js不可用时)
 */
function renderSimpleEfficiencyChart(container) {
  const svgNS = "http://www.w3.org/2000/svg";
  const width = container.clientWidth;
  const height = 250;
  
  const svg = document.createElementNS(svgNS, "svg");
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  svg.style.backgroundColor = "var(--primary-dark)";
  
  const xStep = width / (efficiencyData.labels.length + 1);
  const yScale = (height - 40) / 15; // 15% scale (85-100%)
  
  // 绘制坐标轴
  const axis = document.createElementNS(svgNS, "path");
  axis.setAttribute("d", `M 30 10 V ${height - 30} H ${width - 10}`);
  axis.setAttribute("stroke", "var(--border-color)");
  axis.setAttribute("fill", "none");
  svg.appendChild(axis);
  
  // 绘制OEE线
  const oeeLine = document.createElementNS(svgNS, "path");
  let path = `M ${50} ${height - 30 - (efficiencyData.oee[0] - 85) * yScale}`;
  
  for (let i = 1; i < efficiencyData.oee.length; i++) {
    path += ` L ${50 + i * xStep} ${height - 30 - (efficiencyData.oee[i] - 85) * yScale}`;
  }
  
  oeeLine.setAttribute("d", path);
  oeeLine.setAttribute("stroke", "#2196F3");
  oeeLine.setAttribute("stroke-width", "2");
  oeeLine.setAttribute("fill", "none");
  svg.appendChild(oeeLine);
  
  // 绘制运行时间线
  const uptimeLine = document.createElementNS(svgNS, "path");
  path = `M ${50} ${height - 30 - (efficiencyData.uptime[0] - 85) * yScale}`;
  
  for (let i = 1; i < efficiencyData.uptime.length; i++) {
    path += ` L ${50 + i * xStep} ${height - 30 - (efficiencyData.uptime[i] - 85) * yScale}`;
  }
  
  uptimeLine.setAttribute("d", path);
  uptimeLine.setAttribute("stroke", "#4CAF50");
  uptimeLine.setAttribute("stroke-width", "2");
  uptimeLine.setAttribute("fill", "none");
  svg.appendChild(uptimeLine);
  
  // 绘制性能效率线
  const perfLine = document.createElementNS(svgNS, "path");
  path = `M ${50} ${height - 30 - (efficiencyData.performance[0] - 85) * yScale}`;
  
  for (let i = 1; i < efficiencyData.performance.length; i++) {
    path += ` L ${50 + i * xStep} ${height - 30 - (efficiencyData.performance[i] - 85) * yScale}`;
  }
  
  perfLine.setAttribute("d", path);
  perfLine.setAttribute("stroke", "#FF9800");
  perfLine.setAttribute("stroke-width", "2");
  perfLine.setAttribute("fill", "none");
  svg.appendChild(perfLine);
  
  container.appendChild(svg);
}

/**
 * 更新实时数据
 */
function updateRealTimeData() {
  if (!systemRunning) return;
  
  // 模拟产量数据
  const hourlyRate = Math.floor(1200 * (productionSpeed / 100) * (Math.random() * 0.2 + 0.9));
  document.getElementById('current-output').textContent = hourlyRate.toLocaleString() + ' 件/小时';
  
  // 更新各工站状态
  updateStationStatus();
  
  // 模拟产品质量数据
  const qualityRate = (99.5 + Math.random() * 0.5).toFixed(1);
  document.getElementById('quality-rate').textContent = qualityRate + '%';
  
  const qualityTrend = Math.random() > 0.7 ? -0.1 : 0.2;
  const trendEl = document.getElementById('quality-rate').nextElementSibling;
  trendEl.textContent = (qualityTrend >= 0 ? '↑' : '↓') + Math.abs(qualityTrend).toFixed(1) + '%';
  trendEl.className = 'card-trend ' + (qualityTrend >= 0 ? 'positive' : 'negative');
  
  // 模拟设备效率数据
  const efficiency = (94.0 + Math.random() * 1.0).toFixed(1);
  document.getElementById('equipment-efficiency').textContent = efficiency + '%';
  
  const efficiencyTrend = Math.random() > 0.3 ? 1.5 : -0.8;
  const effTrendEl = document.getElementById('equipment-efficiency').nextElementSibling;
  effTrendEl.textContent = (efficiencyTrend >= 0 ? '↑' : '↓') + Math.abs(efficiencyTrend).toFixed(1) + '%';
  effTrendEl.className = 'card-trend ' + (efficiencyTrend >= 0 ? 'positive' : 'negative');
  
  // 更新总产量
  if (Math.random() > 0.7) {
    const increment = Math.floor(Math.random() * 20 + 10);
    totalProduction += increment;
    document.getElementById('total-output').textContent = totalProduction.toLocaleString();
  }
  
  // 检查是否需要产生告警
  checkAlarms();
}

/**
 * 更新各工站状态
 */
function updateStationStatus() {
  if (!systemRunning) return;
  
  // 随机选择一个工站可能出现临时警告
  if (Math.random() < 0.05) { // 5%概率出现警告
    const stationId = 'station-' + Math.ceil(Math.random() * 6);
    
    if (stationStatus[stationId] === 'active') {
      stationStatus[stationId] = 'warning';
      document.getElementById(stationId + '-status').className = 'station-status warning';
      
      // 添加警告信息
      const stationName = document.querySelector('#' + stationId + ' .station-label').textContent;
      addAlarm('warning', stationName + '状态异常', '检测到性能波动,请注意监控');
      
      // 2-5秒后自动恢复
      setTimeout(() => {
        if (systemRunning && stationStatus[stationId] === 'warning') {
          stationStatus[stationId] = 'active';
          document.getElementById(stationId + '-status').className = 'station-status active';
        }
      }, 2000 + Math.random() * 3000);
    }
  }
}

/**
 * 更新流动动画
 */
function updateFlowAnimation() {
  if (!systemRunning) return;
  
  // 更新流动状态动画
  Object.keys(flowStatus).forEach(flow => {
    if (flowStatus[flow]) {
      const el = document.getElementById(flow);
      
      // 切换动画状态来重启动画
      el.classList.remove('active');
      setTimeout(() => {
        if (systemRunning && flowStatus[flow]) {
          el.classList.add('active');
        }
      }, 50);
    }
  });
}

/**
 * 更新系统时间
 */
function updateSystemTime() {
  const now = new Date();
  const timeStr = now.toLocaleString('zh-CN', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false
  });
  
  document.getElementById('system-time').textContent = timeStr;
  
  setTimeout(updateSystemTime, 1000);
}

/**
 * 更新运行时间
 */
function updateRunningTime() {
  if (!systemRunning) return;
  
  runningTime++;
  
  const hours = Math.floor(runningTime / 3600).toString().padStart(2, '0');
  const minutes = Math.floor((runningTime % 3600) / 60).toString().padStart(2, '0');
  const seconds = (runningTime % 60).toString().padStart(2, '0');
  
  document.getElementById('running-time').textContent = `${hours}:${minutes}:${seconds}`;
}

/**
 * 更新系统指标数据
 */
function updateSystemMetrics() {
  if (!systemRunning) return;
  
  // 更新CPU负载
  const cpuLoad = Math.floor(20 + Math.random() * 25);
  document.getElementById('cpu-load').textContent = cpuLoad + '%';
  
  // 更新内存使用
  const memoryUsage = (1.0 + Math.random() * 0.5).toFixed(1);
  document.getElementById('memory-usage').textContent = memoryUsage + 'GB/4GB';
  
  // 更新通信状态
  if (Math.random() < 0.02) { // 2%概率通信状态变化
    const commStatus = document.getElementById('comm-status');
    if (commStatus.textContent === '已连接') {
      commStatus.textContent = '重连中...';
      commStatus.className = 'metric-value disconnected';
      
      // 添加通信中断告警
      addAlarm('warning', '通信状态异常', '系统正在尝试重新建立连接');
      
      // 1-3秒后恢复
      setTimeout(() => {
        if (systemRunning) {
          commStatus.textContent = '已连接';
          commStatus.className = 'metric-value connected';
          
          addAlarm('info', '通信已恢复', '系统通信连接已重新建立');
        }
      }, 1000 + Math.random() * 2000);
    }
  }
}

/**
 * 更新产量数据(模拟数据变化)
 */
function updateProductionData() {
  if (!systemRunning) return;
  
  // 移除第一个时间点数据
  productionData.labels.shift();
  productionData.actual.shift();
  productionData.target.shift();
  productionData.defects.shift();
  
  // 添加新的时间点数据
  const lastTime = productionData.labels[productionData.labels.length - 1];
  const [hour, minute] = lastTime.split(':').map(Number);
  
  let newHour = hour;
  let newMinute = minute + 30;
  
  if (newMinute >= 60) {
    newMinute = 0;
    newHour += 1;
  }
  
  const newTimeStr = `${newHour}:${newMinute === 0 ? '00' : '30'}`;
  productionData.labels.push(newTimeStr);
  
  // 添加新的产量数据
  const lastTarget = productionData.target[productionData.target.length - 1];
  const newTarget = lastTarget + (Math.random() > 0.7 ? 100 : 0);
  
  const baseProduction = newTarget * (productionSpeed / 100);
  const newProduction = Math.floor(baseProduction * (0.9 + Math.random() * 0.2));
  
  const newDefect = Math.max(0.1, Math.min(3.0, productionData.defects[productionData.defects.length - 1] + (Math.random() - 0.5))).toFixed(1);
  
  productionData.target.push(newTarget);
  productionData.actual.push(newProduction);
  productionData.defects.push(parseFloat(newDefect));
}

/**
 * 检查是否产生告警
 */
function checkAlarms() {
  if (!systemRunning) return;
  
  // 随机触发告警(低概率)
  if (Math.random() < 0.04) { // 4%概率产生新告警
    const alarmTypes = [
      { level: 'info', title: '批次变更通知', desc: '系统已自动更新至新批次:' + batchNumber },
      { level: 'info', title: '日常维护提醒', desc: '设备1号传送带已运行720小时,建议进行日常维护检查' },
      { level: 'warning', title: '质量波动', desc: '最近30分钟内包装质量合格率出现轻微下降' },
      { level: 'warning', title: '能耗异常', desc: '3号包装工位能耗高于正常值15%,建议检查' },
      { level: 'warning', title: '备料不足', desc: '备料区原材料库存低于预警阈值,请及时补充' },
      { level: 'critical', title: '设备故障', desc: '标签打印机5分钟内多次出现卡纸现象,需要检修' },
      { level: 'critical', title: '温度超限', desc: '热封区温度超出工艺范围,当前值: 185°C (标准:160±10°C)' }
    ];
    
    const alarm = alarmTypes[Math.floor(Math.random() * alarmTypes.length)];
    addAlarm(alarm.level, alarm.title, alarm.desc);
  }
}

/**
 * 添加新告警
 */
function addAlarm(level, title, description) {
  // 创建新告警
  const alarm = {
    id: Date.now(),
    level: level,
    title: title,
    description: description,
    time: new Date(),
    acknowledged: false
  };
  
  // 添加到告警列表
  alarms.unshift(alarm);
  
  // 限制告警列表最大长度
  if (alarms.length > 50) {
    alarms.pop();
  }
  
  // 更新告警计数
  updateAlarmCount();
  
  // 更新当前告警信息
  document.getElementById('current-alarm').textContent = title;
  
  // 更新告警图标状态
  const alarmIcon = document.getElementById('alarm-icon');
  alarmIcon.classList.add('active');
  
  // 如果是严重告警,弹出告警窗口
  if (level === 'critical') {
    showAlarmModal();
  }
  
  // 更新告警列表(如果弹窗已显示)
  if (document.querySelector('.alarm-modal.show')) {
    updateAlarmList();
  }
}

/**
 * 更新告警计数
 */
function updateAlarmCount() {
  // 统计未确认告警数量
  const unacknowledgedCount = alarms.filter(alarm => !alarm.acknowledged).length;
  alarmCount = unacknowledgedCount;
  
  // 更新告警计数显示
  document.getElementById('alarm-count').textContent = alarmCount;
  
  // 更新告警图标状态
  const alarmIcon = document.getElementById('alarm-icon');
  if (alarmCount > 0) {
    alarmIcon.classList.add('active');
  } else {
    alarmIcon.classList.remove('active');
  }
}

/**
 * 显示告警弹窗
 */
function showAlarmModal() {
  // 更新告警列表
  updateAlarmList();
  
  // 显示弹窗
  const alarmModal = document.getElementById('alarm-modal');
  alarmModal.classList.add('show');
}

/**
 * 隐藏告警弹窗
 */
function hideAlarmModal() {
  const alarmModal = document.getElementById('alarm-modal');
  alarmModal.classList.remove('show');
}

/**
 * 更新告警列表
 */
function updateAlarmList() {
  const alarmList = document.getElementById('alarm-list');
  alarmList.innerHTML = '';
  
  if (alarms.length === 0) {
    const emptyMessage = document.createElement('div');
    emptyMessage.className = 'empty-alarm';
    emptyMessage.textContent = '无告警信息';
    alarmList.appendChild(emptyMessage);
    return;
  }
  
  // 创建告警列表项
  alarms.forEach(alarm => {
    const alarmItem = document.createElement('div');
    alarmItem.className = `alarm-item ${alarm.level} ${alarm.acknowledged ? 'acknowledged' : ''}`;
    alarmItem.dataset.id = alarm.id;
    
    // 告警时间
    const time = document.createElement('div');
    time.className = 'alarm-time';
    time.textContent = formatTime(alarm.time);
    
    // 告警图标
    const icon = document.createElement('div');
    icon.className = 'alarm-icon';
    icon.innerHTML = alarm.level === 'critical' ? '⚠' : (alarm.level === 'warning' ? '⚠' : 'ℹ');
    
    // 告警内容
    const content = document.createElement('div');
    content.className = 'alarm-content';
    
    const title = document.createElement('div');
    title.className = 'alarm-title';
    title.textContent = alarm.title;
    
    const description = document.createElement('div');
    description.className = 'alarm-description';
    description.textContent = alarm.description;
    
    content.appendChild(title);
    content.appendChild(description);
    
    // 确认按钮
    const ackBtn = document.createElement('button');
    ackBtn.className = 'alarm-ack-btn';
    ackBtn.textContent = '确认';
    ackBtn.addEventListener('click', () => acknowledgeAlarm(alarm.id));
    
    if (!alarm.acknowledged) {
      alarmItem.appendChild(icon);
      alarmItem.appendChild(time);
      alarmItem.appendChild(content);
      alarmItem.appendChild(ackBtn);
    } else {
      alarmItem.appendChild(icon);
      alarmItem.appendChild(time);
      alarmItem.appendChild(content);
      
      const ackMark = document.createElement('div');
      ackMark.className = 'alarm-ack-mark';
      ackMark.textContent = '已确认';
      alarmItem.appendChild(ackMark);
    }
    
    alarmList.appendChild(alarmItem);
  });
}

/**
 * 确认单个告警
 */
function acknowledgeAlarm(id) {
  const alarm = alarms.find(a => a.id === id);
  if (alarm) {
    alarm.acknowledged = true;
    
    // 更新告警计数
    updateAlarmCount();
    
    // 更新告警列表
    updateAlarmList();
  }
}

/**
 * 确认所有告警
 */
function acknowledgeAllAlarms() {
  alarms.forEach(alarm => {
    alarm.acknowledged = true;
  });
  
  // 更新告警计数
  updateAlarmCount();
  
  // 更新告警列表
  updateAlarmList();
  
  // 如果没有未确认的告警,自动关闭弹窗
  setTimeout(hideAlarmModal, 500);
}

/**
 * 格式化时间显示
 */
function formatTime(date) {
  const hours = date.getHours().toString().padStart(2, '0');
  const minutes = date.getMinutes().toString().padStart(2, '0');
  const seconds = date.getSeconds().toString().padStart(2, '0');
  
  return `${hours}:${minutes}:${seconds}`;
}

/**
 * 切换逻辑编程区域的Tab
 */
function switchProgrammingTab(event) {
  // 获取当前点击的Tab
  const clickedTab = event.currentTarget;
  
  // 获取目标Tab的ID
  const targetTabId = clickedTab.dataset.tab;
  
  // 移除所有Tab的active类
  document.querySelectorAll('.tab').forEach(tab => {
    tab.classList.remove('active');
  });
  
  // 隐藏所有Tab内容
  document.querySelectorAll('.tab-pane').forEach(pane => {
    pane.classList.remove('active');
  });
  
  // 添加当前Tab的active类
  clickedTab.classList.add('active');
  
  // 显示对应的Tab内容
  document.getElementById(targetTabId + '-pane').classList.add('active');
}

/**
 * 初始化逻辑编程界面
 */
function initializeLogicProgramming() {
  // 设置Canvas的拖放区域
  setupDragAndDrop();
  
  // 初始化代码编辑器
  initializeCodeEditor();
  
  // 初始化时序图
  updateSequenceDiagram();
}

/**
 * 设置拖放功能
 */
function setupDragAndDrop() {
  const logicCanvas = document.getElementById('logic-canvas');
  
  // 添加提示文本
  const placeholderText = document.createElement('div');
  placeholderText.className = 'placeholder-text';
  placeholderText.textContent = '拖放控制元件到此区域创建逻辑流程';
  
  // 初始化工作流容器
  const workflowContainer = document.getElementById('workflow-container');
  if (!workflowContainer) {
    const container = document.createElement('div');
    container.id = 'workflow-container';
    container.className = 'workflow-container';
    logicCanvas.appendChild(container);
  }
}

/**
 * 处理拖动开始事件
 */
function handleDragStart(event) {
  // 存储被拖动元素的类型
  event.dataTransfer.setData('type', event.target.dataset.type);
  event.dataTransfer.effectAllowed = 'copy';
}

/**
 * 处理拖动经过事件
 */
function handleDragOver(event) {
  event.preventDefault();
  event.dataTransfer.dropEffect = 'copy';
  
  // 添加拖动经过的视觉效果
  event.currentTarget.classList.add('drag-over');
}

/**
 * 处理拖放事件
 */
function handleDrop(event) {
  event.preventDefault();
  
  // 移除拖动经过的视觉效果
  event.currentTarget.classList.remove('drag-over');
  
  // 获取被拖动元素的类型
  const type = event.dataTransfer.getData('type');
  
  // 获取放置位置
  const canvasRect = event.currentTarget.getBoundingClientRect();
  const x = event.clientX - canvasRect.left;
  const y = event.clientY - canvasRect.top;
  
  // 创建新的逻辑元素
  createLogicElement(type, x, y);
}

/**
 * 创建新的逻辑元素
 */
function createLogicElement(type, x, y) {
  // 元素配置
  const elementConfig = {
    start: { shape: 'circle', label: '开始', color: '#4CAF50' },
    decision: { shape: 'diamond', label: '判断', color: '#FF9800' },
    action: { shape: 'rect', label: '动作', color: '#2196F3' },
    delay: { shape: 'rect', label: '延时', color: '#9C27B0' },
    parallel: { shape: 'rect', label: '并行', color: '#00BCD4' },
    end: { shape: 'circle', label: '结束', color: '#F44336' },
    feeding: { shape: 'rect', label: '上料', color: '#2196F3' },
    weighing: { shape: 'rect', label: '称重', color: '#4CAF50' },
    packaging: { shape: 'rect', label: '包装', color: '#FF9800' },
    labeling: { shape: 'rect', label: '贴标', color: '#9C27B0' },
    inspection: { shape: 'rect', label: '检测', color: '#00BCD4' },
    palletizing: { shape: 'rect', label: '码垛', color: '#795548' }
  };
  
  const config = elementConfig[type] || { shape: 'rect', label: type, color: '#607D8B' };
  
  // 创建新元素
  const id = 'element-' + Date.now();
  const element = {
    id: id,
    type: type,
    label: config.label,
    shape: config.shape,
    color: config.color,
    x: x,
    y: y,
    connections: []
  };
  
  // 添加到元素列表
  workflowElements.push(element);
  
  // 渲染新元素
  renderLogicElement(element);
}

/**
 * 渲染逻辑元素
 */
function renderLogicElement(element) {
  const container = document.getElementById('workflow-container');
  
  // 创建元素DOM
  const el = document.createElement('div');
  el.id = element.id;
  el.className = `workflow-element ${element.shape} ${element.type}`;
  el.style.left = element.x + 'px';
  el.style.top = element.y + 'px';
  el.style.backgroundColor = element.color;
  
  // 添加标签
  const label = document.createElement('div');
  label.className = 'element-label';
  label.textContent = element.label;
  el.appendChild(label);
  
  // 添加连接点
  const connectionPoints = document.createElement('div');
  connectionPoints.className = 'connection-points';
  
  ['top', 'right', 'bottom', 'left'].forEach(position => {
    const point = document.createElement('div');
    point.className = `connection-point ${position}`;
    point.dataset.position = position;
    point.dataset.elementId = element.id;
    
    // 添加连接点的事件处理
    point.addEventListener('mousedown', startConnection);
    
    connectionPoints.appendChild(point);
  });
  
  el.appendChild(connectionPoints);
  
  // 添加拖动功能
  el.draggable = true;
  el.addEventListener('dragstart', handleElementDragStart);
  el.addEventListener('dragend', handleElementDragEnd);
  
  // 添加双击编辑功能
  el.addEventListener('dblclick', editElement);
  
  // 添加到容器
  container.appendChild(el);
}

/**
 * 开始创建连接
 */
function startConnection(event) {
  // 这里实现连接创建逻辑
  console.log('开始创建连接点,从元素:', event.target.dataset.elementId);
}

/**
 * 处理元素拖动开始
 */
function handleElementDragStart(event) {
  // 保存当前位置信息
  const elementId = event.target.id;
  const element = workflowElements.find(el => el.id === elementId);
  
  if (element) {
    event.dataTransfer.setData('elementId', elementId);
    
    // 设置拖动时的视觉效果
    event.target.classList.add('dragging');
  }
}

/**
 * 处理元素拖动结束
 */
function handleElementDragEnd(event) {
  // 移除拖动时的视觉效果
  event.target.classList.remove('dragging');
}

/**
 * 编辑元素
 */
function editElement(event) {
  const elementId = event.currentTarget.id;
  const element = workflowElements.find(el => el.id === elementId);
  
  if (element) {
    // 这里可以实现弹出编辑对话框等功能
    console.log('编辑元素:', element);
  }
}

/**
 * 创建新的逻辑流程
 */
function createNewLogic() {
  // 清空工作区
  const container = document.getElementById('workflow-container');
  container.innerHTML = '';
  
  // 清空元素列表
  workflowElements = [];
  
  console.log('创建新的逻辑流程');
}

/**
 * 保存当前逻辑流程
 */
function saveLogic() {
  // 这里可以实现保存逻辑,如导出JSON等
  console.log('保存逻辑流程:', workflowElements);
}

/**
 * 部署逻辑流程
 */
function deployLogic() {
  // 这里可以实现部署逻辑
  console.log('部署逻辑流程');
  
  // 显示部署成功消息
  addAlarm('info', '逻辑流程已部署', '新的控制逻辑已成功部署到系统');
}

/**
 * 初始化代码编辑器
 */
function initializeCodeEditor() {
  // 这里可以添加代码编辑器的高亮和自动完成等功能
  console.log('初始化代码编辑器');
}

/**
 * 检查代码语法
 */
function checkCodeSyntax() {
  const code = document.getElementById('code-content').textContent;
  
  // 这里可以实现语法检查逻辑
  console.log('检查代码语法');
  
  // 模拟语法检查结果
  const hasErrors = Math.random() < 0.3;
  
  if (hasErrors) {
    addAlarm('warning', '语法检查发现问题', '代码第25行可能存在语法错误,请检查');
  } else {
    addAlarm('info', '语法检查通过', '代码语法检查未发现问题');
  }
}

/**
 * 格式化代码
 */
function formatCode() {
  // 这里可以实现代码格式化逻辑
  console.log('格式化代码');
  
  // 添加操作提示
  addAlarm('info', '代码已格式化', '代码格式化操作已完成');
}

/**
 * 更新时序图
 */
function updateSequenceDiagram() {
  const selectedStation = document.getElementById('station-selector').value;
  const diagram = document.getElementById('sequence-diagram');
  
  // 清空时序图区域
  diagram.innerHTML = '';
  
  if (selectedStation === 'all') {
    renderFullSequenceDiagram(diagram);
  } else {
    renderStationSequenceDiagram(diagram, selectedStation);
  }
}

/**
 * 渲染完整流程时序图
 */
function renderFullSequenceDiagram(container) {
  // 这里可以实现完整流程时序图的渲染
  console.log('渲染完整流程时序图');
  
  // 示例简单时序图
  const svgNS = "http://www.w3.org/2000/svg";
  const width = container.clientWidth;
  const height = 300;
  
  const svg = document.createElementNS(svgNS, "svg");
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  svg.style.backgroundColor = "var(--primary-dark)";
  
  // 绘制简单的时序线
  const stations = ['控制系统', '上料站', '称重站', '包装站', '贴标站', '检测站', '码垛站'];
  const xStep = width / (stations.length + 1);
  
  // 绘制垂直生命线
  stations.forEach((station, i) => {
    const x = (i + 1) * xStep;
    
    // 绘制站点标签
    const text = document.createElementNS(svgNS, "text");
    text.setAttribute("x", x);
    text.setAttribute("y", 20);
    text.setAttribute("text-anchor", "middle");
    text.setAttribute("fill", "var(--text-primary)");
    text.setAttribute("font-size", "12");
    text.textContent = station;
    svg.appendChild(text);
    
    // 绘制垂直线
    const line = document.createElementNS(svgNS, "line");
    line.setAttribute("x1", x);
    line.setAttribute("y1", 30);
    line.setAttribute("x2", x);
    line.setAttribute("y2", height - 10);
    line.setAttribute("stroke", "var(--border-color)");
    line.setAttribute("stroke-dasharray", "5,5");
    svg.appendChild(line);
  });
  
  // 绘制消息箭头
  const messages = [
    { from: 0, to: 1, label: '启动指令', y: 60 },
    { from: 1, to: 2, label: '物料传送', y: 90 },
    { from: 2, to: 3, label: '重量数据', y: 120 },
    { from: 3, to: 4, label: '包装完成', y: 150 },
    { from: 4, to: 5, label: '贴标完成', y: 180 },
    { from: 5, to: 6, label: '检测结果', y: 210 },
    { from: 6, to: 0, label: '流程完成', y: 240 }
  ];
  
  messages.forEach(msg => {
    const x1 = (msg.from + 1) * xStep;
    const x2 = (msg.to + 1) * xStep;
    const y = msg.y;
    
    // 绘制箭头线
    const arrow = document.createElementNS(svgNS, "line");
    arrow.setAttribute("x1", x1);
    arrow.setAttribute("y1", y);
    arrow.setAttribute("x2", x2);
    arrow.setAttribute("y2", y);
    arrow.setAttribute("stroke", "#4CAF50");
    arrow.setAttribute("stroke-width", "1.5");
    arrow.setAttribute("marker-end", "url(#arrow)");
    svg.appendChild(arrow);
    
    // 绘制消息标签
    const text = document.createElementNS(svgNS, "text");
    text.setAttribute("x", (x1 + x2) / 2);
    text.setAttribute("y", y - 5);
    text.setAttribute("text-anchor", "middle");
    text.setAttribute("fill", "var(--text-secondary)");
    text.setAttribute("font-size", "10");
    text.textContent = msg.label;
    svg.appendChild(text);
  });
  
  // 添加箭头标记定义
  const defs = document.createElementNS(svgNS, "defs");
  const marker = document.createElementNS(svgNS, "marker");
  marker.setAttribute("id", "arrow");
  marker.setAttribute("viewBox", "0 0 10 10");
  marker.setAttribute("refX", "9");
  marker.setAttribute("refY", "5");
  marker.setAttribute("markerWidth", "6");
  marker.setAttribute("markerHeight", "6");
  marker.setAttribute("orient", "auto");
  
  const path = document.createElementNS(svgNS, "path");
  path.setAttribute("d", "M 0 0 L 10 5 L 0 10 z");
  path.setAttribute("fill", "#4CAF50");
  
  marker.appendChild(path);
  defs.appendChild(marker);
  svg.appendChild(defs);
  
  container.appendChild(svg);
}

/**
 * 渲染单个工站的时序图
 */
function renderStationSequenceDiagram(container, stationId) {
  // 这里可以实现单个工站的时序图渲染
  console.log('渲染工站时序图:', stationId);
  
  // 添加提示信息
  const info = document.createElement('div');
  info.className = 'station-sequence-info';
  info.textContent = '显示 ' + document.querySelector('#' + stationId + ' .station-label').textContent + ' 的详细时序操作';
  container.appendChild(info);
}

// 页面加载完成后初始化系统
document.addEventListener('DOMContentLoaded', initializeSystem); 

网站公告

今日签到

点亮在社区的每一天
去签到