Просмотр исходного кода

Merge remote-tracking branch 'origin/store-plantform' into store-plantform

zjy 3 недель назад
Родитель
Сommit
182eabef60

+ 301 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/config/GaoDeMapUtil.java

@@ -0,0 +1,301 @@
+package shop.alien.storeplatform.config;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import shop.alien.entity.store.EssentialCityCode;
+import shop.alien.mapper.EssentialCityCodeMapper;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 高德地图工具类
+ *
+ * @author ssk
+ * @version 1.0.0
+ * @discription 打死你个龟孙
+ * @since 1937-7-7
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class GaoDeMapUtil {
+
+    @Value("${gaode.key}")
+    private String key;
+
+    @Value("${gaode.geoUrl}")
+    private String geoUrl;
+
+    @Value("${gaode.geoListUrl}")
+    private String geoListUrl;
+
+    @Value("${gaode.getDistrict}")
+    private String getDistrict;
+
+    @Value("${gaode.distanceUrl}")
+    private String distanceUrl;
+
+    @Value("${gaode.distanceTypeUrl}")
+    private String distanceTypeUrl;
+
+    @Value("${gaode.nearUrl}")
+    private String nearUrl;
+
+    @Value("${gaode.subwayUrl}")
+    private String subwayUrl;
+
+    @Value("${gaode.addressUrl}")
+    private String addressUrl;
+
+    private final EssentialCityCodeMapper essentialCityCodeMapper;
+
+    /**
+     * 地址转经纬度
+     *
+     * @param address 地址
+     * @return 经纬度
+     */
+    public String getLonAndLatByAddress(String address) {
+        String formattedUrl = String.format(geoUrl, address, key);
+        JSONObject obj = getResponse(formattedUrl);
+        if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+            JSONArray geocodesArray = obj.getJSONArray("geocodes");
+            if (geocodesArray != null && !geocodesArray.isEmpty()) {
+                JSONObject jobJSON = geocodesArray.getJSONObject(0);
+                return jobJSON.getString("location");
+            } else {
+                log.error("AddressLocationUtil.getLonAndLatByAddress ERROR 未找到与地址匹配的经纬度信息");
+                return "ERROR 未找到与地址匹配的经纬度信息";
+            }
+        } else {
+            log.error("AddressLocationUtil.getLonAndLatByAddress ERROR 地址转换经纬度失败");
+            return "ERROR 地址转换经纬度失败";
+        }
+    }
+
+    /**
+     * 地址转经纬度
+     *
+     * @param address 地址
+     * @return 经纬度
+     */
+    public JSONObject getInputPrompt(String address, String city) {
+        //如果按照城市查询
+        String cityCode = "";
+        if (StringUtils.isNotEmpty(city)) {
+            EssentialCityCode essentialCityCode = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaName, city));
+            if (null != essentialCityCode) {
+                cityCode = essentialCityCode.getCityCode().toString();
+            }
+        }
+        String formattedUrl = String.format(geoListUrl, address, key, cityCode);
+        JSONObject obj = getResponse(formattedUrl);
+        return obj;
+    }
+
+    /**
+     * 地址转经纬度
+     * cityCode:城市编码
+     *
+     * @return
+     */
+    public JSONObject getDistrict(String cityCode) {
+        String formattedUrl = String.format(getDistrict, key, cityCode);
+        JSONObject obj = getResponse(formattedUrl);
+        return obj;
+    }
+
+    /**
+     * 计算两个经纬度的距离
+     *
+     * @param longitudeOne 经度1
+     * @param latitudeOne  纬度1
+     * @param longitudeTwo 经度2
+     * @param latitudeTwo  纬度2
+     * @return distance
+     */
+    public Double getDistance(String longitudeOne, String latitudeOne, String longitudeTwo, String latitudeTwo) {
+        try {
+            String urlString = String.format(distanceUrl, key, longitudeOne, latitudeOne, longitudeTwo, latitudeTwo);
+            JSONObject obj = getResponse(urlString);
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                JSONArray resultsArray = obj.getJSONArray("results");
+                if (resultsArray != null && !resultsArray.isEmpty()) {
+                    JSONObject resultJSON = resultsArray.getJSONObject(0);
+                    return Double.parseDouble(resultJSON.getString("distance"));
+                } else {
+                    log.error("AddressLocationUtil.getDistance ERROR 计算距离失败,结果为空");
+                    return null;
+                }
+            } else {
+                log.error("AddressLocationUtil.getDistance ERROR 计算距离失败");
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("AddressLocationUtil.getDistance ERROR {}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 计算两个经纬度的距离
+     *
+     * @param longitudeOne 经度1
+     * @param latitudeOne  纬度1
+     * @param longitudeTwo 经度2
+     * @param latitudeTwo  纬度2
+     * @return distance
+     */
+    public Double getDistanceStraightLine(String longitudeOne, String latitudeOne, String longitudeTwo, String latitudeTwo) {
+        try {
+            String urlString = String.format(distanceTypeUrl, key, longitudeOne, latitudeOne, longitudeTwo, latitudeTwo, 0);
+            JSONObject obj = getResponse(urlString);
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                JSONArray resultsArray = obj.getJSONArray("results");
+                if (resultsArray != null && !resultsArray.isEmpty()) {
+                    JSONObject resultJSON = resultsArray.getJSONObject(0);
+                    return Double.parseDouble(resultJSON.getString("distance"));
+                } else {
+                    log.error("AddressLocationUtil.getDistance ERROR 计算距离失败,结果为空");
+                    return null;
+                }
+            } else {
+                log.error("AddressLocationUtil.getDistance ERROR 计算距离失败");
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("AddressLocationUtil.getDistance ERROR {}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取附近商家、建筑等信息
+     *
+     * @param longitude 经度
+     * @param latitude  纬度
+     * @return
+     */
+    public JSONArray getNear(String longitude, String latitude) {
+        try {
+            String urlString = String.format(nearUrl, longitude, latitude, key, 10000, 20, 1);
+            JSONObject obj = getResponse(urlString);
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                JSONArray resultsArray = obj.getJSONArray("pois");
+                return resultsArray;
+            }
+        } catch (Exception e) {
+            log.error("AddressLocationUtil.getNear ERROR {}", e.getMessage());
+        }
+        return new JSONArray();
+    }
+
+    /**
+     * 获取10公里范围内的商场
+     *
+     * @param longitude 经度
+     * @param latitude  纬度
+     * @return 商场列表
+     */
+    public JSONArray getNearbyShoppingMalls(String longitude, String latitude) {
+        try {
+            // 使用高德地图POI搜索接口,搜索类型为商场(060100)
+            String urlString = String.format(nearUrl, longitude, latitude, key, 10000, 20, 1) + "&types=060100";
+            JSONObject obj = getResponse(urlString);
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                JSONArray resultsArray = obj.getJSONArray("pois");
+                return resultsArray;
+            }
+        } catch (Exception e) {
+            log.error("GaoDeMapUtil.getNearbyShoppingMalls ERROR {}", e.getMessage());
+        }
+        return new JSONArray();
+    }
+
+    public JSONObject getNearbySubway(String longitude, String latitude) {
+        try {
+            // 使用高德地图POI搜索接口,搜索类型为地铁站(010100)
+            String encodedKeywords = URLEncoder.encode("地铁站", "UTF-8");
+            String urlString = String.format(
+                    subwayUrl,
+                    key, latitude, longitude, encodedKeywords, 1000, 150500);
+            JSONObject obj = getResponse(urlString);
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                JSONObject pois = obj.getJSONArray("pois").getJSONObject(0);
+                return pois;
+            }
+        } catch (Exception e) {
+            log.error("GaoDeMapUtil.getNearbySubway ERROR {}", e.getMessage());
+        }
+        return new JSONObject();
+    }
+
+    /**
+     * 通过经纬度获取地址信息
+     *
+     * @param longitude
+     * @param latitude
+     * @param radius
+     * @param extensions
+     * @return
+     */
+    public Map<String, String> getAddressByLonAndLat(String longitude, String latitude, String radius, String extensions) {
+        String formattedUrl = String.format(addressUrl, longitude, latitude, key, radius, extensions);
+        JSONObject obj = getResponse(formattedUrl);
+        try {
+            if (null != obj && "1".equals(String.valueOf(obj.get("status")))) {
+                Map<String, String> address = new HashMap<>();
+                JSONObject regeocodeObject = obj.getJSONObject("regeocode");
+                JSONObject addressComponent = regeocodeObject.getJSONObject("addressComponent");
+                address.put("city", addressComponent.getString("city"));
+                address.put("district", addressComponent.getString("district"));
+                address.put("province", addressComponent.getString("province"));
+                JSONObject streetNumber = addressComponent.getJSONObject("streetNumber");
+                address.put("street", streetNumber.getString("street"));
+                address.put("streetNumber", streetNumber.getString("number"));
+                JSONObject pois = regeocodeObject.getJSONArray("pois").getJSONObject(0);
+                address.put("poiName", pois.getString("name"));
+                return address;
+            }
+        } catch (Exception e) {
+            log.error("GaoDeMapUtil.getAddressByLonAndLat ERROR {}", e.getMessage());
+        }
+        return new HashMap<>();
+    }
+
+    /**
+     * 创建请求
+     *
+     * @param serverUrl 请求地址
+     * @return JSONObject
+     */
+    private JSONObject getResponse(String serverUrl) {
+        StringBuilder result = new StringBuilder();
+        try {
+            URL url = new URL(serverUrl);
+            URLConnection conn = url.openConnection();
+            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null) {
+                result.append(line);
+            }
+            in.close();
+        } catch (Exception e) {
+            log.error("AddressLocationUtil.getResponse ERROR {}", e.getMessage());
+            return null;
+        }
+        return JSONObject.parseObject(result.toString());
+    }
+}

+ 684 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StoreBusinessController.java

@@ -0,0 +1,684 @@
+package shop.alien.storeplatform.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.config.redis.BaseRedisService;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.entity.store.vo.*;
+import shop.alien.entity.storePlatform.StoreLicenseHistory;
+import shop.alien.mapper.StoreCommentSummaryInterestMapper;
+import shop.alien.mapper.TagsMainMapper;
+import shop.alien.mapper.WebAuditMapper;
+import shop.alien.mapper.storePlantform.StoreLicenseHistoryMapper;
+import shop.alien.storeplatform.service.StoreBusinessService;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 二期-门店信息Controller
+ *
+ * @author ssk
+ * @since 2024-12-05
+ */
+@Slf4j
+@Api(tags = {"二期-门店信息"})
+@ApiSort(1)
+@CrossOrigin
+@RestController
+@RequestMapping("/store/info")
+@RequiredArgsConstructor
+public class StoreBusinessController {
+
+    private final StoreBusinessService storeInfoService;
+
+    private final TagsMainMapper tagsMainMapper;
+
+    private final WebAuditMapper webAuditMapper;
+
+    private final BaseRedisService baseRedisService;
+
+    private final StoreCommentSummaryInterestMapper storeCommentSummaryInterestMapper;
+
+    /** 商户证照历史记录数据访问对象 */
+    private final StoreLicenseHistoryMapper licenseHistoryMapper;
+
+    @ApiOperation("获取所有门店")
+    @ApiOperationSupport(order = 1)
+    @GetMapping("/getAll")
+    public R<List<StoreInfo>> getAll() {
+        log.info("StoreInfoController.getAll");
+        return R.data(storeInfoService.list());
+    }
+
+    @ApiOperation("根据id获取门店")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getOne")
+    public R<StoreInfo> getOne(Integer id) {
+        log.info("StoreInfoController.getOne?id={}", id);
+        return R.data(storeInfoService.getById(id));
+    }
+
+    @ApiOperation("门店装修-编辑门店信息")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/saveOrUpdate")
+    public R<StoreInfo> saveOrUpdate(@RequestBody StoreInfoDto storeInfo) {
+        log.info("StoreInfoController.saveOrUpdate?storeInfo={}", storeInfo);
+        try {
+            int num = storeInfoService.saveOrUpdateStoreInfo(storeInfo);
+            if (num > 0) {
+                return R.success("成功");
+            }
+            return R.fail("失败");
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
+        }
+    }
+
+    @ApiOperation("web端新增门店")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/saveStoreInfo")
+    public R saveStoreInfo(@RequestBody StoreInfoDto storeInfoDto) throws Exception {
+        log.info("StoreInfoController.saveStoreInfo?storeInfoDto={}", storeInfoDto);
+        StoreInfoVo storeInfoVo = storeInfoService.saveStoreInfo(storeInfoDto);
+        if (storeInfoVo != null) {
+            return R.data(storeInfoVo);
+        }
+        return R.fail("失败");
+    }
+
+    @ApiOperation("新增门店草稿")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/saveStoreInfoDraft")
+    public R<Boolean> saveStoreInfoDraft(@RequestBody StoreInfoDraft storeInfoDraft) {
+        log.info("StoreInfoController.saveStoreInfoDraft?storeInfoDraft={}", storeInfoDraft);
+        int num = storeInfoService.saveStoreInfoDraft(storeInfoDraft);
+        if (num > 0) {
+            return R.data(true);
+        }
+        return R.fail("失败");
+    }
+
+    @ApiOperation("查询门店草稿")
+    @ApiOperationSupport(order = 3)
+    @GetMapping("/selectDraftByUserId")
+    public R<StoreInfoDraft> selectDraftByUserId(int storeUserId) throws Exception {
+        log.info("StoreInfoController.saveStoreInfoDraft?storeUserId={}", storeUserId);
+        return R.data(storeInfoService.selectDraftByUserId(storeUserId));
+    }
+
+
+    @ApiOperation("web端修改门店")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/editStoreInfo")
+    public R editStoreInfo(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.editStoreInfo?storeInfoDto={}", storeInfoDto);
+        StoreInfoVo storeInfoVo = storeInfoService.editStoreInfo(storeInfoDto);
+        if (storeInfoVo != null) {
+            return R.data(storeInfoVo);
+        }
+        return R.fail("失败");
+    }
+
+    @ApiOperation("web修改门店抽成")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/updateStoreCommissionRate")
+    public R updateStoreCommissionRate(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.updateStoreCommissionRate?storeInfoDto={}", storeInfoDto);
+        if (storeInfoService.editStoreCommissionRate(storeInfoDto) > 0) {
+            return R.data("成功");
+        }
+        return R.fail("失败");
+    }
+
+    @ApiOperation("web端删除门店")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/deleteStoreInfo")
+    public R deleteStoreInfo(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.deleteStoreInfo?storeInfoDto={}", storeInfoDto);
+        String s;
+        try {
+            s = storeInfoService.deleteStoreInfo(storeInfoDto);
+        } catch (Exception e) {
+            return R.fail("失败");
+        }
+        if ("成功".equals(s)) {
+            return R.success(s);
+        } else {
+            return R.fail(s);
+        }
+    }
+
+    @ApiOperation("web端重置商户及管理账户密码")
+    @ApiOperationSupport(order = 3)
+    @PostMapping("/restPassword")
+    public R restPassword(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.restPassword?storeInfoDto={}", storeInfoDto);
+        try {
+            storeInfoService.restPassword(storeInfoDto);
+        } catch (Exception e) {
+            return R.fail("失败");
+        }
+        return R.success("成功");
+    }
+
+    @ApiOperation(value = "删除门店")
+    @ApiOperationSupport(order = 4)
+    @PostMapping("/delete")
+    public R<String> delete(@RequestBody List<Integer> ids) {
+        log.info("StoreInfoController.delete?ids={}", ids);
+        if (storeInfoService.removeByIds(ids)) {
+            return R.success("删除成功");
+        }
+        return R.fail("删除失败");
+    }
+
+    @ApiOperation(value = "门店详细信息")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getDetail")
+    public R<StoreMainInfoVo> getDetail(Integer id) {
+        log.info("StoreInfoController.getDetail?id={}", id);
+        return R.data(storeInfoService.getDetail(id));
+    }
+
+    @ApiOperation(value = "门店信息-修改后展示")
+    @ApiOperationSupport(order = 6)
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getStoreInfo")
+    public R<StoreMainInfoVo> getStoreInfo(Integer id) {
+        log.info("StoreInfoController.getStoreInfo?id={}", id);
+        return R.data(storeInfoService.getStoreInfo(id));
+    }
+
+    /**
+     * web-分页查询店铺信息
+     *
+     * @param pageNum      页码
+     * @param pageSize     页容
+     * @param storeName    门店名称
+     * @param storeContact 联系人
+     * @param storePhone   门店电话
+     * @param storeType    门店类型
+     * @return IPage<StoreInfoVo>
+     */
+    @ApiOperation("web-分页查询店铺信息")
+    @ApiOperationSupport(order = 7)
+    @ApiImplicitParams({@ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), @ApiImplicitParam(name = "pageSize", value = "页容", dataType = "int", paramType = "query", required = true), @ApiImplicitParam(name = "storeName", value = "门店名称", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storeContact", value = "门店联系人", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storePhone", value = "门店电话", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storeType", value = "门店类型", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "expiredState", value = "过期状态", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "businessSection", value = "经营板块", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storeApplicationStatus", value = "门店审核状态", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "jingdu", value = "jingdu", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "weidu", value = "weidu", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "renewContractStatus", value = "门店续签合同状态", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "foodLicenceStatus", value = "门店经营许可证状态", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "foodLicenceWhetherExpiredStatus", value = "门店经营许可证是否过期状态", dataType = "String", paramType = "query")})
+    @GetMapping("/getStorePage")
+    public R<IPage<StoreInfoVo>> getStoresPage(@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize, @RequestParam(required = false) String storeName, @RequestParam(required = false) String storeContact, @RequestParam(required = false) String id, @RequestParam(required = false) String storePhone, @RequestParam(required = false) String storeType, @RequestParam(required = false) String expiredState, @RequestParam(required = false) String storeApplicationStatus, @RequestParam(required = false) String businessSection, @RequestParam(required = false) String storeStatus, @RequestParam(required = false) String jingdu, @RequestParam(required = false) String weidu, @RequestParam(required = false) String renewContractStatus, @RequestParam(required = false) String foodLicenceStatus, @RequestParam(required = false) String foodLicenceWhetherExpiredStatus) {
+        log.info("StoreInfoController.getStoresPage?pageNum={},pageSize={},storeName={},storeContact={},id={},storePhone={},storeType={},expiredState={},storeApplicationStatus={},storeStatus={},businessSection={},jingdu={},weidu={},renewContractStatus={},foodLicenceStatus={},foodLicenceWhetherExpiredStatus={}", pageNum, pageSize, storeName, storeContact, id, storePhone, storeType, expiredState, storeApplicationStatus, storeStatus, businessSection, jingdu, weidu, renewContractStatus, foodLicenceStatus, foodLicenceWhetherExpiredStatus);
+        return R.data(storeInfoService.getStorePage(pageNum, pageSize, storeName, storeContact, id, storePhone, storeType, expiredState, storeApplicationStatus, storeStatus, businessSection, jingdu, weidu, renewContractStatus, foodLicenceStatus, foodLicenceWhetherExpiredStatus));
+    }
+
+    /**
+     * web-重置门店密码
+     *
+     * @param storeId 门店id
+     * @return R
+     */
+    @ApiOperation("web-重置门店密码")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "int", paramType = "query")})
+    @GetMapping("/resetPassword")
+    public R<Boolean> resetPassword(@RequestParam("storeId") String storeId) {
+        log.info("StoreInfoController.resetPassword?id={}", storeId);
+        if (storeInfoService.resetPassword(storeId)) {
+            return R.success("密码重置成功");
+        }
+        return R.fail("密码重置失败");
+    }
+
+    /**
+     * web-修改门店状态
+     *
+     * @param storeId        门店id
+     * @param businessStatus 营业状态
+     * @return R
+     */
+    @ApiOperation("web-修改门店状态")
+    @ApiOperationSupport(order = 9)
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "int", paramType = "query"), @ApiImplicitParam(name = "businessStatus", value = "营业状态(0:正常营业, 1:暂停营业, 2:筹建中, 99:永久关门)", dataType = "int", paramType = "query")})
+    @GetMapping("/setStoreState")
+    public R<Boolean> setStoreState(@RequestParam("storeId") String storeId, @RequestParam("businessStatus") Integer businessStatus) {
+        log.info("StoreInfoController.setStoreState?storeId={},storeState={}", storeId, businessStatus);
+        if (storeInfoService.setStoreState(storeId, businessStatus)) {
+            return R.success("状态修改成功");
+        }
+        return R.fail("状态修改失败");
+    }
+
+    /**
+     * web-新增店铺
+     *
+     * @param multipartRequest 文件请求
+     * @param store            店铺信息
+     * @return R
+     */
+    @ApiOperation("web-新增店铺")
+    @ApiOperationSupport(order = 10)
+    @PostMapping("/saveStore")
+    public R<Boolean> saveStore(MultipartRequest multipartRequest, StoreInfo store) {
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        log.info("StoreInfoController.saveStore?store={}&file={}", store.toString(), fileNameSet);
+        if (storeInfoService.saveStore(multipartRequest, store)) {
+            return R.success("新增成功");
+        }
+        return R.fail("新增失败");
+    }
+
+    @ApiOperation("web-导出Excel")
+    @ApiOperationSupport(order = 11)
+    @GetMapping("/export")
+    public ResponseEntity<byte[]> exportToExcel() {
+        log.info("StoreInfoController.exportToExcel");
+        return storeInfoService. exportToExcel();
+    }
+
+    @ApiOperation(value = "web端查询经营板块信息")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/getBusinessSection")
+    public R<List<StoreDictionaryVo>> getBusinessSection() {
+        log.info("StoreInfoController.getBusinessSection");
+        return R.data(storeInfoService.getBusinessSection());
+    }
+
+    @ApiOperation(value = "web端查询经营板块的经营种类信息")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/getBusinessSectionTypes")
+    public R<List<StoreDictionaryVo>> getBusinessSectionTypes(@RequestParam("parentId") String parentId) {
+        log.info("StoreInfoController.getBusinessSectionTypes?parentId={}", parentId);
+        return R.data(storeInfoService.getBusinessSectionTypes(parentId));
+    }
+
+    @ApiOperation(value = "web端查询未绑定店铺的商家端账号")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/getUnboundAccountList")
+    public R<List<StoreUserVo>> getUnboundAccountList(@RequestParam(value = "id", required = false) String id) {
+        log.info("StoreInfoController.getUnboundAccountList");
+        return R.data(storeInfoService.getUnboundAccountList(id));
+    }
+
+    @ApiOperation(value = "web端新增经营板块及经营类型")
+    @ApiOperationSupport(order = 6)
+    @PostMapping("/addBusinessSectionAndTypes")
+    public R addBusinessSectionAndTypes(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.addBusinessSectionAndTypes");
+        storeInfoService.addBusinessSectionAndTypes(storeInfoDto);
+        return R.success("新增成功");
+    }
+
+    @ApiOperation(value = "web端获取店铺明细详情")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/getStoreDetail")
+    public R getStoreDetail(@RequestParam("id") String id, @RequestParam(value = "userId", required = false) String userId, @RequestParam(value = "jingdu", required = false) String jingdu, @RequestParam(value = "weidu", required = false) String weidu) {
+        log.info("StoreInfoController.getStoreDetail?id={},userId={},jingdu={},weidu={}", id, jingdu, weidu);
+        StoreInfoVo storeDetail = storeInfoService.getStoreDetail(id, userId, jingdu, weidu);
+        return R.data(storeDetail);
+    }
+
+    @ApiOperation(value = "web端审批店铺")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/approveStoreInfo")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "approvalStatus", value = "审批状态(1:审批成功,2:审批失败)", dataType = "int", paramType = "query"), @ApiImplicitParam(name = "reason", value = "原因", dataType = "String", paramType = "query")})
+    public R approveStoreInfo(@RequestParam("id") String id, @RequestParam("approvalStatus") Integer approvalStatus, @RequestParam(value = "reason", required = false) String reason) {
+        log.info("StoreInfoController.approveStoreInfo?id={}&approvalStatus={}&reason={}", id, approvalStatus, reason);
+        storeInfoService.approveStoreInfo(id, approvalStatus, reason);
+        return R.success("审批完成");
+    }
+
+    @ApiOperation(value = "web端导出店铺信息")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/exportExcel")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storePhone", value = "联系电话", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "businessSection", value = "经营板块", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storeApplicationStatus", value = "审核状态", dataType = "String", paramType = "query"),})
+    public R exportExcel(@RequestParam(value = "id", required = false) String id, @RequestParam(value = "storePhone", required = false) String storePhone, @RequestParam(value = "businessSection", required = false) String businessSection, @RequestParam(value = "storeApplicationStatus", required = false) String storeApplicationStatus) throws IOException {
+        log.info("StoreInfoController.exportExcel");
+        String excelPath = storeInfoService.exportExcel(id, storePhone, businessSection, storeApplicationStatus);
+        return R.data(excelPath);
+    }
+
+    @ApiOperation(value = "web端导出商铺到期时间信息")
+    @ApiOperationSupport(order = 6)
+    @GetMapping("/exportExcelExpirationTime")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storePhone", value = "联系电话", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "businessSection", value = "经营板块", dataType = "String", paramType = "query"), @ApiImplicitParam(name = "storeApplicationStatus", value = "审核状态", dataType = "String", paramType = "query"),})
+    public R exportExcelExpirationTime(@RequestParam(value = "id", required = false) String id, @RequestParam(value = "expiredState", required = false) String expiredState) throws IOException {
+        log.info("StoreInfoController.exportExcelExpirationTime");
+        String excelPath = storeInfoService.exportExcelExpirationTime(id, expiredState);
+        return R.data(excelPath);
+    }
+
+    @ApiOperation(value = "注销店铺")
+    @ApiOperationSupport(order = 14)
+    @PostMapping("/logoutStore")
+    public R logoutStore(@RequestBody StoreInfoVo storeInfo) {
+        log.info("StoreInfoController.logoutStore?storeInfo={}", storeInfo);
+        // 2025-11-04 验证码-商家端注销店铺
+        String cacheCode = baseRedisService.getString("verification_store_cancel_store_" + storeInfo.getStorePhone());
+        if (null == cacheCode) {
+            return R.fail("当验证码过期或未发送");
+        }
+        if (!cacheCode.trim().equals(storeInfo.getVerificationCode().trim())) {
+            return R.fail("验证码错误");
+        }
+        try {
+            storeInfoService.logoutStore(storeInfo);
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
+        }
+        return R.success("注销成功");
+    }
+
+    @ApiOperation(value = "取消注销店铺")
+    @ApiOperationSupport(order = 15)
+    @PostMapping("/cancelLogoutStore")
+    public R cancelLogoutStore(@RequestBody StoreInfoVo storeInfo) {
+        log.info("StoreInfoController.cancelLogoutStore?id={}", storeInfo.getId());
+        try {
+            storeInfoService.cancelLogoutStore(storeInfo);
+        } catch (Exception e) {
+            return R.fail(e.getMessage());
+        }
+        return R.success("撤销注销成功");
+    }
+
+    /**
+     * 八大类用户端筛选
+     * 根据筛选条件获取门店信息列表
+     *
+     * @param screeningOfEightMajorCategoriesVO 筛选条件VO对象
+     * @return R<IPage < StoreInfo>> 分页的门店信息列表
+     */
+    @ApiOperation("八大类用户端筛选")
+    @PostMapping(value = "getScreening")
+    public R<IPage<StoreInfo>> getScreening(@RequestBody ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO) {
+        // 参数校验
+        if (screeningOfEightMajorCategoriesVO == null) {
+            return R.fail("筛选参数不能为空");
+        }
+        // 记录请求日志
+        log.info("八大类用户端筛选请求 - 参数: screeningId={}, lon={}, lat={}, distance={}, flag={}, pageNum={}, pageSize={}", screeningOfEightMajorCategoriesVO.getScreeningId(), screeningOfEightMajorCategoriesVO.getLon(), screeningOfEightMajorCategoriesVO.getLat(), screeningOfEightMajorCategoriesVO.getDistance(), screeningOfEightMajorCategoriesVO.getFlag(), screeningOfEightMajorCategoriesVO.getPageNum(), screeningOfEightMajorCategoriesVO.getPageSize());
+        try {
+            // 调用服务层获取筛选结果
+            IPage<StoreInfo> result = storeInfoService.getScreening(screeningOfEightMajorCategoriesVO);
+            // 记录响应日志
+            log.info("八大类用户端筛选响应 - 总记录数: {}, 当前页: {}, 页大小: {}", result.getTotal(), result.getCurrent(), result.getSize());
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            log.warn("八大类用户端筛选参数错误: {}", e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("八大类用户端筛选异常", e);
+            return R.fail("筛选失败,请稍后重试");
+        }
+    }
+
+    /**
+     * 新八大类用户端筛选
+     * 根据筛选条件获取门店信息列表
+     *
+     * @param screeningOfEightMajorCategoriesVO 筛选条件VO对象
+     * @return R<IPage < StoreInfo>> 分页的门店信息列表
+     */
+    @ApiOperation("新八大类用户端筛选")
+    @PostMapping(value = "getScreeningNew")
+    public R<IPage<StoreInfoVo>> getScreeningNew(@RequestBody ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO) {
+        // 参数校验
+        if (screeningOfEightMajorCategoriesVO == null) {
+            return R.fail("筛选参数不能为空");
+        }
+        // 记录请求日志
+        log.info("新八大类用户端筛选请求 - 参数: screeningId={}, lon={}, lat={}, distance={}, flag={}, pageNum={}, pageSize={}", screeningOfEightMajorCategoriesVO.getScreeningId(), screeningOfEightMajorCategoriesVO.getLon(), screeningOfEightMajorCategoriesVO.getLat(), screeningOfEightMajorCategoriesVO.getDistance(), screeningOfEightMajorCategoriesVO.getFlag(), screeningOfEightMajorCategoriesVO.getPageNum(), screeningOfEightMajorCategoriesVO.getPageSize());
+        try {
+            // 调用服务层获取筛选结果
+            IPage<StoreInfoVo> result = storeInfoService.getScreeningNew(screeningOfEightMajorCategoriesVO);
+            // 记录响应日志
+            log.info("新八大类用户端筛选响应 - 总记录数: {}, 当前页: {}, 页大小: {}", result.getTotal(), result.getCurrent(), result.getSize());
+
+            return R.data(result);
+        } catch (IllegalArgumentException e) {
+            log.warn("新八大类用户端筛选参数错误: {}", e.getMessage());
+            return R.fail(e.getMessage());
+        } catch (Exception e) {
+            log.error("新八大类用户端筛选异常", e);
+            return R.data(null);
+            //return R.fail("筛选失败,请稍后重试");
+        }
+    }
+
+
+    /**
+     * 八大类用户端经营类型筛选
+     *
+     * @param businessTypesNames 经营类型名称,多个类型用逗号分隔
+     * @return R<List < StoreInfo>> 筛选结果
+     */
+    @ApiOperation("八大类用户端经营类型筛选")
+    @ApiOperationSupport(order = 13)
+    @ApiImplicitParams({@ApiImplicitParam(name = "businessTypesNames", value = "经营类型名称,多个类型用逗号分隔", dataType = "String", paramType = "query")})
+    @GetMapping(value = "getBusinessTypesName")
+    public R<List<StoreInfo>> getBusinessTypesName(@RequestParam(value = "businessTypesNames", required = false) String businessTypesNames) {
+        log.info("StoreInfoController.getBusinessTypesName?businessTypesNames={}", businessTypesNames);
+        try {
+            List<StoreInfo> result = storeInfoService.getBusinessTypesName(businessTypesNames);
+            return R.data(result);
+        } catch (Exception e) {
+            log.error("八大类用户端经营类型筛选失败", e);
+            return R.fail("筛选失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * web-查询店铺信息根据门店电话
+     *
+     * @param storeTel 门店电话
+     * @return R
+     */
+    @ApiOperation("web-查询店铺信息根据门店电话")
+    @ApiOperationSupport(order = 14)
+    @GetMapping("/getStoreInfoByStoreTel")
+    public R<List<StoreInfo>> getStoreInfoByCreateUser(@RequestParam(value = "storeTel") String storeTel) {
+        log.info("StoreInfoController.getStoreInfoByStoreTel?storeTel={}", storeTel);
+        return R.data(storeInfoService.getStoreInfoByStoreTel(storeTel));
+    }
+
+    /**
+     * 商家端注销店铺效验
+     *
+     * @param id 门店id
+     */
+    @ApiOperation("商家端注销店铺效验")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "int", paramType = "query", required = true)})
+    @GetMapping("/storeInfoVerification")
+    public R<Map<String, String>> storeInfoVerification(int id) {
+        log.info("StoreInfoController.storeInfoVerification?id={}", id);
+        return R.data(storeInfoService.storeInfoVerification(id));
+    }
+
+    /**
+     * 手动删除店铺
+     */
+    @ApiOperation("手动删除店铺")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "int", paramType = "query", required = true)})
+    @GetMapping("/deleteManualStoreInfo")
+    public R<StoreUserVo> deleteManualStoreInfo(int id) {
+        log.info("StoreUserController.deleteManualStoreInfo?id={}", id);
+        storeInfoService.deleteManualStoreInfo(id);
+        return R.success("删除成功");
+    }
+
+    @ApiOperation(value = "门店装修-详细信息")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getDecorationDetail")
+    public R<StoreMainInfoVo> getDecorationDetail(Integer id) {
+        log.info("StoreInfoController.getDecorationDetail?id={}", id);
+        return R.data(storeInfoService.getDecorationDetail(id));
+    }
+
+    @ApiOperation(value = "门店装修-门店营业时间")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getStoreInfoBusinessHours")
+    public R<List<StoreBusinessInfo>> getStoreInfoBusinessHours(Integer id) {
+        log.info("StoreInfoController.getStoreInfoBusinessHours?id={}", id);
+        return R.data(storeInfoService.getStoreInfoBusinessHours(id));
+    }
+
+    @ApiOperation(value = "门店装修-续签合同")
+    @PostMapping("/uploadRenewalContract")
+    public R<String> uploadRenewalContract(@RequestBody List<StoreImg> storeImgList) {
+        log.info("StoreInfoController.uploadRenewalContract?storeImgList={}", storeImgList);
+        int num = storeInfoService.uploadRenewalContract(storeImgList);
+        if (num <= 0) {
+            return R.fail("续签合同图片添加失败");
+        }
+        return R.success("续签合同图片添加成功");
+    }
+
+    @ApiOperation(value = "门店装修-续签合同状态及合同图片")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "int", paramType = "query", required = true)})
+    @GetMapping("/getStoreContractStatus")
+    public R<Map<String, Object>> getStoreContractStatus(int id) {
+        log.info("StoreInfoController.getStoreContractStatus?id={}", id);
+        return R.data(storeInfoService.getStoreContractStatus(id));
+    }
+
+    @ApiOperation(value = "门店装修-审核续签合同状态")
+    @PostMapping("/updateContractImageStatus")
+    public R<String> updateContractImageStatus(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.updateContractImageStatus?storeInfoDto={}", storeInfoDto);
+        StoreInfo storeInfo = storeInfoService.getOne(new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, storeInfoDto.getId()));
+        if (storeInfo != null) {
+            if (storeInfoDto.getRenewContractStatus() == 3) {
+                storeInfo.setContractReason(storeInfoDto.getContractReason());
+                storeInfo.setRenewContractStatus(storeInfoDto.getRenewContractStatus());
+                boolean flag = storeInfoService.updateById(storeInfo);
+                if (flag) {
+                    return R.success("拒绝审核成功");
+                } else {
+                    return R.fail("拒绝审核失败");
+                }
+            }
+            storeInfo.setRenewContractStatus(storeInfoDto.getRenewContractStatus());
+            storeInfo.setContractReason(storeInfoDto.getContractReason());
+            boolean flag = storeInfoService.updateById(storeInfo);
+            if (flag) {
+                //审核通过后删除原店铺合同 续签合同类型变为合同
+                int num = storeInfoService.conversionContract(storeInfoDto.getId());
+                if (num > 0) {
+                    return R.success("审核通过成功");
+                } else {
+                    return R.fail("审核通过失败");
+                }
+            }
+        }
+        return R.fail("审核失败 店铺不存在");
+    }
+
+    @ApiOperation(value = "门店装修-食品经营许可证")
+    @PostMapping("/uploadfoodLicence")
+    public R<String> uploadfoodLicence(@RequestBody StoreImg storeImg) {
+        log.info("StoreInfoController.uploadfoodLicence?storeImg={}", storeImg);
+        int num = storeInfoService.uploadfoodLicence(storeImg);
+        if (num > 0) {
+            WebAudit webAudit = new WebAudit();
+            webAudit.setStoreInfoId(storeImg.getStoreId().toString());
+            webAudit.setType("7");
+            webAudit.setStatus("0");
+            webAudit.setContent("经营许可证");
+            webAuditMapper.insert(webAudit);
+            return R.success("食品经营许可证图片添加成功");
+        }
+        return R.fail("食品经营许可证图片添加失败");
+    }
+
+    @ApiOperation(value = "门店装修-食品经营许可证状态及合同图片")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "int", paramType = "query", required = true)})
+    @GetMapping("/getStoreFoodLicenceStatus")
+    public R<Map<String, Object>> getStoreFoodLicenceStatus(int id) {
+        log.info("StoreInfoController.getStoreFoodLicenceStatus?id={}", id);
+        return R.data(storeInfoService.getStoreFoodLicenceStatus(id));
+    }
+
+    @ApiOperation(value = "门店装修-审核食品经营许可证状态")
+    @PostMapping("/updatefoodLicenceImageStatus")
+    public R<String> updatefoodLicenceImageStatus(@RequestBody StoreInfoDto storeInfoDto) {
+        log.info("StoreInfoController.updatefoodLicenceImageStatus?storeInfoDto={}", storeInfoDto);
+        StoreInfo storeInfo = storeInfoService.getOne(new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, storeInfoDto.getId()));
+        if (storeInfo != null) {
+            if (storeInfoDto.getFoodLicenceStatus() == 3) {
+                storeInfo.setFoodLicenceReason(storeInfoDto.getFoodLicenceReason());
+                storeInfo.setFoodLicenceStatus(storeInfoDto.getFoodLicenceStatus());
+                boolean flag = storeInfoService.updateById(storeInfo);
+                if (flag) {
+                    // 审核拒绝时修改提交记录
+                    LambdaUpdateWrapper<StoreLicenseHistory> wrapper = new LambdaUpdateWrapper<>();
+                    wrapper.eq(StoreLicenseHistory::getStoreId, storeInfo.getId());
+                    wrapper.eq(StoreLicenseHistory::getLicenseStatus, 2);
+                    wrapper.set(StoreLicenseHistory::getLicenseExecuteStatus, 3);
+                    wrapper.set(StoreLicenseHistory::getDeleteFlag, 1);
+                    licenseHistoryMapper.update(null, wrapper);
+
+                    //待审核状态变为已审核
+                    WebAudit webAudit = webAuditMapper.selectOne(new LambdaQueryWrapper<WebAudit>().eq(WebAudit::getStoreInfoId, storeInfo.getId()).eq(WebAudit::getDeleteFlag, 0).eq(WebAudit::getType, "7"));
+                    if (webAudit != null) {
+                        webAudit.setStatus("1");
+                        webAuditMapper.updateById(webAudit);
+                    }
+                    return R.success("拒绝审核成功");
+                } else {
+                    return R.fail("拒绝审核失败");
+                }
+            }
+            storeInfo.setFoodLicenceReason(storeInfoDto.getFoodLicenceReason());
+            storeInfo.setFoodLicenceStatus(storeInfoDto.getFoodLicenceStatus());
+            boolean flag = storeInfoService.updateById(storeInfo);
+            if (flag) {
+                int num = storeInfoService.foodLicenceType(storeInfoDto.getId());
+                if (num > 0) {
+                    //待审核状态变为已审核
+                    WebAudit webAudit = webAuditMapper.selectOne(new LambdaQueryWrapper<WebAudit>().eq(WebAudit::getStoreInfoId, storeInfo.getId()).eq(WebAudit::getDeleteFlag, 0).eq(WebAudit::getType, "7"));
+                    if (webAudit != null) {
+                        webAudit.setStatus("1");
+                        webAuditMapper.updateById(webAudit);
+                    }
+                }
+                return R.success("审核通过成功");
+            } else {
+                return R.fail("审核失败");
+            }
+        }
+        return R.fail("审核失败 店铺不存在");
+    }
+
+    @ApiOperation(value = "AI服务-门店评价标签")
+    @GetMapping("/getStoreEvaluateTags")
+    @ApiImplicitParams({@ApiImplicitParam(name = "storeId", value = "门店id", dataType = "int", paramType = "query")})
+    public R<List<TagsMainVo>> getStoreEvaluateTags(int storeId) {
+        log.info("StoreInfoController.getStoreEvaluateTags?storeId={}", storeId);
+        List<TagsMainVo> voList = tagsMainMapper.getStoreEvaluateTags(storeId);
+        return R.data(voList);
+    }
+
+    @ApiOperation(value = "AI服务-门店趣味信息")
+    @GetMapping("/getStoreInterestInfo")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "int", paramType = "query")
+    })
+    public R<List<StoreCommentSummaryInterest>> getStoreInterestInfo(int storeId) {
+        log.info("StoreInfoController.getStoreInterestInfo?storeId={}", storeId);
+        List<StoreCommentSummaryInterest> list = storeCommentSummaryInterestMapper.selectList(new LambdaQueryWrapper<StoreCommentSummaryInterest>().eq(StoreCommentSummaryInterest :: getStoreId, storeId));
+        return R.data(list);
+    }
+
+}

