This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package jnpf.franchisee.consumer;
|
||||
|
||||
import org.springframework.cloud.stream.annotation.Input;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
|
||||
/**
|
||||
* 加盟商消息通道定义
|
||||
*/
|
||||
public interface FranchiseeConsumerSource {
|
||||
/**
|
||||
* 消费通道
|
||||
*/
|
||||
String INPUT = "permission-franchisee-input";
|
||||
|
||||
@Input(INPUT)
|
||||
SubscribableChannel input();
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package jnpf.franchisee.consumer;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import jnpf.base.UserInfo;
|
||||
import jnpf.config.ConfigValueUtil;
|
||||
import jnpf.database.util.TenantDataSourceUtil;
|
||||
import jnpf.exception.LoginException;
|
||||
import jnpf.franchisee.mapper.FranchiseeMapper;
|
||||
import jnpf.message.enums.permission.v2.OperationTypeMessageEnums;
|
||||
import jnpf.message.enums.permission.v2.OrganizeCategoryMessageEnums;
|
||||
import jnpf.message.model.permission.v2.OrganizeUpdateMessageDTO;
|
||||
import jnpf.model.franchisee.po.FranchiseeEntity;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.StreamListener;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 加盟商门店数量写扩散消费者
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@EnableBinding(FranchiseeConsumerSource.class)
|
||||
public class FranchiseeStoreNumConsumer {
|
||||
|
||||
private static final String IDEMPOTENT_KEY_PREFIX = "franchisee:storeNum:consume";
|
||||
private static final String IDEMPOTENT_VALUE = "1";
|
||||
private static final long IDEMPOTENT_EXPIRE_DAYS = 1L;
|
||||
|
||||
@Resource
|
||||
private FranchiseeMapper franchiseeMapper;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ConfigValueUtil configValueUtil;
|
||||
|
||||
/**
|
||||
* 监听组织消息中的门店更新事件,执行加盟商门店数量写扩散。
|
||||
* <p>
|
||||
* 幂等与并发控制在上层消费入口处理:使用消息头 ROCKET_KEYS 作为 setnx 键,过期时间 1 天。
|
||||
* 如果缓存过期后发生重复消费导致数量偏差,会在“查询加盟商门店数量接口”按门店表实时修正。
|
||||
*
|
||||
* @param message 消息体
|
||||
*/
|
||||
@StreamListener(target = FranchiseeConsumerSource.INPUT, condition = "headers['ROCKET_TAGS'] == 'TAG_ORGANIZE'")
|
||||
public void receiveStoreFranchiseeChange(Message<String> message) {
|
||||
String payload = message.getPayload();
|
||||
if (StrUtil.isBlank(payload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeaders headers = message.getHeaders();
|
||||
String rocketKeys = headers.get("ROCKET_KEYS", String.class);
|
||||
if (StrUtil.isBlank(rocketKeys)) {
|
||||
log.warn("加盟商门店数量写扩散消息缺少ROCKET_KEYS,跳过处理。payload={}", payload);
|
||||
return;
|
||||
}
|
||||
|
||||
String idempotentKey = IDEMPOTENT_KEY_PREFIX + ":" + rocketKeys;
|
||||
Boolean firstConsume = stringRedisTemplate.opsForValue()
|
||||
.setIfAbsent(idempotentKey, IDEMPOTENT_VALUE, IDEMPOTENT_EXPIRE_DAYS, TimeUnit.DAYS);
|
||||
if (!Boolean.TRUE.equals(firstConsume)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<OrganizeUpdateMessageDTO> messageList;
|
||||
try {
|
||||
messageList = JSONUtil.toList(JSONUtil.parseArray(payload), OrganizeUpdateMessageDTO.class);
|
||||
} catch (Exception e) {
|
||||
log.error("加盟商门店数量写扩散消息解析失败,payload={}", payload, e);
|
||||
return;
|
||||
}
|
||||
if (CollUtil.isEmpty(messageList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (OrganizeUpdateMessageDTO item : messageList) {
|
||||
try {
|
||||
processStoreUpdate(item);
|
||||
} catch (Exception e) {
|
||||
log.error("处理加盟商门店数量写扩散消息失败,item={}", JSONUtil.toJsonStr(item), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单条门店更新消息
|
||||
*
|
||||
* @param item 消息项
|
||||
*/
|
||||
private void processStoreUpdate(OrganizeUpdateMessageDTO item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (!OrganizeCategoryMessageEnums.STORE.equals(item.getOrganizeCategoryEnum())) {
|
||||
return;
|
||||
}
|
||||
log.error("处理加盟商门店数量写扩散消息,item={}", JSONUtil.toJsonStr(item));
|
||||
OperationTypeMessageEnums operationType = item.getOperationTypeEnum();
|
||||
if (operationType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String tenantId = StrUtil.trim(item.getTenantId());
|
||||
if (StrUtil.isBlank(tenantId)) {
|
||||
return;
|
||||
}
|
||||
String oldFranchiseeId = StrUtil.trim(item.getOldFranchiseeId());
|
||||
JSONObject jsonObject = parseJsonEntity(item.getJsonEntity());
|
||||
String newFranchiseeId = jsonObject.getStr("franchiseeId");
|
||||
Date lastModifyTime = jsonObject.getDate("lastModifyTime");//使用门店表修改时间,作为事件水位线。
|
||||
if(Objects.isNull(lastModifyTime)){
|
||||
log.error("processStoreUpdate lastModifyTime is null.item:{}",JSONUtil.toJsonStr(item));
|
||||
return;
|
||||
}
|
||||
long updateStoreNumTimestamp = lastModifyTime.getTime();
|
||||
if (OperationTypeMessageEnums.ADD.equals(operationType)) {
|
||||
if (StrUtil.isBlank(newFranchiseeId)) {
|
||||
return;
|
||||
}
|
||||
switchTenant(tenantId);
|
||||
updateStoreNum(newFranchiseeId, updateStoreNumTimestamp,1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (OperationTypeMessageEnums.DELETE.equals(operationType)) {
|
||||
String deleteFranchiseeId = StrUtil.isNotBlank(oldFranchiseeId) ? oldFranchiseeId : newFranchiseeId;
|
||||
if (StrUtil.isBlank(deleteFranchiseeId)) {
|
||||
return;
|
||||
}
|
||||
switchTenant(tenantId);
|
||||
updateStoreNum(deleteFranchiseeId, updateStoreNumTimestamp,-1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (OperationTypeMessageEnums.UPDATE.equals(operationType)) {
|
||||
if (StrUtil.equals(oldFranchiseeId, newFranchiseeId)) {
|
||||
return;
|
||||
}
|
||||
switchTenant(tenantId);
|
||||
if (StrUtil.isNotBlank(newFranchiseeId)) {
|
||||
updateStoreNum(newFranchiseeId, updateStoreNumTimestamp,1);
|
||||
}
|
||||
if (StrUtil.isNotBlank(oldFranchiseeId)) {
|
||||
updateStoreNum(oldFranchiseeId, updateStoreNumTimestamp,-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析消息中的新加盟商ID
|
||||
*
|
||||
* @param jsonEntity 门店JSON实体
|
||||
* @return 新加盟商ID
|
||||
*/
|
||||
private String parseNewFranchiseeId(String jsonEntity) {
|
||||
if (StrUtil.isBlank(jsonEntity) || !JSONUtil.isTypeJSONObject(jsonEntity)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JSONObject jsonObject = JSONUtil.parseObj(jsonEntity);
|
||||
return StrUtil.trim(jsonObject.getStr("franchiseeId"));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject parseJsonEntity(String jsonEntity) {
|
||||
if (StrUtil.isBlank(jsonEntity) || !JSONUtil.isTypeJSONObject(jsonEntity)) {
|
||||
return new JSONObject();
|
||||
}
|
||||
try {
|
||||
return JSONUtil.parseObj(jsonEntity);
|
||||
} catch (Exception e) {
|
||||
return new JSONObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写扩散更新加盟商门店数量
|
||||
*
|
||||
* @param franchiseeId 加盟商ID
|
||||
* @param updateStoreNumTimestamp 更新水位
|
||||
* @param delta 变更值(+1 或 -1)
|
||||
*/
|
||||
private void updateStoreNum(String franchiseeId,long updateStoreNumTimestamp, int delta) {
|
||||
if (StrUtil.isBlank(franchiseeId) || delta == 0) {
|
||||
return;
|
||||
}
|
||||
LambdaUpdateWrapper<FranchiseeEntity> updateWrapper = Wrappers.lambdaUpdate();
|
||||
updateWrapper.eq(FranchiseeEntity::getId, franchiseeId);
|
||||
updateWrapper.eq(FranchiseeEntity::getEnabledMark, 0);
|
||||
updateWrapper.lt(FranchiseeEntity::getUpdateStoreNumTimestamp, updateStoreNumTimestamp);//作为事件水位线。
|
||||
if (delta > 0) {
|
||||
updateWrapper.setSql("F_StoreNum = IFNULL(F_StoreNum, 0) + " + delta);
|
||||
} else {
|
||||
int abs = Math.abs(delta);
|
||||
updateWrapper.setSql("F_StoreNum = CASE WHEN IFNULL(F_StoreNum, 0) >= "
|
||||
+ abs + " THEN IFNULL(F_StoreNum, 0) - " + abs + " ELSE 0 END");
|
||||
}
|
||||
franchiseeMapper.update(null, updateWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换租户数据源
|
||||
*
|
||||
* @param tenantId 租户ID
|
||||
*/
|
||||
private void switchTenant(String tenantId) {
|
||||
// 判断是否为多租户
|
||||
if (!configValueUtil.isMultiTenancy()) {
|
||||
log.info("加盟商门店数量写扩散消息,配置为非多租户,跳过处理。tenantId={}", tenantId);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
TenantDataSourceUtil.switchTenant(tenantId);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("切换租户失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package jnpf.franchisee.controller;
|
||||
|
||||
import jnpf.franchisee.FranchiseeApi;
|
||||
import jnpf.franchisee.service.FranchiseeService;
|
||||
import jnpf.model.franchisee.vo.FranchiseeIdName;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/web/franchise-api")
|
||||
public class FranchiseeApiController implements FranchiseeApi {
|
||||
|
||||
@Autowired
|
||||
private FranchiseeService franchiseeService;
|
||||
|
||||
/**
|
||||
* 获取所有加盟商信息
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
@GetMapping("/getFranchiseeIdNameList")
|
||||
public List<FranchiseeIdName> getFranchiseeIdNameList() {
|
||||
return franchiseeService.queryIdListByPrefix(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID列表获取加盟商信息
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<FranchiseeIdName> getFranchiseeIdNameListByIds(Collection<String> ids) {
|
||||
return franchiseeService.getFranchiseeIdNameListByIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取加盟商信息
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public FranchiseeIdName getFranchiseeIdNameListById(String id) {
|
||||
return franchiseeService.getFranchiseeIdNameListById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取加盟商信息
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<FranchiseeIdName> getFranchiseeIdNameListByName(String name) {
|
||||
return franchiseeService.getFranchiseeIdNameListByName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称列表获取加盟商信息
|
||||
* @param names
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<FranchiseeIdName> getFranchiseeIdNameListByNames(Collection<String> names) {
|
||||
return franchiseeService.getFranchiseeIdNameListByNames(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FranchiseeIdName getFranchiseeIdNameListByCode(String code) {
|
||||
return franchiseeService.getFranchiseeIdNameListByCode(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FranchiseeIdName> getFranchiseeIdNameListByCodes(Collection<String> codes) {
|
||||
return franchiseeService.getFranchiseeIdNameListByCodes(codes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package jnpf.franchisee.controller.app;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import jnpf.base.ActionResult;
|
||||
import jnpf.base.vo.PageListVO;
|
||||
import jnpf.franchisee.service.FranchiseeService;
|
||||
import jnpf.model.franchisee.req.FranchiseeAddReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeQueryReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeSimpleAddReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeUpdateReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeIdName;
|
||||
import jnpf.model.franchisee.vo.FranchiseePageVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeStoreVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeVO;
|
||||
import jnpf.parameter.service.ParamService;
|
||||
import jnpf.util.FtbUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* APP加盟商控制器
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping("/app/franchisee")
|
||||
public class FranchiseeAppController {
|
||||
|
||||
private static final String FRANCHISEE_CODE_PREFIX = "JSM";
|
||||
private static final String FRANCHISEE_CODE_SEQ_KEY = "franchiseeCodeSeq";
|
||||
private static final DateTimeFormatter FRANCHISEE_CODE_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
@Autowired
|
||||
private FranchiseeService franchiseeService;
|
||||
@Autowired
|
||||
private ParamService paramService;
|
||||
|
||||
/**
|
||||
* 简单新增加盟商
|
||||
*
|
||||
* @param req 简单新增请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/simple-add")
|
||||
public ActionResult<Void> simpleAdd(@Validated @RequestBody FranchiseeSimpleAddReq req) {
|
||||
franchiseeService.add(req.convert());
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动生成加盟商编码
|
||||
*
|
||||
* 规则:JSM + yyyyMMdd + 递增序号。
|
||||
* 递增序号通过固定key在数据库中维护,不按天重置。
|
||||
*
|
||||
* @return 加盟商编码
|
||||
*/
|
||||
@GetMapping("/generate-code")
|
||||
public ActionResult<String> generateCode() {
|
||||
return ActionResult.success("success",franchiseeService.generateCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增加盟商
|
||||
*
|
||||
* @param req 新增请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public ActionResult<Void> add(@Validated @RequestBody FranchiseeAddReq req) {
|
||||
franchiseeService.add(req);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑加盟商
|
||||
*
|
||||
* @param req 编辑请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public ActionResult<Void> update(@Validated @RequestBody FranchiseeUpdateReq req) {
|
||||
franchiseeService.update(req);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除加盟商
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ActionResult<Void> delete(@PathVariable("id") @NotBlank(message = "主键ID不能为空") String id) {
|
||||
franchiseeService.delete(id);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询加盟商详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 加盟商详情
|
||||
*/
|
||||
@GetMapping("/query-info/{id}")
|
||||
public ActionResult<FranchiseeVO> queryInfo(@PathVariable("id") @NotBlank(message = "主键ID不能为空") String id) {
|
||||
return ActionResult.success(franchiseeService.queryInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询加盟商列表
|
||||
*
|
||||
* @param req 查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
@GetMapping("/query-page")
|
||||
public ActionResult<PageListVO<FranchiseePageVO>> queryPage(@Valid FranchiseeQueryReq req) {
|
||||
PageInfo<FranchiseePageVO> pageInfo = franchiseeService.queryPage(req,true);
|
||||
return ActionResult.page(pageInfo.getList(), FtbUtil.getPagination(pageInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关键字查询加盟商ID列表(模糊匹配加盟商名称)
|
||||
*
|
||||
* @param keyword 关键字(加盟商名称)
|
||||
* @return 加盟商ID列表
|
||||
*/
|
||||
@GetMapping("/query-id-list")
|
||||
public ActionResult<List<FranchiseeIdName>> queryIdListByPrefix(@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
return ActionResult.success(franchiseeService.queryIdListByPrefix(keyword));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据加盟商ID查询其下门店列表
|
||||
*
|
||||
* @param franchiseeId 加盟商ID
|
||||
* @return 门店列表
|
||||
*/
|
||||
@GetMapping("/query-store-list/{franchiseeId}")
|
||||
public ActionResult<List<FranchiseeStoreVO>> queryStoreList(@PathVariable("franchiseeId") @NotBlank(message = "加盟商ID不能为空") String franchiseeId) {
|
||||
return ActionResult.success(franchiseeService.queryStoreList(franchiseeId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package jnpf.franchisee.controller.web;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import jnpf.base.ActionResult;
|
||||
import jnpf.base.vo.PageListVO;
|
||||
import jnpf.franchisee.service.FranchiseeService;
|
||||
import jnpf.model.franchisee.req.FranchiseeAddReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeQueryReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeSimpleAddReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeUpdateReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeIdName;
|
||||
import jnpf.model.franchisee.vo.FranchiseePageVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeStoreVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeVO;
|
||||
import jnpf.util.FtbUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Web加盟商控制器
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping("/web/franchisee")
|
||||
public class FranchiseeController {
|
||||
|
||||
@Autowired
|
||||
private FranchiseeService franchiseeService;
|
||||
|
||||
/**
|
||||
* 简单新增加盟商
|
||||
*
|
||||
* @param req 简单新增请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/simple-add")
|
||||
public ActionResult<Void> simpleAdd(@Validated @RequestBody FranchiseeSimpleAddReq req) {
|
||||
franchiseeService.add(req.convert());
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动生成加盟商编码
|
||||
*
|
||||
* 规则:JMS + yyyyMMdd + 递增序号。
|
||||
* 递增序号通过固定key在数据库中维护,不按天重置。
|
||||
*
|
||||
* @return 加盟商编码
|
||||
*/
|
||||
@GetMapping("/generate-code")
|
||||
public ActionResult<String> generateCode() {
|
||||
return ActionResult.success("succeed",franchiseeService.generateCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增加盟商
|
||||
*
|
||||
* @param req 新增请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public ActionResult<Void> add(@Validated @RequestBody FranchiseeAddReq req) {
|
||||
franchiseeService.add(req);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑加盟商
|
||||
*
|
||||
* @param req 编辑请求参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public ActionResult<Void> update(@Validated @RequestBody FranchiseeUpdateReq req) {
|
||||
franchiseeService.update(req);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除加盟商
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/delete/{id}")
|
||||
public ActionResult<Void> delete(@PathVariable("id") @NotBlank(message = "主键ID不能为空") String id) {
|
||||
franchiseeService.delete(id);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询加盟商详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 加盟商详情
|
||||
*/
|
||||
@GetMapping("/query-info/{id}")
|
||||
public ActionResult<FranchiseeVO> queryInfo(@PathVariable("id") @NotBlank(message = "主键ID不能为空") String id) {
|
||||
return ActionResult.success(franchiseeService.queryInfo(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询加盟商列表
|
||||
*
|
||||
* @param req 查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
@GetMapping("/query-page")
|
||||
public ActionResult<PageListVO<FranchiseePageVO>> queryPage(@Valid FranchiseeQueryReq req) {
|
||||
PageInfo<FranchiseePageVO> pageInfo = franchiseeService.queryPage(req,false);
|
||||
return ActionResult.page(pageInfo.getList(), FtbUtil.getPagination(pageInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关键字查询加盟商ID列表(模糊匹配加盟商名称)
|
||||
*
|
||||
* @param keyword 关键字(加盟商名称)
|
||||
* @return 加盟商ID列表
|
||||
*/
|
||||
@GetMapping("/query-id-list")
|
||||
public ActionResult<List<FranchiseeIdName>> queryIdListByPrefix(@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
return ActionResult.success(franchiseeService.queryIdListByPrefix(keyword));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据加盟商ID查询其下门店列表
|
||||
*
|
||||
* @param franchiseeId 加盟商ID
|
||||
* @return 门店列表
|
||||
*/
|
||||
@GetMapping("/query-store-list/{franchiseeId}")
|
||||
public ActionResult<List<FranchiseeStoreVO>> queryStoreList(@PathVariable("franchiseeId") @NotBlank(message = "加盟商ID不能为空") String franchiseeId) {
|
||||
return ActionResult.success(franchiseeService.queryStoreList(franchiseeId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package jnpf.franchisee.controller.web;
|
||||
|
||||
import jnpf.base.ActionResult;
|
||||
import jnpf.franchisee.service.FranchiseeCustomFieldConfigService;
|
||||
import jnpf.model.franchisee.req.FranchiseeCustomFieldConfigReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeCustomNameUpdateReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeCustomFieldConfigVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* web加盟商自定义字段配置控制器
|
||||
*/
|
||||
@RestController
|
||||
@Validated
|
||||
@RequestMapping("/web/franchisee/custom-field-config")
|
||||
public class FranchiseeCustomFieldConfigController {
|
||||
|
||||
@Autowired
|
||||
private FranchiseeCustomFieldConfigService franchiseeCustomFieldConfigService;
|
||||
|
||||
/**
|
||||
* 新增自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public ActionResult<String> add(@Validated @RequestBody FranchiseeCustomFieldConfigReq req) {
|
||||
return ActionResult.success("succeed",franchiseeCustomFieldConfigService.add(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
@PutMapping("/update")
|
||||
public ActionResult<String> update(@Validated @RequestBody FranchiseeCustomFieldConfigReq req) {
|
||||
return ActionResult.success("succeed",franchiseeCustomFieldConfigService.update(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有自定义字段配置
|
||||
*
|
||||
* @return 配置列表
|
||||
*/
|
||||
@GetMapping("/query-list")
|
||||
public ActionResult<List<FranchiseeCustomFieldConfigVO>> queryList() {
|
||||
return ActionResult.success(franchiseeCustomFieldConfigService.queryList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询自定义字段配置详情
|
||||
*
|
||||
* @return 配置列表
|
||||
*/
|
||||
@GetMapping("/query")
|
||||
public ActionResult<FranchiseeCustomFieldConfigVO> query(@RequestParam("key") String key) {
|
||||
return ActionResult.success(franchiseeCustomFieldConfigService.query(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询自定义名称
|
||||
*
|
||||
* @return 自定义名称
|
||||
*/
|
||||
@GetMapping("/query-custom-name")
|
||||
public ActionResult<String> queryCustomName() {
|
||||
return ActionResult.success("succeed",franchiseeCustomFieldConfigService.queryCustomName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新自定义名称
|
||||
*
|
||||
* @param req 更新请求参数
|
||||
* @return 更新后的自定义名称
|
||||
*/
|
||||
@PutMapping("/update-custom-name")
|
||||
public ActionResult<String> updateCustomName(@Validated @RequestBody FranchiseeCustomNameUpdateReq req) {
|
||||
return ActionResult.success("succeed",franchiseeCustomFieldConfigService.updateCustomName(req.getCustomName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自定义字段配置
|
||||
*
|
||||
* @param key 配置key
|
||||
* @return 操作结果
|
||||
*/
|
||||
@DeleteMapping("/delete/{key}")
|
||||
public ActionResult<Void> delete(@PathVariable("key") @NotBlank(message = "key不能为空") String key) {
|
||||
franchiseeCustomFieldConfigService.delete(key);
|
||||
return ActionResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整自定义字段排序
|
||||
*
|
||||
* @param key 按目标顺序传入的字段key列表
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PutMapping("/adjust-sort")
|
||||
public ActionResult<Void> adjustSort(@RequestBody List<String> key) {
|
||||
franchiseeCustomFieldConfigService.adjustSort(key);
|
||||
return ActionResult.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package jnpf.franchisee.mapper;
|
||||
|
||||
import jnpf.base.mapper.SuperMapper;
|
||||
import jnpf.model.franchisee.po.FranchiseeCustomFieldEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商自定义字段值Mapper
|
||||
*/
|
||||
public interface FranchiseeCustomFieldMapper extends SuperMapper<FranchiseeCustomFieldEntity> {
|
||||
/**
|
||||
* 批量插入
|
||||
*
|
||||
* @param entities 实体列表
|
||||
* @return 插入的数量
|
||||
*/
|
||||
int batchInsert(@Param("entities") List<FranchiseeCustomFieldEntity> entities);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package jnpf.franchisee.mapper;
|
||||
|
||||
import jnpf.base.mapper.SuperMapper;
|
||||
import jnpf.model.franchisee.po.FranchiseeExperienceEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商从业经历Mapper
|
||||
*/
|
||||
public interface FranchiseeExperienceMapper extends SuperMapper<FranchiseeExperienceEntity> {
|
||||
/**
|
||||
* 批量插入
|
||||
*
|
||||
* @param entities
|
||||
* @return 插入的数量
|
||||
*/
|
||||
int batchInsert(@Param("entities") List<FranchiseeExperienceEntity> entities);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package jnpf.franchisee.mapper;
|
||||
|
||||
import jnpf.base.mapper.SuperMapper;
|
||||
import jnpf.model.franchisee.po.FranchiseeJoinRegionEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商加盟地区冗余表Mapper
|
||||
*/
|
||||
public interface FranchiseeJoinRegionMapper extends SuperMapper<FranchiseeJoinRegionEntity> {
|
||||
/**
|
||||
* 批量插入
|
||||
*
|
||||
* @param entities 实体列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
int batchInsert(@Param("entities") List<FranchiseeJoinRegionEntity> entities);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package jnpf.franchisee.mapper;
|
||||
|
||||
import jnpf.base.mapper.SuperMapper;
|
||||
import jnpf.model.franchisee.po.FranchiseeEntity;
|
||||
import jnpf.model.franchisee.req.FranchiseeJoinRegionReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeQueryReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseePageVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商主表 Mapper
|
||||
*/
|
||||
public interface FranchiseeMapper extends SuperMapper<FranchiseeEntity> {
|
||||
|
||||
/**
|
||||
* 分页查询加盟商列表
|
||||
*
|
||||
* @param req 查询参数
|
||||
* @param provinceCityJoinRegion 区为空时的省市集合
|
||||
* @param provinceList 市为空时的省集合
|
||||
* @return 列表数据
|
||||
*/
|
||||
List<FranchiseePageVO> queryPageList(@Param("req") FranchiseeQueryReq req,
|
||||
@Param("provinceCityJoinRegion") List<FranchiseeJoinRegionReq> provinceCityJoinRegion,
|
||||
@Param("provinceList") List<String> provinceList);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package jnpf.franchisee.mapper;
|
||||
|
||||
import jnpf.base.mapper.SuperMapper;
|
||||
import jnpf.permission.entity.StoreEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 加盟商门店Mapper。
|
||||
*/
|
||||
public interface FranchiseeStoreMapper extends SuperMapper<StoreEntity> {
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package jnpf.franchisee.service;
|
||||
|
||||
import jnpf.model.franchisee.req.FranchiseeCustomFieldConfigReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeCustomFieldConfigVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商自定义字段配置服务
|
||||
*/
|
||||
public interface FranchiseeCustomFieldConfigService {
|
||||
|
||||
/**
|
||||
* 新增自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
String add(FranchiseeCustomFieldConfigReq req);
|
||||
|
||||
/**
|
||||
* 更新自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
String update(FranchiseeCustomFieldConfigReq req);
|
||||
|
||||
/**
|
||||
* 查询所有自定义字段配置
|
||||
*
|
||||
* @return 配置列表
|
||||
*/
|
||||
List<FranchiseeCustomFieldConfigVO> queryList();
|
||||
|
||||
/**
|
||||
* 查询自定义字段配置详情
|
||||
*
|
||||
* @return 配置
|
||||
*/
|
||||
FranchiseeCustomFieldConfigVO query(String key);
|
||||
|
||||
/**
|
||||
* 删除自定义字段配置
|
||||
*
|
||||
* @param key 配置key
|
||||
*/
|
||||
void delete(String key);
|
||||
|
||||
/**
|
||||
* 调整自定义字段排序
|
||||
*
|
||||
* @param key 按目标顺序传入的字段key列表
|
||||
*/
|
||||
void adjustSort(List<String> key);
|
||||
|
||||
/**
|
||||
* 查询自定义名称。
|
||||
*
|
||||
* @return 自定义名称
|
||||
*/
|
||||
String queryCustomName();
|
||||
|
||||
/**
|
||||
* 更新自定义名称。
|
||||
*
|
||||
* @param customName 自定义名称
|
||||
* @return 更新后的自定义名称
|
||||
*/
|
||||
String updateCustomName(String customName);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package jnpf.franchisee.service;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import jnpf.model.franchisee.po.FranchiseeEntity;
|
||||
import jnpf.model.franchisee.req.FranchiseeAddReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeQueryReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeUpdateReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeIdName;
|
||||
import jnpf.model.franchisee.vo.FranchiseePageVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeStoreVO;
|
||||
import jnpf.permission.vo.store.StoreInfoDetailVO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 加盟商服务
|
||||
*/
|
||||
public interface FranchiseeService extends IService<FranchiseeEntity> {
|
||||
|
||||
/**
|
||||
* 新增加盟商
|
||||
*
|
||||
* @param req 新增请求参数
|
||||
*/
|
||||
void add(FranchiseeAddReq req);
|
||||
|
||||
/**
|
||||
* 编辑加盟商
|
||||
*
|
||||
* @param req 编辑请求参数
|
||||
*/
|
||||
void update(FranchiseeUpdateReq req);
|
||||
|
||||
/**
|
||||
* 删除加盟商
|
||||
*
|
||||
* @param id 主键ID
|
||||
*/
|
||||
void delete(String id);
|
||||
|
||||
/**
|
||||
* 查询加盟商详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 加盟商详情
|
||||
*/
|
||||
FranchiseeVO queryInfo(String id);
|
||||
|
||||
/**
|
||||
* 分页查询加盟商列表
|
||||
*
|
||||
* @param req 查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageInfo<FranchiseePageVO> queryPage(FranchiseeQueryReq req,boolean includeJoinRegion);
|
||||
|
||||
/**
|
||||
* 根据关键字查询加盟商ID列表(模糊匹配加盟商编码/名称/手机号)
|
||||
*
|
||||
* @param keyword 关键字(加盟商编码/加盟商名称/手机号)
|
||||
* @return 加盟商ID,Name列表
|
||||
*/
|
||||
List<FranchiseeIdName> queryIdListByPrefix(String keyword);
|
||||
|
||||
/**
|
||||
* 根据加盟商ID查询其下门店列表。
|
||||
*
|
||||
* @param franchiseeId 加盟商ID
|
||||
* @return 门店列表
|
||||
*/
|
||||
List<FranchiseeStoreVO> queryStoreList(String franchiseeId);
|
||||
|
||||
/**
|
||||
* 查询加盟商门店数量,并修正加盟商门店数量。返回查询到的门店信息
|
||||
* @param franchiseeId
|
||||
* @return
|
||||
*/
|
||||
List<StoreInfoDetailVO> queryFranchiseeStoreNumAndUpdate(String franchiseeId);
|
||||
|
||||
/**
|
||||
* 生成加盟商编码
|
||||
*
|
||||
* @return 加盟商编码
|
||||
*/
|
||||
String generateCode();
|
||||
|
||||
/**
|
||||
* 根据ID列表获取加盟商信息
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
List<FranchiseeIdName> getFranchiseeIdNameListByIds(Collection<String> ids);
|
||||
|
||||
/**
|
||||
* 根据ID获取加盟商信息
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
default FranchiseeIdName getFranchiseeIdNameListById(String id){
|
||||
List<FranchiseeIdName> franchiseeIdNames = getFranchiseeIdNameListByIds(List.of(id));
|
||||
if(CollectionUtil.isEmpty(franchiseeIdNames)){
|
||||
return null;
|
||||
}
|
||||
return franchiseeIdNames.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取加盟商信息
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
default List<FranchiseeIdName> getFranchiseeIdNameListByName(String name){
|
||||
return getFranchiseeIdNameListByNames(List.of(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称列表获取加盟商信息
|
||||
* @param names
|
||||
* @return
|
||||
*/
|
||||
List<FranchiseeIdName> getFranchiseeIdNameListByNames(Collection<String> names);
|
||||
|
||||
/**
|
||||
* 根据编码获取加盟商信息
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
default FranchiseeIdName getFranchiseeIdNameListByCode(String code){
|
||||
List<FranchiseeIdName> franchiseeIdNames = getFranchiseeIdNameListByCodes(List.of(code));
|
||||
if(CollectionUtil.isEmpty(franchiseeIdNames)){
|
||||
return null;
|
||||
}
|
||||
return franchiseeIdNames.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码列表获取加盟商信息
|
||||
* @param codes
|
||||
* @return
|
||||
*/
|
||||
List<FranchiseeIdName> getFranchiseeIdNameListByCodes(Collection<String> codes);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
package jnpf.franchisee.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import jnpf.franchisee.service.FranchiseeCustomFieldConfigService;
|
||||
import jnpf.model.franchisee.enums.FranchiseeCustomFieldTypeEnum;
|
||||
import jnpf.model.franchisee.req.FranchiseeCustomFieldConfigOptionReq;
|
||||
import jnpf.model.franchisee.req.FranchiseeCustomFieldConfigReq;
|
||||
import jnpf.model.franchisee.vo.FranchiseeCustomFieldConfigOptionVO;
|
||||
import jnpf.model.franchisee.vo.FranchiseeCustomFieldConfigVO;
|
||||
import jnpf.model.warningnotice.po.FtbParamEntity;
|
||||
import jnpf.storecertificatephoto.mapper.BaseParamMapper;
|
||||
import jnpf.util.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 加盟商自定义字段配置服务实现
|
||||
*/
|
||||
@Service
|
||||
public class FranchiseeCustomFieldConfigServiceImpl implements FranchiseeCustomFieldConfigService {
|
||||
|
||||
/**
|
||||
* 自定义字段配置类型
|
||||
*/
|
||||
private static final String customerFieldType = "customerFieldType";
|
||||
/**
|
||||
* 自定义名称配置:固定key,同时type也固定为该值。
|
||||
*/
|
||||
private static final String customerNameType = "franchiseeCustomerNameType";
|
||||
private static final String lockPrefix = "franchisee:customer:field:";
|
||||
|
||||
@Autowired
|
||||
private BaseParamMapper baseParamMapper;
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
/**
|
||||
* 新增自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String add(FranchiseeCustomFieldConfigReq req) {
|
||||
return saveOrUpdate(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新自定义字段配置
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String update(FranchiseeCustomFieldConfigReq req) {
|
||||
String key = req.getKey();
|
||||
if(StringUtil.isBlank(key)){
|
||||
throw new ServiceException("key不能为空");
|
||||
}
|
||||
return saveOrUpdate(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有自定义字段配置
|
||||
*
|
||||
* @return 配置列表
|
||||
*/
|
||||
@Override
|
||||
public List<FranchiseeCustomFieldConfigVO> queryList() {
|
||||
LambdaQueryWrapper<FtbParamEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(FtbParamEntity::getType, customerFieldType);
|
||||
queryWrapper.orderByAsc(FtbParamEntity::getSort);
|
||||
List<FtbParamEntity> entityList = baseParamMapper.selectList(queryWrapper);
|
||||
if (CollUtil.isEmpty(entityList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<FranchiseeCustomFieldConfigVO> result = new ArrayList<>();
|
||||
for (FtbParamEntity entity : entityList) {
|
||||
FranchiseeCustomFieldConfigVO vo = buildFranchiseeCustomerFieldVo(entity);
|
||||
if (vo == null) {
|
||||
continue;
|
||||
}
|
||||
result.add(vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FranchiseeCustomFieldConfigVO query(String key) {
|
||||
FtbParamEntity ftbParamEntity = baseParamMapper.selectByKey(key);
|
||||
if(Objects.isNull(ftbParamEntity)){
|
||||
throw new ServiceException("找不到该配置!",404);
|
||||
}
|
||||
FranchiseeCustomFieldConfigVO franchiseeCustomFieldConfigVO = buildFranchiseeCustomerFieldVo(ftbParamEntity);
|
||||
if(Objects.isNull(franchiseeCustomFieldConfigVO)){
|
||||
throw new ServiceException("该配置不正确!",404);
|
||||
}
|
||||
return franchiseeCustomFieldConfigVO;
|
||||
}
|
||||
|
||||
private FranchiseeCustomFieldConfigVO buildFranchiseeCustomerFieldVo(FtbParamEntity entity) {
|
||||
FranchiseeCustomFieldConfigVO vo = JsonUtil.getJsonToBean(entity.getValue(), FranchiseeCustomFieldConfigVO.class);
|
||||
if (vo == null) {
|
||||
return null;
|
||||
}
|
||||
vo.setKey(entity.getKey());
|
||||
vo.setFieldCode(entity.getKey());
|
||||
vo.setSort(entity.getSort());
|
||||
vo.setFieldName(StrUtil.trim(vo.getFieldName()));
|
||||
if (vo.getOptionList() == null) {
|
||||
vo.setOptionList(new ArrayList<>());
|
||||
}
|
||||
if(vo.getImageList() == null){
|
||||
vo.setImageList(new ArrayList<>());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自定义字段配置
|
||||
*
|
||||
* @param key 配置key
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(String key) {
|
||||
String trimKey = StrUtil.trim(key);
|
||||
ServiceException.isTrue(StrUtil.isNotBlank(trimKey), "key不能为空");
|
||||
LambdaQueryWrapper<FtbParamEntity> deleteWrapper = Wrappers.lambdaQuery();
|
||||
deleteWrapper.eq(FtbParamEntity::getType, customerFieldType);
|
||||
deleteWrapper.eq(FtbParamEntity::getKey, trimKey);
|
||||
int deleteCount = baseParamMapper.delete(deleteWrapper);
|
||||
ServiceException.isTrue(deleteCount > 0, "自定义字段配置不存在");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void adjustSort(List<String> key) {
|
||||
ServiceException.isTrue(CollUtil.isNotEmpty(key), "key list cannot be empty");
|
||||
List<String> sortedKeyList = new ArrayList<>();
|
||||
Set<String> keySet = new HashSet<>();
|
||||
for (String item : key) {
|
||||
String trimKey = StrUtil.trim(item);
|
||||
ServiceException.isTrue(StrUtil.isNotBlank(trimKey), "key cannot be blank");
|
||||
ServiceException.isTrue(keySet.add(trimKey), "key list contains duplicate key");
|
||||
sortedKeyList.add(trimKey);
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<FtbParamEntity> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(FtbParamEntity::getType, customerFieldType);
|
||||
List<FtbParamEntity> entityList = baseParamMapper.selectList(queryWrapper);
|
||||
if (CollUtil.isEmpty(entityList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, FtbParamEntity> entityMap = entityList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(item -> StrUtil.trim(item.getKey()), item -> item, (a, b) -> a));
|
||||
for (String sortKey : sortedKeyList) {
|
||||
ServiceException.isTrue(entityMap.containsKey(sortKey), "自定义字段配置不存在");
|
||||
}
|
||||
|
||||
List<FtbParamEntity> remainingEntityList = entityList.stream()
|
||||
.filter(item -> !keySet.contains(StrUtil.trim(item.getKey())))
|
||||
.sorted((a, b) -> {
|
||||
Long sortA = a.getSort() == null ? Long.MAX_VALUE : a.getSort();
|
||||
Long sortB = b.getSort() == null ? Long.MAX_VALUE : b.getSort();
|
||||
int sortCompare = sortA.compareTo(sortB);
|
||||
if (sortCompare != 0) {
|
||||
return sortCompare;
|
||||
}
|
||||
return StrUtil.nullToDefault(a.getKey(), "").compareTo(StrUtil.nullToDefault(b.getKey(), ""));
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
for (FtbParamEntity entity : remainingEntityList) {
|
||||
sortedKeyList.add(StrUtil.trim(entity.getKey()));
|
||||
}
|
||||
|
||||
long targetSort = 1L;
|
||||
for (String sortKey : sortedKeyList) {
|
||||
FtbParamEntity entity = entityMap.get(sortKey);
|
||||
if (entity == null) {
|
||||
continue;
|
||||
}
|
||||
if (!Objects.equals(entity.getSort(), targetSort)) {
|
||||
entity.setSort(targetSort);
|
||||
baseParamMapper.updateByKey(sortKey, entity);
|
||||
}
|
||||
targetSort++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按key新增或更新
|
||||
*
|
||||
* 规则:
|
||||
* 1. key为空,新增;
|
||||
* 2. key不为空,按key更新。
|
||||
*
|
||||
* @param req 请求参数
|
||||
* @return 配置key
|
||||
*/
|
||||
/**
|
||||
* 查询自定义名称。
|
||||
*
|
||||
* 读取 base_param 表中 key=customerNameType 且 type=customerNameType 的记录。
|
||||
*
|
||||
* @return 自定义名称;未配置时返回空字符串
|
||||
*/
|
||||
@Override
|
||||
public String queryCustomName() {
|
||||
FtbParamEntity entity = baseParamMapper.selectByKey(customerNameType);
|
||||
if (entity == null || !StrUtil.equals(customerNameType, StrUtil.trim(entity.getType()))) {
|
||||
return "";
|
||||
}
|
||||
return StrUtil.blankToDefault(StrUtil.trim(entity.getValue()), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新自定义名称。
|
||||
*
|
||||
* 保存逻辑:先按固定key更新,若不存在则插入;type 固定为 customerNameType。
|
||||
*
|
||||
* @param customName 自定义名称
|
||||
* @return 更新后的自定义名称
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String updateCustomName(String customName) {
|
||||
String name = StrUtil.trim(customName);
|
||||
ServiceException.isTrue(StrUtil.isNotBlank(name), "customName cannot be blank");
|
||||
|
||||
FtbParamEntity entity = new FtbParamEntity();
|
||||
entity.setId(FtbUtil.getId());
|
||||
entity.setKey(customerNameType);
|
||||
entity.setType(customerNameType);
|
||||
entity.setValue(name);
|
||||
entity.setSort(0L);
|
||||
|
||||
int updateCount = baseParamMapper.updateByKey(customerNameType, entity);
|
||||
if (updateCount > 0) {
|
||||
return name;
|
||||
}
|
||||
|
||||
try {
|
||||
baseParamMapper.insertParam(entity);
|
||||
} catch (DuplicateKeyException e) {
|
||||
int retryCount = baseParamMapper.updateByKey(customerNameType, entity);
|
||||
ServiceException.isTrue(retryCount > 0, "update customName failed");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private String saveOrUpdate(FranchiseeCustomFieldConfigReq req) {
|
||||
validateReq(req);
|
||||
String key = StrUtil.trim(req.getKey());
|
||||
if (StrUtil.isBlank(key)) {
|
||||
key = FtbUtil.getId();
|
||||
FtbParamEntity entity = buildEntity(key, req);
|
||||
entity.setId(FtbUtil.getId());
|
||||
insertCustomerField(entity);
|
||||
return key;
|
||||
}
|
||||
|
||||
FtbParamEntity source = baseParamMapper.selectByKey(key);
|
||||
ServiceException.notNull(source, "自定义字段配置不存在");
|
||||
ServiceException.isTrue(customerFieldType.equals(source.getType()), "自定义字段配置不存在");
|
||||
int updateCount = baseParamMapper.updateByKey(key, buildEntity(key, req));
|
||||
ServiceException.isTrue(updateCount > 0, "更新失败");
|
||||
return key;
|
||||
}
|
||||
|
||||
private void insertCustomerField(FtbParamEntity entity) {
|
||||
String lockKey = buildFranchiseeCustomerFieldAddLock();
|
||||
RLock rLock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
rLock.lock(10, TimeUnit.SECONDS);
|
||||
Long count = baseParamMapper.selectCount(new LambdaQueryWrapper<FtbParamEntity>()
|
||||
.eq(FtbParamEntity::getType, customerFieldType));
|
||||
if(count >= 100){
|
||||
throw new ServiceException("自定义字段配置已满100");
|
||||
}
|
||||
baseParamMapper.insertParam(entity);
|
||||
}finally {
|
||||
rLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建并序列化配置实体
|
||||
*
|
||||
* @param key 配置key
|
||||
* @param req 请求参数
|
||||
* @return BaseParam实体
|
||||
*/
|
||||
private FtbParamEntity buildEntity(String key, FranchiseeCustomFieldConfigReq req) {
|
||||
FranchiseeCustomFieldConfigValueModel saveData = buildSaveData(key, req);
|
||||
FtbParamEntity entity = new FtbParamEntity();
|
||||
entity.setKey(key);
|
||||
entity.setType(customerFieldType);
|
||||
entity.setSort(req.getSort() == null ? 0L : req.getSort());
|
||||
entity.setValue(JsonUtil.getObjectToString(saveData));
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建保存数据对象
|
||||
*
|
||||
* @param key 配置key
|
||||
* @param req 请求参数
|
||||
* @return 保存对象
|
||||
*/
|
||||
private FranchiseeCustomFieldConfigValueModel buildSaveData(String key, FranchiseeCustomFieldConfigReq req) {
|
||||
FranchiseeCustomFieldConfigValueModel vo = new FranchiseeCustomFieldConfigValueModel();
|
||||
vo.setFieldCode(key);
|
||||
vo.setFieldName(StrUtil.trim(req.getFieldName()));
|
||||
vo.setFieldType(req.getFieldType());
|
||||
vo.setRequiredMark(req.getRequiredMark() != null && req.getRequiredMark());
|
||||
vo.setSort(req.getSort() == null ? 0L : req.getSort());
|
||||
List<FranchiseeCustomFieldConfigOptionVO> optionList = req.getOptionList().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(item -> {
|
||||
FranchiseeCustomFieldConfigOptionVO option = new FranchiseeCustomFieldConfigOptionVO();
|
||||
option.setOptionName(StrUtil.trim(item.getOptionName()));
|
||||
return option;
|
||||
})
|
||||
.filter(item -> StrUtil.isNotBlank(item.getOptionName()))
|
||||
.collect(Collectors.toList());
|
||||
vo.setOptionList(optionList);
|
||||
|
||||
List<FranchiseeCustomFieldConfigOptionVO> imageList = req.getImageList().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(item -> {
|
||||
FranchiseeCustomFieldConfigOptionVO option = new FranchiseeCustomFieldConfigOptionVO();
|
||||
option.setOptionName(StrUtil.trim(item.getOptionName()));
|
||||
return option;
|
||||
})
|
||||
.filter(item -> StrUtil.isNotBlank(item.getOptionName()))
|
||||
.collect(Collectors.toList());
|
||||
vo.setImageList(imageList);
|
||||
vo.setTextTips(req.getTextTips());
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验请求参数
|
||||
*
|
||||
* @param req 请求参数
|
||||
*/
|
||||
private void validateReq(FranchiseeCustomFieldConfigReq req) {
|
||||
ServiceException.notNull(req, "请求参数不能为空");
|
||||
ServiceException.isTrue(StrUtil.isNotBlank(req.getFieldName()), "字段名称不能为空");
|
||||
ServiceException.notNull(req.getFieldType(), "字段类型不能为空");
|
||||
if (req.getOptionList() == null) {
|
||||
req.setOptionList(new ArrayList<>());
|
||||
}
|
||||
if (FranchiseeCustomFieldTypeEnum.MULTI_OPTION.equals(req.getFieldType())) {
|
||||
ServiceException.isTrue(CollUtil.isNotEmpty(req.getOptionList()), "选项不能为空");
|
||||
}
|
||||
for (FranchiseeCustomFieldConfigOptionReq option : req.getOptionList()) {
|
||||
ServiceException.notNull(option, "选项不能为空");
|
||||
ServiceException.isTrue(StrUtil.isNotBlank(option.getOptionName()), "选项名称不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private String buildFranchiseeCustomerFieldAddLock() {
|
||||
return lockPrefix+ UserProvider.getUser().getTenantId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存到BaseParamEntity.value的模型(不包含key)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
private static class FranchiseeCustomFieldConfigValueModel {
|
||||
private String fieldCode;
|
||||
private String fieldName;
|
||||
private FranchiseeCustomFieldTypeEnum fieldType;
|
||||
private List<FranchiseeCustomFieldConfigOptionVO> optionList = new ArrayList<>();
|
||||
private List<FranchiseeCustomFieldConfigOptionVO> imageList = new ArrayList<>();
|
||||
private Boolean requiredMark;
|
||||
private Long sort;
|
||||
private String textTips;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user