Forráskód Böngészése

新增投资商端小程序登录

tjf 3 éve
szülő
commit
44f771217a

BIN
doc/若依环境使用手册.docx


+ 1 - 0
pom.xml

@@ -209,6 +209,7 @@
         <module>ruoyi-quartz</module>
         <module>ruoyi-generator</module>
         <module>ruoyi-common</module>
+        <module>ruoyi-card</module>
     </modules>
     <packaging>pom</packaging>
 

+ 4 - 0
ruoyi-admin/.rebel-remote.xml.bak

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rebel-remote xmlns="http://www.zeroturnaround.com/rebel/remote">
+    <id>com.ruoyi.ruoyi-admin</id>
+</rebel-remote>

+ 16 - 0
ruoyi-admin/.rebel.xml.bak

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
+  Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
+-->
+<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
+
+	<id>ruoyi-admin</id>
+
+	<classpath>
+		<dir name="E:/qianshancard/ruoyi-admin/target/classes">
+		</dir>
+	</classpath>
+
+</application>

+ 3 - 3
ruoyi-admin/pom.xml

@@ -9,7 +9,7 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
-    <artifactId>ruoyi-admin</artifactId>
+    <artifactId>qianshancard</artifactId>
 
     <description>
         web服务入口
@@ -49,11 +49,11 @@
             <artifactId>ruoyi-framework</artifactId>
         </dependency>
 
-        <!-- 定时任务-->
+<!--        &lt;!&ndash; 定时任务&ndash;&gt;
         <dependency>
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-quartz</artifactId>
-        </dependency>
+        </dependency>-->
 
         <!-- 代码生成-->
         <dependency>