+ 11 - 4
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformInfoController.java

@@ -1,15 +1,13 @@
 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 io.swagger.annotations.*;
 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.entity.store.vo.StoreMainInfoVo;
 import shop.alien.storeplatform.service.StorePlatformInfoService;
 
 @Slf4j
@@ -39,4 +37,13 @@ public class StorePlatformInfoController {
         }
     }
 
+    @ApiOperation(value = "门店详细信息")
+    @ApiOperationSupport(order = 5)
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getDetail")
+    public R<StoreMainInfoVo> getDetail(Integer id) {
+        log.info("StoreInfoController.getDetail?id={}", id);
+        return R.data(storePlatformInfoService.getDetail(id));
+    }
+
 }

+ 1 - 1
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformMenuController.java

@@ -18,7 +18,7 @@ import java.util.List;
  * @since 2024-12-05
  */
 @Slf4j
-@Api(tags = {"二期-门店菜单"})
+@Api(tags = {"商户平台-门店菜单"})
 @ApiSort(4)
 @CrossOrigin
 @RestController

+ 2 - 2
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformOfficialAlbumController.java

@@ -21,11 +21,11 @@ import java.util.List;
  * @since 2025-07-16
  */
 @Slf4j
-@Api(tags = {"二期-官方相册"})
+@Api(tags = {"商户平台-官方相册"})
 @ApiSort(1)
 @CrossOrigin
 @RestController
-@RequestMapping("/store/official")
+@RequestMapping("/storePlatformOfficial")
 @RequiredArgsConstructor
 public class StorePlatformOfficialAlbumController {
     private final StorePlatformOfficialAlbumService storeOfficialAlbumService;

+ 12 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/controller/StorePlatformRenovationController.java

@@ -5,8 +5,10 @@ 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.StoreBusinessInfo;
 import shop.alien.entity.store.vo.StoreDictionaryVo;
 import shop.alien.entity.store.vo.StoreMainInfoVo;
+import shop.alien.storeplatform.service.StorePlatformInfoService;
 import shop.alien.storeplatform.service.StorePlatformRenovationService;
 
 import java.util.ArrayList;
@@ -23,6 +25,8 @@ public class StorePlatformRenovationController {
 
     private final StorePlatformRenovationService storePlatformRenovationService;
 
+    private final StorePlatformInfoService storePlatformInfoService;
+
     @ApiOperation(value = "web端查询经营板块信息")
     @ApiOperationSupport(order = 6)
     @GetMapping("/getBusinessSection")
@@ -47,4 +51,12 @@ public class StorePlatformRenovationController {
         return R.data(storePlatformRenovationService.getDecorationDetail(id));
     }
 
+    @ApiOperation(value = "门店装修-门店营业时间")
+    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "门店id", dataType = "Long", paramType = "query", required = true)})
+    @GetMapping("/getStoreInfoBusinessHours")
+    public R<List<StoreBusinessInfo>> getStoreInfoBusinessHours(Integer id) {
+        log.info("StoreInfoController.getStoreInfoBusinessHours?id={}", id);
+        return R.data(storePlatformInfoService.getStoreInfoBusinessHours(id));
+    }
+
 }

+ 282 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/StoreBusinessService.java

