|
|
|
@ -16,6 +16,8 @@ import cc.hiver.mall.ie.vo.IeUserProfileVO; |
|
|
|
import cn.hutool.core.util.IdUtil; |
|
|
|
import cn.hutool.json.JSONUtil; |
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.dao.DuplicateKeyException; |
|
|
|
@ -40,7 +42,7 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
private IeRoomMapper roomMapper; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private IeRecordMapper recordMapper; |
|
|
|
private IeBlockMapper blockMapper; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private IeRedisService redisService; |
|
|
|
@ -78,8 +80,13 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
return toProfileVO(ensureProfile(userId)); |
|
|
|
} |
|
|
|
IeUserProfile profile = findProfileByUserId(targetUserId); |
|
|
|
if (profile == null || profile.getProfileCompleted() == null || profile.getProfileCompleted() != 1) { |
|
|
|
throw new RuntimeException("对方资料暂时不可见"); |
|
|
|
if (profile == null) { |
|
|
|
IeUserProfileVO vo = new IeUserProfileVO(); |
|
|
|
vo.setUserId(targetUserId); |
|
|
|
vo.setExists(false); |
|
|
|
vo.setInterestTags(new ArrayList<>()); |
|
|
|
vo.setPersonaImages(new ArrayList<>()); |
|
|
|
return vo; |
|
|
|
} |
|
|
|
return toProfileVO(profile); |
|
|
|
} |
|
|
|
@ -101,6 +108,7 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
profile.setGender(normalizeGender(dto.getGender(), "unknown")); |
|
|
|
profile.setIntro(intro); |
|
|
|
profile.setInterestTags(tagsToJson(dto.getInterestTags())); |
|
|
|
profile.setPersonaImages(imagesToJson(dto.getPersonaImages())); |
|
|
|
profile.setCurrentMode(normalizeMode(dto.getCurrentMode(), "i")); |
|
|
|
profile.setRecentPreference(profile.getCurrentMode()); |
|
|
|
profile.setTargetModePreference(normalizeTargetMode(dto.getTargetModePreference())); |
|
|
|
@ -187,6 +195,9 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
if (redisService.isRecentlyMatched(userId, candidateUserId)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
if (hasBlockRelation(userId, candidateUserId)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
IeUserProfile candidateProfile = findProfileByUserId(candidateUserId); |
|
|
|
if (!matchCandidate(candidateProfile, targetMode, targetGender)) { |
|
|
|
continue; |
|
|
|
@ -225,9 +236,10 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
match.setUpdateTime(new Date()); |
|
|
|
matchAttemptMapper.insert(match); |
|
|
|
|
|
|
|
IeRoom room = createRoom(match, userId, targetUserId, mode, mood); |
|
|
|
createChatRecord(room, userId, targetUserId, targetProfile); |
|
|
|
createChatRecord(room, targetUserId, userId, profile); |
|
|
|
IeRoom room = findReusableRoom(userId, targetUserId); |
|
|
|
if (room == null) { |
|
|
|
room = createRoom(match, userId, targetUserId, mode, mood); |
|
|
|
} |
|
|
|
redisService.markRecentlyMatched(userId, targetUserId); |
|
|
|
redisService.markRecentlyMatched(targetUserId, userId); |
|
|
|
|
|
|
|
@ -244,6 +256,73 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public IPage<IeMatchVO> pageMatches(Long userId, Integer pageNumber, Integer pageSize) { |
|
|
|
Page<IeMatchAttempt> page = new Page<>(safePageNumber(pageNumber), safePageSize(pageSize)); |
|
|
|
IPage<IeMatchAttempt> result = matchAttemptMapper.selectPage(page, new LambdaQueryWrapper<IeMatchAttempt>() |
|
|
|
.eq(IeMatchAttempt::getUserId, userId) |
|
|
|
.orderByDesc(IeMatchAttempt::getCreateTime)); |
|
|
|
Page<IeMatchVO> voPage = new Page<>(result.getCurrent(), result.getSize(), result.getTotal()); |
|
|
|
List<IeMatchVO> records = new ArrayList<>(); |
|
|
|
for (IeMatchAttempt match : result.getRecords()) { |
|
|
|
IeMatchVO vo = toMatchVO(match); |
|
|
|
fillMatchRoom(vo, userId); |
|
|
|
fillLatestTargetProfile(vo); |
|
|
|
records.add(vo); |
|
|
|
} |
|
|
|
voPage.setRecords(records); |
|
|
|
return voPage; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional |
|
|
|
public void rewardMatchQuota(Long userId, Integer amount) { |
|
|
|
if (userId == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
int reward = amount == null ? 1 : Math.max(1, amount); |
|
|
|
IeUserProfile profile = ensureProfile(userId); |
|
|
|
int dailyQuota = profile.getDailyQuota() == null ? IeConstants.DEFAULT_DAILY_QUOTA : profile.getDailyQuota(); |
|
|
|
profile.setDailyQuota(dailyQuota + reward); |
|
|
|
profile.setUpdateTime(new Date()); |
|
|
|
userProfileMapper.updateById(profile); |
|
|
|
} |
|
|
|
|
|
|
|
private int safePageNumber(Integer pageNumber) { |
|
|
|
return pageNumber == null || pageNumber < 1 ? 1 : pageNumber; |
|
|
|
} |
|
|
|
|
|
|
|
private int safePageSize(Integer pageSize) { |
|
|
|
return pageSize == null ? 10 : Math.max(1, Math.min(pageSize, 50)); |
|
|
|
} |
|
|
|
|
|
|
|
private void fillMatchRoom(IeMatchVO vo, Long userId) { |
|
|
|
if (vo == null || vo.getTargetUserId() == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
IeRoom room = findReusableRoom(userId, vo.getTargetUserId()); |
|
|
|
if (room == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
vo.setRoomId(room.getId()); |
|
|
|
vo.setRoomNo(room.getRoomNo()); |
|
|
|
} |
|
|
|
|
|
|
|
private void fillLatestTargetProfile(IeMatchVO vo) { |
|
|
|
if (vo == null || vo.getTargetUserId() == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
IeUserProfile profile = findProfileByUserId(vo.getTargetUserId()); |
|
|
|
if (profile == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
vo.setAnonymousName(defaultText(profile.getAnonymousName(), vo.getAnonymousName())); |
|
|
|
vo.setAvatarText(defaultText(profile.getAvatarText(), vo.getAvatarText())); |
|
|
|
vo.setAvatarUrl(profile.getAvatarUrl()); |
|
|
|
vo.setMode(defaultText(profile.getCurrentMode(), vo.getMode())); |
|
|
|
vo.setQuoteText(defaultText(profile.getIntro(), vo.getQuoteText())); |
|
|
|
} |
|
|
|
|
|
|
|
private IeRoom createRoom(IeMatchAttempt match, Long userId, Long targetUserId, String mode, String mood) { |
|
|
|
Date now = new Date(); |
|
|
|
IeRoom room = new IeRoom(); |
|
|
|
@ -263,6 +342,23 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
return room; |
|
|
|
} |
|
|
|
|
|
|
|
private IeRoom findReusableRoom(Long userId, Long targetUserId) { |
|
|
|
IeRoom room = roomMapper.selectOne(new LambdaQueryWrapper<IeRoom>() |
|
|
|
.eq(IeRoom::getStatus, IeConstants.ROOM_STATUS_ACTIVE) |
|
|
|
.and(wrapper -> wrapper |
|
|
|
.eq(IeRoom::getUserAId, userId) |
|
|
|
.eq(IeRoom::getUserBId, targetUserId) |
|
|
|
.or() |
|
|
|
.eq(IeRoom::getUserAId, targetUserId) |
|
|
|
.eq(IeRoom::getUserBId, userId)) |
|
|
|
.orderByDesc(IeRoom::getUpdateTime) |
|
|
|
.last("limit 1")); |
|
|
|
if (room != null) { |
|
|
|
redisService.cacheRoom(room.getId(), JSONUtil.toJsonStr(room), 20 * 60L); |
|
|
|
} |
|
|
|
return room; |
|
|
|
} |
|
|
|
|
|
|
|
private Date longTermExpireTime(Date startTime) { |
|
|
|
Calendar calendar = Calendar.getInstance(); |
|
|
|
calendar.setTime(startTime == null ? new Date() : startTime); |
|
|
|
@ -270,29 +366,6 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
return calendar.getTime(); |
|
|
|
} |
|
|
|
|
|
|
|
private void createChatRecord(IeRoom room, Long userId, Long targetUserId, IeUserProfile targetProfile) { |
|
|
|
IeRecord exists = recordMapper.selectOne(new LambdaQueryWrapper<IeRecord>() |
|
|
|
.eq(IeRecord::getRoomId, room.getId()) |
|
|
|
.eq(IeRecord::getUserId, userId) |
|
|
|
.last("limit 1")); |
|
|
|
if (exists != null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
IeRecord record = new IeRecord(); |
|
|
|
record.setRoomId(room.getId()); |
|
|
|
record.setUserId(userId); |
|
|
|
record.setTargetUserId(targetUserId); |
|
|
|
record.setMode(room.getMode()); |
|
|
|
record.setMood(room.getMood()); |
|
|
|
record.setAnonymousName(defaultText(targetProfile == null ? null : targetProfile.getAnonymousName(), "半匿名漂流者")); |
|
|
|
record.setDurationSeconds(0); |
|
|
|
record.setSummary("你们已经匹配成功,可以从这里回到聊天继续对话。"); |
|
|
|
record.setTags(room.getMode() + "," + room.getMood() + ",继续聊天"); |
|
|
|
record.setRemeetAvailable(1); |
|
|
|
record.setCreateTime(new Date()); |
|
|
|
recordMapper.insert(record); |
|
|
|
} |
|
|
|
|
|
|
|
private IeMatchVO fail(Long userId, IeMatchStartDTO dto, String reason) { |
|
|
|
IeMatchAttempt match = new IeMatchAttempt(); |
|
|
|
match.setMatchNo(IdUtil.fastSimpleUUID()); |
|
|
|
@ -322,6 +395,7 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
vo.setQuoteText(match.getQuoteText()); |
|
|
|
vo.setStatus(match.getStatus()); |
|
|
|
vo.setFailReason(match.getFailReason()); |
|
|
|
vo.setCreateTime(match.getCreateTime()); |
|
|
|
return vo; |
|
|
|
} |
|
|
|
|
|
|
|
@ -384,6 +458,17 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
return new ArrayList<>(set); |
|
|
|
} |
|
|
|
|
|
|
|
private boolean hasBlockRelation(Long userId, Long candidateUserId) { |
|
|
|
Long count = blockMapper.selectCount(new LambdaQueryWrapper<IeBlock>() |
|
|
|
.and(wrapper -> wrapper |
|
|
|
.eq(IeBlock::getUserId, userId) |
|
|
|
.eq(IeBlock::getBlockedUserId, candidateUserId)) |
|
|
|
.or(wrapper -> wrapper |
|
|
|
.eq(IeBlock::getUserId, candidateUserId) |
|
|
|
.eq(IeBlock::getBlockedUserId, userId))); |
|
|
|
return count != null && count > 0; |
|
|
|
} |
|
|
|
|
|
|
|
private List<Long> statusCandidates(String mode, int limit) { |
|
|
|
List<IeUserStatus> statuses = userStatusMapper.selectList(new LambdaQueryWrapper<IeUserStatus>() |
|
|
|
.eq(IeUserStatus::getOnlineStatus, 1) |
|
|
|
@ -446,6 +531,7 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
vo.setGender(profile.getGender()); |
|
|
|
vo.setIntro(profile.getIntro()); |
|
|
|
vo.setInterestTags(jsonToTags(profile.getInterestTags())); |
|
|
|
vo.setPersonaImages(jsonToTags(profile.getPersonaImages())); |
|
|
|
vo.setCurrentMode(profile.getCurrentMode()); |
|
|
|
vo.setRecentPreference(profile.getRecentPreference()); |
|
|
|
vo.setTargetModePreference(profile.getTargetModePreference()); |
|
|
|
@ -454,6 +540,7 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
vo.setDailyQuota(profile.getDailyQuota()); |
|
|
|
vo.setUsedQuota(profile.getUsedQuota()); |
|
|
|
vo.setProfileCompleted(profile.getProfileCompleted() == null ? 0 : profile.getProfileCompleted()); |
|
|
|
vo.setExists(true); |
|
|
|
return vo; |
|
|
|
} |
|
|
|
|
|
|
|
@ -552,6 +639,22 @@ public class IeMatchServiceImpl implements IeMatchService { |
|
|
|
return JSONUtil.toJsonStr(tags); |
|
|
|
} |
|
|
|
|
|
|
|
private String imagesToJson(List<String> images) { |
|
|
|
if (images == null || images.isEmpty()) { |
|
|
|
return "[]"; |
|
|
|
} |
|
|
|
List<String> safeImages = new ArrayList<>(); |
|
|
|
for (String image : images) { |
|
|
|
if (image != null && !image.trim().isEmpty()) { |
|
|
|
safeImages.add(image.trim()); |
|
|
|
} |
|
|
|
if (safeImages.size() >= 5) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return JSONUtil.toJsonStr(safeImages); |
|
|
|
} |
|
|
|
|
|
|
|
private List<String> jsonToTags(String tags) { |
|
|
|
if (tags == null || tags.trim().isEmpty()) { |
|
|
|
return new ArrayList<>(); |
|
|
|
|