device.php 6.69 KB
<?php
/**
 * 设备管理模块
 * 处理设备注册、绑定、状态管理
 */

class DeviceService
{
    private $pdo;
    private $config;

    public function __construct($pdo, $config)
    {
        $this->pdo = $pdo;
        $this->config = $config;
    }

    /**
     * 绑定设备到用户
     * @param int $userId 用户ID
     * @param string $deviceId 设备ID
     * @param string $deviceSecret 设备密钥 (可选验证)
     * @return array
     */
    public function bindDevice($userId, $deviceId, $deviceSecret = null)
    {
        // 1. 检查设备是否存在
        $stmt = $this->pdo->prepare("SELECT * FROM devices WHERE id = ?");
        $stmt->execute([$deviceId]);
        $device = $stmt->fetch();

        if (!$device) {
            return ['ok' => false, 'error' => '设备不存在'];
        }

        // 2. 验证设备密钥 (如果提供)
        if ($deviceSecret !== null && $device['secret'] !== $deviceSecret) {
            return ['ok' => false, 'error' => '设备密钥错误'];
        }

        // 3. 检查是否已绑定
        $stmt = $this->pdo->prepare("
            SELECT * FROM user_device_bindings 
            WHERE user_id = ? AND device_id = ?
        ");
        $stmt->execute([$userId, $deviceId]);
        if ($stmt->fetch()) {
            return ['ok' => false, 'error' => '设备已绑定'];
        }

        // 4. 检查用户是否有其他设备
        $stmt = $this->pdo->prepare("SELECT COUNT(*) FROM user_device_bindings WHERE user_id = ?");
        $stmt->execute([$userId]);
        $count = $stmt->fetchColumn();
        $isPrimary = ($count == 0) ? 1 : 0;

        // 5. 创建绑定
        $stmt = $this->pdo->prepare("
            INSERT INTO user_device_bindings (user_id, device_id, is_primary)
            VALUES (?, ?, ?)
        ");
        $stmt->execute([$userId, $deviceId, $isPrimary]);

        return [
            'ok' => true,
            'device' => [
                'id' => $device['id'],
                'name' => $device['name'],
                'status' => $device['status'],
                'is_primary' => (bool) $isPrimary,
            ]
        ];
    }

    /**
     * 解绑设备
     * @param int $userId 用户ID
     * @param string $deviceId 设备ID
     * @return array
     */
    public function unbindDevice($userId, $deviceId)
    {
        $stmt = $this->pdo->prepare("
            DELETE FROM user_device_bindings 
            WHERE user_id = ? AND device_id = ?
        ");
        $stmt->execute([$userId, $deviceId]);

        if ($stmt->rowCount() === 0) {
            return ['ok' => false, 'error' => '绑定关系不存在'];
        }

        return ['ok' => true];
    }

    /**
     * 获取用户的设备列表
     * @param int $userId 用户ID
     * @return array
     */
    public function getUserDevices($userId)
    {
        $stmt = $this->pdo->prepare("
            SELECT d.id, d.name, d.status, d.last_seen, b.is_primary, b.bound_at
            FROM user_device_bindings b
            JOIN devices d ON b.device_id = d.id
            WHERE b.user_id = ?
            ORDER BY b.is_primary DESC, b.bound_at ASC
        ");
        $stmt->execute([$userId]);
        return $stmt->fetchAll();
    }

    /**
     * 设置主设备
     * @param int $userId 用户ID
     * @param string $deviceId 设备ID
     * @return array
     */
    public function setPrimaryDevice($userId, $deviceId)
    {
        // 先取消所有主设备
        $stmt = $this->pdo->prepare("
            UPDATE user_device_bindings SET is_primary = 0 WHERE user_id = ?
        ");
        $stmt->execute([$userId]);

        // 设置新主设备
        $stmt = $this->pdo->prepare("
            UPDATE user_device_bindings SET is_primary = 1 
            WHERE user_id = ? AND device_id = ?
        ");
        $stmt->execute([$userId, $deviceId]);

        if ($stmt->rowCount() === 0) {
            return ['ok' => false, 'error' => '设备未绑定'];
        }

        return ['ok' => true];
    }

    /**
     * 更新设备状态
     * @param string $deviceId 设备ID
     * @param string $status online/offline
     * @return bool
     */
    public function updateDeviceStatus($deviceId, $status)
    {
        $stmt = $this->pdo->prepare("
            UPDATE devices SET status = ?, last_seen = NOW() WHERE id = ?
        ");
        $stmt->execute([$status, $deviceId]);
        return $stmt->rowCount() > 0;
    }

    /**
     * 注册新设备
     * @param string $deviceId 设备ID
     * @param string $secret 设备密钥
     * @param string $name 设备名称
     * @return array
     */
    public function registerDevice($deviceId, $secret, $name = null)
    {
        // 检查是否已存在
        $stmt = $this->pdo->prepare("SELECT * FROM devices WHERE id = ?");
        $stmt->execute([$deviceId]);
        if ($stmt->fetch()) {
            return ['ok' => false, 'error' => '设备ID已存在'];
        }

        // 创建设备
        $stmt = $this->pdo->prepare("
            INSERT INTO devices (id, secret, name, status)
            VALUES (?, ?, ?, 'offline')
        ");
        $stmt->execute([$deviceId, $secret, $name ?: '未命名设备']);

        return [
            'ok' => true,
            'device' => [
                'id' => $deviceId,
                'name' => $name ?: '未命名设备',
                'status' => 'offline',
            ]
        ];
    }

    /**
     * 验证设备连接
     * @param string $deviceId 设备ID
     * @param string $secret 设备密钥
     * @return bool
     */
    public function verifyDevice($deviceId, $secret)
    {
        $stmt = $this->pdo->prepare("SELECT secret FROM devices WHERE id = ?");
        $stmt->execute([$deviceId]);
        $device = $stmt->fetch();

        if (!$device) {
            return false;
        }

        return $device['secret'] === $secret;
    }

    /**
     * 获取设备的绑定用户
     * @param string $deviceId 设备ID
     * @return array 用户ID列表
     */
    public function getDeviceUsers($deviceId)
    {
        $stmt = $this->pdo->prepare("
            SELECT u.id, u.phone, u.nickname
            FROM user_device_bindings b
            JOIN users u ON b.user_id = u.id
            WHERE b.device_id = ?
        ");
        $stmt->execute([$deviceId]);
        return $stmt->fetchAll();
    }

    /**
     * 检查用户是否有权限访问设备
     * @param int $userId 用户ID
     * @param string $deviceId 设备ID
     * @return bool
     */
    public function canAccessDevice($userId, $deviceId)
    {
        $stmt = $this->pdo->prepare("
            SELECT 1 FROM user_device_bindings 
            WHERE user_id = ? AND device_id = ?
        ");
        $stmt->execute([$userId, $deviceId]);
        return (bool) $stmt->fetch();
    }
}