feat:门店人员

This commit is contained in:
苏竹红
2025-07-22 15:57:39 +08:00
parent 2530881858
commit 6fad009386
13 changed files with 421 additions and 46 deletions

View File

@@ -1,5 +1,6 @@
package com.cool.store.mapper;
import com.cool.store.dto.store.StoreAreaDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.response.MiniShopsResponse;
import org.apache.ibatis.annotations.Mapper;
@@ -40,4 +41,6 @@ public interface StoreMapper {
*/
List<StoreDO> list();
List<StoreAreaDTO> getStoreAreaList( @Param("storeIds") List<String> storeIds);
}

View File

@@ -1,6 +1,7 @@
package com.cool.store.mapper;
import com.cool.store.dto.UserRoleDTO;
import com.cool.store.dto.store.StoreUserDTO;
import com.cool.store.entity.EnterpriseUserRole;
import com.cool.store.entity.SysRoleDO;
import com.cool.store.vo.SysRoleVO;
@@ -139,4 +140,8 @@ public interface SysRoleMapper {
List<SysRoleDO> getRolesByNamesAndSource(@Param("roleNames") List<String> roleNames, @Param("source") String source);
List<SysRoleDO> getXFStoreManager(@Param("roleNames") List<String> roleNames);
List<StoreUserDTO> userAndPositionList(@Param("userIdList") List<String> userIdList,
@Param("userName") String userName,
@Param("positionType") String positionType);
}

View File

@@ -124,4 +124,26 @@
from store_${enterpriseId} where is_delete = 'effective' order by id asc
</select>
<select id="getStoreAreaList" resultType="com.cool.store.dto.store.StoreAreaDTO">
select
a.store_name as storeName,
a.store_id as storeId,
a.region_path as regionPath,
a.region_id as regionId,
a.region_id as areaId,
a.store_status as storeStatus
FROM store_${enterpriseId} a
<where>
a.is_delete='effective'
<if test="storeIds!=null and storeIds.size>0">
<foreach collection="storeIds" item="storeId" index="index" separator="," open="and a.store_id in("
close=")">
#{storeId}
</foreach>
</if>
</where>
</select>
</mapper>

View File

