zepengdev
2025-07-14 43315000b2840313a5aff96bf314b3c061e4616d
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQueryServiceImpl.java
@@ -1,33 +1,85 @@
package com.oying.modules.pc.store.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.oying.modules.pc.store.domain.Store;
import com.oying.modules.pc.store.domain.dto.StoreCustomerDetailDto;
import com.oying.modules.pc.store.domain.dto.StoreCustomerQueryCriteria;
import com.oying.modules.pc.store.domain.dto.StoreQueryCriteria;
import com.oying.modules.pc.store.service.StoreQueryService;
import com.oying.modules.pc.store.service.StoreService;
import com.oying.utils.PageResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class StoreQueryServiceImpl implements StoreQueryService {
    private final RedisTemplate<Object, Object> redisTemplate;
    private final StoreService storeService;
    @Override
    public StoreCustomerDetailDto getCustomerStoreDetail(StoreCustomerQueryCriteria criteria) {
        Store store = storeService.getById(criteria.getStoreId());
        StoreCustomerDetailDto storeDto = new StoreCustomerDetailDto();
        BeanUtils.copyProperties(store, storeDto);
        storeDto.setName(store.getStoreName());
        storeDto.setLogoUrl("");
        storeDto.setBusinessHours("");
        storeDto.setDeliveryDuration(0);
        storeDto.setMonthlySales(0);
        storeDto.setScore(0);
        return storeDto;
    public PageResult<Store> findPagedStores(StoreQueryCriteria criteria) {
        PageResult<Store> page = new PageResult<>();
        // 1. 检查ZSET是否存在
        String setKey = criteria.buildConditionCacheKey();
        Long total = redisTemplate.opsForZSet().size(setKey);
        if (total == null || total == 0) {
            // 初始化缓存
            List<Long> ids = storeService.queryStoreIds(criteria);
            int index = 0;
            for (Long id : ids) {
                redisTemplate.opsForZSet().add(setKey, id, index++);
            }
            // 设置缓存过期时间
            redisTemplate.expire(setKey, 15, TimeUnit.MINUTES);
            total = (long) ids.size();
        }
        // 2. 从ZSET获取分页ID
        int current = (criteria.getPage() == null || criteria.getPage() < 1) ? 1 : criteria.getPage();
        int offset = (current - 1) * criteria.getSize();
        int end = offset + criteria.getSize() - 1;
        Set<Long> storeIds = Optional.ofNullable(redisTemplate.opsForZSet().range(setKey, offset, end))
                .orElse(Collections.emptySet())
                .stream()
                .map(i -> (Long) i)
                .collect(Collectors.toSet());
        // 3. 获取详情数据]
        List<Store> stores = Optional.of(storeIds)
                .filter(CollectionUtil::isNotEmpty)
                .map(storeService::getStoresByIds)
                .orElse(ListUtil.toList());
        stores.forEach(u -> u.setDeliveryDuration(distanceCalculation(criteria.getLatitude(), criteria.getLongitude(), u.getLatitude(), u.getLongitude())));
        page.setContent(stores);
        page.setTotalElements(total);
        return page;
    }
    private Integer distanceCalculation(double lat1, double lon1, double lat2, double lon2) {
        // 地球半径(千米)
        final int R = 6371;
        // 将纬度、经度从度转换为弧度
        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);
        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return new Double(R * c * 1000).intValue();
    }
}