@@ -0,0 +1,282 @@
+package shop.alien.storeplatform.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.entity.store.StoreBusinessInfo;
+import shop.alien.entity.store.StoreImg;
+import shop.alien.entity.store.StoreInfo;
+import shop.alien.entity.store.StoreInfoDraft;
+import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.entity.store.vo.*;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 二期-门店信息 服务类
+ *
+ * @author ssk
+ * @since 2024-12-05
+ */
+public interface StoreBusinessService extends IService<StoreInfo> {
+
+    /**
+     * 门店详情
+     *
+     * @param id 门店id
+     * @return StoreMainInfoVo
+     */
+    StoreMainInfoVo getDetail(Integer id);
+
+    /**
+     * 门店装修详情
+     * @param id 门店id
+     * @param id 门店id
+     */
+    StoreMainInfoVo getDecorationDetail(Integer id);
+
+    /**
+     *
+     */
+    List<StoreBusinessInfo>  getStoreInfoBusinessHours(Integer id);
+
+    /**
+     * 门店信息-修改后展示
+     *
+     * @param id 门店id
+     * @return StoreMainInfoVo
+     */
+    StoreMainInfoVo getStoreInfo(Integer id);
+
+    /**
+     * web-分页查询店铺信息
+     *
+     * @param page         页码
+     * @param size         页容
+     * @param storeName    门店名称
+     * @param storeContact 联系人
+     * @param storePhone   门店电话
+     * @param storeType    门店类型
+     * @return IPage<StoreInfoVo>
+     */
+    IPage<StoreInfoVo> getStorePage(int page, int size, String storeName, String storeContact, String id, String storePhone, String storeType, String expiredState, String storeApplicationStatus, String storeStatus, String businessSection, String jingdu, String weidu, String renewContractStatus, String foodLicenceStatus, String foodLicenceWhetherExpiredStatus);
+
+    /**
+     * web-重置门店密码
+     *
+     * @param storeId 门店id
+     * @return boolean
+     */
+    boolean resetPassword(String storeId);
+
+    /**
+     * web-修改门店状态
+     *
+     * @param storeId        门店id
+     * @param businessStatus 营业状态
+     * @return boolean
+     */
+    boolean setStoreState(String storeId, Integer businessStatus);
+
+    /**
+     * web-新增店铺
+     *
+     * @param multipartRequest 文件请求
+     * @param store            店铺信息
+     * @return boolean
+     */
+    boolean saveStore(MultipartRequest multipartRequest, StoreInfo store);
+
+    /**
+     * 导出Excel
+     *
+     * @return ResponseEntity
+     */
+    ResponseEntity<byte[]> exportToExcel();
+
+    /**
+     * web端新增门店及门店用户
+     *
+     * @return ResponseEntity
+     */
+    StoreInfoVo saveStoreInfo(StoreInfoDto storeInfoDto) throws Exception;
+
+    /**
+     * 新增店铺草稿
+     *
+     * @param storeInfoDraft
+     * @return
+     */
+    int saveStoreInfoDraft(StoreInfoDraft storeInfoDraft);
+
+    /**
+     * 查询草稿信息
+     *
+     * @param storeUserId
+     * @return
+     */
+    StoreInfoDraft selectDraftByUserId(int storeUserId);
+
+    /**
+     * web端修改门店及门店用户
+     *
+     * @return ResponseEntity
+     */
+    StoreInfoVo editStoreInfo(StoreInfoDto storeInfoDto);
+
+    /**
+     * web端删除门店及门店用户
+     *
+     * @return ResponseEntity
+     */
+    String deleteStoreInfo(StoreInfoDto storeInfoDto);
+
+    /**
+     * web端删除门店及门店用户
+     *
+     * @return ResponseEntity
+     */
+    void restPassword(StoreInfoDto storeInfoDto);
+
+    /**
+     * web端查询经营板块信息
+     */
+    List<StoreDictionaryVo> getBusinessSection();
+
+    /**
+     * web端查询经营板块的经营种类信息
+     */
+    List<StoreDictionaryVo> getBusinessSectionTypes(String parentId);
+
+    /**
+     * web端查询未绑定的账号信息
+     */
+    List<StoreUserVo> getUnboundAccountList(String id);
+
+    /**
+     * web端新增经营板块及经营类型
+     */
+    void addBusinessSectionAndTypes(StoreInfoDto storeInfoDto);
+
+    /**
+     * web端查询门店明细
+     */
+    StoreInfoVo getStoreDetail(String storeId, String userId, String jingdu, String weidu);
+
+    /**
+     * web端审批结果
+     */
+    void approveStoreInfo(String storeId, Integer approvalStatus, String reason);
+
+    /**
+     * web端导出商铺信息结果
+     */
+    String exportExcel(String id, String storePhone, String businessSection, String storeApplicationStatus) throws IOException;
+
+    /**
+     * web端导出商铺到期时间信息
+     */
+    String exportExcelExpirationTime(String id, String expiredState) throws IOException;
+
+    /**
+     * 八大类用户端筛选
+     */
+    IPage<StoreInfo> getScreening(ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO);
+    IPage<StoreInfoVo> getScreeningNew(ScreeningOfEightMajorCategoriesVO screeningOfEightMajorCategoriesVO);
+
+    List<StoreInfo> getBusinessTypesName(String businessTypesNames);
+
+    /**
+     * 注销店铺
+     *
+     * @param storeInfo 店铺Vo
+     * @return boolean
+     */
+    void logoutStore(StoreInfoVo storeInfo);
+
+    /**
+     * 取消注销店铺
+     *
+     * @param storeInfo 店铺Vo
+     * @return boolean
+     */
+    void cancelLogoutStore(StoreInfoVo storeInfo);
+
+    /**
+     * web-查询店铺信息根据门店电话
+     *
+     * @param storeTel 门店电话
+     * @return List<StoreInfo>
+     */
+    List<StoreInfo> getStoreInfoByStoreTel(String storeTel);
+
+    /**
+     * 修改店铺佣金比率
+     *
+     * @param storeInfoDto
+     * @return
+     */
+    int editStoreCommissionRate(StoreInfoDto storeInfoDto);
+
+    /**
+     * 门店装修 - 编辑
+     * @param storeInfo
+     * @return
+     */
+    int saveOrUpdateStoreInfo(StoreInfoDto storeInfo);
+
+    /**
+     * 商家注销店铺效验
+     */
+    Map<String,String> storeInfoVerification(int id);
+
+    /**
+     * 手动删除店铺
+     * @param id
+     */
+    void deleteManualStoreInfo(int id);
+
+    /**
+     * 店铺续签合同
+     *
+     */
+    int uploadRenewalContract(List<StoreImg> storeImgList);
+
+    /**
+     * 店铺食品经营许可证
+     * @param storeImg
+     * @return
+     */
+    int uploadfoodLicence(StoreImg storeImg);
+
+    /**
+     * 获取店铺续签合同状态以及店铺状态为审核中合同图片list
+     *
+     */
+    Map<String,Object> getStoreContractStatus(int id);
+
+    /**
+     * 获取店铺食品经营许可证状态以及店铺状态为审核中合同图片list
+     * @param id
+     * @return
+     */
+    Map<String,Object> getStoreFoodLicenceStatus(int id);
+
+    int updateStoreImgModeInfo(StoreImgInfoVo storeImgInfoVo);
+
+
+    /**
+     * 审核通过续签合同转为正常合同删除之前合同
+     *
+     */
+    int conversionContract(int id);
+
+    /**
+     * 经营许可证审核通过后 图片类型变为审核通过后 img_type25
+     *
+     */
+    int foodLicenceType(int id);
+}

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

@@ -1,8 +1,12 @@
 package shop.alien.storeplatform.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.store.StoreBusinessInfo;
 import shop.alien.entity.store.StoreInfo;
 import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.entity.store.vo.StoreMainInfoVo;
