wwh недель назад: 2
Родитель
Сommit
9fd2689018

+ 4 - 0
baqing-shop/src/main/java/com/ruoyi/web/modules/merchant/mapper/MerchantBindMapper.java

@@ -3,6 +3,7 @@ package com.ruoyi.web.modules.merchant.mapper;
3 3
 import java.util.List;
4 4
 import org.apache.ibatis.annotations.Param;
5 5
 import com.ruoyi.web.modules.merchant.vo.MerchantAdminUserOptionVO;
6
+import com.ruoyi.web.modules.merchant.vo.MerchantMemberOptionVO;
6 7
 
7 8
 /**
8 9
  * 商户入驻绑定查询
@@ -12,5 +13,8 @@ public interface MerchantBindMapper
12 13
     List<MerchantAdminUserOptionVO> selectAdminUsersByKeyword(@Param("keyword") String keyword,
13 14
             @Param("roleKey") String roleKey);
14 15
 
16
+    List<MerchantMemberOptionVO> selectMembersByKeyword(
17
+            @Param("keyword") String keyword, @Param("roleKey") String roleKey);
18
+
15 19
     int countUserHasRole(@Param("userId") Long userId, @Param("roleKey") String roleKey);
16 20
 }

+ 13 - 7
baqing-shop/src/main/java/com/ruoyi/web/modules/merchant/service/impl/MerchantAccountBindServiceImpl.java

@@ -7,7 +7,9 @@ import com.ruoyi.common.exception.ServiceException;
7 7
 import com.ruoyi.common.utils.SecurityUtils;
8 8
 import com.ruoyi.common.utils.StringUtils;
9 9
 import com.ruoyi.system.service.ISysConfigService;
10
-import com.ruoyi.system.service.ISysUserService;import com.ruoyi.web.modules.account.domain.BizMember;
10
+import com.ruoyi.system.service.ISysUserService;
11
+import com.ruoyi.web.modules.account.constant.MemberConstants;
12
+import com.ruoyi.web.modules.account.domain.BizMember;
11 13
 import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
12 14
 import com.ruoyi.web.modules.account.support.MemberSysUserSupport;
13 15
 import com.ruoyi.web.modules.merchant.constant.MerchantBindConstants;
@@ -101,16 +103,20 @@ public class MerchantAccountBindServiceImpl implements IMerchantAccountBindServi
101 103
         }
102 104
         memberSysUserSupport.grantRoleIfAbsent(memberId, MerchantBindConstants.MERCHANT_ADMIN_ROLE_KEY);
103 105
 
104
-        String memberName = StringUtils.isNotEmpty(member.getMemberCode()) ? member.getMemberCode() : member.getNickName();
105
-        if (StringUtils.isEmpty(memberName))
106
+        if (merchantBindMapper.countUserHasRole(memberId, MemberConstants.MEMBER_ROLE_KEY) <= 0)
106 107
         {
107
-            memberName = "会员";
108
+            throw new ServiceException("所选用户不是会员账号");
108 109
         }
109
-        String adminName = memberName + memberId;
110
-        String loginName = member.getNickName();
110
+
111
+        String loginName = member.getMemberCode();
111 112
         if (StringUtils.isEmpty(loginName))
112 113
         {
113
-            throw new ServiceException("会员昵称不能为空,无法作为经营账号登录名");
114
+            throw new ServiceException("会员名称不能为空,无法作为经营账号登录名");
115
+        }
116
+        String adminName = member.getNickName();
117
+        if (StringUtils.isEmpty(adminName))
118
+        {
119
+            throw new ServiceException("会员昵称不能为空,无法作为经营账号管理员姓名");
114 120
         }
115 121
         assertLoginNameAvailable(loginName);
116 122
 

+ 5 - 19
baqing-shop/src/main/java/com/ruoyi/web/modules/merchant/service/impl/MerchantServiceImpl.java

@@ -20,8 +20,7 @@ import com.ruoyi.web.modules.merchant.mapper.MerchantBindMapper;
20 20
 import com.ruoyi.web.modules.merchant.service.IMerchantAccountBindService;
21 21
 import com.ruoyi.web.modules.merchant.vo.MerchantAdminUserOptionVO;
22 22
 import com.ruoyi.web.modules.merchant.vo.MerchantMemberOptionVO;
23
-import com.ruoyi.web.modules.account.domain.BizMember;
24
-import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
23
+import com.ruoyi.web.modules.account.constant.MemberConstants;
25 24
 import com.ruoyi.web.modules.account.util.MemberMobileUtils;
26 25
 import com.ruoyi.web.modules.merchant.exception.MerchantBatchDeleteException;
27 26
 import com.ruoyi.web.modules.merchant.facade.IMerchantOrderFacade;
@@ -56,9 +55,6 @@ public class MerchantServiceImpl implements IMerchantService
56 55
     @Autowired
57 56
     private MerchantBindMapper merchantBindMapper;
58 57
 
59
-    @Autowired
60
-    private BizMemberMapper memberMapper;
61
-
62 58
     @Override
63 59
     public List<MerchantListVO> selectMerchantList(BizMerchant query)
64 60
     {
@@ -129,21 +125,11 @@ public class MerchantServiceImpl implements IMerchantService
129 125
     @Override
130 126
     public List<MerchantMemberOptionVO> searchMemberOptions(String keyword)
131 127
     {
132
-        BizMember query = new BizMember();
133
-        query.setKeyword(keyword);
134
-        List<MerchantMemberOptionVO> rows = new ArrayList<>();
135
-        for (BizMember m : memberMapper.selectList(query))
128
+        List<MerchantMemberOptionVO> rows = merchantBindMapper.selectMembersByKeyword(keyword,
129
+                com.ruoyi.web.modules.account.constant.MemberConstants.MEMBER_ROLE_KEY);
130
+        for (MerchantMemberOptionVO vo : rows)
136 131
         {
137
-            if (rows.size() >= 50)
138
-            {
139
-                break;
140
-            }
141
-            MerchantMemberOptionVO vo = new MerchantMemberOptionVO();
142
-            vo.setMemberId(m.getMemberId());
143
-            vo.setMemberCode(m.getMemberCode());
144
-            vo.setNickName(m.getNickName());
145
-            vo.setMobile(MemberMobileUtils.mask(m.getMobile()));
146
-            rows.add(vo);
132
+            vo.setMobile(MemberMobileUtils.mask(vo.getMobile()));
147 133
         }
148 134
         return rows;
149 135
     }

+ 20 - 0
baqing-shop/src/main/resources/mapper/merchant/MerchantBindMapper.xml

@@ -23,6 +23,26 @@
23 23
         limit 50
24 24
     </select>
25 25
 
26
+    <select id="selectMembersByKeyword" resultType="com.ruoyi.web.modules.merchant.vo.MerchantMemberOptionVO">
27
+        select distinct u.user_id as memberId,
28
+               u.user_name as memberCode,
29
+               u.nick_name as nickName,
30
+               u.phonenumber as mobile
31
+        from sys_user u
32
+        inner join sys_user_role ur on u.user_id = ur.user_id
33
+        inner join sys_role r on ur.role_id = r.role_id and r.del_flag = '0' and r.status = '0'
34
+        where u.del_flag = '0' and u.status = '0'
35
+          and (r.role_key = #{roleKey} or cast(r.role_id as char) = #{roleKey})
36
+        <if test="keyword != null and keyword != ''">
37
+            and (
38
+                u.user_name like concat('%', #{keyword}, '%')
39
+                or u.phonenumber like concat('%', #{keyword}, '%')
40
+            )
41
+        </if>
42
+        order by u.user_id desc
43
+        limit 50
44
+    </select>
45
+
26 46
     <select id="countUserHasRole" resultType="int">
27 47
         select count(1)
28 48
         from sys_user_role ur

+ 22 - 1
baqing-shop/src/test/java/com/ruoyi/web/modules/merchant/service/MerchantAccountBindServiceImplTest.java

@@ -13,6 +13,7 @@ import org.mockito.Mock;
13 13
 import org.mockito.junit.jupiter.MockitoExtension;
14 14
 import com.ruoyi.common.core.domain.entity.SysUser;
15 15
 import com.ruoyi.common.exception.ServiceException;
16
+import com.ruoyi.web.modules.account.constant.MemberConstants;
16 17
 import com.ruoyi.web.modules.account.domain.BizMember;
17 18
 import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
18 19
 import com.ruoyi.web.modules.merchant.constant.MerchantBindConstants;
@@ -83,6 +84,25 @@ class MerchantAccountBindServiceImplTest
83 84
         SysUser user = new SysUser();
84 85
         user.setUserId(5L);
85 86
         when(sysUserService.selectUserById(5L)).thenReturn(user);
87
+        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);
88
+
89
+        MerchantCreateDTO dto = new MerchantCreateDTO();
90
+        dto.setBindType(MerchantBindConstants.BIND_MEMBER);
91
+        dto.setBindMemberId(5L);
92
+
93
+        assertThrows(ServiceException.class, () -> bindService.bindAccountOnMerchantCreate(1L, dto, "op"));
94
+    }
95
+
96
+    @Test
97
+    void bindFromMember_requiresMemberName()
98
+    {
99
+        BizMember member = new BizMember();
100
+        member.setMemberId(5L);
101
+        member.setMemberCode("");
102
+        member.setNickName("小张");
103
+        when(memberMapper.selectById(5L)).thenReturn(member);
104
+        when(sysUserService.selectUserById(5L)).thenReturn(new SysUser());
105
+        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);
86 106
 
87 107
         MerchantCreateDTO dto = new MerchantCreateDTO();
88 108
         dto.setBindType(MerchantBindConstants.BIND_MEMBER);
@@ -103,7 +123,8 @@ class MerchantAccountBindServiceImplTest
103 123
         user.setUserId(5L);
104 124
         user.setPassword("hash");
105 125
         when(sysUserService.selectUserById(5L)).thenReturn(user);
106
-        when(merchantAccountMapper.countByLoginName(eq("小张"), isNull())).thenReturn(0);
126
+        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);
127
+        when(merchantAccountMapper.countByLoginName(eq("张三"), isNull())).thenReturn(0);
107 128
 
108 129
         MerchantCreateDTO dto = new MerchantCreateDTO();
109 130
         dto.setBindType(MerchantBindConstants.BIND_MEMBER);

+ 8 - 8
doc/农资商城web/组织管理/商户管理/商户管理功能需求.md

@@ -187,12 +187,11 @@
187 187
 
188 188
 | 项 | 规则 |
189 189
 |----|------|
190
-| 检索范围 | `biz_member` 未删除会员 |
191
-| 检索字段 | 手机号、**会员名称**(`member_code`)模糊匹配;可选展示会员昵称 |
192
-| 保存 — 同步 `sys_user` | 新建平台用户:角色编码 **100**;**用户名称** = 会员名称 + 会员 ID(`member_code` 为空时用会员昵称代替名称部分);**用户昵称** = 会员昵称 |
193
-| 保存 — `biz_merchant_account` | **管理员姓名** = 会员名称 + 会员 ID(同上);**登录名** = **会员昵称**(必填,空则阻断) |
194
-| 密码 | 会员路径:`sys_user.password` **直接复制** 会员已有 BCrypt 哈希(`biz_member.password`);经营账号密码同会员密码;`user_name` 冲突时加 `_m` 后缀 |
195
-| 唯一性 | 经营账号 **登录名** 全平台唯一;`sys_user.user_name` 冲突时系统自动加 `_m` 后缀 |
190
+| 检索范围 | `sys_user` 中 **已分配角色编码为 102** 的账号 |
191
+| 检索字段 | 手机号、**会员名称**(`user_name`)模糊匹配 |
192
+| 保存 — `sys_user_role` | 向已有会员用户 **追加** 角色 **100**(`user_id = member_id`) |
193
+| 保存 — `biz_merchant_account` | **管理员姓名** = **会员昵称**(`nick_name`,必填);**登录名** = **会员名称**(`user_name`,必填) |
194
+| 密码 | 复制会员 `sys_user.password` 至经营账号 |
196 195
 
197 196
 #### 6.7.3 校验与提示
198 197
 
@@ -203,7 +202,8 @@
203 202
 | 选会员但未选人 | 请选择会员账号 |
204 203
 | 用户无角色 100 | 所选用户未分配商户经营角色 |
205 204
 | 登录名已占用 | 经营账号登录名已存在 |
206
-| 会员无昵称 | 会员昵称不能为空,无法作为经营账号登录名 |
205
+| 会员无昵称 | 会员昵称不能为空,无法作为经营账号管理员姓名 |
206
+| 会员无名称 | 会员名称不能为空,无法作为经营账号登录名 |
207 207
 
208 208
 > **说明:** 本条仅在 **平台新增商户** 生效;编辑商户、店铺侧增删经营账号规则仍见《店铺管理功能需求》。
209 209
 
@@ -362,7 +362,7 @@
362 362
 | R1 | 单商户可开设 **多个** 未删除店铺;**本期不设数量上限**(`shop_count` 仅作统计展示) |
363 363
 | R2 | **新增商户** 须绑定管理员或会员并创建首条经营账号;会员模块能力不在本文展开 |
364 364
 | R12 | 绑定管理员:须具备角色编码 **100**;经营账号登录名 = `user_name`,管理员姓名 = `nick_name` |
365
-| R13 | 绑定会员:同步建 `sys_user`(角色 100)+ 经营账号;登录名 = 会员昵称,管理员姓名 = 会员名称+会员 ID |
365
+| R13 | 绑定会员:追加角色 **100**;经营账号 **登录名** = 会员名称,**管理员姓名** = 会员昵称 |
366 366
 | R3 | 入驻成功 → 认证 **正常** + 认证时间 |
367 367
 | R4 | 个人/企业类型创建后不可互转 |
368 368
 | R5 | 认证状态仅在 **查看详情** 修改 |

+ 13 - 13
doc/农资商城web/组织管理/商户管理/商户管理技术方案.md

@@ -186,11 +186,11 @@ biz_merchant(商户)
186 186
 
187 187
 | Query | 说明 |
188 188
 |-------|------|
189
-| keyword | 可选;模糊 `user_name` / `nick_name` / `phonenumber` |
189
+| keyword | 可选;模糊 `user_name` / `phonenumber` |
190 190
 
191 191
 | 响应 data[] | 说明 |
192 192
 |-------------|------|
193
-| userId, userName, nickName, phonenumber | 仅含 `sys_user` 且拥有 `role_key='100'` 或 `role_id=100` 的用户;最多 50 条 |
193
+| userId, userName, nickName, phonenumber | 仅含 `sys_user` 且拥有 **角色 100** 的用户;最多 50 条 |
194 194
 
195 195
 权限:`agri:merchant:add`
196 196
 
@@ -198,11 +198,11 @@ biz_merchant(商户)
198 198
 
199 199
 | Query | 说明 |
200 200
 |-------|------|
201
-| keyword | 可选;模糊 `mobile` / `member_code` / `nick_name` |
201
+| keyword | 可选;模糊 `user_name`(会员名称)/ `phonenumber` |
202 202
 
203 203
 | 响应 data[] | 说明 |
204 204
 |-------------|------|
205
-| memberId, memberCode, nickName, mobile | 未删除会员;最多 50 条 |
205
+| memberId, memberCode, nickName, mobile | `sys_user` 且拥有 **角色 102**;`memberId=userId`;mobile 脱敏;最多 50 条 |
206 206
 
207 207
 权限:`agri:merchant:add`
208 208
 
@@ -266,7 +266,7 @@ biz_merchant(商户)
266 266
 | R1 | **不设** 店铺数量上限;`shop_count` 仅统计;selectList / openShopCheck **不校验** 店数 |
267 267
 | R2 | `MerchantAccountBindServiceImpl`;`MerchantBindMapper` |
268 268
 | R12 | `BIND_SYS_USER`:`login_name=user_name`,`admin_name=nick_name` |
269
-| R13 | `BIND_MEMBER`:insert `sys_user` + `biz_merchant_account`;见 §9.8 |
269
+| R13 | `BIND_MEMBER`:追加角色 100 + `biz_merchant_account`;见 §9.8 |
270 270
 | R3 | insert `cert_status=0` + `cert_time` |
271 271
 | R4 | update 忽略 `merchantType` |
272 272
 | R5 | `certStatus` 仅 `PUT .../certStatus` |
@@ -445,16 +445,16 @@ biz_merchant(商户)
445 445
 | 未选绑定 | 请选择并绑定管理员账号或会员账号 |
446 446
 | 用户无角色 100 | 所选用户未分配商户经营角色 |
447 447
 | 登录名重复 | 经营账号登录名已存在 |
448
-| 会员无昵称 | 会员昵称不能为空,无法作为经营账号登录名 |
448
+| 会员无昵称 | 会员昵称不能为空,无法作为经营账号管理员姓名 |
449
+| 会员无名称 | 会员名称不能为空,无法作为经营账号登录名 |
449 450
 
450 451
 ### 9.8 入驻绑定请求字段(`MerchantCreateDTO`)
451 452
 
452 453
 | 字段 | 类型 | 必填 | 说明 |
453 454
 |------|------|:----:|------|
454 455
 | bindType | String | ✓ | `SYS_USER` 或 `MEMBER` |
455
-| bindUserId | Long | SYS_USER 时 ✓ | `sys_user.user_id` |
456
-| bindMemberId | Long | MEMBER 时 ✓ | `biz_member.member_id` |
457
-| sysUserInitPassword | String | — | 仅 MEMBER;明文初始密码,空则读 `sys.user.initPassword` |
456
+| bindUserId | Long | SYS_USER 时 ✓ | `sys_user.user_id`(角色 100) |
457
+| bindMemberId | Long | MEMBER 时 ✓ | `member_id = sys_user.user_id`(角色 102) |
458 458
 
459 459
 **`BIND_SYS_USER` 落库 `biz_merchant_account`**
460 460
 
@@ -466,10 +466,10 @@ biz_merchant(商户)
466 466
 
467 467
 **`BIND_MEMBER`**
468 468
 
469
-1. `adminName` = `member_code`(空则 `nick_name`)+ `memberId`  
470
-2. `loginName` = `nick_name`(必填)  
471
-3. `insert sys_user`:`user_name=adminName`(冲突加 `_m`),`nick_name`,`role_ids=[role_id(100)]`,`dept_id=100`  
472
-4. `insert biz_merchant_account`:`login_name`、`admin_name` 同上;`password` 优先会员密码哈希  
469
+1. `grantRoleIfAbsent(userId, 100)` → `sys_user_role` 追加角色 100  
470
+2. `login_name` = 会员名称(`user_name`,必填)  
471
+3. `admin_name` = 会员昵称(`nick_name`,必填)  
472
+4. `insert biz_merchant_account`;`password` 复制会员 `sys_user.password`  
473 473
 
474 474
 实现类:`com.ruoyi.web.modules.merchant.service.impl.MerchantAccountBindServiceImpl`  
475 475
 SQL:`mapper/merchant/MerchantBindMapper.xml`