xuzhancheng пре 1 дан
родитељ
комит
b267eef864

+ 32 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/member/MemberRemoteService.java

@@ -0,0 +1,32 @@
+package cn.start.tz.module.member.service.member;
+
+
+import cn.start.tz.module.member.service.member.vo.MemberUserCreateReqVO;
+import cn.start.tz.module.member.service.member.vo.MemberUserRespVO;
+
+/**
+ * 平台用户远程服务接口
+ * <p>
+ * 提供平台用户的远程调用服务,包括用户创建和查询功能
+ *
+ * @author 系统管理员
+ */
+public interface MemberRemoteService {
+
+    /**
+     * 创建平台用户
+     *
+     * @param reqVO 平台用户创建请求对象,包含用户基本信息
+     * @return 创建成功的平台用户响应对象,包含用户ID和详细信息
+     */
+    MemberUserRespVO createUser(MemberUserCreateReqVO reqVO);
+
+    /**
+     * 根据手机号查询平台用户
+     *
+     * @param mobile 手机号码,用于唯一标识用户
+     * @return 平台用户响应对象,如果用户不存在则返回null
+     */
+    MemberUserRespVO getUserByMobile(String mobile);
+
+}

+ 135 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/member/MemberRemoteServiceImpl.java

@@ -0,0 +1,135 @@
+package cn.start.tz.module.member.service.member;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.start.tz.framework.common.pojo.CommonResult;
+import cn.start.tz.framework.common.util.json.JsonUtils;
+
+import cn.start.tz.module.member.service.member.vo.MemberUserCreateReqVO;
+import cn.start.tz.module.member.service.member.vo.MemberUserRespVO;
+import com.fasterxml.jackson.core.type.TypeReference;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.Duration;
+
+@Slf4j
+@Service
+public class MemberRemoteServiceImpl implements MemberRemoteService {
+
+    /**
+     * nonce Redis Key 模板: member_remote_nonce:{appId}:{nonce}
+     */
+    private static final String NONCE_KEY_FORMAT = "member_remote_nonce:%s:%s";
+
+    private static final TypeReference<CommonResult<MemberUserRespVO>> USER_RESULT_TYPE =
+            new TypeReference<CommonResult<MemberUserRespVO>>() {};
+
+    @Resource
+    private RestTemplate restTemplate;
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Value("${app-auth.base-url:http://localhost:48080}")
+    private String baseUrl;
+
+    @Value("${app-auth.app-id:xxxxxx}")
+    private String appId;
+
+    @Value("${app-auth.app-secret:yyyyyy}")
+    private String appSecret;
+
+    @Override
+    public MemberUserRespVO createUser(MemberUserCreateReqVO reqVO) {
+        long timestamp = System.currentTimeMillis();
+        String nonce = IdUtil.fastSimpleUUID();
+
+        // 请求体序列化
+        String bodyJson = JsonUtils.toJsonString(reqVO);
+
+        // 签名计算:第1步(查询参数为空)+ 第2步(请求体)+ 第3步(Header排序)+ appSecret
+        String signString = buildSignString("", bodyJson, timestamp, nonce);
+        String sign = DigestUtil.sha256Hex(signString);
+
+        // nonce 存 Redis 防重放
+        String nonceKey = String.format(NONCE_KEY_FORMAT, appId, nonce);
+        stringRedisTemplate.opsForValue().set(nonceKey, "1", Duration.ofSeconds(120));
+
+        HttpHeaders headers = buildSignHeaders(timestamp, nonce, sign);
+        headers.setContentType(MediaType.APPLICATION_JSON);
+
+        HttpEntity<String> entity = new HttpEntity<>(bodyJson, headers);
+
+        String url = baseUrl + "/external-api/member/user/create";
+        ResponseEntity<String> response = restTemplate.exchange(
+                url, HttpMethod.POST, entity, String.class);
+
+        return parseResponse(response);
+    }
+
+    @Override
+    public MemberUserRespVO getUserByMobile(String mobile) {
+        long timestamp = System.currentTimeMillis();
+        String nonce = IdUtil.fastSimpleUUID();
+
+        // 查询参数按 key 字典序拼接: mobile={mobile}
+        String queryStr = "mobile=" + mobile;
+
+        // 签名计算:第1步(查询参数)+ 第2步(空)+ 第3步(Header排序)+ appSecret
+        String signString = buildSignString(queryStr, "", timestamp, nonce);
+        String sign = DigestUtil.sha256Hex(signString);
+
+        // nonce 存 Redis 防重放
+        String nonceKey = String.format(NONCE_KEY_FORMAT, appId, nonce);
+        stringRedisTemplate.opsForValue().set(nonceKey, "1", Duration.ofSeconds(120));
+
+        HttpHeaders headers = buildSignHeaders(timestamp, nonce, sign);
+        HttpEntity<Void> entity = new HttpEntity<>(headers);
+
+        String url = baseUrl + "/external-api/member/user/getByMobile?mobile=" + mobile;
+        ResponseEntity<String> response = restTemplate.exchange(
+                url, HttpMethod.GET, entity, String.class);
+
+        return parseResponse(response);
+    }
+
+    private String buildSignString(String queryParams, String requestBody, long timestamp, String nonce) {
+        // 第1步 + 第2步 + 第3步(Header按key字典序: appId < nonce < timestamp) + appSecret
+        return queryParams
+                + requestBody
+                + "appId=" + appId + "&nonce=" + nonce + "&timestamp=" + timestamp
+                + appSecret;
+    }
+
+    private HttpHeaders buildSignHeaders(long timestamp, String nonce, String sign) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("appId", appId);
+        headers.set("timestamp", String.valueOf(timestamp));
+        headers.set("nonce", nonce);
+        headers.set("sign", sign);
+        return headers;
+    }
+
+    private MemberUserRespVO parseResponse(ResponseEntity<String> response) {
+        if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
+            CommonResult<MemberUserRespVO> result = JsonUtils.parseObject(
+                    response.getBody(), USER_RESULT_TYPE);
+            if (result != null && result.isSuccess()) {
+                return result.getData();
+            }
+            log.warn("[parseResponse][接口返回失败: code={}, msg={}]",
+                    result != null ? result.getCode() : null,
+                    result != null ? result.getMsg() : null);
+            return null;
+        }
+        log.warn("[parseResponse][HTTP状态异常: {}]", response.getStatusCode());
+        return null;
+    }
+
+}