+
+import java.util.List;
 
 public interface StorePlatformInfoService extends IService<StoreInfo> {
 
@@ -13,4 +17,14 @@ public interface StorePlatformInfoService extends IService<StoreInfo> {
      */
     int saveOrUpdateStoreInfo(StoreInfoDto storeInfo);
 
+    List<StoreBusinessInfo> getStoreInfoBusinessHours(Integer id);
+
+    /**
+     * 门店详情
+     *
+     * @param id 门店id
+     * @return StoreMainInfoVo
+     */
+    StoreMainInfoVo getDetail(Integer id);
+
 }

+ 2288 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StoreBusinessServiceImpl.java

@@ -0,0 +1,2288 @@
+package shop.alien.storeplatform.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.geo.Point;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.config.redis.BaseRedisService;
+import shop.alien.entity.store.*;
+import shop.alien.entity.store.dto.NearMeDto;
+import shop.alien.entity.store.dto.StoreInfoDto;
+import shop.alien.entity.store.excelVo.StoreInfoExcelVo;
+import shop.alien.entity.store.excelVo.StoreInfoExpiredRecordsExcelVo;
+import shop.alien.entity.store.excelVo.util.ExcelExporter;
+import shop.alien.entity.store.excelVo.util.ExcelGenerator;
+import shop.alien.entity.store.vo.*;
+import shop.alien.entity.storePlatform.StoreLicenseHistory;
+import shop.alien.mapper.*;
+import shop.alien.mapper.storePlantform.StoreLicenseHistoryMapper;
+import shop.alien.storeplatform.config.GaoDeMapUtil;
+import shop.alien.storeplatform.service.NearMeService;
+import shop.alien.storeplatform.service.StoreBusinessService;
+import shop.alien.storeplatform.util.FileUploadUtil;
+import shop.alien.util.ali.AliOSSUtil;
+import shop.alien.util.common.DistanceUtil;
+import shop.alien.util.common.constant.CouponStatusEnum;
+import shop.alien.util.common.constant.CouponTypeEnum;
+import shop.alien.util.common.constant.OrderStatusEnum;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 二期-门店信息 服务实现类
+ *
+ * @author ssk
+ * @since 2024-12-05
+ */
+@Service
+@RequiredArgsConstructor
+@Transactional
+public class StoreBusinessServiceImpl extends ServiceImpl<StoreInfoMapper, StoreInfo> implements StoreBusinessService {
+
+    private final String DEFAULT_PASSWORD = "123456";
+
+    private final StoreInfoMapper storeInfoMapper;
+
+    private final StoreImgMapper storeImgMapper;
+
+    private final StoreBusinessInfoMapper storeBusinessInfoMapper;
+
+    private final StoreLabelMapper storeLabelMapper;
+
+    private final StoreMenuMapper storeMenuMapper;
+
+    private final StoreUserMapper storeUserMapper;
+
+    private final FileUploadUtil fileUploadUtil;
+
+    private final StoreDictionaryMapper storeDictionaryMapper;
+
+    private final GaoDeMapUtil gaoDeMapUtil;
+
+    private final BaseRedisService baseRedisService;
+
+    private final TagStoreRelationMapper tagStoreRelationMapper;
+
+    private final NearMeService nearMeService;
+
+    private final WebAuditMapper webAuditMapper;
+
+    private final EssentialCityCodeMapper essentialCityCodeMapper;
+
+    private final LifeCouponMapper lifeCouponMapper;
+
+    private final StoreEvaluationMapper storeEvaluationMapper;
+
+    private final LifeUserOrderMapper lifeUserOrderMapper;
+
+    private final LifeCollectMapper lifeCollectMapper;
+
+    private final StoreStaffConfigMapper storeStaffConfigMapper;
+
+    private final StoreClockInMapper storeClockInMapper;
+
+    private final LifeUserDynamicsMapper lifeUserDynamicsMapper;
+
+    private final StoreCommentMapper storeCommentMapper;
+
+    private final StoreInfoDraftMapper storeInfoDraftMapper;
+
+    private final LifeNoticeMapper lifeNoticeMapper;
+
+    private final LifeGroupBuyMainMapper lifeGroupBuyMainMapper;
+
+
+    private final AliOSSUtil aliOSSUtil;
+
+
+    private final LifeFansMapper lifeFansMapper;
+
+    private final LifeBlacklistMapper lifeBlacklistMapper;
+
+    /** 商户证照历史记录数据访问对象 */
+    private final StoreLicenseHistoryMapper licenseHistoryMapper;
+
+
+    @Value("${spring.web.resources.excel-path}")
+    private String excelPath;
+
+    @Value("${spring.web.resources.excel-generate-path}")
+    private String excelGeneratePath;
+
+    /**
+     * 懒得查, 留着导出Excel
+     */
+    List<StoreInfoVo> toExcel = new ArrayList<>();
+    private final LifeUserMapper lifeUserMapper;
+
+    /**
+     * 门店详情
+     *
+     * @return StoreMainInfoVo
+     */
+    @Override
+    public StoreMainInfoVo getDetail(Integer id) {
+
+        StoreInfo storeInfo = storeInfoMapper.selectById(id);
+        if(storeInfo == null){
+             return null;
+        }
+        StoreMainInfoVo storeMainInfoVo = storeInfoMapper.getStoreInfo(id);
+
+        //判断门店是否到期
+        if (ObjectUtils.isNotEmpty(storeMainInfoVo.getExpirationTime())) {
+            if (new Date().after(storeMainInfoVo.getExpirationTime())) {
+                storeMainInfoVo.setExpirationFlag(0);
+            }else {
+                storeMainInfoVo.setExpirationFlag(1);
+            }
+        }else {
+            storeMainInfoVo.setExpirationFlag(1);
+        }
+
+        //存入门店地址、
+        storeMainInfoVo.setStoreAddress(storeInfo.getStoreAddress());
+        //入口图
+        LambdaQueryWrapper<StoreImg> inletsUrlQueryWrapper = new LambdaQueryWrapper<>();
+        inletsUrlQueryWrapper.eq(StoreImg::getImgType, 1);
+        inletsUrlQueryWrapper.eq(StoreImg::getStoreId, id);
+        List<StoreImg> inletsUrlList = storeImgMapper.selectList(inletsUrlQueryWrapper);
+        storeMainInfoVo.setInletsUrl(inletsUrlList.stream().sorted(Comparator.comparing(StoreImg::getImgSort)).map(StoreImg::getImgUrl).collect(Collectors.toList()));
+        //相册
+        LambdaQueryWrapper<StoreImg> albumUrlQueryWrapper = new LambdaQueryWrapper<>();
+        albumUrlQueryWrapper.eq(StoreImg::getImgType, 2);
+        albumUrlQueryWrapper.eq(StoreImg::getStoreId, id);
+        List<StoreImg> albumUrlList = storeImgMapper.selectList(albumUrlQueryWrapper);
+        storeMainInfoVo.setAlbumUrl(albumUrlList.stream().sorted(Comparator.comparing(StoreImg::getImgSort)).map(StoreImg::getImgUrl).collect(Collectors.toList()));
+        //推荐菜
+        storeMainInfoVo.setRecommendUrl(storeMenuMapper.getStoreMenuList(id, 1).stream().sorted(Comparator.comparing(StoreMenuVo::getImgSort)).collect(Collectors.toList()));
+        //菜单
+        storeMainInfoVo.setMenuUrl(storeMenuMapper.getStoreMenuList(id, 0).stream().sorted(Comparator.comparing(StoreMenuVo::getImgSort)).collect(Collectors.toList()));
+        //门店标签
+        storeMainInfoVo.setStoreLabel(storeLabelMapper.selectOne(new LambdaQueryWrapper<StoreLabel>().eq(StoreLabel::getStoreId, id)));
+        //营业时间
+        storeMainInfoVo.setStoreBusinessInfo(storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id)));
+        //门店头像
+        LambdaQueryWrapper<StoreImg> eq = new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 10).eq(StoreImg::getStoreId, id);
+        StoreImg storeImg = storeImgMapper.selectOne(eq);
+        storeMainInfoVo.setHeadImgUrl(storeImg != null ? storeImg.getImgUrl() : "");
+        List<StoreUser> storeUsers = storeUserMapper.selectList(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()));
+        for (StoreUser storeUser : storeUsers) {
+            storeMainInfoVo.setLogoutFlagUser(storeUser.getLogoutFlag());
+        }
+        // 计算店铺到最近地铁站的距离
+        JSONObject nearbySubway = gaoDeMapUtil.getNearbySubway(storeMainInfoVo.getStorePosition().split(",")[0], storeMainInfoVo.getStorePosition().split(",")[1]);
+        // 地铁名
+        String subWayName = nearbySubway.getString("name");
+        storeMainInfoVo.setSubwayName(subWayName);
+        // 地铁站经纬度
+        String subWayJing = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[0];
+        String subWayWei = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[1];
+        if ((subWayJing != null && !subWayJing.isEmpty()) && (subWayWei != null && !subWayWei.isEmpty())) {
+            double storeJing = Double.parseDouble(storeMainInfoVo.getStorePosition().split(",")[0]);
+            double storeWei = Double.parseDouble(storeMainInfoVo.getStorePosition().split(",")[1]);
+            double storeDistance2 = DistanceUtil.haversineCalculateDistance(Double.parseDouble(subWayJing), Double.parseDouble(subWayWei), storeJing, storeWei);
+            storeMainInfoVo.setDistance2(storeDistance2);
+        } else {
+            storeMainInfoVo.setDistance2(0);
+        }
+        return storeMainInfoVo;
+    }
+
+    @Override
+    public StoreMainInfoVo getDecorationDetail(Integer id) {
+        StoreInfo storeInfo = storeInfoMapper.selectById(id);
+        StoreMainInfoVo storeMainInfoVo = storeInfoMapper.getStoreInfo(id);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        String expirationDate = sdf.format(storeMainInfoVo.getExpirationTime());
+        storeMainInfoVo.setExpirationDate(expirationDate);
+        //审核通过给前台反显未提交
+        if (storeMainInfoVo.getRenewContractStatus() == 1) {
+            storeMainInfoVo.setRenewContractStatus(0);
+        }
+        if (storeMainInfoVo.getStoreStatus() == -1) {
+            LocalDateTime localDateTime = storeMainInfoVo.getLogoutTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+            LocalDateTime future = localDateTime.plusDays(7);
+            LocalDateTime now = LocalDateTime.now();
+            Duration duration = Duration.between(now, future);
+            long correct = duration.toMillis();
+            storeMainInfoVo.setCountdown(correct);
+        }
+        //存入门店地址
+        storeMainInfoVo.setStoreAddress(storeInfo.getStoreAddress());
+        //经营种类
+        if (storeInfo.getBusinessTypes() != null) {
+            String[] strings = storeInfo.getBusinessTypes().split(",");
+            storeMainInfoVo.setBusinessTypesList(Arrays.stream(strings).collect(Collectors.toList()));
+        }
+        //门店标签
+        storeMainInfoVo.setStoreLabel(storeLabelMapper.selectOne(new LambdaQueryWrapper<StoreLabel>().eq(StoreLabel::getStoreId, id)));
+        //营业时间
+        List<StoreBusinessInfo> storeBusinessInfoList = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id));
+        storeMainInfoVo.setStoreBusinessInfo(storeBusinessInfoList);
+        //营业执照
+        storeMainInfoVo.setBusinessLicenseList(storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 14).eq(StoreImg::getStoreId, id)));
+        //合同照片
+        storeMainInfoVo.setContractList(storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 15).eq(StoreImg::getStoreId, id)));
+        //经营许可证图片照片
+        storeMainInfoVo.setFoodLicenceList(storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 25).eq(StoreImg::getStoreId, id)));
+        //是否连锁
+        String isChain = (storeInfo.getIsChain() == 0) ? "否" : "是";
+        storeMainInfoVo.setIsChainStr(isChain);
+        storeMainInfoVo.setFoodLicenceExpirationTime(storeInfo.getFoodLicenceExpirationTime());
+        return storeMainInfoVo;
+    }
+
+    @Override
+    public List<StoreBusinessInfo> getStoreInfoBusinessHours(Integer id) {
+        //营业时间
+        List<StoreBusinessInfo> storeBusinessInfoList = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id));
+        return storeBusinessInfoList;
+    }
+
+    /**
+     * 门店信息-修改后展示
+     *
+     * @param id 门店id
+     * @return StoreMainInfoVo
+     */
+    @Override
+    public StoreMainInfoVo getStoreInfo(Integer id) {
+        StoreMainInfoVo storeMainInfoVo = storeInfoMapper.getStoreInfo(id);
+        //门店标签
+        storeMainInfoVo.setStoreLabel(storeLabelMapper.selectOne(new LambdaQueryWrapper<StoreLabel>().eq(StoreLabel::getStoreId, id)));
+        //营业时间
+        storeMainInfoVo.setStoreBusinessInfo(storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id)));
+        return storeMainInfoVo;
+    }
+
+
+    /**
+     * web-分页查询店铺信息
+     *
+     * @param page         页码
+     * @param size         页容
+     * @param storeName    门店名称
+     * @param storeContact 联系人
+     * @param storePhone   门店电话
+     * @param storeType    门店类型
+     * @return IPage<StoreInfoVo>
+     */
+    @Override
+    public IPage<StoreInfoVo> getStorePage(int page, int size, String storeName, String storeContact, String id, String storePhone, String storeType, String expiredState, String storeApplicationStatus, String storeStatus, String businessSection, String jingdu, String weidu, String renewContractStatus, String foodLicenceStatus, String foodLicenceWhetherExpiredStatus) {
+        checkAndUpdateExpiredRecords();
+        IPage<StoreInfoVo> iPage = new Page<>(page, size);
+        QueryWrapper<StoreInfoVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.like(storeName != null && !storeName.isEmpty(), "a.store_name", storeName).like(storeContact != null && !storeContact.isEmpty(), "b.name", storeContact).like(storePhone != null && !storePhone.isEmpty(), "b.phone", storePhone).like(storeType != null && !storeType.isEmpty(), "a.store_type", storeType).eq(StringUtils.isNotEmpty(storeApplicationStatus), "a.store_application_status", storeApplicationStatus).eq(StringUtils.isNotEmpty(businessSection), "a.business_section", businessSection).eq(StringUtils.isNotEmpty(storeStatus), "a.store_status", storeStatus).eq(StringUtils.isNotEmpty(renewContractStatus), "a.renew_contract_status", renewContractStatus).eq(StringUtils.isNotEmpty(foodLicenceStatus), "a.food_licence_status", foodLicenceStatus).like(StringUtils.isNotEmpty(id), "a.id", id).eq("a.delete_flag", 0).eq("b.delete_flag", 0).orderByDesc("a.created_time");
+        //如果查询未过期
+        // 获取当前时刻
+        Date currentDate = new Date();
+        // 获取当前日期和时间
+        Calendar calendar = Calendar.getInstance();
+        // 将时间设置为 0 点
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        // 加上 30 天
+        calendar.add(Calendar.DAY_OF_MONTH, 30);
+        // 获取 Date 对象
+        Date thirtyDaysAgo = calendar.getTime();
+        if ("0".equals(expiredState)) {
+            queryWrapper.ge("a.expiration_time", thirtyDaysAgo);
+        } else if ("1".equals(expiredState)) {
+            queryWrapper.lt("a.expiration_time", thirtyDaysAgo);
+            queryWrapper.ge("a.expiration_time", currentDate);
+        } else if ("2".equals(expiredState)) {
+            queryWrapper.lt("a.expiration_time", currentDate);
+        }
+        // 获取当前时间
+        LocalDate nowDay = LocalDate.now();
+        IPage<StoreInfoVo> storeInfoVoPage = storeInfoMapper.getStoreInfoVoPage(iPage, queryWrapper);
+        List<StoreInfoVo> records = storeInfoVoPage.getRecords();
+        if (!records.isEmpty()) {
+            // 提前查询所有需要的字典数据
+            List<StoreInfoVo> collect = records.stream().filter(record -> StringUtils.isNotEmpty(record.getStoreType())).collect(Collectors.toList());
+            Set<String> allTypes = collect.stream().map(StoreInfoVo::getStoreType).flatMap(type -> Arrays.stream(type.split(","))).collect(Collectors.toSet());
+
+            List<StoreDictionary> storeDictionaries = storeDictionaryMapper.selectList(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getTypeName, "storeType").isNull(StoreDictionary::getParentId).in(!allTypes.isEmpty(), StoreDictionary::getDictId, allTypes));
+            Map<String, String> typeMap = storeDictionaries.stream().collect(Collectors.toMap(StoreDictionary::getDictId, StoreDictionary::getDictDetail));
+
+            Map<String, List<LifeCoupon>> quanListByStoreId = new HashMap<>();
+            Map<Object, List<Map<String, Object>>> avgScoreMap = new HashMap<>();
+            Map<Object, List<Map<String, Object>>> avgPriceMap = new HashMap<>();
+            Map<Integer, List<StoreComment>> commentMap = new HashMap<>();
+            // 如果获取美食列表进行以下前置操作
+            if (StringUtils.isNotEmpty(businessSection) && businessSection.equals("1")) {
+                List<Integer> storeIds = records.stream().map(StoreInfoVo::getId).collect(Collectors.toList());
+                LambdaUpdateWrapper<LifeCoupon> quanWrapper = new LambdaUpdateWrapper<>();
+                quanWrapper.in(LifeCoupon::getStoreId, storeIds).eq(LifeCoupon::getStatus, 1).orderByDesc(LifeCoupon::getCreatedTime);
+                List<LifeCoupon> quanList = lifeCouponMapper.selectList(quanWrapper);
+                quanListByStoreId = quanList.stream().collect(Collectors.groupingBy(LifeCoupon::getStoreId));
+                // 获取全部店铺的评分与平均花销
+                // TODO sotre_comment 没有花销 怎么算平均花销
+                avgScoreMap = storeEvaluationMapper.allStoreAvgScore().stream().collect(Collectors.groupingBy(o -> o.get("store_id")));
+                commentMap = storeCommentMapper.selectList(new QueryWrapper<StoreComment>().eq("business_type", "5").eq("delete_flag", 0)).stream().collect(Collectors.groupingBy(StoreComment::getStoreId));
+                avgPriceMap = lifeUserOrderMapper.allStoreAvgPrice().stream().collect(Collectors.groupingBy(o -> o.get("store_id")));
+            }
+            for (StoreInfoVo record : records) {
+                //处理类型
+                if (StringUtils.isNotEmpty(record.getStoreType())) {
+                    String[] types = record.getStoreType().split(",");
+                    List<String> typeDetails = Arrays.stream(types).map(typeMap::get).filter(Objects::nonNull).collect(Collectors.toList());
+                    record.setStoreTypeStr(String.join(",", typeDetails));
+                    record.setStoreTypeList(Arrays.asList(types));
+                }
+                //写经纬度
+                String[] split = record.getStorePosition().split(",");
+                record.setStorePositionLongitude(split[0]);
+                record.setStorePositionLatitude(split[1]);
+                //处理一下到期状态
+                Date expirationTime = record.getExpirationTime();
+                if (expirationTime != null) {
+                    // 获取当前时间
+                    Calendar now = Calendar.getInstance();
+                    Date nowCurrentDate = now.getTime();
+                    // 计算 30 天后的时间
+                    now.add(Calendar.DAY_OF_YEAR, 30);
+                    Date thirtyDaysLater = now.getTime();
+                    // 比较两个日期
+                    if (expirationTime.after(currentDate)) {
+                        record.setExpiredState("0");
+                        if (expirationTime != null && (expirationTime.after(nowCurrentDate) || expirationTime.equals(nowCurrentDate)) && expirationTime.before(thirtyDaysLater)) {
+                            record.setExpiredState("1");
+                        }
+                    } else {
+                        record.setExpiredState("2");
+                    }
+
+                    // 获取当前时间
+                    LocalDate nowLocal = LocalDate.now();
+                    // 将 expirationTime 转换为 LocalDate
+                    LocalDate expDate = expirationTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+                    // 计算距离到期的天数
+                    long daysToExpire = ChronoUnit.DAYS.between(nowLocal, expDate);
+                    record.setDaysToExpire(daysToExpire);
+                }
+                // 处理经营许可证到期时间回显状态 根据经营许可证筛选状态筛选
+                Date foodDate = record.getFoodLicenceExpirationTime();
+                if(foodDate != null){
+                    // 获取当前时间
+                    LocalDate nowLocal = LocalDate.now();
+                    LocalDate localDate = foodDate.toInstant()  // Date -> Instant(UTC时间戳)
+                            .atZone(ZoneId.systemDefault())  // Instant -> ZonedDateTime(系统默认时区)
+                            .toLocalDate();
+                    long remainingDays = ChronoUnit.DAYS.between(nowLocal, localDate);
+                    if(remainingDays == -1){
+                        record.setFoodLicenceRemainingDays("0天");
+                        record.setFoodLicenceExpireStatus("已到期");
+                    }else if(remainingDays >= 0 && remainingDays <= 30){
+                        record.setFoodLicenceRemainingDays(remainingDays + "天");
+                        record.setFoodLicenceExpireStatus("即将到期");
+                    }else if(remainingDays > 30){
+                        record.setFoodLicenceRemainingDays(remainingDays + "天");
+                        record.setFoodLicenceExpireStatus("未到期");
+                    }
+                }
+
+
+                // 处理状态
+                if (record.getLogoutFlag() == 1) {
+                    record.setStoreStatusStr("已注销");
+                    record.setStoreStatus(2);
+                }
+                // 根据八大类不同进行个性化操作
+                if (StringUtils.isNotEmpty(businessSection)) {
+                    switch (businessSection) {
+                        case "1":
+                            record.setAvgScore("0");
+                            record.setAvgPrice("0");
+                            record.setTotalNum("0");
+
+                            if ((jingdu != null && !jingdu.isEmpty()) && (weidu != null && !weidu.isEmpty())) {
+                                double storeJing = Double.parseDouble(split[0]);
+                                double storeWei = Double.parseDouble(split[1]);
+                                double storeDistance = DistanceUtil.haversineCalculateDistance(Double.parseDouble(jingdu), Double.parseDouble(weidu), storeJing, storeWei);
+                                record.setDistance(storeDistance);
+                            } else {
+                                record.setDistance(0);
+                            }
+
+                            // 设置店铺得分,设置店铺人均消费,设置总评论数
+                            if (avgScoreMap.containsKey(String.valueOf(record.getId()))) {
+                                record.setAvgScore(String.valueOf(avgScoreMap.get(String.valueOf(record.getId())).get(0).get("avg_score")));
+                                record.setAvgPrice(String.valueOf(avgPriceMap.get(String.valueOf(record.getId())).get(0).get("avg_price")));
+                            }
+                            // 设置店铺得分,设置店铺人均消费,设置总评论数
+                            if (commentMap.containsKey(record.getId())) {
+                                record.setTotalNum(String.valueOf(commentMap.get(record.getId()).size()));
+                            }
+
+                            // 设置店铺优惠券列表
+                            if (!quanListByStoreId.isEmpty() && quanListByStoreId.containsKey(String.valueOf(record.getId()))) {
+                                record.setQuanList(quanListByStoreId.get(String.valueOf(record.getId())));
+                            }
+                            break;
+                    }
+                }
+            }
+        }
+        toExcel = storeInfoVoPage.getRecords();
+        return storeInfoVoPage;
+    }
+
+    /**
+     * 重置门店密码
+     *
+     * @param storeId 门店id
+     * @return boolean
+     */
+    @Override
+    public boolean resetPassword(String storeId) {
+        QueryWrapper<StoreUser> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("store_id", storeId);
+        StoreUser storeUser = new StoreUser();
+        storeUser.setPassword("000000");
+        return storeUserMapper.update(storeUser, queryWrapper) > 0;
+    }
+
+    /**
+     * 修改门店状态
+     *
+     * @param storeId        门店id
+     * @param businessStatus 营业状态
+     * @return boolean
+     */
+    @Override
+    public boolean setStoreState(String storeId, Integer businessStatus) {
+        LambdaUpdateWrapper<StoreInfo> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(StoreInfo::getId, storeId).set(StoreInfo::getBusinessStatus, businessStatus);
+        return this.update(null, updateWrapper);
+    }
+
+    /**
+     * web-新增店铺
+     *
+     * @param multipartRequest 文件请求
+     * @param store            店铺信息
+     * @return boolean
+     */
+    @Override
+    public boolean saveStore(MultipartRequest multipartRequest, StoreInfo store) {
+        try {
+            String LonAndLat = gaoDeMapUtil.getLonAndLatByAddress(store.getStoreAddress());
+            if (LonAndLat == null || LonAndLat.isEmpty()) {
+                log.error("LifeStoreController.addOrUpdateStore ERROR 经纬度获取失败");
+                return false;
+            }
+            store.setStorePosition(LonAndLat);
+            if (org.apache.commons.lang3.StringUtils.isBlank(store.getCommissionRate())) {
+                store.setCommissionRate("3");
+            }
+            this.save(store);
+            Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+            if (!fileNameSet.isEmpty()) {
+                for (int i = 0; i < fileNameSet.size(); i++) {
+                    MultipartFile multipartFile = multipartRequest.getFileMap().get(i);
+                    if (null != multipartFile) {
+                        StoreImg storeImg = new StoreImg();
+                        storeImg.setStoreId(store.getId());
+                        storeImg.setImgType(12);
+                        storeImg.setImgSort(i + 1);
+                        storeImg.setImgUrl(fileUploadUtil.uploadOneFile(multipartFile));
+                        storeImgMapper.insert(storeImg);
+                    }
+                }
+            }
+            return true;
+        } catch (Exception e) {
+            log.error("LifeStoreController.addOrUpdateStore ERROR Msg={}", e);
+            return false;
+        }
+    }
+
+    /**
+     * 导出Excel
+     *
+     * @return ResponseEntity
+     */
+    @Override
+    public ResponseEntity<byte[]> exportToExcel() {
+        try {
+            String[] headers = {"商家名称", "联系人", "联系电话", "经营种类", "创建时间", "状态"};
+            byte[] excelData = ExcelExporter.exportToExcel(toExcel, headers, "商家列表清单");
+            HttpHeaders responseHeaders = new HttpHeaders();
+            responseHeaders.add("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode("商家列表清单.xlsx") + "\";charset=utf-8");
+            responseHeaders.set("Charset", "UTF-8");
+            return new ResponseEntity<>(excelData, responseHeaders, HttpStatus.OK);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public StoreInfoVo saveStoreInfo(StoreInfoDto storeInfoDto) throws Exception {
+        //获取经营板块id
+        Integer businessSection = storeInfoDto.getBusinessSection();
+        //查询经营板块名称
+        StoreDictionary businessSectionName = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getDictId, businessSection).eq(StoreDictionary::getTypeName, "business_section"));
+        //查询经营种类
+        List<String> businessTypes = storeInfoDto.getBusinessTypes();
+        List<String> businessTypeNames = new ArrayList<>();
+        //获取经营种类名称
+        for (String businessType : businessTypes) {
+            StoreDictionary storeDictionary = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getDictId, businessType).eq(StoreDictionary::getParentId, businessSectionName.getId()));
+            businessTypeNames.add(storeDictionary.getDictDetail());
+        }
+
+        StoreInfoVo result = new StoreInfoVo();
+        StoreInfo storeInfo = new StoreInfo();
+        BeanUtils.copyProperties(storeInfoDto, storeInfo);
+//        List<String> storeTypeList = storeInfoDto.getStoreTypeList();
+//        String storeType = String.join(",", storeTypeList);
+//        //存入营运类型
+//        storeInfo.setStoreType(storeType);
+        //存入门店状态
+        storeInfo.setStoreStatus(storeInfoDto.getStoreStatus());
+        //存入经纬度
+        storeInfo.setStorePosition(storeInfoDto.getStorePositionLongitude() + "," + storeInfoDto.getStorePositionLatitude());
+        //如果有门店密码,并且门店密码不为默认密码。则存入密码
+        if (StringUtils.isNotEmpty(storeInfoDto.getStorePass()) && !DEFAULT_PASSWORD.equals(storeInfoDto.getStorePass())) {
+            storeInfo.setStorePass(storeInfoDto.getStorePass());
+            storeInfo.setPassType(1);
+        } else {
+            storeInfo.setStorePass(DEFAULT_PASSWORD);
+            storeInfo.setPassType(0);
+        }
+        //板块及类型
+        storeInfo.setBusinessSection(businessSection);
+        storeInfo.setBusinessSectionName(businessSectionName.getDictDetail());
+        storeInfo.setBusinessTypes(String.join(",", businessTypes));
+        storeInfo.setBusinessTypesName(String.join(",", businessTypeNames));
+        //存入审批状态为待审批
+        storeInfo.setStoreApplicationStatus(0);
+        //处理一下行政区域信息
+        EssentialCityCode essentialCityCode1 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionProvinceAdcode()));
+        storeInfo.setAdministrativeRegionProvinceName(essentialCityCode1.getAreaName());
+        EssentialCityCode essentialCityCode2 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionCityAdcode()));
+        storeInfo.setAdministrativeRegionCityName(essentialCityCode2.getAreaName());
+        EssentialCityCode essentialCityCode3 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionDistrictAdcode()));
+        storeInfo.setAdministrativeRegionDistrictName(essentialCityCode3.getAreaName());
+        if (null == storeInfo.getCommissionRate()) {
+            storeInfo.setCommissionRate("3");
+        }
+        storeInfoMapper.insert(storeInfo);
+        result.setId(storeInfo.getId());
+        nearMeService.inGeolocation(new Point(Double.parseDouble(storeInfoDto.getStorePositionLongitude()), Double.parseDouble(storeInfoDto.getStorePositionLatitude())), storeInfo.getId().toString(), Boolean.TRUE);
+        //修改门店店铺用户绑定关系
+        String userAccount = storeInfoDto.getUserAccount();
+        StoreUser storeUser = storeUserMapper.selectById(userAccount);
+        storeUser.setStoreId(storeInfo.getId());
+        if(StringUtils.isNotEmpty(storeInfoDto.getStoreContact())){
+            storeUser.setName(storeInfoDto.getStoreContact());
+        }
+        if(StringUtils.isNotEmpty(storeInfoDto.getIdCard())){
+            storeUser.setIdCard(storeInfoDto.getIdCard());
+        }
+        storeUserMapper.updateById(storeUser);
+        //存入店铺营业执照图片
+        List<String> businessLicenseAddress = storeInfoDto.getBusinessLicenseAddress();
+        for (String licenseAddress : businessLicenseAddress) {
+            StoreImg storeImg = new StoreImg();
+            storeImg.setStoreId(storeInfo.getId());
+            storeImg.setImgType(14);
+            storeImg.setImgSort(0);
+            storeImg.setImgDescription("营业执照");
+            storeImg.setImgUrl(licenseAddress);
+            storeImgMapper.insert(storeImg);
+        }
+        //存入店铺合同图片
+        if(!CollectionUtils.isEmpty(storeInfoDto.getContractImageList())){
+            List<String> contractImageList = storeInfoDto.getContractImageList();
+            //先移除此前数据
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfo.getId()).eq(StoreImg::getImgType, 15));
+            for (String licenseAddress : contractImageList) {
+                StoreImg storeImg = new StoreImg();
+                storeImg.setStoreId(storeInfo.getId());
+                storeImg.setImgType(15);
+                storeImg.setImgSort(0);
+                storeImg.setImgDescription("合同图片");
+                storeImg.setImgUrl(licenseAddress);
+                storeImgMapper.insert(storeImg);
+            }
+        }
+
+        //存入店铺经营许可证图片
+        if(StringUtils.isNotEmpty(storeInfoDto.getFoodLicenceUrl())){
+                StoreImg storeImg = new StoreImg();
+                storeImg.setStoreId(storeInfo.getId());
+                storeImg.setImgType(25);
+                storeImg.setImgSort(0);
+                storeImg.setImgDescription("经营许可证审核通过图片");
+                storeImg.setImgUrl(storeInfoDto.getFoodLicenceUrl());
+                storeImgMapper.insert(storeImg);
+        }
+
+        //初始化标签数据
+        LambdaQueryWrapper<TagStoreRelation> tagStoreRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        tagStoreRelationLambdaQueryWrapper.eq(TagStoreRelation::getStoreId, storeInfo.getId());
+        tagStoreRelationLambdaQueryWrapper.eq(TagStoreRelation::getDeleteFlag, 0);
+        int tagStoreCount = tagStoreRelationMapper.selectCount(tagStoreRelationLambdaQueryWrapper);
+        if(tagStoreCount == 0){
+            TagStoreRelation tagStoreRelation = new TagStoreRelation();
+            tagStoreRelation.setStoreId(storeInfo.getId());
+            tagStoreRelation.setDeleteFlag(0);
+            tagStoreRelationMapper.insert(tagStoreRelation);
+        }
+
+
+        // 发送通知
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String commonDate = simpleDateFormat.format(new Date());
+        String text = "您在"+commonDate+"提交的入驻店铺申请,平台已受理,1-3个工作日将审核结果发送至应用内的消息-通知中,请注意查收。";
+        com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
+        jsonObject.put("message", text);
+        LifeNotice lifeMessage = new LifeNotice();
+        lifeMessage.setReceiverId("store_" + storeUser.getPhone());
+        lifeMessage.setContext(jsonObject.toJSONString());
+        lifeMessage.setTitle("入住店铺申请");
+        lifeMessage.setSenderId("system");
+        lifeMessage.setIsRead(0);
+        lifeMessage.setNoticeType(1);
+        lifeNoticeMapper.insert(lifeMessage);
+
+        WebSocketVo websocketVo = new WebSocketVo();
+        websocketVo.setSenderId("system");
+        websocketVo.setReceiverId("store_" + storeUser.getPhone());
+        websocketVo.setCategory("notice");
+        websocketVo.setNoticeType("1");
+        websocketVo.setIsRead(0);
+        websocketVo.setText(com.alibaba.fastjson2.JSONObject.from(lifeMessage).toJSONString());
+
+        return result;
+    }
+
+    @Override
+    public int saveStoreInfoDraft(StoreInfoDraft storeInfoDraft) {
+        //处理一下行政区域信息
+        if (storeInfoDraft.getAdministrativeRegionProvinceAdcode() != null) {
+            EssentialCityCode essentialCityCode1 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfoDraft.getAdministrativeRegionProvinceAdcode()));
+            if (null != essentialCityCode1) {
+                storeInfoDraft.setAdministrativeRegionProvinceName(essentialCityCode1.getAreaName());
+            }
+        }
+        if (storeInfoDraft.getAdministrativeRegionCityAdcode() != null) {
+            EssentialCityCode essentialCityCode2 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfoDraft.getAdministrativeRegionCityAdcode()));
+            if (null != essentialCityCode2) {
+                storeInfoDraft.setAdministrativeRegionCityName(essentialCityCode2.getAreaName());
+            }
+        }
+        if (storeInfoDraft.getAdministrativeRegionDistrictAdcode() != null) {
+            EssentialCityCode essentialCityCode3 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfoDraft.getAdministrativeRegionDistrictAdcode()));
+            if (null != essentialCityCode3) {
+                storeInfoDraft.setAdministrativeRegionDistrictName(essentialCityCode3.getAreaName());
+            }
+        }
+        if (storeInfoDraft.getBusinessLicenseUrl().isEmpty()) {
+            storeInfoDraft.setBusinessLicenseUrl(null);
+        }
+        if (storeInfoDraft.getContractUrl().isEmpty()) {
+            storeInfoDraft.setContractUrl(null);
+        }
+
+        if (storeInfoDraft.getFoodLicenceUrl().isEmpty()) {
+            storeInfoDraft.setFoodLicenceUrl(null);
+        }
+        return storeInfoDraftMapper.insert(storeInfoDraft);
+    }
+
+    @Override
+    public StoreInfoDraft selectDraftByUserId(int storeUserId) {
+        LambdaQueryWrapper<StoreInfoDraft> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreInfoDraft::getStoreUserId, storeUserId);
+        wrapper.orderByDesc(StoreInfoDraft::getCreatedTime);
+        List<StoreInfoDraft> list = storeInfoDraftMapper.selectList(wrapper);
+        return CollectionUtils.isEmpty(list) ? null : list.get(0);
+    }
+
+    @Override
+    public StoreInfoVo editStoreInfo(StoreInfoDto storeInfoDto) {
+
+        //判断是否修改变更过的用户账户
+        String userAccountId = storeInfoDto.getUserAccount();
+        Integer id = storeInfoDto.getId();
+        StoreUser storeUserEntity = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, id));
+        //如果更换了用户,则原有用户绑定门店删除
+        if (!userAccountId.equals(storeUserEntity.getId().toString())) {
+            LambdaUpdateWrapper<StoreUser> storeUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+            storeUserLambdaUpdateWrapper.set(StoreUser::getStoreId, null).eq(StoreUser::getId, storeUserEntity.getId());
+            storeUserMapper.update(null, storeUserLambdaUpdateWrapper);
+        }
+        //获取经营板块id
+        Integer businessSection = storeInfoDto.getBusinessSection();
+        //查询经营板块名称
+        StoreDictionary businessSectionName = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getDictId, businessSection).eq(StoreDictionary::getTypeName, "business_section"));
+        //查询经营种类
+        List<String> businessTypes = storeInfoDto.getBusinessTypes();
+        List<String> businessTypeNames = new ArrayList<>();
+        //获取经营种类名称
+        for (String businessType : businessTypes) {
+            StoreDictionary storeDictionary = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getDictId, businessType).eq(StoreDictionary::getParentId, businessSectionName.getId()));
+            businessTypeNames.add(storeDictionary.getDictDetail());
+        }
+
+        StoreInfoVo result = new StoreInfoVo();
+        StoreInfo storeInfo = new StoreInfo();
+        BeanUtils.copyProperties(storeInfoDto, storeInfo);
+//        List<String> storeTypeList = storeInfoDto.getStoreTypeList();
+//        String storeType = String.join(",", storeTypeList);
+        //存入营运类型
+//        storeInfo.setStoreType(storeType);
+        //存入门店状态
+        storeInfo.setStoreStatus(storeInfoDto.getStoreStatus());
+        //存入经纬度
+        storeInfo.setStorePosition(storeInfoDto.getStorePositionLongitude() + "," + storeInfoDto.getStorePositionLatitude());
+        //如果有门店密码,并且门店密码不为默认密码。则存入密码
+        if (StringUtils.isNotEmpty(storeInfoDto.getStorePass()) && !DEFAULT_PASSWORD.equals(storeInfoDto.getStorePass())) {
+            storeInfo.setStorePass(storeInfoDto.getStorePass());
+            storeInfo.setPassType(1);
+        } else {
+            storeInfo.setStorePass(DEFAULT_PASSWORD);
+            storeInfo.setPassType(0);
+        }
+        //板块及类型
+        storeInfo.setBusinessSection(businessSection);
+        storeInfo.setBusinessSectionName(businessSectionName.getDictDetail());
+        storeInfo.setBusinessTypes(String.join(",", businessTypes));
+        storeInfo.setBusinessTypesName(String.join(",", businessTypeNames));
+        //处理一下行政区域信息
+        EssentialCityCode essentialCityCode1 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionProvinceAdcode()));
+        storeInfo.setAdministrativeRegionProvinceName(essentialCityCode1.getAreaName());
+        EssentialCityCode essentialCityCode2 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionCityAdcode()));
+        storeInfo.setAdministrativeRegionCityName(essentialCityCode2.getAreaName());
+        EssentialCityCode essentialCityCode3 = essentialCityCodeMapper.selectOne(new LambdaQueryWrapper<EssentialCityCode>().eq(EssentialCityCode::getAreaCode, storeInfo.getAdministrativeRegionDistrictAdcode()));
+        storeInfo.setAdministrativeRegionDistrictName(essentialCityCode3.getAreaName());
+        storeInfoMapper.updateById(storeInfo);
+        nearMeService.inGeolocation(new Point(Double.parseDouble(storeInfoDto.getStorePositionLongitude()), Double.parseDouble(storeInfoDto.getStorePositionLatitude())), storeInfo.getId().toString(), Boolean.TRUE);
+
+        //修改门店店铺用户绑定关系
+        String userAccount = storeInfoDto.getUserAccount();
+        StoreUser storeUser = storeUserMapper.selectById(userAccount);
+        storeUser.setStoreId(storeInfo.getId());
+        storeUserMapper.updateById(storeUser);
+        BeanUtils.copyProperties(storeInfoDto, result);
+        //存入店铺营业执照图片
+        if(!CollectionUtils.isEmpty(storeInfoDto.getBusinessLicenseAddress())){
+            List<String> businessLicenseAddress = storeInfoDto.getBusinessLicenseAddress();
+            //先移除此前数据
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfo.getId()).eq(StoreImg::getImgType, 14));
+            for (String licenseAddress : businessLicenseAddress) {
+                StoreImg storeImg = new StoreImg();
+                storeImg.setStoreId(storeInfo.getId());
+                storeImg.setImgType(14);
+                storeImg.setImgDescription("营业执照");
+                storeImg.setImgSort(0);
+                storeImg.setImgUrl(licenseAddress);
+                storeImgMapper.insert(storeImg);
+            }
+        }
+
+        //存入店铺合同图片
+        List<String> contractImageList = storeInfoDto.getContractImageList();
+        if(!CollectionUtils.isEmpty(contractImageList)){
+            //先移除此前数据
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfo.getId()).eq(StoreImg::getImgType, 15));
+            for (String licenseAddress : contractImageList) {
+                StoreImg storeImg = new StoreImg();
+                storeImg.setStoreId(storeInfo.getId());
+                storeImg.setImgType(15);
+                storeImg.setImgSort(0);
+                storeImg.setImgDescription("合同图片");
+                storeImg.setImgUrl(licenseAddress);
+                storeImgMapper.insert(storeImg);
+            }
+        }
+
+        //存入店铺经营许可证图片
+        if(StringUtils.isNotEmpty(storeInfoDto.getFoodLicenceUrl())){
+            //先移除此前数据 type:25 审核通过后的图片
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfo.getId()).eq(StoreImg::getImgType, 25));
+            //先移除此前数据 type:24 审核前的或者审核拒绝的图片
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfo.getId()).eq(StoreImg::getImgType, 24));
+            StoreImg storeImg = new StoreImg();
+            storeImg.setStoreId(storeInfo.getId());
+            //type:25 审核通过的类型
+            storeImg.setImgType(25);
+            storeImg.setImgSort(0);
+            storeImg.setImgDescription("经营许可证审核通过图片");
+            storeImg.setImgUrl(storeInfoDto.getFoodLicenceUrl());
+            storeImgMapper.insert(storeImg);
+        }
+
+        return result;
+    }
+
+    @Override
+    public String deleteStoreInfo(StoreInfoDto storeInfoDto) {
+        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfoDto.getId()));
+        //判断是否有未完成的订单
+        List<LifeUserOrder> lifeUserOrders = lifeUserOrderMapper.selectList(new LambdaQueryWrapper<LifeUserOrder>().in(LifeUserOrder::getStatus, 0, 3).eq(ObjectUtils.isNotEmpty(storeUser), LifeUserOrder::getUserId, storeUser.getId()).eq(LifeUserOrder::getDeleteFlag, 0));
+        if (ObjectUtils.isNotEmpty(lifeUserOrders)) {
+            return "您有暂未完成的订单无法删除店铺,请在完成后删除";
+        } else {
+            //判断是否修改变更过的用户账户
+            if (storeUser != null) {
+                LambdaUpdateWrapper<StoreUser> storeUserLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+                storeUserLambdaUpdateWrapper.set(StoreUser::getStoreId, null).eq(StoreUser::getId, storeUser.getId());
+                storeUserMapper.update(null, storeUserLambdaUpdateWrapper);
+            }
+            //删除商铺信息
+            storeInfoMapper.deleteById(storeInfoDto.getId());
+            return "成功";
+        }
+    }
+
+    @Override
+    public void restPassword(StoreInfoDto storeInfoDto) {
+        StoreInfo storeInfo = storeInfoMapper.selectById(storeInfoDto.getId());
+        storeInfo.setStorePass(DEFAULT_PASSWORD);
+        //修改商铺信息密码
+        storeInfoMapper.updateById(storeInfo);
+        //删除商铺的用户
+        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfoDto.getId()));
+        storeUser.setPassword(DEFAULT_PASSWORD);
+        storeUserMapper.updateById(storeUser);
+    }
+
+    @Override
+    public List<StoreDictionaryVo> getBusinessSection() {
+        List<StoreDictionary> businessSection = storeDictionaryMapper.selectList(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getTypeName, "business_section").ne(StoreDictionary::getDictId, 0));
+        List<StoreDictionaryVo> voList = new ArrayList<>();
+        for (StoreDictionary storeDictionary : businessSection) {
+            StoreDictionaryVo vo = new StoreDictionaryVo();
+            BeanUtils.copyProperties(storeDictionary, vo);
+            voList.add(vo);
+        }
+        return voList;
+    }
+
+    @Override
+    public List<StoreDictionaryVo> getBusinessSectionTypes(String parentId) {
+        StoreDictionary businessSection = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getTypeName, "business_section").eq(StoreDictionary::getDictId, parentId));
+        List<StoreDictionary> storeDictionaries = storeDictionaryMapper.selectList(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getParentId, businessSection.getId()));
+        List<StoreDictionaryVo> voList = new ArrayList<>();
+        for (StoreDictionary storeDictionary : storeDictionaries) {
+            StoreDictionaryVo vo = new StoreDictionaryVo();
+            BeanUtils.copyProperties(storeDictionary, vo);
+            voList.add(vo);
+        }
+        return voList;
+    }
+
+    @Override
+    public List<StoreUserVo> getUnboundAccountList(String id) {
+        List<StoreUserVo> storeUserVoList = new ArrayList<>();
+        List<StoreUser> storeUsers = storeUserMapper.selectList(new LambdaQueryWrapper<StoreUser>().isNull(StoreUser::getStoreId));
+        for (StoreUser storeUser : storeUsers) {
+            StoreUserVo vo = new StoreUserVo();
+            BeanUtils.copyProperties(storeUser, vo);
+            vo.setPayPassword("");
+            vo.setPassword("");
+            storeUserVoList.add(vo);
+        }
+        if (StringUtils.isNotEmpty(id)) {
+            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, id));
+            if (storeUser != null) {
+                StoreUserVo vo = new StoreUserVo();
+                BeanUtils.copyProperties(storeUser, vo);
+                vo.setPayPassword("");
+                vo.setPassword("");
+                storeUserVoList.add(vo);
+            }
+        }
+        return storeUserVoList;
+    }
+
+    @Override
+    public void addBusinessSectionAndTypes(StoreInfoDto storeInfoDto) {
+        StoreDictionary businessSectionParent = storeDictionaryMapper.selectOne(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getTypeName, "business_section").eq(StoreDictionary::getDictId, 0));
+        //查看当前最大id
+        List<StoreDictionary> businessSection = storeDictionaryMapper.selectList(new LambdaQueryWrapper<StoreDictionary>().eq(StoreDictionary::getTypeName, "business_section"));
+        Integer maxId = 0;
+        for (StoreDictionary storeDictionary : businessSection) {
+            if (Integer.parseInt(storeDictionary.getDictId()) > maxId) {
+                maxId = Integer.parseInt(storeDictionary.getDictId());
+            }
+        }
+        //构建新增的经营板块
+        StoreDictionary addStoreDictionary = new StoreDictionary();
+        BeanUtils.copyProperties(businessSection.get(0), addStoreDictionary);
+        addStoreDictionary.setId(null);
+        addStoreDictionary.setDictDetail(storeInfoDto.getBusinessSectionName());
+        addStoreDictionary.setDictId((maxId + 1) + "");
+        addStoreDictionary.setParentId(businessSectionParent.getId());
+        storeDictionaryMapper.insert(addStoreDictionary);
+        //构建新增的经营类型
+        List<String> businessTypesList = storeInfoDto.getBusinessTypesList();
+        Integer dictgId = 0;
+        for (String businessTypeName : businessTypesList) {
+            StoreDictionary storeDictionary = new StoreDictionary();
+            storeDictionary.setTypeName(storeInfoDto.getBusinessTypeValue());
+            storeDictionary.setTypeDetail(addStoreDictionary.getDictDetail());
+            storeDictionary.setParentId(addStoreDictionary.getId());
+            storeDictionary.setDictId(dictgId + "");
+            storeDictionary.setDictDetail(businessTypeName);
+            storeDictionary.setCreatedTime(new Date());
+            storeDictionaryMapper.insert(storeDictionary);
+            dictgId++;
+        }
+    }
+
+    @Override
+    public StoreInfoVo getStoreDetail(String storeId, String userId, String jingdu, String weidu) {
+        StoreInfoVo result = new StoreInfoVo();
+        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
+        BeanUtils.copyProperties(storeInfo, result);
+        //将经营板块和种类拆分成集合
+        String businessTypes = storeInfo.getBusinessTypes();
+        if (StringUtils.isNotEmpty(businessTypes)) {
+            String[] split = businessTypes.split(",");
+            List<String> list = Arrays.asList(split);
+            result.setBusinessTypesList(list);
+        }
+        //存入用户账户
+        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeId));
+        if (storeUser != null) {
+            result.setUserAccount(storeUser.getId().toString());
+            result.setStorePhone(storeUser.getPhone());
+            result.setStoreUserName(storeUser.getName());
+            result.setIdCard(storeUser.getIdCard());
+        }
+        //存入执照图片地址
+        List<StoreImg> storeImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 14));
+        List<String> storeImgPaths = new ArrayList<>();
+        for (StoreImg storeImg : storeImgs) {
+            storeImgPaths.add(storeImg.getImgUrl());
+        }
+        result.setBusinessLicenseAddress(storeImgPaths);
+        //存入合同图片地址
+        List<StoreImg> storeContractImageImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 15));
+        List<String> storeContractImagePathImgs = new ArrayList<>();
+        for (StoreImg storeImg : storeContractImageImgs) {
+            storeContractImagePathImgs.add(storeImg.getImgUrl());
+        }
+        result.setContractImageList(storeContractImagePathImgs);
+        //存入续签合同地址
+        List<StoreImg> renewContractImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 22));
+        List<String> renewContractImagePathImgs = new ArrayList<>();
+        for (StoreImg storeImg : renewContractImgs) {
+            renewContractImagePathImgs.add(storeImg.getImgUrl());
+        }
+        result.setRenewContractImageList(renewContractImagePathImgs);
+        //存入经营许可证通过地址
+        List<StoreImg> foodLicenceImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 25));
+        List<String> foodLicenceImgsPathImgs = new ArrayList<>();
+        for (StoreImg storeImg : foodLicenceImgs) {
+            foodLicenceImgsPathImgs.add(storeImg.getImgUrl());
+        }
+        result.setFoodLicenceImageList(foodLicenceImgsPathImgs);
+        //存入经营许可证未通过地址
+        List<StoreImg> notPassFoodLicenceImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 24));
+        List<String> notPassFoodLicenceList = new ArrayList<>();
+        for (StoreImg storeImg : notPassFoodLicenceImgs) {
+            notPassFoodLicenceList.add(storeImg.getImgUrl());
+        }
+        result.setNotPassFoodLicenceImageList(notPassFoodLicenceList);
+        // 存放商家入口图
+        List<StoreImg> storeEntranceImageImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 1));
+        if (!storeEntranceImageImgs.isEmpty()) {
+            result.setEntranceImage(storeEntranceImageImgs.get(0).getImgUrl());
+        } else {
+            result.setEntranceImage("null");
+        }
+        // 存放商家头像
+        List<StoreImg> storeImgs1 = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeId).eq(StoreImg::getImgType, 10));
+        if (!storeImgs1.isEmpty()) {
+            result.setImgUrl(storeImgs1.get(0).getImgUrl());
+        } else {
+            result.setImgUrl("null");
+        }
+
+        // 设置经纬度
+        result.setStorePositionLongitude(result.getStorePosition().split(",")[0]);
+        result.setStorePositionLatitude(result.getStorePosition().split(",")[1]);
+        // 设置距离
+        if ((jingdu != null && !jingdu.isEmpty()) && (weidu != null && !weidu.isEmpty())) {
+            /*double storeJing = Double.parseDouble(result.getStorePosition().split(",")[0]);
+            double storeWei = Double.parseDouble(result.getStorePosition().split(",")[1]);
+            double storeDistance = DistanceUtil.haversineCalculateDistance(Double.parseDouble(jingdu), Double.parseDouble(weidu), storeJing, storeWei);*/
+
+            Double distance = storeInfoMapper.getStoreDistance(jingdu + "," + weidu,result.getId());
+
+            result.setDistance(distance);
+        }
+        // 计算店铺到最近地铁站的距离
+        JSONObject nearbySubway = gaoDeMapUtil.getNearbySubway(result.getStorePosition().split(",")[0], result.getStorePosition().split(",")[1]);
+        // 地铁名
+        String subWayName = nearbySubway.getString("name");
+        result.setSubwayName(subWayName);
+        // 地铁站经纬度
+        String subWayJing = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[0];
+        String subWayWei = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[1];
+        if ((subWayJing != null && !subWayJing.isEmpty()) && (subWayWei != null && !subWayWei.isEmpty())) {
+            double storeJing = Double.parseDouble(result.getStorePosition().split(",")[0]);
+            double storeWei = Double.parseDouble(result.getStorePosition().split(",")[1]);
+            double storeDistance2 = DistanceUtil.haversineCalculateDistance(Double.parseDouble(subWayJing), Double.parseDouble(subWayWei), storeJing, storeWei);
+            result.setDistance2(storeDistance2);
+        } else {
+            result.setDistance2(0);
+        }
+        // 当前登录用户是否收藏
+        LambdaUpdateWrapper<LifeCollect> shouCangWrapper = new LambdaUpdateWrapper<>();
+        shouCangWrapper.eq(LifeCollect::getUserId, userId).eq(LifeCollect::getStoreId, storeId);
+        List<LifeCollect> shouCangList = lifeCollectMapper.selectList(shouCangWrapper);
+        if (null == shouCangList || shouCangList.isEmpty()) {
+            result.setCollection(0);
+        } else {
+            result.setCollection(1);
+        }
+        // 获取店铺代金券列表
+        LambdaUpdateWrapper<LifeCoupon> quanWrapper = new LambdaUpdateWrapper<>();
+        quanWrapper.eq(LifeCoupon::getStoreId, storeId).eq(LifeCoupon::getStatus, CouponStatusEnum.ONGOING.getCode()).eq(LifeCoupon::getType, 1);
+        List<LifeCoupon> quanList = lifeCouponMapper.selectList(quanWrapper);
+        List<LifeCouponVo> quanVoList = new ArrayList<>();
+        List<String> collect = quanList.stream().map(LifeCoupon::getId).collect(Collectors.toList());
+        // 设置已售数量
+        // 定义需要的订单状态集合
+        Set<Integer> excludeStatuses = new HashSet<>(Arrays.asList(
+                OrderStatusEnum.WAIT_PAY.getStatus(),
+                OrderStatusEnum.WAIT_USE.getStatus(),
+                OrderStatusEnum.USED.getStatus()
+        ));
+        if (!collect.isEmpty()) {
+            List<LifeUserOrderVo> quanCount = lifeUserOrderMapper.getQuanCount(new QueryWrapper<LifeUserOrderVo>()
+                    .eq("luo.store_id",storeId)
+                    .eq("luo.coupon_type", CouponTypeEnum.COUPON.getCode())
+                    .eq("luo.delete_flag",0)
+                    .in("ocm.status",excludeStatuses)
+                    .groupBy("ocm.coupon_id"));
+            quanList.forEach(a -> {
+                LifeCouponVo lifeCouponVo = new LifeCouponVo();
+                BeanUtils.copyProperties(a, lifeCouponVo);
+                quanCount.forEach(item -> {
+                    if (a.getId().equals(item.getCouponId().toString())) {
+                        lifeCouponVo.setCount(item.getCount());
+                    }
+                });
+                quanVoList.add(lifeCouponVo);
+            });
+        }
+        result.setCouponList(quanVoList);
+
+        // 获取店铺团购
+        LambdaUpdateWrapper<LifeGroupBuyMain> tuangouWrapper = new LambdaUpdateWrapper<>();
+        tuangouWrapper.eq(LifeGroupBuyMain::getStoreId, storeId).eq(LifeGroupBuyMain::getStatus, CouponStatusEnum.ONGOING.getCode()).orderByDesc(LifeGroupBuyMain::getCreatedTime);
+        List<LifeGroupBuyMain> tuangouList = lifeGroupBuyMainMapper.selectList(tuangouWrapper);
+        List<LifeGroupBuyMainVo> tuangouVOList = new ArrayList<>();
+        for (LifeGroupBuyMain lifeGroupBuyMain : tuangouList) {
+            LifeGroupBuyMainVo lifeGroupBuyMainVo = new LifeGroupBuyMainVo();
+            BeanUtils.copyProperties(lifeGroupBuyMain, lifeGroupBuyMainVo);
+            if (StringUtils.isNotEmpty(lifeGroupBuyMain.getImageId())) {
+                List<String> ids = Arrays.stream(lifeGroupBuyMain.getImageId().split(",")).map(String::trim).collect(Collectors.toList());
+                List<StoreImg> imgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().in(StoreImg::getId, ids));
+                if (imgList != null) {
+                    String imgs = imgList.stream().map(StoreImg::getImgUrl).collect(Collectors.joining(","));
+                    lifeGroupBuyMainVo.setImageId(imgs);
+                }
+            }
+            tuangouVOList.add(lifeGroupBuyMainVo);
+        }
+        result.setTuangouList(tuangouVOList);
+
+        // 获取员工列表
+        LambdaQueryWrapper<StoreStaffConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(StoreStaffConfig::getStoreId, storeId);
+        List<StoreStaffConfig> storeStaffConfigs = storeStaffConfigMapper.selectList(lambdaQueryWrapper);
+        result.setEmployeeList(storeStaffConfigs);
+
+        // 该用户的打卡记录
+        LambdaQueryWrapper<StoreClockIn> clockInWrapper = new LambdaQueryWrapper<>();
+        clockInWrapper.eq(StoreClockIn::getUserId, userId);
+        List<StoreClockIn> clockInList = storeClockInMapper.selectList(clockInWrapper);
+
+        List<StoreClockIn> clockStoreList = clockInList.stream().filter(item -> item.getStoreId() == Integer.parseInt(storeId)).collect(Collectors.toList());
+        // 该用户是否在该店铺打过卡
+        if (!clockStoreList.isEmpty()) {
+            result.setClockInStore(1);
+        } else {
+            result.setClockInStore(0);
+        }
+
+        // 今天在该店铺是否打过卡
+        int today = (int) clockStoreList.stream().filter(item -> item.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().equals(LocalDate.now())).count();
+        if (today > 0) {
+            result.setClockInStoreToday(1);
+        } else {
+            result.setClockInStoreToday(0);
+        }
+
+        // 店铺平均分
+        /*Map<Object, List<Map<String, Object>>> avgScoreMap = storeEvaluationMapper.allStoreAvgScore().stream().collect(Collectors.groupingBy(o -> o.get("store_id")));
+        if (avgScoreMap.containsKey(String.valueOf(result.getId()))) {
+            result.setScore(Double.parseDouble(avgScoreMap.get(String.valueOf(result.getId())).get(0).get("avg_score").toString()));
+        }*/
+
+
+
+        // 在该店铺的打卡次数
+        result.setClockInStoreNum(clockStoreList.size());
+
+        // 该用户打卡的所有店铺次数(一个店铺只算一次)
+        int clockInNum = (int) clockInList.stream().map(StoreClockIn::getStoreId).distinct().count();
+        result.setClockInNum(clockInNum);
+
+        // 获取店铺动态列表
+        QueryWrapper<LifeUserDynamics> dynamicsWrapper = new QueryWrapper<>();
+        dynamicsWrapper.eq("phone_id", "store_" + result.getStorePhone()).orderByDesc("lud.created_time");
+        dynamicsWrapper.eq("lud.delete_flag", 0);
+        //List<LifeUserDynamicsVo> storeDynamicslist = lifeUserDynamicsMapper.getStoreDynamicslist(userId, dynamicsWrapper);
+
+        LambdaQueryWrapper<LifeBlacklist> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper1.eq(LifeBlacklist :: getBlockerId, userId);
+        lambdaQueryWrapper1.eq(LifeBlacklist :: getBlockedPhoneId, "store_" + result.getStorePhone());
+        LifeBlacklist blacklist = lifeBlacklistMapper.selectOne(lambdaQueryWrapper1);
+        List<LifeUserDynamicsVo> storeDynamicslist = new ArrayList<>();
+
+        //判断没有拉黑当前门店账户 查出门店动态
+        if(blacklist == null){
+            storeDynamicslist = lifeUserDynamicsMapper.getStoreDynamicslist(userId, "store_" + result.getStorePhone());
+        }
+
+        List<String> followList = new ArrayList<>();
+        List<String> fansList = new ArrayList<>();
+
+        if (StringUtils.isNotEmpty(userId)) {
+            LifeUser lifeUser = lifeUserMapper.selectById(userId);
+            if (lifeUser != null && StringUtils.isNotEmpty(lifeUser.getUserPhone())) {
+                // 查询我的关注信息,构建关注者ID列表
+                LambdaQueryWrapper<LifeFans> lifeFansWrapper = new LambdaQueryWrapper<>();
+                lifeFansWrapper.eq(LifeFans::getFansId, "user_" + result.getStorePhone());
+                List<LifeFans> lifeFansList = lifeFansMapper.selectList(lifeFansWrapper);
+                if (!CollectionUtils.isEmpty(lifeFansList)) {
+                    followList = lifeFansList.stream().map(LifeFans::getFollowedId).collect(Collectors.toList());
+                }
+
+                // 查询我的粉丝信息,构建粉丝ID列表
+                lifeFansWrapper = new LambdaQueryWrapper<>();
+                lifeFansWrapper.eq(LifeFans::getFollowedId, "user_" + result.getStorePhone());
+                lifeFansList = lifeFansMapper.selectList(lifeFansWrapper);
+                if (!CollectionUtils.isEmpty(lifeFansList)) {
+                    fansList = lifeFansList.stream().map(LifeFans::getFansId).collect(Collectors.toList());
+                }
+            }
+        }
+
+        for (LifeUserDynamicsVo vo : storeDynamicslist) {
+            if (followList.contains(vo.getPhoneId())) {
+                vo.setIsFollowThis("1");
+            } else {
+                vo.setIsFollowThis("0");
+            }
+            if (fansList.contains(vo.getPhoneId())) {
+                vo.setIsFollowMe("1");
+            } else {
+                vo.setIsFollowMe("0");
+            }
+        }
+
+        // 返回动态最新的5条
+        List<LifeUserDynamicsVo> storeDynamicslist2 = storeDynamicslist.stream()
+                .limit(5).collect(Collectors.toList());
+        result.setDynamicsList(storeDynamicslist2);
+        //设置动态条数
+        Integer dynamicsNum = storeDynamicslist2.size();
+        result.setDynamicsNum(dynamicsNum);
+
+        // 获取店铺动态总数
+        result.setTotalDynamicsNum(storeDynamicslist.size());
+
+        //营业时间
+        List<StoreBusinessInfo> storeBusinessInfos = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, storeId).eq(StoreBusinessInfo::getDeleteFlag, 0));
+        if (ObjectUtils.isNotEmpty(storeBusinessInfos)) {
+            result.setStoreBusinessInfo(storeBusinessInfos.get(0));
+            result.setStoreBusinessInfos(storeBusinessInfos);
+            //StoreBusinessInfo storeBusinessInfo = result.getStoreBusinessInfo();
+            StoreBusinessInfo storeBusinessInfo = result.getStoreBusinessInfos().stream().filter(item -> item.getBusinessType() == 1).findFirst().orElse(null) ;
+            if (ObjectUtils.isNotEmpty(storeBusinessInfo)) {
+
+                Calendar calendar = Calendar.getInstance(); // 获取Calendar实例
+                int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 获取星期几,注意Calendar中的DAY_OF_WEEK是从1(代表星期天)开始的
+                String[] days = {"7", "1", "2", "3", "4", "5", "6"};
+                String day = days[dayOfWeek - 1];
+                if (storeBusinessInfo.getBusinessDate().contains(day)) {
+                    if (StringUtils.isNotEmpty(storeBusinessInfo.getStartTime()) && StringUtils.isNotEmpty(storeBusinessInfo.getEndTime())) {
+                        LocalTime now = LocalTime.now();
+                        List<String> startList = Arrays.asList(storeBusinessInfo.getStartTime().split(":"));
+                        List<String> endList = Arrays.asList(storeBusinessInfo.getEndTime().split(":"));
+                        LocalTime start = LocalTime.of(Integer.parseInt(startList.get(0)), Integer.parseInt(startList.get(1)));
+                        LocalTime end = LocalTime.of(Integer.parseInt(endList.get(0)), Integer.parseInt(startList.get(1)));
+                        if (now.isAfter(start) && now.isBefore(end)) {
+                            result.setYyFlag(1);
+                        } else {
+                            result.setYyFlag(0);
+                        }
+                    }
+                } else {
+                    result.setYyFlag(0);
+                }
+            }
+        }
+        LambdaQueryWrapper<StoreDictionary> storeDictionaryLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        storeDictionaryLambdaQueryWrapper.eq(StoreDictionary::getTypeName, "businessStatus")
+                .eq(StringUtils.isNotEmpty(result.getBusinessStatus().toString()), StoreDictionary::getDictId, result.getBusinessStatus());
+        List<StoreDictionary> storeDictionaries = storeDictionaryMapper.selectList(storeDictionaryLambdaQueryWrapper);
+        if (!storeDictionaries.isEmpty()) {
+            result.setBusinessStatusStr(storeDictionaries.get(0).getDictDetail());
+        }
+        return result;
+    }
+
+    @Override
+    public void approveStoreInfo(String storeId, Integer approvalStatus, String reason) {
+        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
+        storeInfo.setStoreApplicationStatus(approvalStatus);
+        storeInfo.setReason(reason);
+        StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()).eq(StoreUser::getDeleteFlag, 0));
+        storeInfoMapper.updateById(storeInfo);
+
+        //处理中台审核记录
+        LambdaUpdateWrapper<WebAudit> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(WebAudit::getStoreInfoId, storeId);
+        wrapper.set(WebAudit::getStatus, "1");
+        webAuditMapper.update(null, wrapper);
+
+        // 发送审核通知
+        LifeNotice lifeNotice = new LifeNotice();
+        lifeNotice.setSenderId("system");
+        lifeNotice.setReceiverId("store_" + storeUser.getPhone());
+        lifeNotice.setBusinessId(storeInfo.getId());
+        lifeNotice.setTitle("店铺审核通知");
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String createDate = simpleDateFormat.format(storeInfo.getCreatedTime());
+
+        com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
+        if (2 == approvalStatus) {
+            jsonObject.put("message", "您在"+createDate+"提交的入驻店铺申请,审核失败。失败原因:"+reason+"。");
+        } else {
+            jsonObject.put("message", "您在"+createDate+"提交的入驻店铺申请,已通过审核,欢迎您的加入。");
+        }
+        lifeNotice.setContext(jsonObject.toJSONString());
+        lifeNotice.setNoticeType(1); // 系统通知
+        lifeNotice.setIsRead(0);
+        lifeNoticeMapper.insert(lifeNotice);
+
+        WebSocketVo websocketVo = new WebSocketVo();
+        websocketVo.setSenderId("system");
+        websocketVo.setReceiverId("store_" + storeUser.getPhone());
+        websocketVo.setCategory("notice");
+        websocketVo.setNoticeType("1");
+        websocketVo.setIsRead(0);
+        websocketVo.setText(com.alibaba.fastjson2.JSONObject.from(lifeNotice).toJSONString());
+    }
+
+    @Override
+    public String exportExcel(String id, String storePhone, String businessSection, String storeApplicationStatusStr) throws IOException {
+        // 定义格式化模式
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        // 先将 Date 转换为 Instant
+        List<StoreInfoVo> storeInfoVos = storeInfoMapper.getStoreInfoVo(new QueryWrapper<StoreInfoVo>().like(StringUtils.isNotEmpty(id), "a.id", id).like(StringUtils.isNotEmpty(storePhone), "b.phone", storePhone).eq(StringUtils.isNotEmpty(storeApplicationStatusStr), "a.store_application_status", storeApplicationStatusStr).eq(StringUtils.isNotEmpty(businessSection), "a.business_section", businessSection).eq("a.delete_flag", 0).eq("b.delete_flag", 0).orderByDesc("a.created_time"));
+        List<StoreInfoExcelVo> storeInfoExcelVos = new ArrayList<>();
+        int serialNumber = 0;
+        for (StoreInfoVo storeInfoVo : storeInfoVos) {
+            StoreInfoExcelVo storeInfoExcelVo = new StoreInfoExcelVo();
+            //存入序号
+            storeInfoExcelVo.setSerialNumber(++serialNumber);
+            //获取营业执照图片
+            List<StoreImg> storeImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfoVo.getId()).eq(StoreImg::getImgType, 14));
+            storeInfoExcelVo.setBusinessLicense(storeImgs != null && storeImgs.size() > 0 ? storeImgs.get(0).getImgUrl() : "");
+            //获取合同图片
+            List<StoreImg> storeContractImgs = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, storeInfoVo.getId()).eq(StoreImg::getImgType, 15));
+            storeInfoExcelVo.setContractImage(storeContractImgs != null && storeContractImgs.size() > 0 ? storeContractImgs.get(0).getImgUrl() : "");
+            BeanUtils.copyProperties(storeInfoVo, storeInfoExcelVo);
+            Instant instant = storeInfoVo.getCreatedTime().toInstant();
+            // 格式化时间
+            String formattedTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
+            storeInfoExcelVo.setCreatedTime(formattedTime);
+            //格式化状态
+            storeInfoExcelVo.setStoreStatus(storeInfoVo.getStoreStatus() == 0 ? "禁用" : "正常");
+            //格式化审批状态
+            Integer storeApplicationStatus = storeInfoVo.getStoreApplicationStatus();
+            if (storeApplicationStatus == 0) {
+                storeInfoExcelVo.setStoreApplicationStatus("待审批");
+            } else if (storeApplicationStatus == 1) {
+                storeInfoExcelVo.setStoreApplicationStatus("审批通过");
+            } else if (storeApplicationStatus == 2) {
+                storeInfoExcelVo.setStoreApplicationStatus("审批拒绝");
+            }
+            //存入创建时间
+            storeInfoExcelVos.add(storeInfoExcelVo);
+        }
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeInfoExcelVos, StoreInfoExcelVo.class);
+        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
+    }
+
+    @Override
+    public String exportExcelExpirationTime(String id, String expiredState) throws IOException {
+        // 获取当前时刻
+        Date currentDate = new Date();
+        // 定义格式化模式
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        // 先将 Date 转换为 Instant
+        List<StoreInfoVo> storeInfoVos = storeInfoMapper.getStoreInfoVo(new QueryWrapper<StoreInfoVo>().like(StringUtils.isNotEmpty(id), "a.id", id).eq("a.delete_flag", 0).eq("b.delete_flag", 0).orderByDesc("a.created_time"));
+        List<StoreInfoExpiredRecordsExcelVo> storeInfoExpiredRecordsExcelVos = new ArrayList<>();
+        int serialNumber = 0;
+        for (StoreInfoVo storeInfoVo : storeInfoVos) {
+            StoreInfoExpiredRecordsExcelVo storeInfoExpiredRecordsExcelVo = new StoreInfoExpiredRecordsExcelVo();
+            storeInfoExpiredRecordsExcelVo.setSerialNumber(++serialNumber);
+            BeanUtils.copyProperties(storeInfoVo, storeInfoExpiredRecordsExcelVo);
+            if (storeInfoVo.getExpirationTime() != null) {
+                Instant instant = storeInfoVo.getExpirationTime().toInstant();
+                // 格式化时间
+                String formattedTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
+                storeInfoExpiredRecordsExcelVo.setExpirationTime(formattedTime);
+                //格式化过期状态
+                //处理一下到期状态
+                Date expirationTime = storeInfoVo.getExpirationTime();
+                // 获取当前时间
+                Calendar now = Calendar.getInstance();
+                Date nowCurrentDate = now.getTime();
+
+                // 计算 30 天后的时间
+                now.add(Calendar.DAY_OF_YEAR, 30);
+                Date thirtyDaysLater = now.getTime();
+                // 比较两个日期
+                if (expirationTime.after(currentDate)) {
+                    storeInfoExpiredRecordsExcelVo.setExpiredState("未过期");
+                    if (expirationTime != null && (expirationTime.after(nowCurrentDate) || expirationTime.equals(nowCurrentDate)) && expirationTime.before(thirtyDaysLater)) {
+                        storeInfoExpiredRecordsExcelVo.setExpiredState("即将过期");
+                    }
+                } else {
+                    storeInfoExpiredRecordsExcelVo.setExpiredState("已过期");
+                }
+                // 获取当前时间
+                LocalDate nowLocal = LocalDate.now();
+                // 将 expirationTime 转换为 LocalDate
+                LocalDate expDate = expirationTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+
+                // 计算距离到期的天数
+                long daysToExpire = ChronoUnit.DAYS.between(nowLocal, expDate);
+                storeInfoExpiredRecordsExcelVo.setDaysToExpire(daysToExpire > 0 ? daysToExpire : 0);
+
+                //存入创建时间
+                if (StringUtils.isNotEmpty(expiredState)) {
+                    String expiredStateName = storeInfoExpiredRecordsExcelVo.getExpiredState();
+                    if (expiredState.equals("0") && expiredStateName.equals("未过期")) {
+                        storeInfoExpiredRecordsExcelVos.add(storeInfoExpiredRecordsExcelVo);
+                    }
+                    if (expiredState.equals("1") && expiredStateName.equals("即将过期")) {
+                        storeInfoExpiredRecordsExcelVos.add(storeInfoExpiredRecordsExcelVo);
+                    }
+                    if (expiredState.equals("2") && expiredStateName.equals("已过期")) {
+                        storeInfoExpiredRecordsExcelVos.add(storeInfoExpiredRecordsExcelVo);
+                    }
+                } else {
+                    storeInfoExpiredRecordsExcelVos.add(storeInfoExpiredRecordsExcelVo);
+                }
+            }
+        }
+        String fileName = UUID.randomUUID().toString().replace("-", "");
+        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeInfoExpiredRecordsExcelVos, StoreInfoExpiredRecordsExcelVo.class);
+        String url = aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
+        new File(filePath).delete();
+        return url;
+    }
+
+    @Override
+    public IPage<StoreInfo> getScreening(ScreeningOfEightMajorCategoriesVO vo) {
+        // 参数校验
+        if (vo == null) {
+            throw new IllegalArgumentException("筛选参数不能为空");
+        }
+
+        // 创建分页对象
+        IPage<StoreInfo> page = new Page<>(vo.getPageNum(), vo.getPageSize());
+
+        // 获取筛选条件
+        String screeningId = vo.getScreeningId();
+        Double lon = vo.getLon();
+        Double lat = vo.getLat();
+        Double distance = vo.getDistance();
+        Boolean flag = vo.getFlag();
+        String startTime = vo.getStartTime();
+        String endTime = vo.getEndTime();
+        Double priceStr = vo.getPriceStr();
+        Double priceEnd = vo.getPriceEnd();
+
+        // 验证经纬度和距离参数
+        if (flag != null && flag) {
+            if (lon == null || lat == null || distance == null) {
+                throw new IllegalArgumentException("启用距离筛选时,经纬度和距离参数不能为空");
+            }
+            if (distance <= 0) {
+                throw new IllegalArgumentException("距离参数必须大于0");
+            }
+        }
+
+        String storeId = "";
+
+        // 通过筛选id获取商家id
+        if (StringUtils.isNotEmpty(screeningId)) {
+            String[] list = screeningId.split(",");
+            for (String id : list) {
+                if (StringUtils.isEmpty(storeId)) {
+                    storeId = baseRedisService.getString(id);
+                } else {
+                    String redisStoreId = baseRedisService.getString(id);
+                    if (redisStoreId != null) {
+                        storeId = findCommon(storeId, redisStoreId);
+                    }
+                }
+            }
+        }
+
+        // 通过商家id获取商家信息
+        IPage<StoreInfo> storeInfoIPage = new Page<>();
+
+        if (StringUtils.isNotEmpty(storeId)) {
+            List<String> storeIds = Arrays.asList(storeId.split(","));
+            if (StringUtils.isNotEmpty(startTime) && StringUtils.isNotEmpty(endTime)) {
+                List<StoreBusinessInfo> storeBusinessInfos = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().in(StoreBusinessInfo::getStoreId, storeIds));
+                DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendValue(ChronoField.HOUR_OF_DAY, 1, 2, java.time.format.SignStyle.NOT_NEGATIVE).appendLiteral(':').appendValue(ChronoField.MINUTE_OF_HOUR, 2).toFormatter();
+                List<StoreBusinessInfo> list = storeBusinessInfos.stream().filter(item -> {
+                    // 商家开门时间
+                    LocalTime timeStart = LocalTime.parse(item.getEndTime(), formatter);
+                    // 商家关门时间
+                    LocalTime timeEnd = LocalTime.parse(item.getEndTime(), formatter);
+                    // 开始时间
+                    LocalTime time1 = LocalTime.parse(startTime);
+                    // 结束时间
+                    LocalTime time2 = LocalTime.parse(endTime);
+                    return !time1.isBefore(timeStart) && !time2.isAfter(timeEnd);
+                }).collect(Collectors.toList());
+
+                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.toList());
+            }
+            storeIds.stream().filter(Objects::nonNull) // 确保 storeId 不为 null
+                    .distinct() // 去重
+                    .map(String::valueOf).collect(Collectors.toList());
+            if (priceStr != null && priceEnd != null) {
+                List<LifeCoupon> lifeCoupons = lifeCouponMapper.selectList(new LambdaQueryWrapper<LifeCoupon>().in(LifeCoupon::getStoreId, storeIds));
+                List<LifeCoupon> list = lifeCoupons.stream().filter(item -> Double.parseDouble(item.getPrice()) >= priceStr && Double.parseDouble(item.getPrice()) < priceEnd).collect(Collectors.toList());
+                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.toList());
+            }
+            if (!CollectionUtils.isEmpty(storeIds)) {
+                LambdaQueryWrapper<StoreInfo> queryWrapper = new LambdaQueryWrapper<>();
+                queryWrapper.in(StoreInfo::getId, storeIds);
+                storeInfoIPage = storeInfoMapper.selectPage(page, queryWrapper);
+            }
+        }
+        return storeInfoIPage;
+    }
+
+    @Override
+    public IPage<StoreInfoVo> getScreeningNew(ScreeningOfEightMajorCategoriesVO vo) {
+        // 参数校验
+        if (vo == null) {
+            throw new IllegalArgumentException("筛选参数不能为空");
+        }
+
+        // 获取筛选条件
+        String screeningId = vo.getScreeningId();
+        Double lon = vo.getLon();
+        Double lat = vo.getLat();
+        Double distance = vo.getDistance();
+        Boolean flag = vo.getFlag();
+        String startTime = vo.getStartTime();
+        String endTime = vo.getEndTime();
+        Double priceStr = vo.getPriceStr();
+        Double priceEnd = vo.getPriceEnd();
+
+        if (lon == null || lat == null) {
+            throw new IllegalArgumentException("经纬度参数不能为空");
+        }
+        // 创建分页对象
+        IPage<StoreInfoVo> page = new Page<>(vo.getPageNum(), vo.getPageSize());
+
+        String storeId = "";
+
+        // 通过筛选id获取商家id
+        if (StringUtils.isNotEmpty(screeningId)) {
+            String[] list = screeningId.split(",");
+            for (String id : list) {
+                if (StringUtils.isEmpty(storeId)) {
+                    storeId = baseRedisService.getString(id);
+                } else {
+                    String redisStoreId = baseRedisService.getString(id);
+                    if (redisStoreId != null) {
+                        storeId = findCommon(storeId, redisStoreId);
+                    }
+                }
+            }
+        }
+
+        // 通过商家id获取商家信息
+        IPage<StoreInfoVo> storeInfoIPage = new Page<>();
+        QueryWrapper<StoreInfoVo> queryWrapper = new QueryWrapper<>();
+        if (StringUtils.isNotEmpty(storeId)) {
+            List<String> storeIds = Arrays.asList(storeId.split(","));
+            if (StringUtils.isNotEmpty(startTime) && StringUtils.isNotEmpty(endTime)) {
+                List<StoreBusinessInfo> storeBusinessInfos = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().in(StoreBusinessInfo::getStoreId, storeIds));
+                DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendValue(ChronoField.HOUR_OF_DAY, 1, 2, java.time.format.SignStyle.NOT_NEGATIVE).appendLiteral(':').appendValue(ChronoField.MINUTE_OF_HOUR, 2).toFormatter();
+                List<StoreBusinessInfo> list = storeBusinessInfos.stream().filter(item -> {
+                    // 商家开门时间
+                    LocalTime timeStart = LocalTime.parse(item.getEndTime(), formatter);
+                    // 商家关门时间
+                    LocalTime timeEnd = LocalTime.parse(item.getEndTime(), formatter);
+                    // 开始时间
+                    LocalTime time1 = LocalTime.parse(startTime);
+                    // 结束时间
+                    LocalTime time2 = LocalTime.parse(endTime);
+                    return !time1.isBefore(timeStart) && !time2.isAfter(timeEnd);
+                }).collect(Collectors.toList());
+
+                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.toList());
+            }
+            storeIds.stream().filter(Objects::nonNull) // 确保 storeId 不为 null
+                    .distinct() // 去重
+                    .map(String::valueOf).collect(Collectors.toList());
+            if (priceStr != null && priceEnd != null) {
+                List<LifeCoupon> lifeCoupons = lifeCouponMapper.selectList(new LambdaQueryWrapper<LifeCoupon>().in(LifeCoupon::getStoreId, storeIds));
+                List<LifeCoupon> list = lifeCoupons.stream().filter(item -> Double.parseDouble(item.getPrice()) >= priceStr && Double.parseDouble(item.getPrice()) < priceEnd).collect(Collectors.toList());
+                storeIds = list.stream().map(item -> String.valueOf(item.getStoreId())).collect(Collectors.toList());
+            }
+            if (!CollectionUtils.isEmpty(storeIds)) {
+                queryWrapper.in("a.id", storeIds);
+            }
+        }
+
+        queryWrapper.eq("a.delete_flag", 0);
+        queryWrapper.eq("a.logout_flag", 0);
+        queryWrapper.ne("a.store_status", 0);
+
+        queryWrapper.ge("a.food_licence_expiration_time", new Date());
+
+        queryWrapper.like(StringUtils.isNotEmpty(vo.getFoodType()), "a.business_types_name", vo.getFoodType());
+        queryWrapper.like(StringUtils.isNotEmpty(vo.getStoreName()), "a.store_name", vo.getStoreName());
+
+        if (ObjectUtils.isNotEmpty(vo.getRqyx())) {
+            if (vo.getRqyx() == 1) {
+                queryWrapper.orderByDesc("collect_num");
+            }
+        }
+
+        if (ObjectUtils.isNotEmpty(vo.getKwyx())) {
+            if (vo.getKwyx() == 1) {
+                queryWrapper.orderByDesc("taste_score");
+            }
+        }
+
+        if (ObjectUtils.isNotEmpty(vo.getHjyx())) {
+            if (vo.getHjyx() == 1) {
+                queryWrapper.orderByDesc("en_score");
+            }
+        }
+
+        if (ObjectUtils.isNotEmpty(vo.getFwyx())) {
+            if (vo.getFwyx() == 1) {
+                queryWrapper.orderByDesc("service_score");
+            }
+        }
+
+        if (ObjectUtils.isNotEmpty(vo.getHpyx())) {
+            if (vo.getHpyx() == 1) {
+                queryWrapper.orderByDesc("score_avg");
+            }
+        }
+        queryWrapper.orderByAsc("dist");
+        storeInfoIPage = storeInfoMapper.getPageForDistance(page, lon + "," + lat, queryWrapper);
+        List<StoreInfoVo> storeInfoVoList = storeInfoIPage.getRecords();
+
+        // 提取所有符合条件的门店ID
+        List<Integer> storeIds = storeInfoVoList.stream().map(StoreInfoVo::getId).collect(Collectors.toList());
+        // 构建查询优惠券的条件对象
+        LambdaUpdateWrapper<LifeCoupon> quanWrapper = new LambdaUpdateWrapper<>();
+        // 添加门店ID筛选条件
+        quanWrapper.in(ObjectUtils.isNotEmpty(storeIds),LifeCoupon::getStoreId, storeIds)
+                // 添加优惠券状态筛选条件
+                .eq(LifeCoupon::getStatus, CouponStatusEnum.ONGOING.getCode())
+                // 按照创建时间降序排序
+                .orderByDesc(LifeCoupon::getCreatedTime);
+        // 查询符合条件的优惠券列表
+        List<LifeCoupon> quanList = lifeCouponMapper.selectList(quanWrapper);
+        // 构建查询团购套餐条件对象
+        LambdaUpdateWrapper<LifeGroupBuyMain> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        // 添加门店ID筛选条件
+        lambdaUpdateWrapper.in(ObjectUtils.isNotEmpty(storeIds),LifeGroupBuyMain::getStoreId, storeIds)
+                // 添加团购套餐状态筛选条件
+                .eq(LifeGroupBuyMain::getStatus, 5)
+                .orderByDesc(LifeGroupBuyMain::getCreatedTime);
+        // 查询符合条件的团购套餐列表
+        List<LifeGroupBuyMain> lifeGroupBuyMainList = lifeGroupBuyMainMapper.selectList(lambdaUpdateWrapper);
+        // 获取全部店铺的评分与平均花销
+        Map<String, List<Map<String, Object>>> avgScoreMap = storeEvaluationMapper.allStoreAvgScore().stream().collect(Collectors.groupingBy(o -> o.get("store_id").toString()));
+        // 获取用户订单信息,用于计算平均消费
+        Map<String, List<Map<String, Object>>> avgPriceMap = lifeUserOrderMapper.allStoreAvgPrice().stream().collect(Collectors.groupingBy(o -> o.get("store_id").toString()));
+        // 获取所有店铺的打卡次数
+        // 遍历所有门店信息,构造返回结果
+        for (StoreInfoVo store : storeInfoVoList) {
+            Map<String, Object> storeMap = new HashMap<>();
+            storeMap.put("dist", store.getDist());
+            // 添加门店的业务状态及其描述
+            storeMap.put("businessStatus", store.getBusinessStatus());
+            storeMap.put("businessStatusStr", store.getBusinessStatusStr());
+            // 添加门店ID
+            storeMap.put("storeId", store.getId());
+            // 如果存在评分数据,则添加评分、平均消费及评价总数
+            if (avgScoreMap.containsKey(String.valueOf(store.getId()))) {
+                store.setAvgScore(new BigDecimal(avgScoreMap.get(String.valueOf(store.getId())).get(0).get("avg_score").toString()).setScale(1, RoundingMode.HALF_UP).toString());
+                store.setTotalNum(avgScoreMap.get(String.valueOf(store.getId())).get(0).get("total_num").toString());
+                /*storeMap.put("avgScore", avgScoreMap.get(String.valueOf(store.getId())).get(0).get("avg_score"));
+                storeMap.put("avgPrice", avgPriceMap.get(String.valueOf(store.getId())).get(0).get("avg_price"));
+                // 条数
+                storeMap.put("totalNum", avgScoreMap.get(String.valueOf(store.getId())).get(0).get("total_num"));*/
+            } else {
+                // 否则,设置默认值
+                /*storeMap.put("avgScore", 0);
+                storeMap.put("avgPrice", 0);
+                storeMap.put("totalNum", 0);*/
+                store.setAvgScore("0");
+                store.setTotalNum("0");
+            }
+            if (avgPriceMap.containsKey(String.valueOf(store.getId()))) {
+                store.setAvgPrice(avgPriceMap.get(String.valueOf(store.getId())).get(0).get("avg_price").toString());
+            } else {
+                store.setAvgPrice("0");
+            }
+            // 添加门店名称
+            storeMap.put("storeName", store.getStoreName());
+            // 添加门店地址
+            storeMap.put("storeAddress", store.getStoreAddress());
+            // 添加门店类型
+            storeMap.put("storeType", store.getStoreType());
+            // 添加门店入口图片
+            storeMap.put("entranceImage", store.getEntranceImage());
+            // 添加门店图片
+            storeMap.put("storeImage", store.getImgUrl());
+            // 解析并添加门店经纬度
+            String[] position = store.getStorePosition().split(",");
+            storeMap.put("longitude", position.length == 2 ? position[0] : "");
+            storeMap.put("latitude", position.length == 2 ? position[1] : "");
+            // 构造该门店的优惠券列表
+            List<Map<String, Object>> quanMapList = new ArrayList<>();
+            if (!quanList.isEmpty()) {
+                for (LifeCoupon quan : quanList) {
+                    // 如果优惠券的门店ID与当前门店ID匹配,则添加到优惠券列表中
+                    if (store.getId().toString().equals(quan.getStoreId())) {
+                        Map<String, Object> quanMap = new HashMap<>();
+                        quanMap.put("quanType", quan.getType());
+                        quanMap.put("name", quan.getName());
+                        quanMap.put("price", quan.getPrice());
+                        // 折扣价
+                        quanMap.put("offprice", quan.getOffprice());
+                        quanMap.put("quanId", quan.getId());
+                        quanMapList.add(quanMap);
+                    }
+                }
+                // 将优惠券列表添加到门店信息中
+                storeMap.put("quanList", quanMapList);
+                store.setQuanList(quanMapList);
+            }
+
+            // 构造该门店的团购套餐列表
+            List<LifeGroupBuyMainVo> lifeGroupBuyMains = new ArrayList<>();
+            if (!lifeGroupBuyMainList.isEmpty()) {
+                for (LifeGroupBuyMain quan : lifeGroupBuyMainList) {
+                    // 如果团购套餐的门店ID与当前门店ID匹配,则添加到团购列表中
+                    if (store.getId().toString().equals(quan.getStoreId())) {
+                        LifeGroupBuyMainVo lifeGroupBuyMainVo = new LifeGroupBuyMainVo();
+                        BeanUtils.copyProperties(quan, lifeGroupBuyMainVo);
+                        lifeGroupBuyMains.add(lifeGroupBuyMainVo);
+                    }
+                }
+                // 将团购套餐列表添加到门店信息中
+                storeMap.put("tuangouList", lifeGroupBuyMains);
+                // 将团购套餐列表添加到门店信息中
+                store.setTuangouList(lifeGroupBuyMains);
+            }
+            // 添加门店类型的描述
+            storeMap.put("storeTypeStr", store.getStoreTypeStr());
+            // 如果未找到打卡次数,则设置为0
+            if (null == storeMap.get("storeClockInCount")) {
+                storeMap.put("storeClockInCount", 0);
+                store.setStoreClockInCount("0");
+            }
+            // 将当前门店的信息添加到返回结果列表中
+//            returnMaps.add(storeMap);
+        }
+
+        return storeInfoIPage;
+    }
+
+    @Override
+    public List<StoreInfo> getBusinessTypesName(String businessTypesNames) {
+        String[] businessTypesName = businessTypesNames.split(",");
+        List<StoreInfo> storeInfos = new ArrayList<>();
+        for (String typesName : businessTypesName) {
+            LambdaQueryWrapper<StoreInfo> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.like(StoreInfo::getBusinessTypesName, typesName);
+            List<StoreInfo> infos = storeInfoMapper.selectList(queryWrapper);
+            storeInfos.addAll(infos);
+        }
+        return new ArrayList<>(storeInfos.stream().collect(Collectors.toMap(StoreInfo::getId, info -> info, (existing, replacement) -> existing)).values());
+    }
+
+    public static String findCommon(String... strings) {
+        if (strings == null || strings.length == 0) {
+            return "";
+        }
+        // 将第一个字符串拆分成集合
+        Set<String> common = new HashSet<>(Arrays.asList(strings[0].split(",")));
+        // 遍历其余字符串
+        for (int i = 1; i < strings.length; i++) {
+            Set<String> currentSet = new HashSet<>(Arrays.asList(strings[i].split(",")));
+            // 找出共同元素
+            common.retainAll(currentSet);
+        }
+        // 将共同元素集合转换为以逗号分隔的字符串
+        return String.join(",", common);
+    }
+
+    /**
+     * 根据过期时间修改状态
+     */
+    public void checkAndUpdateExpiredRecords() {
+        LambdaUpdateWrapper<StoreInfo> queryWrapper = new LambdaUpdateWrapper<>();
+        queryWrapper.isNotNull(StoreInfo::getExpirationTime).lt(StoreInfo::getExpirationTime, LocalDateTime.now()).eq(StoreInfo::getBusinessStatus, 0).set(StoreInfo::getBusinessStatus, 99);
+        this.update(queryWrapper);
+    }
+
+    @Override
+    public void logoutStore(StoreInfoVo storeInfo) {
+        // 通过id获取当前店铺信息
+        LambdaQueryWrapper<StoreInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(StoreInfo::getId, storeInfo.getId());
+        StoreInfo storeIn = storeInfoMapper.selectOne(lambdaQueryWrapper);
+        if (storeIn != null) {
+            // 添加注销原因
+            storeIn.setLogoutReason(storeInfo.getLogoutReason());
+            // 添加注销code
+            storeIn.setLogoutCode(storeInfo.getLogoutCode());
+            // 注销中状态
+            storeIn.setStoreStatus(-1);
+            // 添加注销申请时间
+            storeIn.setLogoutTime(new Date());
+            // 更新logout_flag状态为1
+            storeIn.setLogoutFlag(1);
+            int num = storeInfoMapper.updateById(storeIn);
+            if (num > 0) {
+                // 发送通知
+                LifeNotice lifeMessage = getLifeNotice(storeInfo);
+                lifeNoticeMapper.insert(lifeMessage);
+                WebSocketVo websocketVo = new WebSocketVo();
+                websocketVo.setSenderId("system");
+                websocketVo.setReceiverId("store_" + storeInfo.getStorePhone());
+                websocketVo.setCategory("notice");
+                websocketVo.setNoticeType("1");
+                websocketVo.setIsRead(0);
+                websocketVo.setText(com.alibaba.fastjson2.JSONObject.from(lifeMessage).toJSONString());
+            }
+        }
+    }
+
+    private static LifeNotice getLifeNotice(StoreInfoVo storeInfo) {
+        LifeNotice lifeMessage = new LifeNotice();
+        lifeMessage.setReceiverId("store_" + storeInfo.getStorePhone());
+        String text = "您提交的店铺注销申请已成功接收,系统将按流程进行处理。注销申请提交后,将进入7天的冷静期,期间您可随在【我的设置】-【店铺信息】-【操作】-【注销店铺】中撤回申请,冷静期结束后,系统将正式开始注销操作,店铺内所数据将被永久清除,且无法恢复。如有疑问,可联系客服咨询,感谢您使用我们的服务。";
+        com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
+        jsonObject.put("message", text);
+        lifeMessage.setContext(jsonObject.toJSONString());
+        lifeMessage.setTitle("注销店铺通知");
+        lifeMessage.setSenderId("system");
+        lifeMessage.setIsRead(0);
+        lifeMessage.setNoticeType(1);
+        return lifeMessage;
+    }
+
+    @Override
+    public void cancelLogoutStore(StoreInfoVo storeInfo) {
+        // 通过id获取当前商家账号信息
+        LambdaQueryWrapper<StoreInfo> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
+        storeUserLambdaQueryWrapper.eq(StoreInfo::getId, storeInfo.getId());
+        StoreInfo storeIn = storeInfoMapper.selectOne(storeUserLambdaQueryWrapper);
+        // 修改注销标记为0
+        storeIn.setLogoutFlag(0);
+        // 注销状态变为可用
+        storeIn.setStoreStatus(1);
+        // 清空注销原因
+        storeIn.setLogoutReason("");
+        // 清空注销code
+        storeIn.setLogoutCode("");
+        // 清空注销申请时间
+        storeIn.setLogoutTime(null);
+        int num = storeInfoMapper.updateById(storeIn);
+        if (num > 0) {
+            // 发送通知
+            LifeNotice lifeMessage = new LifeNotice();
+            lifeMessage.setReceiverId("store_" + storeInfo.getStorePhone());
+            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            String storeDate = simpleDateFormat.format(new Date());
+            String text = "您在"+storeDate+"撤销了注销账号,所有数据均已保留,您可继续在平台使用。";
+            com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
+            jsonObject.put("message", text);
+            lifeMessage.setContext(jsonObject.toJSONString());
+            lifeMessage.setTitle("撤销注销店铺通知");
+            lifeMessage.setSenderId("system");
+            lifeMessage.setIsRead(0);
+            lifeMessage.setNoticeType(1);
+            lifeNoticeMapper.insert(lifeMessage);
+
+            WebSocketVo websocketVo = new WebSocketVo();
+            websocketVo.setSenderId("system");
+            websocketVo.setReceiverId("store_" + storeInfo.getStorePhone());
+            websocketVo.setCategory("notice");
+            websocketVo.setNoticeType("1");
+            websocketVo.setIsRead(0);
+            websocketVo.setText(com.alibaba.fastjson2.JSONObject.from(lifeMessage).toJSONString());
+        }
+    }
+
+    @Override
+    public List<StoreInfo> getStoreInfoByStoreTel(String storeTel) {
+        LambdaQueryWrapper<StoreInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreInfo::getStoreTel, storeTel);
+        return storeInfoMapper.selectList(queryWrapper);
+    }
+
+    @Override
+    public int editStoreCommissionRate(StoreInfoDto storeInfoDto) {
+        LambdaUpdateWrapper<StoreInfo> wrapper = new LambdaUpdateWrapper<>();
+        wrapper.eq(StoreInfo::getId, storeInfoDto.getId());
+        wrapper.set(StoreInfo::getCommissionRate, storeInfoDto.getCommissionRate());
+        return storeInfoMapper.update(null, wrapper);
+    }
+
+    @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;
+        }
+    }
+
+    // 抽取:根据区域编码查询区域名称(通用方法)
+    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() : "";
+    }
+
+    @Override
+    public Map<String, String> storeInfoVerification(int id) {
+        Map<String, String> storeInfoMap = new HashMap<>();
+        LambdaQueryWrapper<StoreInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreInfo::getId, id);
+        StoreInfo storeInfo = storeInfoMapper.selectOne(queryWrapper);
+//      当前时间 string类型的当前时间
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = new Date();
+        String formattedDate = sdf.format(date);
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.add(Calendar.DAY_OF_YEAR, -4);
+        Date startDay = calendar.getTime();
+        String startDayS = sdf.format(startDay);
+        if (storeInfo != null) {
+            //判断店铺存在未体现金额 0:未通过 1:通过
+            //判断店铺存在未完成订单 0:未通过 1:通过
+//            List<LifeUserOrder> lifeUserOrders = lifeUserOrderMapper.selectList(new LambdaQueryWrapper<LifeUserOrder>().in(LifeUserOrder::getStatus, 0, 1).eq(LifeUserOrder::getStoreId, id).eq(LifeUserOrder::getDeleteFlag, 0));
+//            if (!CollectionUtils.isEmpty(lifeUserOrders)) {
+//                storeInfoMap.put("storeOrderStatus", "0");
+//            } else {
+//                storeInfoMap.put("storeOrderStatus", "1");
+//            }
+            //判断店铺存在正在售卖的商品 0:未通过 1:通过  storeGoodsStatus 代金券   storeGroupStatus 团购
+            List<LifeGroupBuyMain> lifeGroupBuyMainList = lifeGroupBuyMainMapper.selectList(new LambdaQueryWrapper<LifeGroupBuyMain>().eq(LifeGroupBuyMain::getStoreId, id).eq(LifeGroupBuyMain::getStatus, 5).eq(LifeGroupBuyMain::getDeleteFlag, 0));
+            List<LifeCoupon> lifeCoupons = lifeCouponMapper.selectList(new LambdaQueryWrapper<LifeCoupon>().in(LifeCoupon::getStatus, 5).and(qw -> qw.gt(LifeCoupon::getSingleQty, 0)).eq(LifeCoupon::getStoreId, id).eq(LifeCoupon::getType, 1).eq(LifeCoupon::getDeleteFlag, 0));
+            if (!CollectionUtils.isEmpty(lifeCoupons) ) {
+                storeInfoMap.put("storeGoodsStatus", "0");
+            } else {
+                storeInfoMap.put("storeGoodsStatus", "1");
+            }
+            if (!CollectionUtils.isEmpty(lifeGroupBuyMainList)) {
+                storeInfoMap.put("storeGroupStatus", "0");
+            } else {
+                storeInfoMap.put("storeGroupStatus", "1");
+            }
+
+        }
+        return storeInfoMap;
+    }
+
+    @Override
+    public void deleteManualStoreInfo(int id) {
+        LambdaQueryWrapper<StoreInfo> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(StoreInfo::getId, id);
+        StoreInfo storeInfo = storeInfoMapper.selectOne(queryWrapper);
+        if (storeInfo != null && storeInfo.getStoreStatus() == -1) {
+            storeInfoMapper.deleteById(id);
+            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId,id));
+            if(storeUser!= null){
+                UpdateWrapper<StoreUser> updateWrapper = new UpdateWrapper<>();
+                updateWrapper.eq("id", storeUser.getId());
+                updateWrapper.set("store_id", null);
+                storeUserMapper.update(null, updateWrapper);
+            }
+        }
+    }
+
+    @Override
+    public int uploadRenewalContract(List<StoreImg> storeImgList) {
+        //取出集合中门店id
+        Optional<Integer> storeId = storeImgList.stream().map(StoreImg::getStoreId).findFirst();
+        int value = storeId.orElse(0);
+        int num = 0;
+        //先清除数据
+        storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType,22).eq(StoreImg::getStoreId,value));
+        for (StoreImg renewContract : storeImgList) {
+            StoreImg storeImg = new StoreImg();
+            storeImg.setStoreId(renewContract.getStoreId());
+            storeImg.setImgType(22);
+            storeImg.setImgSort(renewContract.getImgSort());
+            storeImg.setImgDescription("续签合同图片");
+            storeImg.setImgUrl(renewContract.getImgUrl());
+            storeImg.setCreatedUserId(renewContract.getCreatedUserId());
+            num = storeImgMapper.insert(storeImg);
+        }
+        if (num > 0) {
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setRenewContractStatus(2);
+            storeInfo.setUpdateRenewContractTime(new Date());
+            storeInfo.setId(value);
+            storeInfoMapper.updateById(storeInfo);
+        }
+        return num;
+    }
+
+    @Override
+    public int uploadfoodLicence(StoreImg storeImg) {
+            storeImgMapper.delete(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType,24).eq(StoreImg::getStoreId,storeImg.getStoreId()));
+            storeImg.setImgType(24);
+            storeImg.setImgDescription("经营许可证审核通过前图片");
+            storeImgMapper.insert(storeImg);
+
+            licenseHistoryMapper.delete(new LambdaQueryWrapper<StoreLicenseHistory>()
+                    .eq(StoreLicenseHistory::getLicenseStatus,2)
+                    .eq(StoreLicenseHistory::getStoreId,storeImg.getStoreId()));
+            // 经营许可证历史表插入
+            StoreLicenseHistory licenseHistory = new StoreLicenseHistory();
+            licenseHistory.setStoreId(storeImg.getStoreId());
+            licenseHistory.setLicenseStatus(2);
+            licenseHistory.setLicenseExecuteStatus(2);
+            licenseHistory.setImgUrl(storeImg.getImgUrl());
+            licenseHistory.setDeleteFlag(0);
+            licenseHistoryMapper.insert(licenseHistory);
+
+            //更新店铺
+            StoreInfo storeInfo = new StoreInfo();
+            storeInfo.setFoodLicenceStatus(2);
+            storeInfo.setId(storeImg.getStoreId());
+            storeInfo.setUpdateFoodLicenceTime(new Date());
+        return storeInfoMapper.updateById(storeInfo);
+    }
+
+    @Override
+    public Map<String, Object> getStoreContractStatus(int id) {
+        Map<String, Object> map = new HashMap<>();
+        StoreInfo storeInfo = storeInfoMapper.selectOne(new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, id));
+        //审核通过给前台反显未提交
+        if (storeInfo.getRenewContractStatus() == 1) {
+            map.put("renewContractStatus", 0);
+        } else {
+            map.put("renewContractStatus", storeInfo.getRenewContractStatus());
+        }
+        //续签合同照片列表
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 22).eq(StoreImg::getStoreId, id));
+        if (!CollectionUtils.isEmpty(storeImgList)) {
+            map.put("contractImgList", storeImgList);
+        } else {
+            map.put("contractImgList", "");
+        }
+        if (storeInfo.getContractReason() != null) {
+            map.put("contractReason", storeInfo.getContractReason());
+        } else {
+            map.put("contractReason", "");
+        }
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> getStoreFoodLicenceStatus(int id) {
+        Map<String, Object> map = new HashMap<>();
+        StoreInfo storeInfo = storeInfoMapper.selectOne(new LambdaQueryWrapper<StoreInfo>().eq(StoreInfo::getId, id));
+        //审核通过给前台反显未提交
+        if (storeInfo.getFoodLicenceStatus() == 1) {
+            map.put("foodLicenceStatus", 0);
+        } else {
+            map.put("foodLicenceStatus", storeInfo.getFoodLicenceStatus());
+        }
+        //食品经营许可证照片列表
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 24).eq(StoreImg::getStoreId, id));
+            if (!CollectionUtils.isEmpty(storeImgList)) {
+                map.put("foodLicenceImgList", storeImgList);
+            } else {
+                map.put("foodLicenceImgList", "");
+        }
+        if (storeInfo.getFoodLicenceReason() != null) {
+            map.put("foodLicenceReason", storeInfo.getFoodLicenceReason());
+        } else {
+            map.put("foodLicenceReason", "");
+        }
+        return map;
+    }
+
+    @Override
+    public int conversionContract(int id) {
+        //删除原合同照片
+        LambdaQueryWrapper<StoreImg> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(StoreImg::getStoreId, id);
+        lambdaQueryWrapper.eq(StoreImg::getImgType, 15);
+        storeImgMapper.delete(lambdaQueryWrapper);
+        //修改续签合同类型为合同类型
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, id).eq(StoreImg::getImgType, 22));
+        List<Integer> imgList = storeImgList.stream().map(StoreImg::getId).collect(Collectors.toList());
+        LambdaUpdateWrapper<StoreImg> lambdaUpdateWrapper = new LambdaUpdateWrapper();
+        lambdaUpdateWrapper.in(StoreImg::getId, imgList).set(StoreImg::getImgType, 15).set(StoreImg::getImgDescription,"合同图片");
+        int num = storeImgMapper.update(null, lambdaUpdateWrapper);
+        return num;
+    }
+
+    @Override
+    public int foodLicenceType(int id) {
+        //删除原合同照片
+        LambdaUpdateWrapper<StoreImg> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
+        lambdaUpdateWrapper.eq(StoreImg::getStoreId, id);
+        lambdaUpdateWrapper.eq(StoreImg::getImgType, 25);
+        lambdaUpdateWrapper.set(StoreImg::getDeleteFlag,1);
+        storeImgMapper.update(null,lambdaUpdateWrapper);
+        //修改续签合同类型为合同类型
+        List<StoreImg> storeImgList = storeImgMapper.selectList(new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getStoreId, id).eq(StoreImg::getImgType, 24));
+        List<Integer> imgList = storeImgList.stream().map(StoreImg::getId).collect(Collectors.toList());
+        LambdaUpdateWrapper<StoreImg> imgLambdaUpdateWrapper = new LambdaUpdateWrapper();
+        imgLambdaUpdateWrapper.in(StoreImg::getId, imgList).set(StoreImg::getImgType, 25).set(StoreImg::getImgDescription,"经营许可证审核通过图片");
+        int num = storeImgMapper.update(null, imgLambdaUpdateWrapper);
+
+        // 将原来的食品经营许可证历史表数据删除
+        licenseHistoryMapper.delete(new LambdaQueryWrapper<StoreLicenseHistory>()
+                .eq(StoreLicenseHistory::getStoreId,id)
+                .eq(StoreLicenseHistory::getLicenseStatus,2)
+                .eq(StoreLicenseHistory::getLicenseExecuteStatus,1)
+                .eq(StoreLicenseHistory::getDeleteFlag,0));
+
+        // 将新的食品经营许可证历史表数据变为审核通过
+        LambdaUpdateWrapper<StoreLicenseHistory> wrapper1 = new LambdaUpdateWrapper<>();
+        wrapper1.eq(StoreLicenseHistory::getStoreId, id);
+        wrapper1.eq(StoreLicenseHistory::getLicenseStatus, 2);
+        wrapper1.eq(StoreLicenseHistory::getLicenseExecuteStatus, 2);
+        wrapper1.eq(StoreLicenseHistory::getDeleteFlag, 0);
+        wrapper1.set(StoreLicenseHistory::getLicenseExecuteStatus, 1);
+        licenseHistoryMapper.update(null, wrapper1);
+
+        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("店铺有正在销售的商品");
+            }
+        }
+    }
+
+    public int updateStoreImgModeInfo(StoreImgInfoVo storeImgInfoVo) {
+        int result = 0;
+        if (storeImgInfoVo != null) {
+            // 校验必要参数是否为null
+            if (storeImgInfoVo.getStoreId() == null || storeImgInfoVo.getImgMode() == null) {
+                return result;
+            }
+            int imgType = storeImgInfoVo.getImgType();
+            LambdaUpdateWrapper<StoreInfo> wrapper = new LambdaUpdateWrapper<>();
+            wrapper.eq(StoreInfo::getId, storeImgInfoVo.getStoreId());
+            wrapper.set(StoreInfo::getImgMode, storeImgInfoVo.getImgMode());
+            result = storeInfoMapper.update(null, wrapper);
+        }
+        return result;
+    }
+}