+ 8 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -121,3 +121,11 @@ xss:
   excludes: /system/notice
   # 匹配链接
   urlPatterns: /system/*,/monitor/*,/tool/*
+
+#投资商小程序配置
+auth:
+  wechat:
+    phone_number_url: https://api.weixin.qq.com/wxa/business/getuserphonenumber
+    access_token_url: https://api.weixin.qq.com/cgi-bin/token
+    appId: wxf556d2b0c34da8cf
+    secret: 8f90a52972268f82d5017a2ac29650c4

+ 6 - 6
ruoyi-admin/src/main/resources/logback.xml

@@ -57,19 +57,19 @@
         </filter>
     </appender>
 	
-	<!-- 用户访问日志输出  -->
+<!--	 用户访问日志输出
     <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
 		<file>${log.path}/sys-user.log</file>
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-            <!-- 按天回滚 daily -->
+            &lt;!&ndash; 按天回滚 daily &ndash;&gt;
             <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
-            <!-- 日志最大的历史 60天 -->
+            &lt;!&ndash; 日志最大的历史 60天 &ndash;&gt;
             <maxHistory>60</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${log.pattern}</pattern>
         </encoder>
-    </appender>
+    </appender>-->
 	
 	<!-- 系统模块日志级别控制  -->
 	<logger name="com.ruoyi" level="info" />
@@ -86,8 +86,8 @@
         <appender-ref ref="file_error" />
     </root>
 	
-	<!--系统用户操作日志-->
+<!--	系统用户操作日志
     <logger name="sys-user" level="info">
         <appender-ref ref="sys-user"/>
-    </logger>
+    </logger>-->
 </configuration> 

+ 40 - 0
ruoyi-card/pom.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ruoyi</artifactId>
+        <groupId>com.ruoyi</groupId>
+        <version>3.8.2</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ruoyi-card</artifactId>
+    <description>
+        wechat
+    </description>
+    <dependencies>
+
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-common</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-system</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-framework</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 202 - 0
ruoyi-card/src/main/java/com/ruoyi/wechat/controller/WeChatLoginController.java

@@ -0,0 +1,202 @@
+package com.ruoyi.wechat.controller;
+
+import com.alibaba.fastjson.JSONObject;
+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.core.domain.model.LoginUser;
+import com.ruoyi.common.core.redis.RedisCache;
+import com.ruoyi.common.enums.UserStatus;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.http.HttpUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
+import com.ruoyi.framework.manager.AsyncManager;
+import com.ruoyi.framework.manager.factory.AsyncFactory;
+import com.ruoyi.framework.web.service.SysPermissionService;
+import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ISysUserService;
+import com.ruoyi.wechat.domain.AppletLoginForm;
+import com.ruoyi.wechat.utils.HttpClientUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.impl.client.HttpClients;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+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;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * @author tjf
+ * @Date: 2022/04/15/11:18
+ */
+@RestController
+@RequestMapping("/weChat")
+public class WeChatLoginController {
+    private static final Logger LOGGER = LoggerFactory.getLogger(WeChatLoginController.class);
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
+
+    private final static long EXPIRE_TIME_QR = 3 * 60;
+
+    private final static String ACCESS_TOKEN = Constants.LOGIN_TOKEN_KEY;
+
+    protected static final long MILLIS_SECOND = 1000;
+
+    @Value("${auth.wechat.access_token_url}")
+    private String access_token_url;
+
+    @Value("${auth.wechat.phone_number_url}")
+    private String phone_number_url;
+
+
+    @Value("${auth.wechat.appid}")
+    private String appid;
+
+    @Value("${auth.wechat.secret}")
+    private String secret;
+
+    /**
+     * 投资商端小程序登录获取手机号
+     *
+     * @param loginCode
+     * @return
+     */
+    @PostMapping("/getPhone")
+    public AjaxResult getPhone(@RequestBody AppletLoginForm loginCode) {
+        String code = loginCode.getCode();
+        if (StringUtils.isBlank(code)){
+            return AjaxResult.error("未获取到code");
+        }
+        //grant_type=client_credential&appid=APPID&secret=APPSECRET
+        String param = "grant_type=client_credential&appid=" + appid + "&secret=" + secret;
+        String jsonStr = null;
+        try {
+            jsonStr = HttpClientUtils.doGet(access_token_url, param);
+        } catch (IOException e) {
+            return AjaxResult.error("获取小程序ACCESS_TOKEN失败");
+        }
+        JSONObject result = JSONObject.parseObject(jsonStr);
+        if (StringUtils.isEmpty(result.toString())) {
+            return AjaxResult.error("获取小程序ACCESS_TOKEN失败");
+        }
+        String accessToken = result.getString("access_token");
+        if (StringUtils.isEmpty(accessToken)) {
+            return AjaxResult.error(result.getString("errmsg"));
+        }
+        Map<String, String> paramMap = new HashMap<>();
+        paramMap.put("access_token",accessToken);
+        paramMap.put("code",code);
+        //调用phonenumber.getPhoneNumber
+        try {
+            String jsonPhone = HttpClientUtils.doPost(phone_number_url, paramMap);
+            if (StringUtils.isEmpty(jsonPhone)){
+                return AjaxResult.error("获取小程序手机号失败");
+            }
+            JSONObject resultPhone = JSONObject.parseObject(jsonPhone);
+            if (StringUtils.isEmpty(resultPhone.toJSONString())){
+                return AjaxResult.error("获取小程序手机号失败");
+            }
+            if ("0".equals(resultPhone.getString("errmsg"))){
+                String phone = resultPhone.getJSONObject("phone_info").getString("phoneNumber");
+                return AjaxResult.success().put(Constants.PHONENUMBER, phone);
+            }
+        } catch (IOException e) {
+            return AjaxResult.error("获取小程序手机号失败");
+        }
+        return AjaxResult.error("获取小程序手机号失败");
+    }
+
+
+
+
+    /**
+     * 投资商端小程序登录
+     *
+     * @param loginCode
+     * @return
+     */
+    @PostMapping("/login")
+    public AjaxResult login(@RequestBody AppletLoginForm loginCode) {
+        String phoneNumber = loginCode.getPhoneNumber();
+        if (StringUtils.isBlank(phoneNumber)){
+            return AjaxResult.error("未获取到手机号");
+        }
+        SysUser sysUser = userService.getByPhone(phoneNumber);
+        LoginUser loginUser = loadUserByUsername(sysUser);
+
+        //记录登录信息
+        recordLoginInfo(loginUser.getUserId());
+        // 生成token
+        String token = tokenService.createToken(loginUser);
+        return AjaxResult.success().put(Constants.TOKEN, token);
+    }
+
+    /**
+     * 校验用户账户
+     * @param sysUser
+     * @return
+     * @throws UsernameNotFoundException
+     */
+    public LoginUser loadUserByUsername(SysUser sysUser) throws UsernameNotFoundException
+    {
+        String userName = sysUser.getUserName();
+
+        if (UserStatus.DELETED.getCode().equals(sysUser.getDelFlag()))
+        {
+            LOGGER.info("登录用户:{} 已被删除.", userName);
+            throw new ServiceException("对不起,您的账号:" + userName + " 已被删除");
+        }
+        else if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus()))
+        {
+            LOGGER.info("登录用户:{} 已被停用.", userName);
+            throw new ServiceException("对不起,您的账号:" + userName + " 已停用");
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        return createLoginUser(sysUser);
+    }
+
+    public LoginUser createLoginUser(SysUser user)
+    {
+        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
+    }
+
+    /**
+     * 记录登录信息
+     *
+     * @param userId 用户ID
+     */
+    public void recordLoginInfo(Long userId)
+    {
+        SysUser sysUser = new SysUser();
+        sysUser.setUserId(userId);
+        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+        sysUser.setLoginDate(DateUtils.getNowDate());
+        userService.updateUserProfile(sysUser);
+    }
+}

