2、实验室测控系统 - /自动化与控制组件/lab-monitoring-system
76个工业组件库示例汇总
实验室测控系统开发组件
这是一个专为实验室设备数据采集与分析设计的可视化测控系统组件。采用工业风格界面设计,提供了丰富的动态数据展示与分析功能,可应用于各类实验室环境中的设备监控和数据处理。
功能特点
- 多设备管理与控制:支持多种测量设备的状态监控和控制管理
- 实时数据可视化:提供动态更新的数据图表,直观展示各传感器数据变化
- 数据分析工具:内置FFT分析、统计分析和趋势分析等常用数据分析功能
- 报警系统:可配置的多参数报警机制,及时响应异常情况
- 灵活配置选项:提供采样率、缓冲区大小等核心参数的自定义配置
- 通知系统:系统事件与报警的集中管理和展示
- 数据导出:支持将采集数据导出为标准格式,便于后续处理
- 工业风格界面:专业的深色工业设计风格,降低视觉疲劳
组件区域说明
组件包含以下主要功能区域:
- 设备状态与控制区:显示连接的实验设备状态,提供基本控制功能
- 数据可视化区:动态图表显示采集数据,支持多种显示模式(实时、历史、相关性)
- 数据分析与配置区:
- 数据分析:提供快速分析工具和结果显示
- 测量设置:采样参数和存储选项配置
- 报警设置:温度和压力等参数的警报阈值设置
- 通知系统:汇总显示系统报警和事件通知
- 状态栏:显示数据采集状态信息(数据点数、采集时间、存储空间)
可定制选项
组件提供多种定制选项,可以通过修改代码来调整:
添加新的传感器/设备
- 在HTML的
device-list
区域添加新的设备项 - 在JavaScript中的事件监听器中为新设备添加控制逻辑
- 在数据结构和模拟函数中添加对应的数据处理逻辑
调整界面设计
- 修改CSS中的颜色变量(
:root
部分)可以改变整体配色 - 调整面板的flex属性可以改变各区域的宽度比例
- 修改媒体查询可以优化不同屏幕尺寸下的显示效果
增强数据分析功能
- 在
performFFTAnalysis
、performStatisticalAnalysis
和performTrendAnalysis
函数中添加实际的数据处理算法 - 扩展分析结果的展示方式,如添加更多的可视化图表
连接实际设备
组件目前使用模拟数据进行演示。要连接实际的实验设备,需要:
- 根据设备API替换
simulateNewData
函数中的数据生成逻辑 - 调整数据采集频率和处理方式,适应实际设备的特性
- 在设备控制函数中实现与实际设备的通信逻辑
图表使用说明
组件默认尝试使用Chart.js来绘制图表。如需启用完整的Chart.js功能:
- 或者修改
initializeCharts
函数,添加动态加载Chart.js的逻辑
如果Chart.js不可用,组件会自动使用内置的SVG简易图表进行数据展示。
浏览器兼容性
组件使用了现代Web技术(Flexbox、CSS变量、ES6+),建议在较新版本的浏览器中使用:
- Chrome 60+
- Firefox 55+
- Edge 16+
- Safari 11+
性能优化
对于大规模数据采集场景,建议:
- 调整更新频率,减少DOM操作次数
- 优化数据存储逻辑,避免内存占用过高
- 考虑使用Web Worker处理数据分析任务,提高响应性
项目结构
效果展示
源码
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="lab-monitoring-system"><!-- 顶部标题栏 --><div class="lab-header"><div class="lab-title">实验室测控系统</div><div class="lab-status"><span class="status-label">系统状态:</span><span class="status-value" id="system-status">数据采集中</span><div class="status-indicator active"></div></div></div><!-- 主内容区域 --><div class="lab-content"><!-- 左侧:设备状态与控制 --><div class="panel device-panel"><div class="panel-header"><h3>设备状态与控制</h3><div class="panel-tools"><button class="tool-btn" id="refresh-devices" title="刷新设备状态"><i class="tool-icon">↻</i></button></div></div><div class="panel-body"><div class="device-list" id="device-list"><div class="device-item"><div class="device-header"><span class="device-name">温度传感器阵列</span><span class="device-status online">在线</span></div><div class="device-controls"><button class="control-btn" id="temp-start">启动</button><button class="control-btn" id="temp-stop">停止</button><button class="control-btn" id="temp-calibrate">校准</button></div><div class="device-parameters"><div class="parameter"><span class="param-label">采样率:</span><span class="param-value">5Hz</span></div><div class="parameter"><span class="param-label">精度:</span><span class="param-value">±0.1°C</span></div><div class="parameter"><span class="param-label">状态:</span><span class="param-value">采集中</span></div></div></div><div class="device-item"><div class="device-header"><span class="device-name">压力传感器</span><span class="device-status online">在线</span></div><div class="device-controls"><button class="control-btn" id="pressure-start">启动</button><button class="control-btn" id="pressure-stop">停止</button><button class="control-btn" id="pressure-calibrate">校准</button></div><div class="device-parameters"><div class="parameter"><span class="param-label">采样率:</span><span class="param-value">10Hz</span></div><div class="parameter"><span class="param-label">精度:</span><span class="param-value">±0.01MPa</span></div><div class="parameter"><span class="param-label">状态:</span><span class="param-value">采集中</span></div></div></div><div class="device-item"><div class="device-header"><span class="device-name">光谱分析仪</span><span class="device-status offline">离线</span></div><div class="device-controls"><button class="control-btn" id="spectral-start" disabled>启动</button><button class="control-btn" id="spectral-stop" disabled>停止</button><button class="control-btn" id="spectral-calibrate" disabled>校准</button></div><div class="device-parameters"><div class="parameter"><span class="param-label">波长范围:</span><span class="param-value">380-780nm</span></div><div class="parameter"><span class="param-label">分辨率:</span><span class="param-value">1.5nm</span></div><div class="parameter"><span class="param-label">状态:</span><span class="param-value">未连接</span></div></div></div></div></div></div><!-- 中间:数据可视化 --><div class="panel visualization-panel"><div class="panel-header"><h3>数据可视化</h3><div class="panel-tools"><select id="chart-type"><option value="realtime">实时图表</option><option value="historical">历史数据</option><option value="correlation">相关性分析</option></select><select id="timeframe"><option value="1m">1分钟</option><option value="5m">5分钟</option><option value="15m">15分钟</option><option value="1h">1小时</option><option value="1d">1天</option></select><button class="tool-btn" id="export-data" title="导出数据"><i class="tool-icon">↓</i></button></div></div><div class="panel-body"><div class="chart-container"><div class="chart-header"><div class="chart-title" id="chart-title">温度传感器实时数据</div><div class="chart-legend"><div class="legend-item"><span class="legend-color" style="background-color: #2196F3;"></span><span class="legend-text">传感器 1</span></div><div class="legend-item"><span class="legend-color" style="background-color: #FF5722;"></span><span class="legend-text">传感器 2</span></div><div class="legend-item"><span class="legend-color" style="background-color: #4CAF50;"></span><span class="legend-text">传感器 3</span></div></div></div><div class="chart-wrapper" id="chart-area"><!-- 图表将通过JavaScript绘制 --></div><div class="chart-info"><div class="info-item"><span class="info-label">最大值:</span><span class="info-value" id="max-value">27.8°C</span></div><div class="info-item"><span class="info-label">最小值:</span><span class="info-value" id="min-value">21.2°C</span></div><div class="info-item"><span class="info-label">平均值:</span><span class="info-value" id="avg-value">24.5°C</span></div><div class="info-item"><span class="info-label">标准差:</span><span class="info-value" id="std-value">1.23</span></div></div></div></div></div><!-- 右侧:数据分析与配置 --><div class="panel analysis-panel"><div class="panel-header"><h3>数据分析与配置</h3><div class="panel-tools"><button class="tool-btn" id="save-config" title="保存配置"><i class="tool-icon">✓</i></button></div></div><div class="panel-body"><div class="tabs"><div class="tab-header"><div class="tab-btn active" data-tab="analysis">数据分析</div><div class="tab-btn" data-tab="settings">测量设置</div><div class="tab-btn" data-tab="alarms">报警设置</div></div><div class="tab-content"><!-- 数据分析内容 --><div class="tab-pane active" id="analysis-tab"><div class="analysis-tools"><div class="tool-group"><div class="tool-header">快速分析</div><div class="tool-buttons"><button class="analysis-btn" id="btn-fft">FFT分析</button><button class="analysis-btn" id="btn-statistics">统计分析</button><button class="analysis-btn" id="btn-trend">趋势分析</button></div></div><div class="analysis-result" id="analysis-result"><div class="result-header">分析结果</div><div class="result-content"><p>选择一个分析工具开始数据分析。分析结果将显示在此处。</p></div></div></div></div><!-- 测量设置内容 --><div class="tab-pane" id="settings-tab"><div class="settings-form"><div class="setting-group"><div class="setting-header">采集设置</div><div class="setting-item"><label for="sample-rate">采样率 (Hz)</label><input type="number" id="sample-rate" class="setting-input" value="10" min="1" max="1000"></div><div class="setting-item"><label for="buffer-size">缓冲区大小</label><input type="number" id="buffer-size" class="setting-input" value="1000" min="100" max="10000"></div><div class="setting-item"><label for="averaging">平均次数</label><input type="number" id="averaging" class="setting-input" value="5" min="1" max="50"></div></div><div class="setting-group"><div class="setting-header">存储设置</div><div class="setting-item"><label for="auto-save">自动保存</label><div class="toggle-switch"><input type="checkbox" id="auto-save" checked><span class="toggle-slider"></span></div></div><div class="setting-item"><label for="save-interval">保存间隔 (分钟)</label><input type="number" id="save-interval" class="setting-input" value="5" min="1" max="60"></div></div></div></div><!-- 报警设置内容 --><div class="tab-pane" id="alarms-tab"><div class="alarm-config"><div class="alarm-header">温度报警设置</div><div class="alarm-item"><div class="alarm-param">高温报警</div><div class="alarm-inputs"><input type="number" id="temp-high" class="alarm-input" value="30" step="0.1"><span class="alarm-unit">°C</span></div><div class="toggle-switch"><input type="checkbox" id="temp-high-enabled" checked><span class="toggle-slider"></span></div></div><div class="alarm-item"><div class="alarm-param">低温报警</div><div class="alarm-inputs"><input type="number" id="temp-low" class="alarm-input" value="18" step="0.1"><span class="alarm-unit">°C</span></div><div class="toggle-switch"><input type="checkbox" id="temp-low-enabled" checked><span class="toggle-slider"></span></div></div><div class="alarm-header">压力报警设置</div><div class="alarm-item"><div class="alarm-param">高压报警</div><div class="alarm-inputs"><input type="number" id="pressure-high" class="alarm-input" value="2.5" step="0.01"><span class="alarm-unit">MPa</span></div><div class="toggle-switch"><input type="checkbox" id="pressure-high-enabled" checked><span class="toggle-slider"></span></div></div><div class="alarm-item"><div class="alarm-param">低压报警</div><div class="alarm-inputs"><input type="number" id="pressure-low" class="alarm-input" value="0.5" step="0.01"><span class="alarm-unit">MPa</span></div><div class="toggle-switch"><input type="checkbox" id="pressure-low-enabled"><span class="toggle-slider"></span></div></div></div></div></div></div></div></div></div><!-- 底部状态栏 --><div class="lab-footer"><div class="notifications"><div class="notification-btn" id="notification-btn"><i class="notification-icon">!</i><span class="notification-count" id="notification-count">2</span></div><div class="notification-dropdown" id="notification-dropdown"><div class="notification-header"><span>系统通知</span><button class="clear-btn" id="clear-notifications">清除所有</button></div><div class="notification-list" id="notification-list"><div class="notification-item warning"><div class="notification-time">08:42:15</div><div class="notification-content">温度传感器1数值超出警戒范围 (31.2°C)</div></div><div class="notification-item info"><div class="notification-time">08:15:20</div><div class="notification-content">自动保存已完成,数据已存储至 lab_data_20250409.csv</div></div></div></div></div><div class="system-info"><div class="info-segment"><span class="info-label">数据点数:</span><span class="info-value" id="data-points">12,458</span></div><div class="info-segment"><span class="info-label">采集时间:</span><span class="info-value" id="acquisition-time">02:15:37</span></div><div class="info-segment"><span class="info-label">存储空间:</span><span class="info-value" id="storage-usage">45.8MB / 1GB</span></div></div></div></div> <script src="script.js"></script>
</body>
</html>
styles.css
/* 实验室测控系统 - 工业风格CSS */
:root {--primary-dark: #1a2639;--primary-medium: #263852;--primary-light: #3d5174;--accent-blue: #0288d1;--accent-blue-light: #5eb8ff;--accent-blue-dark: #005b9f;--accent-green: #4caf50;--accent-amber: #ffb300;--accent-red: #e53935;--text-primary: #ffffff;--text-secondary: #c5c8d9;--text-muted: #7a8499;--border-color: #364761;--shadow-color: rgba(0, 0, 0, 0.3);--chart-grid: #2c3e50;
}/* 基本布局和容器样式 */
#lab-monitoring-system {font-family: 'Roboto', 'Segoe UI', Arial, sans-serif;background-color: var(--primary-dark);color: var(--text-primary);display: flex;flex-direction: column;height: 100%;width: 100%;min-height: 750px;border-radius: 5px;box-shadow: 0 4px 16px var(--shadow-color);overflow: hidden;border: 1px solid var(--border-color);
}/* 顶部标题栏 */
.lab-header {background-color: var(--primary-medium);padding: 12px 16px;display: flex;justify-content: space-between;align-items: center;border-bottom: 2px solid var(--border-color);
}.lab-title {font-size: 18px;font-weight: 600;letter-spacing: 0.5px;color: var(--text-primary);text-transform: uppercase;
}.lab-status {display: flex;align-items: center;gap: 8px;
}.status-label {color: var(--text-secondary);font-size: 14px;
}.status-value {font-weight: 500;color: var(--text-primary);
}.status-indicator {width: 12px;height: 12px;border-radius: 50%;background-color: var(--accent-blue);position: relative;
}.status-indicator.active::after {content: '';position: absolute;top: 0;left: 0;width: 100%;height: 100%;border-radius: 50%;background-color: var(--accent-blue);animation: pulse 1.5s infinite;
}@keyframes pulse {0% { transform: scale(1); opacity: 1; }70% { transform: scale(1.5); opacity: 0; }100% { transform: scale(1.5); opacity: 0; }
}/* 主内容区域 */
.lab-content {display: flex;flex: 1;overflow: hidden;padding: 10px;gap: 10px;
}/* 面板通用样式 */
.panel {background-color: var(--primary-medium);border-radius: 5px;border: 1px solid var(--border-color);box-shadow: 0 2px 8px var(--shadow-color);display: flex;flex-direction: column;overflow: hidden;
}.panel-header {padding: 10px 14px;background-color: var(--primary-light);border-bottom: 1px solid var(--border-color);display: flex;justify-content: space-between;align-items: center;
}.panel-header h3 {margin: 0;font-size: 15px;font-weight: 500;color: var(--text-primary);
}.panel-tools {display: flex;gap: 8px;align-items: center;
}.panel-body {flex: 1;padding: 12px;overflow: auto;
}/* 设备面板样式 */
.device-panel {flex: 0 0 280px;
}.device-list {display: flex;flex-direction: column;gap: 12px;
}.device-item {background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);overflow: hidden;
}.device-header {padding: 10px 12px;background-color: var(--primary-light);display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid var(--border-color);
}.device-name {font-weight: 500;font-size: 14px;
}.device-status {font-size: 12px;padding: 2px 8px;border-radius: 10px;font-weight: 500;
}.device-status.online {background-color: var(--accent-green);color: #ffffff;
}.device-status.offline {background-color: var(--text-muted);color: var(--primary-dark);
}.device-controls {display: flex;padding: 8px 12px;gap: 6px;border-bottom: 1px solid var(--border-color);
}.control-btn {flex: 1;background-color: var(--primary-light);color: var(--text-primary);border: 1px solid var(--border-color);border-radius: 3px;padding: 5px 8px;font-size: 12px;cursor: pointer;transition: all 0.2s;
}.control-btn:hover {background-color: var(--accent-blue);
}.control-btn:disabled {background-color: var(--primary-medium);color: var(--text-muted);cursor: not-allowed;
}.device-parameters {padding: 8px 12px;display: flex;flex-direction: column;gap: 6px;
}.parameter {display: flex;justify-content: space-between;font-size: 12px;
}.param-label {color: var(--text-secondary);
}.param-value {font-weight: 500;
}/* 可视化面板样式 */
.visualization-panel {flex: 1;min-width: 400px;
}.chart-container {background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);overflow: hidden;display: flex;flex-direction: column;height: 100%;
}.chart-header {padding: 10px 12px;display: flex;justify-content: space-between;align-items: center;background-color: var(--primary-light);border-bottom: 1px solid var(--border-color);
}.chart-title {font-size: 14px;font-weight: 500;
}.chart-legend {display: flex;gap: 12px;
}.legend-item {display: flex;align-items: center;gap: 5px;font-size: 12px;
}.legend-color {width: 12px;height: 12px;border-radius: 2px;
}.chart-wrapper {flex: 1;padding: 10px;min-height: 350px;position: relative;background: linear-gradient(to bottom,transparent 9px,var(--chart-grid) 10px),linear-gradient(to right,transparent 9px,var(--chart-grid) 10px);background-size: 10% 10%;background-color: var(--primary-dark);
}.chart-info {display: flex;justify-content: space-between;padding: 8px 12px;background-color: var(--primary-medium);border-top: 1px solid var(--border-color);
}.info-item {display: flex;gap: 5px;font-size: 12px;
}.info-label {color: var(--text-secondary);
}.info-value {font-weight: 500;color: var(--text-primary);
}/* 分析面板样式 */
.analysis-panel {flex: 0 0 280px;
}/* 标签页样式 */
.tabs {display: flex;flex-direction: column;height: 100%;
}.tab-header {display: flex;border-bottom: 1px solid var(--border-color);
}.tab-btn {padding: 8px 12px;font-size: 13px;cursor: pointer;border-bottom: 2px solid transparent;transition: all 0.2s;color: var(--text-secondary);
}.tab-btn:hover {color: var(--text-primary);
}.tab-btn.active {color: var(--accent-blue);border-bottom-color: var(--accent-blue);
}.tab-content {flex: 1;overflow: auto;
}.tab-pane {display: none;padding: 10px 0;
}.tab-pane.active {display: block;
}/* 数据分析标签页 */
.analysis-tools {display: flex;flex-direction: column;gap: 12px;
}.tool-group {background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);padding: 8px;
}.tool-header {font-size: 13px;font-weight: 500;margin-bottom: 8px;color: var(--text-secondary);
}.tool-buttons {display: flex;gap: 6px;
}.analysis-btn {flex: 1;background-color: var(--primary-light);color: var(--text-primary);border: 1px solid var(--border-color);border-radius: 3px;padding: 6px 8px;font-size: 12px;cursor: pointer;transition: all 0.2s;
}.analysis-btn:hover {background-color: var(--accent-blue);
}.analysis-result {background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);overflow: hidden;
}.result-header {padding: 8px 10px;font-size: 13px;background-color: var(--primary-light);border-bottom: 1px solid var(--border-color);font-weight: 500;
}.result-content {padding: 8px 10px;font-size: 12px;color: var(--text-secondary);min-height: 80px;
}/* 测量设置标签页 */
.settings-form {display: flex;flex-direction: column;gap: 16px;
}.setting-group {background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);padding: 10px;
}.setting-header {font-size: 13px;font-weight: 500;margin-bottom: 10px;color: var(--text-secondary);
}.setting-item {display: flex;justify-content: space-between;align-items: center;margin-bottom: 8px;font-size: 12px;
}.setting-item:last-child {margin-bottom: 0;
}.setting-item label {color: var(--text-primary);
}.setting-input {width: 80px;background-color: var(--primary-medium);color: var(--text-primary);border: 1px solid var(--border-color);border-radius: 3px;padding: 4px 6px;font-size: 12px;
}/* 开关按钮 */
.toggle-switch {position: relative;display: inline-block;width: 36px;height: 18px;
}.toggle-switch input {opacity: 0;width: 0;height: 0;
}.toggle-slider {position: absolute;cursor: pointer;top: 0;left: 0;right: 0;bottom: 0;background-color: var(--primary-light);transition: .4s;border-radius: 18px;border: 1px solid var(--border-color);
}.toggle-slider:before {position: absolute;content: "";height: 12px;width: 12px;left: 2px;bottom: 2px;background-color: var(--text-secondary);transition: .4s;border-radius: 50%;
}input:checked + .toggle-slider {background-color: var(--accent-blue);
}input:checked + .toggle-slider:before {transform: translateX(18px);background-color: white;
}/* 报警设置标签页 */
.alarm-config {display: flex;flex-direction: column;gap: 6px;
}.alarm-header {font-size: 13px;font-weight: 500;color: var(--text-secondary);padding: 5px 0;margin-top: 5px;
}.alarm-item {display: flex;align-items: center;background-color: var(--primary-dark);border-radius: 4px;border: 1px solid var(--border-color);padding: 8px 10px;
}.alarm-param {flex: 0 0 80px;font-size: 12px;
}.alarm-inputs {flex: 1;display: flex;align-items: center;gap: 4px;
}.alarm-input {width: 60px;background-color: var(--primary-medium);color: var(--text-primary);border: 1px solid var(--border-color);border-radius: 3px;padding: 4px 6px;font-size: 12px;
}.alarm-unit {font-size: 12px;color: var(--text-secondary);
}/* 工具按钮 */
.tool-btn {width: 26px;height: 26px;background-color: var(--primary-dark);color: var(--text-secondary);border: 1px solid var(--border-color);border-radius: 3px;display: flex;align-items: center;justify-content: center;cursor: pointer;transition: all 0.2s;
}.tool-btn:hover {background-color: var(--accent-blue);color: var(--text-primary);
}.tool-icon {font-style: normal;font-size: 14px;
}/* 下拉选择框 */
select {background-color: var(--primary-dark);color: var(--text-primary);border: 1px solid var(--border-color);border-radius: 3px;padding: 4px 8px;font-size: 12px;min-width: 100px;cursor: pointer;appearance: none;background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="12" height="6" viewBox="0 0 12 6"><path fill="%237a8499" d="M0 0l6 6 6-6z"/></svg>');background-repeat: no-repeat;background-position: right 8px center;padding-right: 24px;
}/* 底部状态栏 */
.lab-footer {background-color: var(--primary-medium);padding: 10px 16px;border-top: 2px solid var(--border-color);display: flex;justify-content: space-between;align-items: center;
}.system-info {display: flex;gap: 16px;
}.info-segment {display: flex;align-items: center;gap: 5px;font-size: 12px;
}/* 通知系统 */
.notifications {position: relative;
}.notification-btn {position: relative;width: 30px;height: 30px;background-color: var(--primary-light);border-radius: 50%;display: flex;align-items: center;justify-content: center;cursor: pointer;
}.notification-icon {font-style: normal;color: var(--text-primary);font-weight: bold;
}.notification-count {position: absolute;top: -3px;right: -3px;min-width: 16px;height: 16px;background-color: var(--accent-red);color: white;border-radius: 8px;font-size: 10px;display: flex;align-items: center;justify-content: center;padding: 0 4px;
}.notification-dropdown {position: absolute;bottom: 40px;left: 0;width: 300px;background-color: var(--primary-medium);border-radius: 5px;border: 1px solid var(--border-color);box-shadow: 0 4px 12px var(--shadow-color);overflow: hidden;z-index: 100;display: none;
}.notification-dropdown.show {display: block;
}.notification-header {padding: 10px;background-color: var(--primary-light);border-bottom: 1px solid var(--border-color);display: flex;justify-content: space-between;align-items: center;
}.notification-header span {font-size: 13px;font-weight: 500;
}.clear-btn {background-color: transparent;color: var(--accent-blue);border: none;font-size: 12px;cursor: pointer;padding: 0;
}.notification-list {max-height: 250px;overflow-y: auto;
}.notification-item {padding: 8px 10px;border-bottom: 1px solid var(--border-color);font-size: 12px;
}.notification-item:last-child {border-bottom: none;
}.notification-time {color: var(--text-muted);margin-bottom: 3px;
}.notification-item.warning .notification-content {color: var(--accent-amber);
}.notification-item.error .notification-content {color: var(--accent-red);
}.notification-item.info .notification-content {color: var(--accent-blue-light);
}/* 响应式调整 */
@media (max-width: 1200px) {.lab-content {flex-direction: column;}.device-panel, .analysis-panel {flex: 0 0 auto;width: 100%;}.visualization-panel {min-height: 400px;}
}
script.js
// 实验室测控系统JavaScript
(function() {// 图表实例和数据let temperatureChart;let pressureChart;const temperatureData = {timestamps: [],sensor1: [],sensor2: [],sensor3: []};const pressureData = {timestamps: [],values: []};// 初始化函数function initLabMonitoringSystem() {console.log("实验室测控系统初始化...");setupEventListeners();initializeCharts();startDataSimulation();setupTabNavigation();}// 设置事件监听function setupEventListeners() {// 设备控制按钮document.getElementById('temp-start').addEventListener('click', () => controlDevice('温度传感器阵列', 'start'));document.getElementById('temp-stop').addEventListener('click', () => controlDevice('温度传感器阵列', 'stop'));document.getElementById('temp-calibrate').addEventListener('click', () => calibrateDevice('温度传感器阵列'));document.getElementById('pressure-start').addEventListener('click', () => controlDevice('压力传感器', 'start'));document.getElementById('pressure-stop').addEventListener('click', () => controlDevice('压力传感器', 'stop'));document.getElementById('pressure-calibrate').addEventListener('click', () => calibrateDevice('压力传感器'));// 刷新设备状态document.getElementById('refresh-devices').addEventListener('click', refreshDeviceStatus);// 图表类型和时间范围选择document.getElementById('chart-type').addEventListener('change', updateChartType);document.getElementById('timeframe').addEventListener('change', updateTimeframe);// 导出数据按钮document.getElementById('export-data').addEventListener('click', exportData);// 分析按钮document.getElementById('btn-fft').addEventListener('click', performFFTAnalysis);document.getElementById('btn-statistics').addEventListener('click', performStatisticalAnalysis);document.getElementById('btn-trend').addEventListener('click', performTrendAnalysis);// 保存配置document.getElementById('save-config').addEventListener('click', saveConfiguration);// 通知系统document.getElementById('notification-btn').addEventListener('click', toggleNotifications);document.getElementById('clear-notifications').addEventListener('click', clearNotifications);}// 初始化图表function initializeCharts() {// 创建温度图表的Canvas元素const tempChartCanvas = document.createElement('canvas');tempChartCanvas.id = 'temperature-chart';document.getElementById('chart-area').appendChild(tempChartCanvas);// 如果Chart.js可用,则创建图表if (typeof Chart !== 'undefined') {setupChartJS();} else {// 如果Chart.js不可用,创建一个简单的模拟图表createSimulatedChart();}}// 使用Chart.js创建图表function setupChartJS() {const ctx = document.getElementById('temperature-chart').getContext('2d');temperatureChart = new Chart(ctx, {type: 'line',data: {labels: [],datasets: [{label: '传感器 1',data: [],borderColor: '#2196F3',backgroundColor: 'rgba(33, 150, 243, 0.1)',borderWidth: 2,pointRadius: 0,tension: 0.3},{label: '传感器 2',data: [],borderColor: '#FF5722',backgroundColor: 'rgba(255, 87, 34, 0.1)',borderWidth: 2,pointRadius: 0,tension: 0.3},{label: '传感器 3',data: [],borderColor: '#4CAF50',backgroundColor: 'rgba(76, 175, 80, 0.1)',borderWidth: 2,pointRadius: 0,tension: 0.3}]},options: {responsive: true,maintainAspectRatio: false,animation: {duration: 0},scales: {x: {grid: {color: 'rgba(200, 200, 200, 0.1)'},ticks: {color: '#a7b6c2'}},y: {grid: {color: 'rgba(200, 200, 200, 0.1)'},ticks: {color: '#a7b6c2'}}},plugins: {legend: {display: false}}}});}// 创建模拟图表(当Chart.js不可用时)function createSimulatedChart() {const chartArea = document.getElementById('chart-area');chartArea.innerHTML = `<div class="simulated-chart"><svg width="100%" height="300" viewBox="0 0 600 300" preserveAspectRatio="none"><!-- 图表网格 --><g class="grid"><!-- 水平线 --><line x1="0" y1="0" x2="600" y2="0" stroke="#2c3e50" stroke-width="1" /><line x1="0" y1="60" x2="600" y2="60" stroke="#2c3e50" stroke-width="1" /><line x1="0" y1="120" x2="600" y2="120" stroke="#2c3e50" stroke-width="1" /><line x1="0" y1="180" x2="600" y2="180" stroke="#2c3e50" stroke-width="1" /><line x1="0" y1="240" x2="600" y2="240" stroke="#2c3e50" stroke-width="1" /><line x1="0" y1="299" x2="600" y2="299" stroke="#2c3e50" stroke-width="1" /><!-- 垂直线 --><line x1="0" y1="0" x2="0" y2="300" stroke="#2c3e50" stroke-width="1" /><line x1="120" y1="0" x2="120" y2="300" stroke="#2c3e50" stroke-width="1" /><line x1="240" y1="0" x2="240" y2="300" stroke="#2c3e50" stroke-width="1" /><line x1="360" y1="0" x2="360" y2="300" stroke="#2c3e50" stroke-width="1" /><line x1="480" y1="0" x2="480" y2="300" stroke="#2c3e50" stroke-width="1" /><line x1="599" y1="0" x2="599" y2="300" stroke="#2c3e50" stroke-width="1" /></g><!-- 数据线 - 传感器1 --><path id="sensor1-path" stroke="#2196F3" stroke-width="2" fill="none" /><!-- 数据线 - 传感器2 --><path id="sensor2-path" stroke="#FF5722" stroke-width="2" fill="none" /><!-- 数据线 - 传感器3 --><path id="sensor3-path" stroke="#4CAF50" stroke-width="2" fill="none" /></svg></div>`;// 初始化模拟数据路径updateSimulatedChart();}// 更新模拟图表function updateSimulatedChart() {const generateRandomPath = () => {let path = `M0,150`;for (let i = 1; i <= 60; i++) {const x = i * 10;const y = 150 + (Math.random() * 100 - 50);path += ` L${x},${y}`;}return path;};const sensor1Path = document.getElementById('sensor1-path');const sensor2Path = document.getElementById('sensor2-path');const sensor3Path = document.getElementById('sensor3-path');if (sensor1Path) sensor1Path.setAttribute('d', generateRandomPath());if (sensor2Path) sensor2Path.setAttribute('d', generateRandomPath());if (sensor3Path) sensor3Path.setAttribute('d', generateRandomPath());}// 开始数据模拟function startDataSimulation() {// 初始化一些历史数据点const now = new Date();for (let i = 60; i >= 0; i--) {const time = new Date(now - i * 1000);const timeStr = time.toLocaleTimeString();temperatureData.timestamps.push(timeStr);temperatureData.sensor1.push(22 + Math.random() * 6);temperatureData.sensor2.push(23 + Math.random() * 5);temperatureData.sensor3.push(21 + Math.random() * 7);pressureData.timestamps.push(timeStr);pressureData.values.push(1.8 + Math.random() * 0.5);}updateChart();// 每秒更新一次数据setInterval(() => {simulateNewData();updateChart();}, 1000);// 每30秒随机添加一个通知setInterval(() => {if (Math.random() < 0.3) {addRandomNotification();}}, 30000);// 更新采集时间setInterval(updateAcquisitionTime, 1000);}// 模拟新数据function simulateNewData() {const now = new Date();const timeStr = now.toLocaleTimeString();// 保留最近60个数据点if (temperatureData.timestamps.length > 60) {temperatureData.timestamps.shift();temperatureData.sensor1.shift();temperatureData.sensor2.shift();temperatureData.sensor3.shift();pressureData.timestamps.shift();pressureData.values.shift();}// 添加新的温度数据点 (模拟一些波动)const lastTemp1 = temperatureData.sensor1[temperatureData.sensor1.length - 1];const lastTemp2 = temperatureData.sensor2[temperatureData.sensor2.length - 1];const lastTemp3 = temperatureData.sensor3[temperatureData.sensor3.length - 1];const newTemp1 = lastTemp1 + (Math.random() * 0.6 - 0.3);const newTemp2 = lastTemp2 + (Math.random() * 0.6 - 0.3);const newTemp3 = lastTemp3 + (Math.random() * 0.6 - 0.3);temperatureData.timestamps.push(timeStr);temperatureData.sensor1.push(newTemp1);temperatureData.sensor2.push(newTemp2);temperatureData.sensor3.push(newTemp3);// 添加新的压力数据点const lastPressure = pressureData.values[pressureData.values.length - 1];const newPressure = lastPressure + (Math.random() * 0.1 - 0.05);pressureData.timestamps.push(timeStr);pressureData.values.push(newPressure);// 更新统计信息updateStatistics();// 检查警报checkAlarms(newTemp1, newTemp2, newTemp3, newPressure);// 更新数据点计数updateDataPointCount();}// 更新图表function updateChart() {const chartType = document.getElementById('chart-type').value;if (typeof Chart !== 'undefined' && temperatureChart) {// 使用Chart.js更新图表if (chartType === 'realtime') {temperatureChart.data.labels = temperatureData.timestamps;temperatureChart.data.datasets[0].data = temperatureData.sensor1;temperatureChart.data.datasets[1].data = temperatureData.sensor2;temperatureChart.data.datasets[2].data = temperatureData.sensor3;} else if (chartType === 'historical') {// 切换到历史数据视图// 这里为了演示,仅展示了同一数据的不同时间范围temperatureChart.data.labels = temperatureData.timestamps;temperatureChart.data.datasets[0].data = temperatureData.sensor1;temperatureChart.data.datasets[1].data = temperatureData.sensor2;temperatureChart.data.datasets[2].data = temperatureData.sensor3;} else if (chartType === 'correlation') {// 在实际应用中,这里会显示相关性分析的视图temperatureChart.data.labels = temperatureData.timestamps;temperatureChart.data.datasets[0].data = temperatureData.sensor1;temperatureChart.data.datasets[1].data = temperatureData.sensor2;temperatureChart.data.datasets[2].data = temperatureData.sensor3;}temperatureChart.update();} else {// 更新模拟图表updateSimulatedChart();}}// 更新图表类型function updateChartType() {const chartType = document.getElementById('chart-type').value;const chartTitle = document.getElementById('chart-title');switch (chartType) {case 'realtime':chartTitle.textContent = '温度传感器实时数据';break;case 'historical':chartTitle.textContent = '温度传感器历史数据';break;case 'correlation':chartTitle.textContent = '温度与压力相关性分析';break;}updateChart();}// 更新时间范围function updateTimeframe() {updateChart();}// 更新统计信息function updateStatistics() {// 计算所有传感器的统计数据const allValues = [...temperatureData.sensor1, ...temperatureData.sensor2, ...temperatureData.sensor3];const max = Math.max(...allValues).toFixed(1);const min = Math.min(...allValues).toFixed(1);// 计算平均值const sum = allValues.reduce((a, b) => a + b, 0);const avg = (sum / allValues.length).toFixed(1);// 计算标准差const variance = allValues.reduce((a, b) => a + Math.pow(b - avg, 2), 0) / allValues.length;const std = Math.sqrt(variance).toFixed(2);// 更新DOMdocument.getElementById('max-value').textContent = max + '°C';document.getElementById('min-value').textContent = min + '°C';document.getElementById('avg-value').textContent = avg + '°C';document.getElementById('std-value').textContent = std;}// 检查警报条件function checkAlarms(temp1, temp2, temp3, pressure) {// 获取警报阈值const tempHighThreshold = parseFloat(document.getElementById('temp-high').value);const tempLowThreshold = parseFloat(document.getElementById('temp-low').value);const pressureHighThreshold = parseFloat(document.getElementById('pressure-high').value);const pressureLowThreshold = parseFloat(document.getElementById('pressure-low').value);// 检查温度高警报if (document.getElementById('temp-high-enabled').checked) {if (temp1 > tempHighThreshold) {addNotification(`温度传感器1数值超出警戒范围 (${temp1.toFixed(1)}°C)`, 'warning');} else if (temp2 > tempHighThreshold) {addNotification(`温度传感器2数值超出警戒范围 (${temp2.toFixed(1)}°C)`, 'warning');} else if (temp3 > tempHighThreshold) {addNotification(`温度传感器3数值超出警戒范围 (${temp3.toFixed(1)}°C)`, 'warning');}}// 检查温度低警报if (document.getElementById('temp-low-enabled').checked) {if (temp1 < tempLowThreshold) {addNotification(`温度传感器1数值低于警戒范围 (${temp1.toFixed(1)}°C)`, 'warning');} else if (temp2 < tempLowThreshold) {addNotification(`温度传感器2数值低于警戒范围 (${temp2.toFixed(1)}°C)`, 'warning');} else if (temp3 < tempLowThreshold) {addNotification(`温度传感器3数值低于警戒范围 (${temp3.toFixed(1)}°C)`, 'warning');}}// 检查压力高警报if (document.getElementById('pressure-high-enabled').checked) {if (pressure > pressureHighThreshold) {addNotification(`压力传感器数值超出警戒范围 (${pressure.toFixed(2)} MPa)`, 'warning');}}// 检查压力低警报if (document.getElementById('pressure-low-enabled').checked) {if (pressure < pressureLowThreshold) {addNotification(`压力传感器数值低于警戒范围 (${pressure.toFixed(2)} MPa)`, 'warning');}}}// 设备控制function controlDevice(deviceName, action) {if (action === 'start') {addNotification(`${deviceName}已启动`, 'info');} else if (action === 'stop') {addNotification(`${deviceName}已停止`, 'info');}}// 校准设备function calibrateDevice(deviceName) {addNotification(`${deviceName}校准中...`, 'info');// 模拟校准过程setTimeout(() => {addNotification(`${deviceName}校准完成`, 'info');}, 3000);}// 刷新设备状态function refreshDeviceStatus() {const refreshBtn = document.getElementById('refresh-devices');refreshBtn.classList.add('rotating');// 模拟刷新延迟setTimeout(() => {refreshBtn.classList.remove('rotating');addNotification('设备状态已更新', 'info');}, 1000);}// 添加CSS动画function addCSSAnimation() {const style = document.createElement('style');style.textContent = `@keyframes rotate {from { transform: rotate(0deg); }to { transform: rotate(360deg); }}.rotating {animation: rotate 1s linear;}`;document.head.appendChild(style);}// 导出数据function exportData() {const today = new Date().toISOString().slice(0, 10);addNotification(`数据已导出至 lab_data_${today}.csv`, 'info');}// 执行FFT分析function performFFTAnalysis() {const resultContent = document.querySelector('.result-content');resultContent.innerHTML = '<p>正在执行FFT分析...</p>';// 模拟分析过程setTimeout(() => {resultContent.innerHTML = `<p>FFT分析结果:</p><ul><li>主频率分量: 0.05 Hz</li><li>谐波成分: 0.1 Hz, 0.15 Hz</li><li>信噪比: 24.6 dB</li></ul><p>此温度数据显示周期性变化,可能与环境控制系统相关。</p>`;}, 1500);}// 执行统计分析function performStatisticalAnalysis() {const resultContent = document.querySelector('.result-content');resultContent.innerHTML = '<p>正在执行统计分析...</p>';// 模拟分析过程setTimeout(() => {// 获取当前统计数据const max = document.getElementById('max-value').textContent;const min = document.getElementById('min-value').textContent;const avg = document.getElementById('avg-value').textContent;const std = document.getElementById('std-value').textContent;resultContent.innerHTML = `<p>统计分析结果:</p><ul><li>最大值: ${max}</li><li>最小值: ${min}</li><li>平均值: ${avg}</li><li>标准差: ${std}</li><li>峰度: 2.86</li><li>偏度: 0.12</li></ul><p>数据分布接近正态分布,温度变化稳定。</p>`;}, 1500);}// 执行趋势分析function performTrendAnalysis() {const resultContent = document.querySelector('.result-content');resultContent.innerHTML = '<p>正在执行趋势分析...</p>';// 模拟分析过程setTimeout(() => {resultContent.innerHTML = `<p>趋势分析结果:</p><ul><li>线性趋势: 微增 (0.02°C/分钟)</li><li>预测30分钟后温度: ${(parseFloat(document.getElementById('avg-value').textContent) + 0.6).toFixed(1)}°C</li><li>周期性: 存在10分钟周期</li><li>异常点数量: 0</li></ul><p>温度呈现稳定微增趋势,建议监控制冷系统状态。</p>`;}, 1500);}// 保存配置function saveConfiguration() {addNotification('系统配置已保存', 'info');}// 切换通知下拉菜单function toggleNotifications() {const dropdown = document.getElementById('notification-dropdown');dropdown.classList.toggle('show');}// 添加通知function addNotification(message, type = 'info') {const now = new Date();const timeStr = now.toLocaleTimeString();const notificationList = document.getElementById('notification-list');const notificationItem = document.createElement('div');notificationItem.className = `notification-item ${type}`;notificationItem.innerHTML = `<div class="notification-time">${timeStr}</div><div class="notification-content">${message}</div>`;notificationList.insertBefore(notificationItem, notificationList.firstChild);// 更新通知计数updateNotificationCount();}// 添加随机通知function addRandomNotification() {const notifications = [{ message: '系统自检完成,所有模块工作正常', type: 'info' },{ message: '温度数据波动性增加,建议检查环境稳定性', type: 'warning' },{ message: '数据备份已完成', type: 'info' },{ message: '压力传感器需要定期维护', type: 'warning' },{ message: '网络连接稳定性检查已完成', type: 'info' }];const randomNotification = notifications[Math.floor(Math.random() * notifications.length)];addNotification(randomNotification.message, randomNotification.type);}// 清除所有通知function clearNotifications() {document.getElementById('notification-list').innerHTML = '';updateNotificationCount();addNotification('所有通知已清除', 'info');}// 更新通知计数function updateNotificationCount() {const count = document.getElementById('notification-list').children.length;document.getElementById('notification-count').textContent = count;}// 设置标签页导航function setupTabNavigation() {const tabButtons = document.querySelectorAll('.tab-btn');const tabPanes = document.querySelectorAll('.tab-pane');tabButtons.forEach(button => {button.addEventListener('click', () => {const targetTab = button.dataset.tab;// 更新标签按钮状态tabButtons.forEach(btn => btn.classList.remove('active'));button.classList.add('active');// 更新内容面板tabPanes.forEach(pane => pane.classList.remove('active'));document.getElementById(`${targetTab}-tab`).classList.add('active');});});}// 更新数据点计数function updateDataPointCount() {const totalPoints = temperatureData.sensor1.length * 3 + pressureData.values.length;document.getElementById('data-points').textContent = totalPoints.toLocaleString();}// 更新采集时间function updateAcquisitionTime() {const element = document.getElementById('acquisition-time');const currentText = element.textContent;// 将当前时间文本解析为小时、分钟和秒const [hours, minutes, seconds] = currentText.split(':').map(Number);// 计算总秒数并增加1秒let totalSeconds = hours * 3600 + minutes * 60 + seconds + 1;// 将总秒数转换回时分秒格式const newHours = Math.floor(totalSeconds / 3600);totalSeconds %= 3600;const newMinutes = Math.floor(totalSeconds / 60);const newSeconds = totalSeconds % 60;// 更新显示element.textContent = `${String(newHours).padStart(2, '0')}:${String(newMinutes).padStart(2, '0')}:${String(newSeconds).padStart(2, '0')}`;}// 添加CSS动画addCSSAnimation();// 当DOM加载完成后初始化if (document.readyState === 'loading') {document.addEventListener('DOMContentLoaded', initLabMonitoringSystem);} else {initLabMonitoringSystem();}
})();
相关文章:
2、实验室测控系统 - /自动化与控制组件/lab-monitoring-system
76个工业组件库示例汇总 实验室测控系统开发组件 这是一个专为实验室设备数据采集与分析设计的可视化测控系统组件。采用工业风格界面设计,提供了丰富的动态数据展示与分析功能,可应用于各类实验室环境中的设备监控和数据处理。 功能特点 多设备管理…...
Blender插件机制设计与Python实现
Blender插件机制设计与Python实现 Blender的插件机制是其强大扩展性的核心,允许开发者通过Python创建自定义功能。下面我将详细介绍Blender插件系统的设计原理,并提供一个完整的示例。 Blender插件系统设计原理 模块化架构:Blender将插件作…...
自定义一个 Spring Boot Starter -笔记
SpringBoot Starter的介绍参考: Spring Boot Starter简介-笔记-CSDN博客。这里介绍如何自定义一个springBoot Starter。 1. 项目结构 创建一个 Maven 项目,结构如下: custom-spring-boot-starter-demo/ ├── custom-hello-jdk/ # jdk模…...
【Part 2安卓原生360°VR播放器开发实战】第三节|实现VR视频播放与时间轴同步控制
《VR 360全景视频开发》专栏 将带你深入探索从全景视频制作到Unity眼镜端应用开发的全流程技术。专栏内容涵盖安卓原生VR播放器开发、Unity VR视频渲染与手势交互、360全景视频制作与优化,以及高分辨率视频性能优化等实战技巧。 📝 希望通过这个专栏&am…...
读 书 说
好久没有坐下来手敲打字去输出或者记录分享一些比较正式的事情。 今天节后综合征,虽然我已经加了两天班了,但是还是不想加班便准点下班了。 今天来聊聊看书。 为什么会看书?最开始正如我之前提到过,人脉资源不多,也不…...
DOCX转PDF怎么操作最简单?快速将DOCX转换为专业PDF文档
在日常办公或学习中,我们经常需要将 Word 文档(.docx格式)转换为 PDF 文件。这不仅有助于保持文档格式的一致性,还能确保接收者无需特定软件即可查看文件内容。本文将详细介绍几种常见的方法来实现从 DOCX 到 PDF 的转换ÿ…...
免费轻量化办公pdf修改软件 一键格式转换基础修改到高级加密
各位办公软件小能手们!今天咱来聊聊一款超厉害的 PDF 编辑软件——PDFXEdit。你知道吗,这软件就像个 PDF 处理的超级魔法师,能全方位搞定 PDF 文档。下面我就给大家详细说说它的那些功能和适用场景。 首先是基础编辑功能。这软件在文本与图像…...
【HFP】蓝牙语音通信高级功能解析:快速拨号与呼叫等待协议实现
在蓝牙语音通信系统中,除了基础的通话建立与控制流程,高级功能如快速拨号(内存拨号、最后号码重拨)和呼叫等待通知的实现,直接影响着用户体验的便捷性与系统的实用性。这些功能依赖于蓝牙协议中特定的 AT 命令交互、状…...
CVE-2025-24813:Apache Tomcat RCE 漏洞分析
CVE-2025-24813 是 Apache Tomcat 中的一个严重远程代码执行 (RCE) 漏洞,源于路径等效缺陷,允许攻击者绕过安全约束并远程执行任意代码。 CYFIRMA 的研究发现了一些活跃的漏洞利用,一些 PoC 漏洞在地下论坛上流传。攻击者利用基于 HTTP PUT 的任意文件上传、NTFS 连接漏洞利…...
神经网络之训练的艺术:反向传播与常见问题解决之道
神经网络训练的艺术:反向传播与常见问题解决之道 摘要 神经网络是现代机器学习的核心工具之一,而反向传播则是其训练过程中不可或缺的算法。本文深入探讨了反向传播的工作原理以及在训练过程中常见的问题,如梯度消失、梯度爆炸、死 ReLU 单…...
小土堆pytorch--transform
torchvision中的transform torchvision中的transform1. transforms的使用1.1 transforms的结构及用法理论1.2 相应代码1.3 对上述代码的解释 2. 常见的transforms2.1 python 的call函数2.2 ToTensor的使用2.3 Normalize的使用2.4 Resize的使用2.5 Compose的使用2.6 RandomCrop的…...
【Django】REST 常用类
ModelSerializer serializers.ModelSerializer 是 Django REST framework(DRF)里的一个强大工具,它能极大简化序列化和反序列化 Django 模型实例的流程。下面从多个方面详细介绍它: 1. 基本概念 序列化是把 Django 模型实例转化…...
PyTorch常用命令详解:助力深度学习开发
📌 友情提示: 本文内容由银河易创AI(https://ai.eaigx.com)创作平台的gpt-4-turbo模型生成,旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证,建议读者通过官方文档或实践进一步确认其准…...
第二章 Logback的架构(二)
Logger, Appenders 和 Layouts Appenders 和 Layouts 基于日志记录器选择性地启用或禁用日志记录请求只是其中的一部分功能。Logback允许将日志记录请求输出到多个目标。在Logback术语中,输出目标被称为Appender。 目前,已经存在适用于控制台、文件、远…...
【大数据】服务器上部署Apache Paimon
1. 环境准备 在开始部署之前,请确保服务器满足以下基本要求: 操作系统: 推荐使用 Linux(如 Ubuntu、CentOS)。 Java 环境: Paimon 依赖 Java,推荐安装 JDK 8 或更高版本。 Flink 环境: Paimon 是基于 Apache Flink 的…...
【IP101】图像处理进阶:从直方图均衡化到伽马变换,全面掌握图像增强技术
🌟 图像增强魔法指南 🎨 在图像处理的世界里,增强就像是给图片化妆,让它展现出最佳的状态。让我们一起来探索这些神奇的增强术吧! 📚 目录 基础概念 - 图像增强的"美容院"直方图均衡化 - 光线的…...
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
问题描述 Azure Cache for Redis 服务在传输和存储数据时是如何加密呢? 问题回答 一:关于Azure cache for Redis服务在数据传输过程中是如何加密的? 为了确保在Azure cache for Redis和客户端应用程序之间传输的数据安全,需要启用…...
Cursor 被封解决方案
一、注册一个无限邮箱 没事点点广告,让网站活久一点(✪ω✪) 2925邮箱-无限邮2925无限邮箱支持多种客户端收发邮件且数据安全加密多端同步。只需要注册一个账号,就能生成无限多个2925子邮箱账号,同时利用一邮多用功能对多个子邮箱邮件进行集…...
spring上传文件添加水印
1、实现 MultipartFile package com.pojo.common.core.domain;import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream;import org.springframework.lang.Nullable; import org.springframework.util.Assert; im…...
CSS分栏布局
分栏布局将区域划分为若干垂直的栏,子元素放置到栏中,填满一个后再填充下一个。如果设置了 column-count 栏数量或 column-width 栏宽度,元素就成为分栏容器。需要注意, column-width 实际上是最小栏宽度。浏览器使用这个值计算栏…...
通过 ModernBERT 实现零样本分类的性能提升
文本分类 是机器学习中最基础的任务之一,拥有悠久的研究历史和深远的实用价值。更重要的是,它是许多实际项目中不可或缺的组成部分,从搜索引擎到生物医学研究都离不开它。文本分类方法被广泛应用于科学论文分类、用户工单分类、社交媒体情感分…...
【AI】Ubuntu 22.04 4060Ti 16G vllm-api部署Qwen3-8B-FP8
下载模型 # 非常重要,否则容易不兼容报错 pip install modelscope -U cd /data/ai/models modelscope download --model Qwen/Qwen3-8B-FP8 --local_dir ./Qwen3-8B-FP8 安装vllm 创建虚拟环境 mkdir vllm cd vllm/ python -m venv venv ource venv/bin/activat…...
QML ProgressBar控件详解
在 QML 中,ProgressBar 是一个常用的进度条控件,用于显示任务的完成进度。以下是 ProgressBar 的详细用法,包括基本用法、自定义样式、动态绑定数据等。 1. 基本用法 1.1 最简单的 ProgressBar import QtQuick.Controls 2.15ProgressBar {w…...
STM32教程:串口USART通讯协议原理及分析(基于STM32F103C8T6最小系统板标准库开发)*详细教程*
前言: 本文主要介绍了单片机的通讯协议和STM32的串口USART通讯的原理及分析。 通信的目的 将一个设备的数据传送到另一个设备,扩展硬件系统。 通信协议 指定通信的规则,通信双方按照协议规则进行数据收发。 STM32常见通讯协议 各通讯特点 USART: TX(发送)、RX(接…...
EDA文件
不同的EDA软件使用不同的文件扩展名和格式,以下是主流工具对应的文件类型: EDA软件文件扩展名说明Altium Designer.PcbDocAltium专属格式,需用原软件打开,可导出为Gerber或STEP文件用于生产。KiCad.kicad_pcbKiCad项目文件&#…...
【C/C++】构造函数与析构函数
📘 C 构造函数与析构函数详解笔记 🧠 为什么需要构造函数与析构函数? 在 C 中,对象创建和销毁过程如果仅靠手动赋值和清理非常容易出错。为此,语言提供了构造函数和析构函数: 构造函数:用于在…...
在Unity AR应用中实现摄像头切换功能
本教程将详细讲解如何在Unity AR Foundation项目中实现前后摄像头切换功能,并提供完整的代码解析。我们将使用AR Foundation的核心组件和简单的UI交互来实现这一功能。 第一部分:环境准备 1.1 所需组件 Unity 2019.4或更高版本 AR Foundation 4.0+ ARCore XR Plugin(Andro…...
Pycharm(十九)深度学习
一、深度学习概述 1.1 什么是深度学习 深度学习是机器学习中的一种特殊方法,它使用称为神经网络的复杂结构,特别是“深层”的神经网络,来学习和做出预测。深度学习特别适合处理大规模和高维度的数据,如图像、声音和文本。深度学习、机器学习和人工智能之间的关系如下图所…...
状态模式 VS 策略模式
在软件开发的世界里,设计模式如同工匠手中的精良工具,能帮助开发者打造出结构清晰、易于维护和扩展的软件系统。状态模式和策略模式便是其中两个常用却容易让人混淆的设计模式。接下来,我们会详细剖析它们的区别、适用场景,并给出…...
如何在 Ubuntu 24.04 本地安装 DeepSeek ?
在本地 Ubuntu 系统上安装 DeepSeek 可以让您在本地使用高级 AI 功能,从而消除对云服务的依赖需求。 What is DeepSeek? DeepSeek 是一个先进的开源人工智能模型,专为自然语言理解和生成而设计。它提供了类似ChatGPT的强大功能。 Prerequisites: A …...
云计算训练营笔记day02(Linux、计算机网络、进制)
Linux 是一个操作系统 Linux版本 RedHat Rocky Linux CentOS7 Linux Ubuntu Linux Debian Linux Deepin Linux 登录用户 管理员 root a 普通用户 nsd a 打开终端 放大: ctrl shift 缩小: ctrl - 命令行提示符 [rootlocalhost ~]# ~ 家目录 /root 当前登录的用户…...
数据库实验10 函数存储
数据库实验10 一、实验目的 掌握函数和存储过程的定义方法,包括标量函数、表值函数、存储过程的语法结构。理解函数和存储过程的作用及原理,区分标量函数与表值函数的应用场景,掌握存储过程的参数传递、逻辑控制和错误处理机制。能够熟练运…...
SQL Server执行安装python环境
安装注意事项 启用python脚本支持 sp_configure external scripts enabled, 1; RECONFIGURE; 安装后接受 Python EULA协议 接受python授权 setup.exe /qs /ACTIONInstall /FEATURESSQL_INST_MR /INSTANCENAME您的实例名 /IACCEPTROPENLICENSETERMS1 /IACCEPTPYTHONLICENSETE…...
ActiveMQ 安全机制与企业级实践(二)
四、企业级实践案例分析 4.1 案例背景介绍 某大型电商企业拥有复杂的分布式系统,涵盖订单管理、库存管理、物流配送、用户服务等多个核心业务模块。在业务快速发展过程中,系统间的通信量呈爆发式增长,为了实现系统的高效解耦和异步通信&…...
ActiveMQ 安全机制与企业级实践(一)
一、引言 在当今数字化时代,企业级应用的架构愈发复杂,各个系统之间的通信和协作变得至关重要。消息队列作为一种高效的异步通信机制,在企业级应用集成中扮演着关键角色。ActiveMQ 作为一款广泛使用的开源消息中间件,以其丰富的功…...
【Python pass 语句】
在 Python 中,pass 语句是一个特殊的空操作(no-op)语句,它的核心作用是保持程序结构的完整性,同时不执行任何实际操作。以下是详细说明: 一、基础特性 语法占位符:当语法上需要一条语句&#x…...
Maven依赖未生效问题
在你描述的情况下,测试类无法找到 Maven 依赖的 jar 包,可能由以下原因导致: 依赖未正确添加到 pom.xml 检查 pom.xml 文件中是否正确添加了 Elasticsearch 和 JUnit 等相关依赖。例如,对于 Elasticsearch 的 TransportClient 相关…...
NGINX `ngx_http_auth_request_module` 模块详解基于子请求的认证授权方案
一、背景介绍 在 Web 系统中,我们常常需要根据外部服务(例如单点登录、API 网关、权限中心)的结果来判断用户是否有权限访问某个资源。NGINX 提供的 ngx_http_auth_request_module 模块,正是为这种场景而生。它允许通过向后端发送…...
Qwen3简要介绍(截止20250506)
Qwen3是阿里云推出的一个大语言模型系列,它在多个方面进行了升级和优化。以下是Qwen3的一些主要特点: 模型规模多样:Qwen3提供了一系列不同规模的模型,包括稠密模型(0.6B、1.7B、4B、8B、14B、32B)以及专家…...
精益数据分析(42/126):移动应用商业模式的深度剖析与实战要点
精益数据分析(42/126):移动应用商业模式的深度剖析与实战要点 在创业和数据分析的学习之路上,我们持续探索不同商业模式的奥秘,今天聚焦于移动应用商业模式。我希望和大家一起进步,深入解读《精益数据分析…...
2025.5.6总结
昨天12:30睡觉,结果翻来覆去睡不着,两点半左右才睡着。看了一下最近的睡眠打卡,平均入睡时间是凌晨12:30。 自五一一个人过了5天,我才明白,人是需要社交的,只有在社交中才能找到自我…...
UE5 脚部贴地不穿过地板方案
UE自带的IK RIG和ControlRig技术 【UE5】角色脚部IK——如何让脚贴在不同斜度的地面(设置脚的旋转)_哔哩哔哩_bilibili 实验后这个还是有一部分问题,首先只能保证高度不能穿过,但是脚步旋转还是会导致穿模 IK前,整个模型在斜坡上会浮空 参考制作:https://www.youtube.com/w…...
Spring AI 函数调用(Function Call)系统设计方案
一、系统概述与设计目标 1.1 核心目标 从零构建一个灵活、安全、高效的函数调用系统,使大语言模型能够在对话中调用应用程序中的方法,同时保持良好的开发体验和企业级特性。 1.2 主要功能需求 支持通过注解将普通Java方法标记为可被AI调用的函数自动生成符合LLM要求的函数…...
Jupyter Notebook为什么适合数据分析?
Jupyter Notebook 是一款超实用的 Web 应用程序,在数据科学、编程等诸多领域都发挥着重要作用。它最大的特点就是能让大家轻松创建和共享文学化程序文档。这里说的文学化程序文档,简单来讲,就是把代码、解释说明、数学公式以及数据可视化结果…...
Leetcode Hot 100字母异位词分词
题目描述 思路 根据题意,我们可以得知我们需要将字符统计数一样的字符串,放在一起,并以列表进行返回。因此我们可以通过一个哈希表,把统计相同的放在一起,最终返回即可 代码 class Solution:def groupAnagrams(self…...
用python实现鼠标监听与手势交互
摘要 本文探讨了一种基于Python的数学函数可视化系统的设计与实现,该系统整合了Pynput鼠标事件监听机制、Matplotlib绘图引擎以及PyQt5图形用户界面框架。系统通过人机交互方式实现了函数图像的直观构建与可视化表达,支持多种函数类型的参数化建模与实时…...
UE5 GAS开发P47 游戏标签
FGameplayTag 是 Unreal Engine 中用于标记游戏对象的系统。它允许开发者为游戏对象分配标签,以便在游戏中对其进行分类、识别和操作。 FGameplayTag 结构用于表示单个游戏标签,而 FGameplayTagContainer 则用于表示一组游戏标签。 这些标签可以用于诸…...
C# 实现PLC数据自动化定时采集与存储(无需界面,自动化运行)
C# 实现PLC数据自动化定时采集与存储(无需界面,自动化运行) 在平时开发中,我们时常会遇到需要后台静默运行的应用场景,这些程序不需要用户的直接操作或界面展示,而是专注于定时任务的执行。比如说…...
Java实现堆排序算法
1. 堆排序原理图解 堆排序是一种基于二叉堆(通常使用最大堆)的排序算法。其核心思想是利用堆的性质(父节点的值大于或等于子节点的值)来高效地进行排序。堆排序分为两个主要阶段:建堆和排序。 堆排序步骤: …...
封装axios,实现取消请求
封装axios import axios from axios// 创建自定义的请求类 class CancelableRequest {constructor() {this.controller new AbortController()}abort() {this.controller.abort()} }// 创建 axios 实例 const service axios.create({baseURL: process.env.VUE_APP_BASE_API,…...