Pārlūkot izejas kodu

门店装修基本信息编辑

qrs 3 nedēļas atpakaļ
vecāks
revīzija
5b3ab58648

+ 13 - 0
alien-config/src/main/java/shop/alien/config/redis/BaseRedisService.java

@@ -1,6 +1,7 @@
 package shop.alien.config.redis;
 
 import lombok.RequiredArgsConstructor;
+import org.springframework.data.geo.Point;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.data.redis.core.script.RedisScript;
 import org.springframework.stereotype.Component;
@@ -184,4 +185,16 @@ public class BaseRedisService {
     public void delete(String key) {
         stringRedisTemplate.delete(key);
     }
+
+    /**
+     * 添加地理信息
+     *
+     * @param point
+     * @param content
+     * @param type
+     * @return
+     */
+    public Long inGeolocation(Point point, String content, String type) {
+        return stringRedisTemplate.opsForGeo().add(type, point, content);
+    }
 }

+ 42 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformInfoController.java

@@ -0,0 +1,42 @@
+package shop.alien.storeplatform.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiOperationSupport;
+import io.swagger.annotations.ApiSort;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreInfo;
+import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.storeplatform.service.StorePlatformInfoService;
+
+@Slf4j
+@Api(tags = {"商户平台-门店信息"})
+@ApiSort(1)
+@CrossOrigin
+@RestController
+@RequestMapping("/storePlatformInfo")
+@RequiredArgsConstructor
+public class StorePlatformInfoController {
+
+    private final StorePlatformInfoService storePlatformInfoService;
+
+    @ApiOperation("门店装修-编辑门店信息")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/saveOrUpdate")
+    public R<StoreInfo> saveOrUpdate(@RequestBody StoreInfoDto storeInfo) {
+        log.info("StoreInfoController.saveOrUpdate?storeInfo={}", storeInfo);
+        try {
+            int num = storePlatformInfoService.saveOrUpdateStoreInfo(storeInfo);
+            if (num > 0) {
+                return R.success("成功");
+            }
+            return R.fail("失败");
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
+        }
+    }
+
+}

+ 12 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/NearMeService.java

@@ -0,0 +1,12 @@
+package shop.alien.storeplatform.service;
+
+import org.springframework.data.geo.Point;
+import shop.alien.entity.store.dto.NearMeDto;
+
+import java.util.List;
+
+public interface NearMeService {
+
+    void inGeolocation(Point point, String content, Boolean flag);
+
+}

+ 16 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StorePlatformInfoService.java

@@ -0,0 +1,16 @@
+package shop.alien.storeplatform.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.StoreInfo;
+import shop.alien.entity.store.dto.StoreInfoDto;
+
+public interface StorePlatformInfoService extends IService<StoreInfo> {
+
+    /**
+     * 门店装修 - 编辑
+     * @param storeInfo
+     * @return
+     */
+    int saveOrUpdateStoreInfo(StoreInfoDto storeInfo);
+
+}

+ 27 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/NearMeServiceImpl.java

@@ -0,0 +1,27 @@
+package shop.alien.storeplatform.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.geo.Point;
+import org.springframework.stereotype.Service;
+import shop.alien.config.redis.BaseRedisService;
+import shop.alien.storeplatform.service.NearMeService;
+import shop.alien.util.common.constant.Constant;
+
+@Service
+@RequiredArgsConstructor
+public class NearMeServiceImpl implements NearMeService {
+
+    private final BaseRedisService baseRedisService;
+
+    /**
+     * 添加地址位置
+     *
+     * @param point
+     * @param content
+     */
+    @Override
+    public void inGeolocation(Point point, String content, Boolean flag) {
+        baseRedisService.inGeolocation(point, content, flag ? Constant.GEO_STORE_PRIMARY : Constant.GEO_STORE_NAME);
+    }
+
+}

+ 196 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformInfoServiceImpl.java

