韩星耀 před 2 měsíci
rodič
revize
213491b8ae
18 změnil soubory, kde provedl 366 přidání a 55 odebrání
  1. 6 0
      gig/gig-api/src/main/java/com/stellvoy/api/client/auth/AuthClient.java
  2. 1 0
      gig/gig-api/src/main/java/com/stellvoy/api/dto/user/NewUserDTO.java
  3. 1 3
      gig/gig-auth/gig-auth-service/src/main/java/com/stellvoy/auth/service/impl/AccountServiceImpl.java
  4. 3 1
      gig/gig-customer/src/main/java/com/stellvoy/customer/entity/sessionEntity.java
  5. 1 1
      gig/gig-customer/src/main/java/com/stellvoy/customer/service/serviceImpl/sessionServiceImpl.java
  6. 10 5
      gig/gig-customer/src/main/resources/mapper/sessionMapper.xml
  7. 11 10
      gig/gig-task/src/main/java/com/stellvoy/task/entity/TaskEntity.java
  8. 19 21
      gig/gig-task/src/main/resources/mapper/TaskMapper.xml
  9. 5 0
      gig/gig-user/src/main/java/com/stellvoy/user/config/SecurityConfig.java
  10. 118 7
      gig/gig-user/src/main/java/com/stellvoy/user/controller/UserController.java
  11. 10 0
      gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/CheckLoginDTO.java
  12. 10 0
      gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/WeChatDTO.java
  13. 9 0
      gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/WeChatVerifyCodeDTO.java
  14. 8 0
      gig/gig-user/src/main/java/com/stellvoy/user/domain/po/User.java
  15. 10 0
      gig/gig-user/src/main/java/com/stellvoy/user/service/IUserService.java
  16. 133 6
      gig/gig-user/src/main/java/com/stellvoy/user/service/impl/UserServiceImpl.java
  17. 10 1
      gig/gig-user/src/main/resources/bootstrap.yaml
  18. 1 0
      gig/gig-user/src/main/resources/tempfile_1735870853705.bash

+ 6 - 0
gig/gig-api/src/main/java/com/stellvoy/api/client/auth/AuthClient.java

@@ -1,9 +1,12 @@
 package com.stellvoy.api.client.auth;
 
 import com.stellvoy.api.dto.auth.RoleDTO;
+import com.stellvoy.api.dto.user.LoginFormDTO;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 
 import java.util.List;
 
@@ -15,4 +18,7 @@ public interface AuthClient {
 
     @GetMapping("/roles/list")
     List<RoleDTO> listAllRoles();
+
+    @PostMapping("/accounts/login")
+    String loginByPw(@RequestBody LoginFormDTO loginFormDTO);
 }

+ 1 - 0
gig/gig-api/src/main/java/com/stellvoy/api/dto/user/NewUserDTO.java

@@ -82,4 +82,5 @@ public class NewUserDTO {
      */
     private String resume;
     private Integer sex;//性别:0,男;1,女
+    private String nickName;
 }

+ 1 - 3
gig/gig-auth/gig-auth-service/src/main/java/com/stellvoy/auth/service/impl/AccountServiceImpl.java

@@ -44,13 +44,11 @@ public class AccountServiceImpl implements IAccountService{
         // 2.2.生成token
         String token = generateToken(detail);
 
-        // 3.计入登录信息表
-//        loginRecordService.loginSuccess(loginDTO.getCellPhone(), detail.getUserId());
         // 4.返回结果
         return token;
     }
 