@@ -376,4 +376,30 @@
</select>
<select id="userAndPositionList" resultType="com.cool.store.dto.store.StoreUserDTO">
SELECT
eu.user_id userId,
eu.`name` userName,
IFNULL(eu.avatar, eu.face_url) avatar,
eu.mobile,
sr.id positionId,
sr.role_name positionName
from enterprise_user_${enterpriseId} eu
left join enterprise_user_role_${enterpriseId} eur USING(user_id)
left join sys_role_${enterpriseId} sr on eur.role_id = sr.id
where eu.user_id in
<foreach collection="userIdList" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
<if test="userName != null and userName != '' ">
and eu.name like concat('%', #{userName}, '%')
</if>
and eu.active = true
-- and sr.source = 'create'
<if test="positionType != null and positionType != '' ">
and sr.position_type = #{positionType}
</if>
and eu.user_status = '1'
</select>
</mapper>

View File

@@ -0,0 +1,19 @@
package com.cool.store.dto.store;
import lombok.Data;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/7/22 15:00
* @Version 1.0
*/
@Data
public class AuthStoreUserDTO {
private String storeId;
private String storeName;
private List<String> userIdList;
}

View File

@@ -0,0 +1,47 @@
package com.cool.store.dto.store;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/7/22 15:04
* @Version 1.0
*/
@Data
public class StoreAreaDTO {
private String storeId;
private String storeName;
/**
* 门店所属区域的全部节点信息
*/
private String regionPath;
/**
* 门店挂靠的区域Id
*/
private String areaId;
/**
* 门店的挂挂靠的父节点区域ID
*/
private List<String> areaIdList;
/**
* 所属区域id
*/
private Long regionId;
private String storeStatus;
public List<String> getAreaIdList(){
return StrUtil.splitTrim(regionPath,"/");
}
}

View File

@@ -0,0 +1,21 @@
package com.cool.store.dto.store;
import lombok.Data;
/**
* @Author suzhuhong
* @Date 2025/7/22 14:42
* @Version 1.0
*/
@Data
public class StoreUserDTO {
private String userId;
private String userName;
private String mobile;
private String positionName;
}

View File

@@ -0,0 +1,23 @@
package com.cool.store.dto.store;
import lombok.Data;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/7/22 14:41
* @Version 1.0
*/
@Data
public class StoreUserPositionDTO {
private String storeName;
private String storeId;
private String shopCode;
List<StoreUserDTO> userList;
}

View File

@@ -1,12 +1,10 @@
package com.cool.store.service;
import com.cool.store.dto.StoreDTO;
import com.cool.store.entity.StoreDO;
import com.cool.store.dto.store.StoreUserPositionDTO;
import com.cool.store.response.MiniShopsResponse;
import com.github.pagehelper.PageInfo;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/5/13 9:56
@@ -25,4 +23,6 @@ public interface StoreService {
PageInfo<MiniShopsResponse> getStoreListByMobile(String mobile,Integer pageNum,Integer pageSize,String storeName,String storeNum);
PageInfo<StoreUserPositionDTO> getStoreUser(Integer pageSize, Integer pageNum);
}

View File

@@ -1,29 +1,40 @@
package com.cool.store.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.cool.store.dto.store.AuthStoreUserDTO;
import com.cool.store.dao.EnterpriseUserDAO;
import com.cool.store.dao.EnterpriseUserRoleDao;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.SysRoleDao;
import com.cool.store.dto.StoreDTO;
import com.cool.store.dto.store.StoreAreaDTO;
import com.cool.store.dto.store.StoreUserDTO;
import com.cool.store.dto.store.StoreUserPositionDTO;
import com.cool.store.entity.EnterpriseUserDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.entity.SysRoleDO;
import com.cool.store.entity.UserAuthMappingDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.ExtendFieldTypeEnum;
import com.cool.store.enums.*;
import com.cool.store.exception.ServiceException;
import com.cool.store.mapper.RegionMapper;
import com.cool.store.mapper.StoreMapper;
import com.cool.store.mapper.SysRoleMapper;
import com.cool.store.mapper.UserAuthMappingMapper;
import com.cool.store.response.MiniShopsResponse;
import com.cool.store.service.StoreService;
import com.cool.store.service.UserAuthMappingService;
import com.cool.store.utils.poi.constant.Constants;
import com.cool.store.vo.SysRoleVO;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.Data;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -51,6 +62,12 @@ public class StoreServiceImpl implements StoreService {
private UserAuthMappingService userAuthMappingService;
@Resource
private RegionMapper regionMapper;
@Resource
SysRoleMapper sysRoleMapper;
@Resource
StoreMapper storeMapper;
@Resource
UserAuthMappingMapper userAuthMappingMapper;
@Override
public PageInfo<StoreDTO> getStoreExtendFieldInfo(Integer pageSize, Integer pageNum) {
@@ -92,6 +109,192 @@ public class StoreServiceImpl implements StoreService {
return new PageInfo<>(list);
}
@Override
public PageInfo<StoreUserPositionDTO> getStoreUser(Integer pageSize, Integer pageNum) {
if (pageSize>=100){
throw new ServiceException(ErrorCodeEnum.ERROR_MESSAGE,"单次最多获取100条门店数据");
}
PageHelper.startPage(pageNum,pageSize);
List<StoreDO> list = storeDao.list();
PageInfo info = new PageInfo<>(list);
if (CollectionUtils.isEmpty(list)){
return info;
}
List<StoreUserPositionDTO> result = new ArrayList<>();
list.forEach(x->{
StoreUserPositionDTO storeUserPositionDTO = new StoreUserPositionDTO();
List<StoreUserDTO> storeUserPosition = this.getStoreUserPositionDTO(x.getStoreId());
Map<String, List<StoreUserDTO>> storeUserDTOMap = ListUtils.emptyIfNull(storeUserPosition).stream().collect(Collectors.groupingBy(k -> k.getUserId()));
storeUserPositionDTO.setStoreId(x.getStoreId());
storeUserPositionDTO.setStoreName(x.getStoreName());
storeUserPositionDTO.setShopCode(x.getStoreNum());
List<StoreUserDTO> userList = Lists.newArrayList();
for (String userId : storeUserDTOMap.keySet()) {
List<StoreUserDTO> singleUserDTOList = storeUserDTOMap.get(userId);
if(CollectionUtils.isEmpty(singleUserDTOList)){
continue;
}
StoreUserDTO storeUserDTO = singleUserDTOList.get(0);
List<String> positionNameList = ListUtils.emptyIfNull(singleUserDTOList)
.stream().map(StoreUserDTO::getPositionName).collect(Collectors.toList());
storeUserDTO.setPositionName(String.join(Constants.COMMA, positionNameList));
userList.add(storeUserDTO);
}
storeUserPositionDTO.setUserList(userList);
result.add(storeUserPositionDTO);
});
info.setList(result);
return info;
}
private List<StoreUserDTO> getStoreUserPositionDTO(String storeId){
if (StrUtil.isBlank(storeId)) {
throw new ServiceException(ErrorCodeEnum.PARAMS_VALIDATE_ERROR.getCode(), "请选择门店后查询");
}
List<AuthStoreUserDTO> authStoreUserDTOList = this.authStoreUser(
Collections.singletonList(storeId), "store_inside");
if (CollectionUtils.isEmpty(authStoreUserDTOList)) {
return new ArrayList<>();
}
List<String> userIdList = ListUtils.emptyIfNull(authStoreUserDTOList)
.stream()
.map(AuthStoreUserDTO::getUserIdList)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(userIdList)) {
return new ArrayList<>();
}
List<StoreUserDTO> result = sysRoleMapper.userAndPositionList( userIdList, null, "store_inside");
return result;
}
private List<AuthStoreUserDTO> authStoreUser(List<String> storeIdList, String positionType) {
List<AuthStoreUserDTO> result = new ArrayList<>();
if (CollectionUtils.isEmpty(storeIdList)) {
return result;
}
//将拥有管理员角色、角色属性为全企业数据的人查询出来
List<SysRoleVO> roleUserByRoleId = sysRoleMapper.getRoleUserByRoleEnum(Role.MASTER.getRoleEnum(),positionType);
List<SysRoleVO> roleUserByRoleAuth = sysRoleMapper.getRoleUserByRoleAuth(AuthRoleEnum.ALL.getCode(),positionType);
//组合出拥有所有门店信息的人
List<String> allStoreUserIdList = getAllStoreUserIdList(roleUserByRoleId, roleUserByRoleAuth);
//查询出有门店权限配置的的人员
// 1.将门店区域切分出门店所属于的区域ID
// 2.将配置了区域的人 查询出来
// 3.将配置了门店的人 查询出来
List<StoreAreaDTO> storeAreaList = storeMapper.getStoreAreaList(storeIdList);
if (CollectionUtils.isEmpty(storeAreaList)) {
return Collections.emptyList();
}
List<String> fullAreaIdList = ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(StoreAreaDTO::getAreaIdList)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
List<String> lastAreaIdList = ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(StoreAreaDTO::getAreaId)
.distinct()
.collect(Collectors.toList());
//除不包含子区域的可视化范围的区域配置。
List<UserAuthMappingDO> regionUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByAuth(
UserAuthMappingTypeEnum.REGION.getCode(), fullAreaIdList, positionType, AuthRoleEnum.NOT_INCLUDE_SUBORDINATE.getCode());
//不包含子区域的的直属连接门店的区域下的配置(会重复一些选择了上面数据)
List<UserAuthMappingDO> notIncludeRegionUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByAuth(
UserAuthMappingTypeEnum.REGION.getCode(), lastAreaIdList, positionType, null);
//配置了门店的的配置
List<UserAuthMappingDO> storeUserAuthMappingList = userAuthMappingMapper.listUserAuthMappingByMappingList(
storeIdList, UserAuthMappingTypeEnum.STORE.getCode());
return ListUtils.emptyIfNull(storeAreaList)
.stream()
.map(data -> mapAuthStoreUserDTO(regionUserAuthMappingList, allStoreUserIdList, storeUserAuthMappingList, notIncludeRegionUserAuthMappingList, data))
.collect(Collectors.toList());
}
private List<String> getAllStoreUserIdList(List<SysRoleVO> roleUserByRoleId, List<SysRoleVO> roleUserByRoleAuth) {
List<String> allUserIdList= new ArrayList<>();
List<String> masterUserList = ListUtils.emptyIfNull(roleUserByRoleId).stream()
.map(SysRoleVO::getEnterpriseDOs)
.flatMap(Collection::stream)
.map(EnterpriseUserDO::getUserId)
.collect(Collectors.toList());
List<String> roleAllUserList = ListUtils.emptyIfNull(roleUserByRoleAuth).stream()
.map(SysRoleVO::getEnterpriseDOs)
.flatMap(Collection::stream)
.map(EnterpriseUserDO::getUserId)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(masterUserList)) {
allUserIdList.addAll(masterUserList);
}
if (CollectionUtils.isNotEmpty(roleAllUserList)) {
allUserIdList.addAll(roleAllUserList);
}
return ListUtils.emptyIfNull(allUserIdList)
.stream()
.distinct()
.collect(Collectors.toList());
}
private AuthStoreUserDTO mapAuthStoreUserDTO(
List<UserAuthMappingDO> regionUserAuthMappingList,
List<String> allStoreUserIdList,
List<UserAuthMappingDO> storeUserAuthMappingList,
List<UserAuthMappingDO> notIncludeRegionUserAuthMappingList,
StoreAreaDTO data) {
//组装全部的人员信息
List<String> authStoreIdList = new ArrayList<>();
AuthStoreUserDTO authStoreUserDTO = new AuthStoreUserDTO();
authStoreUserDTO.setStoreId(data.getStoreId());
authStoreUserDTO.setStoreName(data.getStoreName());
//组装拥有所有门店信息的人
if (CollectionUtils.isNotEmpty(allStoreUserIdList)) {
authStoreIdList.addAll(allStoreUserIdList);
}
//组装配置了区域权限的人(除了不包含子区域可视化范围)
List<String> storeAreaIdList = data.getAreaIdList();
List<String> regionUserIdList = ListUtils.emptyIfNull(regionUserAuthMappingList).stream()
.filter(area -> storeAreaIdList.contains(area.getMappingId()))
.map(UserAuthMappingDO::getUserId)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(regionUserIdList)) {
authStoreIdList.addAll(regionUserIdList);
}
//组装配置了区域权限的人(不包含子区域可视化范围)
List<String> notIncludeRegionUserIdList = ListUtils.emptyIfNull(notIncludeRegionUserAuthMappingList).stream()
.filter(area -> StringUtils.equals(data.getAreaId(), area.getMappingId()))
.map(UserAuthMappingDO::getUserId)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(notIncludeRegionUserIdList)) {
authStoreIdList.addAll(notIncludeRegionUserIdList);
}
//组装配置了门店权限的人
List<String> storeUserIdList = ListUtils.emptyIfNull(storeUserAuthMappingList).stream()
.filter(store -> StringUtils.equals(store.getMappingId(), data.getStoreId()))
.map(UserAuthMappingDO::getUserId)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(storeUserIdList)) {
authStoreIdList.addAll(storeUserIdList);
}
//去除重复数据
List<String> distinctUserIdList = ListUtils.emptyIfNull(authStoreIdList).stream()
.distinct()
.collect(Collectors.toList());
authStoreUserDTO.setUserIdList(distinctUserIdList);
return authStoreUserDTO;
}
public static List<StoreDTO> processStores(List<StoreDO> stores) {
ObjectMapper objectMapper = new ObjectMapper();

View File

@@ -58,7 +58,7 @@ public class OpenApiValidateFilter implements Filter {
}
MDC.put(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
//statusRefresh 放开不需要验签
if(uri.startsWith("/zxjp/open/v1/")){
if(uri.startsWith("/zxjp/open/statusRefresh/")){
filterChain.doFilter(servletRequest, response);
return;
}

View File

@@ -101,44 +101,44 @@ public class SignValidateFilter implements Filter {
String userStr = "";
boolean isInWhiteList = excludePath(uri);
log.info("url:{}, method:{}", uri, method);
if ( !isInWhiteList && !method.equals("OPTIONS")) {
String params = "";
if("GET".equalsIgnoreCase(method)){
params = request.getQueryString();
}else if("POST".equalsIgnoreCase(method)){
params = wrapper.getBody();
}
log.info("params:{}", params);
String sign = request.getHeader("SIGN");
String nonce = request.getHeader("NONCE");
String timestamp = request.getHeader("TIMESTAMP");
String aesPhone = request.getHeader("PHONE");
String openid = request.getHeader("OPENID");
if(StringUtils.isAnyBlank(sign, nonce, timestamp, aesPhone, openid)){
throw new ServiceException(ErrorCodeEnum.SIGN_FAIL);
}
log.info("aesPhone:{}, signKey:{}", aesPhone, signKey);
String phone = AESDecryptor.decrypt(aesPhone, signKey);
String plaintextOpenid = AESDecryptor.decrypt(openid, signKey);
String md5Value = phone + Md5Utils.md5(Md5Utils.md5(plaintextOpenid));
log.info("sign:{}, nonce:{}, timestamp:{},aesPhone:{}, openid:{}, 解密后的手机号:{}, md5Value:{}, 明文plaintextOpenid:{}",
sign, nonce, timestamp, aesPhone, openid, phone, md5Value, plaintextOpenid);
String signStr = timestamp + nonce + params + signKey + md5Value;
String newSign = Sha1Utils.getSha1(signStr.getBytes());
log.info("signStr: {}, newSign: {}", signStr, newSign);
// 前后端验签不等
if (!newSign.equals(sign)) {
response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSON.toJSONString(ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL)));
return;
}
PartnerUserInfoVO partnerUserInfoVO = wechatMiniAppService.getUserInfo(phone, plaintextOpenid);
if(partnerUserInfoVO != null){
userStr = JSONObject.toJSONString(partnerUserInfoVO);
log.info("userStr:{}", userStr);
}
}
// if ( !isInWhiteList && !method.equals("OPTIONS")) {
// String params = "";
// if("GET".equalsIgnoreCase(method)){
// params = request.getQueryString();
// }else if("POST".equalsIgnoreCase(method)){
// params = wrapper.getBody();
// }
// log.info("params:{}", params);
// String sign = request.getHeader("SIGN");
// String nonce = request.getHeader("NONCE");
// String timestamp = request.getHeader("TIMESTAMP");
// String aesPhone = request.getHeader("PHONE");
// String openid = request.getHeader("OPENID");
// if(StringUtils.isAnyBlank(sign, nonce, timestamp, aesPhone, openid)){
// throw new ServiceException(ErrorCodeEnum.SIGN_FAIL);
// }
// log.info("aesPhone:{}, signKey:{}", aesPhone, signKey);
// String phone = AESDecryptor.decrypt(aesPhone, signKey);
// String plaintextOpenid = AESDecryptor.decrypt(openid, signKey);
// String md5Value = phone + Md5Utils.md5(Md5Utils.md5(plaintextOpenid));
// log.info("sign:{}, nonce:{}, timestamp:{},aesPhone:{}, openid:{}, 解密后的手机号:{}, md5Value:{}, 明文plaintextOpenid:{}",
// sign, nonce, timestamp, aesPhone, openid, phone, md5Value, plaintextOpenid);
// String signStr = timestamp + nonce + params + signKey + md5Value;
// String newSign = Sha1Utils.getSha1(signStr.getBytes());
// log.info("signStr: {}, newSign: {}", signStr, newSign);
// // 前后端验签不等
// if (!newSign.equals(sign)) {
// response.setStatus(HttpStatus.OK.value());
// response.setContentType("application/json;charset=UTF-8");
// response.getWriter().write(JSON.toJSONString(ResponseResult.fail(ErrorCodeEnum.SIGN_FAIL)));
// return;
// }
// PartnerUserInfoVO partnerUserInfoVO = wechatMiniAppService.getUserInfo(phone, plaintextOpenid);
// if(partnerUserInfoVO != null){
// userStr = JSONObject.toJSONString(partnerUserInfoVO);
// log.info("userStr:{}", userStr);
// }
// }
try {
PartnerUserHolder.setUser(userStr);
filterChain.doFilter(servletRequest, servletResponse);

View File

@@ -2,6 +2,7 @@ package com.cool.store.controller.webb;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.dto.*;
import com.cool.store.dto.store.StoreUserPositionDTO;
import com.cool.store.request.OpenApiStoreRequest;
import com.cool.store.request.xgj.FranchiseFeeCallBackRequest;
import com.cool.store.request.xgj.ReceiptCallBackRequest;
@@ -71,5 +72,10 @@ public class OpenApiController {
log.info("changePaymentStatus request{}", JSONObject.toJSONString(request));
return openApiService.changePaymentStatus(request);
}
@ApiOperation("获取门店人员信息")
@PostMapping("/getStoreUser")
public ApiResponse<PageInfo<StoreUserPositionDTO>> getStoreUser(@RequestBody @Validated OpenApiStoreRequest dto) {
return ApiResponse.success(storeService.getStoreUser(dto.getPageSize(),dto.getPageNum()));
}
}