Sfoglia il codice sorgente

Merge branch 'sit' into sit-OrderFood

# Conflicts:
#	alien-entity/src/main/java/shop/alien/entity/store/StoreTable.java
lutong 2 mesi fa
parent
commit
d797d0178f

+ 0 - 4
alien-entity/src/main/java/shop/alien/entity/store/excelVo/StoreUserExcelVo.java

@@ -23,10 +23,6 @@ public class StoreUserExcelVo {
     @ExcelHeader(value = "账号ID")
     private Integer id;
 
-//    @ApiModelProperty(value = "主账号手机号")
-//    @ExcelHeader(value = "主账号手机号码")
-//    @JsonInclude(JsonInclude.Include.NON_NULL)
-//    private String parentAccountPhone;
 
     @ApiModelProperty(value = "手机号码")
     @ExcelHeader(value = "手机号码")

+ 6 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeFeedbackListVo.java

@@ -22,9 +22,15 @@ public class LifeFeedbackListVo implements Serializable {
     @ApiModelProperty(value = "用户昵称")
     private String nickName;
 
+    @ApiModelProperty(value = "用户昵称")
+    private String userNickName;
+
     @ApiModelProperty(value = "账号(手机号)")
     private String phone;
 
+    @ApiModelProperty(value = "用户手机号)")
+    private String userPhone;
+
     @ApiModelProperty(value = "反馈类型:0-bug反馈,1-优化反馈,2-新增功能反馈")
     private Integer feedbackType;
 

+ 6 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/PerformerVo.java

@@ -43,5 +43,11 @@ public class PerformerVo implements Serializable {
      */
     @ApiModelProperty(value = "职位")
     private String style;
+
+    /**
+     * 标签(对应 store_staff_config.tag)
+     */
+    @ApiModelProperty(value = "标签")
+    private String tag;
 }
 

+ 7 - 3
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreSubExcelVo.java

@@ -15,14 +15,18 @@ public class StoreSubExcelVo {
     @ApiModelProperty(value = "序号")
     private Integer serialNumber;
 
-    @ApiModelProperty(value = "账号ID")
-    @ExcelHeader(value = "账号ID")
-    private Integer id;
+    @ApiModelProperty(value = "账号ID(主账号联系方式所对应的id)")
+    @ExcelHeader(value = "账号ID")
+    private Integer parentAccountId;
 
     @ApiModelProperty(value = "主账号手机号")
     @ExcelHeader(value = "主账号手机号码")
     private String parentAccountPhone;
 
+    @ApiModelProperty(value = "子账号ID")
+    @ExcelHeader(value = "子账号ID")
+    private Integer subAccountId;
+
     @ApiModelProperty(value = "手机号码")
     @ExcelHeader(value = "手机号码")
     private String phone;

+ 4 - 1
alien-entity/src/main/java/shop/alien/entity/store/vo/StoreUserVo.java

@@ -20,9 +20,12 @@ import java.util.List;
 @JsonInclude
 @ApiModel(value = "StoreUserVo对象", description = "门店用户扩展")
 public class StoreUserVo extends StoreUser {
-     @ApiModelProperty(value = "父账号Id")
+     @ApiModelProperty(value = "父账号Id(主账号联系方式所对应的id)")
     private Integer parentAccountId;
 
+    @ApiModelProperty(value = "子账号ID(用于删除/禁用等操作,子账号列表时必填)")
+    private Integer subAccountId;
+
     @ApiModelProperty(value = "登录Token")
     private String token;
 

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/StoreOperationalActivity.java

@@ -136,5 +136,9 @@ public class StoreOperationalActivity {
     @TableField("audit_time")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date auditTime;
+
+    @ApiModelProperty(value = "上传图片类型:0-本地上传, 1-AI生成")
+    @TableField("upload_img_type")
+    private Integer uploadImgType;
 }
 

+ 3 - 0
alien-entity/src/main/java/shop/alien/entity/storePlatform/vo/StoreOperationalActivityVO.java

@@ -60,5 +60,8 @@ public class StoreOperationalActivityVO extends StoreOperationalActivity {
 
     @ApiModelProperty(value = "活动类型名称")
     private String activityTypeName;
+
+    @ApiModelProperty(value = "上传图片类型:0-本地上传, 1-AI生成")
+    private Integer uploadImgType;
 }
 

+ 3 - 0
alien-entity/src/main/resources/mapper/LifeFeedbackMapper.xml

@@ -121,7 +121,9 @@
         SELECT
             f.id,
             u.nick_name AS nickName,
+            lu.user_name AS userNickName,
             u.phone AS phone,
+            lu.user_phone AS userPhone,
             f.feedback_type AS feedbackType,
             CASE f.feedback_type
                 WHEN 0 THEN 'bug反馈'
@@ -149,6 +151,7 @@
         FROM life_feedback f
         LEFT JOIN store_user u ON f.user_id = u.id
         LEFT JOIN life_sys s ON f.staff_id = s.id
+        LEFT JOIN life_user lu ON f.user_id = lu.id
         WHERE 1=1
         <if test="feedbackType != null">
             AND f.feedback_type = #{feedbackType}

+ 145 - 0
alien-job/src/main/java/shop/alien/job/store/StoreOperationalActivityJob.java

@@ -0,0 +1,145 @@
+package shop.alien.job.store;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.xxl.job.core.handler.annotation.XxlJob;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.storePlatform.StoreOperationalActivity;
+import shop.alien.mapper.storePlantform.StoreOperationalActivityMapper;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 营销活动状态定时任务
+ * 根据活动的开始时间和结束时间自动更新活动状态
+ *
+ * @author system
+ * @date 2025/01/XX
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class StoreOperationalActivityJob {
+
+    private final StoreOperationalActivityMapper activityMapper;
+
+    /**
+     * 营销活动状态更新任务
+     * 定时更新活动状态:未开始 -> 进行中 -> 已结束
+     */
+    @XxlJob("operationalActivityStatusUpdateTask")
+    public void operationalActivityStatusUpdateTask() {
+        log.info("【定时任务】开始执行营销活动状态更新任务...");
+        
+        // 获取当前时间(零点)
+        Date now = new Date();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(now);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        now = calendar.getTime();
+
+        try {
+            // 查询需要更新状态的活动:2-未开始, 5-进行中, 8-审核成功
+            List<Integer> statusList = new ArrayList<>();
+            statusList.add(2); // 未开始
+            statusList.add(5); // 进行中
+            statusList.add(8); // 审核成功
+
+            LambdaQueryWrapper<StoreOperationalActivity> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.in(StoreOperationalActivity::getStatus, statusList)
+                    .isNotNull(StoreOperationalActivity::getStartTime)
+                    .isNotNull(StoreOperationalActivity::getEndTime);
+            
+            List<StoreOperationalActivity> activities = activityMapper.selectList(queryWrapper);
+            log.info("【定时任务】查询到需要更新状态的活动数量: {}", activities.size());
+
+            if (activities.isEmpty()) {
+                log.info("【定时任务】没有需要更新状态的活动");
+                return;
+            }
+
+            // 需要设置为"已结束"的活动ID列表
+            List<Integer> endActivityIds = new ArrayList<>();
+            // 需要设置为"进行中"的活动ID列表
+            List<Integer> ongoingActivityIds = new ArrayList<>();
+            // 需要设置为"未开始"的活动ID列表
+            List<Integer> notStartActivityIds = new ArrayList<>();
+
+            // 遍历活动,判断状态
+            for (StoreOperationalActivity activity : activities) {
+                Date startTime = activity.getStartTime();
+                Date endTime = activity.getEndTime();
+                Integer currentStatus = activity.getStatus();
+
+                if (startTime == null || endTime == null) {
+                    log.warn("【定时任务】活动ID: {} 的开始时间或结束时间为空,跳过处理", activity.getId());
+                    continue;
+                }
+
+                // 判断当前时间与活动时间的关系
+                if (now.compareTo(endTime) > 0) {
+                    // 当前时间 > 结束时间:应该设置为"已结束"(7)
+                    // 只处理状态为"未开始"(2)或"进行中"(5)的活动
+                    if (currentStatus == 2 || currentStatus == 5) {
+                        endActivityIds.add(activity.getId());
+                        log.debug("【定时任务】活动ID: {} 已过期,需要设置为已结束", activity.getId());
+                    }
+                } else if (now.compareTo(startTime) >= 0 && now.compareTo(endTime) <= 0) {
+                    // 当前时间在活动时间范围内:应该设置为"进行中"(5)
+                    // 只处理状态为"未开始"(2)或"审核成功"(8)的活动
+                    if (currentStatus == 2 || currentStatus == 8) {
+                        ongoingActivityIds.add(activity.getId());
+                        log.debug("【定时任务】活动ID: {} 正在进行中,需要设置为进行中", activity.getId());
+                    }
+                } else if (now.compareTo(startTime) < 0) {
+                    // 当前时间 < 开始时间:应该设置为"未开始"(2)
+                    // 只处理状态为"审核成功"(8)的活动
+                    if (currentStatus == 8) {
+                        notStartActivityIds.add(activity.getId());
+                        log.debug("【定时任务】活动ID: {} 未开始,需要设置为未开始", activity.getId());
+                    }
+                }
+            }
+
+            // 批量更新状态为"已结束"
+            if (!endActivityIds.isEmpty()) {
+                LambdaUpdateWrapper<StoreOperationalActivity> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.in(StoreOperationalActivity::getId, endActivityIds)
+                        .set(StoreOperationalActivity::getStatus, 7); // 7-已结束
+                int updateCount = activityMapper.update(null, updateWrapper);
+                log.info("【定时任务】已结束活动更新完成,活动ID列表: {},更新数量: {}", endActivityIds, updateCount);
+            }
+
+            // 批量更新状态为"进行中"
+            if (!ongoingActivityIds.isEmpty()) {
+                LambdaUpdateWrapper<StoreOperationalActivity> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.in(StoreOperationalActivity::getId, ongoingActivityIds)
+                        .set(StoreOperationalActivity::getStatus, 5); // 5-进行中
+                int updateCount = activityMapper.update(null, updateWrapper);
+                log.info("【定时任务】进行中活动更新完成,活动ID列表: {},更新数量: {}", ongoingActivityIds, updateCount);
+            }
+
+            // 批量更新状态为"未开始"
+            if (!notStartActivityIds.isEmpty()) {
+                LambdaUpdateWrapper<StoreOperationalActivity> updateWrapper = new LambdaUpdateWrapper<>();
+                updateWrapper.in(StoreOperationalActivity::getId, notStartActivityIds)
+                        .set(StoreOperationalActivity::getStatus, 2); // 2-未开始
+                int updateCount = activityMapper.update(null, updateWrapper);
+                log.info("【定时任务】未开始活动更新完成,活动ID列表: {},更新数量: {}", notStartActivityIds, updateCount);
+            }
+
+            log.info("【定时任务】营销活动状态更新任务执行完成");
+        } catch (Exception e) {
+            log.error("【定时任务】营销活动状态更新任务执行异常", e);
+        }
+    }
+}
+

+ 9 - 9
alien-store/src/main/java/shop/alien/store/controller/StoreUserController.java

@@ -217,7 +217,7 @@ public class StoreUserController {
     }
 
     /**
-     * web端查询用户列表(支持主账号和子账号查询) 分页查询重构
+     * web端查询用户列表(支持主账号和子账号查询)
      */
     @ApiOperation("web端查询用户列表(支持主账号和子账号查询)")
     @ApiOperationSupport(order = 7)
@@ -282,13 +282,14 @@ public class StoreUserController {
     }
 
 
+
     /**
      * web端切换商家端用户状态  (主账号有子账号时禁止禁用;子账号无限制;返回更新后状态供前端及时展示)
      */
     @ApiOperation("web端切换商家端用户状态(主账号有子账号时禁止禁用;返回更新后状态供前端及时展示)")
     @ApiOperationSupport(order = 7)
     @PutMapping("/switchingStates")
-    public R<StoreUserVo> switchingStates(@RequestBody StoreUser storeUser) {
+    public R<StoreUserVo> switchingStates(@RequestBody StoreUserVo storeUser) {
         log.info("StoreUserController.switchingStates?storeUser={}", storeUser);
         try {
             return storeUserService.switchingStates(storeUser);
@@ -298,6 +299,7 @@ public class StoreUserController {
         }
     }
 
+
     @ApiOperation(value = "web端导出商家端账号相关信息")
     @ApiOperationSupport(order = 6)
     @GetMapping("/exportExcel")
@@ -418,15 +420,13 @@ public class StoreUserController {
      */
     @ApiOperation("手动删除商家账号及店铺")
     @PostMapping("/deleteStoreAccountInfo")
-    public R<StoreUserVo> deleteStoreAccountInfo(@RequestBody StoreUserVo storeUserVo) {
-        log.info("StoreUserController.deleteStoreAccountInfo?storeUserVo={}", storeUserVo);
-        try {
-            storeUserService.deleteStoreAccountInfo(storeUserVo);
+    public R<String> deleteStoreAccountInfo(@RequestBody StoreUserVo storeUserVo) {
+        log.info("StoreUserController.deleteStoreAccountInfo?phone={}, id={}", storeUserVo.getPhone(), storeUserVo.getSubAccountId());
+        String errMsg = storeUserService.deleteStoreAccountInfo(storeUserVo);
+        if (errMsg == null || errMsg.isEmpty()) {
             return R.success("删除成功");
-        } catch (Exception e) {
-            log.warn("StoreUserController.deleteStoreAccountInfo 校验或删除失败: {}", e.getMessage());
-            return R.fail(e.getMessage());
         }
+        return R.fail(errMsg);
     }
 
     /**

+ 8 - 5
alien-store/src/main/java/shop/alien/store/service/StoreUserService.java

@@ -117,16 +117,18 @@ public interface StoreUserService extends IService<StoreUser> {
      */
     void resetStoreUserPassword(StoreUser storeUser);
 
+
+
     /**
-     * web端切换商家端用户状态(主账号底下有子账号时禁止禁用;子账号无限制)
+     * web端切换商家端用户状态
      *
-     * @return   更新后的用户信息(含最新 status),供前端及时展示
+     * @return boolean
      */
-    R<StoreUserVo> switchingStates(StoreUser storeUserParam);
+    R<StoreUserVo> switchingStates(StoreUserVo storeUser);
 
 
     /**
-     * web端导出商家端主账号和子账号相关信息
+     * web端导出商家端账号相关信息
      */
     String exportExcel(String id, String phone, String status, Integer accountType) throws IOException;
 
@@ -172,8 +174,9 @@ public interface StoreUserService extends IService<StoreUser> {
 
     /**
      * 手动删除商家账号及店铺 进行校验
+     * @return 成功返回 null;失败返回具体原因:当前账号下存在店铺 禁止删除 / 当前账号下存在子账号禁止删除 / 删除失败
      */
-    void deleteStoreAccountInfo(StoreUserVo storeUserVo);
+    String deleteStoreAccountInfo(StoreUserVo storeUserVo);
 
     /**
      * 获取主键集合

+ 1 - 0
alien-store/src/main/java/shop/alien/store/service/impl/BarPerformanceServiceImpl.java

@@ -534,6 +534,7 @@ public class BarPerformanceServiceImpl implements BarPerformanceService {
         performerVo.setAvatar(staffConfig.getStaffImage());
         performerVo.setName(staffConfig.getName());
         performerVo.setStyle(staffConfig.getStaffPosition());
+        performerVo.setTag(staffConfig.getTag());
         return performerVo;
     }
 

+ 274 - 144
alien-store/src/main/java/shop/alien/store/service/impl/StoreUserServiceImpl.java

@@ -252,12 +252,10 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
     public Map<String, String> changePhoneVerification(String phone, String oldPassword, String verificationCode) {
         Map<String, String> changePhoneMap = new HashMap<>();
         if (oldPassword != null && !oldPassword.equals("")) {
-            LambdaQueryWrapper<StoreUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
-            userLambdaQueryWrapper.eq(StoreUser::getPhone, phone);
-            StoreUser storeUser = this.getOne(userLambdaQueryWrapper);
-            // 由于password字段使用了EncryptTypeHandler,查询时密码会被自动解密
-            // 所以这里直接比较解密后的密码和用户输入的明文密码
-            if (storeUser != null && storeUser.getPassword() != null && storeUser.getPassword().equals(oldPassword)) {
+            LambdaUpdateWrapper<StoreUser> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+            userLambdaUpdateWrapper.eq(StoreUser::getPhone, phone);
+            StoreUser storeUser = this.getOne(userLambdaUpdateWrapper);
+            if (storeUser.getPassword().equals(oldPassword)) {
                 changePhoneMap.put("passwordStatus", "1");
                 return changePhoneMap;
             } else {
@@ -271,7 +269,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
     }
 
     private void passwordVerification(String phone, String password, String newPassword, String confirmNewPassword) {
-        LambdaUpdateWrapper<StoreUser> wrapperFans = new LambdaUpdateWrapper<>();
+        LambdaQueryWrapper<StoreUser> wrapperFans = new LambdaQueryWrapper<>();
         wrapperFans.eq(StoreUser::getPhone, phone);
         StoreUser storeUser = this.getOne(wrapperFans);
         if (!newPassword.equals(confirmNewPassword)) {
@@ -282,9 +280,10 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             log.info("该手机号没有注册过账户");
             throw new RuntimeException("该手机号没有注册过账户");
         } else {
-            wrapperFans.eq(StoreUser::getPassword, password);
-            StoreUser storeUserPw = this.getOne(wrapperFans);
-            if (storeUserPw == null || storeUserPw.getPassword().equals("")) {
+            // 由于password字段使用了EncryptTypeHandler,查询时密码会被自动解密
+            // 所以这里直接比较解密后的密码和用户输入的明文密码
+            String dbPassword = storeUser.getPassword();
+            if (dbPassword == null || dbPassword.isEmpty() || !dbPassword.equals(password)) {
                 log.info("原密码错误");
                 throw new RuntimeException("原密码错误");
             }
@@ -403,7 +402,6 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         return R.data(vo);
     }
 
-
     @Override
     public R<IPage<StoreUserVo>> getStoreUserList(int pageNum, int pageSize, String id, String phone, Integer status, Integer accountType, String mainAccountId, String mainAccountPhone) {
         IPage<StoreUser> page = new Page<>(pageNum, pageSize);
@@ -455,17 +453,57 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
                 return R.data(storeUserVoIPage);
             }
 
+            // 按 (userId, role_id) 去重,同一用户同一角色只保留一条(保留 id 最小的一条)
+            userRoles = userRoles.stream()
+                    .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
+                    .collect(Collectors.toMap(
+                            r -> (r.getUserId() != null ? r.getUserId() : 0) + "_" + (r.getRoleId() != null ? r.getRoleId() : ""),
+                            r -> r,
+                            (a, b) -> a
+                    ))
+                    .values().stream()
+                    .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
+                    .collect(Collectors.toList());
+
             // 按子账号 id/phone/status 过滤:批量查 store_user,只保留对应子账号满足条件的 role
             List<Integer> distinctUserIds = userRoles.stream().map(StorePlatformUserRole::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
             List<StoreUser> subAccountList = distinctUserIds.isEmpty() ? Collections.emptyList() : storeUserMapper.selectBatchIds(distinctUserIds);
-            Map<Integer, StoreUser> subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream().filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0).collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+            // 根据 status 参数决定子账号池:选「注销中/已注销」时只保留对应状态;否则排除注销中、已注销
+            Map<Integer, StoreUser> subAccountMap;
+            if (status != null && (status == -1 || status == 2)) {
+                final int filterStatus = status;
+                subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
+                        .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0)
+                        .filter(u -> {
+                            if (filterStatus == -1) return u.getStatus() != null && u.getStatus() == -1;
+                            return (u.getStatus() != null && u.getStatus() == 2) || (u.getLogoutFlag() != null && u.getLogoutFlag() == 1);
+                        })
+                        .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+            } else {
+                subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
+                        .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0
+                                && (u.getLogoutFlag() == null || u.getLogoutFlag() == 0)
+                                && (u.getStatus() == null || (u.getStatus() != -1 && u.getStatus() != 2)))
+                        .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+            }
             List<StorePlatformUserRole> filteredRoles = new ArrayList<>();
             for (StorePlatformUserRole role : userRoles) {
                 StoreUser subAccount = subAccountMap.get(role.getUserId());
                 if (subAccount == null) continue;
-                if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id))) continue;
-                if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone))) continue;
-                if (status != null && !status.equals(subAccount.getStatus())) continue;
+                if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id)))
+                    continue;
+                if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone)))
+                    continue;
+                // 状态筛选:选「注销中/已注销」时以 store_user 为准(已由 subAccountMap 限定);否则以 role.status 为准
+                int rowStatus;
+                if (status != null && (status == -1 || status == 2)) {
+                    rowStatus = (subAccount.getStatus() != null && subAccount.getStatus() == -1) ? -1
+                            : ((subAccount.getStatus() != null && subAccount.getStatus() == 2) || (subAccount.getLogoutFlag() != null && subAccount.getLogoutFlag() == 1)) ? 2
+                            : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
+                } else {
+                    rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
+                }
+                if (status != null && !status.equals(rowStatus)) continue;
                 filteredRoles.add(role);
             }
             filteredRoles.sort(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())));
@@ -496,13 +534,19 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             for (StorePlatformUserRole role : pageRoles) {
                 StoreUser subAccount = subAccountMap.get(role.getUserId());
                 if (subAccount == null) continue;
+                StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
                 StoreUserVo storeUserVo = new StoreUserVo();
                 BeanUtils.copyProperties(subAccount, storeUserVo);
-                storeUserVo.setSwitchStatus(subAccount.getStatus() != null && subAccount.getStatus() == 0);
+                // 分页列表:账号ID、parentAccountId 均为主账号 id(与主账号联系电话对应),子账号 id 放入 subAccountId
+                Integer mainId = mainAccount != null ? mainAccount.getId() : subAccount.getSubAccountId();
+                storeUserVo.setId(mainId != null ? mainId : subAccount.getId());
+                storeUserVo.setSubAccountId(subAccount.getId());
+                storeUserVo.setParentAccountId(mainId);
+                int rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
+                storeUserVo.setStatus(rowStatus);
+                storeUserVo.setSwitchStatus(rowStatus == 0);
                 storeUserVo.setPhone(subAccount.getPhone());
-                StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
                 if (mainAccount != null) {
-                    storeUserVo.setParentAccountId(mainAccount.getId());
                     storeUserVo.setParentAccountPhone(mainAccount.getPhone());
                     storeUserVo.setParentAccountName(mainAccount.getName());
                 }
@@ -514,13 +558,15 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             return R.data(storeUserVoIPage);
         }
 
-        // 主账号分支:直接查库返回最新 status,主账号页面展示子账号数量(按 store_platform_user_role 统计)
+        // 主账号分支:直接查库返回最新 status,主账号页面展示子账号数量(按 store_platform_user_role 统计);排除注销中、已注销
         LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
         storeUserLambdaQueryWrapper.eq(StoreUser::getDeleteFlag, 0)
                 .like(StringUtils.isNotEmpty(id), StoreUser::getId, id)
                 .like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                 .eq(status != null, StoreUser::getStatus, status)
                 .eq(StoreUser::getAccountType, 1)
+                .and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, 0))
+                .and(w -> w.isNull(StoreUser::getStatus).or().in(StoreUser::getStatus, 0, 1))
                 .orderByDesc(StoreUser::getCreatedTime);
 
         IPage<StoreUser> storeUsers = storeUserMapper.selectPage(page, storeUserLambdaQueryWrapper);
@@ -546,13 +592,17 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         return R.data(storeUserVoIPage);
     }
 
-    /** 按 store_platform_user_role 统计该店铺下子账号数量(排除主账号自身,按 distinct user_id 计) */
+    /**
+     * 按 store_platform_user_role 统计该店铺下子账号数量(排除主账号自身,按 distinct user_id 计)
+     */
     private int countSubAccountUserIdsByStoreId(Integer storeId, Integer excludeUserId) {
         List<Integer> userIds = getSubAccountUserIdsByStoreId(storeId, excludeUserId);
         return userIds == null ? 0 : userIds.size();
     }
 
-    /** 按 store_platform_user_role 查询该店铺下子账号 userId 列表(排除主账号自身) */
+    /**
+     * 按 store_platform_user_role 查询该店铺下子账号 userId 列表(排除主账号自身)
+     */
     private List<Integer> getSubAccountUserIdsByStoreId(Integer storeId, Integer excludeUserId) {
         if (storeId == null) return Collections.emptyList();
         LambdaQueryWrapper<StorePlatformUserRole> w = new LambdaQueryWrapper<>();
@@ -581,48 +631,84 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
 
 
     /**
-     * web端切换商家端用户状态(主账号底下有子账号时禁止禁用;子账号无限制)
-     * @param storeUserParam
-     * @return
+     * web端切换商家端用户状态(主账号底下有子账号时禁止禁用;子账号无限制)。
+     * 若同一账号既是主账号又是子账号:禁用时只禁用子账号角色,主账号保持启用。
      */
     @Override
-    public R<StoreUserVo> switchingStates(StoreUser storeUserParam) {
-        StoreUser storeUser = storeUserMapper.selectById(storeUserParam.getId());
-        if (storeUser == null) {
-            throw new RuntimeException("用户不存在");
+    public R<StoreUserVo> switchingStates(StoreUserVo storeUserParam) {
+        // 默认传 0 表示执行禁用(状态改为 1),分页列表展示为禁用;传 1 表示执行启用(状态改为 0),分页列表展示为启用
+        int currentStatus = storeUserParam.getStatus() != null ? storeUserParam.getStatus() : 0;
+        int newStatus = (currentStatus == 0) ? 1 : 0;
+        boolean isMainAccount = storeUserParam.getAccountType() != null && storeUserParam.getAccountType() == 1;
+
+        if(storeUserParam.getAccountType()==2){
+            StoreUser storeUser = storeUserMapper.selectById(storeUserParam.getSubAccountId());
+            if (storeUser == null) {
+                throw new RuntimeException("用户不存在");
+            }
+            // 统计该用户在 platform 中未删除的角色数,用于判断是否「既是主账号也是子账号」
+            long roleCount = storePlatformUserRoleMapper.selectCount(
+                    new LambdaQueryWrapper<StorePlatformUserRole>()
+                            .eq(StorePlatformUserRole::getUserId, storeUser.getId())
+                            .eq(StorePlatformUserRole::getDeleteFlag, 0));
+            log.info("员工状态的status roleCount={}",roleCount);
+            boolean isBothMainAndSub = isMainAccount && roleCount > 0;
+            // 1 既是主账号也是子账号且本次为禁用:只禁用子账号角色,不更新 store_user,主账号保持启用;子账号在列表上按 role.status 展示为禁用
+            if (isBothMainAndSub) {
+                LambdaUpdateWrapper<StorePlatformUserRole> roleUpdateWrapper = new LambdaUpdateWrapper<>();
+                roleUpdateWrapper.eq(StorePlatformUserRole::getUserId, storeUser.getId())
+                        .eq(StorePlatformUserRole::getDeleteFlag, 0)
+                        .set(StorePlatformUserRole::getStatus, currentStatus);
+                storePlatformUserRoleMapper.update(null, roleUpdateWrapper);
+                StoreUserVo vo = new StoreUserVo();
+                vo.setId(storeUser.getId());
+                vo.setStatus(newStatus);
+                vo.setSwitchStatus(newStatus == 0);
+                return R.data(vo);
+            }
+            LambdaUpdateWrapper<StorePlatformUserRole> roleUpdateWrapper = new LambdaUpdateWrapper<>();
+            roleUpdateWrapper.eq(StorePlatformUserRole::getUserId, storeUser.getId())
+                    .eq(StorePlatformUserRole::getDeleteFlag, 0)
+                    .set(StorePlatformUserRole::getStatus, currentStatus);
+            storePlatformUserRoleMapper.update(null, roleUpdateWrapper);
+            baseRedisService.delete("store_" + storeUser.getPhone());
+            LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
+            userUpdateWrapper.eq(StoreUser::getId, storeUser.getId()).set(StoreUser::getStatus, currentStatus);
+            storeUserMapper.update(null, userUpdateWrapper);
+            StoreUserVo vo = new StoreUserVo();
+            vo.setId(storeUser.getId());
+            vo.setStatus(newStatus);
+            vo.setSwitchStatus(newStatus == 0);
+            return R.data(vo);
+
         }
-        // 仅当「即将禁用」时校验:主账号且该店铺下在 store_platform_user_role 中有关联子账号则禁止禁用
-        if (storeUser.getStatus() != null && storeUser.getStatus() == 0) {
-            if (storeUser.getAccountType() != null && storeUser.getAccountType() == 1) {
-                int subCount = countSubAccountUserIdsByStoreId(storeUser.getStoreId(), storeUser.getId());
-                if (subCount > 0) {
+
+        // 本次为禁用
+        if (newStatus == 0) {
+            // 2 对于主账号:有关联子账号则禁止禁用,请先删除主账号下的子账号
+            if (isMainAccount) {
+                List<StoreUser> subAccounts = getSubAccountsByMainAccountId(storeUserParam.getId());
+                if (subAccounts != null && !subAccounts.isEmpty()) {
                     throw new RuntimeException("请先删除主账号下的子账号后再禁用");
                 }
             }
-            // 禁用时删除 token
-            baseRedisService.delete("store_" + storeUser.getPhone());
         }
-        // 根据当前状态切另一个状态
-        int newStatus = storeUser.getStatus() == 0 ? 1 : 0;
-        LambdaUpdateWrapper<StoreUser> queryWrapper = new LambdaUpdateWrapper<>();
-        queryWrapper.eq(StoreUser::getId, storeUser.getId())
-                .set(StoreUser::getStatus, newStatus);
-        int updateCount = storeUserMapper.update(null, queryWrapper);
-        if (updateCount <= 0) {
-            throw new RuntimeException("更新失败");
-        }
-        // 返回更新后的状态,供前端及时展示
+        // 启用/禁用:更新 store_user 的 status(禁用 0→1,启用 1→0),列表即时展示用返回的 vo
+        LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
+        userUpdateWrapper.eq(StoreUser::getId, storeUserParam.getId()).set(StoreUser::getStatus, newStatus);
+        storeUserMapper.update(null, userUpdateWrapper);
         StoreUserVo vo = new StoreUserVo();
-        vo.setId(storeUser.getId());
+        vo.setId(storeUserParam.getId());
         vo.setStatus(newStatus);
         vo.setSwitchStatus(newStatus == 0);
         return R.data(vo);
     }
 
     /**
-     *  分页查询
-     * @param pageNum
-     * @param pageSize
+     * 分页查询
+     *
+     * @param
+     * @param
      * @param id
      * @param phone
      * @param status
@@ -632,7 +718,7 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
     @Override
     public String exportExcel(String id, String phone, String status, Integer accountType) throws IOException {
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-        // 主账号导出:与 getStoreUserList 主账号分支一致,子账号数量按 store_platform_user_role 统计
+        // 主账号导出:与 getStoreUserList 主账号分支一致,子账号数量按 store_platform_user_role 统计;排除注销中、已注销
         if (accountType == 1) {
             LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
             wrapper.eq(StoreUser::getDeleteFlag, 0)
@@ -640,6 +726,8 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
                     .like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                     .eq(StringUtils.isNotEmpty(status), StoreUser::getStatus, status)
                     .eq(StoreUser::getAccountType, 1)
+                    .and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, 0))
+                    .and(w -> w.isNull(StoreUser::getStatus).or().in(StoreUser::getStatus, 0, 1))
                     .orderByDesc(StoreUser::getCreatedTime);
             List<StoreUser> storeUsers = storeUserMapper.selectList(wrapper);
             List<StoreUserExcelVo> storeUserExcelVoList = new ArrayList<>();
@@ -666,19 +754,71 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
             String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", new ArrayList<StoreSubExcelVo>(), StoreSubExcelVo.class);
             return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
         }
+        // 按 (userId, role_id) 去重,与 getStoreUserList 子账号分页一致
+        userRoles = userRoles.stream()
+                .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
+                .collect(Collectors.toMap(
+                        r -> (r.getUserId() != null ? r.getUserId() : 0) + "_" + (r.getRoleId() != null ? r.getRoleId() : ""),
+                        r -> r,
+                        (a, b) -> a
+                ))
+                .values().stream()
+                .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
+                .collect(Collectors.toList());
         List<Integer> distinctUserIds = userRoles.stream().map(StorePlatformUserRole::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
         List<StoreUser> subAccountList = distinctUserIds.isEmpty() ? Collections.emptyList() : storeUserMapper.selectBatchIds(distinctUserIds);
-        Map<Integer, StoreUser> subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream().filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0).collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+        Integer statusInt = null;
+        if (StringUtils.isNotEmpty(status)) {
+            try {
+                statusInt = Integer.parseInt(status.trim());
+            } catch (NumberFormatException ignored) {
+            }
+        }
+        // 与 getStoreUserList 一致:选「注销中/已注销」时只保留对应状态;否则排除注销中、已注销
+        Map<Integer, StoreUser> subAccountMap;
+        if (statusInt != null && (statusInt == -1 || statusInt == 2)) {
+            final int filterStatus = statusInt;
+            subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
+                    .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0)
+                    .filter(u -> {
+                        if (filterStatus == -1) return u.getStatus() != null && u.getStatus() == -1;
+                        return (u.getStatus() != null && u.getStatus() == 2) || (u.getLogoutFlag() != null && u.getLogoutFlag() == 1);
+                    })
+                    .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+        } else {
+            subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
+                    .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0
+                            && (u.getLogoutFlag() == null || u.getLogoutFlag() == 0)
+                            && (u.getStatus() == null || (u.getStatus() != -1 && u.getStatus() != 2)))
+                    .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
+        }
         List<StorePlatformUserRole> filteredRoles = new ArrayList<>();
         for (StorePlatformUserRole role : userRoles) {
             StoreUser subAccount = subAccountMap.get(role.getUserId());
             if (subAccount == null) continue;
-            if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id))) continue;
-            if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone))) continue;
-            if (status != null && !status.equals(subAccount.getStatus())) continue;
+            if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id)))
+                continue;
+            if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone)))
+                continue;
+            int rowStatus;
+            if (statusInt != null && (statusInt == -1 || statusInt == 2)) {
+                rowStatus = (subAccount.getStatus() != null && subAccount.getStatus() == -1) ? -1
+                        : ((subAccount.getStatus() != null && subAccount.getStatus() == 2) || (subAccount.getLogoutFlag() != null && subAccount.getLogoutFlag() == 1)) ? 2
+                        : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
+            } else {
+                rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
+            }
+            if (statusInt != null && !statusInt.equals(rowStatus)) continue;
             filteredRoles.add(role);
         }
-        filteredRoles.sort(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())));
+        // 子账号导出与列表一致:按创建时间从近到远(降序)
+        filteredRoles.sort(Comparator.comparing(
+                (StorePlatformUserRole r) -> {
+                    StoreUser sub = subAccountMap.get(r.getUserId());
+                    return sub != null && sub.getCreatedTime() != null ? sub.getCreatedTime() : new Date(0L);
+                },
+                Comparator.nullsLast(Comparator.reverseOrder())
+        ).thenComparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.reverseOrder())));
         List<Integer> storeIds = filteredRoles.stream().map(StorePlatformUserRole::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
         Map<Integer, StoreUser> mainAccountMap = new HashMap<>();
         if (!storeIds.isEmpty()) {
@@ -692,21 +832,23 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
         for (StorePlatformUserRole role : filteredRoles) {
             StoreUser subAccount = subAccountMap.get(role.getUserId());
             if (subAccount == null) continue;
+            StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
             StoreSubExcelVo vo = new StoreSubExcelVo();
             vo.setSerialNumber(++serialNumber);
-            vo.setId(subAccount.getId());
+            vo.setParentAccountId(mainAccount != null ? mainAccount.getId() : null);
+            vo.setParentAccountPhone(mainAccount != null ? mainAccount.getPhone() : null);
             vo.setPhone(subAccount.getPhone());
             vo.setCreatedTime(subAccount.getCreatedTime() != null ? subAccount.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter) : null);
-            vo.setStatus(subAccount.getStatus() == null ? "" : (subAccount.getStatus() == 0 ? "启用" : "禁用"));
-            StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
-            if (mainAccount != null) {
-                vo.setParentAccountPhone(mainAccount.getPhone());
-            }
+            int rowStatus = (subAccount.getStatus() != null && subAccount.getStatus() == -1) ? -1
+                    : ((subAccount.getStatus() != null && subAccount.getStatus() == 2) || (subAccount.getLogoutFlag() != null && subAccount.getLogoutFlag() == 1)) ? 2
+                    : (role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0));
+            vo.setStatus(rowStatus == -1 ? "注销中" : rowStatus == 2 ? "已注销" : (rowStatus == 0 ? "启用" : "禁用"));
             storeSubExcelVoList.add(vo);
         }
         String fileName = UUID.randomUUID().toString().replace("-", "");
         String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeSubExcelVoList, StoreSubExcelVo.class);
         return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
+
     }
 
 
@@ -932,102 +1074,90 @@ public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser
     }
 
     /**
-     *  删除门店
+     * 删除门店
+     *
      * @param storeUserVo
      */
 
     @Override
-    public void deleteStoreAccountInfo(StoreUserVo storeUserVo) {
-        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(StoreUser::getId, storeUserVo.getId());
-        queryWrapper.eq(StoreUser::getDeleteFlag, 0);
-        StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);
-        // 主账号删除前校验:底下有店铺或有关联子账号则禁止删除
-        if (storeUser != null && storeUser.getAccountType() != null && storeUser.getAccountType() == 1) {
-            if (storeUser.getStoreId() != null) {
-                throw new RuntimeException("该主账号下存在店铺,禁止删除");
-            }
-            List<StoreUser> subAccounts = getSubAccountsByMainAccountId(storeUser.getId());
-            if (subAccounts != null && !subAccounts.isEmpty()) {
-                throw new RuntimeException("该主账号下存在关联子账号,禁止删除");
+    public String deleteStoreAccountInfo(StoreUserVo storeUserVo) {
+        // 解析用户:优先用子账号联系方式 phone 查;未传 phone 时用 id/subAccountId 查 store_user,后端从库中拿到子账号联系方式(phone)
+        StoreUser storeUser = null;
+        if ((storeUserVo.getId() != null || storeUserVo.getSubAccountId() != null)) {
+            Integer idParam = storeUserVo.getSubAccountId() != null ? storeUserVo.getSubAccountId() : storeUserVo.getId();
+            storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>()
+                    .eq(StoreUser::getId, idParam).eq(StoreUser::getDeleteFlag, 0));
+            if (storeUser != null) {
+                log.info("deleteStoreAccountInfo 通过 id 查到用户,后端拿到子账号联系方式: userId={}, phone={}", storeUser.getId(), storeUser.getPhone());
             }
         }
+        if (storeUserVo == null) {
+            log.warn("deleteStoreAccountInfo 用户不存在或已删除,请传子账号联系电话(phone)或用户id");
+            return "删除失败";
+        }
+        // 通过 phone 再尝试解析用户(前端可能只传 phone)
+        if (storeUser == null && storeUserVo.getPhone() != null) {
+            storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>()
+                    .eq(StoreUser::getPhone, storeUserVo.getPhone()).eq(StoreUser::getDeleteFlag, 0));
+        }
         if (storeUser == null) {
-            return;
+            log.warn("deleteStoreAccountInfo 用户不存在或已删除,请传子账号联系电话(phone)或用户id");
+            return "删除失败";
         }
         Integer userId = storeUser.getId();
-        String phone = storeUser.getPhone();
-
-        // 1. 先查询该用户在所有店铺下的子账号数量(未删除的)
-        LambdaQueryWrapper<StorePlatformUserRole> countWrapper = new LambdaQueryWrapper<>();
-        countWrapper.eq(StorePlatformUserRole::getUserId, userId)
-                .eq(StorePlatformUserRole::getDeleteFlag, 0);
-        long subAccountCount = storePlatformUserRoleMapper.selectCount(countWrapper);
-        log.info("用户在所有店铺下的子账号数量: userId={}, count={}", userId, subAccountCount);
-
-        // 2. 逻辑删除 store_platform_user_role 表的记录
-        LambdaUpdateWrapper<StorePlatformUserRole> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(StorePlatformUserRole::getUserId, userId)
-                .eq(StorePlatformUserRole::getDeleteFlag, 0)
-                .set(StorePlatformUserRole::getDeleteFlag, 1);
-        storePlatformUserRoleMapper.update(null, updateWrapper);
-
-        // 删除 token
-        String tokenKey = "store_" + phone;
-        baseRedisService.delete(tokenKey);
-
-        // 3. 如果只是一个账号的子账号(删除前只有1个),则需要进一步判断是否为主账号,再决定是否同时逻辑删除 store_user 表
-        if (subAccountCount == 1) {
-            boolean isMainAccount = storeUser.getStoreId() != null && storeUser.getStoreId() > 0
-                    || (storeUser.getAccountType() != null && storeUser.getAccountType() == 1);
-            if (isMainAccount) {
-                // 主账号:物理删除 store_user 及关联数据(主账号校验已通过,无店铺无子账号)
-                nearMeService.removeGeolocation(Boolean.TRUE, userId.toString());
-                storeUserMapper.deleteById(userId);
-                LambdaQueryWrapper<LifeFans> lifeFansWrapper = new LambdaQueryWrapper<LifeFans>()
-                        .eq(LifeFans::getFollowedId, "store_" + phone)
-                        .or().eq(LifeFans::getFansId, "store_" + phone);
-                lifeFansMapper.delete(lifeFansWrapper);
-                if (storeUser.getStoreId() != null) {
-                    storeInfoMapper.deleteById(storeUser.getStoreId());
-                }
-                lifeUserDynamicsMapper.delete(new LambdaQueryWrapper<LifeUserDynamics>().eq(LifeUserDynamics::getPhoneId, "store_" + phone));
-                lifeNoticeMapper.delete(new LambdaQueryWrapper<LifeNotice>().eq(LifeNotice::getReceiverId, "store_" + phone));
-                lifeMessageMapper.delete(new LambdaQueryWrapper<LifeMessage>().eq(LifeMessage::getSenderId, "store_" + phone));
-                lifeMessageMapper.delete(new LambdaQueryWrapper<LifeMessage>().eq(LifeMessage::getReceiverId, "store_" + phone));
-                log.info("主账号仅1条 platform 记录,已物理删除 store_user 及关联数据: userId={}", userId);
-            } else {
-                // 不是主账号,逻辑删除 store_user
-                LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
-                userUpdateWrapper.eq(StoreUser::getId, userId)
-                        .eq(StoreUser::getDeleteFlag, 0)
-                        .set(StoreUser::getDeleteFlag, 1);
-                int userUpdateResult = storeUserMapper.update(null, userUpdateWrapper);
-                if (userUpdateResult > 0) {
-                    log.info("用户只有一个子账号且不是主账号,已同时逻辑删除 store_user 记录: userId={}", userId);
-                } else {
-                    log.warn("逻辑删除 store_user 记录失败或记录不存在: userId={}", userId);
-                }
-            }
-        } else if (subAccountCount == 0) {
-            // 无 platform 记录,全量物理删除
-            nearMeService.removeGeolocation(Boolean.TRUE, userId.toString());
-            storeUserMapper.deleteById(userId);
-            LambdaQueryWrapper<LifeFans> lifeFansWrapper = new LambdaQueryWrapper<LifeFans>()
-                    .eq(LifeFans::getFollowedId, "store_" + phone)
-                    .or().eq(LifeFans::getFansId, "store_" + phone);
-            lifeFansMapper.delete(lifeFansWrapper);
+
+        // 删除主账号校验:该主账号下有店铺禁止删除、该主账号下有子账号禁止删除(主账号列表返回的 id 即主账号 id)
+        if (storeUserVo.getAccountType() != null && storeUserVo.getAccountType() == 1) {
             if (storeUser.getStoreId() != null) {
-                storeInfoMapper.deleteById(storeUser.getStoreId());
+                log.error("该主账号下存在店铺,禁止删除");
+                return "当前账号下存在店铺 禁止删除";
             }
-            lifeUserDynamicsMapper.delete(new LambdaQueryWrapper<LifeUserDynamics>().eq(LifeUserDynamics::getPhoneId, "store_" + phone));
-            lifeNoticeMapper.delete(new LambdaQueryWrapper<LifeNotice>().eq(LifeNotice::getReceiverId, "store_" + phone));
-            lifeMessageMapper.delete(new LambdaQueryWrapper<LifeMessage>().eq(LifeMessage::getSenderId, "store_" + phone));
-            lifeMessageMapper.delete(new LambdaQueryWrapper<LifeMessage>().eq(LifeMessage::getReceiverId, "store_" + phone));
-            log.info("用户无 platform 记录,已物理删除 store_user 及关联数据: userId={}", userId);
+            Integer mainIdForCheck = storeUserVo.getId();
+            if (mainIdForCheck != null) {
+                List<StoreUser> subAccounts = getSubAccountsByMainAccountId(mainIdForCheck);
+                if (subAccounts != null && !subAccounts.isEmpty()) {
+                    log.error("该主账号下存在关联子账号,禁止删除");
+                    return "当前账号下存在子账号禁止删除";
+                }
+            }
+        }
+
+        // 主账号 id:优先用子账号 store_user.sub_account_id;无则用前端列表返回的 parentAccountId(与分页接口 records 字段一致)
+        Integer mainAccountId = storeUser.getSubAccountId() != null ? storeUser.getSubAccountId() : storeUserVo.getParentAccountId();
+        if (mainAccountId == null) {
+            log.warn("deleteStoreAccountInfo 无法确定主账号,请传 parentAccountId 或保证子账号 store_user.sub_account_id 有值");
+            return "删除失败";
+        }
+        // 查询主账号下的子账号数量(按 store_user 统计:account_type=2 且 sub_account_id=主账号id)
+        List<StoreUser> subAccountsUnderMain = getSubAccountsByMainAccountId(mainAccountId);
+        int subAccountCount = subAccountsUnderMain != null ? subAccountsUnderMain.size() : 0;
+        log.info("主账号下子账号数量: mainAccountId={}, subAccountCount={}", mainAccountId, subAccountCount);
+
+        // 仅删除该主账号对应店铺下的角色:取主账号的 store_id,按 userId + storeId 逻辑删除 store_platform_user_role
+        StoreUser mainAccount = storeUserMapper.selectById(mainAccountId);
+        Integer storeId = mainAccount != null ? mainAccount.getStoreId() : null;
+        LambdaUpdateWrapper<StorePlatformUserRole> roleUpdateWrapper = new LambdaUpdateWrapper<>();
+        roleUpdateWrapper.eq(StorePlatformUserRole::getUserId, userId).eq(StorePlatformUserRole::getDeleteFlag, 0);
+        if (storeId != null) {
+            roleUpdateWrapper.eq(StorePlatformUserRole::getStoreId, storeId);
+        }
+        roleUpdateWrapper.set(StorePlatformUserRole::getDeleteFlag, 1);
+        storePlatformUserRoleMapper.update(null, roleUpdateWrapper);
+
+        // 主账号下子账号唯一:逻辑删除 store_platform_user_role 和 store_user;不唯一:只逻辑删除 store_platform_user_role
+        if (subAccountCount == 1) {
+            LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
+            userUpdateWrapper.eq(StoreUser::getId, userId)
+                    .eq(StoreUser::getDeleteFlag, 0)
+                    .set(StoreUser::getDeleteFlag, 1);
+            storeUserMapper.update(null, userUpdateWrapper);
+            log.info("主账号下子账号唯一,已逻辑删除 store_platform_user_role 和 store_user: userId={}", userId);
+            String tokenKey = "store_" + storeUser.getPhone();
+            baseRedisService.delete(tokenKey);
         } else {
-            log.info("用户有多个子账号(count={}),仅删除 store_platform_user_role 记录,不删除 store_user: userId={}", subAccountCount, userId);
+            log.info("主账号下子账号数不为1,仅逻辑删除 store_platform_user_role,不删 store_user: mainAccountId={}, subAccountCount={}", mainAccountId, subAccountCount);
         }
+        return "删除失败";
     }
 
     @Override

+ 2 - 1
alien-store/src/main/java/shop/alien/store/service/impl/TrackEventServiceImpl.java

@@ -425,7 +425,8 @@ public class TrackEventServiceImpl extends ServiceImpl<StoreTrackEventMapper, St
             wrapper.eq(LifeUserDynamics::getPhoneId, storePhoneId)
                     .eq(LifeUserDynamics::getType, "2") // 商家社区
                     .eq(LifeUserDynamics::getDraft, 0) // 非草稿
-                    .ge(LifeUserDynamics::getCreatedTime, startDate)
+                    // 统计发布动态数量,统计全部而不是当天的数据
+//                    .ge(LifeUserDynamics::getCreatedTime, startDate)
                     .lt(LifeUserDynamics::getCreatedTime, endDate)
                     .eq(LifeUserDynamics::getDeleteFlag, 0);
             return lifeUserDynamicsMapper.selectCount(wrapper);