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