From 5cb579d8b09978f6fefd829fb6220fcf4391cd2f Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Fri, 22 Aug 2025 03:08:20 +0800
Subject: [PATCH] 1
---
ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java | 1
ruoyi-admin/src/main/java/com/ruoyi/im/util/PhoneNumberValidatorUtil.java | 208 ++++++++++++++++
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountVo.java | 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java | 37 ++
ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java | 4
ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java | 44 +++
ruoyi-admin/src/main/java/com/ruoyi/im/util/ConverterUtil.java | 45 +++
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java | 1
ruoyi-admin/src/main/java/com/ruoyi/im/config/UpdateUserInfoRequest.java | 274 ++++++--------------
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java | 107 ++++---
ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java | 38 ++
11 files changed, 521 insertions(+), 242 deletions(-)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
index 0c937bc..41b2668 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
@@ -2,7 +2,6 @@
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/config/UpdateUserInfoRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/im/config/UpdateUserInfoRequest.java
index 95c3541..f457ce8 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/config/UpdateUserInfoRequest.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/config/UpdateUserInfoRequest.java
@@ -1,207 +1,111 @@
package com.ruoyi.im.config;
-import cn.hutool.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.HashMap;
-import java.util.Map;
-
public class UpdateUserInfoRequest {
- private Map<String, Object> bodyData;
+ @JsonProperty("avatar")
+ private String avatar;
- public UpdateUserInfoRequest() {
- bodyData = new HashMap<>();
+ @JsonProperty("name")
+ private String name;
+
+ @JsonProperty("sign")
+ private String sign;
+
+ @JsonProperty("email")
+ private String email;
+
+ @JsonProperty("mobile")
+ private String mobile;
+
+ // 无参构造函数
+ public UpdateUserInfoRequest() {}
+
+ // 全参构造函数(可选)
+ public UpdateUserInfoRequest(String avatar, String name, String sign, String email, String mobile) {
+ this.avatar = avatar;
+ this.name = name;
+ this.sign = sign;
+ this.email = email;
+ this.mobile = mobile;
}
- /**
- * 设置name字段
- */
- public UpdateUserInfoRequest setName(String name) {
- if (name != null) {
- bodyData.put("name", name);
- }
+ // Getter 和 Setter 方法
+ public String getAvatar() {
+ return avatar;
+ }
+
+ public void setAvatar(String avatar) {
+ this.avatar = avatar;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSign() {
+ return sign;
+ }
+
+ public void setSign(String sign) {
+ this.sign = sign;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getMobile() {
+ return mobile;
+ }
+
+ public void setMobile(String mobile) {
+ this.mobile = mobile;
+ }
+
+ // toString 方法(可选,便于调试)
+ @Override
+ public String toString() {
+ return "UpdateUserInfoRequest{" +
+ "avatar='" + avatar + '\'' +
+ ", name='" + name + '\'' +
+ ", sign='" + sign + '\'' +
+ ", email='" + email + '\'' +
+ ", mobile=" + mobile +
+ '}';
+ }
+
+ // Builder 模式(可选,便于链式调用)
+ public UpdateUserInfoRequest avatar(String avatar) {
+ this.avatar = avatar;
return this;
}
- /**
- * 设置avatar字段
- */
- public UpdateUserInfoRequest setAvatar(String avatar) {
- if (avatar != null) {
- bodyData.put("avatar", avatar);
- }
+ public UpdateUserInfoRequest name(String name) {
+ this.name = name;
return this;
}
- /**
- * 设置sign字段
- */
- public UpdateUserInfoRequest setSign(String sign) {
- if (sign != null) {
- bodyData.put("sign", sign);
- }
+ public UpdateUserInfoRequest sign(String sign) {
+ this.sign = sign;
return this;
}
- /**
- * 设置email字段
- */
- public UpdateUserInfoRequest setEmail(String email) {
- if (email != null) {
- bodyData.put("email", email);
- }
+ public UpdateUserInfoRequest email(String email) {
+ this.email = email;
return this;
}
- /**
- * 设置birthday字段
- */
- public UpdateUserInfoRequest setBirthday(String birthday) {
- if (birthday != null) {
- bodyData.put("birthday", birthday);
- }
+ public UpdateUserInfoRequest mobile(String mobile) {
+ this.mobile = mobile;
return this;
}
-
- /**
- * 设置mobile字段
- */
- public UpdateUserInfoRequest setMobile(String mobile) {
- if (mobile != null) {
- bodyData.put("mobile", mobile);
- }
- return this;
- }
-
- /**
- * 设置gender字段
- */
- public UpdateUserInfoRequest setGender(String gender) {
- if (gender != null) {
- bodyData.put("gender", gender);
- }
- return this;
- }
-
- /**
- * 设置extension字段
- */
- public UpdateUserInfoRequest setExtension(String extension) {
- if (extension != null) {
- bodyData.put("extension", extension);
- }
- return this;
- }
-
- /**
- * 批量设置所有字段
- */
- public UpdateUserInfoRequest setAllFields(Map<String, Object> fields) {
- if (fields != null) {
- for (Map.Entry<String, Object> entry : fields.entrySet()) {
- String key = entry.getKey();
- Object value = entry.getValue();
-
- if (value != null) {
- switch (key) {
- case "name":
- setName((String) value);
- break;
- case "avatar":
- setAvatar((String) value);
- break;
- case "sign":
- setSign((String) value);
- break;
- case "email":
- setEmail((String) value);
- break;
- case "birthday":
- setBirthday((String) value);
- break;
- case "mobile":
- setMobile((String) value);
- break;
- case "gender":
- setGender((String) value);
- break;
- case "extension":
- setExtension((String) value);
- break;
- default:
- // 忽略未知字段
- break;
- }
- }
- }
- }
- return this;
- }
-
- /**
- * 构建JSON字符串
- */
- public String build() {
- JSONObject jsonObject = new JSONObject(bodyData);
- return jsonObject.toString();
- }
-
- /**
- * 获取Map形式的数据
- */
- public Map<String, Object> getBodyData() {
- return new HashMap<>(bodyData);
- }
-
- /**
- * 清空所有已设置的数据
- */
- public void clear() {
- bodyData.clear();
- }
-
- /**
- * 使用示例
- */
- public static void main(String[] args) {
- // 示例1: 只设置部分字段
- UpdateUserInfoRequest builder = new UpdateUserInfoRequest();
- String partialBody = builder
- .setName("zhangsan")
- .setEmail("zhangsan@corp.xx.com")
- .setMobile("13312345678")
- .build();
- System.out.println("部分字段请求体: " + partialBody);
-
- // 示例2: 使用Map批量设置
- builder.clear();
- Map<String, Object> fields = new HashMap<>();
- fields.put("name", "lisi");
- fields.put("avatar", "http://xxxx.xx/lisi.png");
- fields.put("sign", "Hello World");
- fields.put("gender", "1");
-
- String batchBody = builder.setAllFields(fields).build();
- System.out.println("批量设置请求体: " + batchBody);
-
- // 示例3: 完全不设置任何字段
- builder.clear();
- String emptyBody = builder.build();
- System.out.println("空请求体: " + emptyBody);
-
- // 示例4: 设置所有字段
- builder.clear();
- String fullBody = builder
- .setName("zhangsan")
- .setAvatar("http://xxxx.xx/x.png")
- .setSign("Hello World")
- .setEmail("zhangsan@corp.xx.com")
- .setBirthday("1990-01-01")
- .setMobile("13312345678")
- .setGender("2")
- .setExtension("xxxx")
- .build();
- System.out.println("完整请求体: " + fullBody);
- }
-}
-
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java b/ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java
index 75486fb..56e32a3 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java
@@ -9,15 +9,13 @@
@Data
public class RegisterDto {
- @NotNull(message = "账号不能为空")
private String account; // 账号
- @NotEmpty(message = "密码不能为空")
private String password; // 密码
private String confirmPassword; // 再次确认密码
- private String name; // 昵称
+ private String nickname; // 昵称
private Integer type;//类型 1 批量 2 单一
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java b/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java
new file mode 100644
index 0000000..a1c6bcc
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java
@@ -0,0 +1,44 @@
+package com.ruoyi.im.out;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class UserAccountOut {
+
+ // 账号(唯一)
+ private String account;
+
+ // 手机号(唯一)
+ private String phoneNumber;
+
+ // 云信账号
+ private String cloudMessageAccount;
+
+ // 昵称
+ private String nickname;
+
+
+ // 账号状态: 0:正常 1:禁用
+ private Integer status;
+
+ // 最近登录时间
+ private Date loginTime;
+
+ // 最近登录IP
+ private String loginIp;
+
+ // 注册时间
+ private Date registerTime;
+
+ // 个性签名
+ private String signature;
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java
index 5e4bb33..c9c4066 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java
@@ -72,6 +72,7 @@
@Autowired
private JdbcTemplate jdbcTemplate;
+ @Resource
private final YunxinApiHttpClient yunxinClient;
// 使用构造函数注入(推荐)
@@ -102,17 +103,17 @@
@Override
- @Transactional(rollbackFor = Exception.class) // 添加事务注解确保操作原子性
+ @Transactional(rollbackFor = Exception.class)
public Result register(RegisterDto dto) {
try {
- // 验证手机号是否已存在(数据库唯一索引提供最终保障)
+ // 验证手机号是否已存在
List<UserAccount> accounts = userAccountService.list(
new LambdaQueryWrapper<>(UserAccount.class)
.eq(UserAccount::getAccount, dto.getAccount())
);
if (!CollectionUtils.isEmpty(accounts)) {
- return Result.error("手机号已注册!");
+ return Result.error("账号已被注册!");
}
// 创建本地用户账户记录
@@ -122,18 +123,17 @@
userAccount.setCloudMessageAccount(dto.getAccount());
userAccount.setPassword(SymmetricCryptoUtil.encryptPassword(dto.getPassword()));
userAccount.setCreateTime(new Date());
- userAccount.setNickname(dto.getAccount());
-
+ userAccount.setNickname(dto.getNickname());
if (!userAccountService.save(userAccount)) {
- return Result.error("注册失败,请重试");
+ throw new RuntimeException("保存用户账户失败"); // 改为抛出异常
}
// 注册云信账号(远程调用)
Map<String, String> paramMap = new HashMap<>();
paramMap.put("accid", dto.getAccount());
- if(StringUtils.isNotEmpty(dto.getName())){
- paramMap.put("name", dto.getName());
+ if(StringUtils.isNotEmpty(dto.getNickname())){
+ paramMap.put("name", dto.getNickname());
}
paramMap.put("token", dto.getPassword());
@@ -159,26 +159,15 @@
neteaseTeamService.inviteTeamMembers(request);
}
return Result.success("注册成功");
- } else if (code == 414) {
- // 手动触发回滚(事务注解会自动处理)
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- return Result.error("账号已被注册!");
} else {
- // 其他错误码同样触发回滚
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- log.error("云信注册失败,响应: {}, traceId: {}", data, response.getTraceId());
- return Result.error("注册失败,错误码: " + code);
+ // 所有非200状态码都抛出异常触发回滚
+ throw new RuntimeException("云信注册失败,错误码: " + code + ", 响应: " + data);
}
- } catch (YunxinSdkException e) {
- // 云信调用异常时回滚事务
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- log.error("云信服务调用异常 traceId: {}", e.getTraceId(), e);
- return Result.error("注册失败,系统异常");
} catch (Exception e) {
- // 其他异常同样回滚
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
- log.error("注册过程发生未知异常", e);
- return Result.error("注册失败,请重试");
+ // 记录异常日志
+ log.error("注册过程发生异常", e);
+ // 重新抛出异常以确保事务回滚
+ throw new RuntimeException("注册失败: " + e.getMessage(), e);
}
}
@@ -275,18 +264,24 @@
httpPatch.setHeader("CheckSum", checkSum);
// 构建请求体
- UpdateUserInfoRequest builder = new UpdateUserInfoRequest();
- if(StringUtils.isNotEmpty(dto.getMobile())){
- builder.setMobile(dto.getMobile());
- }else if(StringUtils.isNotEmpty(dto.getName())){
- builder.setName(dto.getName());
- }else if(StringUtils.isNotEmpty(dto.getSign())){
- builder.setSign(dto.getSign());
- }else if(StringUtils.isNotEmpty(dto.getAvatar())){
- builder.setAvatar(dto.getAvatar());
- }
- String body = builder.build();
- String jsonBody = objectMapper.writeValueAsString(body);
+// UpdateUserInfoRequest builder = new UpdateUserInfoRequest();
+// if(StringUtils.isNotEmpty(dto.getMobile())){
+// builder.setMobile(dto.getMobile());
+// }
+// if(StringUtils.isNotEmpty(dto.getName())){
+// builder.setName(dto.getName());
+// }
+// if(StringUtils.isNotEmpty(dto.getSign())){
+// builder.setSign(dto.getSign());
+// }
+// if(StringUtils.isNotEmpty(dto.getAvatar())){
+// builder.setAvatar(dto.getAvatar());
+// }
+// String body = builder.build();
+ UpdateUserInfoRequest requestBody = new UpdateUserInfoRequest(dto.getAvatar(),
+ dto.getName(),dto.getSign(),dto.getEmail(),dto.getMobile());
+ String jsonBody = objectMapper.writeValueAsString(requestBody);
+// String jsonBody = objectMapper.writeValueAsString(body);
httpPatch.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));
// 执行请求
@@ -298,11 +293,11 @@
if (neteaseResponse.isSuccess()) {
result.put("success", true);
- result.put("message", "头像更新成功");
+ result.put("message", "更新成功");
result.put("data", neteaseResponse.getData());
} else {
result.put("success", false);
- result.put("message", "头像更新失败: " + neteaseResponse.getMsg());
+ result.put("message", "更新失败: " + neteaseResponse.getMsg());
result.put("errorCode", neteaseResponse.getCode());
}
@@ -332,9 +327,11 @@
UpdateUserBusinessDto dto = new UpdateUserBusinessDto();
if(StringUtils.isNotEmpty(vo.getPhoneNumber())){
dto.setMobile(vo.getPhoneNumber());
- }else if(StringUtils.isNotEmpty(vo.getNickname())){
+ }
+ if(StringUtils.isNotEmpty(vo.getNickname())){
dto.setName(vo.getNickname());
- }else if(StringUtils.isNotEmpty(vo.getSignature())){
+ }
+ if(StringUtils.isNotEmpty(vo.getSignature())){
dto.setSign(vo.getSignature());
}
Map<String, Object> map = updateUserAvatar(vo.getAccountId(), dto);
@@ -343,11 +340,25 @@
AjaxResult ajaxResult = updateAccountProperties(vo.getAccountId(), vo);
if(ajaxResult.isSuccess()){
UserAccount userAccount = userAccountService.getById(vo.getId());
- userAccount.setPhoneNumber(vo.getPhoneNumber());
- userAccount.setAccount(vo.getAccountId());
- userAccount.setNickname(vo.getNickname());
- userAccount.setPassword(SymmetricCryptoUtil.encryptPassword(vo.getPassword()));
- userAccount.setSignature(vo.getSignature());
+ if (StringUtils.isNotBlank(vo.getPhoneNumber())) {
+ userAccount.setPhoneNumber(vo.getPhoneNumber());
+ }
+
+ if (StringUtils.isNotBlank(vo.getAccountId())) {
+ userAccount.setAccount(vo.getAccountId());
+ }
+
+ if (StringUtils.isNotBlank(vo.getNickname())) {
+ userAccount.setNickname(vo.getNickname());
+ }
+
+ if (StringUtils.isNotBlank(vo.getPassword())) {
+ userAccount.setPassword(SymmetricCryptoUtil.encryptPassword(vo.getPassword()));
+ }
+
+ if (StringUtils.isNotBlank(vo.getSignature())) {
+ userAccount.setSignature(vo.getSignature());
+ }
userAccount.setUpdateTime(new Date());
userAccountService.updateById(userAccount);
}else{
@@ -391,7 +402,8 @@
if(null != vo.getStatus() && vo.getStatus() == 0){
builder.setEnabled(false);
builder.setNeedKick(true);
- }else if(StringUtils.isNotEmpty(vo.getPassword())){
+ }
+ if(StringUtils.isNotEmpty(vo.getPassword())){
builder.setToken(vo.getPassword());
}
// 只设置需要的字段
@@ -427,6 +439,7 @@
* @return
*/
@Override
+ @Transactional(rollbackFor = Exception.class)
public Result batchRegister(RegisterDto dto) {
if(dto.getType() == 2){
return register(dto);
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
index ed72cf7..2fb1eb6 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
@@ -30,6 +30,7 @@
@Service
public class NeteaseTeamServiceImpl extends ServiceImpl<NeteaseTeamMapper, NeteaseTeam> implements NeteaseTeamService {
+ @Resource
private final YunxinApiHttpClient yunxinClient;
// 使用构造函数注入(推荐)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/util/ConverterUtil.java b/ruoyi-admin/src/main/java/com/ruoyi/im/util/ConverterUtil.java
new file mode 100644
index 0000000..b540fca
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/util/ConverterUtil.java
@@ -0,0 +1,45 @@
+package com.ruoyi.im.util;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2024-08-19 18:29
+ **/
+public class ConverterUtil {
+
+ public static <T, V> V convert(T pojo, Class<V> voClass) {
+ try {
+ V vo = voClass.newInstance();
+ Field[] pojoFields = pojo.getClass().getDeclaredFields();
+ Field[] voFields = voClass.getDeclaredFields();
+ for (Field pojoField : pojoFields) {
+ pojoField.setAccessible(true);
+ for (Field voField : voFields) {
+ voField.setAccessible(true);
+ if (pojoField.getName().equals(voField.getName()) && pojoField.getType().equals(voField.getType())) {
+ voField.set(vo, pojoField.get(pojo));
+ break;
+ }
+ }
+ }
+ return vo;
+ } catch (InstantiationException | IllegalAccessException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ public static <T, V> List<V> convertToList(List<T> pojoList, Class<V> voClass) {
+ List<V> voList = new ArrayList<>();
+ for (T pojo : pojoList) {
+ V vo = convert(pojo, voClass);
+ voList.add(vo);
+ }
+ return voList;
+ }
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/util/PhoneNumberValidatorUtil.java b/ruoyi-admin/src/main/java/com/ruoyi/im/util/PhoneNumberValidatorUtil.java
new file mode 100644
index 0000000..aa497dc
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/util/PhoneNumberValidatorUtil.java
@@ -0,0 +1,208 @@
+package com.ruoyi.im.util;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 手机号格式校验工具类
+ * 支持中国大陆手机号和国际手机号验证
+ */
+public class PhoneNumberValidatorUtil {
+
+ // 中国大陆手机号正则表达式 (11位数字,1开头)
+ private static final String CHINA_MOBILE_PATTERN = "^1[3-9]\\d{9}$";
+
+ // 国际手机号正则表达式 (国家代码-号码,如+1-1234567890)
+ private static final String INTERNATIONAL_PATTERN = "^\\+\\d{1,4}-\\d{4,15}$";
+
+ // 常见国家/地区代码映射表
+ private static final Map<String, String> COUNTRY_CODES = new HashMap<>();
+
+ static {
+ // 初始化常见国家/地区代码
+ COUNTRY_CODES.put("1", "美国/加拿大");
+ COUNTRY_CODES.put("86", "中国大陆");
+ COUNTRY_CODES.put("852", "香港");
+ COUNTRY_CODES.put("853", "澳门");
+ COUNTRY_CODES.put("886", "台湾");
+ COUNTRY_CODES.put("81", "日本");
+ COUNTRY_CODES.put("82", "韩国");
+ COUNTRY_CODES.put("65", "新加坡");
+ COUNTRY_CODES.put("60", "马来西亚");
+ COUNTRY_CODES.put("44", "英国");
+ COUNTRY_CODES.put("33", "法国");
+ COUNTRY_CODES.put("49", "德国");
+ COUNTRY_CODES.put("61", "澳大利亚");
+ // 可以继续添加更多国家/地区代码
+ }
+
+ /**
+ * 验证手机号格式
+ * @param phoneNumber 手机号码
+ * @return 验证结果
+ */
+ public static ValidationResult validatePhoneNumber(String phoneNumber) {
+ if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
+ return new ValidationResult(false, "手机号不能为空");
+ }
+
+ // 去除可能存在的空格
+ phoneNumber = phoneNumber.trim();
+
+ // 检查是否为中国大陆手机号
+ if (Pattern.matches(CHINA_MOBILE_PATTERN, phoneNumber)) {
+ return new ValidationResult(true, "中国大陆手机号格式正确");
+ }
+
+ // 检查是否为国际手机号格式
+ if (Pattern.matches(INTERNATIONAL_PATTERN, phoneNumber)) {
+ // 提取国家代码部分
+ String[] parts = phoneNumber.split("-", 2);
+ String countryCode = parts[0].substring(1); // 去掉+号
+
+ // 验证国家代码是否有效
+ if (COUNTRY_CODES.containsKey(countryCode)) {
+ return new ValidationResult(true, "国际手机号格式正确 (" + COUNTRY_CODES.get(countryCode) + ")");
+ } else {
+ return new ValidationResult(false, "不支持的国家/地区代码: +" + countryCode);
+ }
+ }
+
+ // 如果都不匹配,返回错误信息
+ if (phoneNumber.startsWith("+")) {
+ return new ValidationResult(false, "国际手机号格式不正确,请使用'+国家代码-本地号码'格式");
+ } else {
+ return new ValidationResult(false, "中国大陆手机号应为11位数字且以1开头");
+ }
+ }
+
+ /**
+ * 验证结果类
+ */
+ public static class ValidationResult {
+ private final boolean valid;
+ private final String message;
+
+ public ValidationResult(boolean valid, String message) {
+ this.valid = valid;
+ this.message = message;
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return message;
+ }
+ }
+
+ /**
+ * 提取国家代码(如果是国际手机号)
+ * @param phoneNumber 手机号码
+ * @return 国家代码(不带+号),如果是中国大陆手机号返回"86"
+ */
+ public static String extractCountryCode(String phoneNumber) {
+ if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
+ return null;
+ }
+
+ phoneNumber = phoneNumber.trim();
+
+ // 如果是国际手机号格式
+ if (Pattern.matches(INTERNATIONAL_PATTERN, phoneNumber)) {
+ String[] parts = phoneNumber.split("-", 2);
+ return parts[0].substring(1); // 去掉+号
+ }
+
+ // 如果是中国大陆手机号
+ if (Pattern.matches(CHINA_MOBILE_PATTERN, phoneNumber)) {
+ return "86";
+ }
+
+ return null;
+ }
+
+ /**
+ * 提取本地号码部分
+ * @param phoneNumber 手机号码
+ * @return 本地号码部分
+ */
+ public static String extractLocalNumber(String phoneNumber) {
+ if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
+ return null;
+ }
+
+ phoneNumber = phoneNumber.trim();
+
+ // 如果是国际手机号格式
+ if (Pattern.matches(INTERNATIONAL_PATTERN, phoneNumber)) {
+ String[] parts = phoneNumber.split("-", 2);
+ return parts[1];
+ }
+
+ // 如果是中国大陆手机号
+ if (Pattern.matches(CHINA_MOBILE_PATTERN, phoneNumber)) {
+ return phoneNumber;
+ }
+
+ return null;
+ }
+
+ /**
+ * 格式化手机号显示
+ * @param phoneNumber 手机号码
+ * @return 格式化后的手机号
+ */
+ public static String formatPhoneNumber(String phoneNumber) {
+ ValidationResult result = validatePhoneNumber(phoneNumber);
+ if (!result.isValid()) {
+ return phoneNumber; // 如果格式不正确,返回原值
+ }
+
+ if (Pattern.matches(CHINA_MOBILE_PATTERN, phoneNumber)) {
+ // 中国大陆手机号格式化为 3-4-4 格式
+ return phoneNumber.replaceFirst("(\\d{3})(\\d{4})(\\d{4})", "$1-$2-$3");
+ } else if (Pattern.matches(INTERNATIONAL_PATTERN, phoneNumber)) {
+ // 国际手机号保持原格式
+ return phoneNumber;
+ }
+
+ return phoneNumber;
+ }
+
+ // 测试方法
+ public static void main(String[] args) {
+ // 测试用例
+ String[] testNumbers = {
+ "13800138000", // 中国大陆手机号
+ "+1-1234567890", // 美国手机号
+ "+852-12345678", // 香港手机号
+ "12345678901", // 无效的中国大陆手机号(不以1开头)
+ "+86-13800138000", // 带国家代码的中国大陆手机号
+ "+999-1234567890", // 不支持的国家代码
+ "+1-123", // 号码部分太短
+ "abc", // 完全无效
+ "+1-1234567890123456" // 号码部分太长
+ };
+
+ for (String number : testNumbers) {
+ ValidationResult result = validatePhoneNumber(number);
+ System.out.println(number + " : " + result.getMessage());
+
+ if (result.isValid()) {
+ System.out.println(" 国家代码: " + extractCountryCode(number));
+ System.out.println(" 本地号码: " + extractLocalNumber(number));
+ System.out.println(" 格式化: " + formatPhoneNumber(number));
+ }
+ System.out.println();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
index b1b596d..9010da3 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
@@ -1,15 +1,24 @@
package com.ruoyi.web.controller.group;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.im.config.AddTeamMembersRequest;
import com.ruoyi.im.config.CreateTeamRequest;
import com.ruoyi.im.config.AssignmentRequest;
import com.ruoyi.im.service.NeteaseTeamService;
+import com.ruoyi.system.domain.NeteaseTeam;
+import com.ruoyi.system.domain.UserAccount;
+import com.ruoyi.system.domain.vo.UserAccountVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
@RestController
@RequestMapping("/im/group")
@@ -21,6 +30,34 @@
NeteaseTeamService neteaseGroupService;
/**
+ * 获取会员列表
+ */
+ @PreAuthorize("@ss.hasPermi('im:group:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(@PathVariable("keyword") String keyword)
+ {
+ // 创建查询条件包装器
+ LambdaQueryWrapper<NeteaseTeam> queryWrapper = new LambdaQueryWrapper<>();
+
+ // 只有当 keyword 不为空时才添加 OR 条件
+ if (ObjectUtil.isNotEmpty(keyword)) {
+ queryWrapper.and(wrapper -> wrapper
+ .eq(NeteaseTeam::getTid, keyword)
+ .or()
+ .eq(NeteaseTeam::getOwnerAccountId, keyword)
+ .or()
+ .eq(NeteaseTeam::getName,keyword)
+ );
+ }
+
+ // 默认按创建时间倒序
+ queryWrapper.orderByDesc(NeteaseTeam::getCreateTime);
+ List<NeteaseTeam> list = neteaseGroupService.list(queryWrapper);
+ return getDataTable(list);
+ }
+
+
+ /**
* 创建群组
*/
@PostMapping("/create")
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
index 095fe20..7a37853 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
@@ -9,7 +9,10 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.im.comm.Result;
import com.ruoyi.im.dto.RegisterDto;
+import com.ruoyi.im.out.UserAccountOut;
import com.ruoyi.im.service.ImApiServcie;
+import com.ruoyi.im.util.ConverterUtil;
+import com.ruoyi.im.util.PhoneNumberValidatorUtil;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.system.domain.vo.UserAccountUpdateVo;
import com.ruoyi.system.domain.vo.UserAccountVo;
@@ -45,6 +48,7 @@
public TableDataInfo list(UserAccountVo vo)
{
// 创建查询条件包装器
+
LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<>();
// 只有当 keyword 不为空时才添加 OR 条件
@@ -70,13 +74,14 @@
// 默认按创建时间倒序
queryWrapper.orderByDesc(UserAccount::getCreateTime);
List<UserAccount> list = userAccountService.list(queryWrapper);
- return getDataTable(list);
+ List<UserAccountOut> toList = ConverterUtil.convertToList(list, UserAccountOut.class);
+ return getDataTable(toList);
}
/**
* 修改会员
*/
- @PreAuthorize("@ss.hasPermi('im:user:updateUserAccount')")
+// @PreAuthorize("@ss.hasPermi('im:user:updateUserAccount')")
@PostMapping("/updateUserAccount")
public AjaxResult updateUserAccount(UserAccountUpdateVo vo) {
@@ -85,6 +90,11 @@
if(ObjectUtil.isEmpty(userAccount)){
return AjaxResult.error("会员不存在!");
}
+ PhoneNumberValidatorUtil.ValidationResult result = PhoneNumberValidatorUtil.validatePhoneNumber(vo.getPhoneNumber());
+ if(!result.isValid()){
+ return AjaxResult.error("手机号格式不正确!");
+ }
+ vo.setAccountId(userAccount.getCloudMessageAccount());
return imApiServcie.updateUserAccount(vo);
}catch (Exception e){
e.printStackTrace();
@@ -94,14 +104,34 @@
}
/**
- * 批量注册
+ * 创建会员
*/
@PostMapping("/batchRegister")
public Result batchRegister(@Validated RegisterDto dto){
try {
+ if(null == dto.getType()){
+ return Result.error("类型不能为空");
+ }else if(dto.getType() == 2){
+ if(StringUtils.isEmpty(dto.getAccount())){
+ return Result.error("账号不能为空");
+ }
+ if(StringUtils.isEmpty(dto.getPassword())){
+ return Result.error("密码不能为空");
+ }
+ if(StringUtils.isEmpty(dto.getNickname())){
+ return Result.error("昵称不能为空");
+ }
+ }else if (dto.getType() == 1){
+ if(dto.getNumber() <= 0){
+ return Result.error("数量不能为空");
+ }else if(dto.getNumber() > 100){
+ return Result.error("批量注册最多一次100");
+ }
+ }
return imApiServcie.batchRegister(dto);
}catch (Exception e){
- log.error("批量注册报错:",e);
+ e.printStackTrace();
+ log.error("-----------批量注册报错------------");
return Result.error("注册失败,请稍后再试!");
}
}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountVo.java
index 07ce4f6..3e748f5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountVo.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountVo.java
@@ -28,7 +28,7 @@
private String password;
// 账号类型: 0:真实 1:虚拟
- private Integer accountType = 0;
+ private Integer accountType;
// 云信账号
private String cloudMessageAccount;
@@ -37,7 +37,7 @@
private String nickname;
// 账号状态: 0:正常 1:禁用
- private Integer status = 0;
+ private Integer status;
// 最近登录时间
private Date loginTime;
--
Gitblit v1.9.3