qinyan il y a 4 mois
Parent
commit
f456a8eca1

+ 77 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/WeChatController.java

@@ -0,0 +1,77 @@
+package com.ruoyi.web.controller.system;
+
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.WeChat;
+import com.ruoyi.framework.web.service.SysLoginService;
+import com.ruoyi.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/api/wechat")
+public class WeChatController {
+    @Autowired
+    private ISysUserService userService;
+    @Autowired
+    private SysLoginService loginService;
+    /**
+     * 处理微信小程序登录请求
+     *
+     * @param code 微信小程序登录时获取的 code
+     * @return 包含 openid 和  JSON 响应
+     */
+    @PostMapping("/login")
+    public AjaxResult login(@RequestParam("code") String code) {
+        Map<String, String> result=null;
+        try {
+            result=WeChat.getOpenIdAndSessionKey(code);
+        } catch (IOException e) {
+            throw new RuntimeException("获取 openid 和 session_key 失败", e);
+        }
+
+        String openId=result.get("openid");
+
+        //通过openId判断是否绑定用户,若以绑定,返回token,直接登录,若无,则返回提示请绑定手机号
+        SysUser sysUser=new SysUser();
+        sysUser.setOpenId(openId);
+        List<SysUser> lst= userService.selectUserList(sysUser);
+        if(lst!=null&&lst.size()>0){
+            //登录并返回token
+            SysUser user=lst.get(0);
+            String token = loginService.wxlogin(user.getUserName(),user.getPassword());
+            return AjaxResult.success(token);
+        }else{
+            return new AjaxResult(500,"当前用户未绑定手机号,请绑定",openId);
+        }
+
+    }
+
+    //绑定手机号并登录
+    @PostMapping("/bindPhone")
+    public AjaxResult bindPhone(@RequestParam("openId") String openId,@RequestParam("phone") String phone) {
+        AjaxResult ajax = AjaxResult.success();
+        //通过手机号查询是否有用户
+        SysUser sysUser=new SysUser();
+        sysUser.setPhonenumber(phone);
+        List<SysUser> lst= userService.selectUserList(sysUser);
+        if(lst!=null&&lst.size()>0){
+            //绑定手机号并登录返回token
+            SysUser user=lst.get(0);
+            user.setOpenId(openId);
+            userService.updateUser(user);
+
+            String token = loginService.wxlogin(user.getUserName(),user.getPassword());
+            ajax.put(Constants.TOKEN, token);
+        }else{
+            return new AjaxResult(500,"当前手机号系统不存在,请确定手机号是否正确或联系管理员",openId);
+        }
+        return ajax;
+    }
+}

+ 6 - 0
ruoyi-common/pom.xml

@@ -127,6 +127,12 @@
             <groupId>com.baomidou</groupId>
             <artifactId>mybatis-plus-boot-starter</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+            <version>5.0.4</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 10 - 0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -53,6 +53,16 @@ public class SysUser extends BaseEntity
     @Excel(name = "用户类型", readConverterExp = "0=男,1=女,2=未知")
     private String user_type;
 
+    private String openId;
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
     public String getUser_type() {
         return user_type;
     }

+ 56 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/WeChat.java

@@ -0,0 +1,56 @@
+package com.ruoyi.common.utils;
+
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.ParseException;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.Map;
+
+public class WeChat {
+
+    private static final String APP_ID = "你的小程序AppID";
+    private static final String APP_SECRET = "你的小程序AppSecret";
+    private static final String CODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";
+
+    /**
+     * 通过 code 换取 openid 和 session_key
+     *
+     * @param code 微信小程序登录时获取的 code
+     * @return 包含 openid 和 session_key 的 Map
+     * @throws IOException 如果请求失败或解析响应时出错
+     */
+    public static Map<String, String> getOpenIdAndSessionKey(String code) throws IOException {
+        // 构建请求 URL
+        String url = CODE_TO_SESSION_URL + "?appid=" + APP_ID + "&secret=" + APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
+
+        // 创建 HttpClient 实例
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+            // 创建 GET 请求
+            HttpGet httpGet = new HttpGet(url);
+
+            // 执行请求并获取响应
+            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
+                // 获取响应内容
+                String responseBody = EntityUtils.toString(response.getEntity());
+
+                // 使用 Jackson 解析 JSON 响应
+                ObjectMapper objectMapper = new ObjectMapper();
+                Map<String, String> resultMap = objectMapper.readValue(responseBody, Map.class);
+
+                // 检查是否有错误码
+                if (resultMap.containsKey("errcode")) {
+                    throw new RuntimeException("微信接口调用失败: " + resultMap.get("errmsg"));
+                }
+
+                return resultMap;
+            } catch (ParseException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}

+ 45 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java

@@ -100,6 +100,50 @@ public class SysLoginService
         return tokenService.createToken(loginUser);
     }
 
+    /**
+     * 微信小程序登录验证
+     *
+     * @param username 用户名
+     * @param password 密码
+     * @return 结果
+     */
+    public String wxlogin(String username, String password)
+    {
+        // 登录前置校验
+        loginPreCheck(username, password);
+        // 用户验证
+        Authentication authentication = null;
+        try
+        {
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+            AuthenticationContextHolder.setContext(authenticationToken);
+            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager.authenticate(authenticationToken);
+        }
+        catch (Exception e)
+        {
+            if (e instanceof BadCredentialsException)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                throw new UserPasswordNotMatchException();
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                throw new ServiceException(e.getMessage());
+            }
+        }
+        finally
+        {
+            AuthenticationContextHolder.clearContext();
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        recordLoginInfo(loginUser.getUserId());
+        // 生成token
+        return tokenService.createToken(loginUser);
+    }
+
     /**
      * 校验验证码
      * 
@@ -178,4 +222,5 @@ public class SysLoginService
         sysUser.setLoginDate(DateUtils.getNowDate());
         userService.updateUserProfile(sysUser);
     }
+
 }

+ 5 - 1
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -23,6 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="updateBy"     column="update_by"    />
         <result property="updateTime"   column="update_time"  />
         <result property="remark"       column="remark"       />
+		<result property="openId"       column="open_id"       />
         <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
     </resultMap>
@@ -57,7 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
     
     <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
-		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
+		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader,u.open_id from sys_user u
 		left join sys_dept d on u.dept_id = d.dept_id
 		where u.del_flag = '0'
 		<if test="userId != null and userId != 0">
@@ -69,6 +70,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<if test="status != null and status != ''">
 			AND u.status = #{status}
 		</if>
+		<if test="openId != null and openId != ''">
+			AND u.open_id = #{openId}
+		</if>
 		<if test="phonenumber != null and phonenumber != ''">
 			AND u.phonenumber like concat('%', #{phonenumber}, '%')
 		</if>

+ 5 - 1
ruoyi-vue/src/views/care/clocks/index.vue

@@ -91,7 +91,11 @@
     </el-dialog>
   </div>
 </template>
-
+<style>
+.app-container{
+  height: 500px;
+}
+</style>
 <script setup name="Clocks">
 import { listClocks, getClocks, delClocks, addClocks, updateClocks } from "@/api/care/clocks";