Browse Source

会员中心:会员管理 50%

YunaiV 1 year ago
parent
commit
e8c1bdde3d
15 changed files with 348 additions and 43 deletions
  1. 2 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
  2. 5 3
      yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
  3. 5 5
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java
  4. 56 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java
  5. 0 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java
  6. 47 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java
  7. 34 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java
  8. 34 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java
  9. 20 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateReqVO.java
  10. 2 2
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java
  11. 11 2
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java
  12. 49 20
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java
  13. 11 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
  14. 25 3
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
  15. 47 7
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java

+ 2 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java

@@ -23,6 +23,8 @@ public class DateUtils {
      */
     public static final long SECOND_MILLIS = 1000;
 
+    public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";
+
     public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
 
     public static final String FORMAT_HOUR_MINUTE_SECOND = "HH:mm:ss";

+ 5 - 3
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm

@@ -120,7 +120,6 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="序号" type="index" width="70px" />
       #foreach($column in $columns)
       #if ($column.listOperationResult)
         #set ($dictType=$column.dictType)
@@ -142,7 +141,7 @@
         </template>
       </el-table-column>
         #else
-      <el-table-column label="${comment}" align="center" prop="${javaField}" width="150px"/>
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="150px" />
         #end
       #end
     #end
@@ -180,7 +179,7 @@
   <${simpleClassName}Form ref="formRef" @success="getList" />
 </template>
 
-<script setup lang="ts" name="${table.className}">
+<script setup lang="ts">
 #if ($dictMethods.size() > 0)
 import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
 #end
@@ -193,6 +192,9 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
 import ${simpleClassName}Form from './${simpleClassName}Form.vue'
+
+defineOptions({ name: '${table.className}' })
+
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 

+ 5 - 5
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.member.api.user;
 
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
-import cn.iocoder.yudao.module.member.convert.user.UserConvert;
+import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import cn.iocoder.yudao.module.member.service.user.MemberUserService;
 import org.springframework.stereotype.Service;
@@ -26,22 +26,22 @@ public class MemberUserApiImpl implements MemberUserApi {
     @Override
     public MemberUserRespDTO getUser(Long id) {
         MemberUserDO user = userService.getUser(id);
-        return UserConvert.INSTANCE.convert2(user);
+        return MemberUserConvert.INSTANCE.convert2(user);
     }
 
     @Override
     public List<MemberUserRespDTO> getUserList(Collection<Long> ids) {
-        return UserConvert.INSTANCE.convertList2(userService.getUserList(ids));
+        return MemberUserConvert.INSTANCE.convertList2(userService.getUserList(ids));
     }
 
     @Override
     public List<MemberUserRespDTO> getUserListByNickname(String nickname) {
-        return UserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname));
+        return MemberUserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname));
     }
 
     @Override
     public MemberUserRespDTO getUserByMobile(String mobile) {
-        return UserConvert.INSTANCE.convert2(userService.getUserByMobile(mobile));
+        return MemberUserConvert.INSTANCE.convert2(userService.getUserByMobile(mobile));
     }
 
 }