@@ -0,0 +1,196 @@
+package shop.alien.storeplatform.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.data.geo.Point;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.mapper.*;
+import shop.alien.storeplatform.service.NearMeService;
+import shop.alien.storeplatform.service.StorePlatformInfoService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class StorePlatformInfoServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo> implements StorePlatformInfoService {
+
+    private final LifeUserOrderMapper lifeUserOrderMapper;
+
+    private final LifeGroupBuyMainMapper lifeGroupBuyMainMapper;
+
+    private final LifeCouponMapper lifeCouponMapper;
+
+    private final StoreDictionaryMapper storeDictionaryMapper;
+
+    private final StoreInfoMapper storeInfoMapper;
+
+    private final EssentialCityCodeMapper essentialCityCodeMapper;
+
+    private final NearMeService nearMeService;
+
+    @Override
+    public int saveOrUpdateStoreInfo(StoreInfoDto storeInfodto) {
+        if (storeInfodto.getId() != null) {
+            // 校验当前店铺存在未完成的订单及正在销售的商品
+            verificationStoreInfoStatus(storeInfodto);
+
+            // 1. 处理经营板块及经营种类
+            Integer businessSection = storeInfodto.getBusinessSection();
+            StoreDictionary businessSectionDict = null;
+            List<String> businessTypeNames = new ArrayList<>();
+
+            // 查询经营板块(非空判断,避免后续空指针)
+            if (Objects.nonNull(businessSection)) {
+                businessSectionDict = storeDictionaryMapper.selectOne(
+                        new LambdaQueryWrapper<StoreDictionary>()
+                                .eq(StoreDictionary::getDictId, businessSection)
+                                .eq(StoreDictionary::getTypeName, "business_section")
+                );
+                // 若经营板块不存在,可根据业务抛出异常或默认处理
+                if (Objects.isNull(businessSectionDict)) {
+                    throw new IllegalArgumentException("经营板块不存在:" + businessSection);
+                }
+            }
+
+            // 批量查询经营种类(替代循环查询,解决N+1问题)
+            List<String> businessTypes = storeInfodto.getBusinessTypes();
+            if (Objects.nonNull(businessSectionDict) && !CollectionUtils.isEmpty(businessTypes)) {
+                // 一次查询所有符合条件的经营种类
+                List<StoreDictionary> typeDicts = storeDictionaryMapper.selectList(
+                        new LambdaQueryWrapper<StoreDictionary>()
+                                .in(StoreDictionary::getDictId, businessTypes) // 批量匹配id
+                                .eq(StoreDictionary::getParentId, businessSectionDict.getId())
+                );
+                // 转为Map<dictId, StoreDictionary>,方便快速获取
+                Map<String, StoreDictionary> typeDictMap = typeDicts.stream()
+                        .collect(Collectors.toMap(
+                                dict -> dict.getDictId().toString(), // 假设dictId是字符串类型,若为数字需转换
+                                Function.identity(),
+                                (existing, replacement) -> existing // 处理重复id(理论上不会有)
+                        ));
+                // 提取经营种类名称
+                for (String typeId : businessTypes) {
+                    StoreDictionary dict = typeDictMap.get(typeId);
+                    if (Objects.nonNull(dict)) {
+                        businessTypeNames.add(dict.getDictDetail());
+                    } else {
+                        // 可选:记录无效的经营种类id,便于排查
+                        log.warn("无效的经营种类id:" + typeId + "(所属板块:" + businessSectionDict.getDictDetail() + ")");
+                    }
+                }
+            }
+
+            // 2. 构建StoreInfo对象
+            StoreInfo storeInfo = new StoreInfo();
+            BeanUtils.copyProperties(storeInfodto, storeInfo);
+
+            // 3. 处理经纬度
+            String longitude = storeInfodto.getStorePositionLongitude();
+            String latitude = storeInfodto.getStorePositionLatitude();
+            if (StringUtils.isEmpty(longitude) || StringUtils.isEmpty(latitude)) {
+                // 经纬度为空时,复用原数据
+                StoreInfo oldStore = storeInfoMapper.selectById(storeInfodto.getId());
+                if (Objects.nonNull(oldStore)) {
+                    storeInfo.setStorePosition(oldStore.getStorePosition());
+                }
+            } else {
+                // 拼接经纬度
+                storeInfo.setStorePosition(longitude + "," + latitude);
+            }
+
+            // 4. 设置门店状态、经营板块及类型
+            storeInfo.setStoreStatus(storeInfodto.getStoreStatus());
+            // 经营板块(非空时才设置)
+            if (Objects.nonNull(businessSection)) {
+                storeInfo.setBusinessSection(businessSection);
+            }
+            // 经营板块名称(非空时才设置)
+            if (Objects.nonNull(businessSectionDict)) {
+                storeInfo.setBusinessSectionName(businessSectionDict.getDictDetail());
+            }
+            // 经营种类及名称(非空时拼接)
+            if (!CollectionUtils.isEmpty(businessTypes) && !CollectionUtils.isEmpty(businessTypeNames)) {
+                storeInfo.setBusinessTypes(String.join(",", businessTypes));
+                storeInfo.setBusinessTypesName(String.join(",", businessTypeNames));
+            }
+
+            // 5. 处理行政区域信息(抽取为方法,减少重复) 不存在单独查的情况
+            if (!Objects.isNull(storeInfo.getAdministrativeRegionProvinceAdcode())) {
+
+                storeInfo.setAdministrativeRegionProvinceName(
+                        getAreaName(storeInfo.getAdministrativeRegionProvinceAdcode())
+                );
+                storeInfo.setAdministrativeRegionCityName(
+                        getAreaName(storeInfo.getAdministrativeRegionCityAdcode())
+                );
+                storeInfo.setAdministrativeRegionDistrictName(
+                        getAreaName(storeInfo.getAdministrativeRegionDistrictAdcode())
+                );
+            }
+
+            // 6. 执行更新
+            int updateNum = storeInfoMapper.updateById(storeInfo);
+
+            // 7. 更新地理位置信息(处理经纬度解析异常)
+            if (!StringUtils.isEmpty(longitude) && !StringUtils.isEmpty(latitude)) {
+                try {
+                    double lon = Double.parseDouble(longitude);
+                    double lat = Double.parseDouble(latitude);
+                    nearMeService.inGeolocation(new Point(lon, lat), storeInfo.getId().toString(), Boolean.TRUE);
+                } catch (NumberFormatException e) {
+                    log.error("经纬度解析失败:longitude=" + longitude + ", latitude=" + latitude);
+                    // 可选:根据业务是否抛出异常,或忽略
+                    // throw new IllegalArgumentException("经纬度格式错误", e);
+                }
+            }
+            return updateNum;
+        } else {
+            StoreInfo storeInfo = new StoreInfo();
+            BeanUtils.copyProperties(storeInfodto, storeInfo);
+            int num = storeInfoMapper.insert(storeInfo);
+            return num;
+        }
+    }
+
+    void verificationStoreInfoStatus(StoreInfoDto storeInfo) {
+        //营业状态 0:正常营业, 1:暂停营业, 2:筹建中, 99:永久关门
+        if (storeInfo.getBusinessStatus() == 99) {
+            //判断店铺有未完成的订单
+            List<LifeUserOrder> lifeUserOrders = lifeUserOrderMapper.selectList(new LambdaQueryWrapper<LifeUserOrder>().in(LifeUserOrder::getStatus, 0, 3).eq(LifeUserOrder::getStoreId, storeInfo.getId()).eq(LifeUserOrder::getDeleteFlag, 0));
+            if (!CollectionUtils.isEmpty(lifeUserOrders)) {
+                throw new RuntimeException("店铺有未完成的订单");
+            }
+            //判断店铺有正在售卖的商品
+            List<LifeGroupBuyMain> lifeGroupBuyMainList = lifeGroupBuyMainMapper.selectList(new LambdaQueryWrapper<LifeGroupBuyMain>().eq(LifeGroupBuyMain::getStoreId, storeInfo.getId()).eq(LifeGroupBuyMain::getStatus, 5).eq(LifeGroupBuyMain::getDeleteFlag, 0));
+            List<LifeCoupon> lifeCoupons = lifeCouponMapper.selectList(new LambdaQueryWrapper<LifeCoupon>().in(LifeCoupon::getStatus, 0, 1).and(qw -> qw.gt(LifeCoupon::getStockQty, 0).or().gt(LifeCoupon::getSingleQty, 0)).eq(LifeCoupon::getStoreId, storeInfo.getId()).eq(LifeCoupon::getType, 1).eq(LifeCoupon::getDeleteFlag, 0));
+            if (!CollectionUtils.isEmpty(lifeCoupons) || !CollectionUtils.isEmpty(lifeGroupBuyMainList)) {
+                throw new RuntimeException("店铺有正在销售的商品");
+            }
+        }
+    }
+
+    // 抽取:根据区域编码查询区域名称(通用方法)
+    private String getAreaName(String areaCode) {
+        if (StringUtils.isEmpty(areaCode)) {
+            return ""; // 或返回null,根据业务定义
+        }
+        EssentialCityCode cityCode = essentialCityCodeMapper.selectOne(
+                new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, areaCode)
+        );
+        return Objects.nonNull(cityCode) ? cityCode.getAreaName() : "";
+    }
+
+}