文章目录[隐藏]
WordPress小批量定制插件与物联网设备集成开发教程
概述:WordPress与物联网的融合
在当今数字化时代,将内容管理系统与物联网设备集成已成为许多企业的需求。WordPress作为全球最流行的CMS平台,通过定制插件可以与各种物联网设备进行通信,实现数据采集、设备控制和状态监控等功能。本教程将指导您开发一个WordPress插件,用于小批量物联网设备集成,特别适合中小型企业或特定场景应用。
开发环境准备
在开始开发之前,请确保您的环境满足以下要求:
- WordPress 5.0+ 安装
- PHP 7.4+ 运行环境
- MySQL 5.6+ 或 MariaDB 10.1+
- 支持HTTPS的服务器环境(物联网通信安全需要)
- 基本的PHP和JavaScript知识
插件基础结构创建
首先,我们创建插件的基本文件结构:
iot-device-integration/
├── iot-device-integration.php # 主插件文件
├── includes/
│ ├── class-device-manager.php # 设备管理类
│ ├── class-api-handler.php # API处理类
│ └── class-data-processor.php # 数据处理类
├── admin/
│ ├── css/
│ │ └── admin-style.css # 后台样式
│ ├── js/
│ │ └── admin-script.js # 后台脚本
│ └── partials/
│ └── admin-display.php # 后台界面
├── public/
│ ├── css/
│ │ └── public-style.css # 前台样式
│ ├── js/
│ │ └── public-script.js # 前台脚本
│ └── partials/
│ └── public-display.php # 前台显示
└── uninstall.php # 卸载清理脚本
主插件文件开发
创建主插件文件 iot-device-integration.php:
<?php
/**
* Plugin Name: IoT设备集成插件
* Plugin URI: https://yourwebsite.com/iot-plugin
* Description: 小批量物联网设备与WordPress集成解决方案
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: iot-device-integration
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('IOT_PLUGIN_VERSION', '1.0.0');
define('IOT_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('IOT_PLUGIN_URL', plugin_dir_url(__FILE__));
define('IOT_PLUGIN_BASENAME', plugin_basename(__FILE__));
// 自动加载类文件
spl_autoload_register(function ($class_name) {
$prefix = 'IOT_';
$base_dir = IOT_PLUGIN_PATH . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class_name, $len) !== 0) {
return;
}
$relative_class = substr($class_name, $len);
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// 初始化插件
class IoT_Device_Integration {
private static $instance = null;
private $device_manager;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->load_dependencies();
$this->init_hooks();
}
private function load_dependencies() {
require_once IOT_PLUGIN_PATH . 'includes/class-device-manager.php';
require_once IOT_PLUGIN_PATH . 'includes/class-api-handler.php';
require_once IOT_PLUGIN_PATH . 'includes/class-data-processor.php';
$this->device_manager = new IOT_Device_Manager();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate_plugin'));
register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin'));
// 初始化钩子
add_action('init', array($this, 'init_plugin'));
// 后台菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载文本域
add_action('plugins_loaded', array($this, 'load_textdomain'));
}
public function activate_plugin() {
// 创建必要的数据库表
$this->create_database_tables();
// 设置默认选项
$this->set_default_options();
// 刷新重写规则
flush_rewrite_rules();
}
public function deactivate_plugin() {
// 清理临时数据
// 注意:这里不删除用户数据
flush_rewrite_rules();
}
private function create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'iot_devices';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
device_id varchar(100) NOT NULL,
device_name varchar(255) NOT NULL,
device_type varchar(100) NOT NULL,
api_key varchar(255) NOT NULL,
status varchar(50) DEFAULT 'inactive',
last_seen datetime DEFAULT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY device_id (device_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
private function set_default_options() {
if (!get_option('iot_plugin_settings')) {
$default_settings = array(
'api_enabled' => true,
'api_auth_required' => true,
'data_retention_days' => 30,
'max_devices' => 50,
'debug_mode' => false
);
update_option('iot_plugin_settings', $default_settings);
}
}
public function init_plugin() {
// 初始化API处理器
$api_handler = new IOT_API_Handler();
$api_handler->register_routes();
}
public function add_admin_menu() {
add_menu_page(
'IoT设备管理',
'IoT设备',
'manage_options',
'iot-devices',
array($this, 'display_admin_page'),
'dashicons-admin-generic',
30
);
add_submenu_page(
'iot-devices',
'设备设置',
'设置',
'manage_options',
'iot-device-settings',
array($this, 'display_settings_page')
);
}
public function display_admin_page() {
include_once IOT_PLUGIN_PATH . 'admin/partials/admin-display.php';
}
public function display_settings_page() {
include_once IOT_PLUGIN_PATH . 'admin/partials/settings-display.php';
}
public function load_textdomain() {
load_plugin_textdomain(
'iot-device-integration',
false,
dirname(IOT_PLUGIN_BASENAME) . '/languages'
);
}
}
// 启动插件
function iot_device_integration_init() {
return IoT_Device_Integration::get_instance();
}
// 延迟初始化以确保WordPress完全加载
add_action('plugins_loaded', 'iot_device_integration_init');
设备管理类实现
创建 includes/class-device-manager.php:
<?php
/**
* 物联网设备管理类
* 负责设备的CRUD操作和状态管理
*/
class IOT_Device_Manager {
private $table_name;
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'iot_devices';
}
/**
* 添加新设备
* @param array $device_data 设备数据
* @return int|false 设备ID或false
*/
public function add_device($device_data) {
global $wpdb;
$defaults = array(
'device_id' => '',
'device_name' => '',
'device_type' => 'sensor',
'api_key' => $this->generate_api_key(),
'status' => 'inactive',
'last_seen' => current_time('mysql')
);
$data = wp_parse_args($device_data, $defaults);
// 验证必要字段
if (empty($data['device_id']) || empty($data['device_name'])) {
return false;
}
// 检查设备是否已存在
if ($this->device_exists($data['device_id'])) {
return false;
}
$result = $wpdb->insert(
$this->table_name,
$data,
array('%s', '%s', '%s', '%s', '%s', '%s')
);
if ($result) {
return $wpdb->insert_id;
}
return false;
}
/**
* 更新设备最后在线时间
* @param string $device_id 设备ID
* @return bool 是否成功
*/
public function update_device_heartbeat($device_id) {
global $wpdb;
return $wpdb->update(
$this->table_name,
array(
'last_seen' => current_time('mysql'),
'status' => 'active'
),
array('device_id' => $device_id),
array('%s', '%s'),
array('%s')
);
}
/**
* 获取所有设备
* @return array 设备列表
*/
public function get_all_devices() {
global $wpdb;
$query = "SELECT * FROM {$this->table_name} ORDER BY created_at DESC";
return $wpdb->get_results($query, ARRAY_A);
}
/**
* 通过设备ID获取设备
* @param string $device_id 设备ID
* @return array|null 设备数据或null
*/
public function get_device_by_id($device_id) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT * FROM {$this->table_name} WHERE device_id = %s",
$device_id
);
return $wpdb->get_row($query, ARRAY_A);
}
/**
* 验证API密钥
* @param string $device_id 设备ID
* @param string $api_key API密钥
* @return bool 是否验证通过
*/
public function validate_api_key($device_id, $api_key) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table_name}
WHERE device_id = %s AND api_key = %s",
$device_id,
$api_key
);
$count = $wpdb->get_var($query);
return $count > 0;
}
/**
* 检查设备是否存在
* @param string $device_id 设备ID
* @return bool 是否存在
*/
private function device_exists($device_id) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table_name} WHERE device_id = %s",
$device_id
);
$count = $wpdb->get_var($query);
return $count > 0;
}
/**
* 生成API密钥
* @return string 生成的API密钥
*/
private function generate_api_key() {
return 'iot_' . bin2hex(random_bytes(16));
}
}
REST API处理器开发
创建 includes/class-api-handler.php:
<?php
/**
* REST API处理器
* 处理物联网设备的HTTP请求
*/
class IOT_API_Handler {
private $namespace = 'iot/v1';
public function register_routes() {
add_action('rest_api_init', array($this, 'register_api_routes'));
}
public function register_api_routes() {
// 设备数据上报端点
register_rest_route($this->namespace, '/data/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'POST',
'callback' => array($this, 'handle_data_submission'),
'permission_callback' => array($this, 'verify_api_key'),
'args' => array(
'device_id' => array(
'required' => true,
'validate_callback' => function($param) {
return is_string($param) && strlen($param) <= 100;
}
),
),
));
// 设备状态查询端点
register_rest_route($this->namespace, '/status/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_device_status'),
'permission_callback' => array($this, 'verify_api_key'),
));
// 命令下发端点
register_rest_route($this->namespace, '/command/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'POST',
'callback' => array($this, 'send_command'),
'permission_callback' => array($this, 'verify_api_key'),
));
}
/**
* 处理设备数据上报
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function handle_data_submission(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$data = $request->get_json_params();
// 更新设备心跳
$device_manager = new IOT_Device_Manager();
$device_manager->update_device_heartbeat($device_id);
// 处理接收到的数据
$processor = new IOT_Data_Processor();
$result = $processor->process_device_data($device_id, $data);
if ($result) {
return new WP_REST_Response(array(
'success' => true,
'message' => '数据接收成功',
'timestamp' => current_time('timestamp'),
'data_id' => $result
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '数据处理失败'
), 500);
}
}
/**
* 获取设备状态
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function get_device_status(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$device_manager = new IOT_Device_Manager();
$device = $device_manager->get_device_by_id($device_id);
if ($device) {
return new WP_REST_Response(array(
'success' => true,
'device' => $device
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '设备未找到'
), 404);
}
}
/**
* 发送命令到设备
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function send_command(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$command = $request->get_json_params();
// 这里可以实现命令队列或直接发送到设备
// 示例:将命令存储到数据库供设备拉取
$result = $this->store_command_for_device($device_id, $command);
if ($result) {
return new WP_REST_Response(array(
'success' => true,
'message' => '命令已接收',
'command_id' => $result
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '命令处理失败'
), 500);
}
}
/**
* 验证API密钥
* @param WP_REST_Request $request 请求对象
* @return bool 是否验证通过
*/
public function verify_api_key(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$api_key = $request->get_header('X-API-Key');
if (empty($api_key)) {
return false;
}
$device_manager = new IOT_Device_Manager();
return $device_manager->validate_api_key($device_id, $api_key);
}
/**
* 存储设备命令
* @param string $device_id 设备ID
* @param array $command 命令数据
* @return int|false 命令ID或false
*/
private function store_command_for_device($device_id, $command) {
global $wpdb;
$table_name = $wpdb->prefix . 'iot_commands';
$data = array(
'device_id' => $device_id,
'command' => json_encode($command),
'status' => 'pending',
'created_at' => current_time('mysql')
);
$result = $wpdb->insert(
$table_name,
$data,
%s', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
}
## 数据处理类实现
创建 `includes/class-data-processor.php`:
<?php
/**
- 物联网数据处理类
- 负责处理、存储和分析设备数据
*/
class IOT_Data_Processor {
private $data_table;
public function __construct() {
global $wpdb;
$this->data_table = $wpdb->prefix . 'iot_device_data';
// 确保数据表存在
$this->create_data_table();
}
/**
* 创建设备数据表
*/
private function create_data_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->data_table} (
id bigint(20) NOT NULL AUTO_INCREMENT,
device_id varchar(100) NOT NULL,
data_type varchar(50) NOT NULL,
value text NOT NULL,
unit varchar(20) DEFAULT NULL,
recorded_at datetime DEFAULT CURRENT_TIMESTAMP,
processed tinyint(1) DEFAULT 0,
PRIMARY KEY (id),
KEY device_id (device_id),
KEY data_type (data_type),
KEY recorded_at (recorded_at)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 处理设备数据
* @param string $device_id 设备ID
* @param array $data 设备数据
* @return int|false 数据ID或false
*/
public function process_device_data($device_id, $data) {
global $wpdb;
// 验证数据格式
if (!$this->validate_data($data)) {
error_log('无效的设备数据格式: ' . json_encode($data));
return false;
}
// 存储原始数据
$data_id = $this->store_raw_data($device_id, $data);
if (!$data_id) {
return false;
}
// 根据数据类型进行特定处理
$this->process_by_data_type($device_id, $data);
// 触发数据处理的钩子
do_action('iot_device_data_processed', $device_id, $data, $data_id);
return $data_id;
}
/**
* 存储原始数据
* @param string $device_id 设备ID
* @param array $data 设备数据
* @return int|false 数据ID或false
*/
private function store_raw_data($device_id, $data) {
global $wpdb;
$insert_data = array(
'device_id' => $device_id,
'data_type' => $data['type'] ?? 'unknown',
'value' => json_encode($data),
'unit' => $data['unit'] ?? null,
'recorded_at' => current_time('mysql')
);
$result = $wpdb->insert(
$this->data_table,
$insert_data,
array('%s', '%s', '%s', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
/**
* 根据数据类型进行特定处理
* @param string $device_id 设备ID
* @param array $data 设备数据
*/
private function process_by_data_type($device_id, $data) {
$data_type = $data['type'] ?? 'unknown';
switch ($data_type) {
case 'temperature':
$this->process_temperature_data($device_id, $data);
break;
case 'humidity':
$this->process_humidity_data($device_id, $data);
break;
case 'pressure':
$this->process_pressure_data($device_id, $data);
break;
case 'custom':
$this->process_custom_data($device_id, $data);
break;
default:
// 通用数据处理
$this->log_generic_data($device_id, $data);
break;
}
}
/**
* 处理温度数据
* @param string $device_id 设备ID
* @param array $data 温度数据
*/
private function process_temperature_data($device_id, $data) {
$temperature = floatval($data['value']);
// 检查温度是否超出阈值
$thresholds = get_option('iot_temperature_thresholds', array(
'min' => 10,
'max' => 35
));
if ($temperature < $thresholds['min'] || $temperature > $thresholds['max']) {
// 触发警报
$this->trigger_alert($device_id, 'temperature', $temperature, $thresholds);
}
// 更新设备的最新温度
update_option("iot_device_{$device_id}_last_temperature", array(
'value' => $temperature,
'timestamp' => current_time('timestamp'),
'unit' => $data['unit'] ?? '°C'
));
}
/**
* 处理湿度数据
* @param string $device_id 设备ID
* @param array $data 湿度数据
*/
private function process_humidity_data($device_id, $data) {
$humidity = floatval($data['value']);
// 更新设备的最新湿度
update_option("iot_device_{$device_id}_last_humidity", array(
'value' => $humidity,
'timestamp' => current_time('timestamp'),
'unit' => $data['unit'] ?? '%'
));
}
/**
* 触发警报
* @param string $device_id 设备ID
* @param string $type 数据类型
* @param mixed $value 当前值
* @param array $thresholds 阈值
*/
private function trigger_alert($device_id, $type, $value, $thresholds) {
$alert_data = array(
'device_id' => $device_id,
'alert_type' => $type . '_threshold',
'current_value' => $value,
'threshold_min' => $thresholds['min'],
'threshold_max' => $thresholds['max'],
'timestamp' => current_time('mysql'),
'status' => 'active'
);
// 存储警报
$this->store_alert($alert_data);
// 发送通知
$this->send_alert_notification($alert_data);
}
/**
* 存储警报
* @param array $alert_data 警报数据
*/
private function store_alert($alert_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'iot_alerts';
$wpdb->insert(
$table_name,
$alert_data,
array('%s', '%s', '%f', '%f', '%f', '%s', '%s')
);
}
/**
* 发送警报通知
* @param array $alert_data 警报数据
*/
private function send_alert_notification($alert_data) {
// 获取管理员邮箱
$admin_email = get_option('admin_email');
$subject = sprintf(
'[IoT警报] 设备 %s 的%s超出阈值',
$alert_data['device_id'],
$alert_data['alert_type']
);
$message = sprintf(
"设备ID: %sn警报类型: %sn当前值: %sn阈值范围: %s - %sn时间: %s",
$alert_data['device_id'],
$alert_data['alert_type'],
$alert_data['current_value'],
$alert_data['threshold_min'],
$alert_data['threshold_max'],
$alert_data['timestamp']
);
// 发送邮件
wp_mail($admin_email, $subject, $message);
// 触发WordPress动作,允许其他插件处理警报
do_action('iot_alert_triggered', $alert_data);
}
/**
* 验证数据格式
* @param array $data 设备数据
* @return bool 是否有效
*/
private function validate_data($data) {
if (!is_array($data) || empty($data)) {
return false;
}
// 检查必要字段
if (!isset($data['value'])) {
return false;
}
return true;
}
/**
* 获取设备历史数据
* @param string $device_id 设备ID
* @param string $data_type 数据类型
* @param int $limit 数据条数限制
* @return array 历史数据
*/
public function get_device_history($device_id, $data_type = null, $limit = 100) {
global $wpdb;
$query = "SELECT * FROM {$this->data_table}
WHERE device_id = %s";
$params = array($device_id);
if ($data_type) {
$query .= " AND data_type = %s";
$params[] = $data_type;
}
$query .= " ORDER BY recorded_at DESC LIMIT %d";
$params[] = $limit;
$prepared_query = $wpdb->prepare($query, $params);
return $wpdb->get_results($prepared_query, ARRAY_A);
}
}
## 后台管理界面开发
创建 `admin/partials/admin-display.php`:
<?php
/**
- 后台管理界面
- 显示设备列表和管理功能
*/
// 检查用户权限
if (!current_user_can('manage_options')) {
wp_die(__('您没有足够的权限访问此页面。', 'iot-device-integration'));
}
// 获取设备管理器实例
$device_manager = new IOT_Device_Manager();
$devices = $device_manager->get_all_devices();
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['iot_action'])) {
$this->handle_admin_form_submission($_POST);
}
// 获取插件设置
$settings = get_option('iot_plugin_settings', array());
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="iot-admin-container">
<!-- 设备概览卡片 -->
<div class="iot-overview-cards">
<div class="iot-card">
<h3>总设备数</h3>
<p class="iot-card-number"><?php echo count($devices); ?></p>
</div>
<div class="iot-card">
<h3>在线设备</h3>
<p class="iot-card-number">
<?php
$active_count = 0;
foreach ($devices as $device) {
if ($device['status'] === 'active') {
$active_count++;
}
}
echo $active_count;
?>
</p>
</div>
<div class="iot-card">
<h3>最大设备数</h3>
<p class="iot-card-number"><?php echo esc_html($settings['max_devices'] ?? 50); ?></p>
</div>
</div>
<!-- 添加新设备表单 -->
<div class="iot-add-device-form">
<h2>添加新设备</h2>
<form method="post" action="">
<?php wp_nonce_field('iot_add_device', 'iot_nonce'); ?>
<input type="hidden" name="iot_action" value="add_device">
<table class="form-table">
<tr>
<th scope="row">
<label for="device_id">设备ID</label>
</th>
<td>
<input type="text" id="device_id" name="device_id"
class="regular-text" required>
<p class="description">设备的唯一标识符</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="device_name">设备名称</label>
</th>
<td>
<input type="text" id="device_name" name="device_name"
class="regular-text" required>
</td>
</tr>
<tr>
<th scope="row">
<label for="device_type">设备类型</label>
</th>
<td>
<select id="device_type" name="device_type" class="regular-text">
<option value="sensor">传感器</option>
<option value="actuator">执行器</option>
<option value="gateway">网关</option>
<option value="controller">控制器</option>
</select>
</td>
</tr>
</table>
<?php submit_button('添加设备'); ?>
</form>
</div>
<!-- 设备列表表格 -->
<div class="iot-device-list">
<h2>设备列表</h2>
<?php if (empty($devices)): ?>
<p>暂无设备,请添加新设备。</p>
<?php else: ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>设备ID</th>
<th>设备名称</th>
<th>类型</th>
<th>状态</th>
<th>最后在线</th>
<th>API密钥</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($devices as $device): ?>
<tr>
<td><?php echo esc_html($device['device_id']); ?></td>
<td><?php echo esc_html($device['device_name']); ?></td>
<td><?php echo esc_html($device['device_type']); ?></td>
<td>
<span class="iot-status-badge iot-status-<?php echo esc_attr($device['status']); ?>">
<?php
$status_labels = array(
'active' => '在线',
'inactive' => '离线',
'error' => '错误'
);
echo esc_html($status_labels[$device['status']] ?? $device['status']);
?>
</span>
</td>
<td>
<?php
if ($device['last_seen']) {
$last_seen = strtotime($device['last_seen']);
$time_diff = human_time_diff($last_seen, current_time('timestamp'));
echo sprintf(__('%s前', 'iot-device-integration'), $time_diff);
} else {
echo '从未';
}
?>
</td>
<td>
<code class="iot-api-key"><?php echo esc_html($device['api_key']); ?></code>
<button type="button" class="button button-small iot-copy-api-key"
data-api-key="<?php echo esc_attr($device['api_key']); ?>">
复制
</button>
</td>
<td>
<div class="iot-action-buttons">
<button type="button" class="button button-small iot-view-data"
data-device-id="<?php echo esc_attr($device['device_id']); ?>">
查看数据
</button>
<form method="post" style="display: inline;">
<?php wp_nonce_field('iot_remove_device', 'iot_nonce'); ?>
<input type="hidden" name="iot_action" value="remove_device">
<input type="hidden" name="device_id" value="<?php echo esc_attr($device['device_id']); ?>">
<button type="submit" class="button button-small button-danger"
onclick="return confirm('确定要删除此设备吗?');">
删除
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<!-- 数据查看模态框 -->
<div id="iot-data-modal" class="iot-modal" style="display: none;">
<div class="iot-modal-content">
<div class="iot-modal-header">
<h3>设备数据</h3>
<span class="iot-modal-close">×</span>
</div>
<div class="iot-modal-body">
<div id="iot-data-chart" style="height: 300px;"></div>
<div id="iot-data-table"></div>
</div>
</div>
</div>
</div>
</div>
<style>
.iot-admin-container {
margin-top: 20px;
}
.iot-overview-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.iot-card {
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
text-align: center;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.iot-card h3 {
margin-top: 0;
color: #23282d;
}
.iot-card-number {
font-size: 2em;
font-weight: bold;
color: #0073aa;
margin: 10px 0 0;
}
.iot-status-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 12px;
font-weight: 600;
}
.iot-status-active {
background-color: #d4edda;
color: #155724;
}
.iot-status-inactive {
background-color: #f8d7da;
color: #721c24;
}
.iot-status-error {
background-color: #fff3cd;
color: #856404;
}
.iot-api-key {
background: #f1f
