liusuyi
2026-05-18 b5cd784d0cde5b7c82ea78aef4ac0e5a161d8c5d
优化
13 files modified
1335 ■■■■ changed files
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/config/AgentConfig.java 85 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/config/SaaLLMConfig.java 13 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/controller/AIController.java 3 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/service/AIChatService.java 143 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/dh/service/DaHuaSDK.java 16 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/factory/CameraSDKFactory.java 63 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/fjr/service/FjrSDK.java 15 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hb/service/HbSDK.java 14 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hik/service/AbstractHikVisionSDK.java 136 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hp/service/HpSDK.java 20 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/service/CameraSDK.java 13 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/service/CameraSDKService.java 799 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/zlxd/service/ZlxdSDK.java 15 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/config/AgentConfig.java
@@ -3,73 +3,64 @@
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.hook.modelcalllimit.ModelCallLimitHook;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.ard.agent.tool.KnowledgeTools;
import com.ard.agent.tool.MonitorTools;
import com.ard.agent.tool.SystemTools;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentConfig {
    @Resource
    @Qualifier("ollamaChatModel")
    @Resource(name = "dashScopeChatModel")
    private ChatModel chatModel;
    @Resource
    private MonitorTools monitorTools;
    @Resource
    private ChatMemory chatMemory;  // 注入聊天记忆
    private SystemTools systemTools;
    @Resource
    private KnowledgeTools knowledgeTools;
    private static final String UNIFIED_AGENT_PROMPT = """
            你是 ARD 智能业务助手,能使用摄像机管理、系统管理和知识库工具。
    // 增强版的系统提示词,专门为 ReAct 模式优化
    private static final String SYSTEM_PROMPT = """
            你是摄像头管理助手,拥有调用工具和查询知识库的能力。
            ## 工作方式
            你需要通过「思考 → 行动 → 观察」的循环来完成任务:
            1. **思考 (Thought)**:分析用户需求,判断下一步该做什么
            2. **行动 (Action)**:决定调用哪个工具
               - getCameraDetail: 查询单个摄像机详情
               - searchCameras: 按条件搜索摄像机
               - updateCameraInfo: 修改摄像机信息
               - 知识库查询: 获取操作指南/故障排查手册
            3. **观察 (Observation)**:分析工具返回的结果
            4. **重复**:直到获得足够信息回答用户
            ## 工具使用原则
            - 涉及摄像机实时状态、修改操作 → 必须调用工具
            - 询问操作指南、故障排查 → 使用知识库
            - 复杂任务需要多个步骤时,自动规划并依次调用工具
            ## 路由原则
            - 查询或修改摄像机:使用摄像机工具。
            - 查询人员、部门、组织架构:使用系统工具。
            - 查询说明书、制度、操作指南、故障排查:使用知识库工具。
            - 复合问题可以连续调用多个工具,再综合回答。
            ## 约束
            - 业务数据必须来自工具调用结果。
            - 修改类操作要在回答中明确修改对象和结果。
            - 无法确认的数据要直接说明,不要编造。
            ## 输出格式
            使用 Markdown 格式输出:
            - ## 标题
            - - 列表项
            - **加粗** 强调
            - 表格用于数据展示
            ## 重要提醒
            不要编造信息,所有数据必须来自工具调用或知识库。
            使用 Markdown,给出清晰结论和下一步建议。
            """;
    ModelCallLimitHook hook = ModelCallLimitHook.builder()
            .runLimit(5)  // 限制最多调用 5 次
            .exitBehavior(ModelCallLimitHook.ExitBehavior.ERROR)  // 超出限制时抛出异常
    private final ModelCallLimitHook modelCallLimitHook = ModelCallLimitHook.builder()
            .runLimit(8)
            .exitBehavior(ModelCallLimitHook.ExitBehavior.ERROR)
            .build();
    @Bean
    public ReactAgent cameraAgent() {
    @Bean("unifiedAgent")
    public ReactAgent unifiedAgent() {
        return buildAgent("unifiedAgent", UNIFIED_AGENT_PROMPT, monitorTools, systemTools, knowledgeTools);
    }
    private ReactAgent buildAgent(String name, String instruction, Object... tools) {
        return ReactAgent.builder()
                .name("cameraAgent") // Agent 的名称
                .model(chatModel)      // 设置底层的大语言模型
                .hooks(hook)
                .instruction(SYSTEM_PROMPT) // 系统提示词,定义角色和行为
                .tools(ToolCallbacks.from(monitorTools))       // 注册可用的工具
                .saver(new MemorySaver())      // 2. 核心:用 MemorySaver 实现记忆
                .enableLogging(true)   // 开启日志,方便调试观察思考过程
                .name(name)
                .model(chatModel)
                .hooks(modelCallLimitHook)
                .instruction(instruction)
                .tools(ToolCallbacks.from(tools))
                .saver(new MemorySaver())
                .enableLogging(true)
                .build();
    }
}
}
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/config/SaaLLMConfig.java
@@ -6,7 +6,6 @@
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@@ -18,21 +17,21 @@
public class SaaLLMConfig {
    /**
     * 创建一个命名的 ChatClient(基于 dashScopeChatModel)
     * 名称为 "dashScopeChatClient"
     * 创建一个默认 ChatClient(基于 Spring AI Alibaba DashScope)
     */
    //@Primary
    @Bean("dashScopeChatClient")
    public ChatClient dashScopeChatClient(@Qualifier("dashScopeChatModel") ChatModel dashScopeChatModel,
                                          ChatMemory chatMemory) {
        return ChatClient.builder(dashScopeChatModel)
                .defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
                .defaultAdvisors(
                        MessageChatMemoryAdvisor.builder(chatMemory).build(),
                        SimpleLoggerAdvisor.builder().build())
                .build();
    }
    /**
     * 创建一个命名的 ChatClient(基于 dashScopeChatModel)
     * 名称为 "dashScopeChatClient"
     * 本地 Ollama ChatClient,保留为离线或本地模型兜底使用。
     */
    @Primary
    @Bean("ollamaChatClient")
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/controller/AIController.java
@@ -5,7 +5,6 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@@ -27,4 +26,4 @@
    public String chat(@RequestParam String message) throws GraphRunnerException {
        return aiChatService.chat(message);
    }
}
}
ard-modules/ard-modules-agent/src/main/java/com/ard/agent/service/AIChatService.java
@@ -2,24 +2,12 @@
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.ard.agent.tool.KnowledgeTools;
import com.ard.agent.tool.MonitorTools;
import com.ard.agent.tool.SystemTools;
import com.ard.common.security.utils.SecurityUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Content;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
@@ -27,110 +15,15 @@
@Service
public class AIChatService {
    @Resource
    private ChatClient chatClient;
    @Resource
    @Qualifier("ollamaChatModel")
    private ChatModel chatModel;
    @Resource
    private SystemTools systemTools;  // 注入工具类
    @Resource
    private MonitorTools monitorTools;  // 注入工具类
    @Resource
    private KnowledgeTools knowledgeTools;
    @Resource
    private ReactAgent cameraAgent; // 注入配置好的 Agent
    private static final String SYSTEM_PROMPT = """
        你是摄像头管理助手。请严格遵守以下规则:
        1. **工具优先原则**:当用户问题涉及摄像机的实时状态、修改操作、查询具体设备信息时,
           必须调用对应的工具(getCameraDetail/searchCameras/updateCameraInfo),
           绝对不要使用自己的记忆或上下文中的静态文本来回答。
        2. **知识库使用场景**:只有当用户询问操作指南、故障排查手册、产品说明等静态知识时,
           才使用知识库中的内容。
        3. **冲突处理**:如果知识库中提到了某类操作,但用户要求执行具体操作,
           必须以工具调用的结果为准。
        ========== 输出格式 ==========
        使用 Markdown 格式输出:
        - ## 标题
        - - 列表项
        - **加粗** 强调
        - 表格用于数据展示
        """;
    @Resource(name = "unifiedAgent")
    private ReactAgent unifiedAgent;
    /**
     * 流式对话
     * 唯一流式聊天入口
     */
    public Flux<String> streamChat(String userMessage) {
        Long userId = SecurityUtils.getUserId();
        return chatClient.prompt()
                .system(SYSTEM_PROMPT)
                .user(userMessage)
                .advisors(advisor -> advisor.param("chat_memory_conversation_id", userId))
                .tools(systemTools,monitorTools, knowledgeTools)
                .stream()
                .content();
    }
    /**
     * 对话服务入口
     */
    public String chat(String userMessage) throws GraphRunnerException {
        Long userId = SecurityUtils.getUserId();
        // 1. 为每个用户创建唯一的 threadId
        RunnableConfig config = RunnableConfig.builder()
                .threadId(userId.toString()) // 比如从 SecurityUtils.getUserId() 获取
                .build();
        // 3. 调用 Agent 的 call 方法并执行
        AssistantMessage response = cameraAgent.call(userMessage,config);
        // 4. 从响应中提取文本内容
        return response.getText();
    }
    private static final String SYSTEM_PROMPT1 = """
            你是智能管理助手,拥有以下能力:
            ## 可用工具
            ### 摄像头管理
            - getCameraDetail: 查询摄像机详情
            - searchCameras: 搜索摄像机
            - updateCameraInfo: 修改摄像机信息
            ### 系统管理
            - searchUsers: 搜索用户
            - searchDepts: 搜索部门
            - searchRoles: 搜索角色
            - getUserRoles: 查询用户角色
            ### 知识库
            - searchKnowledgeBase: 查询知识文档
            ## 原则
            1. 根据问题自动选择工具
            2. 数据必须来自工具调用
            3. 用 Markdown 格式回复
            """;
    /**
     * 流式聊天
     */
    public Flux<String> streamChat1(String userMessage) {
        Long userId = SecurityUtils.getUserId();
        RunnableConfig config = RunnableConfig.builder()
                .threadId(userId.toString())
                .build();
        ReactAgent agent = ReactAgent.builder()
                .name("UnifiedAgent")
                .model(chatModel)
                .instruction(SYSTEM_PROMPT1)
                .tools(ToolCallbacks.from(monitorTools, systemTools, knowledgeTools))
                .saver(new MemorySaver())
                .build();
        try {
            return agent.streamMessages(userMessage, config)
            return unifiedAgent.streamMessages(userMessage, runnableConfig())
                    .filter(msg -> msg instanceof AssistantMessage)
                    .map(Content::getText)
                    .doOnError(error -> log.error("Agent执行出错: {}", error.getMessage()));
@@ -138,4 +31,28 @@
            throw new RuntimeException(e);
        }
    }
}
    /**
     * 唯一同步聊天入口
     */
    public String chat(String userMessage) throws GraphRunnerException {
        AssistantMessage response = unifiedAgent.call(userMessage, runnableConfig());
        return response.getText();
    }
    private RunnableConfig runnableConfig() {
        return RunnableConfig.builder()
                .threadId(currentThreadId())
                .build();
    }
    private String currentThreadId() {
        Long userId;
        try {
            userId = SecurityUtils.getUserId();
        } catch (Exception e) {
            userId = null;
        }
        return userId == null ? "anonymous" : userId.toString();
    }
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/dh/service/DaHuaSDK.java
@@ -380,11 +380,6 @@
    }
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
        return getPtz(cmd);
    }
    @Override
    public PtzScope getPtzScope(CameraCmd cmd) {
        NetSDKLib.LLong loginId = new LLong(cmd.getLoginId());
        NET_PRODUCTION_DEFNITION productionDefinition = new NET_PRODUCTION_DEFNITION();
@@ -400,17 +395,6 @@
        ptzScope.setTMax((float) productionDefinition.nPtzVerticalAngleMax);
        ptzScope.setTMin((float) productionDefinition.nPtzVerticalAngleMin);
        return ptzScope;
    }
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
        return setPtz(cmd);
    }
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
        return setPtz(cmd);
    }
    //设置ptz信息
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/factory/CameraSDKFactory.java
@@ -3,14 +3,13 @@
import com.ard.work.sdk.dh.service.DaHuaSDK;
import com.ard.work.sdk.fjr.service.FjrSDK;
import com.ard.work.sdk.hb.service.HbSDK;
import com.ard.work.sdk.hik.service.AbstractHikVisionSDK;
import com.ard.work.sdk.hik.service.HikSDK;
import com.ard.work.sdk.hp.service.HpSDK;
import com.ard.work.sdk.service.CameraSDK;
import com.ard.work.sdk.zlxd.service.ZlxdSDK;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
@@ -22,29 +21,24 @@
@Component
public class CameraSDKFactory {
    @Autowired
    @Qualifier("hikSDK")
    private HikSDK hikSDK;
    private final Map<String, CameraSDK> sdkRegistry;
    @Autowired
    @Qualifier("dahuaSDK")
    private DaHuaSDK dahuaSDK;
    public CameraSDKFactory(HikSDK hikSDK,
                            DaHuaSDK dahuaSDK,
                            HpSDK hpSDK,
                            ZlxdSDK zlxdSDK,
                            HbSDK hbSDK,
                            FjrSDK fjrSDK) {
        this.sdkRegistry = Map.of(
                "1", hikSDK,
                "2", dahuaSDK,
                "4", zlxdSDK,
                "5", hpSDK,
                "7", hbSDK,
                "8", fjrSDK
        );
    }
    @Autowired
    @Qualifier("hpSDK")
    private HpSDK hpSDK;
    @Autowired
    @Qualifier("zlxdSDK")
    private ZlxdSDK zlxdSDK;
    @Autowired
    @Qualifier("hbSDK")
    private HbSDK hbSDK;
    @Autowired
    @Qualifier("fjrSDK")
    private FjrSDK fjrSDK;
    /**
     * 根据传入的工厂参数创建相应的相机SDK实例
     *
@@ -53,21 +47,10 @@
     * @throws IllegalArgumentException 如果传入的工厂参数不支持
     */
    public CameraSDK createCameraSDK(String factory) {
        switch (factory) {
            case "1":
                return hikSDK;
            case "2":
                return dahuaSDK;
            case "4":
                return zlxdSDK;
            case "5":
                return hpSDK;
            case "7":
                return hbSDK;
            case "8":
                return fjrSDK;
            default:
                throw new IllegalArgumentException("Unsupported device: " + factory);
        CameraSDK sdk = sdkRegistry.get(factory);
        if (sdk == null) {
            throw new IllegalArgumentException("Unsupported camera factory: " + factory);
        }
        return sdk;
    }
}
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/fjr/service/FjrSDK.java
@@ -241,27 +241,12 @@
    }
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
        return null;
    }
    @Override
    public PtzScope getPtzScope(CameraCmd cmd) {
        return null;
    }
    @Override
    public Boolean setPtz(CameraCmd cmd) {
        return true;
    }
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
        return true;
    }
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
        return true;
    }
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hb/service/HbSDK.java
@@ -415,10 +415,6 @@
        return null;
    }
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
        return null;
    }
    @Override
    public PtzScope getPtzScope(CameraCmd cmd) {
@@ -427,16 +423,6 @@
    @Override
    public Boolean setPtz(CameraCmd cmd) {
        return true;
    }
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
        return true;
    }
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
        return true;
    }
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hik/service/AbstractHikVisionSDK.java
@@ -41,6 +41,7 @@
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;
import java.awt.geom.Point2D;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -703,34 +704,41 @@
        String cameraId = cmd.getCameraId();
        Integer chanNo = cmd.getChanNo();
        int userId = cmd.getLoginId().intValue();
        NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
        Pointer point = m_ptzPosCurrent.getPointer();
        IntByReference ibrBytesReturned = new IntByReference(0);
        m_ptzPosCurrent.write();
        boolean bool = hCNetSDK.NET_DVR_GetDVRConfig(userId, HCNetSDK.NET_DVR_GET_PTZPOS, chanNo, point,
                m_ptzPosCurrent.size(), ibrBytesReturned);
        if (!bool) {
            int errorCode = hCNetSDK.NET_DVR_GetLastError();
            String errorDesc = SdkErrorCodeEnum.getDescByCode(errorCode);
            String errorMsg = String.format("获取ptz失败,错误码:%s,原因:%s", errorCode, errorDesc);
            log.warn(errorMsg);
            return null;
        ArdCamera camera = getCamera(cameraId);
        if ("1".equals(camera.getType())) {
            return getPtzHigh(cmd);
        } else {
            NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
            Pointer point = m_ptzPosCurrent.getPointer();
            IntByReference ibrBytesReturned = new IntByReference(0);
            m_ptzPosCurrent.write();
            boolean bool = hCNetSDK.NET_DVR_GetDVRConfig(userId, HCNetSDK.NET_DVR_GET_PTZPOS, chanNo, point,
                    m_ptzPosCurrent.size(), ibrBytesReturned);
            if (!bool) {
                int errorCode = hCNetSDK.NET_DVR_GetLastError();
                String errorDesc = SdkErrorCodeEnum.getDescByCode(errorCode);
                String errorMsg = String.format("获取ptz失败,错误码:%s,原因:%s", errorCode, errorDesc);
                log.warn(errorMsg);
                return null;
            }
            m_ptzPosCurrent.read();
            // DecimalFormat df = new DecimalFormat("0.0");//设置保留位数
            //16进制转Integer后除10,保留小数点1位
            //实际显示的PTZ值是获取到的十六进制值的十分之一,
            //如获取的水平参数P的值是0x1750,实际显示的P值为175度;
            //获取到的垂直参数T的值是0x0789,实际显示的T值为78.9度;
            //获取到的变倍参数Z的值是0x1100,实际显示的Z值为110倍。
            BigDecimal b =
                    BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wPanPos)) / 10);
            BigDecimal c =
                    BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wTiltPos)) / 10);
            BigDecimal d =
                    BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wZoomPos)) / 10);
            float p = b.setScale(1, RoundingMode.HALF_UP).floatValue();
            float t = c.setScale(1, RoundingMode.HALF_UP).floatValue();
            float z = d.setScale(1, RoundingMode.HALF_UP).floatValue();
            return new PtzDto(p, t, z);
        }
        m_ptzPosCurrent.read();
        // DecimalFormat df = new DecimalFormat("0.0");//设置保留位数
        //16进制转Integer后除10,保留小数点1位
        //实际显示的PTZ值是获取到的十六进制值的十分之一,
        //如获取的水平参数P的值是0x1750,实际显示的P值为175度;
        //获取到的垂直参数T的值是0x0789,实际显示的T值为78.9度;
        //获取到的变倍参数Z的值是0x1100,实际显示的Z值为110倍。
        BigDecimal b = BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wPanPos)) / 10);
        BigDecimal c = BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wTiltPos)) / 10);
        BigDecimal d = BigDecimal.valueOf((float) Integer.parseInt(Integer.toHexString(m_ptzPosCurrent.wZoomPos)) / 10);
        float p = b.setScale(1, RoundingMode.HALF_UP).floatValue();
        float t = c.setScale(1, RoundingMode.HALF_UP).floatValue();
        float z = d.setScale(1, RoundingMode.HALF_UP).floatValue();
        return new PtzDto(p, t, z);
    }
    /**
@@ -741,8 +749,7 @@
     * @author 刘苏义
     * @date 2024/9/5 17:00
     */
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
    private PtzDto getPtzHigh(CameraCmd cmd) {
        try {
            String cameraId = cmd.getCameraId();
            Integer chanNo = cmd.getChanNo();
@@ -796,30 +803,39 @@
        Integer channelNum = cmd.getChanNo();
        PtzDto ptzDto = cmd.getPtzDto();
        int userId = cmd.getLoginId().intValue();
        NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
        m_ptzPosCurrent.wAction = 1;
        try {
            String p = String.valueOf((int) (ptzDto.getP() * 10));
            String t = String.valueOf((int) (ptzDto.getT() * 10));
            String z = String.valueOf((int) (ptzDto.getZ() * 10));
            m_ptzPosCurrent.wPanPos = (short) (Integer.parseInt(p, 16));
            m_ptzPosCurrent.wTiltPos = (short) (Integer.parseInt(t, 16));
            m_ptzPosCurrent.wZoomPos = (short) (Integer.parseInt(z, 16));
            Pointer point = m_ptzPosCurrent.getPointer();
            m_ptzPosCurrent.write();
            boolean bool = hCNetSDK.NET_DVR_SetDVRConfig(userId, NET_DVR_SET_PTZPOS, channelNum, point,
                    m_ptzPosCurrent.size());
            if (!bool) {
                int errorCode = hCNetSDK.NET_DVR_GetLastError();
                String errorDesc = SdkErrorCodeEnum.getDescByCode(errorCode);
                String errorMsg = String.format("设置PTZ参数失败,错误码:%s,原因:%s", errorCode, errorDesc);
                log.warn(errorMsg);
        ArdCamera camera = getCamera(cameraId);
        if ("1".equals(camera.getType())) {
            DeviceCFG systemInfo = getSystemInfo(cmd);
            if (systemInfo != null && "5.5.112".equals(systemInfo.getDwSoftwareVersion())) {
                return setPtzHighT(cmd);
            }
            return setPtzHigh(cmd);
        } else {
            NET_DVR_PTZPOS m_ptzPosCurrent = new NET_DVR_PTZPOS();
            m_ptzPosCurrent.wAction = 1;
            try {
                String p = String.valueOf((int) (ptzDto.getP() * 10));
                String t = String.valueOf((int) (ptzDto.getT() * 10));
                String z = String.valueOf((int) (ptzDto.getZ() * 10));
                m_ptzPosCurrent.wPanPos = (short) (Integer.parseInt(p, 16));
                m_ptzPosCurrent.wTiltPos = (short) (Integer.parseInt(t, 16));
                m_ptzPosCurrent.wZoomPos = (short) (Integer.parseInt(z, 16));
                Pointer point = m_ptzPosCurrent.getPointer();
                m_ptzPosCurrent.write();
                boolean bool = hCNetSDK.NET_DVR_SetDVRConfig(userId, NET_DVR_SET_PTZPOS, channelNum, point,
                        m_ptzPosCurrent.size());
                if (!bool) {
                    int errorCode = hCNetSDK.NET_DVR_GetLastError();
                    String errorDesc = SdkErrorCodeEnum.getDescByCode(errorCode);
                    String errorMsg = String.format("设置PTZ参数失败,错误码:%s,原因:%s", errorCode, errorDesc);
                    log.warn(errorMsg);
                    return false;
                }
                return true;
            } catch (Exception ex) {
                log.error(ex.getMessage());
                return false;
            }
            return true;
        } catch (Exception ex) {
            log.error(ex.getMessage());
            return false;
        }
    }
@@ -832,8 +848,7 @@
     * @author 刘苏义
     * @date 2024/9/5 17:04
     */
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
    private Boolean setPtzHighT(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        Integer chanNo = cmd.getChanNo();
        PtzDto ptzDto = cmd.getPtzDto();
@@ -893,8 +908,7 @@
    }
    //非透传 旧设备使用 新固件会导致2通道不自动聚焦
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
    private Boolean setPtzHigh(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        Integer chanNo = cmd.getChanNo();
        PtzDto ptzDto = cmd.getPtzDto();
@@ -1842,6 +1856,7 @@
            return false;
        }
    }
    @Override
    public String recordStop(CameraCmd cmd) {
        String url = "";
@@ -2434,4 +2449,15 @@
            return true;
        }
    }
    /**
     * 获取相机信息(会校验存在性)
     */
    private ArdCamera getCamera(String cameraId) {
        ArdCamera camera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId);
        if (camera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        return camera;
    }
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hp/service/HpSDK.java
@@ -1080,12 +1080,6 @@
        return ptzDto;
    }
    //获取高精度ptz信息
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
        return getPtz(cmd);
    }
    //设置ptz信息
    @Override
    public Boolean setPtz(CameraCmd cmd) {
@@ -1211,18 +1205,6 @@
        return bytes;
    }
    //设置高精度ptz信息
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
        return setPtz(cmd);
    }
    //非透传 旧设备使用 新固件会导致2通道不自动聚焦
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
        return setPtz(cmd);
    }
    //设置零方位角
    @Override
    public Boolean setZeroPtz(CameraCmd cmd) {
@@ -1285,7 +1267,7 @@
        targetPositions.validate(); // 校验目标位置
        PtzDto targetPTZ = GisUtil.getCameraPTZ(cameraPosition, targetPositions, 20, 150);
        //若为车载光电,需要根据修改P值
        if (ardCamera.getType().equals("4")) {
        if ("4".equals(ardCamera.getType())) {
            targetPTZ.setP((targetPTZ.getP() - baseYaw + 360) % 360);
        }
        // pt校验范围
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/service/CameraSDK.java
@@ -85,20 +85,11 @@
    //获取ptz
    PtzDto getPtz(CameraCmd cmd);
    //获取高精度PTZ
    PtzDto getPtzHigh(CameraCmd cmd);
    //获取ptz范围
    PtzScope getPtzScope(CameraCmd cmd);
    //设置ptz(不支持2通道的Z值设置和获取)
    //设置ptz
    Boolean setPtz(CameraCmd cmd);
    //设置ptz(高精度ptz设置)
    Boolean setPtzHigh(CameraCmd cmd);
    //设置ptz(高精度ptz透传设置)
    Boolean setPtzHighT(CameraCmd cmd);
    //设置零方位角
    Boolean setZeroPtz(CameraCmd cmd);
@@ -130,6 +121,6 @@
    //获取系统信息
    DeviceCFG getSystemInfo(CameraCmd cmd);
    List<Map<String, Object>> getCameraVideoLable( Long userId, CameraCmd cmd)throws ServiceException;
    List<Map<String, Object>> getCameraVideoLable(Long userId, CameraCmd cmd) throws ServiceException;
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/service/CameraSDKService.java
@@ -18,22 +18,15 @@
import com.ard.work.utils.gis.GisUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * @Description: 相机sdk业务
 * @ClassName: CameraSdkServiceImpl
 * @Author: 刘苏义
 * @Date: 2023年10月16日15:21:01
 **/
@Service
@Slf4j
public class CameraSDKService {
@@ -45,7 +38,8 @@
    @Resource
    private IArdNoViewingZoneService ardNoViewingZoneService;
    //登录
    // ========== 基础操作 ==========
    @Async("cameraSdkExecutor")
    public void login(ArdCamera ardCamera) {
        if (ardCamera == null) {
@@ -55,708 +49,212 @@
        sdk.login(ardCamera);
    }
    //注销
    public void logout(String cameraId) {
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId);
        if (ardCamera == null) {
        if (ardCamera == null || ardCamera.getFactory() == null) {
            return;
        }
        if(ardCamera.getFactory()!= null) {
            CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCamera.getFactory());
            cameraSDK.logout(cameraId);
        }
        CameraSDK sdk = cameraSDKFactory.createCameraSDK(ardCamera.getFactory());
        sdk.logout(cameraId);
    }
    // ========== 简单操作(一行搞定) ==========
    //在线检测
    public boolean isOnLine(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId);
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cameraId);
        if (loginId == null) {
            return false;
        }
        cmd.setLoginId(loginId);
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCamera.getFactory());
        return cameraSDK.isOnLine(cmd);
    }
    //云台控制
    @SdkOperate
    public Boolean pTZControl(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        // 调用各厂商 SDK 方法,异常由各自 SDK 实现抛出
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCamera.getFactory());
        return cameraSDK.pTZControl(cmd);
        return getSdk(cmd).pTZControl(cmd);
    }
    //设置聚焦值
    public Boolean setFocusPos(CameraCmd cmd) {
        // 1️⃣ 获取相机信息
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        // 3️⃣ 调用对应厂商 SDK
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.setFocusPos(cmd);
        return getSdk(cmd).setFocusPos(cmd);
    }
    //获取聚焦值
    public Integer getFocusPos(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getFocusPos(cmd);
        return getSdk(cmd).getFocusPos(cmd);
    }
    //设置预置位
    public Boolean setPreset(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.setPreset(cmd);
        return getSdk(cmd).setPreset(cmd);
    }
    //调用预置位
    public Boolean gotoPreset(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.gotoPreset(cmd);
        return getSdk(cmd).gotoPreset(cmd);
    }
    //获取码流压缩参数
    public VideoCompressionCfg getVideoCompressionCfg(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getVideoCompressionCfg(cmd);
        return getSdk(cmd).getVideoCompressionCfg(cmd);
    }
    //透雾开关
    public Boolean controlDefog(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.controlDefog(cmd);
        return getSdk(cmd).controlDefog(cmd);
    }
    //查询是否开启透雾
    public Boolean isEnableDefog(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.isEnableDefog(cmd);
        return getSdk(cmd).isEnableDefog(cmd);
    }
    //红外开关
    public Boolean controlInfrared(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.controlInfrared(cmd);
        return getSdk(cmd).controlInfrared(cmd);
    }
    //查询是否开启红外
    public Boolean isEnableInfrared(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.isEnableInfrared(cmd);
        return getSdk(cmd).isEnableInfrared(cmd);
    }
    //手动/自动聚焦
    public Boolean controlFocusMode(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.controlFocusMode(cmd);
        return getSdk(cmd).controlFocusMode(cmd);
    }
    //获取聚焦模式
    public Boolean getFocusMode(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getFocusMode(cmd);
        return getSdk(cmd).getFocusMode(cmd);
    }
    //云台加热
    public Boolean controlPTHeater(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.controlPTHeater(cmd);
        return getSdk(cmd).controlPTHeater(cmd);
    }
    //镜头加热
    public Boolean controlCameraDeicing(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.controlCameraDeicing(cmd);
        return getSdk(cmd).controlCameraDeicing(cmd);
    }
    //获取云台锁定信息
    public Boolean getPTZLockInfo(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getPTZLockInfo(cmd);
        return getSdk(cmd).getPTZLockInfo(cmd);
    }
    //设置云台锁定信息
    public Boolean setPTZLockInfo(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        boolean enable = cmd.isEnable();//0未锁 1锁定
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.setPTZLockInfo(cmd);
        return getSdk(cmd).setPTZLockInfo(cmd);
    }
    //本地抓图
    public byte[] localCapture(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.localCapture(cmd);
        return getSdk(cmd).localCapture(cmd);
    }
    //抓图
    @SdkOperate
    public String picCutCate(CameraCmd cmd) {
        //从redis中获取摄像头信息
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            return "";
        }
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            return "";
        }
        cmd.setLoginId(loginId);
        //获取摄像头工厂
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.picCutCate(cmd);
    }
    //抓图
    @SdkOperate
    public String picCutCate(CameraCmd cmd, String bucketName, String objectName) {
        String url = "";
        try {
            //从redis中获取摄像头信息
            ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
            if (ardCamera == null) {
                return "";
            }
            Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
            if (loginId == null) {
                return "";
            }
            cmd.setLoginId(loginId);
            //获取摄像头工厂
            String factory = ardCamera.getFactory();
            CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
            url = cameraSDK.picCutCate(cmd, bucketName, objectName);
        } catch (Exception ex) {
            log.error("抓图异常:{}", ex.getMessage());
        }
        return url;
    }
    //获取ptz
    public PtzDto getPtz(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        String type = ardCamera.getType();
        if ("1".equals(type)) {
            return cameraSDK.getPtzHigh(cmd);
        } else {
            return cameraSDK.getPtz(cmd);
        }
    }
    //获取ptz范围
    public PtzScope getPtzScope(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getPtzScope(cmd);
        return getSdk(cmd).getPtzScope(cmd);
    }
    //设置ptz
    public Boolean setZeroPtz(CameraCmd cmd) {
        return getSdk(cmd).setZeroPtz(cmd);
    }
    public Boolean set3DPosition(CameraCmd cmd) {
        return getSdk(cmd).set3DPosition(cmd);
    }
    public PtzParamDTO getGisInfo(CameraCmd cmd) {
        return getSdk(cmd).getGisInfo(cmd);
    }
    public Double correctPitch(CameraCmd cmd) {
        return getSdk(cmd).correctPitch(cmd);
    }
    // ========== 需要判断类型的操作 ==========
    public PtzDto getPtz(CameraCmd cmd) {
        return getSdk(cmd).getPtz(cmd);
    }
    @SdkOperate
    public Boolean setPtz(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCamera.getFactory());
        String type = ardCamera.getType();
        if ("1".equals(type)) {
            DeviceCFG systemInfo = cameraSDK.getSystemInfo(cmd);
            if (systemInfo != null && "5.5.112".equals(systemInfo.getDwSoftwareVersion())) {
                //大光电新固件使用高精度ptz透传设置
                return cameraSDK.setPtzHighT(cmd);
            } else {
                //使用高精度ptz设置
                return cameraSDK.setPtzHigh(cmd);
            }
        } else {
            return cameraSDK.setPtz(cmd);
        }
        return getSdk(cmd).setPtz(cmd);
    }
    //设置零方位角
    public Boolean setZeroPtz(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.setZeroPtz(cmd);
    }
    // ========== 抓图(重载方法) ==========
    //引导指向目标
    @SdkOperate
    public Boolean guideTargetPosition(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        //判断是否超出引导距离
        if (isOutMaxDistance(cameraId, cmd.getTargetPosition())) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.OVER_GUIDANCE_RANGE.getCode(), cameraId,
                    "目标超出最大引导距离");
        }
        //判断是否在不可视域
        if (isInNoViewingZone(cameraId, cmd.getTargetPosition())) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.BEYOND_VISIBILITY_RANGE.getCode(), cameraId
                    , "目标超出最大引导距离");
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        cmd.setBaseYaw(ardCamera.getBaseYaw());
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.guideTargetPosition(cmd);
    public String picCutCate(CameraCmd cmd) {
        return getSdk(cmd).picCutCate(cmd);
    }
    //判断坐标是否超出引导范围
    private Boolean isOutMaxDistance(String cameraId, Point targetPoint) {
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId);
        if (ardCamera == null) {
            log.error("设备不存在");
            return true;
        }
        Point cameraCoordinate = new Point(ardCamera.getLongitude(), ardCamera.getLatitude(), ardCamera.getAltitude());
        double distance = GisUtil.getDistance(cameraCoordinate, targetPoint);
        if (ardCamera.getCamMaxVisibleDistance() == null) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getCode(),
                    cameraId, CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getMsg());
        }
        double camMaxVisibleDistance = ardCamera.getCamMaxVisibleDistance();
        return distance > camMaxVisibleDistance;
    @SdkOperate
    public String picCutCate(CameraCmd cmd, String bucketName, String objectName) {
        return getSdk(cmd).picCutCate(cmd, bucketName, objectName);
    }
    //判断坐标是否在不可视域
    private Boolean isInNoViewingZone(String cameraId, Point targetPoint) {
        ArdNoViewingZone ardNoViewingZone = new ArdNoViewingZone();
        ardNoViewingZone.setCameraId(cameraId);
        List<ArdNoViewingZone> ardNoViewingZones =
                ardNoViewingZoneService.selectArdNoViewingZoneList(ardNoViewingZone);//获取相机的不可视域列表
        List<Point> pointList = new ArrayList<>();
        if (ardNoViewingZones.isEmpty()) {
            return false;
        }
        ardNoViewingZones.forEach(noViewingZone -> {
            String poi = noViewingZone.getPoi();
            String[] parts = poi.split(",");
            for (int i = 0; i < parts.length; i += 3) {
                Point point = new Point();
                point.setLongitude(Double.valueOf(parts[i]));
                point.setLatitude(Double.valueOf(parts[i + 1]));
                pointList.add(point);
            }
        });
        return GisUtil.isInPolygon(targetPoint, pointList);
    }
    //录像
    // ========== 录像 ==========
    public String record(CameraCmd cmd) {
        String url = "";
        try {
            ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
            if (ardCamera != null) {
                String factory = ardCamera.getFactory();
                CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
                url = cameraSDK.record(cmd);
            }
        } catch (Exception ex) {
            log.error("录像异常:{}", ex.getMessage());
        }
        return url;
        return getSdk(cmd).record(cmd);
    }
    //开始录像
    public Boolean recordStart(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        Boolean result = cameraSDK.recordStart(cmd);
        CameraSDK sdk = getSdk(cmd);
        Boolean result = sdk.recordStart(cmd);
        if (result != null && result) {
            RecordManager.addRecord(cmd.getCameraId() + "_" + cmd.getChanNo());
        }
        return result;
    }
    //停止录像并存入minio
    public String recordStop(CameraCmd cmd) {
        String url = "";
        try {
            ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
            if (ardCamera == null) {
                return url;
            }
            Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
            if (loginId == null) {
                return url;
            }
            cmd.setLoginId(loginId);
            String factory = ardCamera.getFactory();
            CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
            url = cameraSDK.recordStop(cmd);
            String key = cmd.getCameraId() + "_" + cmd.getChanNo();
            RecordManager.stopRecord(key);
        } catch (Exception ex) {
            log.error("停止录像异常:{}", ex.getMessage());
        }
        CameraSDK sdk = getSdk(cmd);
        String url = sdk.recordStop(cmd);
        String key = cmd.getCameraId() + "_" + cmd.getChanNo();
        RecordManager.stopRecord(key);
        return url;
    }
    // ========== 智能引导 ==========
    //获取相机架设参数
    public PtzParamDTO getGisInfo(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
    @SdkOperate
    public Boolean guideTargetPosition(CameraCmd cmd) {
        CameraSDK sdk = getSdk(cmd);
        ArdCamera camera = getCamera(cmd.getCameraId());
        String cameraId = camera.getId();
        // 判断是否超出引导距离
        if (isOutMaxDistance(cameraId, cmd.getTargetPosition())) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.OVER_GUIDANCE_RANGE.getCode(),
                    cameraId, "目标超出最大引导距离");
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        // 判断是否在不可视域
        if (isInNoViewingZone(cameraId, cmd.getTargetPosition())) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.BEYOND_VISIBILITY_RANGE.getCode(),
                    cameraId, "目标在不可视区域内");
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.getGisInfo(cmd);
        cmd.setBaseYaw(camera.getBaseYaw());
        return sdk.guideTargetPosition(cmd);
    }
    //获取相机通道信息
    // ========== 在线检测 ==========
    public boolean isOnLine(CameraCmd cmd) {
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            return false;
        }
        cmd.setLoginId(loginId);
        CameraSDK sdk = getSdk(cmd);
        return sdk.isOnLine(cmd);
    }
    // ========== 通道信息 ==========
    public List<ArdChannel> getChannels(ArdCamera camera) {
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, camera.getId());
        if (loginId == null) {
            return new ArrayList<>();
        }
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(camera.getFactory());
        return cameraSDK.getChannels(camera);
        CameraSDK sdk = cameraSDKFactory.createCameraSDK(camera.getFactory());
        return sdk.getChannels(camera);
    }
    //NET_DVR_PTZSelZoomIn
    public Boolean set3DPosition(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
    // ========== 视频标签 ==========
    public AjaxResult getCameraVideoLable(CameraCmd cmd) {
        CameraSDK sdk = cameraSDKFactory.createCameraSDK("1"); // 硬编码问题建议修复
        try {
            List<Map<String, Object>> result = sdk.getCameraVideoLable(SecurityUtils.getUserId(), cmd);
            return AjaxResult.success(result);
        } catch (ServiceException e) {
            return AjaxResult.error(e.getMessage());
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.set3DPosition(cmd);
    }
    //录像超时检查
    // ========== 定时任务 ==========
    @Scheduled(fixedRate = 30 * 1000)
    public void checkVideoTimeout() {
        Date now = new Date();
@@ -774,32 +272,69 @@
        });
    }
    //获取相机架设参数
    public Double correctPitch(CameraCmd cmd) {
        String cameraId = cmd.getCameraId();
        // 设备存在性检查
        ArdCamera ardCamera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cmd.getCameraId());
        if (ardCamera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
    // ========== 私有辅助方法 ==========
    /**
     * 获取SDK实例(会校验参数、相机存在性、在线状态)
     */
    private CameraSDK getSdk(CameraCmd cmd) {
        if (cmd == null || cmd.getCameraId() == null || cmd.getCameraId().isBlank()) {
            throw CameraSDKException.cameraNotExist(null);
        }
        // 设备在线检查
        Long loginId = redisService.getCacheMapValue(CacheConstants.CAMERA_ONLINE, cmd.getCameraId());
        if (loginId == null) {
            throw CameraSDKException.cameraOffline(cameraId);
            throw CameraSDKException.cameraOffline(cmd.getCameraId());
        }
        cmd.setLoginId(loginId);
        String factory = ardCamera.getFactory();
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(factory);
        return cameraSDK.correctPitch(cmd);
    }
    public AjaxResult getCameraVideoLable(CameraCmd cmd) {
        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK("1");
        try {
            List<Map<String, Object>>  r= cameraSDK.getCameraVideoLable(SecurityUtils.getUserId(), cmd);
            return AjaxResult.success(r);
        }catch (ServiceException e){
            return AjaxResult.error(e.getMessage());
        }
        ArdCamera camera = getCamera(cmd.getCameraId());
        return cameraSDKFactory.createCameraSDK(camera.getFactory());
    }
}
    /**
     * 获取相机信息(会校验存在性)
     */
    private ArdCamera getCamera(String cameraId) {
        ArdCamera camera = redisService.getCacheMapValue(CacheConstants.CAMERA_LIST, cameraId);
        if (camera == null) {
            throw CameraSDKException.cameraNotExist(cameraId);
        }
        return camera;
    }
    // 判断坐标是否超出引导范围
    private Boolean isOutMaxDistance(String cameraId, Point targetPoint) {
        ArdCamera camera = getCamera(cameraId);
        Point cameraCoordinate = new Point(camera.getLongitude(), camera.getLatitude(), camera.getAltitude());
        double distance = GisUtil.getDistance(cameraCoordinate, targetPoint);
        if (camera.getCamMaxVisibleDistance() == null) {
            throw new CameraSDKException(CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getCode(),
                    cameraId, CameraSDKException.ErrorCode.CAMERA_MAX_VISIBLE_DISTANCE_NULL.getMsg());
        }
        return distance > camera.getCamMaxVisibleDistance();
    }
    // 判断坐标是否在不可视域
    private Boolean isInNoViewingZone(String cameraId, Point targetPoint) {
        ArdNoViewingZone query = new ArdNoViewingZone();
        query.setCameraId(cameraId);
        List<ArdNoViewingZone> zones = ardNoViewingZoneService.selectArdNoViewingZoneList(query);
        if (zones.isEmpty()) {
            return false;
        }
        List<Point> points = new ArrayList<>();
        for (ArdNoViewingZone zone : zones) {
            String[] parts = zone.getPoi().split(",");
            for (int i = 0; i < parts.length; i += 3) {
                Point point = new Point();
                point.setLongitude(Double.valueOf(parts[i]));
                point.setLatitude(Double.valueOf(parts[i + 1]));
                points.add(point);
            }
        }
        return GisUtil.isInPolygon(targetPoint, points);
    }
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/zlxd/service/ZlxdSDK.java
@@ -863,11 +863,6 @@
    }
    @Override
    public PtzDto getPtzHigh(CameraCmd cmd) {
        return getPtz(cmd);
    }
    @Override
    public PtzScope getPtzScope(CameraCmd cmd) {
        PtzScope ptzScope = new PtzScope();
        ptzScope.setPMax(360f);
@@ -915,16 +910,6 @@
            log.error("设置ptz异常:{}", ex.getMessage());
            return false;
        }
    }
    @Override
    public Boolean setPtzHigh(CameraCmd cmd) {
        return setPtz(cmd);
    }
    @Override
    public Boolean setPtzHighT(CameraCmd cmd) {
        return setPtz(cmd);
    }
    @Override