1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package com.dy.pipIrrRemote.monitor.p202404V201.cd92;
 
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.dy.common.aop.SsoAop;
import com.dy.common.mw.protocol.Command;
import com.dy.common.mw.protocol.p206V202404.upVos.DataCd92_A2Vo;
import com.dy.common.util.Callback;
import com.dy.common.webUtil.BaseResponse;
import com.dy.common.webUtil.BaseResponseUtils;
import com.dy.pipIrrGlobal.voSe.VoVirtualCard;
import com.dy.pipIrrRemote.common.dto.DtoBase;
import com.dy.pipIrrRemote.monitor.common.ComCtrl;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
/**
 * @Author: liurunyu
 * @Date: 2025/5/13 08:33
 * @Description
 */
@Slf4j
@Tag(name = "远程命令", description = "平台远程开阀")
@RestController("cd92Ctrl")
@RequestMapping(path = "p202404V201/cd92")
@RequiredArgsConstructor
@Scope("prototype") //因为有对象类属性,所以采用原型模式,每次请求新建一个实例对象
public class CdCtrl extends ComCtrl {
 
    private static final String RtuSuccessMsg = "控制器接收并执行命令成功,无返回数据";
 
    private static final String ComCode = "92" ;
 
    @Autowired
    private CdSv sv ;
    /**
     * 向设备(控制器)发送命令
     * @param dto 前端发来的值对象
     * @param bindingResult 对dto验证的结果
     * @return 返回前端
     */
    @PostMapping(path = "send", consumes = MediaType.APPLICATION_JSON_VALUE)
    @SsoAop()
    public BaseResponse<Object> send(@RequestBody @Valid CdDto dto, BindingResult bindingResult) {
        BaseResponse<Object> res ;
        //发送命令前-1:验证
        res = super.pre1(sv, ComCode, dto, bindingResult);
        if(res == null) {
            //发送命令前-2:获得数据
            res = super.pre2(sv, ComCode, dto, bindingResult);
            if (res == null) {
                if(dto.vtCardId == null || "".equals(dto.vtCardId.trim())){
                    Long vtId = sv.selectVcIdByIntakeId(dto.getIntakeId()) ;
                    if(vtId == null) {
                        return BaseResponseUtils.buildErrorMsg("请选择一张虚拟卡");
                    }else{
                        dto.vtCardId = vtId.toString() ;
                    }
                }
                VoVirtualCard vcPo = sv.selectClientVtCardById(Long.parseLong(dto.vtCardId.trim())) ;
                if(vcPo == null){
                    return BaseResponseUtils.buildErrorMsg("服务端出错,未得到农户虚拟卡") ;
                }
                if(vcPo.getInUse().booleanValue()){
                    return BaseResponseUtils.buildErrorMsg("农户该虚拟卡已经被占用,不能再应用其开阀") ;
                }
                if(vcPo.getMoney() <= 0.0){
                    return BaseResponseUtils.buildErrorMsg("农户该虚拟卡中剩余金额为0,不能再应用其开阀") ;
                }
                Double waterPrice = sv.selectWaterPrice() ;
                if(waterPrice == null){
                    return BaseResponseUtils.buildErrorMsg("服务端出错,未得到水价") ;
                }
                CdParam comParam = CdParam.builder().commandCode(ComCode).projectNo(projectNo).controllerType(controllerType)
                        .icCardNo("" + vcPo.getVcNum())//用户卡序列号(17位数字)(6字节BCD,2字节HEX)
                        .waterRemain(0.0)//用户剩余水量, 两个小数点, 单位m3, 0~99999999.99
                        .moneyRemain(vcPo.getMoney())//用户剩余水量, 两个小数点, 单位m3, 0~99999999.99
                        .waterPrice(waterPrice)//水量单价 单位:元, 2个小数点
                        .elePrice(0.0)//电量单价 单位:元, 2个小数点
                        .orderNo(RandomStringUtils.randomNumeric(16))//订单号(16位数字)
                        .build();
                //发送命令前-3:保存命令日志
                res = super.pre3(sv, dto.getIntakeId(), dto.getOperator(), ComCode, comParam);
                if (res == null) {
                    //发送命令前-4:准备Feature
                    super.pre4();
                    try {
                        //创建外部命令(发给控制器)
                        Command com = sv.createOuterCommand(ctrlPo.getRtuAddr(), "" + comId, ComCode);
                        com.rtuResultSendWebUrl = rtuResultSendWebUrl;
                        com.param = comParam;
                        //发送命令
                        res = super.doSend(sv, com);
                        if (res == null) {
                            //发送命令后
                            res = super.after(ComCode, new Callback() {
                                @Override
                                public void call(Object obj) {
                                    Boolean success = (Boolean) obj;
                                    if(success){
                                        // 添加常用取水口或更新使用信息
                                        sv.addOrUpdateOftenUseIntake(dto.getOperator(), dto.getIntakeId()) ;
                                        //开阀成功,虚拟卡记录上标记已被占用
                                        sv.setVcUsed(vcPo.getId(), dto.getIntakeId());
                                    }
                                }
                                @Override
                                public void call(Object... objs) {
                                }
                                @Override
                                public void exception(Exception e) {
                                }
                            });
                        }
                    } catch (Exception e) {
                        res = BaseResponseUtils.buildFail("服务端构造并向通信中间件发送请求时异常" + (e.getMessage() == null ? "" : e.getMessage()));
                    } finally {
                        //最终
                        super.end();
                    }
                }
            }
        }
        return res ;
    }
 
    @Override
    protected String checkDto(DtoBase dto) {
        return null;
    }
 
    @Override
    protected String dealComResult(String code, JSONObject resultData, Callback callback){
        String msg;
        if(resultData != null){
            JSONObject codeData = resultData.getJSONObject("data") ;
            if(codeData == null){
                msg = RtuSuccessMsg ;
            }else {
                String json = codeData.toJSONString();
                DataCd92_A2Vo cvo = JSON.parseObject(json, DataCd92_A2Vo.class) ;
                if(cvo != null){
                    if(callback != null){
                        if(cvo.opResult != null && cvo.opResult.byteValue() == (byte)0){
                            callback.call(true);//开阀成功
                        }else{
                            callback.call(false);//开阀失败
                        }
                    }
                    msg = cvo.toStr(false) ;
                }else{
                    msg = RtuSuccessMsg ;
                }
            }
        }else{
            msg = RtuSuccessMsg ;
        }
        return msg;
    }
}