+ 61 - 0
ruoyi-card/src/main/java/com/ruoyi/wechat/domain/AppletLoginForm.java

@@ -0,0 +1,61 @@
+package com.ruoyi.wechat.domain;
+
+import com.ruoyi.common.core.domain.entity.SysUser;
+
+public class AppletLoginForm {
+
+
+    // 微信code
+    private String code;
+    //手机号
+    private String phoneNumber;
+
+    // 微信用户基本信息
+    private SysUser user;
+
+    // 加密数据
+    private String encryptedData;
+
+    // 向量
+    private String iv;
+
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    public void setPhoneNumber(String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public SysUser getUser() {
+        return user;
+    }
+
+    public void setUser(SysUser user) {
+        this.user = user;
+    }
+
+    public String getEncryptedData() {
+        return encryptedData;
+    }
+
+    public void setEncryptedData(String encryptedData) {
+        this.encryptedData = encryptedData;
+    }
+
+    public String getIv() {
+        return iv;
+    }
+
+    public void setIv(String iv) {
+        this.iv = iv;
+    }
+}

+ 94 - 0
ruoyi-card/src/main/java/com/ruoyi/wechat/utils/HttpClientUtils.java

@@ -0,0 +1,94 @@
+package com.ruoyi.wechat.utils;
+
+import com.ruoyi.common.utils.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class HttpClientUtils {
+
+    final static int TIMEOUT = 1000;
+    final static int TIMEOUT_MSEC = 5 * 1000;
+
+    public static String doPost(String url, Map<String, String> paramMap) throws IOException {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpPost httpPost = new HttpPost(url);
+            // 创建参数列表
+            if (paramMap != null) {
+                List<NameValuePair> paramList = new ArrayList<>();
+                for (Map.Entry<String, String> param : paramMap.entrySet()) {
+                    paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
+                }
+                // 模拟表单
+                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
+                httpPost.setEntity(entity);
+            }
+
+            httpPost.setConfig(builderRequestConfig());
+
+            // 执行http请求
+            response = httpClient.execute(httpPost);
+
+            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            try {
+                response.close();
+            } catch (IOException e) {
+                throw e;
+            }
+        }
+
+        return resultString;
+    }
+
+    public static String doGet(String url, String param) throws IOException {
+         url = StringUtils.isNotBlank(param) ? url + "?" + param : url;
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http请求
+            HttpGet httpGet = new HttpGet(url);
+            // 执行http请求
+            response = httpClient.execute(httpGet);
+            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            try {
+                response.close();
+            } catch (IOException e) {
+                throw e;
+            }
+        }
+        return resultString;
+    }
+
+
+    private static RequestConfig builderRequestConfig() {
+        return RequestConfig.custom()
+                .setConnectTimeout(TIMEOUT_MSEC)
+                .setConnectionRequestTimeout(TIMEOUT_MSEC)
+                .setSocketTimeout(TIMEOUT_MSEC).build();
+    }
+}