+ 56 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/MemberUserController.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.member.controller.admin.user;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.*;
+import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
+import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
+import cn.iocoder.yudao.module.member.service.user.MemberUserService;
+
+@Tag(name = "管理后台 - 会员用户")
+@RestController
+@RequestMapping("/member/user")
+@Validated
+public class MemberUserController {
+
+    @Resource
+    private MemberUserService memberUserService;
+
+    @PutMapping("/update")
+    @Operation(summary = "更新会员用户")
+    @PreAuthorize("@ss.hasPermission('member:user:update')")
+    public CommonResult<Boolean> updateUser(@Valid @RequestBody MemberUserUpdateReqVO updateReqVO) {
+        memberUserService.updateUser(updateReqVO);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得会员用户")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('member:user:query')")
+    public CommonResult<MemberUserRespVO> getUser(@RequestParam("id") Long id) {
+        MemberUserDO user = memberUserService.getUser(id);
+        return success(MemberUserConvert.INSTANCE.convert03(user));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得会员用户分页")
+    @PreAuthorize("@ss.hasPermission('member:user:query')")
+    public CommonResult<PageResult<MemberUserRespVO>> getUserPage(@Valid MemberUserPageReqVO pageVO) {
+        PageResult<MemberUserDO> pageResult = memberUserService.getUserPage(pageVO);
+        return success(MemberUserConvert.INSTANCE.convertPage(pageResult));
+    }
+
+}

+ 0 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.yudao.module.member.controller.admin.user;

+ 47 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserBaseVO.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.member.controller.admin.user.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
+
+/**
+ * 会员用户 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class MemberUserBaseVO {
+
+    @Schema(description = "手机号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601691300")
+    @NotNull(message = "手机号不能为空")
+    private String mobile;
+
+    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+    @NotNull(message = "状态不能为空")
+    private Byte status;
+
+    @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    @NotNull(message = "用户昵称不能为空")
+    private String nickname;
+
+    @Schema(description = "用户昵称", example = "李四")
+    private String name;
+
+    @Schema(description = "用户性别", example = "1")
+    private Byte sex;
+
+    @Schema(description = "所在地", example = "4371")
+    private Long areaId;
+
+    @Schema(description = "出生日期", example = "2023-03-12")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
+    private LocalDateTime birthday;
+
+    @Schema(description = "会员备注", example = "我是小备注")
+    private String mark;
+
+}

+ 34 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserPageReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.member.controller.admin.user.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 会员用户分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class MemberUserPageReqVO extends PageParam {
+
+    @Schema(description = "手机号", example = "15601691300")
+    private String mobile;
+
+    @Schema(description = "用户昵称", example = "李四")
+    private String nickname;
+
+    @Schema(description = "最后登录时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] loginDate;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 34 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserRespVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.member.controller.admin.user.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 会员用户 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class MemberUserRespVO extends MemberUserBaseVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788")
+    private Long id;
+
+    @Schema(description = "注册 IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
+    private String registerIp;
+
+    @Schema(description = "最后登录IP", requiredMode = Schema.RequiredMode.REQUIRED, example = "127.0.0.1")
+    private String loginIp;
+
+    @Schema(description = "最后登录时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime loginDate;
+
+    @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/x.png")
+    @NotNull(message = "头像不能为空")
+    private String avatar;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+}

+ 20 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/vo/MemberUserUpdateReqVO.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.member.controller.admin.user.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 会员用户更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class MemberUserUpdateReqVO extends MemberUserBaseVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23788")
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+}

+ 2 - 2
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppUserController.java

@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
-import cn.iocoder.yudao.module.member.convert.user.UserConvert;
+import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import cn.iocoder.yudao.module.member.service.user.MemberUserService;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -56,7 +56,7 @@ public class AppUserController {
     @PreAuthenticated
     public CommonResult<AppUserInfoRespVO> getUserInfo() {
         MemberUserDO user = userService.getUser(getLoginUserId());
-        return success(UserConvert.INSTANCE.convert(user));
+        return success(MemberUserConvert.INSTANCE.convert(user));
     }
 
     @PostMapping("/update-mobile")

+ 11 - 2
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java → yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/MemberUserConvert.java

@@ -1,6 +1,9 @@
 package cn.iocoder.yudao.module.member.convert.user;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import org.mapstruct.Mapper;
@@ -9,9 +12,9 @@ import org.mapstruct.factory.Mappers;
 import java.util.List;
 
 @Mapper
-public interface UserConvert {
+public interface MemberUserConvert {
 
-    UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
+    MemberUserConvert INSTANCE = Mappers.getMapper(MemberUserConvert.class);
 
     AppUserInfoRespVO convert(MemberUserDO bean);
 
@@ -19,4 +22,10 @@ public interface UserConvert {
 
     List<MemberUserRespDTO> convertList2(List<MemberUserDO> list);
 
+    MemberUserDO convert(MemberUserUpdateReqVO bean);
+
+    PageResult<MemberUserRespVO> convertPage(PageResult<MemberUserDO> page);
+
+    MemberUserRespVO convert03(MemberUserDO bean);
+
 }

+ 49 - 20
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/user/MemberUserDO.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.member.dal.dataobject.user;
 
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.ip.core.Area;
 import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
+import cn.iocoder.yudao.module.system.enums.common.SexEnum;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -26,26 +28,13 @@ import java.time.LocalDateTime;
 @AllArgsConstructor
 public class MemberUserDO extends TenantBaseDO {
 
+    // ========== 账号信息 ==========
+
     /**
      * 用户ID
      */
     @TableId
     private Long id;
-    /**
-     * 用户昵称
-     */
-    private String nickname;
-    /**
-     * 用户头像
-     */
-    private String avatar;
-    /**
-     * 帐号状态
-     *
-     * 枚举 {@link CommonStatusEnum}
-     */
-    private Integer status;
-
     /**
      * 手机
      */
@@ -56,6 +45,12 @@ public class MemberUserDO extends TenantBaseDO {
      * 因为目前使用 {@link BCryptPasswordEncoder} 加密器,所以无需自己处理 salt 盐
      */
     private String password;
+    /**
+     * 帐号状态
+     *
+     * 枚举 {@link CommonStatusEnum}
+     */
+    private Integer status;
     /**
      * 注册 IP
      */
@@ -69,10 +64,44 @@ public class MemberUserDO extends TenantBaseDO {
      */
     private LocalDateTime loginDate;
 
-    // TODO 芋艿:name 真实名字;
-    // TODO 芋艿:email 邮箱;
-    // TODO 芋艿:gender 性别;
-    // TODO 芋艿:score 积分;
-    // TODO 芋艿:payPassword 支付密码;
+    // ========== 基础信息 ==========
+
+    /**
+     * 用户昵称
+     */
+    private String nickname;
+    /**
+     * 用户头像
+     */
+    private String avatar;
+
+    /**
+     * 真实名字
+     */
+    private String name;
+    /**
+     * 性别
+     *
+     * 枚举 {@link SexEnum}
+     */
+    private Integer sex;
+    /**
+     * 出生日期
+     */
+    private LocalDateTime birthday;
+    /**
+     * 所在地
+     *
+     * 关联 {@link Area#getId()} 字段
+     */
+    private Integer areaId;
+    /**
+     * 用户备注
+     */
+    private String mark;
+
+    // ========== 其它信息 ==========
+
+    // TODO 积分、成长值、会员等级等等
 
 }

+ 11 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.member.dal.mysql.user;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -24,4 +26,13 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
                 .likeIfPresent(MemberUserDO::getNickname, nickname));
     }
 
