|
@@ -1,17 +1,32 @@
|
|
|
package com.ylx.massage.service.impl;
|
|
package com.ylx.massage.service.impl;
|
|
|
|
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.time.Duration;
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.time.ZoneId;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
import java.util.function.Function;
|
|
import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import com.ylx.attendanceconfig.domain.AttendanceRule;
|
|
|
|
|
+import com.ylx.attendanceconfig.mapper.AttendanceRuleMapper;
|
|
|
import com.ylx.common.core.domain.AjaxResult;
|
|
import com.ylx.common.core.domain.AjaxResult;
|
|
|
import com.ylx.common.core.domain.model.LoginUser;
|
|
import com.ylx.common.core.domain.model.LoginUser;
|
|
|
import com.ylx.common.exception.ServiceException;
|
|
import com.ylx.common.exception.ServiceException;
|
|
|
import com.ylx.common.utils.DateUtils;
|
|
import com.ylx.common.utils.DateUtils;
|
|
|
import com.ylx.common.utils.StringUtils;
|
|
import com.ylx.common.utils.StringUtils;
|
|
|
|
|
+import com.ylx.massage.controller.CityOperationApplicationController;
|
|
|
|
|
+import com.ylx.massage.domain.*;
|
|
|
|
|
+import com.ylx.massage.domain.dto.*;
|
|
|
|
|
+import com.ylx.massage.domain.vo.*;
|
|
|
|
|
+import com.ylx.massage.enums.ProjectCategoryEnum;
|
|
|
|
|
+import com.ylx.massage.enums.TechnicianStatusEnum;
|
|
|
|
|
+import com.ylx.massage.mapper.*;
|
|
|
import com.ylx.massage.domain.ContractRecord;
|
|
import com.ylx.massage.domain.ContractRecord;
|
|
|
import com.ylx.massage.domain.MaProject;
|
|
import com.ylx.massage.domain.MaProject;
|
|
|
import com.ylx.massage.domain.MaTeProject;
|
|
import com.ylx.massage.domain.MaTeProject;
|
|
@@ -37,12 +52,14 @@ import lombok.Data;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
-import com.ylx.massage.mapper.MaTechnicianMapper;
|
|
|
|
|
-import com.ylx.massage.domain.MaTechnician;
|
|
|
|
|
import com.ylx.massage.service.IMaTechnicianService;
|
|
import com.ylx.massage.service.IMaTechnicianService;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+
|
|
|
|
|
+import static com.ylx.massage.enums.FileTypeEnum.*;
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 技师Service业务层处理
|
|
* 技师Service业务层处理
|
|
|
*
|
|
*
|
|
@@ -65,12 +82,12 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
private static final Integer NOT_DELETED = 0;
|
|
private static final Integer NOT_DELETED = 0;
|
|
|
private static final String MERCHANT_STATUS_NORMAL = "0";
|
|
private static final String MERCHANT_STATUS_NORMAL = "0";
|
|
|
|
|
|
|
|
- @Autowired
|
|
|
|
|
|
|
+ @Resource
|
|
|
private MaTechnicianMapper maTechnicianMapper;
|
|
private MaTechnicianMapper maTechnicianMapper;
|
|
|
|
|
|
|
|
- @Autowired
|
|
|
|
|
|
|
+ @Resource
|
|
|
private MaTeProjectMapper maTeProjectMapper;
|
|
private MaTeProjectMapper maTeProjectMapper;
|
|
|
- @Autowired
|
|
|
|
|
|
|
+ @Resource
|
|
|
private MaProjectMapper maProjectMapper;
|
|
private MaProjectMapper maProjectMapper;
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
@@ -79,8 +96,17 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private TbFileService fileService;
|
|
private TbFileService fileService;
|
|
|
|
|
|
|
|
- @Autowired
|
|
|
|
|
|
|
+ @Resource
|
|
|
private ContractRecordMapper contractRecordMapper;
|
|
private ContractRecordMapper contractRecordMapper;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private MerchantDailyAttendanceMapper merchantDailyAttendanceMapper;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private AttendanceRuleMapper attendanceRuleMapper;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private TAddressMapper addressMapper;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private MerchantApplyFileMapper merchantApplyFileMapper;
|
|
|
|
|
+
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 商户入驻申请注册
|
|
* 商户入驻申请注册
|
|
@@ -101,6 +127,18 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
maTechnicianMapper.insert(maTechnician);
|
|
maTechnicianMapper.insert(maTechnician);
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 商户入驻申请文件上传
|
|
|
|
|
+ * @param req
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void applyFile(MerchantApplyFileDto req){
|
|
|
|
|
+ MerchantApplyFile maTechnician = new MerchantApplyFile();
|
|
|
|
|
+ BeanUtils.copyProperties(req, maTechnician);
|
|
|
|
|
+ maTechnician.setCreateBy(req.getMerchantId().toString());
|
|
|
|
|
+ maTechnician.setUpdateBy(req.getMerchantId().toString());
|
|
|
|
|
+ merchantApplyFileMapper.insert(maTechnician);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 商户入住前置条件校验
|
|
* 商户入住前置条件校验
|
|
@@ -146,7 +184,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
queryWrapper.eq(MaTechnician::getIsDelete, 0);
|
|
queryWrapper.eq(MaTechnician::getIsDelete, 0);
|
|
|
queryWrapper.eq(MaTechnician::getAuditStatus, 2);
|
|
queryWrapper.eq(MaTechnician::getAuditStatus, 2);
|
|
|
//queryWrapper.eq(MaTechnician::getOpenService, req.getOpenService());
|
|
//queryWrapper.eq(MaTechnician::getOpenService, req.getOpenService());
|
|
|
- queryWrapper.eq(MaTechnician::getServiceTag,req.getServiceTag());
|
|
|
|
|
|
|
+ queryWrapper.eq(MaTechnician::getServiceTag, req.getServiceTag());
|
|
|
MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
|
|
MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
|
|
|
return userProfile;
|
|
return userProfile;
|
|
|
}
|
|
}
|
|
@@ -282,7 +320,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
if (id == null) {
|
|
if (id == null) {
|
|
|
throw new ServiceException("商户ID不能为空");
|
|
throw new ServiceException("商户ID不能为空");
|
|
|
}
|
|
}
|
|
|
- MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
|
|
|
|
|
|
|
+ MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id.intValue());
|
|
|
if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
|
|
if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
|
|
|
throw new ServiceException("商户不存在或已删除");
|
|
throw new ServiceException("商户不存在或已删除");
|
|
|
}
|
|
}
|
|
@@ -357,45 +395,6 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
}
|
|
}
|
|
|
return uploadResult;
|
|
return uploadResult;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 全量替换商户与服务项目关联关系。
|
|
|
|
|
- *
|
|
|
|
|
- * @param technicianId 商户ID
|
|
|
|
|
- * @param projectIds 服务项目ID集合
|
|
|
|
|
- */
|
|
|
|
|
- private void replaceProjectRelations(Integer technicianId, Set<Long> projectIds) {
|
|
|
|
|
- if (technicianId == null) {
|
|
|
|
|
- throw new ServiceException("商户ID不能为空");
|
|
|
|
|
- }
|
|
|
|
|
- maTeProjectMapper.deleteByTechnicianId(technicianId.longValue());
|
|
|
|
|
- for (Long projectId : projectIds) {
|
|
|
|
|
- MaTeProject relation = new MaTeProject();
|
|
|
|
|
- relation.setTeId(technicianId.longValue());
|
|
|
|
|
- relation.setProjectId(projectId);
|
|
|
|
|
- int rows = maTeProjectMapper.insert(relation);
|
|
|
|
|
- if (rows <= 0) {
|
|
|
|
|
- throw new ServiceException("编辑商户服务项目失败");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 后台查询商户入驻审核列表
|
|
|
|
|
- *
|
|
|
|
|
- * @param page 分页参数
|
|
|
|
|
- * @param dto 查询条件
|
|
|
|
|
- * @return 商户入驻审核分页列表
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public Page<MaTechnicianAuditListVO> selectMerchantAuditList(Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
|
|
|
|
|
- if (dto != null && dto.getAuditStatus() != null) {
|
|
|
|
|
- checkEnumValue(dto.getAuditStatus(), "审核状态", 0, 1, 2, 3);
|
|
|
|
|
- }
|
|
|
|
|
- Page<MaTechnicianAuditListVO> pageParam = page == null ? new Page<>(1, 10) : page;
|
|
|
|
|
- return maTechnicianMapper.selectMerchantAuditList(pageParam, dto);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 商户入驻审核。
|
|
* 商户入驻审核。
|
|
|
*
|
|
*
|
|
@@ -448,6 +447,92 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
}
|
|
}
|
|
|
return rows;
|
|
return rows;
|
|
|
}
|
|
}
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 后台查询商户证照
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param id 商户ID
|
|
|
|
|
+ * @return 商户证照
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public MaTechnicianCertificateVO selectMerchantCertificate(Integer id) {
|
|
|
|
|
+ if (id == null) {
|
|
|
|
|
+ throw new ServiceException("商户ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ LambdaQueryWrapper<MerchantApplyFile> queryWrapper = Wrappers.lambdaQuery();
|
|
|
|
|
+ queryWrapper.eq(MerchantApplyFile::getMerchantId, id);
|
|
|
|
|
+ List<MerchantApplyFile> merchantApplyFiles = merchantApplyFileMapper.selectList(queryWrapper);
|
|
|
|
|
+ if (merchantApplyFiles == null) {
|
|
|
|
|
+ throw new ServiceException("商户不存在或已删除");
|
|
|
|
|
+ }
|
|
|
|
|
+ MaTechnicianCertificateVO certificate = new MaTechnicianCertificateVO();
|
|
|
|
|
+ certificate.setMerchantId(merchantApplyFiles.get(0).getMerchantId());
|
|
|
|
|
+ merchantApplyFiles.forEach(merchant -> {
|
|
|
|
|
+ certificate.setAvatar( typeFIleUrl(merchant,PORTRAIT.getCode()));
|
|
|
|
|
+ certificate.setLifePhotos( typeFIleUrl(merchant,LIFE_PHOTO.getCode()));
|
|
|
|
|
+ certificate.setIdCardFrout( typeFIleUrl(merchant,ID_CARD_FRONT.getCode()));
|
|
|
|
|
+ certificate.setIdCardBack( typeFIleUrl(merchant,ID_CARD_BACK.getCode()));
|
|
|
|
|
+ certificate.setIdCardHandheld( typeFIleUrl(merchant,ID_CARD_HANDHELD.getCode()));
|
|
|
|
|
+ certificate.setHealthCertificate( typeFIleUrl(merchant,HEALTH_CERT.getCode()));
|
|
|
|
|
+ certificate.setQualificationCertificate( typeFIleUrl(merchant,QUALIFICATION_CERT.getCode()));
|
|
|
|
|
+ certificate.setNoCrimeRecord( typeFIleUrl(merchant,NO_CRIME_RECORD.getCode()));
|
|
|
|
|
+ certificate.setCommitmentPdf( typeFIleUrl(merchant,COMMITMENT_LETTER.getCode()));
|
|
|
|
|
+ certificate.setCommitmentVideo( typeFIleUrl(merchant,COMMITMENT_VIDEO.getCode()));
|
|
|
|
|
+ certificate.setCommitmentAudio( typeFIleUrl(merchant,COMMITMENT_AUDIO.getCode()));
|
|
|
|
|
+
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return certificate;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String typeFIleUrl(MerchantApplyFile merchant, String type) {
|
|
|
|
|
+
|
|
|
|
|
+ LambdaQueryWrapper<MerchantApplyFile> queryWrapper1 = Wrappers.lambdaQuery();
|
|
|
|
|
+ queryWrapper1.eq(MerchantApplyFile::getMerchantId, merchant.getMerchantId());
|
|
|
|
|
+ queryWrapper1.eq(MerchantApplyFile::getFileType, type);
|
|
|
|
|
+ MerchantApplyFile merchantApplyFiles = merchantApplyFileMapper.selectOne(queryWrapper1);
|
|
|
|
|
+ if (merchantApplyFiles == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ return merchantApplyFiles.getFileUrl();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 全量替换商户与服务项目关联关系。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param technicianId 商户ID
|
|
|
|
|
+ * @param projectIds 服务项目ID集合
|
|
|
|
|
+ */
|
|
|
|
|
+ private void replaceProjectRelations(Integer technicianId, Set<Integer> projectIds) {
|
|
|
|
|
+ if (technicianId == null) {
|
|
|
|
|
+ throw new ServiceException("商户ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ maTeProjectMapper.deleteByTechnicianId(technicianId);
|
|
|
|
|
+ for (Integer projectId : projectIds) {
|
|
|
|
|
+ MaTeProject relation = new MaTeProject();
|
|
|
|
|
+ relation.setTeId(technicianId);
|
|
|
|
|
+ relation.setProjectId(projectId);
|
|
|
|
|
+ int rows = maTeProjectMapper.insert(relation);
|
|
|
|
|
+ if (rows <= 0) {
|
|
|
|
|
+ throw new ServiceException("编辑商户服务项目失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 后台查询商户入驻审核列表
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param page 分页参数
|
|
|
|
|
+ * @param dto 查询条件
|
|
|
|
|
+ * @return 商户入驻审核分页列表
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Page<MaTechnicianAuditListVO> selectMerchantAuditList(Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
|
|
|
|
|
+ if (dto != null && dto.getAuditStatus() != null) {
|
|
|
|
|
+ checkEnumValue(dto.getAuditStatus(), "审核状态", 0, 1, 2, 3);
|
|
|
|
|
+ }
|
|
|
|
|
+ Page<MaTechnicianAuditListVO> pageParam = page == null ? new Page<>(1, 10) : page;
|
|
|
|
|
+ return maTechnicianMapper.selectMerchantAuditList(pageParam, dto);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 后台查询商户列表
|
|
* 后台查询商户列表
|
|
@@ -481,36 +566,6 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
return detail;
|
|
return detail;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 后台查询商户证照
|
|
|
|
|
- *
|
|
|
|
|
- * @param id 商户ID
|
|
|
|
|
- * @return 商户证照
|
|
|
|
|
- */
|
|
|
|
|
- @Override
|
|
|
|
|
- public MaTechnicianCertificateVO selectMerchantCertificate(Integer id) {
|
|
|
|
|
- if (id == null) {
|
|
|
|
|
- throw new ServiceException("商户ID不能为空");
|
|
|
|
|
- }
|
|
|
|
|
- MaTechnician merchant = maTechnicianMapper.selectMerchantCertificateById(id);
|
|
|
|
|
- if (merchant == null || !NOT_DELETED.equals(merchant.getIsDelete())) {
|
|
|
|
|
- throw new ServiceException("商户不存在或已删除");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- MaTechnicianCertificateVO certificate = new MaTechnicianCertificateVO();
|
|
|
|
|
- certificate.setMerchantId(merchant.getId());
|
|
|
|
|
- certificate.setAvatar(merchant.getAvatar());
|
|
|
|
|
- certificate.setLifePhotos(merchant.getLifePhotos());
|
|
|
|
|
- certificate.setIdCard(merchant.getIdCard());
|
|
|
|
|
- certificate.setHealthCertificate(merchant.getHealthCertificate());
|
|
|
|
|
- certificate.setQualificationCertificate(merchant.getQualificationCertificate());
|
|
|
|
|
- certificate.setNoCrimeRecord(merchant.getNoCrimeRecord());
|
|
|
|
|
- certificate.setCommitmentPdf(merchant.getCommitmentPdf());
|
|
|
|
|
- certificate.setCommitmentVideo(merchant.getCommitmentVideo());
|
|
|
|
|
- certificate.setCommitmentAudio(merchant.getCommitmentAudio());
|
|
|
|
|
- return certificate;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 修改技师
|
|
* 修改技师
|
|
|
*
|
|
*
|
|
@@ -622,13 +677,13 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
* @param categoryIds 服务类目ID集合
|
|
* @param categoryIds 服务类目ID集合
|
|
|
* @return 有效服务项目ID集合
|
|
* @return 有效服务项目ID集合
|
|
|
*/
|
|
*/
|
|
|
- private MerchantProjectSelection checkProjectIds(List<Long> projectIds, Set<Integer> categoryIds) {
|
|
|
|
|
|
|
+ private MerchantProjectSelection checkProjectIds(List<Integer> projectIds, Set<Integer> categoryIds) {
|
|
|
if (projectIds == null || projectIds.isEmpty()) {
|
|
if (projectIds == null || projectIds.isEmpty()) {
|
|
|
throw new ServiceException("服务项目不能为空");
|
|
throw new ServiceException("服务项目不能为空");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Set<Long> distinctProjectIds = new LinkedHashSet<>();
|
|
|
|
|
- for (Long projectId : projectIds) {
|
|
|
|
|
|
|
+ Set<Integer> distinctProjectIds = new LinkedHashSet<>();
|
|
|
|
|
+ for (Integer projectId : projectIds) {
|
|
|
if (projectId == null) {
|
|
if (projectId == null) {
|
|
|
throw new ServiceException("服务项目ID不能为空");
|
|
throw new ServiceException("服务项目ID不能为空");
|
|
|
}
|
|
}
|
|
@@ -642,10 +697,10 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
throw new ServiceException("服务项目不存在或已删除");
|
|
throw new ServiceException("服务项目不存在或已删除");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Map<Long, Project> projectMap = projects.stream()
|
|
|
|
|
- .collect(Collectors.toMap(project -> project.getId().longValue(), Function.identity(), (left, right) -> left));
|
|
|
|
|
|
|
+ Map<Integer, Project> projectMap = projects.stream()
|
|
|
|
|
+ .collect(Collectors.toMap(project -> project.getId(), Function.identity(), (left, right) -> left));
|
|
|
Set<Integer> projectCategoryIds = new LinkedHashSet<>();
|
|
Set<Integer> projectCategoryIds = new LinkedHashSet<>();
|
|
|
- for (Long projectId : distinctProjectIds) {
|
|
|
|
|
|
|
+ for (Integer projectId : distinctProjectIds) {
|
|
|
Project project = projectMap.get(projectId);
|
|
Project project = projectMap.get(projectId);
|
|
|
if (project == null || project.getCategoryId() == null) {
|
|
if (project == null || project.getCategoryId() == null) {
|
|
|
throw new ServiceException("服务项目类目不能为空");
|
|
throw new ServiceException("服务项目类目不能为空");
|
|
@@ -687,7 +742,7 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
.collect(Collectors.joining(","));
|
|
.collect(Collectors.joining(","));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private String joinProjectTitles(Set<Long> projectIds, Map<Long, Project> projectMap) {
|
|
|
|
|
|
|
+ private String joinProjectTitles(Set<Integer> projectIds, Map<Integer, Project> projectMap) {
|
|
|
return projectIds.stream()
|
|
return projectIds.stream()
|
|
|
.map(projectMap::get)
|
|
.map(projectMap::get)
|
|
|
.map(Project::getTitle)
|
|
.map(Project::getTitle)
|
|
@@ -701,15 +756,15 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
* @param technicianId
|
|
* @param technicianId
|
|
|
* @param projectIds
|
|
* @param projectIds
|
|
|
*/
|
|
*/
|
|
|
- private void insertProjectRelations(Integer technicianId, Set<Long> projectIds) {
|
|
|
|
|
|
|
+ private void insertProjectRelations(Integer technicianId, Set<Integer> projectIds) {
|
|
|
if (technicianId == null) {
|
|
if (technicianId == null) {
|
|
|
throw new ServiceException("商户ID不能为空");
|
|
throw new ServiceException("商户ID不能为空");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
List<MaTeProject> relations = new ArrayList<>();
|
|
List<MaTeProject> relations = new ArrayList<>();
|
|
|
- for (Long projectId : projectIds) {
|
|
|
|
|
|
|
+ for (Integer projectId : projectIds) {
|
|
|
MaTeProject relation = new MaTeProject();
|
|
MaTeProject relation = new MaTeProject();
|
|
|
- relation.setTeId(technicianId.longValue());
|
|
|
|
|
|
|
+ relation.setTeId(technicianId);
|
|
|
relation.setProjectId(projectId);
|
|
relation.setProjectId(projectId);
|
|
|
relations.add(relation);
|
|
relations.add(relation);
|
|
|
}
|
|
}
|
|
@@ -721,10 +776,10 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
|
|
|
|
|
private static class MerchantProjectSelection {
|
|
private static class MerchantProjectSelection {
|
|
|
private final Set<Integer> categoryIds;
|
|
private final Set<Integer> categoryIds;
|
|
|
- private final Set<Long> projectIds;
|
|
|
|
|
- private final Map<Long, Project> projectMap;
|
|
|
|
|
|
|
+ private final Set<Integer> projectIds;
|
|
|
|
|
+ private final Map<Integer, Project> projectMap;
|
|
|
|
|
|
|
|
- private MerchantProjectSelection(Set<Integer> categoryIds, Set<Long> projectIds, Map<Long, Project> projectMap) {
|
|
|
|
|
|
|
+ private MerchantProjectSelection(Set<Integer> categoryIds, Set<Integer> projectIds, Map<Integer, Project> projectMap) {
|
|
|
this.categoryIds = categoryIds;
|
|
this.categoryIds = categoryIds;
|
|
|
this.projectIds = projectIds;
|
|
this.projectIds = projectIds;
|
|
|
this.projectMap = projectMap;
|
|
this.projectMap = projectMap;
|
|
@@ -734,11 +789,11 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
return categoryIds;
|
|
return categoryIds;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private Set<Long> getProjectIds() {
|
|
|
|
|
|
|
+ private Set<Integer> getProjectIds() {
|
|
|
return projectIds;
|
|
return projectIds;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private Map<Long, Project> getProjectMap() {
|
|
|
|
|
|
|
+ private Map<Integer, Project> getProjectMap() {
|
|
|
return projectMap;
|
|
return projectMap;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -799,9 +854,209 @@ public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaT
|
|
|
maProject.setProjectLowestPrice(project.getPriceMin());
|
|
maProject.setProjectLowestPrice(project.getPriceMin());
|
|
|
maProject.setCreateBy(dto.getUserId());
|
|
maProject.setCreateBy(dto.getUserId());
|
|
|
maProject.setMerchantId(dto.getUserId());
|
|
maProject.setMerchantId(dto.getUserId());
|
|
|
- maProject.setApplyTime((Data) new Date());
|
|
|
|
|
|
|
+ maProject.setApplyTime(DateUtils.getNowDate());
|
|
|
maProject.setMerchantPhone(dto.getMerchantPhone());
|
|
maProject.setMerchantPhone(dto.getMerchantPhone());
|
|
|
|
|
+ maProject.setCreateTime(DateUtils.getNowDate());
|
|
|
maProjectMapper.insert(maProject);
|
|
maProjectMapper.insert(maProject);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 状态切换
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId
|
|
|
|
|
+ * @param forceConfirm
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Result switchToOffline(Long userId, Boolean forceConfirm) {
|
|
|
|
|
+ MaTechnician technician = getTechnician(userId);
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 基础权限校验 (对应流程图左下角)
|
|
|
|
|
+ if (!hasActiveSkills(userId)) {
|
|
|
|
|
+ throw new RuntimeException("请先申请开通技能");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!hasHomeAddress(userId)) {
|
|
|
|
|
+ // 这里通常会触发前端弹窗要求添加地址,或者直接阻断
|
|
|
|
|
+ throw new RuntimeException("请完善家庭地址");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (ProjectCategoryEnum.MASSAGE.getCode().equals(technician.getServiceTag())) {
|
|
|
|
|
+ // 2. 状态判断逻辑 (对应流程图中间的菱形判断)
|
|
|
|
|
+ // 只有处于“在线接单”状态才需要检查疲劳度/时长限制
|
|
|
|
|
+ if (TechnicianStatusEnum.ONLINE.getCode().equals(technician.getPostState())) {
|
|
|
|
|
+ // 获取今日的商户考勤记录
|
|
|
|
|
+ MerchantDailyAttendance attendance = getTodayAttendance(userId);
|
|
|
|
|
+
|
|
|
|
|
+ long minutesOnline = 0;
|
|
|
|
|
+ if (attendance != null && attendance.getAttendanceStartTime() != null) {
|
|
|
|
|
+ LocalDateTime localDateTime = attendance.getAttendanceStartTime().toInstant()
|
|
|
|
|
+ .atZone(ZoneId.systemDefault())
|
|
|
|
|
+ .toLocalDateTime();
|
|
|
|
|
+ //计算截止现在的时长,单位为分钟
|
|
|
|
|
+ minutesOnline = Duration.between(localDateTime, LocalDateTime.now()).toMinutes();
|
|
|
|
|
+ // 计算今日的累加在线时长
|
|
|
|
|
+ minutesOnline = minutesOnline + getWorkDuration(userId);
|
|
|
|
|
+ }
|
|
|
|
|
+ AttendanceRule rule = getAttendanceRule();
|
|
|
|
|
+ if (rule != null) {
|
|
|
|
|
+ // 将小时转换为分钟进行比较
|
|
|
|
|
+ BigDecimal minutes = rule.getBasicWorkHours().multiply(new BigDecimal(60));
|
|
|
|
|
+ // 2. 精确转换成 long(无小数、无溢出才成功)
|
|
|
|
|
+ long requiredMinutes = minutes.longValueExact();
|
|
|
|
|
+ // 判断是否超过了平台规定的在线时间 (X小时)
|
|
|
|
|
+ if (minutesOnline < requiredMinutes) {
|
|
|
|
|
+ // 情况 A: 超时了,且用户还没有点击“确认下线”(forceConfirm=false)
|
|
|
|
|
+ if (!forceConfirm) {
|
|
|
|
|
+ // 返回特定错误码或数据结构,告诉前端弹出“我在想想/确认下线”的模态框
|
|
|
|
|
+ return Result.ok("平台对您的在线时间做了约定,每日在线需满足"
|
|
|
|
|
+ + (requiredMinutes / 60) + "小时,距离您下线时间还剩余" + ((requiredMinutes / 60) - minutesOnline) + "小时"
|
|
|
|
|
+ + "不满足在线时间将收到平台处罚,是否确认下线?");
|
|
|
|
|
+ }
|
|
|
|
|
+ // 情况 B: 超时了,但用户已经点击了“确认下线”,允许通过
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 执行状态更新 (更新为休息中状态)
|
|
|
|
|
+ updateStatus(userId, TechnicianStatusEnum.RESTING);
|
|
|
|
|
+ if (!forceConfirm) {
|
|
|
|
|
+ // 查询商户今日的最近考勤记录
|
|
|
|
|
+ LambdaQueryWrapper<MerchantDailyAttendance> query = new LambdaQueryWrapper<>();
|
|
|
|
|
+ query.eq(MerchantDailyAttendance::getMerchantId, userId)
|
|
|
|
|
+ .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate())
|
|
|
|
|
+ .orderByDesc(MerchantDailyAttendance::getCreateTime);
|
|
|
|
|
+ MerchantDailyAttendance update = merchantDailyAttendanceMapper.selectOne(query);
|
|
|
|
|
+ if (update != null) {
|
|
|
|
|
+ LocalDateTime localDateTime = update.getAttendanceStartTime().toInstant()
|
|
|
|
|
+ .atZone(ZoneId.systemDefault())
|
|
|
|
|
+ .toLocalDateTime();
|
|
|
|
|
+ LambdaUpdateWrapper<MerchantDailyAttendance> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ updateWrapper.eq(MerchantDailyAttendance::getId, update.getId())
|
|
|
|
|
+ .set(MerchantDailyAttendance::getAttendanceEndTime, DateUtils.getNowDate())
|
|
|
|
|
+ .set(MerchantDailyAttendance::getTotalWorkMinutes, Duration.between(localDateTime, LocalDateTime.now()).toMinutes())
|
|
|
|
|
+ .set(MerchantDailyAttendance::getUpdateTime, DateUtils.getNowDate());
|
|
|
|
|
+ merchantDailyAttendanceMapper.update(update, updateWrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ //更新状态为在线接单
|
|
|
|
|
+ updateStatus(userId, TechnicianStatusEnum.ONLINE);
|
|
|
|
|
+ // 插入今日考勤记录
|
|
|
|
|
+ MerchantDailyAttendance merchantDailyAttendance = new MerchantDailyAttendance()
|
|
|
|
|
+ .setMerchantId(userId.intValue())
|
|
|
|
|
+ .setAttendanceDate(DateUtils.getNowDate())
|
|
|
|
|
+ .setMerchantName(technician.getTeName())
|
|
|
|
|
+ .setAttendanceStartTime(DateUtils.getNowDate())
|
|
|
|
|
+ .setCreateBy(technician.getTeName())
|
|
|
|
|
+ .setCreateTime(LocalDateTime.now());
|
|
|
|
|
+ merchantDailyAttendanceMapper.insert(merchantDailyAttendance);
|
|
|
|
|
+ }
|
|
|
|
|
+ return Result.ok("状态已切换成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取今天商户的考勤记录
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 技师ID
|
|
|
|
|
+ * @return 考勤记录
|
|
|
|
|
+ */
|
|
|
|
|
+ private MerchantDailyAttendance getTodayAttendance(Long userId) {
|
|
|
|
|
+ LambdaQueryWrapper<MerchantDailyAttendance> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(MerchantDailyAttendance::getMerchantId, userId)
|
|
|
|
|
+ .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate())
|
|
|
|
|
+ .orderByDesc(MerchantDailyAttendance::getCreateTime)
|
|
|
|
|
+ .last("LIMIT 1");
|
|
|
|
|
+
|
|
|
|
|
+ return merchantDailyAttendanceMapper.selectOne(wrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取商户的累计工作时长
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 技师ID
|
|
|
|
|
+ * @return 工作时长(分钟)
|
|
|
|
|
+ */
|
|
|
|
|
+ private long getWorkDuration(Long userId) {
|
|
|
|
|
+ LambdaQueryWrapper<MerchantDailyAttendance> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(MerchantDailyAttendance::getMerchantId, userId)
|
|
|
|
|
+ .eq(MerchantDailyAttendance::getAttendanceDate, DateUtils.getNowDate());
|
|
|
|
|
+ List<MerchantDailyAttendance> attendances = merchantDailyAttendanceMapper.selectList(wrapper);
|
|
|
|
|
+ if (attendances == null || attendances.isEmpty()) return 0;
|
|
|
|
|
+ // 计算指定日期的总分钟数
|
|
|
|
|
+ long totalMinutes = attendances.stream()
|
|
|
|
|
+ .filter(attendance -> DateUtils.getNowDate().toString().equals(attendance.getAttendanceDate().toString()))
|
|
|
|
|
+ .mapToLong(MerchantDailyAttendance::getTotalWorkMinutes)
|
|
|
|
|
+ .sum();
|
|
|
|
|
+ return totalMinutes;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取商户的考勤规则
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 考勤规则
|
|
|
|
|
+ */
|
|
|
|
|
+ private AttendanceRule getAttendanceRule() {
|
|
|
|
|
+ LambdaQueryWrapper<AttendanceRule> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(AttendanceRule::getIsDelete, 0);
|
|
|
|
|
+ wrapper.eq(AttendanceRule::getWorkDurationRuleEnabled, 1);
|
|
|
|
|
+ wrapper.last("LIMIT 1");
|
|
|
|
|
+ return attendanceRuleMapper.selectOne(wrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断用户是否有生效中的技能
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 技师ID
|
|
|
|
|
+ * @return true: 有可用技能, false: 无
|
|
|
|
|
+ */
|
|
|
|
|
+ public boolean hasActiveSkills(Long userId) {
|
|
|
|
|
+ if (userId == null) return false;
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件:用户ID匹配 AND 状态为已发布/生效中
|
|
|
|
|
+ LambdaQueryWrapper<MaProject> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(MaProject::getMerchantId, userId)
|
|
|
|
|
+ .eq(MaProject::getAuditStatus, 1); // 假设 1 代表 "生效/已审核"
|
|
|
|
|
+ // 只要查到一条记录即返回 true
|
|
|
|
|
+ return maProjectMapper.selectCount(wrapper) > 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断用户是否有家庭地址(通常指设置为默认的地址)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 技师ID
|
|
|
|
|
+ * @return true: 有地址, false: 无
|
|
|
|
|
+ */
|
|
|
|
|
+ public boolean hasHomeAddress(Long userId) {
|
|
|
|
|
+ if (userId == null) return false;
|
|
|
|
|
+
|
|
|
|
|
+ // 构建查询条件:用户ID匹配 AND 是默认地址(可选) AND 未删除
|
|
|
|
|
+ LambdaQueryWrapper<TAddress> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(TAddress::getMerchantId, userId)
|
|
|
|
|
+ .eq(TAddress::getUserType, 2) // 商户类型
|
|
|
|
|
+ .eq(TAddress::getIsDelete, 0); // 逻辑未删除
|
|
|
|
|
+
|
|
|
|
|
+ // 统计数量是否大于0
|
|
|
|
|
+ long count = addressMapper.selectCount(wrapper);
|
|
|
|
|
+ return count > 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 辅助方法:模拟获取用户
|
|
|
|
|
+ private MaTechnician getTechnician(Long userId) {
|
|
|
|
|
+ // ... DB查询逻辑
|
|
|
|
|
+ LambdaQueryWrapper<MaTechnician> query = new LambdaQueryWrapper<>();
|
|
|
|
|
+ query.eq(MaTechnician::getId, userId);
|
|
|
|
|
+ return maTechnicianMapper.selectOne(query);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 辅助方法:更新状态
|
|
|
|
|
+ private void updateStatus(Long userId, TechnicianStatusEnum status) {
|
|
|
|
|
+ LambdaUpdateWrapper<MaTechnician> update = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ update.eq(MaTechnician::getId, userId);
|
|
|
|
|
+ update.set(MaTechnician::getPostState, status.getCode());
|
|
|
|
|
+ // ... DB Update逻辑,同时记录上线/下线时间
|
|
|
|
|
+ maTechnicianMapper.update(null, update);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|