+ 17 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/member/vo/MemberUserCreateReqVO.java

@@ -0,0 +1,17 @@
+package cn.start.tz.module.member.service.member.vo;
+
+import lombok.Data;
+
+@Data
+public class MemberUserCreateReqVO {
+
+    private String mobile;
+    private String nickname;
+    private String name;
+    private String avatar;
+    private Integer sex;
+    private String kszxOpenid;
+    private String registerIp;
+    private Integer registerTerminal;
+
+}

+ 20 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/member/vo/MemberUserRespVO.java

@@ -0,0 +1,20 @@
+package cn.start.tz.module.member.service.member.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MemberUserRespVO {
+
+    private String id;
+    private String mobile;
+    private String nickname;
+    private String name;
+    private String avatar;
+    private Integer sex;
+    private Integer status;
+    private String kszxOpenid;
+    private String createTime;
+
+}

+ 15 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/membermessage/MemberMessageRemoteService.java

@@ -0,0 +1,15 @@
+package cn.start.tz.module.member.service.membermessage;
+
+
+import cn.start.tz.module.member.service.membermessage.vo.SendMpMessageReqVO;
+
+public interface MemberMessageRemoteService {
+
+    /**
+     * 推送微信公众号模版消息
+     *
+     * @return 推送结果: 0=成功, 1=用户拒绝接收, 3=推送失败
+     */
+    Integer sendMpMessage(SendMpMessageReqVO reqVO);
+
+}

+ 93 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/membermessage/MemberMessageRemoteServiceImpl.java