+ 100 - 4
alien-store-platform/src/main/java/shop/alien/storeplatform/service/impl/StorePlatformInfoServiceImpl.java

@@ -1,6 +1,8 @@
 package shop.alien.storeplatform.service.impl;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
@@ -11,14 +13,15 @@ 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.entity.store.vo.StoreMainInfoVo;
+import shop.alien.entity.store.vo.StoreMenuVo;
 import shop.alien.mapper.*;
+import shop.alien.storeplatform.config.GaoDeMapUtil;
 import shop.alien.storeplatform.service.NearMeService;
 import shop.alien.storeplatform.service.StorePlatformInfoService;
+import shop.alien.util.common.DistanceUtil;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -41,6 +44,18 @@ public class StorePlatformInfoServiceImpl extends ServiceImpl<StoreInfoMapper, S
 
     private final NearMeService nearMeService;
 
+    private final StoreBusinessInfoMapper storeBusinessInfoMapper;
+
+    private final StoreImgMapper storeImgMapper;
+
+    private final StoreMenuMapper storeMenuMapper;
+
+    private final StoreLabelMapper storeLabelMapper;
+
+    private final StoreUserMapper storeUserMapper;
+
+    private final GaoDeMapUtil gaoDeMapUtil;
+
     @Override
     public int saveOrUpdateStoreInfo(StoreInfoDto storeInfodto) {
         if (storeInfodto.getId() != null) {
@@ -193,4 +208,85 @@ public class StorePlatformInfoServiceImpl extends ServiceImpl<StoreInfoMapper, S
         return Objects.nonNull(cityCode) ? cityCode.getAreaName() : "";
     }
 
+    @Override
+    public List<StoreBusinessInfo> getStoreInfoBusinessHours(Integer id) {
+        //营业时间
+        List<StoreBusinessInfo> storeBusinessInfoList = storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id));
+        return storeBusinessInfoList;
+    }
+
+    /**
+     * 门店详情
+     *
+     * @return StoreMainInfoVo
+     */
+    @Override
+    public StoreMainInfoVo getDetail(Integer id) {
+
+        StoreInfo storeInfo = storeInfoMapper.selectById(id);
+        if(storeInfo == null){
+            return null;
+        }
+        StoreMainInfoVo storeMainInfoVo = storeInfoMapper.getStoreInfo(id);
+
+        //判断门店是否到期
+        if (ObjectUtils.isNotEmpty(storeMainInfoVo.getExpirationTime())) {
+            if (new Date().after(storeMainInfoVo.getExpirationTime())) {
+                storeMainInfoVo.setExpirationFlag(0);
+            }else {
+                storeMainInfoVo.setExpirationFlag(1);
+            }
+        }else {
+            storeMainInfoVo.setExpirationFlag(1);
+        }
+
+        //存入门店地址、
+        storeMainInfoVo.setStoreAddress(storeInfo.getStoreAddress());
+        //入口图
+        LambdaQueryWrapper<StoreImg> inletsUrlQueryWrapper = new LambdaQueryWrapper<>();
+        inletsUrlQueryWrapper.eq(StoreImg::getImgType, 1);
+        inletsUrlQueryWrapper.eq(StoreImg::getStoreId, id);
+        List<StoreImg> inletsUrlList = storeImgMapper.selectList(inletsUrlQueryWrapper);
+        storeMainInfoVo.setInletsUrl(inletsUrlList.stream().sorted(Comparator.comparing(StoreImg::getImgSort)).map(StoreImg::getImgUrl).collect(Collectors.toList()));
+        //相册
+        LambdaQueryWrapper<StoreImg> albumUrlQueryWrapper = new LambdaQueryWrapper<>();
+        albumUrlQueryWrapper.eq(StoreImg::getImgType, 2);
+        albumUrlQueryWrapper.eq(StoreImg::getStoreId, id);
+        List<StoreImg> albumUrlList = storeImgMapper.selectList(albumUrlQueryWrapper);
+        storeMainInfoVo.setAlbumUrl(albumUrlList.stream().sorted(Comparator.comparing(StoreImg::getImgSort)).map(StoreImg::getImgUrl).collect(Collectors.toList()));
+        //推荐菜
+        storeMainInfoVo.setRecommendUrl(storeMenuMapper.getStoreMenuList(id, 1).stream().sorted(Comparator.comparing(StoreMenuVo::getImgSort)).collect(Collectors.toList()));
+        //菜单
+        storeMainInfoVo.setMenuUrl(storeMenuMapper.getStoreMenuList(id, 0).stream().sorted(Comparator.comparing(StoreMenuVo::getImgSort)).collect(Collectors.toList()));
+        //门店标签
+        storeMainInfoVo.setStoreLabel(storeLabelMapper.selectOne(new LambdaQueryWrapper<StoreLabel>().eq(StoreLabel::getStoreId, id)));
+        //营业时间
+        storeMainInfoVo.setStoreBusinessInfo(storeBusinessInfoMapper.selectList(new LambdaQueryWrapper<StoreBusinessInfo>().eq(StoreBusinessInfo::getStoreId, id)));
+        //门店头像
+        LambdaQueryWrapper<StoreImg> eq = new LambdaQueryWrapper<StoreImg>().eq(StoreImg::getImgType, 10).eq(StoreImg::getStoreId, id);
+        StoreImg storeImg = storeImgMapper.selectOne(eq);
+        storeMainInfoVo.setHeadImgUrl(storeImg != null ? storeImg.getImgUrl() : "");
+        List<StoreUser> storeUsers = storeUserMapper.selectList(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, storeInfo.getId()));
+        for (StoreUser storeUser : storeUsers) {
+            storeMainInfoVo.setLogoutFlagUser(storeUser.getLogoutFlag());
+        }
+        // 计算店铺到最近地铁站的距离
+        JSONObject nearbySubway = gaoDeMapUtil.getNearbySubway(storeMainInfoVo.getStorePosition().split(",")[0], storeMainInfoVo.getStorePosition().split(",")[1]);
+        // 地铁名
+        String subWayName = nearbySubway.getString("name");
+        storeMainInfoVo.setSubwayName(subWayName);
+        // 地铁站经纬度
+        String subWayJing = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[0];
+        String subWayWei = nearbySubway.getString("location") == null ? null : nearbySubway.getString("location").split(",")[1];
+        if ((subWayJing != null && !subWayJing.isEmpty()) && (subWayWei != null && !subWayWei.isEmpty())) {
+            double storeJing = Double.parseDouble(storeMainInfoVo.getStorePosition().split(",")[0]);
+            double storeWei = Double.parseDouble(storeMainInfoVo.getStorePosition().split(",")[1]);
+            double storeDistance2 = DistanceUtil.haversineCalculateDistance(Double.parseDouble(subWayJing), Double.parseDouble(subWayWei), storeJing, storeWei);
+            storeMainInfoVo.setDistance2(storeDistance2);
+        } else {
+            storeMainInfoVo.setDistance2(0);
+        }
+        return storeMainInfoVo;
+    }
+
 }

