diff --git a/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/badge/BadgeDeviceStatusServiceImpl.java b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/badge/BadgeDeviceStatusServiceImpl.java
new file mode 100644
index 0000000..d65ac77
--- /dev/null
+++ b/viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/core/badge/BadgeDeviceStatusServiceImpl.java
@@ -0,0 +1,581 @@
+package com.viewsh.module.ops.core.badge;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
+import com.viewsh.module.ops.enums.BadgeDeviceStatusEnum;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * 工牌设备状态服务实现
+ *
+ * 基于 Redis Hash 存储设备状态,Set 维护区域设备索引
+ *
+ * @author lzh
+ */
+@Slf4j
+@Service
+public class BadgeDeviceStatusServiceImpl implements BadgeDeviceStatusService, InitializingBean {
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Resource
+ private ObjectMapper objectMapper;
+
+ /**
+ * Redis Key 前缀
+ */
+ private static final String BADGE_STATUS_KEY_PREFIX = "ops:badge:status:";
+ private static final String AREA_BADGES_KEY_PREFIX = "ops:area:badges:";
+
+ /**
+ * 心跳超时时间(分钟)
+ */
+ private static final int HEARTBEAT_TIMEOUT_MINUTES = 30;
+
+ /**
+ * 状态过期时间(小时)
+ */
+ private static final int STATUS_EXPIRE_HOURS = 24;
+
+ @Override
+ public void afterPropertiesSet() {
+ // 启动时初始化区域设备索引
+ initAreaDeviceIndex();
+ }
+
+ // ==================== 状态管理 ====================
+
+ @Override
+ public void updateBadgeStatus(Long deviceId, BadgeDeviceStatusEnum status, Long operatorId, String reason) {
+ if (deviceId == null || status == null) {
+ return;
+ }
+
+ try {
+ String key = BADGE_STATUS_KEY_PREFIX + deviceId;
+
+ // 获取当前状态
+ BadgeDeviceStatusDTO currentStatus = getBadgeStatus(deviceId);
+
+ // 验证状态转换
+ if (currentStatus != null && currentStatus.getStatus() != null) {
+ if (!currentStatus.getStatus().canTransitionTo(status)) {
+ log.warn("非法的状态转换: deviceId={}, from={}, to={}, reason={}",
+ deviceId, currentStatus.getStatus(), status, reason);
+ return;
+ }
+ }
+
+ // 更新状态
+ Map statusMap = new HashMap<>();
+ statusMap.put("deviceId", deviceId);
+ statusMap.put("status", status.getCode());
+ statusMap.put("statusChangeTime", LocalDateTime.now().toString());
+
+ if (currentStatus != null) {
+ statusMap.put("deviceCode", currentStatus.getDeviceCode());
+ statusMap.put("batteryLevel", currentStatus.getBatteryLevel());
+ statusMap.put("currentAreaId", currentStatus.getCurrentAreaId());
+ statusMap.put("currentAreaName", currentStatus.getCurrentAreaName());
+ statusMap.put("currentOpsOrderId", currentStatus.getCurrentOpsOrderId());
+ statusMap.put("lastHeartbeatTime", currentStatus.getLastHeartbeatTime());
+ }
+
+ redisTemplate.opsForHash().putAll(key, statusMap);
+ redisTemplate.expire(key, STATUS_EXPIRE_HOURS, TimeUnit.HOURS);
+
+ log.info("更新工牌设备状态: deviceId={}, status={}, operatorId={}, reason={}",
+ deviceId, status, operatorId, reason);
+
+ } catch (Exception e) {
+ log.error("更新工牌设备状态失败: deviceId={}, status={}", deviceId, status, e);
+ }
+ }
+
+ @Override
+ public void batchUpdateBadgeStatus(List deviceIds, BadgeDeviceStatusEnum status, Long operatorId, String reason) {
+ if (deviceIds == null || deviceIds.isEmpty() || status == null) {
+ return;
+ }
+
+ for (Long deviceId : deviceIds) {
+ updateBadgeStatus(deviceId, status, operatorId, reason);
+ }
+
+ log.info("批量更新工牌设备状态: count={}, status={}, operatorId={}", deviceIds.size(), status, operatorId);
+ }
+
+ // ==================== 状态查询 ====================
+
+ @Override
+ public BadgeDeviceStatusDTO getBadgeStatus(Long deviceId) {
+ if (deviceId == null) {
+ return null;
+ }
+
+ try {
+ String key = BADGE_STATUS_KEY_PREFIX + deviceId;
+ Map