@@ -0,0 +1,93 @@
+package cn.start.tz.module.member.service.membermessage;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.start.tz.framework.common.pojo.CommonResult;
+import cn.start.tz.framework.common.util.json.JsonUtils;
+
+import cn.start.tz.module.member.service.membermessage.vo.SendMpMessageReqVO;
+import com.fasterxml.jackson.core.type.TypeReference;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.Duration;
+
+@Slf4j
+@Service
+public class MemberMessageRemoteServiceImpl implements MemberMessageRemoteService {
+
+    private static final String NONCE_KEY_FORMAT = "member_message_nonce:%s:%s";
+
+    private static final TypeReference<CommonResult<Integer>> RESULT_TYPE =
+            new TypeReference<CommonResult<Integer>>() {};
+
+    @Resource
+    private RestTemplate restTemplate;
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Value("${app-auth.base-url:http://localhost:48080}")
+    private String baseUrl;
+
+    @Value("${app-auth.app-id:xxxxxx}")
+    private String appId;
+
+    @Value("${app-auth.app-secret:yyyyyy}")
+    private String appSecret;
+
+    @Override
+    public Integer sendMpMessage(SendMpMessageReqVO reqVO) {
+        long timestamp = System.currentTimeMillis();
+        String nonce = IdUtil.fastSimpleUUID();
+
+        // 请求体序列化
+        String bodyJson = JsonUtils.toJsonString(reqVO);
+
+        // 签名:第1步(查询参数空) + 第2步(请求体) + 第3步(Header按key字典序) + appSecret
+        String signString = bodyJson
+                + "appId=" + appId + "&nonce=" + nonce + "&timestamp=" + timestamp
+                + appSecret;
+        String sign = DigestUtil.sha256Hex(signString);
+
+        // nonce 存 Redis 防重放
+        String nonceKey = String.format(NONCE_KEY_FORMAT, appId, nonce);
+        stringRedisTemplate.opsForValue().set(nonceKey, "1", Duration.ofSeconds(120));
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        headers.set("appId", appId);
+        headers.set("timestamp", String.valueOf(timestamp));
+        headers.set("nonce", nonce);
+        headers.set("sign", sign);
+
+        HttpEntity<String> entity = new HttpEntity<>(bodyJson, headers);
+
+        String url = baseUrl + "/external-api/member/message/send-mp-message";
+        ResponseEntity<String> response = restTemplate.exchange(
+                url, HttpMethod.POST, entity, String.class);
+
+        if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
+            CommonResult<Integer> result = JsonUtils.parseObject(
+                    response.getBody(), RESULT_TYPE);
+            if (result != null && result.isSuccess()) {
+                log.info("[sendMpMessage][推送完成, memberId={}, templateId={}, result={}]",
+                        reqVO.getMemberId(), reqVO.getTemplateId(), result.getData());
+                return result.getData();
+            }
+            log.warn("[sendMpMessage][接口返回失败: code={}, msg={}]",
+                    result != null ? result.getCode() : null,
+                    result != null ? result.getMsg() : null);
+            return 3;
+        }
+
+        log.warn("[sendMpMessage][HTTP状态异常: {}]", response.getStatusCode());
+        return 3;
+    }
+
+}

+ 39 - 0
tz-module-member/tz-module-member-biz/src/main/java/cn/start/tz/module/member/service/membermessage/vo/SendMpMessageReqVO.java

@@ -0,0 +1,39 @@
+package cn.start.tz.module.member.service.membermessage.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+public class SendMpMessageReqVO {
+
+    private String memberId;
+    private String templateId;
+    private List<TemplateData> templateDataList;
+    private MiniProgram miniProgram;
+    private String businessId;
+    private Integer businessType;
+
+    @Data
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class TemplateData {
+
+        private String name;
+        private String value;
+        private String color;
+
+    }
+
+    @Data
+    public static class MiniProgram {
+
+        private String appid;
+        private String pagePath;
+        private Boolean usePath;
+
+    }
+
+}

+ 84 - 0
tz-module-pressure2/tz-module-pressure2-biz/src/main/java/cn/start/tz/module/pressure2/service/boilertaskorderissuereport/BoilerTaskOrderIssueReportServiceImpl.java

@@ -76,6 +76,11 @@ import cn.start.tz.module.pressure2.service.boilertaskorderitemreportrecord.Boil
 import cn.start.tz.module.pressure2.service.boilertaskorderitemreportversion.BoilerTaskOrderItemReportVersionService;
 import cn.start.tz.module.pressure2.service.boilertaskordersignfile.BoilerTaskOrderSignFileService;
 import cn.start.tz.module.pressure2.service.dynamictbins.DynamicTbInsService;
+import cn.start.tz.module.pressure2.service.member.MemberRemoteService;
+import cn.start.tz.module.pressure2.service.member.vo.MemberUserCreateReqVO;
+import cn.start.tz.module.pressure2.service.member.vo.MemberUserRespVO;
+import cn.start.tz.module.pressure2.service.membermessage.MemberMessageRemoteService;
+import cn.start.tz.module.pressure2.service.membermessage.vo.SendMpMessageReqVO;
 import cn.start.tz.module.pressure2.service.pdf.PdfService;
 import cn.start.tz.module.pressure2.util.JwApiClient;
 import cn.start.tz.module.pressure2.util.vo.ApiResponse;
@@ -261,6 +266,12 @@ public class BoilerTaskOrderIssueReportServiceImpl extends ServiceImpl<BoilerTas
     @Resource
     private MemberUserApi memberUserApi;
 
+    @Resource
+    private MemberRemoteService memberRemoteService;
+
+    @Resource
+    private MemberMessageRemoteService memberMessageRemoteService;
+
     @Resource
     private FileApi fileApi;
 
@@ -486,6 +497,79 @@ public class BoilerTaskOrderIssueReportServiceImpl extends ServiceImpl<BoilerTas
                     }
 
                 }