+ 10 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java

@@ -14,6 +14,11 @@ public class Constants
      */
     public static final String UTF8 = "UTF-8";
 
+    /**
+     * 手机号
+     */
+    public static final String PHONENUMBER = "phoneNumber";
+
     /**
      * GBK 字符集
      */
@@ -99,6 +104,11 @@ public class Constants
      */
     public static final String LOGIN_USER_KEY = "login_user_key";
 
+    /**
+     * 令牌有效期(分钟)
+     */
+    public final static long TOKEN_EXPIRE = 720;
+
     /**
      * 用户ID
      */

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

@@ -38,6 +38,14 @@ public class SysUser extends BaseEntity
     /** 用户昵称 */
     @Excel(name = "用户名称")
     private String nickName;
+    /**
+     * 用户身份证
+     */
+    private String idCard;
+    /**
+     * 用户的父级身份证号码
+     */
+    private String pid;
 
     /** 用户邮箱 */
     @Excel(name = "用户邮箱")
@@ -94,6 +102,22 @@ public class SysUser extends BaseEntity
     /** 角色ID */
     private Long roleId;
 
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+
+    public String getPid() {
+        return pid;
+    }
+
+    public void setPid(String pid) {
+        this.pid = pid;
+    }
+
     public SysUser()
     {
 

+ 189 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/IdCardUtils.java

@@ -0,0 +1,189 @@
+package com.ruoyi.common.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author tjf
+ * @date 2022年04月13日 17:12
+ **/
+public class IdCardUtils {
+
+    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+    public static String hideIdCard(String idCard) {
+        if (ObjectUtils.isEmpty(idCard)) {
+            return "";
+        }
+
+        // 340104202201050105
+        try {
+            String before = idCard.substring(0, 4);
+            String after = idCard.substring(13);
+            return before + "*********" + after;
+        } catch (Exception e) {
+            return idCard;
+        }
+    }
+
+
+    public static Integer getAge(String IDCard) {
+        int age = 0;
+        Date date = new Date();
+        if (StringUtils.isNotBlank(IDCard) && isValid(IDCard)) {
+            //15位身份证号
+            if (IDCard.length() == 15) {
+                // 身份证上的年份(15位身份证为1980年前的)
+                String uyear = "19" + IDCard.substring(6, 8);
+                // 身份证上的月份
+                String uyue = IDCard.substring(8, 10);
+                // 当前年份
+                String fyear = FORMAT.format(date).substring(0, 4);
+                // 当前月份
+                String fyue = FORMAT.format(date).substring(5, 7);
+                if (Integer.parseInt(uyue) <= Integer.parseInt(fyue)) {
+                    age = Integer.parseInt(fyear) - Integer.parseInt(uyear) + 1;
+                    // 当前用户还没过生
+                } else {
+                    age = Integer.parseInt(fyear) - Integer.parseInt(uyear);
+                }
+                //18位身份证号
+            } else if (IDCard.length() == 18) {
+                // 身份证上的年份
+                String year = IDCard.substring(6).substring(0, 4);
+                // 身份证上的月份
+                String yue = IDCard.substring(10).substring(0, 2);
+                // 当前年份
+                String fyear = FORMAT.format(date).substring(0, 4);
+                // 当前月份
+                String fyue = FORMAT.format(date).substring(5, 7);
+                // 当前月份大于用户出身的月份表示已过生日
+                if (Integer.parseInt(yue) <= Integer.parseInt(fyue)) {
+                    age = Integer.parseInt(fyear) - Integer.parseInt(year) + 1;
+                    // 当前用户还没过生日
+                } else {
+                    age = Integer.parseInt(fyear) - Integer.parseInt(year);
+                }
+            }
+        }
+
+        return age;
+    }
+
+    /**
+     * 身份证验证
+     *
+     * @param id 号码内容
+     * @return 是否有效
+     */
+    public static boolean isValid(String id) {
+        boolean validResult = true;
+        //校验长度只能为15或18
+        int len = id.length();
+        if (len != 15 && len != 18) {
+            validResult = false;
+        }
+        //校验生日
+        if (!validDate(id)) {
+            validResult = false;
+        }
+
+        return validResult;
+    }
+
+    /**
+     * 校验生日
+     *
+     * @param id id
+     * @return boolean
+     */
+    private static boolean validDate(String id) {
+        try {
+            String birth = id.length() == 15 ? "19" + id.substring(6, 12) : id.substring(6, 14);
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+            Date birthDate = sdf.parse(birth);
+            if (!birth.equals(sdf.format(birthDate))) {
+                return false;
+            }
+        } catch (ParseException e) {
+            return false;
+        }
+        return true;
+    }
+
+
+
+    /**
+     * 15位身份证号
+     */
+    private static final Integer FIFTEEN_ID_CARD = 15;
+    /**
+     * 18位身份证号
+     */
+    private static final Integer EIGHTEEN_ID_CARD = 18;
+
+    /**
+     * 根据身份证号获取性别
+     *
+     * @param IDCard
+     * @return
+     */
+    public static String getSex(String IDCard) {
+        String sex = "";
+        if (StringUtils.isNotBlank(IDCard)) {
+            //15位身份证号
+            if (IDCard.length() == FIFTEEN_ID_CARD) {
+                if (Integer.parseInt(IDCard.substring(14, 15)) % 2 == 0) {
+                    sex = "女";
+                } else {
+                    sex = "男";
+                }
+                //18位身份证号
+            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
+                // 判断性别
+                if (Integer.parseInt(IDCard.substring(16).substring(0, 1)) % 2 == 0) {
+                    sex = "女";
+                } else {
+                    sex = "男";
+                }
+            }
+        }
+        return sex;
+    }
+
+    /**
+     * 获取出生日期  yyyy年MM月dd日
+     *
+     * @param IDCard
+     * @return
+     */
+    public static String getBirthday(String IDCard) {
+        String birthday = "";
+        String year = "";
+        String month = "";
+        String day = "";
+        if (StringUtils.isNotBlank(IDCard)) {
+            //15位身份证号
+            if (IDCard.length() == FIFTEEN_ID_CARD) {
+                // 身份证上的年份(15位身份证为1980年前的)
+                year = "19" + IDCard.substring(6, 8);
+                //身份证上的月份
+                month = IDCard.substring(8, 10);
+                //身份证上的日期
+                day = IDCard.substring(10, 12);
+                //18位身份证号
+            } else if (IDCard.length() == EIGHTEEN_ID_CARD) {
+                // 身份证上的年份
+                year = IDCard.substring(6).substring(0, 4);
+                // 身份证上的月份
+                month = IDCard.substring(10).substring(0, 2);
+                //身份证上的日期
+                day = IDCard.substring(12).substring(0, 2);
+            }
+            birthday = year + "-" + month + "-" + day;
+        }
+        return birthday;
+    }
+
+}

+ 303 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/ObjectUtils.java

@@ -0,0 +1,303 @@
+package com.ruoyi.common.utils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+
+/**
+ * @author tjf
+ * @date 2022年04月13日 17:12
+ **/
+public class ObjectUtils {
+
+    private static final String NULL = "null";
+    private static final String UNDEFINED = "undefined";
+
+
+    public static  <T> Collection<T> requireNonNull(Collection<T> input, String errorMsg){
+        if (null == input || input.size() == 0) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static  <T> List<T> requireNonNull(List<T> input, String errorMsg){
+        if (null == input || input.size() == 0) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static  <T> boolean isEmpty(Collection<T> input){
+        return null == input || input.size() == 0;
+    }
+
+    public static  <T> boolean isNotEmpty(Collection<T> input){
+        return !isEmpty(input);
+    }
+
+    public static long[] requireNonNull(long[] input, String errorMsg){
+        if (ArrayUtils.isEmpty(input)) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+
+        return input;
+    }
+
+
+    public static Long[] requireNonNull(Long[] input, String errorMsg){
+        if (ArrayUtils.isEmpty(input)) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+
+        return input;
+    }
+
+    public static Boolean requireNonNull(Boolean input, String errorMsg) {
+        if (input == null) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static <T> T requireNonNull(T input, String errorMsg) {
+        if (input == null) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static Integer requireNonNull(Integer input, String errorMsg) {
+        if (input == null || input < 0) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static boolean isEmpty(Integer input) {
+        return input == null || input < 0;
+    }
+
+    public static boolean isNotEmpty(Integer input) {
+        return !isEmpty(input);
+    }
+
+
+    public static boolean isEmpty(Long input) {
+        return input == null || input < 0;
+    }
+
+    public static boolean isNotEmpty(Long input) {
+        return !isEmpty(input);
+    }
+
+    public static String requireNonNull(String input, String errorMsg) {
+        if (input == null || input.isEmpty() || NULL.equalsIgnoreCase(input) || UNDEFINED.equalsIgnoreCase(input)) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    public static int requireNonNull(int input, String errorMsg) {
+        if (input <= 0) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+
+    public static JSONObject requireNonNull(JSONObject input, String errorMsg) {
+        if (input == null || input.isEmpty()) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+
+    public static JSONObject ifNullSetEmpty(JSONObject input) {
+        if (input == null || input.isEmpty()) {
+            input = new JSONObject();
+        }
+        return input;
+    }
+
+
+    public static List<JSONObject> ifNullSetEmpty(List<JSONObject> input) {
+        if (input == null || input.isEmpty()) {
+            input = Collections.emptyList();
+        }
+        return input;
+    }
+
+    public static JSONArray ifNullSetEmpty(JSONArray input) {
+        if (input == null || input.isEmpty()) {
+            input = new JSONArray();
+        }
+        return input;
+    }
+
+
+    public static boolean isNotEmpty(JSONObject input){
+        return input != null && !input.isEmpty();
+    }
+
+    public static boolean isEmpty(JSONObject input){
+        return !isNotEmpty(input);
+    }
+
+    public static boolean isNotEmpty(JSONArray input){
+        return input != null && !input.isEmpty();
+    }
+
+    public static boolean isEmpty(JSONArray input){
+        return !isNotEmpty(input);
+    }
+
+    /**
+     * 功能描述: 暂且只做 string collection long 三种类型的校验
+     *
+     * @param input input
+     * @return boolean
+     */
+    public static boolean isEmpty(Object input) {
+        if (input instanceof String) {
+            return StringUtils.isEmpty((String) input);
+        } else if (input instanceof Collection) {
+            return CollectionUtils.isEmpty(((Collection<?>) input));
+        } else {
+            return Objects.isNull(input);
+        }
+    }
+
+    public static boolean isNotEmpty(Object input) {
+        return !isEmpty(input);
+    }
+
+    public static boolean isEmpty(String input) {
+        return input == null || input.isEmpty() || NULL.equalsIgnoreCase(input) || UNDEFINED.equalsIgnoreCase(input);
+    }
+
+    public static boolean isNotEmpty(String input) {
+        return !isEmpty(input);
+    }
+
+    public static JSONArray requireNonNull(JSONArray input, String errorMsg) {
+        if (input == null || input.isEmpty()) {
+            throw new IllegalArgumentException(errorMsg);
+        }
+        return input;
+    }
+
+    /**
+     * 功能描述: 需要判断数据库是什么类型,如果是VARCHAR则需要转,如果是数字则无需转
+     *
+     * @param input 输入
+     * @return java.lang.String
+     */
+    public static String escapeStr(String input) {
+        return "'" + input + "'";
+    }
+
+
+    /**
+     * 功能描述: 是否小于0
+     *
+     * @param aLong aLong
+     * @return boolean true小于0
+     */
+    public static boolean ltZero(Long aLong) {
+        return null != aLong && aLong < 0;
+    }
+
+
+    /**
+     * 功能描述: 根据规则过滤
+     *
+     * @param input     原数据
+     * @param predicate FunctionalInterface
+     * @return java.util.List<T>
+     */
+    public static <T> List<T> filter(List<T> input, Predicate<T> predicate) {
+        return requireNonNull(input, "list is null")
+                .stream().filter(predicate).collect(Collectors.toList());
+    }
+
+    public static <T> int count(List<T> input, ToIntFunction<T> toIntFunction) {
+        return requireNonNull(input, "list is null").stream().mapToInt(toIntFunction).sum();
+    }
+
+    public static <T> boolean anyMatch(List<T> input, Predicate<T> predicate){
+        return requireNonNull(input, "list is null").stream().anyMatch(predicate);
+    }
+
+
+    public static <T> boolean noneMatch(List<T> input, Predicate<T> predicate) {
+        return requireNonNull(input, "list is null").stream().noneMatch(predicate);
+    }
+
+    /**
+     * 功能描述: 根据规则过滤
+     *
+     * @param input     原数据
+     * @param predicate FunctionalInterface
+     * @return java.util.List<T>
+     */
+    public static <T> T filterOne(List<T> input, Predicate<T> predicate) {
+        return requireNonNull(input, "list is null")
+                .stream().filter(predicate).findFirst().orElse(null);
+    }
+
+    /**
+     * 功能描述: 根据规则获取
+     *
+     * @param input    原数据
+     * @param function FunctionalInterface
+     * @return java.util.List<T>
+     */
+    public static <T, R> List<R> map(List<T> input, Function<T, R> function) {
+        return requireNonNull(input, "list is null")
+                .stream().map(function).distinct().collect(Collectors.toList());
+    }
+
+    /**
+     * 功能描述: 根据规则获取
+     *
+     * @param input     原数据
+     * @param predicate predicate
+     * @param function  FunctionalInterface
+     * @return java.util.List<R>
+     */
+    public static <T, R> List<R> mapFilter(List<T> input, Predicate<T> predicate, Function<T, R> function) {
+        return requireNonNull(input, "list is null")
+                .stream()
+                .filter(predicate)
+                .map(function)
+                .distinct()
+                .collect(Collectors.toList());
+    }
+
+
+    /**
+     * 功能描述: 根据规则获取单个
+     *
+     * @param input    原数据
+     * @param function FunctionalInterface
+     * @return java.util.List<T>
+     */
+    public static <T, R> R mapFirst(List<T> input, Function<T, R> function) {
+        requireNonNull(input, "list is null");
+        List<R> rList = input.stream().map(function).collect(Collectors.toList());
+        requireNonNull(rList, "rList is null");
+        Optional<R> optionalR = rList.stream().findFirst();
+        return optionalR.orElse(null);
+    }
+
+}

+ 7 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java

@@ -124,4 +124,11 @@ public interface SysUserMapper
      * @return 结果
      */
     public SysUser checkEmailUnique(String email);
+
+    /**
+     * 根据手机号获取人员信息
+     * @param phonenumber
+     * @return
+     */
+    public SysUser getByPhone(String phonenumber);
 }

+ 8 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java

@@ -203,4 +203,12 @@ public interface ISysUserService
      * @return 结果
      */
     public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
+
+
+    /**
+     * 根据手机号获取人员信息
+     * @param phoneNumber
+     * @return
+     */
+    public SysUser getByPhone(String phoneNumber);
 }

+ 11 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -559,4 +559,15 @@ public class SysUserServiceImpl implements ISysUserService
         }
         return successMsg.toString();
     }
+
+
+    /**
+     * 根据手机号获取人员信息
+     * @param phoneNumber
+     * @return
+     */
+    @Override
+    public SysUser getByPhone(String phoneNumber){
+        return userMapper.getByPhone(phoneNumber);
+    }
 }

+ 17 - 4
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -9,6 +9,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="deptId"       column="dept_id"      />
         <result property="userName"     column="user_name"    />
         <result property="nickName"     column="nick_name"    />
+        <result property="idCard"     column="id_card"    />
+        <result property="pid"     column="pid"    />
         <result property="email"        column="email"        />
         <result property="phonenumber"  column="phonenumber"  />
         <result property="sex"          column="sex"          />
@@ -47,7 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 	
 	<sql id="selectUserVo">
-        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, 
+        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, u.id_card,u.pid,
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
         from sys_user u
@@ -57,7 +59,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.password, 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.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,u.id_card,u.pid, d.dept_name, d.leader 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">
@@ -86,7 +88,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	</select>
 	
 	<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
-	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time,u.id_card,u.pid
 	    from sys_user u
 			 left join sys_dept d on u.dept_id = d.dept_id
 			 left join sys_user_role ur on u.user_id = ur.user_id
@@ -103,7 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	</select>
 	
 	<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
-	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time,u.id_card,u.pid
 	    from sys_user u
 			 left join sys_dept d on u.dept_id = d.dept_id
 			 left join sys_user_role ur on u.user_id = ur.user_id
@@ -141,6 +143,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
 		select user_id, email from sys_user where email = #{email} limit 1
 	</select>
+
+	<select id="getByPhone" parameterType="String" resultMap="SysUserResult">
+		<include refid="selectUserVo"/>
+		where u.phonenumber = #{phonenumber} and del_flag = '0' limit 1
+	</select>
 	
 	<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
  		insert into sys_user(
@@ -148,6 +155,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="deptId != null and deptId != 0">dept_id,</if>
  			<if test="userName != null and userName != ''">user_name,</if>
  			<if test="nickName != null and nickName != ''">nick_name,</if>
+ 			<if test="idCard != null and idCard != ''">id_card,</if>
+ 			<if test="pid != null and pid != ''">pid,</if>
  			<if test="email != null and email != ''">email,</if>
  			<if test="avatar != null and avatar != ''">avatar,</if>
  			<if test="phonenumber != null and phonenumber != ''">phonenumber,</if>
@@ -162,6 +171,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="deptId != null and deptId != ''">#{deptId},</if>
  			<if test="userName != null and userName != ''">#{userName},</if>
  			<if test="nickName != null and nickName != ''">#{nickName},</if>
+ 			<if test="idCard != null and idCard != ''">#{idCard},</if>
+ 			<if test="pid != null and pid != ''">#{pid},</if>
  			<if test="email != null and email != ''">#{email},</if>
  			<if test="avatar != null and avatar != ''">#{avatar},</if>
  			<if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if>
@@ -180,6 +191,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  			<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
  			<if test="userName != null and userName != ''">user_name = #{userName},</if>
  			<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
+ 			<if test="idCard != null and idCard != ''">id_card = #{idCard},</if>
+ 			<if test="pid != null and pid != ''">pid = #{pid},</if>
  			<if test="email != null ">email = #{email},</if>
  			<if test="phonenumber != null ">phonenumber = #{phonenumber},</if>
  			<if test="sex != null and sex != ''">sex = #{sex},</if>