diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/application.yml b/xinnengyuan/ruoyi-admin/src/main/resources/application.yml index 996d67a0..e6eed2d8 100644 --- a/xinnengyuan/ruoyi-admin/src/main/resources/application.yml +++ b/xinnengyuan/ruoyi-admin/src/main/resources/application.yml @@ -386,5 +386,5 @@ warm-flow: --- # 百度云配置 baidu: client: - id: zSB7KdLgY7a1tIEx3eTy65TE - secret: 5nabjclW5BWGV8UwEueDgBDmOveRVkmD + id: pXACgshs1ABNFa6UM6HvkQ78 #zSB7KdLgY7a1tIEx3eTy65TE + secret: EtTCBwd0KjGFOMDkbq84y3RxJxWpIVv4 #5nabjclW5BWGV8UwEueDgBDmOveRVkmD diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAuthenticationReq.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAuthenticationReq.java index 8f0d71c7..6472f603 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAuthenticationReq.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/contractor/domain/dto/constructionuser/SubConstructionUserAuthenticationReq.java @@ -36,7 +36,7 @@ public class SubConstructionUserAuthenticationReq implements Serializable { private String phone; /** - * 0:保密 1:男 2女 + * 0男1女2未知 */ @NotBlank(message = "性别不能为空") private String sex; diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/TokenUtils.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/TokenUtils.java new file mode 100644 index 00000000..a3d1dd76 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/TokenUtils.java @@ -0,0 +1,159 @@ +package org.dromara.dataTransmission; + +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson2.JSONObject; +import org.dromara.common.redis.utils.RedisUtils; + +import javax.crypto.Cipher; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.time.Duration; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import java.io.ByteArrayOutputStream; + + +@Component +public class TokenUtils { + + // Token过期时间:25分钟(与Redis存储过期时间保持一致) + private static final long TOKEN_EXPIRE_SECONDS = 1500; + // HTTP请求超时时间:10秒 + private static final Duration HTTP_TIMEOUT = Duration.ofSeconds(10); + //通用字符 + private static final String USER_NAME = "username"; + private static final String PASSWORD = "password"; + private static final String PUBLIC_KEY = "publicKey"; + private static final String URL = "url"; + + //clientId + public static final String CLARITYPM = "claritypm"; + + //接口信息及参数 + private static final Map> tokenMap = new HashMap<>(){ + { + put(CLARITYPM, new HashMap<>(){{ + put(URL, "https://claritypm.powerchina.cn/neSmartsite-api/loginCli"); + put(USER_NAME, "zhangweiwei"); + put(PASSWORD, "Hkrsoft@#2023"); + put(PUBLIC_KEY, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoaejbjbttHyHuEzHL8lIX5GZZ6zIYrqJpEDlPM4V5LHn19rSAYp2FyAr8y5Ctny9uUdaYbkoFiVQgxWrAYo4X/3O0OFDsowE25FMOLQY0Mn5B6CvVR7Sdt3DqzIzM1tUnJCIbVGNfDMgxLrLwFN8RvOW8MPlB6LgOvlGMDbj+OQIDAQAB"); + }}); + } + }; + + //字段参数 + private static final Map> paramMap = new HashMap<>(){ + { + put(CLARITYPM, new HashMap<>(){{ + + put(USER_NAME, "username"); + put(PASSWORD, "password"); + }}); + } + }; + + /** + * 优先从Redis获取Token,不存在则调用接口获取并存储 + * @param clientId 客户端ID + * @return 有效的Token字符串 + * @throws Exception 当获取过程发生异常时抛出 + */ + public static String getToken(String clientId) throws Exception { + // 1. 定义Redis中的Token键名 +// String redisKey = "data_auth:token:" + clientId; +// +// // 2. 尝试从Redis获取Token +// String token = RedisUtils.getCacheObject(redisKey); +// if (token != null && !token.isBlank()) { +// // 缓存命中,直接返回 +// return token; +// } + + // 3. 缓存未命中,调用接口获取Token + Map map = tokenMap.get(clientId); + String token = fetchTokenFromApi(clientId,map.get(URL), map.get(USER_NAME), rsaEncrypt(map.get(PASSWORD),map.get(PUBLIC_KEY))); + + // 4. 存储到Redis(设置25分钟过期) +// RedisUtils.setCacheObject(redisKey, token,Duration.ofSeconds(TOKEN_EXPIRE_SECONDS) ); + + return token; + } + + /** + * 从接口获取Token的内部方法 + */ + private static String fetchTokenFromApi(String clientId, String authUrl, String username, String encryptedPassword) throws Exception { + // 构建JSON请求体(包含加密后的密码) + // 1. 构建请求头(与原 Go 代码一致的头信息) +// Map headers = new HashMap<>(); +// headers.put(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8"); +// headers.put("User-Agent", "Mozilla/5.0"); +// headers.put(HttpHeaders.ACCEPT, "application/json"); +// headers.put("Origin", "https://claritypm.powerchina.cn"); +// headers.put("Referer", "https://claritypm.powerchina.cn/"); + + // 2. 构建请求体(保持你的原有逻辑) + Map map = paramMap.get(clientId); + JSONObject requestBody = new JSONObject(); + requestBody.put(map.get(USER_NAME), username); // 从 map 中获取接口要求的用户名参数名 + requestBody.put(map.get(PASSWORD), encryptedPassword); // 加密后的密码 + String jsonBody = requestBody.toJSONString(); + System.out.println("请求体:" + jsonBody); + + // 3. 带 Header 发送 POST 请求(Hutool HttpUtil 重载方法) + String post = HttpUtil.createPost(authUrl) +// .addHeaders(headers) // 设置所有请求头 + .body(jsonBody) // 设置请求体 + .execute() // 执行请求 + .body(); // 获取响应体 + + System.out.println("响应结果:" + post); + // 3. 解析响应(核心解析逻辑) + JSONObject responseJson = JSONObject.parseObject(post); + int code = responseJson.getIntValue("code"); + String msg = responseJson.getString("msg"); + String token = responseJson.getString("token"); + + // 4. 校验响应有效性 + if (code != 200) { + throw new RuntimeException("获取 Token 失败,响应信息:" + msg + ",状态码:" + code); + } + if (token == null || token.trim().isEmpty()) { + throw new RuntimeException("响应中未包含有效 Token,响应内容:" + post); + } + + return token; + } + + /** + * RSA公钥加密(核心加密方法) + * @param content 待加密内容(原始密码) + * @param publicKeyStr 公钥字符串(Base64编码) + * @return 加密后的Base64字符串 + * @throws Exception 加密过程异常 + */ + public static String rsaEncrypt(String content, String publicKeyStr) throws Exception { + RSA rsa = new RSA(null, publicKeyStr); + byte[] encryptedBytes = rsa.encrypt(content, KeyType.PublicKey); + return Base64.getEncoder().encodeToString(encryptedBytes); + } + + + public static void main(String[] args) throws Exception { + String claritypm = getToken(CLARITYPM); + System.out.println(claritypm); + } + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/ClaritypmClient.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/ClaritypmClient.java new file mode 100644 index 00000000..085dc6e6 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/ClaritypmClient.java @@ -0,0 +1,79 @@ +package org.dromara.dataTransmission.claritypm; + + +import org.dromara.dataTransmission.TokenUtils; +import org.dromara.dataTransmission.claritypm.dto.RealUser; +import org.springframework.stereotype.Component; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +@Component +public class ClaritypmClient { + + // 接口地址 + private static final String INSERT_REAL_USER_URL = "https://claritypm.powerchina.cn/neSmartsite-api/realUser/tiandong/insertRealUser"; + + @Autowired + private TokenUtils tokenUtils; // 依赖之前的Token获取服务 + + /** + * 批量新增实名制用户信息 + * @param userList 用户信息列表(建议单次不超过10条) + * @return 接口响应结果(JSON格式) + * @throws Exception 调用异常 + */ + public static String batchInsertRealUser(List userList) throws Exception { + // 1. 校验列表大小(建议不超过10条) + if (userList == null || userList.isEmpty()) { + throw new IllegalArgumentException("用户列表不能为空"); + } + if (userList.size() > 10) { + throw new IllegalArgumentException("单次批量新增不能超过10条数据"); + } + + // 2. 获取Token(从之前的TokenService获取) + String token = TokenUtils.getToken(TokenUtils.CLARITYPM); + if ( token.trim().isEmpty()) { + throw new RuntimeException("获取Token失败,无法调用接口"); + } + + // 3. 构建请求头(包含Token认证) + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json; charset=UTF-8"); + headers.put("User-Agent", "Mozilla/5.0"); + headers.put("Accept", "application/json"); + headers.put("Origin", "https://claritypm.powerchina.cn"); + headers.put("Referer", "https://claritypm.powerchina.cn/"); + headers.put("Authorization", "Bearer " + token); // 假设接口使用Bearer Token认证 + + // 4. 构建请求体(JSONArray格式) + JSONArray requestBody = JSONArray.parseArray(JSON.toJSONString(userList)); + String jsonBody = requestBody.toJSONString(); + System.out.println("批量新增用户请求体:" + jsonBody); + + // 5. 发送POST请求 + String response = HttpUtil.createPost(INSERT_REAL_USER_URL) + .addHeaders(headers) + .body(jsonBody) + .execute() + .body(); + System.out.println("批量新增用户响应:" + response); + + // 6. 解析响应(根据实际响应结构调整,此处假设与登录接口类似) + JSONObject responseJson = JSONObject.parseObject(response); + int code = responseJson.getIntValue("code"); + String msg = responseJson.getString("msg"); + if (code != 200) { + throw new RuntimeException("批量新增用户失败:" + msg + "(状态码:" + code + ")"); + } + + return response; + } +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/dto/RealUser.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/dto/RealUser.java new file mode 100644 index 00000000..0f390010 --- /dev/null +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/dataTransmission/claritypm/dto/RealUser.java @@ -0,0 +1,92 @@ +package org.dromara.dataTransmission.claritypm.dto; + +import lombok.Data; + +import java.time.LocalDate; + + +/** + * 实名制用户信息实体类(对应接口参数) + */ +@Data +public class RealUser { + // 人员姓名(必填) + private String userName; + + // 是否班组长(非必填,0-否 1-是) + private String classManagerFlag; + + // 手机号码(必填) + private String phone; + + // 性别(必填,1.男 2.女 3.未知) + private String sex; + + // 证件类型(必填,0.身份证) + private String cardType; + + // 证件号码(必填,身份证号码) + private String cardNumber; + + // 人员类型(必填,0.作业人员 1.管理人员) + private String userType; + + // 发证机关(非必填) + private String cardDept; + + // 民族(非必填) + private String nation; + + // 生日(非必填,datetime格式) + private LocalDate birthday; + + // 住址(非必填) + private String address; + + // 头像(非必填,http地址) + private String avatar; + + // 采集相片(非必填,http地址) + private String pic; + + // 安全教育表(非必填,http地址) + private String safetyEdu; + + // 技术交底表(非必填,http地址) + private String technology; + + // 证件有效期始(非必填,datetime格式) + private LocalDate cardStartTime; + + // 证件有效期至(非必填,datetime格式) + private LocalDate cardEndTime; + + // 学历(非必填,1-9对应小学至其他) + private String studyLevel; + + // 政治面貌(非必填,0-3对应党员至民主党派) + private String politicsType; + + // 购买保险(非必填,0-否 1-是) + private String insuranceFlag; + + // 重大病史(非必填,0-否 1-是) + private String diseaseFlag; + + // 劳动合同(非必填,0-未签订 1-已签订) + private String laborContractFlag; + + // 紧急联系人(非必填) + private String contacts; + + // 紧急联系人电话(非必填) + private String contactsPhone; + + // 婚姻状况(非必填,0-3对应未婚至丧偶) + private String marryRemark; + + // 企业名称(非必填) + private String companyName; + + +} diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJob.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJob.java index 3c2b9580..7b1f6248 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJob.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/job/attendance/AttendanceJob.java @@ -210,8 +210,7 @@ public class AttendanceJob { .lt(BusAttendanceRule::getClockOutResultTime, end)); } - //获取当前日期 - LocalDate date = LocalDate.now(); + //管理员关联多个项目,需要记录是否已生成缺卡记录 // HashSet manageUserIds = new HashSet<>(); @@ -220,6 +219,8 @@ public class AttendanceJob { List missList = new ArrayList<>(); for (BusAttendanceRule rule : list) { + //获取当前日期 + LocalDate date = LocalDate.now(); LocalTime clockOutTime = rule.getClockOutTime(); LocalTime clockOutResultTime = rule.getClockOutResultTime();