+ 234 - 0
alien-store-platform/src/main/java/shop/alien/storeplatform/util/FileUploadUtil.java

@@ -0,0 +1,234 @@
+package shop.alien.storeplatform.util;
+
+import com.alibaba.fastjson.JSONArray;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartRequest;
+import shop.alien.entity.store.vo.StoreImgVo;
+import shop.alien.mapper.StoreImgMapper;
+import shop.alien.util.ali.AliOSSUtil;
+import shop.alien.util.common.RandomCreateUtil;
+import shop.alien.util.common.VideoUtils;
+import shop.alien.util.file.FileUtil;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+
+/**
+ * 二期-文件上传
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class FileUploadUtil {
+
+    private final VideoUtils videoUtils;
+
+    private final StoreImgMapper storeImgMapper;
+
+    @Value("${spring.web.resources.static-locations}")
+    private String uploadDir;
+
+    private final AliOSSUtil aliOSSUtil;
+
+    List<String> imageFileType = Arrays.asList("jpg", "jpeg", "png", "bmp", "webp", "gif", "svg");
+    List<String> videoFileType = Arrays.asList("mp4", "avi", "flv", "mkv", "rmvb", "wmv", "3gp", "mov");
+    List<String> appFileType = Arrays.asList("apk", "ipk", "wgt");
+
+    /**
+     * 上传文件
+     *
+     * @param multipartFile 文件名
+     * @return 文件路径
+     */
+    public String uploadOneFile(MultipartFile multipartFile) {
+        try {
+            Map<String, String> fileNameAndType = FileUtil.getFileNameAndType(multipartFile);
+            String prefix = "";
+            if (imageFileType.contains(fileNameAndType.get("type").toLowerCase())) {
+                prefix = "image/";
+            } else if (videoFileType.contains(fileNameAndType.get("type").toLowerCase())) {
+                prefix = "video/";
+            }
+            return aliOSSUtil.uploadFile(multipartFile, prefix + fileNameAndType.get("name") + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type"));
+        } catch (Exception e) {
+            log.error("FileUpload.uploadOneFile ERROR Msg={}", e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 上传app文件
+     *
+     * @param multipartFile 文件名
+     * @return 文件路径
+     */
+    public String uploadApp(MultipartFile multipartFile) {
+        try {
+            Map<String, String> fileNameAndType = FileUtil.getFileNameAndType(multipartFile);
+            if (!appFileType.contains(fileNameAndType.get("type").toLowerCase())) {
+                log.error("FileUpload.uploadApp ERROR 该文件不是app格式文件");
+                return null;
+            }
+            String prefix = "app/";
+            return aliOSSUtil.uploadFile(multipartFile, prefix + fileNameAndType.get("name") + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type"));
+        } catch (Exception e) {
+            log.error("FileUpload.uploadApp ERROR Msg={}", e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 上传多个文件
+     *
+     * @param multipartRequest 多文件
+     * @return List<String>
+     */
+    public List<String> uploadMoreFile(MultipartRequest multipartRequest) {
+        try {
+            log.info("FileUpload.uploadMoreFile multipartRequest={}", multipartRequest.getFileNames());
+            Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+            List<String> filePathList = new ArrayList<>();
+            for (String s : fileNameSet) {
+                MultipartFile multipartFile = multipartRequest.getFileMap().get(s);
+                log.info("FileUpload.uploadMoreFile fileName={}", multipartFile.getOriginalFilename());
+                String uploadDir = this.uploadDir.replace("file:///", "").replace("\\", "/");
+                String prefix;
+                Map<String, String> fileNameAndType = FileUtil.getFileNameAndType(multipartFile);
+                //区分文件类型
+                if (imageFileType.contains(fileNameAndType.get("type").toLowerCase())) {
+                    uploadDir += "/image";
+                    prefix = "image/";
+                    log.info("FileUpload.uploadMoreFile 获取到图片文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
+                    filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + fileNameAndType.get("name") + RandomCreateUtil.getRandomNum(6) + "." + fileNameAndType.get("type")));
+                    ;
+                } else if (videoFileType.contains(fileNameAndType.get("type").toLowerCase())) {
+                    uploadDir += "/video/";
+                    prefix = "video/";
+                    //上传视频文件
+                    log.info("FileUpload.uploadMoreFile 获取到视频文件准备复制 {} {} {}", uploadDir, prefix, multipartFile.getOriginalFilename());
+                    String videoFileName = fileNameAndType.get("name") + RandomCreateUtil.getRandomNum(6);
+                    String cacheVideoPath = copyFile(uploadDir, multipartFile);
+                    filePathList.add(aliOSSUtil.uploadFile(multipartFile, prefix + videoFileName + "." + fileNameAndType.get("type")));
+                    //缓存视频截图使用
+                    File videoFile = new File(cacheVideoPath);
+                    //获取视频某帧截图
+                    log.info("FileUpload.uploadMoreFile 视频文件复制完毕, 获取第一秒图片 {}", videoFile.getName());
+                    String videoPath = videoUtils.getImg(uploadDir + "/" + videoFile.getName());
+                    log.info("FileUpload.uploadMoreFile 视频文件复制完毕, 图片位置 {}", videoPath);
+                    if (!videoPath.isEmpty()) {
+                        File videoImgFile = new File(videoPath);
+                        Map<String, String> videoImg = FileUtil.getFileNameAndType(videoImgFile);
+                        filePathList.add(aliOSSUtil.uploadFile(videoImgFile, prefix + videoFileName + "." + videoImg.get("type")));
+                        videoImgFile.delete();
+                        videoFile.delete();
+                    } else {
+                        throw new RuntimeException("视频截图失败");
+                    }
+                }
+            }
+            return filePathList;
+        } catch (Exception e) {
+            log.error("FileUpload.uploadMoreFile ERROR Msg={}", e.getMessage());
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 上传图片
+     *
+     * @param multipartRequest 文件
+     * @param list             图片List
+     * @return 图片id
+     */
+    public List<Integer> uploadImg(MultipartRequest multipartRequest, String list) {
+        JSONArray jsonArray = JSONArray.parseArray(list);
+        List<StoreImgVo> storeImgList = jsonArray.toJavaList(StoreImgVo.class);
+        List<Integer> resultList = new ArrayList<>();
+        Set<String> fileNameSet = multipartRequest.getMultiFileMap().keySet();
+        if (fileNameSet.size() != storeImgList.size()) {
+            log.error("FileUpload.uploadImg ERROR 文件数量与参数数量不匹配 fileNameSet{}, storeImgList={}", fileNameSet.size(), storeImgList.size());
+            throw new RuntimeException("文件数量与参数数量不匹配");
+        }
+        //匹配文件与数据
+        for (String s : fileNameSet) {
+            String[] split = s.split("_");
+            int index = Integer.parseInt(split[1]);
+            storeImgList.get(index).setName(s);
+        }
+        for (StoreImgVo storeImgVo : storeImgList) {
+            //获取文件
+            MultipartFile multipartFile = multipartRequest.getFileMap().get(storeImgVo.getName());
+            Map<String, String> fileInfo = FileUtil.getFileNameAndType(multipartFile);
+            String videoFileName = fileInfo.get("name") + RandomCreateUtil.getRandomNum(6);
+            String prefix;
+            String filePath = "";
+            if (imageFileType.contains(fileInfo.get("type").toLowerCase())) {
+                prefix = "image/";
+                filePath = aliOSSUtil.uploadFile(multipartFile, prefix + videoFileName + "." + fileInfo.get("type"));
+            } else if (videoFileType.contains(fileInfo.get("type").toLowerCase())) {
+                prefix = "video/";
+                filePath = aliOSSUtil.uploadFile(multipartFile, prefix + videoFileName + "." + fileInfo.get("type"));
+            }
+            storeImgVo.setImgUrl(filePath);
+            storeImgMapper.insert(storeImgVo);
+            resultList.add(storeImgVo.getId());
+        }
+        return resultList;
+    }
+
+    /**
+     * 复制文件, 返回url链接
+     *
+     * @param localFilePath 本地路径
+     * @param file          文件
+     * @return 访问url路径
+     */
+    private String copyFile(String localFilePath, MultipartFile file) {
+        try {
+            File cacheFilePath = new File(localFilePath);
+            if (!cacheFilePath.exists()) {
+                cacheFilePath.mkdirs();
+            }
+            String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.'));
+            log.info("FileUpload.copyFile fileName={}", fileName);
+            String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
+            log.info("FileUpload.copyFile fileType={}", fileType);
+            System.out.println(file.getOriginalFilename());
+            Path path = Paths.get(localFilePath, file.getOriginalFilename());
+            Files.createDirectories(path.getParent());
+            Files.write(path, file.getBytes());
+            return localFilePath + file.getOriginalFilename();
+        } catch (Exception e) {
+            log.error("FileUpload.copyFile ERROR Msg={}", e.getMessage());
+            return e.getMessage();
+        }
+    }
+
+    private String copyFile(String localFilePath, String urlPath, MultipartFile file) {
+        try {
+            String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.'));
+            log.info("FileUpload.copyFile fileName={}", fileName);
+            String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
+            log.info("FileUpload.copyFile fileType={}", fileType);
+            String newFileName = fileName + RandomCreateUtil.getRandomNum(6) + fileType;
+            log.info("FileUpload.copyFile newFileName={}", newFileName);
+            newFileName = newFileName.replaceAll(",", "");
+            log.info("FileUpload.copyFile newFileName={}", newFileName);
+            Path path = Paths.get(localFilePath, newFileName);
+            Files.createDirectories(path.getParent());
+            Files.write(path, file.getBytes());
+            return urlPath + newFileName;
+        } catch (Exception e) {
+            log.error("FileUpload.copyFile ERROR Msg={}", e.getMessage());
+            return e.getMessage();
+        }
+    }
+
+}