+    default PageResult<MemberUserDO> selectPage(MemberUserPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<MemberUserDO>()
+                .likeIfPresent(MemberUserDO::getMobile, reqVO.getMobile())
+                .betweenIfPresent(MemberUserDO::getLoginDate, reqVO.getLoginDate())
+                .likeIfPresent(MemberUserDO::getNickname, reqVO.getNickname())
+                .betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(MemberUserDO::getId));
+    }
+
 }

+ 25 - 3
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java

@@ -1,9 +1,13 @@
 package cn.iocoder.yudao.module.member.service.user;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.validation.Mobile;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 
+import javax.validation.Valid;
 import java.io.InputStream;
 import java.util.Collection;
 import java.util.List;
@@ -66,14 +70,16 @@ public interface MemberUserService {
     List<MemberUserDO> getUserList(Collection<Long> ids);
 
     /**
-     * 修改用户昵称
+     * 【会员】修改用户昵称
+     *
      * @param userId 用户id
      * @param nickname 用户新昵称
      */
     void updateUserNickname(Long userId, String nickname);
 
     /**
-     * 修改用户头像
+     * 【会员】修改用户头像
+     *
      * @param userId 用户id
      * @param inputStream 头像文件
      * @return 头像url
@@ -81,7 +87,8 @@ public interface MemberUserService {
     String updateUserAvatar(Long userId, InputStream inputStream) throws Exception;
 
     /**
-     * 修改手机
+     * 【会员】修改手机
+     *
      * @param userId 用户id
      * @param reqVO 请求实体
      */
@@ -96,4 +103,19 @@ public interface MemberUserService {
      */
     boolean isPasswordMatch(String rawPassword, String encodedPassword);
 
+    /**
+     * 【管理员】更新会员用户
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateUser(@Valid MemberUserUpdateReqVO updateReqVO);
+
+    /**
+     * 【管理员】获得会员用户分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 会员用户分页
+     */
+    PageResult<MemberUserDO> getUserPage(MemberUserPageReqVO pageReqVO);
+
 }

+ 47 - 7
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java

@@ -2,9 +2,14 @@ package cn.iocoder.yudao.module.member.service.user;
 
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
+import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
+import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
@@ -19,14 +24,14 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import java.io.InputStream;
+import java.time.LocalDateTime;
 import java.util.Collection;
-import java.util.Date;
 import java.util.List;
-import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_NOT_EXISTS;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_MOBILE_EXISTS;
 
 /**
  * 会员 User Service 实现类
@@ -101,7 +106,7 @@ public class MemberUserServiceImpl implements MemberUserService {
 
     @Override
     public void updateUserNickname(Long userId, String nickname) {
-        MemberUserDO user = this.checkUserExists(userId);
+        MemberUserDO user = this.validateUserExists(userId);
         // 仅当新昵称不等于旧昵称时进行修改
         if (nickname.equals(user.getNickname())){
             return;
@@ -113,8 +118,8 @@ public class MemberUserServiceImpl implements MemberUserService {
     }
 
     @Override
-    public String updateUserAvatar(Long userId, InputStream avatarFile) throws Exception {
-        this.checkUserExists(userId);
+    public String updateUserAvatar(Long userId, InputStream avatarFile) {
+        validateUserExists(userId);
         // 创建文件
         String avatar = fileApi.createFile(IoUtil.readBytes(avatarFile));
         // 更新头像路径
@@ -126,7 +131,7 @@ public class MemberUserServiceImpl implements MemberUserService {
     @Transactional(rollbackFor = Exception.class)
     public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) {
         // 检测用户是否存在
-        checkUserExists(userId);
+        validateUserExists(userId);
         // TODO 芋艿:oldMobile 应该不用传递
 
         // 校验旧手机和旧验证码
@@ -155,8 +160,20 @@ public class MemberUserServiceImpl implements MemberUserService {
         return passwordEncoder.encode(password);
     }
 
+    @Override
+    public void updateUser(MemberUserUpdateReqVO updateReqVO) {
+        // 校验存在
+        validateUserExists(updateReqVO.getId());
+        // 校验手机唯一
+        validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile());
+
+        // 更新
+        MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO);
+        memberUserMapper.updateById(updateObj);
+    }
+
     @VisibleForTesting
-    public MemberUserDO checkUserExists(Long id) {
+    MemberUserDO validateUserExists(Long id) {
         if (id == null) {
             return null;
         }
@@ -167,4 +184,27 @@ public class MemberUserServiceImpl implements MemberUserService {
         return user;
     }
 
+    @VisibleForTesting
+    void validateMobileUnique(Long id, String mobile) {
+        if (StrUtil.isBlank(mobile)) {
+            return;
+        }
+        MemberUserDO user = memberUserMapper.selectByMobile(mobile);
+        if (user == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的用户
+        if (id == null) {
+            throw exception(USER_MOBILE_EXISTS);
+        }
+        if (!user.getId().equals(id)) {
+            throw exception(USER_MOBILE_EXISTS);
+        }
+    }
+
+    @Override
+    public PageResult<MemberUserDO> getUserPage(MemberUserPageReqVO pageReqVO) {
+        return memberUserMapper.selectPage(pageReqVO);
+    }
+
 }