Files
shanxia2.0/docs/crm-migration/reference/java/quote/service/impl/CrmQuoteShareLogServiceImpl.java
T
2026-06-01 08:21:21 +08:00

151 lines
5.4 KiB
Java

package org.dromara.crm.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.crm.domain.CrmQuoteShareLog;
import org.dromara.crm.domain.vo.CrmQuoteShareLogVo;
import org.dromara.crm.mapper.CrmQuoteShareLogMapper;
import org.dromara.crm.service.ICrmQuoteShareLogService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 报价单分享访问日志Service实现
*
* @author 系统管理员
* @date 2025-10-05
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class CrmQuoteShareLogServiceImpl implements ICrmQuoteShareLogService {
private final CrmQuoteShareLogMapper baseMapper;
@Override
public Boolean recordVisit(Long quoteId, String shareCode, String ipAddress, String userAgent) {
CrmQuoteShareLog log = new CrmQuoteShareLog();
log.setQuoteId(quoteId);
log.setShareCode(shareCode);
log.setVisitTime(LocalDateTime.now());
log.setIpAddress(ipAddress);
log.setPageViews(1);
log.setStayDuration(0);
// 解析User-Agent
if (StrUtil.isNotBlank(userAgent)) {
try {
UserAgent ua = UserAgentUtil.parse(userAgent);
// 设置浏览器信息
String browser = ua.getBrowser().getName() + " " + ua.getVersion();
log.setBrowser(browser);
// 判断设备类型
if (ua.isMobile()) {
log.setDeviceType("Mobile");
} else {
log.setDeviceType("PC");
}
} catch (Exception e) {
CrmQuoteShareLogServiceImpl.log.warn("解析User-Agent失败: userAgent={}", userAgent, e);
log.setBrowser(userAgent.length() > 100 ? userAgent.substring(0, 100) : userAgent);
log.setDeviceType("Unknown");
}
} else {
log.setDeviceType("Unknown");
}
// TODO: 根据IP地址解析地理位置(可使用ip2region库)
// log.setLocation(getLocationByIp(ipAddress));
CrmQuoteShareLogServiceImpl.log.info("记录报价单访问日志: quoteId={}, shareCode={}, ip={}, device={}",
quoteId, shareCode, ipAddress, log.getDeviceType());
return baseMapper.insert(log) > 0;
}
@Override
public List<CrmQuoteShareLogVo> queryLogsByQuoteId(Long quoteId) {
LambdaQueryWrapper<CrmQuoteShareLog> lqw = Wrappers.lambdaQuery();
lqw.eq(CrmQuoteShareLog::getQuoteId, quoteId);
lqw.orderByDesc(CrmQuoteShareLog::getVisitTime);
List<CrmQuoteShareLog> list = baseMapper.selectList(lqw);
return MapstructUtils.convert(list, CrmQuoteShareLogVo.class);
}
@Override
public Map<String, Object> statisticsVisits(Long quoteId) {
LambdaQueryWrapper<CrmQuoteShareLog> lqw = Wrappers.lambdaQuery();
lqw.eq(CrmQuoteShareLog::getQuoteId, quoteId);
List<CrmQuoteShareLog> logs = baseMapper.selectList(lqw);
Map<String, Object> stats = new HashMap<>();
// 总访问次数
stats.put("totalVisits", logs.size());
// 独立IP数
long uniqueIps = logs.stream()
.filter(log -> StrUtil.isNotBlank(log.getIpAddress()))
.map(CrmQuoteShareLog::getIpAddress)
.distinct()
.count();
stats.put("uniqueIps", uniqueIps);
// 最近访问时间
LocalDateTime lastVisit = logs.stream()
.map(CrmQuoteShareLog::getVisitTime)
.max(LocalDateTime::compareTo)
.orElse(null);
stats.put("lastVisitTime", lastVisit);
// 首次访问时间
LocalDateTime firstVisit = logs.stream()
.map(CrmQuoteShareLog::getVisitTime)
.min(LocalDateTime::compareTo)
.orElse(null);
stats.put("firstVisitTime", firstVisit);
// 设备类型分布
Map<String, Long> deviceStats = logs.stream()
.collect(Collectors.groupingBy(
log -> StrUtil.isNotBlank(log.getDeviceType()) ? log.getDeviceType() : "Unknown",
Collectors.counting()));
stats.put("deviceStats", deviceStats);
// 总停留时长
int totalStayDuration = logs.stream()
.mapToInt(log -> log.getStayDuration() != null ? log.getStayDuration() : 0)
.sum();
stats.put("totalStayDuration", totalStayDuration);
// 平均停留时长
double avgStayDuration = logs.isEmpty() ? 0 : (double) totalStayDuration / logs.size();
stats.put("avgStayDuration", avgStayDuration);
log.info("统计报价单访问数据: quoteId={}, totalVisits={}, uniqueIps={}",
quoteId, stats.get("totalVisits"), stats.get("uniqueIps"));
return stats;
}
// TODO: 实现IP地址解析地理位置功能
// private String getLocationByIp(String ipAddress) {
// // 使用ip2region等库解析IP地址
// return null;
// }
}