package com.ylx.address.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ylx.address.domain.TAddress; import com.ylx.address.domain.dto.UserAddressAddDto; import com.ylx.address.domain.dto.UserAddressDeleteDto; import com.ylx.address.domain.dto.UserAddressDto; import com.ylx.address.domain.dto.UserAddressUpdateDto; import com.ylx.address.domain.vo.UserAddressVo; import com.ylx.address.mapper.TAddressMapper; import com.ylx.address.service.TAddressService; import com.ylx.area.service.AreaService; import com.ylx.common.utils.StringUtils; import com.ylx.massage.domain.dto.CoordinateDTO; import com.ylx.massage.domain.vo.CityInfoVo; import com.ylx.massage.domain.vo.MerchantCurrentAddressVO; import com.ylx.massage.domain.vo.UserAddressListVO; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; /** * 轮播图(TAddress)表服务实现类 * * @author makejava * @since 2024-04-11 17:18:53 */ @Service("tAddressService") @Slf4j public class TAddressServiceImpl extends ServiceImpl implements TAddressService { //0=未删除 private static final Integer NO_DELETE = 0; //1=用户 private static final Integer USER_TYPE = 1; //2=商户 private static final Integer MERCHANT_USER_TYPE = 2; //1=真实地址 private static final Integer TYPE = 1; //1=默认地址 private static final Integer IS_DEFAULT = 1; //0=不是默认地址 private static final Integer NO_DEFAULT = 0; @Resource private AreaService areaService; @Override public TAddress getByOpenId(String openId) { LambdaQueryWrapper objectLambdaQueryWrapper = new LambdaQueryWrapper<>(); objectLambdaQueryWrapper.eq(TAddress::getOpenid, openId).eq(TAddress::getType, 1); return this.getOne(objectLambdaQueryWrapper); } private List getAddressList(String openId, Integer userType,String cityCode) { LambdaQueryWrapper objectLambdaQueryWrapper = new LambdaQueryWrapper<>(); objectLambdaQueryWrapper.eq(TAddress::getOpenid, openId) .eq(TAddress::getUserType, userType) // cityCode不为null才添加eq条件 .and(StrUtil.isNotBlank(cityCode), w -> w.eq(TAddress::getCityCode, cityCode)) .eq(TAddress::getIsDelete,0) .orderByDesc(TAddress::getCreateTime); return this.list(objectLambdaQueryWrapper); } /** * 根据openId和userType获取地址列表 用户类型(1:用户 2:商户) * @param dto * @return */ @Override public List getByOpenIdList(UserAddressDto dto) { List addressList = getAddressList(dto.getOpenId(), 1,dto.getCityCode()); if (CollectionUtils.isEmpty(addressList)) { return Collections.emptyList(); } return addressList.stream().map(this::convertToVo).collect(Collectors.toList()); } @Override public List getPcUserAddressList(String openId) { return this.baseMapper.selectPcUserAddressList(openId); } @Override public MerchantCurrentAddressVO getCurrentMerchantAddress(Integer merchantId) { if (Objects.isNull(merchantId)) { throw new RuntimeException("商户id不能为空"); } return this.baseMapper.selectCurrentMerchantRealAddress(merchantId); } private UserAddressVo convertToVo(TAddress address) { UserAddressVo vo = new UserAddressVo(); BeanUtils.copyProperties(address, vo); return vo; } @Override @Transactional(rollbackFor = Exception.class) public Boolean defaultAddress(TAddress tAddress) { if (StringUtils.isBlank(tAddress.getOpenid())) { throw new RuntimeException("openid不能为空"); } // 查询默认地址 TAddress oldAddress = this.getByOpenId(tAddress.getOpenid()); if (oldAddress != null) { oldAddress.setType(0); this.updateById(oldAddress); } tAddress.setType(1); return this.updateById(tAddress); } @Override @Transactional(rollbackFor = Exception.class) public Object insertAddress(TAddress tAddress) { if (Objects.isNull(tAddress)) { throw new RuntimeException("地址信息不能为空"); } if (Objects.isNull(tAddress.getMerchantId())) { throw new RuntimeException("商户id不能为空"); } if (StringUtils.isBlank(tAddress.getAddress())) { throw new RuntimeException("地址不能为空"); } if (Objects.isNull(tAddress.getLongitude())) { throw new RuntimeException("经度不能为空"); } if (Objects.isNull(tAddress.getLatitude())) { throw new RuntimeException("纬度不能为空"); } TAddress oldDefaultAddress = this.getMerchantDefaultAddress(tAddress.getMerchantId()); boolean setAsDefault = oldDefaultAddress == null || IS_DEFAULT.equals(tAddress.getIsDefault()); fillMerchantAddressDefaults(tAddress, setAsDefault); if (oldDefaultAddress != null && IS_DEFAULT.equals(tAddress.getIsDefault())) { oldDefaultAddress.setIsDefault(NO_DEFAULT); this.updateById(oldDefaultAddress); } return this.save(tAddress); } /** * 获取商户默认地址 * * @param merchantId * @return TAddress */ @Override public TAddress getMerchantDefaultAddress(Long merchantId) { return this.getOne(new LambdaQueryWrapper() .eq(TAddress::getMerchantId, merchantId) .eq(TAddress::getUserType, MERCHANT_USER_TYPE) .eq(TAddress::getType, TYPE) .eq(TAddress::getIsDelete, NO_DELETE) .eq(TAddress::getIsDefault, IS_DEFAULT) .last("limit 1")); } private void fillMerchantAddressDefaults(TAddress tAddress, boolean setAsDefault) { tAddress.setUserType(MERCHANT_USER_TYPE); tAddress.setType(TYPE); tAddress.setIsDelete(NO_DELETE); tAddress.setIsDefault(setAsDefault ? IS_DEFAULT : NO_DEFAULT); if (StringUtils.isBlank(tAddress.getDetailAddress())) { String detailAddress = tAddress.getAddress(); if (StringUtils.isNotBlank(tAddress.getRoomNumber())) { detailAddress = detailAddress + " " + tAddress.getRoomNumber(); } tAddress.setDetailAddress(detailAddress); } if (StringUtils.isBlank(tAddress.getCityCode())) { CoordinateDTO dto = new CoordinateDTO(); dto.setLongitude(tAddress.getLongitude()); dto.setLatitude(tAddress.getLatitude()); CityInfoVo cityInfoVo = areaService.getCityInfoByCoordinates(dto); if (cityInfoVo != null && StringUtils.isNotBlank(cityInfoVo.getCityCode())) { tAddress.setCityCode(cityInfoVo.getCityCode()); } } } @Override @Transactional(rollbackFor = Exception.class) public Object insertVirtualAddress(TAddress tAddress) { if (StringUtils.isBlank(tAddress.getOpenid())) { throw new RuntimeException("openid不能为空"); } //检查用户类型是否为空 if (Objects.isNull(tAddress.getUserType())) { throw new RuntimeException("用户类型不能为空"); } //检查用户类型是否为1或2 if (tAddress.getUserType() != 1 && tAddress.getUserType() != 2) { throw new RuntimeException("用户类型只能为1或2"); } //检查用户类型是否正确 if (tAddress.getUserType() != 2) { throw new RuntimeException("用户类型错误,用户类型只能为2"); } //检查地址类型是否为空 if (Objects.isNull(tAddress.getType())) { throw new RuntimeException("地址类型不能为空"); } //检查地址类型是否为1或2 if (tAddress.getType() != 2) { throw new RuntimeException("地址类型错误,地址类型只能为2"); } if(StringUtils.isBlank(tAddress.getCityCode())){ CoordinateDTO dto = new CoordinateDTO(); dto.setLongitude(tAddress.getLongitude()); dto.setLatitude(tAddress.getLatitude()); CityInfoVo cityInfoVo = areaService.getCityInfoByCoordinates(dto); log.info("根据经纬度获取城市信息:{}", JSON.toJSONString(cityInfoVo)); tAddress.setCityCode(cityInfoVo.getCityCode()); } if (StringUtils.isBlank(tAddress.getDetailAddress())){ tAddress.setDetailAddress(tAddress.getAddress()); } return this.save(tAddress); } @Override public Object updateAddress(TAddress tAddress) { if (StringUtils.isBlank(tAddress.getOpenid())) { throw new RuntimeException("openid不能为空"); } if (StringUtils.isBlank(tAddress.getId())) { throw new RuntimeException("地址id不能为空"); } //查询默认地址 TAddress oldAddress = this.getByOpenId(tAddress.getOpenid()); tAddress.setType(1); if (oldAddress != null && !oldAddress.getId().equals(tAddress.getId())) { tAddress.setType(0); } return this.updateById(tAddress); } /** * 用户端新增地址 * @param dto */ @Override public void addUserAddress(UserAddressAddDto dto) { // 1. DTO -> 实体 转换 TAddress address = new TAddress(); BeanUtil.copyProperties(dto, address); // 2. 补充实体中缺失但需要入库的字段 address.setIsDelete(NO_DELETE); address.setUserType(USER_TYPE); address.setType(TYPE); address.setDetailAddress(address.getAddress() + " " + address.getRoomNumber()); // 3. 处理默认地址逻辑 // 如果当前新增的地址是默认地址,需要先将该用户下的其他地址设为非默认 if (IS_DEFAULT.equals(dto.getIsDefault())) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(TAddress::getUserId, dto.getUserId()) .eq(TAddress::getIsDefault, IS_DEFAULT); TAddress defaultExists = this.baseMapper.selectOne(wrapper); if (defaultExists != null) { defaultExists.setIsDefault(NO_DEFAULT); this.updateById(defaultExists); } } // 5. 执行入库 this.baseMapper.insert(address); } /** * 用户端更新地址 * @param dto */ @Override public void updateUserAddress(UserAddressUpdateDto dto) { // 1. 参数校验:地址ID不能为空 if (StrUtil.isBlank(dto.getId())) { throw new RuntimeException("地址ID不能为空"); } // 2. 查询原有地址记录 TAddress existingAddress = this.baseMapper.selectById(dto.getId()); if (existingAddress == null) { throw new RuntimeException("地址不存在"); } // 3. 权限校验:只能修改自己的地址 if (!existingAddress.getUserId().equals(dto.getUserId())) { throw new RuntimeException("无权修改该地址"); } // 4. 将DTO中非空字段拷贝到实体(忽略为null的字段) BeanUtil.copyProperties(dto, existingAddress, "id", "userId", "openid", "merchantId", "userType", "type", "createTime", "isDelete"); // 6. 拼接详细地址(address + 空格 + roomNumber) String detailAddress = ""; if (StrUtil.isNotBlank(existingAddress.getAddress()) && StrUtil.isNotBlank(existingAddress.getRoomNumber())) { detailAddress = existingAddress.getAddress() + " " + existingAddress.getRoomNumber(); } else if (StrUtil.isNotBlank(existingAddress.getAddress())) { detailAddress = existingAddress.getAddress(); } else if (StrUtil.isNotBlank(existingAddress.getRoomNumber())) { detailAddress = existingAddress.getRoomNumber(); } existingAddress.setDetailAddress(detailAddress); // 8. 执行更新(根据ID更新) int rows = this.baseMapper.updateById(existingAddress); if (rows != 1) { throw new RuntimeException("更新地址失败"); } } /** * 用户端删除地址 * @param dto */ @Override public void deleteUserAddress(UserAddressDeleteDto dto) { String addressId = dto.getId(); // 1. 查询地址是否存在且未被删除 TAddress address = this.baseMapper.selectOne( new LambdaQueryWrapper() .eq(TAddress::getId, addressId) .eq(TAddress::getIsDelete, 0) ); if (address == null) { throw new RuntimeException("地址不存在或已被删除"); } // 2. 权限校验:只能删除自己的地址 if (!address.getUserId().equals(dto.getUserId())) { throw new RuntimeException("无权删除该地址"); } // 3. 执行逻辑删除(MyBatis-Plus 会自动将 isDelete 设为 1,并更新 updateTime) int rows = this.baseMapper.deleteById(addressId); if (rows != 1) { throw new RuntimeException("删除地址失败"); } // 4. 【可选】如果删除的是默认地址,将用户的其他最新地址设为默认 if (IS_DEFAULT.equals(address.getIsDefault())) { // 查询该用户下未被删除的其他地址,按创建时间倒序取第一条 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(TAddress::getUserId, dto.getUserId()) .eq(TAddress::getIsDelete, 0) .orderByDesc(TAddress::getCreateTime) .last("limit 1"); TAddress newDefault = this.baseMapper.selectOne(wrapper); if (newDefault != null) { newDefault.setIsDefault(IS_DEFAULT); this.baseMapper.updateById(newDefault); } } } }