-    private String generateToken(LoginUserDTO detail) {
+    public String generateToken(LoginUserDTO detail) {
         // 2.2.生成access-token
         String token = jwtTool.createToken(detail);
         // 2.3.生成refresh-token,将refresh-token的JTI 保存到Redis

+ 3 - 1
gig/gig-customer/src/main/java/com/stellvoy/customer/entity/sessionEntity.java

@@ -20,8 +20,10 @@ public class sessionEntity implements Serializable {
     @TableId(value = "session_id",type = IdType.AUTO)
     private Long sessionId;
     private Long userId;
-    private String userName;
+    private String nickName;
     private LocalDateTime createTime;
+    private Long sessionStatus;
+    private LocalDateTime dealTime;
 
     private List<messageEntity> messageEntity;
     private List<fileEntity> fileEntity;

+ 1 - 1
gig/gig-customer/src/main/java/com/stellvoy/customer/service/serviceImpl/sessionServiceImpl.java

@@ -42,7 +42,7 @@ public class sessionServiceImpl extends ServiceImpl<sessionMapper, sessionEntity
                 // 创建一条新的会话记录
                 session = new sessionEntity();
                 session.setUserId(userId);
-                session.setUserName(userName);
+                session.setNickName(userName);
                 session.setCreateTime(LocalDateTime.now());
                 sessionMapper.insertSession(session);
 

+ 10 - 5
gig/gig-customer/src/main/resources/mapper/sessionMapper.xml

@@ -5,8 +5,12 @@
     <resultMap id="BaseResultMap" type="com.stellvoy.customer.entity.sessionEntity">
         <result column="session_id" property="sessionId" />
         <result column="user_id" property="userId" />
-        <result column="user_name" property="userName" />
+        <result column="nick_name" property="nickName" />
         <result column="create_time" property="createTime" />
+        <result column="session_status" property="sessionStatus" />
+        <result column="deal_time" property="dealTime" />
+
+
 
         <!-- 处理一对一关系(会话表-用户表) -->
         <association property="userEntity" javaType="com.stellvoy.customer.entity.userEntity">
@@ -53,7 +57,7 @@
     </resultMap>
 
     <sql id="Base_Column_List">
-        session_id, user_id,  create_time
+        session_id, user_id,  create_time,deal_time,session_status,nick_name
     </sql>
     <!--    操作会话表-->
     <select id="findSessionByUserId" resultMap="BaseResultMap">
@@ -63,7 +67,8 @@
     </select>
     <!-- 查询会话表并关联消息表 -->
     <select id="getSessionWithMessagesByUserId" resultMap="BaseResultMap">
-        SELECT s.session_id, s.user_id, s.create_time,
+        SELECT s.session_id, s.user_id, s.create_time,s.deal_time,s.session_status,
+               s.niick_name,
                f.file_id, f.file_path, f.file_name,
                f.create_time AS file_create_time,
                m.message_id, m.sender_id, m.message_content,m.message_status,
@@ -75,8 +80,8 @@
     </select>
     <!-- 插入会话 -->
     <insert id="insertSession" parameterType="com.stellvoy.customer.entity.sessionEntity">
-        INSERT INTO session (user_id,user_name, create_time)
-        VALUES (#{userId},#{userName},#{createTime})
+        INSERT INTO session (user_id,nick_name, create_time)
+        VALUES (#{userId},#{nickName},#{createTime})
     </insert>
 
 <!--    操作消息表-->

+ 11 - 10
gig/gig-task/src/main/java/com/stellvoy/task/entity/TaskEntity.java

@@ -18,24 +18,25 @@ public class TaskEntity implements Serializable {
 
     @TableId(value = "id")
     private Long id;
-    private String taskName; // 任务名称
-    private String taskDescription; // 任务描述
-    private LocalDateTime createTime; // 任务创建时间
-    private LocalDateTime endTime; // 任务完成时间
-    private LocalDateTime updateTime; // 任务修改时间,分派时间
+    private String taskName; // 项目名称
+    private String taskDescription; // 项目描述
+    private LocalDateTime createTime; // 项目创建时间
+    private LocalDateTime endTime; // 项目完成时间
+    private LocalDateTime updateTime; // 项目修改时间,分派时间
     private String projectCycle; // 项目周期
     private Long createId; // 创建人id
     private String createName; // 创建人姓名
     private Long number; // 所需人数
     private Long recruitedNumber; // 已招券人数
-    private Long status; // 任务状态:0,库存中;1,已出库;2,已完成
-    private String image; // 推送任务显示图
-    private Double taskRate; // 任务单价(元/条)
+    private Long status; // 项目招募状态: 1,招募中;2,已完成招募;3,已完结
+    private String image; // 推送项目显示图
+    private Double taskRate; // 项目单价(元/条)
     private String requirementType; // 需求类型
     private LocalDateTime feedBack; // 报名反馈
     private String code; // 工会二维码
     private LocalDateTime applicationDeadline; // 报名截止时间
-    private Long totalWorkload; // 任务总量
-    private LocalDateTime beginTime;//任务开始时间
+    private Long totalWorkload; // 项目总量
+    private LocalDateTime beginTime;//项目开始时间
+    private Integer statusDel;//项目状态:0,启用;1,禁用;
 
 }

+ 19 - 21
gig/gig-task/src/main/resources/mapper/TaskMapper.xml

@@ -23,6 +23,7 @@
         <result column="application_deadline" property="applicationDeadline" />
         <result column="total_workload" property="totalWorkload" />
         <result column="begin_time" property="beginTime" />
+        <result column="status_del" property="statusDel" />
     </resultMap>
 
     <!-- 专用的 resultMap 用于 findTopFiveAndCurrentUserIncome 查询 -->
@@ -35,10 +36,10 @@
     <sql id="Base_Column_List">
         id, task_name, task_description, create_time, end_time, update_time,
         project_cycle, create_id, create_name, number,
-        recruited_number, status, image, task_rate, feed_back, code, application_deadline, total_workload
+        recruited_number, status, image, task_rate, feed_back, code, application_deadline, total_workload,status_del
     </sql>
 
-    <!-- 根据获取每个用户的技能列表,并根据技能匹配任务标签,最多推送 8 条数据(状态为 0) -->
+    <!-- 根据获取每个用户的技能列表,并根据技能匹配任务标签,最多推送 8 条数据(statu状态为 0) -->
     <select id="findTasksByUserId" resultType="com.stellvoy.task.entity.TaskEntity">
         SELECT *
         FROM (
@@ -46,42 +47,38 @@
                  (SELECT gt.id, gt.task_name, gt.task_description, gt.create_time, gt.begin_time, gt.end_time, gt.update_time,
                          gt.project_cycle, gt.create_id, gt.create_name, gt.number,
                          gt.recruited_number, gt.status, gt.image, gt.task_rate,
-                         gt.feed_back, gt.code, gt.application_deadline, gt.total_workload
+                         gt.feed_back, gt.code, gt.application_deadline, gt.total_workload, gt.status_del
                   FROM task gt
                            JOIN task_interest t ON gt.id = t.task_id
                   WHERE t.interest_id IN (
                       SELECT ut.user_id
                       FROM user_task ut
-                      WHERE ut.user_id = #{userId} AND gt.status = 0
+                      WHERE ut.user_id = #{userId} AND gt.status_del = 0 AND gt.status = 1
                   )
                       LIMIT 4
                  )
                  UNION ALL
-                 -- 子查询二:随机选择四个状态为0的任务,但排除已匹配的任务
+                 -- 子查询二:随机选择四个状态为0的任务,但排除已领取的任务
                  (SELECT gt.id, gt.task_name, gt.task_description, gt.create_time, gt.begin_time, gt.end_time, gt.update_time,
                          gt.project_cycle, gt.create_id, gt.create_name, gt.number,
                          gt.recruited_number, gt.status, gt.image, gt.task_rate,
-                         gt.feed_back, gt.code, gt.application_deadline, gt.total_workload
+                         gt.feed_back, gt.code, gt.application_deadline, gt.total_workload, gt.status_del
                   FROM task gt
-                  WHERE gt.status = 0
+                  WHERE gt.status_del = 0
+                    AND gt.status = 1
                     AND gt.id NOT IN (
-                      SELECT id FROM (
-                                         SELECT gt.id
-                                         FROM task gt
-                                                  JOIN task_interest t ON gt.id = t.task_id
-                                         WHERE t.interest_id IN (
-                                             SELECT ut.user_id
-                                             FROM user_task ut
-                                             WHERE ut.user_id = #{userId} AND gt.status = 0
-                                         )
-                                     ) AS matched_tasks
+                      SELECT ut.task_id
+                      FROM user_task ut
+                      WHERE ut.user_id = #{userId} AND ut.task_status = 2
                   )
                   ORDER BY RAND()
                       LIMIT 4
                  )
              ) final_query
             LIMIT 8;
+
     </select>
+
 <!--     当前用户未登录的情况下,随机根据最新创建时间推送八条任务数据-->
     <select id="findTopEightEnabledTasks" resultType="com.stellvoy.task.entity.TaskEntity">
         SELECT
@@ -103,11 +100,12 @@
             gt.feed_back,
             gt.code,
             gt.application_deadline,
-            gt.total_workload
+            gt.total_workload,
+            gt.status_del
         FROM
             task gt
         WHERE
-            gt.status = 0
+            gt.status_del = 0 AND gt.status=1
         ORDER BY
             gt.create_time DESC
             LIMIT 8;
@@ -122,7 +120,7 @@
         SELECT gt.*
         FROM task gt
                  JOIN user_task ut ON gt.id = ut.task_id
-        WHERE ut.user_id = #{userId} AND ut.task_status = 2 and gt.status IN (0, 2)
+        WHERE ut.user_id = #{userId} AND ut.task_status = 2 and gt.status_del= 0
         ORDER BY gt.status ASC, gt.create_time DESC
         LIMIT #{currentPage}, #{pageSize}
     </select>
@@ -132,7 +130,7 @@
         SELECT COUNT(*)
         FROM task gt
                  JOIN user_task ut ON gt.id = ut.task_id
-        WHERE ut.user_id = #{userId}  AND ut.task_status = 2 AND gt.status IN (0, 2)
+        WHERE ut.user_id = #{userId}  AND ut.task_status = 2 AND gt.status_del= 0
     </select>
 
     <!--    获取前五名用户以及当前用户信息,收入排名和任务完成数-->

+ 5 - 0
gig/gig-user/src/main/java/com/stellvoy/user/config/SecurityConfig.java

@@ -1,9 +1,14 @@
 package com.stellvoy.user.config;
 
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.bootstrap.encrypt.KeyProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
+
+import java.security.KeyPair;
 
 @Configuration
 public class SecurityConfig {

+ 118 - 7
gig/gig-user/src/main/java/com/stellvoy/user/controller/UserController.java

@@ -9,22 +9,35 @@ import com.stellvoy.common.domain.dto.LoginUserDTO;
 import com.stellvoy.common.exceptions.BadRequestException;
 import com.stellvoy.common.utils.BeanUtils;
 import com.stellvoy.user.constants.UserErrorInfo;
-import com.stellvoy.user.domain.dto.UpdateEmailDTO;
-import com.stellvoy.user.domain.dto.UpdatePasswordDTO;
-import com.stellvoy.user.domain.dto.UserTaskDTO;
-import com.stellvoy.user.domain.dto.VerifyCodeDTO;
+import com.stellvoy.user.domain.dto.*;
 import com.stellvoy.user.domain.po.*;
 import com.stellvoy.user.service.*;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
-
+import org.springframework.web.client.RestTemplate;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.beans.Transient;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 @RestController
 @RequestMapping("/users")
+@Slf4j
 public class UserController {
 
     @Autowired
@@ -37,6 +50,7 @@ public class UserController {
     private UserInterestService userInterestService;
     @Autowired
     private LearningClient learningClient;
+    private static final String TOKEN = "7zN4K2xQ8mP5L1rT9B3vF6z0H7jJ2mQ8"; // 你在微信公众平台配置的 token
 
     /**
      * 根据id查询用户信息
@@ -74,7 +88,13 @@ public class UserController {
             @PathVariable("phone") String cellPhone) {
         codeService.sendVerifyCode(cellPhone);
     }
-
+    /**
+     * 验证验证码
+     */
+    @PostMapping("/weChatVerify/{userId}")
+    public void weChatVerifyCode(@RequestBody WeChatVerifyCodeDTO dto, @PathVariable("userId") Long userId) {
+        userService.weChatVerifyCode(dto,userId);
+    }
 
     @GetMapping("/list/ids")
     public Long exchangeUserIdWithPhone(@RequestParam("phone") String phone) {
@@ -217,4 +237,95 @@ public class UserController {
                 .set(User::getResume, trimmedResume)
                 .update();
     }
+
+
+
+    @GetMapping("/wechat/callback")
+    public void wechatCallback(@RequestParam String signature,
+                               @RequestParam String timestamp,
+                               @RequestParam String nonce,
+                               @RequestParam String echostr,
+                               HttpServletResponse response) {
+        log.info("微信回调参数:signature={}, timestamp={}, nonce={}, echostr={}", signature, timestamp, nonce, echostr);
+
+        // 设置响应内容类型为 text/plain
+        response.setContentType("text/plain;charset=UTF-8");
+
+        // 验证签名
+        if (checkSignature(signature, timestamp, nonce)) {
+            // 验证成功,返回 echostr
+            try {
+                response.getWriter().write(echostr);
+            } catch (IOException e) {
+                log.error("写入响应时发生错误", e);
+                throw new RuntimeException("写入响应时发生错误", e);
+            }
+        } else {
+            // 验证失败,返回任意内容
+            try {
+                response.getWriter().write("验证失败");
+            } catch (IOException e) {
+                log.error("写入响应时发生错误", e);
+                throw new RuntimeException("写入响应时发生错误", e);
+            }
+        }
+    }
+
+    private boolean checkSignature(String signature, String timestamp, String nonce) {
+        String[] arr = new String[]{TOKEN, timestamp, nonce};
+        Arrays.sort(arr);
+        StringBuilder content = new StringBuilder();
+        for (String s : arr) {
+            content.append(s);
+        }
+        String tmp = sha1(content.toString());
+        log.info("计算签名: {}", tmp);
+        log.info("微信签名: {}", signature);
+        return tmp.equals(signature);
+    }
+
+    private String sha1(String str) {
+        try {
+            MessageDigest digest = MessageDigest.getInstance("SHA-1");
+            byte[] result = digest.digest(str.getBytes());
+            StringBuilder sb = new StringBuilder();
+            for (byte b : result) {
+                sb.append(String.format("%02x", b));
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+
+
+
+
+    /**
+     * 生成微信登录二维码
+     */
+    @GetMapping("/wechat/login")
+    public WeChatDTO wechatLogin() throws IOException {
+        return userService.wechatLogin();
+    }
+
+    /**
+     * 处理微信回调,接收 code
+     */
+    @GetMapping("/wechat/code")
+    public void wechatCallback(@RequestParam String code,
+                               @RequestParam String state){
+        userService.wechatCallback(code, state);
+    }
+    /**
+     * 处理前端轮询
+     */
+    @GetMapping("/wechat/login/status")
+    public CheckLoginDTO checkLoginStatus(@RequestParam String state){
+        log.info("state={}",state);
+        return userService.checkLoginStatus(state);
+    }
+
 }

+ 10 - 0
gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/CheckLoginDTO.java

@@ -0,0 +1,10 @@
+package com.stellvoy.user.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class CheckLoginDTO {
+    private String token;
+    private Long userId;
+    private String cellPhone;
+}

+ 10 - 0
gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/WeChatDTO.java

@@ -0,0 +1,10 @@
+package com.stellvoy.user.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class WeChatDTO {
+    private String appid;
+    private String redirectUri;
+    private String state;
+}

+ 9 - 0
gig/gig-user/src/main/java/com/stellvoy/user/domain/dto/WeChatVerifyCodeDTO.java

@@ -0,0 +1,9 @@
+package com.stellvoy.user.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class WeChatVerifyCodeDTO {
+    private String code;
+    private String phone;
+}

+ 8 - 0
gig/gig-user/src/main/java/com/stellvoy/user/domain/po/User.java

@@ -91,4 +91,12 @@ public class User{
      * 性别
      */
     private Integer sex;
+    /**
+     * openId
+     */
+    private String openId;
+    /**
+     * 昵称
+     */
+    private String nickName;
 }

+ 10 - 0
gig/gig-user/src/main/java/com/stellvoy/user/service/IUserService.java

@@ -6,6 +6,8 @@ import com.stellvoy.common.domain.dto.LoginUserDTO;
 import com.stellvoy.user.domain.dto.*;
 import com.stellvoy.user.domain.po.User;
 
+import java.io.UnsupportedEncodingException;
+
 /**
  * <p>
  * 学员用户表 服务类
@@ -23,4 +25,12 @@ public interface IUserService extends IService<User> {
     void updateEmail(UpdateEmailDTO dto, Long userId);
 
     UserTaskDTO getStats(Long userId);
+
+    WeChatDTO wechatLogin() throws UnsupportedEncodingException;
+
+    void wechatCallback(String code, String state);
+
+    CheckLoginDTO checkLoginStatus(String state);
+
+    void weChatVerifyCode(WeChatVerifyCodeDTO dto, Long userId);
 }

+ 133 - 6
gig/gig-user/src/main/java/com/stellvoy/user/service/impl/UserServiceImpl.java

@@ -1,9 +1,12 @@
 package com.stellvoy.user.service.impl;
 
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.stellvoy.api.client.auth.AuthClient;
 import com.stellvoy.api.client.task.TaskClient;
+import com.stellvoy.api.client.user.UserClient;
 import com.stellvoy.api.dto.task.NewTaskDTO;
 import com.stellvoy.api.dto.user.LoginFormDTO;
 import com.stellvoy.common.domain.dto.LoginUserDTO;
@@ -21,17 +24,23 @@ import com.stellvoy.user.service.ICodeService;
 import com.stellvoy.user.service.IUserService;
 import com.stellvoy.user.service.UserTaskService;
 import com.stellvoy.user.utils.AliyunIdCardVerifier;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.StringRedisTemplate;
-import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
 
 
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import static com.stellvoy.user.constants.UserErrorInfo.Msg.*;
@@ -43,6 +52,7 @@ import static com.stellvoy.user.constants.UserErrorInfo.Msg.*;
  * </p>
  */
 @Service
+@Slf4j
 public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
 
     @Autowired
@@ -55,6 +65,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
     private UserTaskService userTaskService;
     @Autowired
     private TaskClient taskClient;
+    @Autowired
+    private AuthClient authClient;
+    @Value("${wechat.appid}")
+    private String appId;
+
+    @Value("${wechat.appsecret}")
+    private String appSecret;
+    private final RestTemplate restTemplate = new RestTemplate();
+
     @Override
     public LoginUserDTO queryUserDetail(LoginFormDTO loginDTO, boolean isStaff) {
         // 1.判断登录方式
@@ -68,6 +87,11 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         if (type == 2) {
             user = loginByVerifyCode(loginDTO.getCellPhone(), loginDTO.getPassword());
         }
+        // 微信登录
+        if (type == 3) {
+            int userId = Integer.parseInt(loginDTO.getUsername());
+            user = lambdaQuery().eq(User::getId, userId).one();
+        }
         // 4.错误的登录方式
         if (user == null) {
             throw new BadRequestException(ILLEGAL_LOGIN_TYPE);
@@ -99,6 +123,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         user.setCreater(UserContext.getUser());
         user.setUpdater(UserContext.getUser());
         user.setUsername(dto.getCellPhone());
+        user.setNickName(dto.getCellPhone());
         user.setImage("https://suppliermanage.oss-cn-shanghai.aliyuncs.com/gig/img/woman.png");
         save(user);
         return user;
@@ -124,6 +149,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         }
         lambdaUpdate()
                 .eq(User::getId, userId)
+                .set(User::getNickName, dto.getName())
                 .set(User::getIdentityCardId, dto.getIdentityCardId())
                 .set(User::getSex, sex)
                 .set(User::getImage, image)
@@ -232,6 +258,107 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         return userTaskDTO;
     }
 
+    /**
+     * 生成微信登录二维码
+     */
+    public WeChatDTO wechatLogin() throws UnsupportedEncodingException {
+        WeChatDTO weChatDTO = new WeChatDTO();
+        String redirectUri = "https://labelx.stellvoy.com/us/users/wechat/code";
+        String encodedRedirectUri = URLEncoder.encode(redirectUri, StandardCharsets.UTF_8.toString());
+        String state = UUID.randomUUID().toString();
+        weChatDTO.setRedirectUri(encodedRedirectUri);
+        weChatDTO.setState(state);
+        weChatDTO.setAppid(appId);
+        stringRedisTemplate.opsForValue().set("weChatCode:" + state, state, 5, TimeUnit.MINUTES);
+        return weChatDTO;
+    }
+
+    /**
+     * 处理微信回调,接收 code
+     */
+    public void wechatCallback(String code, String state) {
+        // 从Redis中获取state
+        String storedCode = stringRedisTemplate.opsForValue().get("weChatCode:" + state);
+        // state校验
+        if (storedCode == null || !storedCode.equals(state)) {
+            throw new RuntimeException("state错误或已过期");
+        }
+        // 使用 code 获取 access_token 和 openid
+        String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId +
+                "&secret=" + appSecret +
+                "&code=" + code +
+                "&grant_type=authorization_code";
+        RestTemplate restTemplate = new RestTemplate();
+        restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
+        ResponseEntity<String> accessTokenResponse = restTemplate.getForEntity(accessTokenUrl, String.class);
+        JSONObject accessTokenJson = JSON.parseObject(accessTokenResponse.getBody());
+        String accessToken = accessTokenJson.getString("access_token");
+        String openid = accessTokenJson.getString("openid");
+        // 使用 access_token 和 openid 获取用户信息
+        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken +
+                "&openid=" + openid +
+                "&lang=zh_CN";
+        ResponseEntity<String> userInfoResponse = restTemplate.getForEntity(userInfoUrl, String.class);
+        JSONObject userInfoJson = JSON.parseObject(userInfoResponse.getBody());
+
+        // 处理用户信息,例如登录或注册用户
+        String nickname = userInfoJson.getString("nickname");
+        String headimgurl = userInfoJson.getString("headimgurl");
+        User user = lambdaQuery().eq(User::getOpenId, openid).one();
+        if(user == null){
+            user = new User();
+            user.setNickName(nickname);
+            user.setImage(headimgurl);
+            user.setOpenId(openid);
+            user.setPassword("123456");
+            save(user);
+            user = lambdaQuery().eq(User::getOpenId, openid).one();
+        }
+        stringRedisTemplate.opsForValue().set("weChatCode:" + state, openid, 5, TimeUnit.MINUTES);
+        stringRedisTemplate.opsForValue().set("userId:" + state, user.getId().toString(), 5, TimeUnit.MINUTES);
+    }
+
+    /**
+     * 处理前端轮询
+     */
+    public CheckLoginDTO checkLoginStatus(String state) {
+        // 从Redis中获取state
+        String storedCode = stringRedisTemplate.opsForValue().get("weChatCode:" + state);
+        // state校验
+        if (storedCode == null) {
+            throw new RuntimeException("state错误或已失效");
+        }
+        User one = lambdaQuery().eq(User::getOpenId, storedCode).one();
+        if (one == null) {
+            throw new RuntimeException("用户未登录");
+        }
+        LoginFormDTO loginDTO = new LoginFormDTO();
+        loginDTO.setType(3);
+        loginDTO.setPassword("123456");
+        String userId = stringRedisTemplate.opsForValue().get("userId:" + state);
+        loginDTO.setUsername(userId);
+        String token = authClient.loginByPw(loginDTO);
+        CheckLoginDTO checkLoginDTO = new CheckLoginDTO();
+        checkLoginDTO.setToken(token);
+        checkLoginDTO.setUserId(one.getId());
+        if(one.getCellPhone()==null){
+            checkLoginDTO.setCellPhone("未绑定手机号");
+        }
+        checkLoginDTO.setCellPhone(one.getCellPhone());
+        return checkLoginDTO;
+    }
+
+    /**
+     * 验证验证码
+     */
+    public void weChatVerifyCode(WeChatVerifyCodeDTO dto, Long userId) {
+        codeService.verifyCode(dto.getPhone(), dto.getCode());
+        lambdaUpdate().eq(User::getId, userId)
+                .set(User::getCellPhone, dto.getPhone())
+                .set(User::getUsername, dto.getPhone())
+                .update();
+    }
+
     public User loginByPw(LoginFormDTO loginDTO) {
         // 1.数据校验
         String cellPhone = loginDTO.getCellPhone();
@@ -247,7 +374,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         if (user.getStatus() == 0) {
             throw new ForbiddenException(USER_FROZEN);
         }
-        // 4.校验密码
+        //4.校验密码
 //        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
 //            throw new BadRequestException(INVALID_UN_OR_PW);
 //        }

+ 10 - 1
gig/gig-user/src/main/resources/bootstrap.yaml

@@ -48,6 +48,11 @@ gig:
         - /users/isNew/{userId}
         - /users/stats/{userId}
         - /users/resume/{userId}
+        - /users/wechat/callback
+        - /users/wechat/login
+        - /users/wechat/code
+        - /users/wechat/login/status
+        - /users/weChatVerify/{userId}
 
 sms:
   accessKeyId: "LTAI5t6SFbZkrZqYizczn5pR"
@@ -57,4 +62,8 @@ sms:
 aliyun:
   identity-check:
     url: http://id2meta.market.alicloudapi.com
-    app-code: c8414628de9046e8b541cac44056f871
+    app-code: c8414628de9046e8b541cac44056f871
+
+wechat:
+  appid: wx40fabfc32d03a0b4
+  appsecret: 9084f25755aaec040106e9948e99ab2a

+ 1 - 0
gig/gig-user/src/main/resources/tempfile_1735870853705.bash

@@ -0,0 +1 @@
+export JAVA_HOME=/usr/lib/jvm/j