| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048 |
- package com.ylx.massage.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ylx.common.exception.ServiceException;
- import com.ylx.massage.domain.MaTechnician;
- import com.ylx.massage.domain.MomentMedia;
- import com.ylx.massage.domain.TJs;
- import com.ylx.massage.domain.TechnicianMoment;
- import com.ylx.massage.domain.dto.EditMomentDTO;
- import com.ylx.massage.domain.dto.MomentAuditDTO;
- import com.ylx.massage.domain.dto.MomentManageQueryDTO;
- import com.ylx.massage.domain.dto.PublishMomentDTO;
- import com.ylx.massage.domain.vo.*;
- import com.ylx.massage.mapper.MaTechnicianMapper;
- import com.ylx.massage.mapper.MomentMediaMapper;
- import com.ylx.massage.mapper.TJsMapper;
- import com.ylx.massage.mapper.TechnicianMomentMapper;
- import com.ylx.massage.service.ITechnicianMomentService;
- import com.ylx.merchant.domain.dto.MerchantMomentDTO;
- import com.ylx.merchant.domain.vo.MomentVO;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.math.BigDecimal;
- import java.time.LocalDateTime;
- import java.util.*;
- import java.util.stream.Collectors;
- /**
- * 技师动态服务实现类
- */
- @Service
- @Slf4j
- public class TechnicianMomentServiceImpl extends ServiceImpl<TechnicianMomentMapper, TechnicianMoment> implements ITechnicianMomentService {
- private static final int AUDIT_STATUS_PENDING = 1;
- private static final int NOT_DELETED = 0;
- private static final int DELETED = 1;
- @Autowired
- private TechnicianMomentMapper momentMapper;
- @Autowired
- private MomentMediaMapper mediaMapper;
- @Autowired
- private TJsMapper tJsMapper;
- @Autowired
- private MaTechnicianMapper maTechnicianMapper;
- /**
- * 查询推荐动态列表(不分地区,按日期倒序,同一天按浏览量倒序)
- *
- * @param pageNum 页码,默认1
- * @param pageSize 每页数量,默认10
- * @return R<List < MomentListVO>> 动态列表
- */
- @Override
- public List<MomentListVO> getRecommendedMoments(Integer pageNum, Integer pageSize) {
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- List<TechnicianMoment> moments = momentMapper.selectRecommendedMoments(page);
- if (moments == null || moments.isEmpty()) {
- return new ArrayList<>();
- }
- // 查询技师信息
- List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
- Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);
- // 组装VO
- return moments.stream().map(moment -> {
- MomentListVO vo = new MomentListVO();
- BeanUtils.copyProperties(moment, vo);
- MaTechnician technician = technicianMap.get(moment.getTechnicianId());
- if (technician != null) {
- vo.setTechnicianNickName(technician.getTeNickName());
- vo.setTechnicianAvatar(technician.getTeAvatar());
- vo.setTechnicianStatus(getTechnicianStatus(technician));
- }
- return vo;
- }).collect(Collectors.toList());
- }
- /**
- * 查询同城动态列表(按城市和发布时间倒序)
- */
- @Override
- public List<MomentListVO> getSameCityMoments(String cityCode, Integer pageNum, Integer pageSize) {
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- List<TechnicianMoment> moments = momentMapper.selectSameCityMoments(page, cityCode);
- if (moments == null || moments.isEmpty()) {
- return new ArrayList<>();
- }
- // 查询技师信息
- List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
- Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);
- // 组装VO
- return moments.stream().map(moment -> {
- MomentListVO vo = new MomentListVO();
- BeanUtils.copyProperties(moment, vo);
- MaTechnician technician = technicianMap.get(moment.getTechnicianId());
- if (technician != null) {
- vo.setTechnicianNickName(technician.getTeNickName());
- vo.setTechnicianAvatar(technician.getTeAvatar());
- vo.setTechnicianStatus(getTechnicianStatus(technician));
- }
- return vo;
- }).collect(Collectors.toList());
- }
- /**
- * 查询附近动态列表(10km内,按日期倒序,同一天按距离排序)
- *
- * @param longitude 经度
- * @param latitude 纬度
- * @param pageNum 页码,默认1
- * @param pageSize 每页数量,默认10
- * @return R<List < MomentListVO>> 动态列表
- */
- @Override
- public List<MomentListVO> getNearbyMoments(BigDecimal longitude, BigDecimal latitude, Integer pageNum, Integer pageSize) {
- if (latitude == null || longitude == null) {
- throw new ServiceException("地理位置信息不能为空");
- }
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- List<TechnicianMoment> moments = momentMapper.selectNearbyMoments(page, longitude, latitude);
- if (moments == null || moments.isEmpty()) {
- return new ArrayList<>();
- }
- // 查询技师信息
- List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
- Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);
- // 组装VO(需要计算距离)
- return moments.stream().map(moment -> {
- MomentListVO vo = new MomentListVO();
- BeanUtils.copyProperties(moment, vo);
- MaTechnician technician = technicianMap.get(moment.getTechnicianId());
- if (technician != null) {
- vo.setTechnicianNickName(technician.getTeNickName());
- vo.setTechnicianAvatar(technician.getTeAvatar());
- vo.setTechnicianStatus(getTechnicianStatus(technician));
- // 计算距离
- if (moment.getLatitude() != null && moment.getLongitude() != null) {
- double distance = calculateDistance(
- latitude.doubleValue(), longitude.doubleValue(),
- moment.getLatitude().doubleValue(), moment.getLongitude().doubleValue()
- );
- vo.setDistance(Math.round(distance * 100.0) / 100.0); // 保留两位小数
- }
- }
- return vo;
- }).collect(Collectors.toList());
- }
- /**
- * 查询动态详情(浏览量+1)
- *
- * @param momentId 动态ID
- * @param longitude 用户经度
- * @param latitude 用户纬度
- * @return MomentDetailVO 动态详情
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public MomentDetailVO getMomentDetail(Long momentId, BigDecimal longitude, BigDecimal latitude) {
- // 查询动态信息
- TechnicianMoment moment = momentMapper.selectById(momentId);
- if (moment == null) {
- throw new ServiceException("动态不存在");
- }
- // 增加浏览量
- momentMapper.incrementViewCount(momentId);
- moment.setViewCount(moment.getViewCount() + 1);
- // 查询商户信息
- MaTechnician technician = maTechnicianMapper.selectById(moment.getTechnicianId());
- // 查询媒体列表
- List<MomentMedia> mediaList = mediaMapper.selectMediaListByMomentId(momentId);
- List<MomentMediaVO> mediaVOList = mediaList.stream().map(media -> {
- MomentMediaVO mediaVO = new MomentMediaVO();
- BeanUtils.copyProperties(media, mediaVO);
- return mediaVO;
- }).collect(Collectors.toList());
- // 组装VO
- MomentDetailVO vo = new MomentDetailVO();
- BeanUtils.copyProperties(moment, vo);
- if (technician != null) {
- vo.setTechnicianNickName(technician.getTeNickName());
- vo.setTechnicianAvatar(technician.getTeAvatar());
- vo.setTechnicianStatus(getTechnicianStatus(technician));
- }
- vo.setMediaList(mediaVOList);
- // 计算距离(如果有位置信息)
- if (moment.getLatitude() != null && moment.getLongitude() != null) {
- if(latitude != null && longitude != null){
- // 传入用户位置,计算用户与技师之间的距离
- double distance = calculateDistance(
- latitude.doubleValue(), longitude.doubleValue(),
- moment.getLatitude().doubleValue(), moment.getLongitude().doubleValue()
- );
- vo.setDistance(Math.round(distance * 100.0) / 100.0); // 保留两位小数
- }
- }
- return vo;
- }
- /**
- * 批量查询技师信息
- *
- * @param technicianIds 技师ID列表
- * @return Map<String, TJs> 技师ID-技师实体映射
- */
- private Map<Integer, MaTechnician> getTechnicianMap(List<Integer> technicianIds) {
- return maTechnicianMapper.selectBatchIds(technicianIds).stream().collect(Collectors.toMap(MaTechnician::getId, t -> t));
- }
- /**
- * 获取技师状态
- * 1-可服务(当前时间技师空闲)
- * 2-可预约(当前时间技师"已接单-服务中")
- */
- private Integer getTechnicianStatus(MaTechnician technician) {
- if (technician.getServiceState() != null && technician.getServiceState() == 1) {
- return 1; // 可服务
- } else if (technician.getServiceState() != null && technician.getServiceState() == 0) {
- return 2; // 可预约(服务中)
- }
- return null;
- }
- /**
- * 计算两点之间的距离(单位:km)
- *
- * @param lat1 纬度1(用户纬度)
- * @param lon1 经度1(用户经度)
- * @param lat2 纬度2(技师纬度)
- * @param lon2 经度2(技师经度)
- * @return double 距离(单位:km)
- * <p>
- * 使用Haversine公式
- */
- private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
- final double R = 6371; // 地球半径,单位km
- double dLat = Math.toRadians(lat2 - lat1);
- double dLon = Math.toRadians(lon2 - lon1);
- double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
- Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
- Math.sin(dLon / 2) * Math.sin(dLon / 2);
- double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- return R * c;
- }
- /**
- * 发布动态或保存草稿
- *
- * @param dto 发布动态请求对象
- * @param openId 技师OpenID
- * @return Long 动态ID
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Long publishMoment(PublishMomentDTO dto, String openId) {
- // 根据openId查询技师信息
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getCOpenid, openId);
- MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
- if (technician == null) {
- throw new ServiceException("商户信息不存在");
- }
- //查询是否保存为草稿
- Integer isDraft = dto.getIsDraft();
- if (isDraft == 1) {
- //只校验标题
- if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
- throw new ServiceException("动态标题不能为空");
- }
- } else {
- // 校验动态标题
- if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
- throw new ServiceException("动态标题不能为空");
- }
- // 校验动态内容
- if (StringUtils.isBlank(dto.getContent())) {
- throw new ServiceException("动态内容不能为空");
- }
- // 校验媒体类型和媒体文件
- if (dto.getMediaType() == null) {
- throw new ServiceException("媒体类型不能为空");
- }
- if (dto.getMediaType() == 1) {
- // 图片类型
- if (dto.getImageUrls() == null || dto.getImageUrls().isEmpty()) {
- throw new ServiceException("图片不能为空");
- }
- if (dto.getImageUrls().size() > 9) {
- throw new ServiceException("最多只能上传9张图片");
- }
- } else if (dto.getMediaType() == 2) {
- // 视频类型
- if (StringUtils.isBlank(dto.getVideoUrl())) {
- throw new ServiceException("视频不能为空");
- }
- } else {
- throw new ServiceException("媒体类型不正确");
- }
- }
- // 创建动态对象
- TechnicianMoment moment = new TechnicianMoment();
- moment.setTechnicianId(technician.getId());
- moment.setTitle(dto.getTitle());
- moment.setContent(dto.getContent());
- moment.setMediaType(dto.getMediaType());
- moment.setLatitude(dto.getLatitude());
- moment.setLongitude(dto.getLongitude());
- moment.setLocation(dto.getLocation());
- moment.setAddress(dto.getAddress());
- if(Objects.nonNull(dto.getMediaType())){
- // 设置封面图
- if (dto.getMediaType() == 1) {
- // 图片类型,默认取第一张作为封面
- if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
- moment.setCoverUrl(dto.getImageUrls().get(0));
- }
- } else if (dto.getMediaType() == 2) {
- // 视频类型,使用视频URL作为封面
- moment.setCoverUrl(dto.getVideoCoverUrl());
- }
- }
- // 设置审核状态和发布时间
- if (dto.getIsDraft() != null && dto.getIsDraft() == 1) {
- // 保存草稿
- moment.setAuditStatus(0);
- moment.setPublishTime(null);
- } else {
- // 立即发布,进入待审核状态
- moment.setAuditStatus(1);
- moment.setPublishTime(LocalDateTime.now());
- }
- // 设置初始状态
- moment.setIsDelete(0);
- moment.setViewCount(0);
- moment.setCreateTime(LocalDateTime.now());
- moment.setUpdateTime(LocalDateTime.now());
- // 8. 保存动态到数据库
- int insertResult = momentMapper.insert(moment);
- if (insertResult <= 0) {
- throw new ServiceException("发布动态失败");
- }
- Long momentId = moment.getId();
- // 9. 保存媒体信息到媒体表
- if(Objects.nonNull(dto.getMediaType())){
- if (dto.getMediaType() == 1) {
- // 保存图片
- if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
- for (int i = 0; i < dto.getImageUrls().size(); i++) {
- MomentMedia media = new MomentMedia();
- media.setMomentId(momentId);
- media.setMediaUrl(dto.getImageUrls().get(i));
- media.setMediaType(1); // 图片
- media.setSortOrder(i + 1);
- media.setCreateTime(LocalDateTime.now());
- //获取文件的格式
- String fileFormat = dto.getImageUrls().get(i).substring(dto.getImageUrls().get(i).lastIndexOf(".") + 1);
- media.setFileFormat(fileFormat);
- mediaMapper.insert(media);
- }
- }
- } else if (dto.getMediaType() == 2) {
- // 保存视频
- MomentMedia media = new MomentMedia();
- media.setMomentId(momentId);
- media.setMediaUrl(dto.getVideoUrl());
- media.setMediaType(2); // 视频
- media.setSortOrder(1);
- media.setCreateTime(LocalDateTime.now());
- mediaMapper.insert(media);
- }
- }
- log.info("发布动态成功,动态ID:{},技师ID:{},是否草稿:{}", momentId, technician.getId(), dto.getIsDraft());
- return momentId;
- }
- /**
- * 编辑动态
- *
- * @param dto 编辑动态请求对象
- * @param openId 技师OpenID
- * @return Long 动态ID
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Long editMoment(EditMomentDTO dto, String openId) {
- // 1. 参数校验
- if (dto == null) {
- throw new ServiceException("编辑动态信息不能为空");
- }
- if (openId == null || openId.trim().isEmpty()) {
- throw new ServiceException("openId不能为空");
- }
- if (dto.getMomentId() == null) {
- throw new ServiceException("动态ID不能为空");
- }
- // 2. 根据openId查询商户信息
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getCOpenid, openId);
- MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
- if (technician == null) {
- throw new ServiceException("商户信息不存在");
- }
- // 3. 查询动态信息
- TechnicianMoment moment = momentMapper.selectById(dto.getMomentId());
- if (moment == null) {
- throw new ServiceException("动态不存在");
- }
- // 4. 验证动态是否属于当前商户
- if (!moment.getTechnicianId().equals(technician.getId())) {
- throw new ServiceException("无权编辑此动态");
- }
- // 5. 验证动态状态是否允许编辑(只能编辑草稿和审核拒绝的动态)
- if (moment.getAuditStatus() == null || (moment.getAuditStatus() != 0 && moment.getAuditStatus() != 3)) {
- throw new ServiceException("只能编辑草稿或审核拒绝的动态");
- }
- // 6. 校验媒体类型和媒体文件
- if (dto.getMediaType() == null) {
- throw new ServiceException("媒体类型不能为空");
- }
- if (dto.getMediaType() == 1) {
- // 图片类型
- if (dto.getImageUrls() == null || dto.getImageUrls().isEmpty()) {
- throw new ServiceException("图片不能为空");
- }
- if (dto.getImageUrls().size() > 9) {
- throw new ServiceException("最多只能上传9张图片");
- }
- } else if (dto.getMediaType() == 2) {
- // 视频类型
- if (dto.getVideoUrl() == null || dto.getVideoUrl().trim().isEmpty()) {
- throw new ServiceException("视频不能为空");
- }
- } else {
- throw new ServiceException("媒体类型不正确");
- }
- // 7. 更新动态对象
- moment.setTitle(dto.getTitle());
- moment.setContent(dto.getContent());
- moment.setMediaType(dto.getMediaType());
- moment.setLongitude(dto.getLongitude());
- moment.setLatitude(dto.getLatitude());
- moment.setLocation(dto.getLocation());
- moment.setAddress(dto.getAddress());
- // 8.设置封面图
- if (dto.getMediaType() == 1) {
- // 图片类型,默认取第一张作为封面
- if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
- moment.setCoverUrl(dto.getImageUrls().get(0));
- }
- } else if (dto.getMediaType() == 2) {
- // 视频类型,使用视频封面URL(如果提供了)或视频URL作为封面
- if (dto.getVideoCoverUrl() != null && !dto.getVideoCoverUrl().trim().isEmpty()) {
- moment.setCoverUrl(dto.getVideoCoverUrl());
- } else {
- moment.setCoverUrl(dto.getVideoUrl());
- }
- }
- // 9. 设置审核状态和发布时间
- if (dto.getIsDraft() != null && dto.getIsDraft() == 1) {
- // 保存草稿
- moment.setAuditStatus(0); // 草稿
- moment.setPublishTime(null);
- moment.setRejectReason(null); // 清空拒绝原因
- } else {
- // 提交发布,进入待审核状态
- moment.setAuditStatus(1);
- if (moment.getPublishTime() == null) {
- moment.setPublishTime(LocalDateTime.now());
- }
- moment.setRejectReason(null); // 清空拒绝原因
- }
- moment.setUpdateTime(LocalDateTime.now());
- // 10. 更新动态到数据库
- int updateResult = momentMapper.updateById(moment);
- if (updateResult <= 0) {
- throw new ServiceException("编辑动态失败");
- }
- Long momentId = moment.getId();
- // 11. 删除旧的媒体信息
- LambdaQueryWrapper<MomentMedia> mediaWrapper = new LambdaQueryWrapper<>();
- mediaWrapper.eq(MomentMedia::getMomentId, momentId);
- mediaMapper.delete(mediaWrapper);
- // 12. 保存新的媒体信息到媒体表
- if (dto.getMediaType() == 1) {
- // 保存图片
- if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
- for (int i = 0; i < dto.getImageUrls().size(); i++) {
- MomentMedia media = new MomentMedia();
- media.setMomentId(momentId);
- media.setMediaUrl(dto.getImageUrls().get(i));
- media.setMediaType(1); // 图片
- media.setSortOrder(i + 1);
- media.setCreateTime(LocalDateTime.now());
- // 获取文件的格式
- String fileFormat = dto.getImageUrls().get(i).substring(dto.getImageUrls().get(i).lastIndexOf(".") + 1);
- media.setFileFormat(fileFormat);
- mediaMapper.insert(media);
- }
- }
- } else if (dto.getMediaType() == 2) {
- // 保存视频
- MomentMedia media = new MomentMedia();
- media.setMomentId(momentId);
- media.setMediaUrl(dto.getVideoUrl());
- media.setMediaType(2); // 视频
- media.setSortOrder(1);
- media.setCreateTime(LocalDateTime.now());
- mediaMapper.insert(media);
- }
- log.info("编辑动态成功,动态ID:{},技师ID:{},是否草稿:{}", momentId, technician.getId(), dto.getIsDraft());
- return momentId;
- }
- /**
- * 查询草稿箱列表
- *
- * @param openId 技师OpenID
- * @param pageNum 页码
- * @param pageSize 每页数量
- * @return List<MomentListVO> 草稿列表
- */
- @Override
- public Page<MomentListVO> getDraftMoments(String openId, Integer pageNum, Integer pageSize) {
- if (openId == null || openId.trim().isEmpty()) {
- throw new ServiceException("openId不能为空");
- }
- // 1. 根据openId查询技师信息
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getCOpenid, openId);
- MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
- if (technician == null) {
- throw new ServiceException("商户信息不存在");
- }
- // 2. 查询该商户的草稿列表
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
- momentWrapper.eq(TechnicianMoment::getTechnicianId, technician.getId())
- .eq(TechnicianMoment::getAuditStatus, 0) // 草稿状态
- .orderByDesc(TechnicianMoment::getCreateTime);
- Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, momentWrapper);
- List<TechnicianMoment> moments = momentPage.getRecords();
- Page<MomentListVO> voPage = new Page<>(pageNum, pageSize);
- if (moments == null || moments.isEmpty()) {
- // 草稿列表为空时,返回空Page对象
- return voPage;
- }
- // 3. 组装VO
- List<MomentListVO> collect = moments.stream().map(moment -> {
- MomentListVO vo = new MomentListVO();
- BeanUtils.copyProperties(moment, vo);
- vo.setTechnicianId(technician.getId());
- vo.setTechnicianNickName(technician.getTeNickName());
- vo.setTechnicianAvatar(technician.getTeAvatar());
- vo.setTechnicianStatus(getTechnicianStatus(technician));
- // 草稿的发布时间使用创建时间
- vo.setPublishTime(moment.getCreateTime());
- return vo;
- }).collect(Collectors.toList());
- //返回Page对象
- voPage.setTotal(momentPage.getTotal());
- voPage.setRecords(collect);
- return voPage;
- }
- /**
- * 查询我的动态列表(已发布的动态:审核中+审核通过+审核拒绝)
- *
- * @param openId 技师OpenID
- * @param pageNum 页码
- * @param pageSize 每页数量
- * @return Page<MyMomentVO> 我的动态列表
- */
- @Override
- public Page<MyMomentVO> getMyMoments(String openId, Integer pageNum, Integer pageSize) {
- // 1. 参数校验
- if (openId == null || openId.trim().isEmpty()) {
- throw new ServiceException("openId不能为空");
- }
- // 2. 根据openId查询技师信息
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getCOpenid, openId);
- MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
- if (technician == null) {
- throw new ServiceException("商户信息不存在");
- }
- // 3. 查询该商户的已发布动态(待审核、审核通过、审核拒绝)
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
- momentWrapper.eq(TechnicianMoment::getTechnicianId, technician.getId())
- .in(TechnicianMoment::getAuditStatus, 0,1, 2,3) // 1-待审核, 2-审核通过,3-审核拒绝
- .orderByDesc(TechnicianMoment::getPublishTime);
- Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, momentWrapper);
- // 4. 组装分页返回结果
- Page<MyMomentVO> voPage = new Page<>(pageNum, pageSize);
- voPage.setTotal(momentPage.getTotal());
- voPage.setCurrent(momentPage.getCurrent());
- voPage.setSize(momentPage.getSize());
- List<TechnicianMoment> moments = momentPage.getRecords();
- if (moments == null || moments.isEmpty()) {
- voPage.setRecords(new ArrayList<>());
- return voPage;
- }
- // 5. 组装VO列表
- List<MyMomentVO> voList = moments.stream().map(moment -> {
- MyMomentVO vo = new MyMomentVO();
- vo.setId(moment.getId());
- vo.setTitle(moment.getTitle());
- vo.setContent(moment.getContent());
- vo.setAuditStatus(moment.getAuditStatus());
- vo.setCoverUrl(moment.getCoverUrl());
- vo.setPublishTime(moment.getPublishTime());
- vo.setViewCount(moment.getViewCount());
- return vo;
- }).collect(Collectors.toList());
- voPage.setRecords(voList);
- return voPage;
- }
- /**
- * 删除我的动态。
- *
- * <p>审核中的动态不允许删除;其它属于当前商户且未删除的动态仅做逻辑删除。</p>
- *
- * @param momentId 动态ID
- * @param openId 当前登录商户OpenID
- * @return Boolean 是否删除成功
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Boolean deleteMyMoment(Long momentId, String openId) {
- if (momentId == null) {
- throw new ServiceException("动态ID不能为空");
- }
- if (StringUtils.isBlank(openId)) {
- throw new ServiceException("openId不能为空");
- }
- LambdaQueryWrapper<MaTechnician> technicianWrapper = new LambdaQueryWrapper<>();
- technicianWrapper.eq(MaTechnician::getCOpenid, openId);
- MaTechnician technician = maTechnicianMapper.selectOne(technicianWrapper);
- if (technician == null) {
- throw new ServiceException("商户信息不存在");
- }
- TechnicianMoment moment = momentMapper.selectById(momentId);
- if (moment == null || Objects.equals(moment.getIsDelete(), DELETED)) {
- throw new ServiceException("动态不存在或已删除");
- }
- if (!Objects.equals(moment.getTechnicianId(), technician.getId())) {
- throw new ServiceException("无权删除此动态");
- }
- if (Objects.equals(moment.getAuditStatus(), AUDIT_STATUS_PENDING)) {
- throw new ServiceException("审核中的动态不支持删除");
- }
- TechnicianMoment update = new TechnicianMoment();
- update.setIsDelete(DELETED);
- update.setUpdateBy(openId);
- update.setUpdateTime(LocalDateTime.now());
- LambdaUpdateWrapper<TechnicianMoment> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(TechnicianMoment::getId, momentId)
- .eq(TechnicianMoment::getTechnicianId, technician.getId())
- .eq(TechnicianMoment::getIsDelete, NOT_DELETED);
- int rows = momentMapper.update(update, updateWrapper);
- if (rows <= 0) {
- throw new ServiceException("删除动态失败");
- }
- LambdaQueryWrapper<MomentMedia> mediaQueryWrapper = new LambdaQueryWrapper<>();
- mediaQueryWrapper.eq(MomentMedia::getMomentId, momentId);
- mediaMapper.delete(mediaQueryWrapper);
- log.info("删除动态成功,动态ID:{},商户ID:{}", momentId, technician.getId());
- return true;
- }
- /**
- * 根据技师ID查询动态列表(已发布的动态:审核中+审核通过)
- *
- * @param technicianId 技师ID
- * @return List<MomentListVO> 动态列表
- */
- @Override
- public List<MomentListVO> getMomentsByTechnicianId(String technicianId) {
- // 1. 参数校验
- if (technicianId == null || technicianId.trim().isEmpty()) {
- throw new ServiceException("技师ID不能为空");
- }
- // 2. 查询该技师的已发布动态(待审核、审核通过)
- LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
- momentWrapper.eq(TechnicianMoment::getTechnicianId, technicianId)
- .in(TechnicianMoment::getAuditStatus, 1, 2) // 1-待审核, 2-审核通过
- .orderByDesc(TechnicianMoment::getPublishTime);
- List<TechnicianMoment> moments = momentMapper.selectList(momentWrapper);
- if (moments == null || moments.isEmpty()) {
- return new ArrayList<>();
- }
- // 3. 组装VO列表
- List<MomentListVO> voList = moments.stream().map(moment -> {
- MomentListVO vo = new MomentListVO();
- vo.setId(moment.getId());
- vo.setTitle(moment.getTitle());
- vo.setAuditStatus(moment.getAuditStatus());
- vo.setCoverUrl(moment.getCoverUrl());
- vo.setPublishTime(moment.getPublishTime());
- vo.setViewCount(moment.getViewCount());
- return vo;
- }).collect(Collectors.toList());
- log.info("根据技师ID查询动态列表成功,技师ID:{},记录数:{}", technicianId, voList.size());
- return voList;
- }
- /**
- * 查询待审核动态列表(管理后台)
- *
- * @param queryDTO 查询参数
- * @return Page<MomentManageVO> 分页结果
- */
- @Override
- public Page<MomentManageVO> getMomentManageList(MomentManageQueryDTO queryDTO) {
- // 1. 参数处理
- Integer pageNum = queryDTO.getPageNum() != null ? queryDTO.getPageNum() : 1;
- Integer pageSize = queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10;
- String technicianName = queryDTO.getTechnicianName();
- Integer auditStatus = queryDTO.getAuditStatus();
- String startTime = queryDTO.getStartTime();
- if (StringUtils.isNotBlank(startTime)) {
- startTime = startTime + " 00:00:00";
- }
- String endTime = queryDTO.getEndTime();
- if (StringUtils.isNotBlank(endTime)) {
- endTime = endTime + " 23:59:59";
- }
- // 2. 构建查询条件
- LambdaQueryWrapper<TechnicianMoment> queryWrapper = new LambdaQueryWrapper<>();
- // 如果传入了审核状态,则按照审核状态查询
- if (auditStatus != null) {
- queryWrapper.eq(TechnicianMoment::getAuditStatus, auditStatus);
- } else {
- // 默认查询全部的动态(待审核、审核通过、审核拒绝)
- queryWrapper.in(TechnicianMoment::getAuditStatus, 1, 2, 3);
- }
- // 技师姓名查询
- if (StringUtils.isNotBlank(technicianName)) {
- //根据技师姓名查询技师的ID
- LambdaQueryWrapper<MaTechnician> jsQueryWrapper = new LambdaQueryWrapper<>();
- jsQueryWrapper.like(MaTechnician::getTeName, technicianName);
- List<MaTechnician> technicians = maTechnicianMapper.selectList(jsQueryWrapper);
- if (CollUtil.isNotEmpty(technicians)) {
- // 构建查询条件,查询所有匹配商户的动态
- queryWrapper.in(TechnicianMoment::getTechnicianId, technicians.stream().map(MaTechnician::getId).collect(Collectors.toList()));
- } else {
- // 没有匹配的商户,查询空字符串列表
- queryWrapper.in(TechnicianMoment::getTechnicianId, Collections.singleton(""));
- }
- }
- // 时间范围查询
- if (startTime != null && !startTime.trim().isEmpty()) {
- queryWrapper.ge(TechnicianMoment::getPublishTime, startTime);
- }
- if (endTime != null && !endTime.trim().isEmpty()) {
- queryWrapper.le(TechnicianMoment::getPublishTime, endTime);
- }
- // 按创建时间倒序排序
- queryWrapper.orderByDesc(TechnicianMoment::getCreateTime);
- // 3. 分页查询
- Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
- Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, queryWrapper);
- // 4. 组装VO
- Page<MomentManageVO> voPage = new Page<>(pageNum, pageSize);
- voPage.setTotal(momentPage.getTotal());
- voPage.setCurrent(momentPage.getCurrent());
- voPage.setSize(momentPage.getSize());
- List<TechnicianMoment> moments = momentPage.getRecords();
- if (moments == null || moments.isEmpty()) {
- voPage.setRecords(new ArrayList<>());
- return voPage;
- }
- // 5. 批量查询技师信息
- List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
- Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);
- // 6. 组装VO列表
- List<MomentManageVO> voList = moments.stream().map(moment -> {
- MomentManageVO vo = new MomentManageVO();
- BeanUtils.copyProperties(moment, vo);
- // 设置技师信息
- MaTechnician technician = technicianMap.get(moment.getTechnicianId());
- if (technician != null) {
- // 设置技师姓名
- vo.setTechnicianName(technician.getTeName());
- // 设置技师昵称
- vo.setTechnicianNickname(technician.getTeNickName());
- }
- return vo;
- }).collect(Collectors.toList());
- voPage.setRecords(voList);
- log.info("查询动态管理列表,页码:{},每页数量:{},总记录数:{}", pageNum, pageSize, voPage.getTotal());
- return voPage;
- }
- /**
- * 查询后台动态管理审核状态统计。
- *
- * @return MomentAuditStatusCountVO 审核状态统计
- */
- @Override
- public MomentAuditStatusCountVO getManageAuditStatusCount() {
- MomentAuditStatusCountVO count = momentMapper.selectManageAuditStatusCount();
- if (count == null) {
- count = new MomentAuditStatusCountVO();
- }
- if (count.getPendingCount() == null) {
- count.setPendingCount(0L);
- }
- if (count.getApprovedCount() == null) {
- count.setApprovedCount(0L);
- }
- if (count.getRejectedCount() == null) {
- count.setRejectedCount(0L);
- }
- return count;
- }
- /**
- * 审核动态(通过/拒绝)
- *
- * @param momentId 动态ID
- * @param auditStatus 审核状态:2-通过,3-拒绝
- * @param rejectReason 拒绝原因(拒绝时必填)
- * @return Boolean 是否成功
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Boolean auditMoment(MomentAuditDTO dto) {
- // 1. 参数校验
- if (dto.getMomentId() == null) {
- throw new ServiceException("动态ID不能为空");
- }
- if (dto.getAuditStatus() == null || (dto.getAuditStatus() != 2 && dto.getAuditStatus() != 3)) {
- throw new ServiceException("审核状态不正确");
- }
- if (dto.getAuditStatus() == 3 && (dto.getRejectReason() == null || dto.getRejectReason().trim().isEmpty())) {
- throw new ServiceException("拒绝时必须填写拒绝原因");
- }
- // 2. 查询动态信息
- TechnicianMoment moment = momentMapper.selectById(dto.getMomentId());
- if (moment == null) {
- throw new ServiceException("动态不存在");
- }
- // 3. 校验动态状态
- if (moment.getAuditStatus() != 1) {
- throw new ServiceException("只能审核待审核状态的动态");
- }
- // 4. 更新审核状态
- moment.setAuditStatus(dto.getAuditStatus());
- // 审核通过默认上架状态和推荐状态
- if(dto.getAuditStatus()==2){
- moment.setIsRecommend(1);
- moment.setIsList(1);
- }
- moment.setRejectReason(dto.getRejectReason());
- moment.setUpdateTime(LocalDateTime.now());
- int updateResult = momentMapper.updateById(moment);
- if (updateResult <= 0) {
- throw new ServiceException("审核失败");
- }
- return true;
- }
- /**
- * 更新动态推荐状态
- *
- * @param momentId 动态ID
- * @param isRecommend 是否推荐:0-否,1-是
- * @return 是否成功
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Boolean updateRecommendStatus(Long momentId, Integer isRecommend) {
- if (momentId == null) {
- throw new ServiceException("动态ID不能为空");
- }
- if (isRecommend == null || (isRecommend != 0 && isRecommend != 1)) {
- throw new ServiceException("是否推荐参数不正确");
- }
- int rows = momentMapper.updateRecommendStatus(momentId, isRecommend);
- if (rows <= 0) {
- throw new ServiceException("动态不存在或已删除");
- }
- log.info("更新动态推荐状态成功,动态ID:{},是否推荐:{}", momentId, isRecommend);
- return true;
- }
- /**
- * 更新动态上架状态
- *
- * @param momentId 动态ID
- * @param isList 是否上架:0-否,1-是
- * @return Boolean 是否成功
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Boolean updateListStatus(Long momentId, Integer isList) {
- if (momentId == null) {
- throw new ServiceException("动态ID不能为空");
- }
- if (isList == null || (isList != 0 && isList != 1)) {
- throw new ServiceException("上架状态参数不正确");
- }
- int rows = momentMapper.updateListStatus(momentId, isList);
- if (rows <= 0) {
- throw new ServiceException("动态不存在或已删除");
- }
- log.info("更新动态上架状态成功,动态ID:{},是否上架:{}", momentId, isList);
- return true;
- }
- /**
- * 根据动态ID查询动态简要详情(包含媒体URL列表)
- *
- * @param momentId 动态ID
- * @return MomentSimpleDetailVO动态简要详情
- */
- @Override
- public MomentSimpleDetailVO getMomentSimpleDetail(Long momentId) {
- // 1. 参数校验
- if (momentId == null) {
- throw new ServiceException("动态ID不能为空");
- }
- // 2. 查询动态信息
- Map<String, Object> result = momentMapper.selectMomentSimpleDetail(momentId);
- if (result == null || result.isEmpty()) {
- throw new ServiceException("动态不存在");
- }
- // 3. 组装VO
- MomentSimpleDetailVO vo = new MomentSimpleDetailVO();
- vo.setId(((Number) result.get("id")).longValue());
- vo.setTitle((String) result.get("title"));
- vo.setContent((String) result.get("content"));
- vo.setMediaType((Integer) result.get("media_type"));
- vo.setAuditStatus((Integer) result.get("audit_status"));
- vo.setRejectReason((String) result.get("reject_reason"));
- // 4. 处理媒体URL列表
- String mediaUrlsStr = (String) result.get("media_urls");
- if (mediaUrlsStr != null && !mediaUrlsStr.trim().isEmpty()) {
- // 将逗号分隔的字符串转换为List
- List<String> mediaUrls = Arrays.asList(mediaUrlsStr.split(","));
- vo.setMediaUrls(mediaUrls);
- } else {
- vo.setMediaUrls(new ArrayList<>());
- }
- log.info("查询动态简要详情成功,动态ID:{}", momentId);
- return vo;
- }
- @Override
- public Page<MomentVO> getByMerchantMoment(MerchantMomentDTO dto) {
- Page<MomentVO> page = new Page<>(dto.getCurrent(), dto.getSize());
- return this.baseMapper.getMerchantProject(page, dto);
- }
- }
|