diff --git a/common-ruoyi/ruoyi-common/pom.xml b/common-ruoyi/ruoyi-common/pom.xml index 9e8286b..5da5b26 100644 --- a/common-ruoyi/ruoyi-common/pom.xml +++ b/common-ruoyi/ruoyi-common/pom.xml @@ -16,6 +16,14 @@ + + + + com.github.binarywang + weixin-java-miniapp + 4.6.0 + + com.k3cloud diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/AccessTokenUtil.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/AccessTokenUtil.java new file mode 100644 index 0000000..248d2ea --- /dev/null +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/AccessTokenUtil.java @@ -0,0 +1,36 @@ +package com.ruoyi.common.auth.wx; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.ruoyi.common.constant.CacheConstants; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import lombok.SneakyThrows; + +import java.util.concurrent.TimeUnit; + +public class AccessTokenUtil { + + public static final String APPID = SpringUtils.getRequiredProperty("wx.appid"); + public static final String APP_SECRET = SpringUtils.getRequiredProperty("wx.appSecret"); + + @SneakyThrows + public static String getToken() { + RedisCache redisCache = SpringUtils.getBean(RedisCache.class); + String token = redisCache.getCacheObject(CacheConstants.WX_ACCESS_TOKEN); + + if (StringUtils.isBlank(token)) { + WxMaService wxMaService = new WxMaServiceImpl(); + WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl(); + config.setAppid(APPID); + config.setSecret(APP_SECRET); + wxMaService.setWxMaConfig(config); + token = wxMaService.getAccessToken(); + + redisCache.setCacheObject(CacheConstants.WX_ACCESS_TOKEN, token, 5400, TimeUnit.SECONDS); + } + return token; + } +} diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/WxAuthService.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/WxAuthService.java new file mode 100644 index 0000000..992f438 --- /dev/null +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/WxAuthService.java @@ -0,0 +1,84 @@ +package com.ruoyi.common.auth.wx; + +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.auth.wx.config.WxConfig; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.http.HttpUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author wjh + * 2024/7/29 + */ +@Service +@Slf4j +public class WxAuthService { + + + @Autowired + private WxConfig wxConfig; + + /** + * 使用登录码获取微信用户信息 + * @param jsCode 登录码,通过wx.login获得 + */ + public WxMaJscode2SessionResult wxJsCode2Session(String jsCode) { + if (StringUtils.isBlank(jsCode)) { + return null; + } + String grantType = "authorization_code"; + String url = String.format("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=%s", wxConfig.getAppId(), wxConfig.getAppSecret(), jsCode, grantType); + String body = HttpUtils.sendGet(url); + return JSON.parseObject(body, WxMaJscode2SessionResult.class); + } + + public String getOpenId(String jsCode) { + WxMaJscode2SessionResult result = this.wxJsCode2Session(jsCode); + if (result == null) { + return null; + } + return result.getOpenid(); + } + + /** + * 通过微信手机号授权码获取微信手机号 + * @param mobileCode 微信手机号授权码 + * @return + */ + public String getWxPhoneNumber(String mobileCode) { + String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="; + + // 根据手机号获取到用户名 + String token = AccessTokenUtil.getToken(); + url = url + token; + JSONObject jsonObject = new JSONObject(); + jsonObject.put("code", mobileCode); + String post = HttpUtils.sendPost(url, jsonObject.toString()); + // 获取微信用户手机号 + JSONObject body = JSONObject.parseObject(post); + if (body == null) { + return null; + } + + Integer errcode = body.getInteger("errcode"); + if (errcode == null || !errcode.equals(0)) { + log.error("获取手机号失败 {}", body); + throw new ServiceException("获取手机号失败"); + } + + String phoneInfo = body.getString("phone_info"); + WxMaPhoneNumberInfo wxMaPhoneNumberInfo = JSONObject.parseObject(phoneInfo, WxMaPhoneNumberInfo.class); + if (wxMaPhoneNumberInfo == null) { + return null; + } + + return wxMaPhoneNumberInfo.getPhoneNumber(); + } + +} diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/config/WxConfig.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/config/WxConfig.java new file mode 100644 index 0000000..b1a9b5a --- /dev/null +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/config/WxConfig.java @@ -0,0 +1,23 @@ +package com.ruoyi.common.auth.wx.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * @author wjh + * 2024/3/13 + */ +@Configuration +@Getter +@Setter +public class WxConfig { + + @Value("${wx.appid}") + private String appId; + + @Value("${wx.appSecret}") + private String appSecret; + +} diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/vo/AccessToken.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/vo/AccessToken.java new file mode 100644 index 0000000..3d84277 --- /dev/null +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/auth/wx/vo/AccessToken.java @@ -0,0 +1,83 @@ +package com.ruoyi.common.auth.wx.vo; + +public class AccessToken { + private String expires_in; //成功有效时间 + private String access_token; // 普通Token + private String refresh_token; // 普通Token + private String openid; + private String errcode; //失败ID + private String errmsg; //失败消息 + private long expiresIn; //过期时间 , 默认2小时 + + public long getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(long expiresIn) { + this.expiresIn = expiresIn; + } + + public String getExpires_in() { + return expires_in; + } + + public void setExpires_in(String expires_in) { + this.expires_in = expires_in; + } + + public String getAccess_token() { + return access_token; + } + + public void setAccess_token(String access_token) { + this.access_token = access_token; + } + + public String getErrcode() { + return errcode; + } + + public void setErrcode(String errcode) { + this.errcode = errcode; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getRefresh_token() { + return refresh_token; + } + + public void setRefresh_token(String refresh_token) { + this.refresh_token = refresh_token; + } + + /** + * + * @param expires_in 从微信服务器获取到的过期时间 + * @param access_token 从微信服务器获取到的过期时间access-token + */ + public AccessToken(String expires_in, String access_token) { + this.access_token = access_token; + //当前系统时间+上过期时间 + expiresIn = System.currentTimeMillis() + Integer.parseInt(expires_in) * 1000; + } + + //判断token是否过期 + public boolean isExpired() { + return System.currentTimeMillis() > expiresIn; + } +} diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java index 0080343..2e3ab8f 100644 --- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java @@ -2,7 +2,7 @@ package com.ruoyi.common.constant; /** * 缓存的key 常量 - * + * * @author ruoyi */ public class CacheConstants @@ -41,4 +41,8 @@ public class CacheConstants * 登录账户密码错误次数 redis key */ public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + /** + * 微信access_token + */ + public static final String WX_ACCESS_TOKEN = "wx_access_token"; } diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 4ed70dc..b3a8579 100644 --- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -175,4 +175,12 @@ public class Constants * 系统 用户ID */ public static final Long SYSTEM_USER_ID = 0L; + /** + * 微信授权登录 + */ + public static final String LOGIN_TYPE_WX = "LOGIN_TYPE_WX"; + /** + * 账号密码登录 + */ + public static final String LOGIN_TYPE_PASSWORD = "LOGIN_TYPE_PASSWORD"; } diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index 9ac46fc..d5a9402 100644 --- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -41,11 +41,11 @@ public class SysUser extends BaseEntity @Excel(name = "工号") @ApiModelProperty("工号") + @NotBlank(message = "工号不允许为空", groups = {ValidGroup.Create.class}) @Size(max = 32, message = "工号长度不允许超过32个字符") private String userNo; /** 部门ID */ - @Excel(name = "部门ID", type = Type.IMPORT) private Long deptId; /** 登录账号 */ @@ -62,15 +62,12 @@ public class SysUser extends BaseEntity private String nickName; /** 用户邮箱 */ - @Excel(name = "邮箱") @Email(message = "邮箱格式不正确") - @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + @Size( max = 50, message = "邮箱长度不能超过50个字符") private String email; /** 手机号码 */ - @Excel(name = "手机号", cellType = ColumnType.TEXT) - @NotBlank(message = "手机号不允许为空", groups = {ValidGroup.Create.class}) - @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") + @Size(max = 11, message = "手机号码长度不能超过11个字符") @Pattern(regexp = RegexpUtils.MOBILE_PHONE_REGEXP, message = "手机号格式不正确") private String phonenumber; @@ -132,6 +129,9 @@ public class SysUser extends BaseEntity @ApiModelProperty("在职情况") private String employStatus; + @ApiModelProperty("微信openId") + private String wxOpenId; + public SysUser(Long userId) { this.userId = userId; diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 986b0b2..0637fea 100644 --- a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -9,6 +9,7 @@ import java.time.*; import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; +import java.util.List; /** * 时间工具类 @@ -330,4 +331,40 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils public static LocalDate parseLocalDate(String val) { return null; } + + /** + * 获取列表中的最大年月,并返回最大年月的最后一天 + * @param yearMonthList 列表 + */ + public static LocalDate getMaxYearMonthLastDate(List yearMonthList, String pattern) { + if (yearMonthList == null || yearMonthList.isEmpty()) { + return null; + } + YearMonth maxYearMonth = null; + for (String yearMonth : yearMonthList) { + YearMonth localDate = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern(pattern)); + if (maxYearMonth == null || localDate.isAfter(maxYearMonth)) { + maxYearMonth = localDate; + } + } + return maxYearMonth.atEndOfMonth(); + } + + /** + * 获取列表中的最小年月,并返回最小年月的第一天 + * @param yearMonthList 列表 + */ + public static LocalDate getMinYearMonthFirstDate(List yearMonthList, String pattern) { + if (yearMonthList == null || yearMonthList.isEmpty()) { + return null; + } + YearMonth minYearMonth = null; + for (String yearMonth : yearMonthList) { + YearMonth localDate = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern(pattern)); + if (minYearMonth == null || localDate.isBefore(minYearMonth)) { + minYearMonth = localDate; + } + } + return minYearMonth.atDay(1); + } } diff --git a/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/RegexpUtils.java b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/RegexpUtils.java new file mode 100644 index 0000000..7f71d2d --- /dev/null +++ b/common-ruoyi/ruoyi-common/src/main/java/com/ruoyi/common/utils/RegexpUtils.java @@ -0,0 +1,464 @@ +package com.ruoyi.common.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author xdja + * @date 2020/11/20 16:08 + */ +public final class RegexpUtils { + /** + * 匹配email地址 + *

+ *

+ * 格式: XXX@XXX.XXX.XX + *

+ * 匹配 : foo@bar.com 或 foobar@foobar.com.au + *

+ * 不匹配: foo@bar 或 $$$@bar.com + */ + public static final String EMAIL_REGEXP = "^([a-zA-Z0-9]+[-|\\_|\\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[-|\\_|\\.]?)*[a-zA-Z0-9]+\\.[a-zA-Z]{2,}$"; + /** + * 匹配并提取url + *

+ *

+ * 格式: XXXX://XXX.XXX.XXX.XX/XXX.XXX?XXX=XXX + *

+ * 匹配 : http://www.suncer.com 或news://www + *

+ * 不匹配: c:/window + */ + public static final String URL_REGEXP = "(//w+)://([^/:]+)(://d*)?([^#//s]*)"; + /** + * 匹配并提取http + *

+ * 格式: http://XXX.XXX.XXX.XX/XXX.XXX?XXX=XXX 或 ftp://XXX.XXX.XXX 或 https://XXX + *

+ * 匹配 : http://www.suncer.com:8080/index.html?login=true + *

+ * 不匹配: news://www + */ + public static final String HTTP_REGEXP = "(http|https|ftp)://([^/:]+)(://d*)?([^#//s]*)"; + /** + * 匹配并提取http + *

+ * 格式: http://XXX.XXX.XXX.XX/XXX.XXX?XXX=XXX 或 ftp://XXX.XXX.XXX 或 https://XXX + *

+ * 匹配 : http://www.suncer.com:8080/index.html?login=true + *

+ * 不匹配: news://www + */ + public static final String HTTP_REGEXP_BANNER = "((https|http|ftp|rtsp|mms)?://)([0-9a-z_!~*'()-]+\\.)*([a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(\\.[a-zA-Z]{1,4})(:[0-9]{1,4})?((/?)|(/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+/?)\\.?$"; + /** + * 匹配日期 + *

+ *

+ * 格式(首位不为0): XXXX-XX-XX或 XXXX-X-X + *

+ *

+ * 范围:1900--2099 + *

+ *

+ * 匹配 : 2005-04-04 + *

+ *

+ * 不匹配: 01-01-01 + */ + public static final String DATE_BARS_REGEXP = "^((((19){1}|(20){1})\\d{2})|\\d{2})-[0,1]?\\d{1}-[0-3]?\\d{1}$"; + /** + * wzw + *

+ *

+ * 匹配格式 20160606 + */ + public static final String DATE_BARS_DAY_REGEXP = "^((((19){1}|(20){1})\\d{2})|\\d{2})[0,1]?\\d{1}[0-3]?\\d{1}$"; + /** + * 匹配格式 20130101 + */ + public static final String DATE_BARS_REGEXP_SIMPLE = + "([\\d]{4}(((0[13578]|1[02])((0[1-9])|([12][0-9])|(3[01])))|(((0[469])|11)((0[1-9])|([12][0-9])|30))|(02((0[1-9])|(1[0-9])|(2[0-8])))))|((((([02468][048])|([13579][26]))00)|([0-9]{2}(([02468][048])|([13579][26]))))(((0[13578]|1[02])((0[1-9])|([12][0-9])|(3[01])))|(((0[469])|11)((0[1-9])|([12][0-9])|30))|(02((0[1-9])|(1[0-9])|(2[0-9])))))"; + /** + * 匹配格式 20130101 + */ + public static final String DATE_BARS_REGEXP_HOUR_FULL = + "^\\d{4}-(?:0\\d|1[0-2])-(?:[0-2]\\d|3[01])( (?:[01]\\d|2[0-3])\\:[0-5]\\d)?$"; + /** + * 匹配日期 + *

+ *

+ * 格式(首位不为0): XXXX-XX-XX或 XXXX-X-X + *

+ *

+ * 范围:1900--2099 + *

+ *

+ * 匹配 : 2005-04-04 11:00:00 + *

+ *

+ * 不匹配: 01-01-01 + */ + public static final String DATE_BARS_REGEXP_HOUR = + "^((((19){1}|(20){1})\\d{2})|\\d{2})-[0,1]?\\d{1}-[0-3]?\\d{1}\\s[0,2]?\\d{1}[0,9]?\\d{1}$"; + + /** + * 匹配 : 2005-04-04 11:00:00 + */ + public static final String DATE_BARS_REGEXP_HOUR_MIN_SS = + "^\\d{4}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D+\\d{1,2}\\D*$"; + /** + * 匹配日期 + *

+ *

+ * 格式: XXXX.XX.XX + *

+ *

+ * 范围: + *

+ *

+ * 匹配 : 2005.04.04 + *

+ *

+ * 不匹配: 01.01.01 + */ + public static final String DATE_SLASH_REGEXP = "^[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}$"; + + /** + * 匹配电话 + *

+ *

+ * 格式为: 0XXX-XXXXXX(10-13位首位必须为0) 或0XXX XXXXXXX(10-13位首位必须为0) 或 + *

+ * (0XXX)XXXXXXXX(11-14位首位必须为0) 或 XXXXXXXX(6-8位首位不为0) 或 XXXXXXXXXXX(11位首位不为0) + *

+ *

+ * 匹配 : 0371-123456 或 (0371)1234567 或 (0371)12345678 或 010-123456 或 010-12345678 或 12345678912 + *

+ *

+ * 不匹配: 1111-134355 或 0123456789 + */ + public static final String PHONE_REGEXP = + "^(?:0[0-9]{2,3}[-//s]{1}|//(0[0-9]{2,4}//))[0-9]{6,8}$|^[1-9]{1}[0-9]{5,7}$|^[1-9]{1}[0-9]{10}$"; + + /** + * 11位手机号格式验证 + */ + public static final String MOBILE_PHONE_REGEXP = "^1[3,4,5,6,7,8,9]\\d{9}$"; + /** + * 20位联系方式格式验证 + */ + public static final String PHONE_20_REGEXP = "^[0-9\\-]{1,20}$"; + + /** + * 匹配身份证 + *

+ * 格式为: XXXXXXXXXX(10位) 或 XXXXXXXXXXXXX(13位) 或 XXXXXXXXXXXXXXX(15位) 或 XXXXXXXXXXXXXXXXXX(18位) + *

+ * 匹配 : 0123456789123 + *

+ * 不匹配: 0123456 + */ + public static final String IDENTITY_CARD_REGEXP = + "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$"; + /** + * 匹配身份证 + *

+ * 格式为: XXXXXXXXXX(10位) 或 XXXXXXXXXXXXX(13位) 或 XXXXXXXXXXXXXXX(15位) 或 XXXXXXXXXXXXXXXXXX(18位) + *

+ * 匹配 : 0123456789123 + *

+ * 不匹配: 0123456 + */ + public static final String ID_CARD_REGEXP = "^d{18} | $"; + + /** + * 匹配邮编代码 + *

+ * 格式为: XXXXXX(6位) + *

+ * 匹配 : 012345 + *

+ * 不匹配: 0123456 + */ + public static final String ZIP_REGEXP = "^[0-9]{6}$"; + + /** + * 不包括特殊字符的匹配 (字符串中不包括符号 数学次方号^ 单引号' 双引号" 分号; 逗号, 帽号: 数学减号- 右尖括号> 左尖括号< 反斜杠/ 即空格,制表符,回车符等 ) + *

+ * 格式为: x 或 一个一上的字符 + *

+ * 匹配 : 012345 + *

+ * 不匹配: 0123456 // ;,:-<>//s].+$";// + */ + public static final String NON_SPECIAL_CHAR_REGEXP = "^[^'/"; + + /** + * 匹配一位数的0-1整数 + */ + public static final String ZERO__TO_ONE_NUMBER = "[0-1]$"; + + /** + * 匹配一位数的0-2整数 + */ + public static final String ZERO__TO_TWO_NUMBER = "[0-2]$"; + + /** + * 匹配一位数的0-2整数 + */ + public static final String ZERO__TO_THREE_NUMBER = "[0-3]$"; + /** + * 匹配一位数的1-4的非负整数 + */ + public static final String ONE__TO_FOUR_NATURAL_NUMBER = "[1-4]$"; + /** + * 匹配一位数的0-4的非负整数 + */ + public static final String ZERO__TO_FOUR_NATURAL_NUMBER = "[0-4]$"; + /** + * 匹配一位数的1-3的非负整数 + */ + public static final String ONE_TO_THREE_NATURAL_NUMBER = "[1-3]$"; + /** + * 匹配一位数的1-3的非负整数 + */ + public static final String ONE__TO_TWO_NATURAL_NUMBER = "[1-3]$"; + /** + * 匹配一位数的1-6的非负整数 + */ + public static final String ONE__TO_SIX_NATURAL_NUMBER = "[1-6]$"; + /** + * 匹配0-18的正整数 + */ + public static final String ONE_TO_EIGHTEEN_NUMBER = "^(18|[0-9]|(1[0-8]))$"; + + /** + * 匹配1-99的正整数 + */ + public static final String ONE_TO_NINETYNINE_NUMBER = "^(99|[1-9]|([1-9][0-9]))$"; + + /** + * 匹配非负整数(正整数 + 0) + */ + public static final String NON_NEGATIVE_INTEGERS_REGEXP = "^//d+$"; + /** + * 匹配带1位小数且不超过2位的数 + */ + public static final String CAR_LENGTH_REGEXP = "^(\\d|\\d\\d)(\\.\\d)?$"; + /** + * 匹配整数位最大3位且小数位最大2位的数 + */ + public static final String CAR_LOAD_REGEXP = "^(\\d{1,3})(\\.\\d{1,2})?$"; + /** + * 匹配不包括零的非负整数(正整数 > 0) + */ + public static final String NON_ZERO_NEGATIVE_INTEGERS_REGEXP = "^[1-9]+//d*$"; + /** + * 匹配包括零的正整数 + */ + public static final String ZERO_NEGATIVE_INTEGERS_REGEXP = "^[0-9]*[0-9][0-9]*$"; + /** + * 匹配正整数 + */ + public static final String POSITIVE_INTEGER_REGEXP = "^[0-9]*[1-9][0-9]*$"; + /** + * 匹配非正整数(负整数 + 0) + */ + public static final String NON_POSITIVE_INTEGERS_REGEXP = "^((-//d+)|(0+))$"; + /** + * 匹配负整数 + */ + public static final String NEGATIVE_INTEGERS_REGEXP = "^-[0-9]*[1-9][0-9]*$"; + /** + * 匹配整数 + */ + public static final String INTEGER_REGEXP = "^-?//d+$"; + /** + * 匹配非负浮点数(正浮点数 + 0) + */ + public static final String NON_NEGATIVE_RATIONAL_NUMBERS_REGEXP = "^\\d+(\\.\\d+)?$"; + /** + * 匹配正浮点数 + */ + public static final String POSITIVE_RATIONAL_NUMBERS_REGEXP = "^[0-9]+(.[0-9]{1})?$"; + /** + * 匹配正浮点数(1-6位) + */ + public static final String POSITIVE_ONE_TO_SIX_RATIONAL_NUMBERS_REGEXP = "^((?!0\\d)\\d+(\\.\\d{1,6}?))$"; + /** + * 匹配非正浮点数(负浮点数 + 0) + */ + public static final String NON_POSITIVE_RATIONAL_NUMBERS_REGEXP = "^((-//d+(//.//d+)?)|(0+(//.0+)?))$"; + /** + * 匹配负浮点数 + */ + public static final String NEGATIVE_RATIONAL_NUMBERS_REGEXP = + "^(-(([0-9]+//.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*//.[0-9]+)|([0-9]*[1-9][0-9]*)))$"; + + /** + * 匹配浮点数 + */ + public static final String RATIONAL_NUMBERS_REGEXP = "^(-?//d+)(//.//d+)?$"; + /** + * 匹配由26个英文字母组成的字符串 + */ + public static final String LETTER_REGEXP = "^[A-Za-z]+$"; + /** + * 匹配由26个英文字母的大写组成的字符串 + */ + public static final String UPWARD_LETTER_REGEXP = "^[A-Z]+$"; + /** + * 匹配由A-D英文字母的大写的字符 + */ + public static final String UPWARD_LETTER_A_D = "^[A-D]{1}"; + /** + * 匹配由26个英文字母的大写的字符 + */ + public static final String UPWARD_LETTER_STR = "^[A-Z]{1}$"; + /** + * 匹配由26个英文字母的小写组成的字符串 + */ + public static final String LOWER_LETTER_REGEXP = "^[a-z]+$"; + /** + * 匹配由数字和26个英文字母组成的字符串 + */ + public static final String LETTER_NUMBER_REGEXP = "^[A-Za-z0-9]+$"; + /** + * 匹配由数字、26个英文字母或者下划线组成的字符串 + */ + public static final String LETTER_NUMBER_UNDERLINE_REGEXP = "^//w+$"; + /** + * 必须由数字和26个英文字母组合组成的字符串 + */ + public static final String LETTER_NUMBER_REGEXP_MUST = "[0-9]+[a-zA-Z]+[0-9a-zA-Z]*|[a-zA-Z]+[0-9]+[0-9a-zA-Z]*"; + /** + * 匹配5位数字 + */ + public static final String FIVE_NUMBER_ONLY_REGEXP = "^[0-9]{5}$"; + /** + * 匹配4位数字 + */ + public static final String FOUR_NUMBER_ONLY_REGEXP = "^[0-9]{4}$"; + /** + * 匹配1位字母 + */ + public static final String ONE_LETTER = "^[a-zA-Z]{1}$"; + /** + * 匹配19位数字 + */ + public static final String NINETEEN_NUMBER_ONLY_REGEXP = "^[0-9]{19}$"; + /** + * 匹配8位数字 + */ + public static final String EIGHT_NUMBER_ONLY_REGEXP = "^[0-9]{8}$"; + /** + * 匹配19位数字 + */ + public static final String TWENTY_NUMBER_ONLY_REGEXP = "^[0-9]{20}$"; + /** + * 匹配1位数字 + */ + public static final String NUMBER_ONLY_ONE_REGEXP = "^\\d$"; + /** + * 匹配日期 + *

+ *

+ * 格式: yyyymmdd + *

+ *

+ * 范围: + *

+ *

+ * 匹配 : 20050404 + *

+ *

+ * 不匹配: 010101 + */ + public static final String DATE_YYYYMMMDD_REGEXP = "(" + + "(^\\d{3}[1-9]|\\d{2}[1-9]\\d{1}|\\d{1}[1-9]\\d{2}|[1-9]\\d{3}" + "(10|12|0?[13578])" + + "((3[01]|[12][0-9]|0?[1-9])?)" + "([\\s]?)" + "((([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9]))?))$" + "|" + + "(^\\d{3}[1-9]|\\d{2}[1-9]\\d{1}|\\d{1}[1-9]\\d{2}|[1-9]\\d{3}" + "(11|0?[469])" + "(30|[12][0-9]|0?[1-9])" + + "([\\s]?)" + "((([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9]))?))$" + "|" + + "(^\\d{3}[1-9]|\\d{2}[1-9]\\d{1}|\\d{1}[1-9]\\d{2}|[1-9]\\d{3}" + "(0?2)" + "(2[0-8]|1[0-9]|0?[1-9])" + + "([\\s]?)" + "((([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9]))?))$" + "|" + + "(^((\\d{2})(0[48]|[2468][048]|[13579][26]))|((0[48]|[2468][048]|[13579][26])00)" + "(0?2)" + "(29)" + + "([\\s]?)" + "((([0-1]?\\d|2[0-3]):([0-5]?\\d):([0-5]?\\d))?))$" + ")"; + /** + * 匹配日期 格式: yyyymm 匹配 : 200504 不匹配: 010101 + */ + public static final String DATE_YYYYMM_REGEXP = "^(\\d{4})(0\\d{1}|1[0-2])$"; + /** + * 匹配日期 格式: yyyy-MM-dd 10位 匹配 : 2005-04-01 不匹配: 010101 + */ + public static final String DATE_YYYY_MM_DD_REGEXP = "^((?:19|20)\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$"; + /** + * 匹配日期 格式: yyyy/MM/dd 10位 匹配 : 2005/04/01 不匹配: 010101 + */ + public static final String DATE_YYYYMMDD_REGEXP = "^((?:19|20)\\d\\d)/(0[1-9]|1[012])/(0[1-9]|[12][0-9]|3[01])$"; + /** + * 匹配日期 格式: yyyyMMdd 8位 匹配 : 20050401 不匹配: 010101 + */ + public static final String DATE_YYYYMMDD_EIGHT_REGEXP = + "^((?:19|20)\\d\\d)(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$"; + /** + * 匹配格式 2016-02-02 01:01 + */ + public static final String DATE_BARS_REGEXP_HOUR_MIN = + "^\\d{4}-(?:0\\d|1[0-2])-(?:[0-2]\\d|3[01]) (?:[01]\\d|2[0-3])\\:[0-5]\\d?$"; + /** + * 匹配格式 2016-02-02 01:01:01 + */ + public static final String DATE_BARS_REGEXP_HOUR_MIN_SECOND = + "^\\d{4}[-]([0][1-9]|(1[0-2]))[-]([1-9]|([012]\\d)|(3[01]))([ \\t\\n\\x0B\\f\\r])(([0-1]{1}[0-9]{1})|([2]{1}[0-4]{1}))([:])(([0-5]{1}[0-9]{1}|[6]{1}[0]{1}))([:])((([0-5]{1}[0-9]{1}|[6]{1}[0]{1})))$"; + /** + * 匹配整数或者空串 + */ + public static final String NUMBER_BLANK_REGEXP = "^[1-9]\\d*|0|^\\s*$"; + /** + * 匹配正整数或者空串 + */ + public static final String POSITIVE_NUMBER_BLANK_REGEXP = "^[1-9]\\d*|^\\s*$"; + /** + * 任意位数的非负整数 + */ + public static final String NATURAL_NUMBER = "\\d*$"; + /** + * 数字加逗号 + */ + public static final String COMMA_NUMBER = "[\\d,]*$"; + /** + * 匹配汉字 + */ + public static final String CHINESE_VAR = "[\\u4e00-\\u9fa5]*$"; + /** + * 不允许包含"/"或"\"正则 + */ + public static final String BACK_SLANT_REGEXP = "^[^/^\\\\]+$"; + + /** + * 匹配日期 格式: yyyy-MM 7位 匹配 : 2005-04 不匹配: 0101 + */ + public static final String DATE_YYYY_MM_REGEXP = "^((?:19|20)\\d\\d)-(0[1-9]|1[012])$"; + + + private RegexpUtils() { + } + + /** + * 校验正则表达式结果 + * + * @param content + * @param reg + * @return + */ + public static boolean validateInfo(String content, String reg) { + + Pattern pat = Pattern.compile(reg); + Matcher mat = pat.matcher(content); + + return mat.matches(); + } + + +} + diff --git a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 511842b..7078230 100644 --- a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.ruoyi.framework.config; +import com.ruoyi.framework.security.filter.CustomLoginAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -23,7 +24,7 @@ import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl; /** * spring security配置 - * + * * @author ruoyi */ @EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) @@ -35,7 +36,7 @@ public class SecurityConfig */ @Autowired private UserDetailsService userDetailsService; - + /** * 认证失败处理类 */ @@ -53,7 +54,7 @@ public class SecurityConfig */ @Autowired private JwtAuthenticationTokenFilter authenticationTokenFilter; - + /** * 跨域过滤器 */ @@ -72,10 +73,10 @@ public class SecurityConfig @Bean public AuthenticationManager authenticationManager() { - DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); - daoAuthenticationProvider.setUserDetailsService(userDetailsService); - daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); - return new ProviderManager(daoAuthenticationProvider); + CustomLoginAuthenticationProvider provider = new CustomLoginAuthenticationProvider(); + provider.setUserDetailsService(userDetailsService); + provider.setPasswordEncoder(bCryptPasswordEncoder()); + return new ProviderManager(provider); } /** @@ -111,7 +112,7 @@ public class SecurityConfig .authorizeHttpRequests((requests) -> { permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll()); // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - requests.antMatchers("/login", "/register", "/captchaImage").permitAll() + requests.antMatchers("/login", "/register", "/captchaImage", "/wxLogin").permitAll() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() diff --git a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/CustomLoginAuthenticationProvider.java b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/CustomLoginAuthenticationProvider.java new file mode 100644 index 0000000..ba437ce --- /dev/null +++ b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/CustomLoginAuthenticationProvider.java @@ -0,0 +1,21 @@ +package com.ruoyi.framework.security.filter; + +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * 自定义登录扩展 + */ +public class CustomLoginAuthenticationProvider extends DaoAuthenticationProvider { + + public CustomLoginAuthenticationProvider() { + super(); + } + + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + // 什么都不需要做 + } +} diff --git a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index e7108ce..0a2b825 100644 --- a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -1,6 +1,10 @@ package com.ruoyi.framework.web.service; import javax.annotation.Resource; + +import com.ruoyi.common.auth.wx.WxAuthService; +import com.ruoyi.common.enums.UserStatus; +import com.ruoyi.common.utils.ServiceUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; @@ -29,6 +33,8 @@ import com.ruoyi.framework.security.context.AuthenticationContextHolder; import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysUserService; +import java.util.Objects; + /** * 登录校验方法 * @@ -52,6 +58,9 @@ public class SysLoginService @Autowired private ISysConfigService configService; + @Autowired + private WxAuthService wxAuthService; + /** * 登录验证 * @@ -73,6 +82,8 @@ public class SysLoginService { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); AuthenticationContextHolder.setContext(authenticationToken); + // 把用户登录类型放在上下文中的details属性中,在UserDetailsServiceImpl.loadUserByUsername中获取 + authenticationToken.setDetails(Constants.LOGIN_TYPE_PASSWORD); // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername authentication = authenticationManager.authenticate(authenticationToken); } @@ -178,4 +189,35 @@ public class SysLoginService sysUser.setLoginDate(DateUtils.getNowDate()); userService.updateUserProfile(sysUser); } + + public String wxLogin(String loginCode) { + // 通过openId查询用户 + String openId = wxAuthService.getOpenId(loginCode); + ServiceUtil.assertion(openId == null, "获取微信openId失败"); + SysUser user = userService.selectByWxOpenId(openId); + + ServiceUtil.assertion(user == null, "当前微信尚未绑定账号,请使用账号密码登录"); + + Authentication authentication = null; + try { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserId(), ""); + // 用户名和密码等信息保存在一个上下文中,只要是同一线程等会就能拿到用户名和密码,也就是能在loadUserByUsername(String username)方法中进行密码验证等 + AuthenticationContextHolder.setContext(authenticationToken); + // 把用户登录类型放在上下文中的details属性中,在UserDetailsServiceImpl.loadUserByUsername中获取 + authenticationToken.setDetails(Constants.LOGIN_TYPE_WX); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) { + if (e instanceof BadCredentialsException) { + throw new UserPasswordNotMatchException(); //抛出账号或者密码错误的异常 + } else { + throw new ServiceException(e.getMessage()); //抛出其他异常 + } + } finally { + AuthenticationContextHolder.clearContext(); + } + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + return tokenService.createToken(loginUser); + } } diff --git a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java index 6ca6323..f144b52 100644 --- a/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java +++ b/common-ruoyi/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java @@ -1,8 +1,12 @@ package com.ruoyi.framework.web.service; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.framework.security.context.AuthenticationContextHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -37,7 +41,27 @@ public class UserDetailsServiceImpl implements UserDetailsService @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - SysUser user = userService.selectUserByUserName(username); + + Authentication authentication = AuthenticationContextHolder.getContext(); + String loginType = (String) authentication.getDetails(); + ServiceUtil.assertion(StringUtils.isBlank(loginType), "用户登录方式未正常获取"); + + if (Constants.LOGIN_TYPE_PASSWORD.equals(loginType)) { + SysUser user = userService.selectUserByUserName(username); + this.checkUser(user, username); + passwordService.validate(user); + return createLoginUser(user); + } else if (Constants.LOGIN_TYPE_WX.equals(loginType)) { + SysUser user = userService.selectUserById(Long.valueOf(username)); + this.checkUser(user, username); + return createLoginUser(user); + } else { + throw new ServiceException("不支持的登录方式"); + } + } + + + private void checkUser(SysUser user, String username) { if (StringUtils.isNull(user)) { log.info("登录用户:{} 不存在.", username); @@ -53,10 +77,6 @@ public class UserDetailsServiceImpl implements UserDetailsService log.info("登录用户:{} 已被停用.", username); throw new ServiceException(MessageUtils.message("user.blocked")); } - - passwordService.validate(user); - - return createLoginUser(user); } public UserDetails createLoginUser(SysUser user) diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVO.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVO.java deleted file mode 100644 index 8cbb7c6..0000000 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysUserVO.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ruoyi.system.domain.vo; - -import com.ruoyi.common.core.domain.entity.SysUser; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * @author wjh - * 2024/10/22 - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class SysUserVO extends SysUser { -} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index bc5a25f..fc7f2d5 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -2,8 +2,8 @@ package com.ruoyi.system.service; import java.util.List; import com.ruoyi.common.core.domain.entity.SysUser; -import com.ruoyi.system.domain.dto.SysUserQuery; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserVO; /** * 用户 业务层 @@ -196,7 +196,7 @@ public interface ISysUserService * @param operaId 操作用户 * @return 结果 */ - public int importUser(List userList, Boolean isUpdateSupport, Long operaId); + public int importUser(List userList, Boolean isUpdateSupport, Long operaId); /** * 根据用户名称列表查询用户 @@ -213,4 +213,22 @@ public interface ISysUserService * 查询数量 */ int selectCount(SysUserQuery query); + + /* + * 用户授权绑定微信 + * @return 绑定成功则返回openId,否则返回 null + */ + String bindWxByLoginCode(Long userId, String loginCode); + + /** + * 根据openId查询用户 + * @param openId + * @return + */ + SysUserVO selectByWxOpenId(String openId); + + /** + * 解绑微信 + */ + int unbindWx(Long userId); } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 1560b2a..4f0d16d 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -3,16 +3,20 @@ package com.ruoyi.system.service.impl; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.validation.Validator; import com.github.pagehelper.PageHelper; +import com.ruoyi.common.auth.wx.WxAuthService; +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.common.core.validate.ValidGroup; import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.collection.CollectionUtils; -import com.ruoyi.system.domain.dto.SysUserQuery; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserVO; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.user.service.UserValidator; import com.ruoyi.yh.logImport.domain.LogImportVO; @@ -40,7 +44,7 @@ import com.ruoyi.system.domain.SysUserPost; import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.mapper.SysPostMapper; import com.ruoyi.system.mapper.SysRoleMapper; -import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.user.mapper.SysUserMapper; import com.ruoyi.system.mapper.SysUserPostMapper; import com.ruoyi.system.mapper.SysUserRoleMapper; import com.ruoyi.system.service.ISysConfigService; @@ -100,6 +104,9 @@ public class SysUserServiceImpl implements ISysUserService @Autowired private ISysRoleService roleService; + @Autowired + private WxAuthService wxAuthService; + /** * 根据条件分页查询用户列表 @@ -538,7 +545,7 @@ public class SysUserServiceImpl implements ISysUserService * @return 结果 */ @Override - public int importUser(List userList, Boolean isUpdateSupport, Long operaId) { + public int importUser(List userList, Boolean isUpdateSupport, Long operaId) { if (CollectionUtils.isEmptyElement(userList)) { throw new ServiceException("导入用户数据不能为空!"); } @@ -552,13 +559,21 @@ public class SysUserServiceImpl implements ISysUserService // 开始异步导入 scheduledExecutorService.schedule(() -> { - for (SysUser user : userList) { + + // 查询部门列表 + List deptList = deptService.selectDeptListByNames(CollectionUtils.map(userList, SysUserVO::getDeptName)); + SysDept defaultDept = new SysDept(); + + for (SysUserVO user : userList) { try { // 通过手机号验证是否存在这个用户 - SysUser u = this.selectUserByPhonenumber(user.getPhonenumber()); + SysUser old = this.selectUserByUserNo(user.getUserNo()); transactionTemplate.execute(status -> { - if (StringUtils.isNull(u)) { - BeanValidators.validateWithException(validator, user); + + user.setDeptId(deptList.stream().filter(d -> Objects.equals(d.getDeptName(), user.getDeptName())).findFirst().orElse(defaultDept).getDeptId()); + + if (StringUtils.isNull(old)) { + BeanValidators.validateWithException(validator, ValidGroup.Create.class); deptService.checkDeptDataScope(user.getDeptId()); String password = configService.selectConfigByKey("sys.user.initPassword"); user.setPassword(SecurityUtils.encryptPassword(password)); @@ -569,11 +584,9 @@ public class SysUserServiceImpl implements ISysUserService return insert; } else if (isUpdateSupport) { - BeanValidators.validateWithException(validator, user); - checkUserAllowed(u); - checkUserDataScope(u.getUserId()); - deptService.checkDeptDataScope(user.getDeptId()); - user.setUserId(u.getUserId()); + BeanValidators.validateWithException(validator, ValidGroup.Update.class); + checkUserAllowed(old); + user.setUserId(old.getUserId()); user.setUpdateBy(operator.getNickName()); int update = userMapper.updateUser(user); ServiceUtil.assertion(update != 1, "修改用户失败"); @@ -581,13 +594,13 @@ public class SysUserServiceImpl implements ISysUserService return update; } else { - String msg = "用户手机号为 " + user.getPhonenumber() + " 的数据已存在"; + String msg = "用户工号为 " + user.getUserNo() + " 的数据已存在"; logImportDetailService.addResult(importLog.getLogId(), LogImportDetailType.FAIL, user, msg); return 0; } }); } catch (Exception e) { - String msg = "用户手机号为 " + user.getPhonenumber() + " 的数据导入失败:" + e.getMessage(); + String msg = "用户工号为 " + user.getUserNo() + " 的数据导入失败:" + e.getMessage(); log.error(msg, e); logImportDetailService.addResult(importLog.getLogId(), LogImportDetailType.FAIL, user, msg); } @@ -602,6 +615,15 @@ public class SysUserServiceImpl implements ISysUserService return userList.size(); } + private SysUser selectUserByUserNo(String userNo) { + if (StringUtils.isBlank(userNo)) { + return null; + } + SysUserQuery query = new SysUserQuery(); + query.setEqUserNo(userNo); + return selectOne(query); + } + @Override public SysUser selectUserByPhonenumber(String phonenumber) { if (StringUtils.isBlank(phonenumber)) { @@ -617,7 +639,52 @@ public class SysUserServiceImpl implements ISysUserService return userMapper.selectCount(query); } - private SysUser selectOne(SysUserQuery query) { + @Override + public String bindWxByLoginCode(Long userId, String loginCode) { + if (userId == null || StringUtils.isBlank(loginCode)) { + log.error("绑定微信失败:参数错误 userId = {}, loginCode = {}", userId, loginCode); + return null; + } + + // 获取微信openId + String openId = wxAuthService.getOpenId(loginCode); + ServiceUtil.assertion(StringUtils.isBlank(openId), "获取微信openId失败"); + + // 获取用户信息 + SysUser user = selectUserById(userId); + ServiceUtil.assertion(user == null, "用户不存在"); + ServiceUtil.assertion(StringUtils.hasText(user.getWxOpenId()), "当前用户已绑定微信,请解绑后重试"); + + // 操作绑定 + Integer result = transactionTemplate.execute(status -> { + int update = userMapper.bindWxOpenId(user.getUserId(), openId); + ServiceUtil.assertion(update != 1, "绑定微信失败,当前用户信息已发生变化,请重试"); + return update; + }); + + if (result != null && result == 1) { + return openId; + } else { + return null; + } + } + + @Override + public SysUserVO selectByWxOpenId(String openId) { + if (StringUtils.isBlank(openId)) { + return null; + } + SysUserQuery query = new SysUserQuery(); + query.setEqWxOpenId(openId); + return this.selectOne(query); + } + + @Override + public int unbindWx(Long userId) { + return userMapper.unbindWxOpenId(userId); + } + + private SysUserVO selectOne(SysUserQuery query) { PageHelper.startPage(1, 1); List list = userMapper.selectUserList(query); if (CollectionUtils.isEmpty(list)) { diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserQuery.java similarity index 81% rename from common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java rename to common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserQuery.java index 1f0207f..a41f07b 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/SysUserQuery.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserQuery.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain.dto; +package com.ruoyi.system.user.domain; import com.ruoyi.common.core.domain.entity.SysUser; import io.swagger.annotations.ApiModelProperty; @@ -13,7 +13,7 @@ import java.util.List; */ @Data @EqualsAndHashCode(callSuper = true) -public class SysUserQuery extends SysUser { +public class SysUserQuery extends SysUserVO { @ApiModelProperty("用户ID列表") private List userIds; @@ -27,6 +27,9 @@ public class SysUserQuery extends SysUser { @ApiModelProperty("精准手机号") private String eqPhonenumber; + @ApiModelProperty("精准微信openId") + private String eqWxOpenId; + @ApiModelProperty("精准工号") private String eqUserNo; diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserVO.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserVO.java new file mode 100644 index 0000000..0a8b2f8 --- /dev/null +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/domain/SysUserVO.java @@ -0,0 +1,21 @@ +package com.ruoyi.system.user.domain; + +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.entity.SysUser; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author wjh + * 2024/10/22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SysUserVO extends SysUser { + + @ApiModelProperty("部门名称") + @Excel(name = "部门名称", type = Excel.Type.IMPORT) + private String deptName; + +} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.java similarity index 89% rename from common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java rename to common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.java index dbff1e4..0e5ad70 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.java @@ -1,9 +1,9 @@ -package com.ruoyi.system.mapper; +package com.ruoyi.system.user.mapper; import java.util.List; -import com.ruoyi.system.domain.dto.SysUserQuery; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserVO; import org.apache.ibatis.annotations.Param; import com.ruoyi.common.core.domain.entity.SysUser; @@ -133,4 +133,13 @@ public interface SysUserMapper */ int selectCount(SysUserQuery query); + /** + * 绑定微信openId + */ + int bindWxOpenId(@Param("userId") Long userId,@Param("openId") String openId); + + /** + * 解绑微信 + */ + int unbindWxOpenId(Long userId); } diff --git a/common-ruoyi/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.xml similarity index 92% rename from common-ruoyi/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml rename to common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.xml index a8bb29e..4897bd1 100644 --- a/common-ruoyi/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/mapper/SysUserMapper.xml @@ -2,10 +2,11 @@ - + + @@ -51,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" u.birthday, u.employ_date, u.employ_status, + u.wx_open_id, d.dept_id, d.parent_id, d.ancestors, @@ -81,6 +83,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND u.status = #{status} + + AND u.wx_open_id like concat('%', #{wxOpenId}, '%') + + + AND u.wx_open_id = #{eqWxOpenId} + AND u.phonenumber like concat('%', #{phonenumber}, '%') @@ -143,6 +151,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" u.birthday, u.employ_date, u.employ_status, + u.wx_open_id, d.dept_name, d.leader from sys_user u left join sys_dept d on u.dept_id = d.dept_id @@ -237,6 +246,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" birthday, employ_date, employ_status, + wx_open_id, create_time )values( #{userId}, @@ -255,6 +265,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{birthday}, #{employDate}, #{employStatus}, + #{wxOpenId}, sysdate() ) @@ -279,6 +290,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" birthday = #{birthday}, employ_date = #{employDate}, employ_status = #{employStatus}, + wx_open_id = #{wxOpenId}, update_time = sysdate() where user_id = #{userId} @@ -296,7 +308,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update sys_user set password = #{password} where user_name = #{userName} - + + update sys_user + set wx_open_id = #{openId} + where user_id = #{userId} and (wx_open_id is null or wx_open_id = '') + + + + update sys_user + set wx_open_id = null + where user_id = #{userId} and wx_open_id is not null and wx_open_id != '' + + + update sys_user set del_flag = '2' where user_id = #{userId} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/UserValidator.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/UserValidator.java index 0947e83..a3d5391 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/UserValidator.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/UserValidator.java @@ -1,5 +1,6 @@ package com.ruoyi.system.user.service; +import com.ruoyi.common.core.domain.entity.SysUser; import org.springframework.stereotype.Service; /** diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/impl/UserValidatorImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/impl/UserValidatorImpl.java index 31194e6..a1c0b1f 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/impl/UserValidatorImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/system/user/service/impl/UserValidatorImpl.java @@ -1,7 +1,7 @@ package com.ruoyi.system.user.service.impl; import com.ruoyi.common.utils.ServiceUtil; -import com.ruoyi.system.domain.dto.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserQuery; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.user.service.UserValidator; import org.apache.commons.lang3.StringUtils; diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/price/service/impl/PriceServiceImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/price/service/impl/PriceServiceImpl.java index eb0db4f..b144218 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/price/service/impl/PriceServiceImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/price/service/impl/PriceServiceImpl.java @@ -16,7 +16,7 @@ import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.bean.BeanValidators; import com.ruoyi.common.utils.collection.CollectionUtils; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserVO; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.yh.logImport.domain.LogImportVO; diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/report/service/impl/ReportValidatorImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/report/service/impl/ReportValidatorImpl.java index 28ff715..2dbc6ac 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/report/service/impl/ReportValidatorImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/report/service/impl/ReportValidatorImpl.java @@ -3,8 +3,8 @@ package com.ruoyi.yh.report.service.impl; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.collection.CollectionUtils; -import com.ruoyi.system.domain.dto.SysUserQuery; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserVO; import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.yh.price.domain.PriceQuery; diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/ReportUserProdQuery.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/ReportUserProdQuery.java index 5d8c436..c3bb3e7 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/ReportUserProdQuery.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/ReportUserProdQuery.java @@ -2,7 +2,10 @@ package com.ruoyi.yh.reportUserProd.domain; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDate; +import java.time.YearMonth; import java.util.List; /** @@ -15,4 +18,18 @@ public class ReportUserProdQuery extends ReportUserProdVO { @ApiModelProperty("产量ID列表") private List prodIds; + @ApiModelProperty("年份") + private Integer year; + + @ApiModelProperty("月份") + private Integer month; + + @ApiModelProperty("起始日期") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate startDate; + + @ApiModelProperty("结束日期") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate endDate; + } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdDetailVO.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdDetailVO.java new file mode 100644 index 0000000..9f18a0e --- /dev/null +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdDetailVO.java @@ -0,0 +1,22 @@ +package com.ruoyi.yh.reportUserProd.domain.vo; + +import com.ruoyi.yh.reportUserProd.domain.ReportUserProdVO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author wjh + * 2024/12/5 + */ +@Data +public class ReportUserProdDetailVO { + + @ApiModelProperty("当日统计") + private ReportUserProdGroupByDateVO group; + + @ApiModelProperty("员工产量报表列表") + private List list; + +} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByDateVO.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByDateVO.java new file mode 100644 index 0000000..68d6ba4 --- /dev/null +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByDateVO.java @@ -0,0 +1,27 @@ +package com.ruoyi.yh.reportUserProd.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * @author wjh + * 2024/12/5 + */ +@Data +public class ReportUserProdGroupByDateVO { + + @ApiModelProperty("日期") + private LocalDate date; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("已审核金额") + private BigDecimal verified; + + @ApiModelProperty("审核中金额") + private BigDecimal verifying; +} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByYearMonthVO.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByYearMonthVO.java new file mode 100644 index 0000000..6371b5c --- /dev/null +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/domain/vo/ReportUserProdGroupByYearMonthVO.java @@ -0,0 +1,38 @@ +package com.ruoyi.yh.reportUserProd.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.YearMonth; +import java.util.List; + +/** + * @author wjh + * 2024/12/5 + */ +@Data +public class ReportUserProdGroupByYearMonthVO { + + @ApiModelProperty("年份") + private Integer year; + + @ApiModelProperty("月份") + private Integer month; + + @ApiModelProperty("年月") + private String yearMonth; + + @ApiModelProperty("用户ID") + private Long userId; + + @ApiModelProperty("已审核金额") + private BigDecimal verified; + + @ApiModelProperty("审核中金额") + private BigDecimal verifying; + + @ApiModelProperty("明细") + private List children; + +} diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.java index db10c7f..68e86ee 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.java @@ -5,6 +5,8 @@ import com.ruoyi.yh.reportUserProd.domain.ReportUserProd; import com.ruoyi.yh.reportUserProd.domain.ReportUserProdVO; import com.ruoyi.yh.reportUserProd.domain.ReportUserProdQuery; import com.ruoyi.yh.reportUserProd.domain.bo.ReportUserProdBO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByDateVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; import org.apache.ibatis.annotations.Param; /** @@ -77,4 +79,14 @@ public interface ReportUserProdMapper * 批量逻辑删除 */ int batchLogicDel(@Param("ids") List ids); + + /** + * 查询统计,根据年月分组 + */ + List selectListGroupByYearMonth(@Param("query") ReportUserProdQuery query); + + /** + * 查询统计,根据日期分组 + */ + List selectListGroupByDate(@Param("query") ReportUserProdQuery query); } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.xml b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.xml index 4414ecb..fa74ed3 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.xml +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/mapper/ReportUserProdMapper.xml @@ -32,8 +32,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and brup.prod_id = #{query.prodId} and brup.user_id = #{query.userId} and brp.report_id = #{query.reportId} - and brup.deleted = `false` + and brup.deleted = false and brup.deleted = #{query.deleted} + and br.report_date = #{query.reportDate} + and year(br.report_date) = #{query.year} + and month(br.report_date) = #{query.month} + and date(br.report_date) >= #{query.startDate} + and date(br.report_date) <= #{query.endDate} and brup.prod_id in @@ -55,6 +60,49 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where brup.id = #{id} and brp.deleted = false + + + + + + + + + + + + insert into bst_report_user_prod diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdAssembler.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdAssembler.java index 4def144..0a69287 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdAssembler.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdAssembler.java @@ -1,6 +1,6 @@ package com.ruoyi.yh.reportUserProd.service; -import com.ruoyi.yh.reportProd.domain.ReportProdVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; import java.util.List; @@ -10,4 +10,8 @@ import java.util.List; */ public interface ReportUserProdAssembler { + /** + * 拼接子集 + */ + void assembleChildren(List list, Long userId); } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdService.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdService.java index bb091c4..67c35a8 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdService.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/ReportUserProdService.java @@ -4,6 +4,8 @@ import java.util.List; import com.ruoyi.yh.reportUserProd.domain.ReportUserProd; import com.ruoyi.yh.reportUserProd.domain.ReportUserProdVO; import com.ruoyi.yh.reportUserProd.domain.ReportUserProdQuery; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByDateVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; /** * 员工产量Service接口 @@ -85,4 +87,8 @@ public interface ReportUserProdService * 批量删除 */ int batchLogicDel(List list); + + List selectListGroupByYearMonth(ReportUserProdQuery query); + + List selectListGroupByDate(ReportUserProdQuery query); } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdAssemblerImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdAssemblerImpl.java index 7ab7161..b0a1b77 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdAssemblerImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdAssemblerImpl.java @@ -1,17 +1,18 @@ package com.ruoyi.yh.reportUserProd.service.impl; +import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.collection.CollectionUtils; -import com.ruoyi.yh.reportProd.domain.ReportProdVO; import com.ruoyi.yh.reportUserProd.domain.ReportUserProdQuery; -import com.ruoyi.yh.reportUserProd.domain.ReportUserProdVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByDateVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; import com.ruoyi.yh.reportUserProd.service.ReportUserProdAssembler; import com.ruoyi.yh.reportUserProd.service.ReportUserProdService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; +import java.time.LocalDate; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; /** @@ -24,4 +25,31 @@ public class ReportUserProdAssemblerImpl implements ReportUserProdAssembler { @Autowired private ReportUserProdService reportUserProdService; + @Override + public void assembleChildren(List list, Long userId) { + if (CollectionUtils.isEmptyElement(list)) { + return; + } + // 确认日期范围 + // 获取列表最大年月、最小年月 + String pattern = "yyyy-MM"; + List yearMonthList = list.stream().map(ReportUserProdGroupByYearMonthVO::getYearMonth).collect(Collectors.toList()); + LocalDate endDate = DateUtils.getMaxYearMonthLastDate(yearMonthList, pattern); + LocalDate startDate = DateUtils.getMinYearMonthFirstDate(yearMonthList, pattern); + + // 查询列表 + ReportUserProdQuery query = new ReportUserProdQuery(); + query.setUserId(userId); + query.setStartDate(startDate); + query.setEndDate(endDate); + List groups = reportUserProdService.selectListGroupByDate(query); + + // 拼接数据 + for (ReportUserProdGroupByYearMonthVO vo : list) { + List children = groups.stream().filter(item -> + Objects.equals(item.getDate().getYear(), vo.getYear()) && Objects.equals(item.getDate().getMonthValue(), vo.getMonth()) + ).collect(Collectors.toList()); + vo.setChildren(children); + } + } } diff --git a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdServiceImpl.java b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdServiceImpl.java index ca6ae35..1c5d4ec 100644 --- a/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdServiceImpl.java +++ b/common-ruoyi/ruoyi-system/src/main/java/com/ruoyi/yh/reportUserProd/service/impl/ReportUserProdServiceImpl.java @@ -2,9 +2,10 @@ package com.ruoyi.yh.reportUserProd.service.impl; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import com.ruoyi.common.utils.collection.CollectionUtils; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByDateVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.yh.reportUserProd.mapper.ReportUserProdMapper; @@ -131,4 +132,14 @@ public class ReportUserProdServiceImpl implements ReportUserProdService List ids = CollectionUtils.map(list, ReportUserProd::getId); return reportUserProdMapper.batchLogicDel(ids); } + + @Override + public List selectListGroupByYearMonth(ReportUserProdQuery query) { + return reportUserProdMapper.selectListGroupByYearMonth(query); + } + + @Override + public List selectListGroupByDate(ReportUserProdQuery query) { + return reportUserProdMapper.selectListGroupByDate(query); + } } diff --git a/ruoyi-web/src/main/java/com/ruoyi/app/AppUserProdController.java b/ruoyi-web/src/main/java/com/ruoyi/app/AppUserProdController.java new file mode 100644 index 0000000..70133f0 --- /dev/null +++ b/ruoyi-web/src/main/java/com/ruoyi/app/AppUserProdController.java @@ -0,0 +1,76 @@ +package com.ruoyi.app; + +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.utils.collection.CollectionUtils; +import com.ruoyi.yh.reportUserProd.domain.ReportUserProdQuery; +import com.ruoyi.yh.reportUserProd.domain.ReportUserProdVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdDetailVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByDateVO; +import com.ruoyi.yh.reportUserProd.domain.vo.ReportUserProdGroupByYearMonthVO; +import com.ruoyi.yh.reportUserProd.service.ReportUserProdAssembler; +import com.ruoyi.yh.reportUserProd.service.ReportUserProdService; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDate; +import java.util.List; + +/** + * @author wjh + * 2024/12/5 + */ +@RestController +@RequestMapping("/app/userProd") +public class AppUserProdController extends BaseController { + + @Autowired + private ReportUserProdService reportUserProdService; + + @Autowired + private ReportUserProdAssembler reportUserProdAssembler; + + @ApiOperation("根据年月分组查询本人工资列表") + @GetMapping("/listGroupByYearMonth") + public TableDataInfo listGroupByYearMonth(ReportUserProdQuery query) { + query.setUserId(getUserId()); + startPage(); + List list = reportUserProdService.selectListGroupByYearMonth(query); + reportUserProdAssembler.assembleChildren(list, getUserId()); + return getDataTable(list); + } + + @ApiOperation("根据日期分组查询本人工资列表") + @GetMapping("/listGroupByDate") + public TableDataInfo listGroupByDate(ReportUserProdQuery query) { + query.setUserId(getUserId()); + startPage(); + return getDataTable(reportUserProdService.selectListGroupByDate(query)); + } + + @ApiModelProperty("按日查询本人工资明细") + @GetMapping("/detailByDate") + public AjaxResult detailByDate(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd")LocalDate date) { + ReportUserProdQuery query = new ReportUserProdQuery(); + query.setReportDate(date); + query.setUserId(getUserId()); + List groups = reportUserProdService.selectListGroupByDate(query); + if (CollectionUtils.isEmptyElement(groups)) { + return success(); + } + List list = reportUserProdService.selectReportUserProdList(query); + + ReportUserProdDetailVO vo = new ReportUserProdDetailVO(); + vo.setGroup(groups.get(0)); + vo.setList(list); + return success(vo); + } + +} diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysLoginController.java b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysLoginController.java index f5f5ef6..6fc8153 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysLoginController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysLoginController.java @@ -2,11 +2,10 @@ package com.ruoyi.web.system; import java.util.List; import java.util.Set; + +import com.ruoyi.system.service.ISysUserService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysMenu; @@ -34,6 +33,9 @@ public class SysLoginController @Autowired private SysPermissionService permissionService; + @Autowired + private ISysUserService userService; + /** * 登录方法 * @@ -51,6 +53,19 @@ public class SysLoginController return ajax; } + /** + * 微信授权登录 + */ + @PostMapping("/wxLogin") + public AjaxResult wxLogin(@RequestParam String loginCode) + { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = loginService.wxLogin(loginCode); + ajax.put(Constants.TOKEN, token); + return ajax; + } + /** * 获取用户信息 * @@ -59,7 +74,7 @@ public class SysLoginController @GetMapping("getInfo") public AjaxResult getInfo() { - SysUser user = SecurityUtils.getLoginUser().getUser(); + SysUser user = userService.selectUserById(SecurityUtils.getUserId()); // 角色集合 Set roles = permissionService.getRolePermission(user); // 权限集合 diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysProfileController.java b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysProfileController.java index b0e7c32..484032a 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysProfileController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysProfileController.java @@ -1,5 +1,6 @@ package com.ruoyi.web.system; +import com.ruoyi.system.user.service.UserValidator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -38,6 +39,9 @@ public class SysProfileController extends BaseController @Autowired private TokenService tokenService; + @Autowired + private UserValidator userValidator; + /** * 个人信息 */ @@ -45,7 +49,7 @@ public class SysProfileController extends BaseController public AjaxResult profile() { LoginUser loginUser = getLoginUser(); - SysUser user = loginUser.getUser(); + SysUser user = userService.selectUserById(loginUser.getUserId()); AjaxResult ajax = AjaxResult.success(user); ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); @@ -133,4 +137,20 @@ public class SysProfileController extends BaseController } return error("上传图片异常,请联系管理员"); } + + @Log(title = "绑定微信", businessType = BusinessType.OTHER) + @PutMapping("/bindWx") + public AjaxResult bindWx(@RequestParam String loginCode) { + String openId = userService.bindWxByLoginCode(getUserId(), loginCode); + if (StringUtils.isBlank(openId)) { + return error("绑定微信失败"); + } + return AjaxResult.success("绑定成功", openId); + } + + @Log(title = "解绑微信", businessType = BusinessType.OTHER) + @PutMapping("/unbindWx") + public AjaxResult unbindWx() { + return toAjax(userService.unbindWx(getUserId())); + } } diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java index 119492a..2f5a72d 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/system/SysUserController.java @@ -4,9 +4,10 @@ import java.util.List; import java.util.stream.Collectors; import javax.servlet.http.HttpServletResponse; +import com.ruoyi.common.core.validate.ValidGroup; import com.ruoyi.system.domain.dto.SysDeptQuery; -import com.ruoyi.system.domain.dto.SysUserQuery; -import com.ruoyi.system.domain.vo.SysUserVO; +import com.ruoyi.system.user.domain.SysUserQuery; +import com.ruoyi.system.user.domain.SysUserVO; import org.apache.commons.lang3.ArrayUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -97,8 +98,8 @@ public class SysUserController extends BaseController @PostMapping("/importData") public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { - ExcelUtil util = new ExcelUtil(SysUser.class); - List userList = util.importExcel(file.getInputStream()); + ExcelUtil util = new ExcelUtil(SysUserVO.class); + List userList = util.importExcel(file.getInputStream()); int size = userService.importUser(userList, updateSupport, getUserId()); return success(size); } @@ -138,7 +139,7 @@ public class SysUserController extends BaseController @PreAuthorize("@ss.hasPermi('system:user:add')") @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping - public AjaxResult add(@Validated @RequestBody SysUser user) { + public AjaxResult add(@Validated(ValidGroup.Create.class) @RequestBody SysUser user) { user.setCreateBy(getUsername()); return toAjax(userService.insertUser(user)); } @@ -149,7 +150,7 @@ public class SysUserController extends BaseController @PreAuthorize("@ss.hasPermi('system:user:edit')") @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult edit(@Validated @RequestBody SysUser user) { + public AjaxResult edit(@Validated(ValidGroup.Update.class) @RequestBody SysUser user) { user.setUpdateBy(getUsername()); return toAjax(userService.updateUser(user)); } diff --git a/ruoyi-web/src/main/resources/application-dev.yml b/ruoyi-web/src/main/resources/application-dev.yml index b6774b9..38118cb 100644 --- a/ruoyi-web/src/main/resources/application-dev.yml +++ b/ruoyi-web/src/main/resources/application-dev.yml @@ -21,3 +21,9 @@ spring: max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms + +wx: + # 微信小程序appId + appid: wx04e3ec11c6f44d0f + # 微信小程序appSecret + appSecret: fba9d527f2a59f980ed8dc760abffda1