+                /*if (item.getMiniProgramPush() != null && item.getMiniProgramPush()) {
+                    //根据接收人电话获取平台用户信息
+//                    MemberUserRespDTO memberUser = memberUserApi.getUserByMobile(item.getRecipientPhone()).getCheckedData();
+                    MemberUserRespVO memberUser = memberRemoteService.getUserByMobile(item.getRecipientPhone());
+                    // 获取不到平台用户信息时创建一个平台用户账号
+                    if (ObjectUtil.isEmpty(memberUser)) {
+                        MemberUserCreateReqVO memberUserReqVo = new MemberUserCreateReqVO();
+                        memberUserReqVo.setMobile(item.getRecipientPhone());
+                        memberUserReqVo.setName(item.getRecipientPhone());
+                        memberUserReqVo.setRegisterIp(getClientIP());
+                        memberUser = memberRemoteService.createUser(memberUserReqVo);
+                        if (ObjectUtil.isEmpty(memberUser)) {
+                            throw exception(new ErrorCode(1007,"创建用户失败"));
+                        }
+                    }
+
+                    if (ObjectUtil.isNotEmpty(memberUser)) {
+                        SendMpMessageReqVO param = new SendMpMessageReqVO();
+                        param.setMemberId(memberUser.getId());
+                        if (EnvEnum.LOCAL.getEnvName().equals(env)){
+                            param.setTemplateId("y_D6jCp4MuYMABo5O0mTrREGmI6rip0Feke-r9PkV_g");
+                        } else if (EnvEnum.UAT.getEnvName().equals(env)) {
+                            param.setTemplateId("fTvRP72t6_8xZZ1u8F0PhYOUHUVreor7aCD3qIF596Y");
+                        }
+                        List<SendMpMessageReqVO.TemplateData> list1 = new ArrayList<>();
+                        list1.add(new SendMpMessageReqVO.TemplateData("thing2", itemReportDOS.get(0).getReportName(), null));
+                        list1.add(new SendMpMessageReqVO.TemplateData("time4", taskOrderDO.getCheckDate().toString(), null));
+                        list1.add(new SendMpMessageReqVO.TemplateData("thing6", TaskOrderStatusEnum.getByStatus(taskOrderDO.getTaskStatus()).getName(), null));
+                        param.setTemplateDataList(list1);
+                        SendMpMessageReqVO.MiniProgram mini = new SendMpMessageReqVO.MiniProgram();
+                        mini.setPagePath("pagesSub/reportArchive/index");
+                        mini.setUsePath(true);
+                        param.setMiniProgram(mini);
+                        param.setBusinessId(taskOrderDO.getId());
+                        param.setBusinessType(1);
+//                        memberUserApi.sendMpMessage(param).getCheckedData();
+                        memberMessageRemoteService.sendMpMessage(param);
+
+                        // 生成url
+                        MemberUserRespVO finalMemberUser = memberUser;
+                        taskOrderItemDOList.forEach(taskOrderItemDO -> {
+                            try {
+
+                                // 生成报告URL
+                                ReportUrlInfo reportUrlInfo = generateReportUrl(taskOrderItemDO);
+                                String reportUrl = reportUrlInfo.getReportUrl();
+                                String fileUrl = reportUrlInfo.getFileUrl();
+
+                                // 公众模版发送
+                                List<BoilerTaskOrderItemReportDO> reports = itemReportDOS.stream().filter(x -> x.getOrderItemId().equals(taskOrderItemDO.getId())).toList();
+                                if (CollUtil.isNotEmpty(reports)) {
+                                    //更新任务单出具报告记录-公众号推送人员信息
+                                    LambdaUpdateWrapper<BoilerTaskOrderIssueReportDO> updateWrapper = new LambdaUpdateWrapper<>();
+                                    updateWrapper.set(BoilerTaskOrderIssueReportDO::getOrderItemReportId, reports.get(0).getId());
+                                    updateWrapper.set(BoilerTaskOrderIssueReportDO::getRecipientMemberUserId, finalMemberUser.getId());
+                                    updateWrapper.eq(BoilerTaskOrderIssueReportDO::getId, taskOrderIssueReport.getId());
+                                    taskOrderIssueReportMapper.update(updateWrapper);
+                                    // }
+                                    BoilerTaskOrderItemDO updateOb = new BoilerTaskOrderItemDO();
+                                    updateOb.setId(taskOrderItemDO.getId());
+                                    updateOb.setIssueUrl(fileUrl);
+                                    taskOrderItemMapper.updateById(updateOb);
+                                }
+                            } catch (Exception e) {
+                                log.error("公众模版发送失败", e);
+                                throw new RuntimeException(e);
+                            }
+                        });
+                    } else {
+                        //todo 获取不到平台用户信息是创建一个平台用户账号
+                    }
+
+                }*/
             });
         });