| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425 |
- package com.ylx.massage.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.util.ObjectUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.ylx.address.domain.TAddress;
- import com.ylx.address.mapper.TAddressMapper;
- import com.ylx.attendanceconfig.domain.AttendanceRule;
- import com.ylx.attendanceconfig.mapper.AttendanceRuleMapper;
- import com.ylx.collect.service.CollectService;
- import com.ylx.common.core.domain.model.LoginUser;
- import com.ylx.common.exception.ServiceException;
- import com.ylx.common.utils.DateUtils;
- import com.ylx.common.utils.DistanceUtil;
- import com.ylx.common.utils.ServletUtils;
- import com.ylx.common.utils.StringUtils;
- import com.ylx.fareSetting.service.IMaProjectFareSettingService;
- import com.ylx.massage.domain.*;
- import com.ylx.massage.domain.dto.*;
- import com.ylx.massage.domain.vo.*;
- import com.ylx.massage.enums.*;
- import com.ylx.massage.mapper.*;
- import com.ylx.massage.service.IMaTechnicianService;
- import com.ylx.address.service.TAddressService;
- import com.ylx.merchant.domain.dto.MerchantDetailDTO;
- import com.ylx.merchant.domain.dto.MerchantListDTO;
- import com.ylx.merchant.domain.dto.MerchantProjectDTO;
- import com.ylx.merchant.domain.vo.MerchantDetailVO;
- import com.ylx.merchant.domain.vo.MerchantListVO;
- import com.ylx.order.domain.TOrder;
- import com.ylx.order.mapper.TOrderMapper;
- import com.ylx.project.domain.Project;
- import com.ylx.project.domain.bookMerchant.vo.ProjectInfoVO;
- import com.ylx.project.mapper.ProjectMapper;
- import org.springframework.beans.BeanUtils;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.CollectionUtils;
- import javax.annotation.Resource;
- import java.math.BigDecimal;
- import java.time.Duration;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.ZoneId;
- import java.time.format.DateTimeFormatter;
- import java.util.*;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- import static com.ylx.massage.enums.FileTypeEnum.*;
- /**
- * 技师Service业务层处理
- *
- * @author ylx
- * @date 2024-03-22
- */
- @Service
- public class MaTechnicianServiceImpl extends ServiceImpl<MaTechnicianMapper, MaTechnician> implements IMaTechnicianService {
- private static final int SERVICE_STATE_AVAILABLE = 1;
- private static final int POST_STATE_OFFLINE = 0;
- private static final int ENABLED = 1;
- private static final int AUDIT_APPROVED = 2;
- private static final int AUDIT_WAIT_ENTER = 0;
- private static final int AUDIT_WAIT_REVIEW = 1;
- private static final int AUDIT_REJECTED = 3;
- private static final int AUDIT_REMARK_MAX_LENGTH = 500;
- private static final int NS_STATUS_NOT_ON_DUTY = -1;
- private static final int DEFAULT_STAT_VALUE = 0;
- private static final Integer NOT_DELETED = 0;
- private static final Integer MERCHANT_STATUS_NORMAL = 0;
- private static final String PASSWORD = "123456";
- private static final int PROFILE_AUDIT_PENDING = 0;
- private static final int PROFILE_AUDIT_APPROVED = 1;
- private static final int PROFILE_AUDIT_REJECTED = 2;
- private static final Set<String> PROFILE_FILE_TYPES = new LinkedHashSet<>(Arrays.asList(
- PORTRAIT.getCode(),
- LIFE_PHOTO.getCode(),
- PROMOTION_VIDEO.getCode(),
- ID_CARD_FRONT.getCode(),
- ID_CARD_BACK.getCode(),
- ID_CARD_HANDHELD.getCode(),
- HEALTH_CERT.getCode(),
- QUALIFICATION_CERT.getCode(),
- NO_CRIME_RECORD.getCode(),
- COMMITMENT_LETTER.getCode(),
- COMMITMENT_AUDIO.getCode(),
- COMMITMENT_VIDEO.getCode()
- ));
- @Resource
- private MaTechnicianMapper maTechnicianMapper;
- @Resource
- private TWxUserMapper tWxUserMapper;
- @Resource
- private MaTeProjectMapper maTeProjectMapper;
- @Resource
- private MaProjectMapper maProjectMapper;
- @Resource
- private ProjectMapper projectMapper;
- @Resource
- private ContractRecordMapper contractRecordMapper;
- @Resource
- private MerchantDailyAttendanceMapper merchantDailyAttendanceMapper;
- @Resource
- private AttendanceRuleMapper attendanceRuleMapper;
- @Resource
- private TAddressMapper addressMapper;
- @Resource
- private MerchantApplyFileMapper merchantApplyFileMapper;
- @Resource
- private TOrderMapper orderMapper;
- @Resource
- private CityOperationApplicationMapper cityOperationApplicationMapper;
- @Resource
- private IMaProjectFareSettingService maProjectFareSettingService;
- @Resource
- private TAddressService addressService;
- @Resource
- private CollectService collectService;
- /**
- * 商户入驻申请注册
- *
- * @param req 申请参数
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void apply(MaTechnicianAppAddVo req) {
- String phone = req.getTePhone();
- //商户入住前置条件校验
- getMaTechnician(req, phone);
- MaTechnician maTechnician = new MaTechnician();
- BeanUtils.copyProperties(req, maTechnician);
- //通过openid校验商户是否存在
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getCOpenid, req.getCOpenid());
- MaTechnician maTechnician1 = maTechnicianMapper.selectOne(queryWrapper);
- if (maTechnician1 == null) {
- throw new RuntimeException("商户不存在");
- }
- //添加城市管理地址
- insertCity(req, maTechnician1, maTechnician);
- }
- /**
- * 添加城市管理地址
- *
- * @param req
- * @param maTechnician1
- * @param maTechnician
- */
- private void insertCity(MaTechnicianAppAddVo req, MaTechnician maTechnician1, MaTechnician maTechnician) {
- //商户类型默认为真实商户
- maTechnician.setTechType(0);
- maTechnician.setCreateBy("admin");
- // 审核状态:待入驻
- maTechnician.setAuditStatus(AUDIT_WAIT_ENTER);
- maTechnicianMapper.insert(maTechnician);
- TWxUser wxUser = new TWxUser();
- // 初始化加密工具
- BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
- //密码默认123456
- wxUser.setCPassword(encoder.encode(PASSWORD));
- wxUser.setRole(1);
- LambdaUpdateWrapper<TWxUser> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(TWxUser::getcOpenid, req.getCOpenid());
- tWxUserMapper.update(wxUser, updateWrapper);
- /*LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(MaTechnician::getId, maTechnician1.getId());
- maTechnicianMapper.update(maTechnician, updateWrapper);*/
- CityOperationApplication cityOperationApplication = new CityOperationApplication();
- cityOperationApplication.setMerchantId(maTechnician1.getId());
- cityOperationApplication.setProvinceCode(req.getProvinceCode());
- cityOperationApplication.setProvinceName(req.getProvinceName());
- cityOperationApplication.setCityCode(req.getCityCode());
- cityOperationApplication.setCityName(req.getCityName());
- cityOperationApplication.setOperationCenterId(req.getOperationCenterId());
- cityOperationApplication.setOperationCenterName(req.getOperationCenterName());
- cityOperationApplication.setCreateBy(maTechnician1.getId().toString());
- cityOperationApplication.setCreateTime(LocalDateTime.now());
- cityOperationApplicationMapper.insert(cityOperationApplication);
- }
- /**
- * 商户申请入驻
- *
- * @param req
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void applyFile(MerchantApplyFileRequestDto req) {
- if (req == null) {
- throw new ServiceException("上传参数不能为空");
- }
- Integer merchantId = resolveMerchantId(req.getTechnician());
- List<MerchantApplyFileDto> files = resolveApplyFiles(req.getReq());
- if (CollectionUtils.isEmpty(files)) {
- throw new ServiceException("请上传申请入驻文件");
- }
- replaceApplyFiles(merchantId, files);
- updateTechnicianBaseInfo(req.getTechnician());
- }
- /**
- * 将文件分组格式转换为单文件记录。
- *
- * @param reqFiles 入驻资料文件
- * @return List<MerchantApplyFileDto> 转换后的文件记录
- */
- private List<MerchantApplyFileDto> resolveApplyFiles(List<MerchantApplyFileDto> reqFiles) {
- if (CollectionUtils.isEmpty(reqFiles)) {
- return Collections.emptyList();
- }
- List<MerchantApplyFileDto> files = new ArrayList<>();
- for (MerchantApplyFileDto item : reqFiles) {
- if (item == null) {
- throw new ServiceException("入驻资料文件不能为空");
- }
- checkApplyFileGroupParam(item);
- for (MerchantApplyFileDto child : item.getFiles()) {
- files.add(buildApplyFileFromGroup(item, child));
- }
- }
- return files;
- }
- /**
- * 校验文件组参数是否符合要求。
- *
- * @param group
- */
- private void checkApplyFileGroupParam(MerchantApplyFileDto group) {
- if (StringUtils.isBlank(group.getFileType())) {
- throw new ServiceException("文件类型不能为空");
- }
- if (CollectionUtils.isEmpty(group.getFiles())) {
- throw new ServiceException("文件列表不能为空");
- }
- }
- private MerchantApplyFileDto buildApplyFileFromGroup(MerchantApplyFileDto group, MerchantApplyFileDto child) {
- if (child == null) {
- throw new ServiceException("入驻资料文件不能为空");
- }
- MerchantApplyFileDto file = new MerchantApplyFileDto();
- BeanUtils.copyProperties(child, file);
- file.setFiles(null);
- if (StringUtils.isBlank(file.getFileType())) {
- file.setFileType(group.getFileType());
- } else if (!group.getFileType().equals(file.getFileType())) {
- throw new ServiceException("同一组文件类型必须一致");
- }
- checkApplyFileParam(file);
- return file;
- }
- /**
- * 按本次提交的文件类型整组替换旧文件。
- *
- * @param merchantId 商户ID
- * @param files 入驻资料文件
- */
- private void replaceApplyFiles(Integer merchantId, List<MerchantApplyFileDto> files) {
- Map<String, List<MerchantApplyFileDto>> filesByType = files.stream()
- .collect(Collectors.groupingBy(MerchantApplyFileDto::getFileType, LinkedHashMap::new, Collectors.toList()));
- for (Map.Entry<String, List<MerchantApplyFileDto>> entry : filesByType.entrySet()) {
- LambdaQueryWrapper<MerchantApplyFile> deleteWrapper = new LambdaQueryWrapper<>();
- deleteWrapper.eq(MerchantApplyFile::getMerchantId, merchantId).eq(MerchantApplyFile::getFileType, entry.getKey());
- merchantApplyFileMapper.delete(deleteWrapper);
- for (MerchantApplyFileDto file : entry.getValue()) {
- MerchantApplyFile applyFile = new MerchantApplyFile();
- BeanUtils.copyProperties(file, applyFile);
- applyFile.setMerchantId(merchantId);
- applyFile.setCreateBy(merchantId.toString());
- applyFile.setUpdateBy(merchantId.toString());
- applyFile.setIsDelete(NOT_DELETED);
- merchantApplyFileMapper.insert(applyFile);
- }
- }
- }
- /**
- * 修改商户资料。
- * <p>
- * 基础信息只允许修改昵称和简介;入驻资料文件按本次提交的文件类型整组替换。
- * </p>
- *
- * @param req 修改参数
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void updateTechnician(MerchantApplyFileRequestDto req) {
- if (req == null) {
- throw new ServiceException("修改参数不能为空");
- }
- MaTechnician technician = req.getTechnician();
- MerchantProfileSubmitDTO submitDTO = new MerchantProfileSubmitDTO();
- submitDTO.setMerchantId(resolveMerchantId(technician));
- if (technician != null) {
- submitDTO.setNickName(technician.getTeNickName());
- submitDTO.setBrief(technician.getTeBrief());
- }
- // 处理入驻资料文件
- submitDTO.setFiles(req.getReq());
- submitMerchantProfile(submitDTO);
- }
- @Override
- public MerchantProfileVO getMerchantProfile(String openid) {
- MaTechnician merchant = getExistingMerchant(openid);
- List<MerchantApplyFile> files = listMerchantApplyFiles(merchant.getId());
- MerchantProfileVO profile = new MerchantProfileVO();
- profile.setMerchantId(merchant.getId());
- profile.setName(merchant.getTeName());
- profile.setSex(merchant.getTeSex());
- profile.setPhone(merchant.getTePhone());
- profile.setAddress(merchant.getTeAddress());
- profile.setAreaCode(merchant.getTeAreaCode());
- profile.setAvatar(merchant.getAvatar());
- profile.setServiceTag(merchant.getServiceTag());
- profile.setAuditStatus(merchant.getAuditStatus());
- LambdaQueryWrapper<CityOperationApplication> query1 = new LambdaQueryWrapper<>();
- query1.eq(CityOperationApplication::getMerchantId, merchant.getId());
- //query1.eq(CityOperationApplication::getStatus,1);
- query1.orderByDesc(CityOperationApplication::getCreateTime).last("limit 1");
- CityOperationApplication application = cityOperationApplicationMapper.selectOne(query1);
- profile.setProvinceCode(application.getProvinceCode());
- profile.setProvinceName(application.getProvinceName());
- profile.setCityCode(application.getCityCode());
- profile.setCityName(application.getCityName());
- profile.setOperationCenterId(application.getOperationCenterId());
- profile.setOperationCenterName(application.getOperationCenterName());
- profile.setNickName(buildTextItem(merchant.getTeNickName(), merchant.getPendingTeNickName(),
- merchant.getTeNickNameAuditStatus(), merchant.getTeNickNameAuditRemark()));
- profile.setBrief(buildTextItem(merchant.getTeBrief(), merchant.getPendingTeBrief(),
- merchant.getTeBriefAuditStatus(), merchant.getTeBriefAuditRemark()));
- profile.setFileGroups(buildFileGroups(files));
- return profile;
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public void submitMerchantProfile(MerchantProfileSubmitDTO dto) {
- if (dto == null) {
- throw new ServiceException("修改参数不能为空");
- }
- checkProfileSubmitParam(dto);
- MaTechnician merchant = getExistingMerchant1(dto.getMerchantId());
- boolean changed = submitProfileTextFields(merchant, dto);
- List<MerchantApplyFileDto> files = resolveApplyFiles(dto.getFiles());
- if (!CollectionUtils.isEmpty(files)) {
- submitProfileFiles(merchant.getId(), files);
- changed = true;
- }
- if (!changed) {
- throw new ServiceException("请至少提交一项资料修改");
- }
- }
- private void checkProfileSubmitParam(MerchantProfileSubmitDTO dto) {
- if (dto.getNickName() != null) {
- checkProfileTextValue(dto.getNickName(), "昵称");
- }
- if (dto.getBrief() != null) {
- checkProfileTextValue(dto.getBrief(), "简介");
- }
- resolveApplyFiles(dto.getFiles());
- }
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int auditMerchantProfile(Integer merchantId, MerchantProfileAuditDTO dto, LoginUser loginUser) {
- // 检查merchantId是否为空
- if (merchantId == null) {
- throw new ServiceException("商户ID不能为空");
- }
- // 检查dto参数是否为空
- if (dto == null) {
- throw new ServiceException("审核参数不能为空");
- }
- // 检查商户是否存在
- MaTechnician merchant = getExistingMerchant1(merchantId);
- if (merchant == null) {
- throw new ServiceException("商户不存在");
- }
- if ((AUDIT_APPROVED == dto.getAuditStatus() || AUDIT_REJECTED == dto.getAuditStatus())) {
- String profileAuditRemark = dto.getAuditRemark() == null ? "" : dto.getAuditRemark().trim();
- if (AUDIT_REJECTED == dto.getAuditStatus() && StringUtils.isBlank(profileAuditRemark)) {
- throw new ServiceException("审核驳回时审核备注不能为空");
- }
- if (AUDIT_APPROVED == dto.getAuditStatus()) {
- checkProfileAuditExpirationDates(dto);
- // 审核通过所有待审核资料
- return approveAllPendingProfile(merchant, dto, profileAuditRemark, loginUser);
- }
- // 审核驳回所有待审核资料
- return rejectAllPendingProfile(merchant, profileAuditRemark, loginUser);
- }
- return 0;
- }
- /**
- * 检查审核通过时,是否填写了身份证到期日期、健康证到期日期、从业资格证到期日期
- * @param dto
- */
- private void checkProfileAuditExpirationDates(MerchantProfileAuditDTO dto) {
- if (dto.getIdCardExpirationDate() == null
- || dto.getHealthCertificateExpirationDate() == null
- || dto.getQualificationCertificateExpirationDate() == null) {
- throw new ServiceException("审核通过时,身份证到期日期、健康证到期日期、从业资格证到期日期不能为空");
- }
- }
- /**
- * 审核通过所有待审核资料
- *
- * @param merchant
- * @param dto
- * @param auditRemark
- * @param loginUser
- * @return int
- */
- private int approveAllPendingProfile(MaTechnician merchant, MerchantProfileAuditDTO dto, String auditRemark, LoginUser loginUser) {
- List<MerchantApplyFile> pendingFiles = listPendingProfileFiles(merchant.getId());
- boolean hasPendingText = hasPendingProfileText(merchant);
- if (!hasPendingText && CollectionUtils.isEmpty(pendingFiles)) {
- throw new ServiceException("当前商户没有待审核资料");
- }
- int rows = approveProfileTechnicianInfo(merchant, dto, auditRemark, loginUser);
- if (!CollectionUtils.isEmpty(pendingFiles)) {
- rows += approvePendingProfileFiles(merchant.getId(), pendingFiles, auditRemark, loginUser);
- }
- //同时修改ma_technician表的审核状态
- LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<MaTechnician>();
- updateWrapper.eq(MaTechnician::getId, merchant.getId()).set(MaTechnician::getAuditStatus, dto.getAuditStatus());
- rows += maTechnicianMapper.update(null, updateWrapper);
- return rows;
- }
- /**
- * 审核驳回所有待审核资料
- *
- * @param merchant
- * @param auditRemark
- * @param loginUser
- * @return int
- */
- private int rejectAllPendingProfile(MaTechnician merchant, String auditRemark, LoginUser loginUser) {
- List<MerchantApplyFile> pendingFiles = listPendingProfileFiles(merchant.getId());
- boolean hasPendingText = hasPendingProfileText(merchant);
- if (!hasPendingText && CollectionUtils.isEmpty(pendingFiles)) {
- throw new ServiceException("当前商户没有待审核资料");
- }
- int rows = 0;
- if (hasPendingText) {
- rows += rejectProfileTextInfo(merchant, auditRemark, loginUser);
- }
- if (!CollectionUtils.isEmpty(pendingFiles)) {
- rows += rejectPendingProfileFiles(merchant.getId(), auditRemark, loginUser);
- }
- //同时修改ma_technician表的审核状态
- LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<MaTechnician>();
- updateWrapper.eq(MaTechnician::getId, merchant.getId()).set(MaTechnician::getAuditStatus, AUDIT_REJECTED);
- rows += maTechnicianMapper.update(null, updateWrapper);
- return rows;
- }
- /**
- * 检查商户是否有待审核资料(昵称或简介)
- *
- * @param merchant
- * @return boolean
- */
- private boolean hasPendingProfileText(MaTechnician merchant) {
- return Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeNickNameAuditStatus())
- || Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeBriefAuditStatus());
- }
- /**
- * 获取待审核的申请入驻文件资料
- *
- * @param merchantId
- * @return List<MerchantApplyFile>
- */
- private List<MerchantApplyFile> listPendingProfileFiles(Integer merchantId) {
- LambdaQueryWrapper<MerchantApplyFile> queryWrapper = Wrappers.lambdaQuery();
- queryWrapper.eq(MerchantApplyFile::getMerchantId, merchantId).eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_PENDING);
- return merchantApplyFileMapper.selectList(queryWrapper);
- }
- /**
- * 审核通过所有待审核资料(昵称或简介)
- *
- * @param merchant
- * @param dto
- * @param auditRemark
- * @param loginUser
- * @return int
- */
- private int approveProfileTechnicianInfo(MaTechnician merchant, MerchantProfileAuditDTO dto, String auditRemark, LoginUser loginUser) {
- LambdaUpdateWrapper<MaTechnician> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MaTechnician::getId, merchant.getId())
- .set(MaTechnician::getIdCardExpirationDate, dto.getIdCardExpirationDate())
- .set(MaTechnician::getHealthCertificateExpirationDate, dto.getHealthCertificateExpirationDate())
- .set(MaTechnician::getQualificationCertificateExpirationDate, dto.getQualificationCertificateExpirationDate())
- .set(MaTechnician::getUpdateBy, getAuditUserName(loginUser))
- .set(MaTechnician::getUpdateTime, DateUtils.getNowDate());
- // 审核通过昵称
- if (Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeNickNameAuditStatus())) {
- updateWrapper.set(MaTechnician::getTeNickName, merchant.getPendingTeNickName())
- .set(MaTechnician::getPendingTeNickName, null)
- .set(MaTechnician::getTeNickNameAuditStatus, PROFILE_AUDIT_APPROVED)
- .set(MaTechnician::getTeNickNameAuditRemark, auditRemark);
- }
- // 审核通过简介
- if (Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeBriefAuditStatus())) {
- updateWrapper.set(MaTechnician::getTeBrief, merchant.getPendingTeBrief())
- .set(MaTechnician::getPendingTeBrief, null)
- .set(MaTechnician::getTeBriefAuditStatus, PROFILE_AUDIT_APPROVED)
- .set(MaTechnician::getTeBriefAuditRemark, auditRemark);
- }
- return maTechnicianMapper.update(null, updateWrapper);
- }
- private int rejectProfileTextInfo(MaTechnician merchant, String auditRemark, LoginUser loginUser) {
- LambdaUpdateWrapper<MaTechnician> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MaTechnician::getId, merchant.getId())
- .set(MaTechnician::getUpdateBy, getAuditUserName(loginUser))
- .set(MaTechnician::getUpdateTime, DateUtils.getNowDate());
- if (Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeNickNameAuditStatus())) {
- updateWrapper.set(MaTechnician::getTeNickNameAuditStatus, PROFILE_AUDIT_REJECTED)
- .set(MaTechnician::getTeNickNameAuditRemark, auditRemark);
- }
- if (Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeBriefAuditStatus())) {
- updateWrapper.set(MaTechnician::getTeBriefAuditStatus, PROFILE_AUDIT_REJECTED)
- .set(MaTechnician::getTeBriefAuditRemark, auditRemark);
- }
- return maTechnicianMapper.update(null, updateWrapper);
- }
- /**
- * 审核通过所有待审核文件资料
- *
- * @param merchantId
- * @param pendingFiles
- * @param auditRemark
- * @param loginUser
- * @return int
- */
- private int approvePendingProfileFiles(Integer merchantId, List<MerchantApplyFile> pendingFiles, String auditRemark, LoginUser loginUser) {
- Set<String> fileTypes = pendingFiles.stream()
- .map(MerchantApplyFile::getFileType)
- .filter(StringUtils::isNotBlank)
- .collect(Collectors.toCollection(LinkedHashSet::new));
- if (fileTypes.isEmpty()) {
- return 0;
- }
- String updateBy = getAuditUserName(loginUser);
- LambdaUpdateWrapper<MerchantApplyFile> deleteOldWrapper = Wrappers.lambdaUpdate();
- deleteOldWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .in(MerchantApplyFile::getFileType, fileTypes)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_APPROVED)
- .set(MerchantApplyFile::getIsDelete, 1)
- .set(MerchantApplyFile::getUpdateBy, updateBy)
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- int rows = merchantApplyFileMapper.update(null, deleteOldWrapper);
- LambdaUpdateWrapper<MerchantApplyFile> auditWrapper = Wrappers.lambdaUpdate();
- auditWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_PENDING)
- .set(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_APPROVED)
- .set(MerchantApplyFile::getAuditRemark, auditRemark)
- .set(MerchantApplyFile::getUpdateBy, updateBy)
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- return rows + merchantApplyFileMapper.update(null, auditWrapper);
- }
- private int rejectPendingProfileFiles(Integer merchantId, String auditRemark, LoginUser loginUser) {
- LambdaUpdateWrapper<MerchantApplyFile> auditWrapper = Wrappers.lambdaUpdate();
- auditWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_PENDING)
- .set(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_REJECTED)
- .set(MerchantApplyFile::getAuditRemark, auditRemark)
- .set(MerchantApplyFile::getUpdateBy, getAuditUserName(loginUser))
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- return merchantApplyFileMapper.update(null, auditWrapper);
- }
- /**
- * 获取存在的商户信息
- *
- * @param merchantId
- * @return MaTechnician
- */
- private MaTechnician getExistingMerchant(String openid) {
- MaTechnician merchant = maTechnicianMapper.selectOne(Wrappers.lambdaQuery(MaTechnician.class)
- .eq(MaTechnician::getCOpenid, openid));
- if (merchant == null || (merchant.getIsDelete() != null && !NOT_DELETED.equals(merchant.getIsDelete()))) {
- throw new ServiceException("商户不存在或已删除");
- }
- return merchant;
- }
- /**
- *
- * @param merchantId
- * @return
- */
- private MaTechnician getExistingMerchant1(Integer merchantId) {
- MaTechnician merchant = maTechnicianMapper.selectById(merchantId);
- if (merchant == null || (merchant.getIsDelete() != null && !NOT_DELETED.equals(merchant.getIsDelete()))) {
- throw new ServiceException("商户不存在或已删除");
- }
- return merchant;
- }
- /**
- * 提交文本资料
- *
- * @param merchant
- * @param dto
- * @return boolean
- */
- private boolean submitProfileTextFields(MaTechnician merchant, MerchantProfileSubmitDTO dto) {
- boolean changed = false;
- LambdaUpdateWrapper<MaTechnician> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MaTechnician::getId, merchant.getId());
- // 处理昵称
- if (dto.getNickName() != null) {
- String nickName = checkProfileTextValue(dto.getNickName(), "昵称");
- if (PROFILE_AUDIT_PENDING == valueOrApproved(merchant.getTeNickNameAuditStatus())) {
- throw new ServiceException("该资料正在审核中,请勿重复提交");
- }
- if (!nickName.equals(merchant.getTeNickName()) || PROFILE_AUDIT_REJECTED == valueOrApproved(merchant.getTeNickNameAuditStatus())) {
- updateWrapper.set(MaTechnician::getPendingTeNickName, nickName)
- .set(MaTechnician::getTeNickNameAuditStatus, PROFILE_AUDIT_PENDING)
- .set(MaTechnician::getTeNickNameAuditRemark, null);
- changed = true;
- }
- }
- // 处理简介
- if (dto.getBrief() != null) {
- String brief = checkProfileTextValue(dto.getBrief(), "简介");
- if (PROFILE_AUDIT_PENDING == valueOrApproved(merchant.getTeBriefAuditStatus())) {
- throw new ServiceException("该资料正在审核中,请勿重复提交");
- }
- if (!brief.equals(merchant.getTeBrief()) || PROFILE_AUDIT_REJECTED == valueOrApproved(merchant.getTeBriefAuditStatus())) {
- updateWrapper.set(MaTechnician::getPendingTeBrief, brief)
- .set(MaTechnician::getTeBriefAuditStatus, PROFILE_AUDIT_PENDING)
- .set(MaTechnician::getTeBriefAuditRemark, null);
- changed = true;
- }
- }
- if (changed) {
- updateWrapper.set(MaTechnician::getUpdateTime, DateUtils.getNowDate());
- // 同时修改audit_status字段的值
- updateWrapper.set(MaTechnician::getAuditStatus, 1);
- int rows = maTechnicianMapper.update(null, updateWrapper);
- if (rows <= 0) {
- throw new ServiceException("提交商户资料审核失败");
- }
- }
- return changed;
- }
- /**
- * 检查文本资料是否为空
- *
- * @param value
- * @param fieldName
- * @return String
- */
- private String checkProfileTextValue(String value, String fieldName) {
- if (StringUtils.isBlank(value)) {
- throw new ServiceException(fieldName + "不能为空");
- }
- return value.trim();
- }
- private int valueOrApproved(Integer status) {
- return status == null ? PROFILE_AUDIT_APPROVED : status;
- }
- private void submitProfileFiles(Integer merchantId, List<MerchantApplyFileDto> files) {
- Map<String, List<MerchantApplyFileDto>> filesByType = files.stream()
- .collect(Collectors.groupingBy(MerchantApplyFileDto::getFileType, LinkedHashMap::new, Collectors.toList()));
- for (Map.Entry<String, List<MerchantApplyFileDto>> entry : filesByType.entrySet()) {
- String fileType = entry.getKey();
- checkProfileFileType(fileType);
- if (hasPendingProfileFile(merchantId, fileType)) {
- throw new ServiceException("该资料正在审核中,请勿重复提交");
- }
- deleteRejectedProfileFiles(merchantId, fileType);
- String batchNo = UUID.randomUUID().toString().replace("-", "");
- for (MerchantApplyFileDto file : entry.getValue()) {
- MerchantApplyFile applyFile = new MerchantApplyFile();
- BeanUtils.copyProperties(file, applyFile);
- applyFile.setMerchantId(merchantId);
- applyFile.setApplyBatchNo(batchNo);
- applyFile.setAuditStatus(PROFILE_AUDIT_PENDING);
- applyFile.setAuditRemark(null);
- applyFile.setCreateBy(merchantId.toString());
- applyFile.setUpdateBy(merchantId.toString());
- applyFile.setIsDelete(NOT_DELETED);
- merchantApplyFileMapper.insert(applyFile);
- }
- }
- }
- private void checkProfileFileType(String fileType) {
- if (!PROFILE_FILE_TYPES.contains(fileType)) {
- throw new ServiceException("资料文件类型不支持修改");
- }
- }
- private boolean hasPendingProfileFile(Integer merchantId, String fileType) {
- LambdaQueryWrapper<MerchantApplyFile> queryWrapper = Wrappers.lambdaQuery();
- queryWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getFileType, fileType)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_PENDING);
- return merchantApplyFileMapper.selectCount(queryWrapper) > 0;
- }
- private void deleteRejectedProfileFiles(Integer merchantId, String fileType) {
- LambdaUpdateWrapper<MerchantApplyFile> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getFileType, fileType)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_REJECTED)
- .set(MerchantApplyFile::getIsDelete, 1)
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- merchantApplyFileMapper.update(null, updateWrapper);
- }
- private int auditProfileNickName(Integer merchantId, Integer auditStatus, String auditRemark, LoginUser loginUser) {
- MaTechnician merchant = getExistingMerchant1(merchantId);
- if (!Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeNickNameAuditStatus())) {
- throw new ServiceException("昵称资料不是审核中状态");
- }
- LambdaUpdateWrapper<MaTechnician> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MaTechnician::getId, merchantId)
- .set(MaTechnician::getTeNickNameAuditStatus, auditStatus)
- .set(MaTechnician::getTeNickNameAuditRemark, auditRemark)
- .set(MaTechnician::getUpdateBy, getAuditUserName(loginUser))
- .set(MaTechnician::getUpdateTime, DateUtils.getNowDate());
- if (PROFILE_AUDIT_APPROVED == auditStatus) {
- updateWrapper.set(MaTechnician::getTeNickName, merchant.getPendingTeNickName())
- .set(MaTechnician::getPendingTeNickName, null);
- }
- return maTechnicianMapper.update(null, updateWrapper);
- }
- private int auditProfileBrief(Integer merchantId, Integer auditStatus, String auditRemark, LoginUser loginUser) {
- MaTechnician merchant = getExistingMerchant1(merchantId);
- if (!Integer.valueOf(PROFILE_AUDIT_PENDING).equals(merchant.getTeBriefAuditStatus())) {
- throw new ServiceException("简介资料不是审核中状态");
- }
- LambdaUpdateWrapper<MaTechnician> updateWrapper = Wrappers.lambdaUpdate();
- updateWrapper.eq(MaTechnician::getId, merchantId)
- .set(MaTechnician::getTeBriefAuditStatus, auditStatus)
- .set(MaTechnician::getTeBriefAuditRemark, auditRemark)
- .set(MaTechnician::getUpdateBy, getAuditUserName(loginUser))
- .set(MaTechnician::getUpdateTime, DateUtils.getNowDate());
- if (PROFILE_AUDIT_APPROVED == auditStatus) {
- updateWrapper.set(MaTechnician::getTeBrief, merchant.getPendingTeBrief())
- .set(MaTechnician::getPendingTeBrief, null);
- }
- return maTechnicianMapper.update(null, updateWrapper);
- }
- private int auditProfileFile(Integer merchantId, String fileType, Integer auditStatus, String auditRemark, LoginUser loginUser) {
- if (StringUtils.isBlank(fileType)) {
- throw new ServiceException("文件类型不能为空");
- }
- checkProfileFileType(fileType);
- if (!hasPendingProfileFile(merchantId, fileType)) {
- throw new ServiceException("该文件资料不是审核中状态");
- }
- String updateBy = getAuditUserName(loginUser);
- if (PROFILE_AUDIT_APPROVED == auditStatus) {
- LambdaUpdateWrapper<MerchantApplyFile> deleteOldWrapper = Wrappers.lambdaUpdate();
- deleteOldWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getFileType, fileType)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_APPROVED)
- .set(MerchantApplyFile::getIsDelete, 1)
- .set(MerchantApplyFile::getUpdateBy, updateBy)
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- merchantApplyFileMapper.update(null, deleteOldWrapper);
- }
- LambdaUpdateWrapper<MerchantApplyFile> auditWrapper = Wrappers.lambdaUpdate();
- auditWrapper.eq(MerchantApplyFile::getMerchantId, merchantId)
- .eq(MerchantApplyFile::getFileType, fileType)
- .eq(MerchantApplyFile::getAuditStatus, PROFILE_AUDIT_PENDING)
- .set(MerchantApplyFile::getAuditStatus, auditStatus)
- .set(MerchantApplyFile::getAuditRemark, auditRemark)
- .set(MerchantApplyFile::getUpdateBy, updateBy)
- .set(MerchantApplyFile::getUpdateTime, LocalDateTime.now());
- return merchantApplyFileMapper.update(null, auditWrapper);
- }
- private String getAuditUserName(LoginUser loginUser) {
- if (loginUser != null && loginUser.getUser() != null) {
- return loginUser.getUser().getUserName();
- }
- return null;
- }
- private MerchantProfileTextItemVO buildTextItem(String value, String pendingValue, Integer auditStatus, String auditRemark) {
- MerchantProfileTextItemVO item = new MerchantProfileTextItemVO();
- item.setValue(value);
- item.setPendingValue(pendingValue);
- item.setAuditStatus(shouldShowAuditStatus(auditStatus) ? auditStatus : null);
- item.setAuditStatusText(shouldShowAuditStatus(auditStatus) ? getProfileAuditStatusText(auditStatus) : null);
- item.setAuditRemark(shouldShowAuditStatus(auditStatus) ? auditRemark : null);
- item.setEditable(!Integer.valueOf(PROFILE_AUDIT_PENDING).equals(auditStatus));
- return item;
- }
- private List<MerchantProfileFileGroupVO> buildFileGroups(List<MerchantApplyFile> files) {
- Map<String, List<MerchantApplyFile>> filesByType = CollectionUtils.isEmpty(files)
- ? Collections.emptyMap()
- : files.stream()
- .filter(Objects::nonNull)
- .filter(file -> PROFILE_FILE_TYPES.contains(file.getFileType()))
- .collect(Collectors.groupingBy(MerchantApplyFile::getFileType, LinkedHashMap::new, Collectors.toList()));
- List<MerchantProfileFileGroupVO> groups = new ArrayList<>();
- for (String fileType : PROFILE_FILE_TYPES) {
- List<MerchantApplyFile> typeFiles = filesByType.getOrDefault(fileType, Collections.emptyList());
- List<MerchantApplyFile> officialFiles = typeFiles.stream()
- .filter(file -> Integer.valueOf(PROFILE_AUDIT_APPROVED).equals(file.getAuditStatus()))
- .collect(Collectors.toList());
- List<MerchantApplyFile> pendingFiles = typeFiles.stream()
- .filter(file -> !Integer.valueOf(PROFILE_AUDIT_APPROVED).equals(file.getAuditStatus()))
- .collect(Collectors.toList());
- Integer auditStatus = resolveFileGroupAuditStatus(pendingFiles);
- MerchantProfileFileGroupVO group = new MerchantProfileFileGroupVO();
- group.setFileType(fileType);
- group.setFileTypeName(FileTypeEnum.getDescByCode(fileType));
- group.setOfficialFiles(toProfileFileVOList(officialFiles));
- group.setPendingFiles(toProfileFileVOList(pendingFiles));
- group.setAuditStatus(shouldShowAuditStatus(auditStatus) ? auditStatus : null);
- group.setAuditStatusText(shouldShowAuditStatus(auditStatus) ? getProfileAuditStatusText(auditStatus) : null);
- group.setAuditRemark(shouldShowAuditStatus(auditStatus) ? resolveFileGroupAuditRemark(pendingFiles) : null);
- group.setEditable(!Integer.valueOf(PROFILE_AUDIT_PENDING).equals(auditStatus));
- groups.add(group);
- }
- return groups;
- }
- private Integer resolveFileGroupAuditStatus(List<MerchantApplyFile> pendingFiles) {
- if (CollectionUtils.isEmpty(pendingFiles)) {
- return null;
- }
- if (pendingFiles.stream().anyMatch(file -> Integer.valueOf(PROFILE_AUDIT_PENDING).equals(file.getAuditStatus()))) {
- return PROFILE_AUDIT_PENDING;
- }
- return pendingFiles.get(0).getAuditStatus();
- }
- private String resolveFileGroupAuditRemark(List<MerchantApplyFile> pendingFiles) {
- if (CollectionUtils.isEmpty(pendingFiles)) {
- return null;
- }
- return pendingFiles.stream()
- .map(MerchantApplyFile::getAuditRemark)
- .filter(StringUtils::isNotBlank)
- .findFirst()
- .orElse(null);
- }
- private List<MerchantProfileFileVO> toProfileFileVOList(List<MerchantApplyFile> files) {
- if (CollectionUtils.isEmpty(files)) {
- return Collections.emptyList();
- }
- return files.stream().map(this::toProfileFileVO).collect(Collectors.toList());
- }
- private MerchantProfileFileVO toProfileFileVO(MerchantApplyFile file) {
- MerchantProfileFileVO vo = new MerchantProfileFileVO();
- vo.setId(file.getId());
- vo.setFileName(file.getFileName());
- vo.setFileUrl(file.getFileUrl());
- vo.setFileSize(file.getFileSize());
- vo.setContentType(file.getContentType());
- vo.setApplyBatchNo(file.getApplyBatchNo());
- vo.setAuditStatus(file.getAuditStatus());
- vo.setAuditRemark(file.getAuditRemark());
- return vo;
- }
- private boolean shouldShowAuditStatus(Integer auditStatus) {
- return auditStatus != null && !Integer.valueOf(PROFILE_AUDIT_APPROVED).equals(auditStatus);
- }
- private String getProfileAuditStatusText(Integer auditStatus) {
- if (Integer.valueOf(PROFILE_AUDIT_PENDING).equals(auditStatus)) {
- return "审核中";
- }
- if (Integer.valueOf(PROFILE_AUDIT_REJECTED).equals(auditStatus)) {
- return "审核驳回";
- }
- return null;
- }
- /**
- * 修改商户基础信息,仅允许修改昵称和简介。
- *
- * @param technician 商户基础信息
- */
- private void updateTechnicianBaseInfo(MaTechnician technician) {
- Integer merchantId = technician.getId();
- if (merchantId == null) {
- throw new ServiceException("商户ID不能为空");
- }
- if (StringUtils.isBlank(technician.getTeNickName())) {
- throw new ServiceException("昵称不能为空");
- }
- if (StringUtils.isBlank(technician.getTeBrief())) {
- throw new ServiceException("简介不能为空");
- }
- LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(MaTechnician::getId, merchantId);
- updateWrapper.set(MaTechnician::getTeNickName, technician.getTeNickName().trim());
- updateWrapper.set(MaTechnician::getTeBrief, technician.getTeBrief().trim());
- // 审核状态默认设为1 待审核
- updateWrapper.set(MaTechnician::getAuditStatus, 1);
- int rows = maTechnicianMapper.update(null, updateWrapper);
- if (rows <= 0) {
- throw new ServiceException("修改商户基础信息失败");
- }
- }
- /**
- * 按本次提交的文件类型整组替换商户入驻资料文件。
- *
- * @param merchantId 商户ID
- * @param files 入驻资料文件
- */
- private void replaceApplyFilesBySubmittedTypes(Integer merchantId, List<MerchantApplyFileDto> files) {
- if (CollectionUtils.isEmpty(files)) {
- return;
- }
- replaceApplyFiles(merchantId, files);
- }
- /**
- * 从商户基础信息中解析商户ID。
- *
- * @param technician 商户基础信息
- * @return Integer 商户ID
- */
- private Integer resolveMerchantId(MaTechnician technician) {
- if (technician != null && technician.getId() != null) {
- return technician.getId();
- }
- throw new ServiceException("商户ID不能为空");
- }
- private void checkApplyFileParam(MerchantApplyFileDto file) {
- if (file == null) {
- throw new ServiceException("入驻资料文件不能为空");
- }
- if (StringUtils.isBlank(file.getFileType())) {
- throw new ServiceException("文件类型不能为空");
- }
- if (StringUtils.isBlank(file.getFileUrl())) {
- throw new ServiceException("文件访问地址不能为空");
- }
- }
- /**
- * 商户入住前置条件校验
- *
- * @param req
- * @param phone
- */
- private void getMaTechnician(MaTechnicianAppAddVo req, String phone) {
- // 1. 判断当前用户是否已入驻
- MaTechnician userProfile = getMaTechnician(req);
- if (userProfile != null) {
- throw new RuntimeException("当前用户已入驻,请勿重复提交");
- }
- // 2. 判断手机号是否已存在
- LambdaQueryWrapper<MaTechnician> queryPhoneWrapper = new LambdaQueryWrapper<>();
- queryPhoneWrapper.eq(MaTechnician::getTePhone, phone);
- MaTechnician maTechnicianPhone = maTechnicianMapper.selectOne(queryPhoneWrapper);
- if (maTechnicianPhone != null) {
- throw new RuntimeException("手机号已存在,请更换手机号");
- }
- //3、判断手机号是否已绑定其他用户
- LambdaQueryWrapper<MaTechnician> queryTePhoneWrapper = new LambdaQueryWrapper<>();
- queryTePhoneWrapper.eq(MaTechnician::getTePhone, phone);
- queryTePhoneWrapper.eq(MaTechnician::getAuditStatus, 2);
- MaTechnician maTechnicianTePhone = maTechnicianMapper.selectOne(queryTePhoneWrapper);
- if (maTechnicianTePhone != null) {
- throw new RuntimeException("手机号已被其他用户绑定,请更换手机号");
- }
- }
- /**
- * 判断当前用户是否已入驻
- *
- * @param req
- * @return MaTechnician
- */
- private MaTechnician getMaTechnician(MaTechnicianAppAddVo req) {
- LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaTechnician::getTePhone, req.getTePhone());
- queryWrapper.eq(MaTechnician::getAuditStatus, 2);
- queryWrapper.eq(MaTechnician::getServiceTag, req.getServiceTag());
- MaTechnician userProfile = maTechnicianMapper.selectOne(queryWrapper);
- return userProfile;
- }
- /**
- * 查询商户服务项目列表
- *
- * @param merchantId 商户id
- * @param auditStatus 审核状态
- * @return List<MaProject>
- */
- @Override
- public List<MaProject> selectMaTechnicianListBy(Integer merchantId, Integer auditStatus) {
- LambdaQueryWrapper<MaProject> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(MaProject::getMerchantId, merchantId);
- queryWrapper.eq(MaProject::getAuditStatus, auditStatus);
- List<MaProject> maProjects = maProjectMapper.selectList(queryWrapper);
- maProjects.forEach(maProject -> {
- //根据项目ID查询项目图片
- Integer projectId = maProject.getProjectId();
- Project project = projectMapper.selectById(projectId);
- maProject.setCover(project.getCover());
- maProject.setUnitType(project.getUnitType());
- });
- return maProjects;
- }
- /**
- * 查询服务分类项目列表
- *
- * @param typeId 技师类型
- * @return 技师列表
- */
- @Override
- public List<Project> selectTechnicianListBy(String typeId) {
- LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(Project::getType, typeId);
- return projectMapper.selectList(queryWrapper);
- }
- /**
- * 查询技师
- *
- * @param id 技师主键
- * @return 技师
- */
- @Override
- public MaTechnician selectMaTechnicianById(Long id) {
- return maTechnicianMapper.selectMaTechnicianById(id);
- }
- /**
- * 查询技师列表
- *
- * @param maTechnician 技师
- * @return 技师
- */
- @Override
- public List<MaTechnician> selectMaTechnicianList(MaTechnician maTechnician) {
- return maTechnicianMapper.selectMaTechnicianList(maTechnician);
- }
- /**
- * 新增技师
- *
- * @param maTechnicianAppAddVo 技师
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int insertMaTechnician(MaTechnicianAppAddVo maTechnicianAppAddVo) {
- MaTechnician maTechnician = new MaTechnician();
- BeanUtils.copyProperties(maTechnicianAppAddVo, maTechnician);
- int rows = maTechnicianMapper.insertMaTechnician(maTechnician);
- if (maTechnicianAppAddVo.getProjectIds() != null && !maTechnicianAppAddVo.getProjectIds().isEmpty()) {
- insertProjectRelations(maTechnician.getId(), new LinkedHashSet<>(maTechnicianAppAddVo.getProjectIds()));
- }
- return rows;
- }
- /**
- * 后台新增商户
- *
- * @param dto 新增商户参数
- * @param loginUser 当前登录用户
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int insertMerchant(MaTechnicianMerchantAddDTO dto, LoginUser loginUser) {
- MerchantProjectSelection selection = checkMerchantAddParam(dto);
- String userName = loginUser.getUser().getUserName();
- MaTechnician maTechnician = new MaTechnician();
- maTechnician.setTeName(dto.getTeName().trim());
- maTechnician.setTeNickName(dto.getTeNickName().trim());
- maTechnician.setTeSex(dto.getTeSex());
- maTechnician.setTePhone(dto.getTePhone().trim());
- maTechnician.setOpenService(joinIds(selection.getCategoryIds()));
- maTechnician.setTeProject(joinProjectTitles(selection.getProjectIds(), selection.getProjectMap()));
- maTechnician.setTechType(dto.getTechType());
- maTechnician.setIsRecommend(normalizeSwitchValue(dto.getIsRecommend(), "是否推荐"));
- maTechnician.setServiceState(SERVICE_STATE_AVAILABLE);
- maTechnician.setPostState(POST_STATE_OFFLINE);
- maTechnician.setTeIsEnable(ENABLED);
- //上岗状态:默认-1 未上岗
- maTechnician.setNStatus2(NS_STATUS_NOT_ON_DUTY);
- maTechnician.setMerchantStatus(MERCHANT_STATUS_NORMAL);
- //审核状态
- maTechnician.setAuditStatus(AUDIT_APPROVED);
- maTechnician.setTeAddress("");
- maTechnician.setNStar(DEFAULT_STAT_VALUE);
- maTechnician.setNNum(DEFAULT_STAT_VALUE);
- maTechnician.setCreateBy(userName);
- maTechnician.setUpdateBy(userName);
- maTechnician.setCreateTime(DateUtils.getNowDate());
- maTechnician.setUpdateTime(DateUtils.getNowDate());
- int rows = maTechnicianMapper.insert(maTechnician);
- if (rows <= 0) {
- throw new ServiceException("新增商户失败");
- }
- insertProjectRelations(maTechnician.getId(), selection.getProjectIds());
- return rows;
- }
- /**
- * 后台编辑商户
- *
- * @param id 商户ID
- * @param dto 编辑商户参数
- * @param loginUser 当前登录用户
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int updateMerchant(Integer id, MaTechnicianMerchantAddDTO dto, LoginUser loginUser) {
- if (id == null) {
- throw new ServiceException("商户ID不能为空");
- }
- MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id.intValue());
- if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
- throw new ServiceException("商户不存在或已删除");
- }
- MerchantProjectSelection selection = checkMerchantAddParam(dto);
- String userName = loginUser.getUser().getUserName();
- MaTechnician maTechnician = new MaTechnician();
- maTechnician.setId(id);
- maTechnician.setTeName(dto.getTeName().trim());
- maTechnician.setTeNickName(dto.getTeNickName().trim());
- maTechnician.setTeSex(dto.getTeSex());
- maTechnician.setTePhone(dto.getTePhone().trim());
- maTechnician.setOpenService(joinIds(selection.getCategoryIds()));
- maTechnician.setTeProject(joinProjectTitles(selection.getProjectIds(), selection.getProjectMap()));
- maTechnician.setTechType(dto.getTechType());
- maTechnician.setIsRecommend(normalizeSwitchValue(dto.getIsRecommend(), "是否推荐"));
- maTechnician.setUpdateBy(userName);
- maTechnician.setUpdateTime(DateUtils.getNowDate());
- int rows = maTechnicianMapper.updateMerchantById(maTechnician);
- if (rows <= 0) {
- throw new ServiceException("编辑商户失败");
- }
- replaceProjectRelations(id, selection.getProjectIds());
- return rows;
- }
- /**
- * 后台上传商户合同文件
- *
- * @param id 商户ID
- * @param
- * @param loginUser 当前登录用户
- * @return 上传结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Integer uploadMerchantContract(Integer id, Map<String, Object> map, LoginUser loginUser) {
- if (id == null) {
- throw new ServiceException("商户ID不能为空");
- }
- MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
- if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
- throw new ServiceException("商户不存在或已删除");
- }
- // 合同的名称
- String contractName = String.valueOf(map.get("contractName"));
- // 合同文件的URL
- String url = String.valueOf(map.get("url"));
- if (StringUtils.isBlank(url)) {
- throw new ServiceException("合同文件上传失败,未返回文件地址");
- }
- ContractRecord contractRecord = new ContractRecord();
- contractRecord.setMerchantId(id);
- contractRecord.setContractName(contractName);
- contractRecord.setFileUrl(url);
- contractRecord.setSignTime(DateUtils.getNowDate());
- contractRecord.setSignerName(existsMerchant.getTeName());
- contractRecord.setCreateTime(DateUtils.getNowDate());
- int rows = contractRecordMapper.insert(contractRecord);
- if (rows <= 0) {
- throw new ServiceException("保存合同记录失败");
- }
- return rows;
- }
- /**
- * 商户入驻审核。
- *
- * @param id 商户ID
- * @param dto 审核提交参数
- * @param loginUser 当前登录用户
- * @return int 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int submitMerchantAudit(Integer id, MaTechnicianAuditSubmitDTO dto, LoginUser loginUser) {
- if (id == null) {
- throw new ServiceException("商户ID不能为空");
- }
- if (dto == null) {
- throw new ServiceException("审核参数不能为空");
- }
- checkEnumValue(dto.getAuditStatus(), "审核意见", AUDIT_APPROVED, AUDIT_REJECTED);
- String auditRemark = dto.getAuditRemark() == null ? "" : dto.getAuditRemark().trim();
- if (dto.getAuditStatus() == AUDIT_REJECTED && StringUtils.isBlank(auditRemark)) {
- throw new ServiceException("审核驳回时审核备注不能为空");
- }
- if (auditRemark.length() > AUDIT_REMARK_MAX_LENGTH) {
- throw new ServiceException("审核备注长度不能超过" + AUDIT_REMARK_MAX_LENGTH + "个字符");
- }
- MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
- if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
- throw new ServiceException("商户不存在或已删除");
- }
- Integer currentAuditStatus = existsMerchant.getAuditStatus();
- if (currentAuditStatus == null || (currentAuditStatus != AUDIT_WAIT_ENTER)) {
- throw new ServiceException("当前商户待入驻已审核,不用重复审核");
- }
- MaTechnician maTechnician = new MaTechnician();
- maTechnician.setId(id);
- if (dto.getAuditStatus() == AUDIT_APPROVED) {
- maTechnician.setAuditStatus(1);
- } else {
- maTechnician.setAuditStatus(3);
- }
- maTechnician.setAuditRemark(auditRemark);
- maTechnician.setApproveTime(DateUtils.getNowDate());
- if (loginUser != null && loginUser.getUser() != null) {
- maTechnician.setUpdateBy(loginUser.getUser().getUserName());
- }
- maTechnician.setUpdateTime(DateUtils.getNowDate());
- int rows = maTechnicianMapper.submitMerchantAuditById(maTechnician);
- if (rows <= 0) {
- throw new ServiceException("商户待入驻审核失败");
- }
- return rows;
- }
- /**
- * 后台查询商户证照
- *
- * @param id 商户ID
- * @return MaTechnicianCertificateVO 商户证照
- */
- @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);
- MaTechnicianCertificateVO certificate = new MaTechnicianCertificateVO();
- certificate.setMerchantId(id);
- Map<String, List<String>> fileUrlsByType = CollectionUtils.isEmpty(merchantApplyFiles)
- ? Collections.emptyMap()
- : merchantApplyFiles.stream()
- .filter(Objects::nonNull)
- .filter(file -> StringUtils.isNotBlank(file.getFileType()) && StringUtils.isNotBlank(file.getFileUrl()))
- .collect(Collectors.groupingBy(MerchantApplyFile::getFileType,
- Collectors.mapping(MerchantApplyFile::getFileUrl, Collectors.toList())));
- certificate.setAvatar(getCertificateFileUrls(fileUrlsByType, PORTRAIT.getCode()));
- certificate.setLifePhotos(getCertificateFileUrls(fileUrlsByType, LIFE_PHOTO.getCode()));
- certificate.setPromotionVideo(getCertificateFileUrls(fileUrlsByType, PROMOTION_VIDEO.getCode()));
- certificate.setIdCardFrout(getCertificateFileUrls(fileUrlsByType, ID_CARD_FRONT.getCode()));
- certificate.setIdCardBack(getCertificateFileUrls(fileUrlsByType, ID_CARD_BACK.getCode()));
- certificate.setIdCardHandheld(getCertificateFileUrls(fileUrlsByType, ID_CARD_HANDHELD.getCode()));
- certificate.setHealthCertificate(getCertificateFileUrls(fileUrlsByType, HEALTH_CERT.getCode()));
- certificate.setQualificationCertificate(getCertificateFileUrls(fileUrlsByType, QUALIFICATION_CERT.getCode()));
- certificate.setNoCrimeRecord(getCertificateFileUrls(fileUrlsByType, NO_CRIME_RECORD.getCode()));
- certificate.setCommitmentPdf(getCertificateFileUrls(fileUrlsByType, COMMITMENT_LETTER.getCode()));
- certificate.setCommitmentAudio(getCertificateFileUrls(fileUrlsByType, COMMITMENT_AUDIO.getCode()));
- certificate.setCommitmentVideo(getCertificateFileUrls(fileUrlsByType, COMMITMENT_VIDEO.getCode()));
- return certificate;
- }
- /**
- * 获取指定证照类型的全部文件URL
- *
- * @param fileUrlsByType 文件类型与URL列表映射
- * @param type 文件类型
- * @return List<String> 文件URL列表
- */
- private List<String> getCertificateFileUrls(Map<String, List<String>> fileUrlsByType, String type) {
- return fileUrlsByType.getOrDefault(type, Collections.emptyList());
- }
- /**
- * 全量替换商户与服务项目关联关系。
- *
- * @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);
- }
- /**
- * 后台查询商户列表
- *
- * @param page 分页参数
- * @param dto 查询条件
- * @return 商户分页列表
- */
- @Override
- public Page<MaTechnicianMerchantListVO> selectMerchantList(Page<MaTechnicianMerchantListVO> page,
- MaTechnicianMerchantQueryDTO dto) {
- Page<MaTechnicianMerchantListVO> pageParam = page == null ? new Page<>(1, 10) : page;
- return maTechnicianMapper.selectMerchantList(pageParam, dto);
- }
- /**
- * 后台查询商户详情
- *
- * @param id 商户ID
- * @return 商户详情
- */
- @Override
- public MaTechnicianMerchantDetailVO selectMerchantDetail(Long id) {
- if (id == null) {
- throw new ServiceException("商户ID不能为空");
- }
- MaTechnicianMerchantDetailVO detail = maTechnicianMapper.selectMerchantDetailById(id);
- if (detail == null) {
- throw new ServiceException("商户不存在或已删除");
- }
- return detail;
- }
- /**
- * 修改技师
- *
- * @param maTechnicianAppAddVo
- * @return 结果
- */
- @Override
- public int updateMaTechnician(MaTechnicianAppAddVo maTechnicianAppAddVo) {
- MaTechnician maTechnician = new MaTechnician();
- BeanUtils.copyProperties(maTechnicianAppAddVo, maTechnician);
- return maTechnicianMapper.updateMaTechnician(maTechnician);
- }
- /**
- * 批量删除技师
- *
- * @param ids 需要删除的技师主键
- * @return 结果
- */
- @Override
- public int deleteMaTechnicianByIds(Long[] ids) {
- return maTechnicianMapper.deleteMaTechnicianByIds(ids);
- }
- /**
- * 删除技师信息
- *
- * @param id 技师主键
- * @return 结果
- */
- @Override
- public int deleteMaTechnicianById(Long id) {
- return maTechnicianMapper.deleteMaTechnicianById(id);
- }
- /**
- * 首页选中的城市是否有开通服务
- *
- * @param areaCode
- * @return
- */
- @Override
- public Boolean isHasMerchantCity(String areaCode) {
- return maTechnicianMapper.isHasMerchantCity(areaCode);
- }
- /**
- * 首页按摩推荐
- *
- * @param dto
- * @return
- */
- @Override
- public List<MerchantVo> getMerchantRecommend(MassageMerchantRecommendDto dto) {
- return maTechnicianMapper.getMerchantRecommend(dto);
- }
- private MerchantProjectSelection checkMerchantAddParam(MaTechnicianMerchantAddDTO dto) {
- if (dto == null) {
- throw new ServiceException("商户参数不能为空");
- }
- checkRequiredText(dto.getTeName(), "姓名", 10);
- checkRequiredText(dto.getTeNickName(), "昵称", 10);
- checkRequiredText(dto.getTePhone(), "电话", 11);
- checkEnumValue(dto.getTeSex(), "性别", 0, 1);
- Set<Integer> categoryIds = checkOpenServiceIds(dto.getOpenService());
- checkEnumValue(dto.getTechType(), "商户类型", 0, 1);
- if (dto.getIsRecommend() != null) {
- checkEnumValue(dto.getIsRecommend(), "是否推荐", 0, 1);
- }
- return checkProjectIds(dto.getProjectIds(), categoryIds);
- }
- private void checkRequiredText(String value, String fieldName, int maxLength) {
- if (StringUtils.isBlank(value)) {
- throw new ServiceException(fieldName + "不能为空");
- }
- if (value.trim().length() > maxLength) {
- throw new ServiceException(fieldName + "长度不能超过" + maxLength + "个字符");
- }
- }
- private void checkEnumValue(Integer value, String fieldName, int... allowedValues) {
- if (value == null) {
- throw new ServiceException(fieldName + "不能为空");
- }
- for (int allowedValue : allowedValues) {
- if (value == allowedValue) {
- return;
- }
- }
- throw new ServiceException(fieldName + "值不正确");
- }
- private Integer normalizeSwitchValue(Integer value, String fieldName) {
- if (value == null) {
- return 0;
- }
- checkEnumValue(value, fieldName, 0, 1);
- return value;
- }
- /**
- * 校验服务项目ID集合
- *
- * @param projectIds 服务项目ID集合
- * @param categoryIds 服务类目ID集合
- * @return 有效服务项目ID集合
- */
- private MerchantProjectSelection checkProjectIds(List<Integer> projectIds, Set<Integer> categoryIds) {
- if (projectIds == null || projectIds.isEmpty()) {
- throw new ServiceException("服务项目不能为空");
- }
- Set<Integer> distinctProjectIds = new LinkedHashSet<>();
- for (Integer projectId : projectIds) {
- if (projectId == null) {
- throw new ServiceException("服务项目ID不能为空");
- }
- distinctProjectIds.add(projectId);
- }
- List<Project> projects = projectMapper.selectList(new LambdaQueryWrapper<Project>()
- .in(Project::getId, distinctProjectIds)
- .eq(Project::getIsDelete, 0));
- if (projects.size() != distinctProjectIds.size()) {
- throw new ServiceException("服务项目不存在或已删除");
- }
- Map<Integer, Project> projectMap = projects.stream()
- .collect(Collectors.toMap(project -> project.getId(), Function.identity(), (left, right) -> left));
- Set<Integer> projectCategoryIds = new LinkedHashSet<>();
- for (Integer projectId : distinctProjectIds) {
- Project project = projectMap.get(projectId);
- if (project == null || project.getCategoryId() == null) {
- throw new ServiceException("服务项目类目不能为空");
- }
- if (!categoryIds.contains(project.getCategoryId())) {
- throw new ServiceException("服务项目不属于所选服务类目");
- }
- projectCategoryIds.add(project.getCategoryId());
- }
- if (!projectCategoryIds.containsAll(categoryIds)) {
- throw new ServiceException("每个服务类目至少选择一个服务项目");
- }
- return new MerchantProjectSelection(categoryIds, distinctProjectIds, projectMap);
- }
- /**
- * 校验服务类目ID集合
- *
- * @param openService 服务类目ID集合
- * @return 去重后的服务类目ID集合
- */
- private Set<Integer> checkOpenServiceIds(List<Integer> openService) {
- if (openService == null || openService.isEmpty()) {
- throw new ServiceException("服务类目不能为空");
- }
- Set<Integer> categoryIds = new LinkedHashSet<>();
- for (Integer categoryId : openService) {
- if (categoryId == null) {
- throw new ServiceException("服务类目ID不能为空");
- }
- categoryIds.add(categoryId);
- }
- return categoryIds;
- }
- private String joinIds(Set<Integer> ids) {
- return ids.stream()
- .map(String::valueOf)
- .collect(Collectors.joining(","));
- }
- private String joinProjectTitles(Set<Integer> projectIds, Map<Integer, Project> projectMap) {
- return projectIds.stream()
- .map(projectMap::get)
- .map(Project::getTitle)
- .filter(StringUtils::isNotBlank)
- .collect(Collectors.joining(","));
- }
- /**
- * 新增商户与服务项目关联关系
- *
- * @param technicianId
- * @param projectIds
- */
- private void insertProjectRelations(Integer technicianId, Set<Integer> projectIds) {
- if (technicianId == null) {
- throw new ServiceException("商户ID不能为空");
- }
- List<MaTeProject> relations = new ArrayList<>();
- for (Integer projectId : projectIds) {
- MaTeProject relation = new MaTeProject();
- relation.setTeId(technicianId);
- relation.setProjectId(projectId);
- relations.add(relation);
- }
- int rows = maTeProjectMapper.insertBatch(relations);
- if (rows != relations.size()) {
- throw new ServiceException("新增商户服务项目失败");
- }
- }
- private static class MerchantProjectSelection {
- private final Set<Integer> categoryIds;
- private final Set<Integer> projectIds;
- private final Map<Integer, Project> projectMap;
- private MerchantProjectSelection(Set<Integer> categoryIds, Set<Integer> projectIds, Map<Integer, Project> projectMap) {
- this.categoryIds = categoryIds;
- this.projectIds = projectIds;
- this.projectMap = projectMap;
- }
- private Set<Integer> getCategoryIds() {
- return categoryIds;
- }
- private Set<Integer> getProjectIds() {
- return projectIds;
- }
- private Map<Integer, Project> getProjectMap() {
- return projectMap;
- }
- }
- /**
- * 获取未申请技能列表
- *
- * @param merchantId
- * @param serviceTag
- * @return List<Project>
- */
- @Override
- public List<Project> getNotApplyList(Integer merchantId, Integer serviceTag) {
- LambdaQueryWrapper<MaProject> query = new LambdaQueryWrapper<>();
- query.eq(MaProject::getMerchantId, merchantId);
- query.eq(MaProject::getServiceTag, serviceTag);
- // 审核状态:审核通过
- query.eq(MaProject::getAuditStatus, 1);
- List<MaProject> maProjectList = maProjectMapper.selectList(query);
- // 获取已申请技能ID集合
- List<Integer> projectIdList = maProjectList.stream().map(MaProject::getProjectId).collect(Collectors.toList());
- if (projectIdList.size() == 0) {
- LambdaQueryWrapper<Project> query1 = new LambdaQueryWrapper<>();
- query1.eq(Project::getType, serviceTag);
- return projectMapper.selectList(query1);
- }
- LambdaQueryWrapper<Project> query2 = new LambdaQueryWrapper<>();
- query2.eq(Project::getType, serviceTag);
- query2.notIn(Project::getId, projectIdList);
- return projectMapper.selectList(query2);
- }
- /**
- * 申请开通新服务
- *
- * @param dto
- * @return
- */
- @Transactional(rollbackFor = Exception.class)
- public int applyForService(MaProjectSaveDto dto) {
- if (Objects.isNull(dto)) {
- return 0;
- }
- if (dto.getProjectIdList().size() > 0) {
- // 插入商户技能
- extracted(dto);
- } else {
- return 0;
- }
- return 1;
- }
- /**
- * 根据微信openid查询商户信息和入驻资料。
- *
- * @param openid 微信openid
- * @return MerchantAuditFile
- */
- @Override
- public MerchantAuditFile getTechnicianInfo(String openid) {
- if (StringUtils.isBlank(openid)) {
- throw new IllegalArgumentException("openid不能为空");
- }
- MaTechnician merchant = findMerchantByOpenid(openid);
- return buildMerchantAuditFile(merchant);
- }
- /**
- * 商户入驻信息
- *
- * @param userId 商户ID
- * @return MerchantAuditFile
- */
- @Override
- public MerchantAuditFile getTechnicianList(Integer userId) {
- if (userId == null) {
- throw new IllegalArgumentException("商户ID不能为空");
- }
- return buildMerchantAuditFile(findMerchantById(userId));
- }
- /**
- * 根据微信openid查询商户信息
- *
- * @param openid
- * @return MaTechnician
- */
- private MaTechnician findMerchantByOpenid(String openid) {
- LambdaQueryWrapper<MaTechnician> query = new LambdaQueryWrapper<>();
- query.eq(MaTechnician::getCOpenid, openid);
- MaTechnician merchant = maTechnicianMapper.selectOne(query);
- // 根据商户ID查询city_operation_application表
- if (merchant != null && merchant.getId() != null) {
- LambdaQueryWrapper<CityOperationApplication> query1 = new LambdaQueryWrapper<>();
- query1.eq(CityOperationApplication::getMerchantId, merchant.getId()).last("limit 1");
- CityOperationApplication application = cityOperationApplicationMapper.selectOne(query1);
- if (application != null) {
- merchant.setProvinceCode(application.getProvinceCode());
- merchant.setProvinceName(application.getProvinceName());
- merchant.setCityCode(application.getCityCode());
- merchant.setCityName(application.getCityName());
- merchant.setOperationCenterId(application.getOperationCenterId());
- merchant.setOperationCenterName(application.getOperationCenterName());
- }
- }
- return merchant;
- }
- private MaTechnician findMerchantById(Integer userId) {
- LambdaQueryWrapper<MaTechnician> query = new LambdaQueryWrapper<>();
- query.eq(MaTechnician::getId, userId);
- return maTechnicianMapper.selectOne(query);
- }
- private MerchantAuditFile buildMerchantAuditFile(MaTechnician merchant) {
- MerchantAuditFile merchantAuditFile = new MerchantAuditFile();
- merchantAuditFile.setMerchant(merchant);
- if (merchant != null && merchant.getId() != null) {
- merchantAuditFile.setMerchantAuditFile(listMerchantApplyFiles(merchant.getId()));
- } else {
- merchantAuditFile.setMerchantAuditFile(Collections.emptyList());
- }
- return merchantAuditFile;
- }
- private List<MerchantApplyFile> listMerchantApplyFiles(Integer userId) {
- LambdaQueryWrapper<MerchantApplyFile> query1 = new LambdaQueryWrapper<>();
- query1.eq(MerchantApplyFile::getMerchantId, userId);
- return merchantApplyFileMapper.selectList(query1);
- }
- /**
- * 查询商户合同记录信息
- *
- * @param userId
- * @return ContractRecordVO
- */
- @Override
- public ContractRecordVO getContractRecords(Long userId) {
- LambdaQueryWrapper<ContractRecord> query = new LambdaQueryWrapper<>();
- query.eq(ContractRecord::getMerchantId, userId);
- List<ContractRecord> contractRecordList = contractRecordMapper.selectList(query);
- ContractRecordVO result = new ContractRecordVO();
- if (CollectionUtils.isEmpty(contractRecordList)) {
- result.setMerchantId(userId == null ? null : userId.intValue());
- result.setFile(Collections.emptyList());
- return result;
- }
- Set<String> seen = new HashSet<>();
- contractRecordList = contractRecordList.stream()
- .filter(record -> record.getContractName() != null && seen.add(record.getContractName()))
- .collect(Collectors.toList());
- ContractRecord firstRecord = contractRecordList.get(0);
- result.setSignTime(firstRecord.getSignTime());
- result.setSignerName(firstRecord.getSignerName());
- result.setMerchantId(firstRecord.getMerchantId());
- result.setFile(contractRecordList.stream()
- .map(this::buildContractFileVO)
- .collect(Collectors.toList()));
- return result;
- }
- /**
- * 构建合同文件VO
- * @param record
- * @return ContractFileVO.Contract
- */
- private ContractRecordVO.ContractFileVO buildContractFileVO(ContractRecord record) {
- ContractRecordVO.ContractFileVO fileVO = new ContractRecordVO.ContractFileVO();
- fileVO.setId(record.getId());
- fileVO.setContractName(record.getContractName());
- // 获取当前项目的访问路径
- String contextPath = ServletUtils.getProjectAccessPath();
- String fileUrl = contextPath + record.getFileUrl();
- fileVO.setFileUrl(fileUrl);
- return fileVO;
- }
- @Override
- public Page<MerchantListVO> getMerchantPage(MerchantListDTO dto) {
- // 1. 执行分页查询 (不带免车费过滤)
- Page<MerchantListVO> page = new Page<>(dto.getCurrent(), dto.getSize());
- page = this.baseMapper.getMerchantPage(page, dto);
- List<MerchantListVO> records = page.getRecords();
- if (CollUtil.isEmpty(records)) {
- return page;
- }
- // 2. 如果用户勾选了“免车费”,则在内存中进行精准过滤
- if (Boolean.TRUE.equals(dto.getFreeCarFee())) {
- boolean isDay = this.maProjectFareSettingService.isDayTimePeriod(LocalDateTime.now());
- // 3. 过滤列表
- Iterator<MerchantListVO> iterator = records.iterator();
- while (iterator.hasNext()) {
- MerchantListVO vo = iterator.next();
- double currentDistance = vo.getDistance(); // 数据库算出的距离(km)
- // 获取该商户的有效免费里程
- BigDecimal freeKm = this.maProjectFareSettingService.getMerchantFreeKm(Long.parseLong(vo.getId()), vo.getProjectId(), isDay);
- // 核心判断:如果没配置(为0) 或者 距离超过了免费里程,则剔除
- if (freeKm == null || freeKm.doubleValue() <= 0 || currentDistance > freeKm.doubleValue()) {
- iterator.remove();
- }
- }
- }
- return page;
- }
- @Override
- public Page<ProjectInfoVO> getByMerchantProject(MerchantProjectDTO dto) {
- Page<ProjectInfoVO> page = new Page<>(dto.getCurrent(), dto.getSize());
- return this.baseMapper.getByMerchantProject(page, dto);
- }
- @Override
- public MerchantDetailVO getDetail(MerchantDetailDTO dto) {
- // 1. 获取商户信息
- Long merchantId = dto.getMerchantId();
- MerchantDetailVO detail = this.baseMapper.getDetail(dto);
- if (ObjectUtil.isNull(detail)) {
- throw new ServiceException("商户不存在");
- }
- // 2. 获取商户的默认地址
- TAddress address = this.addressService.getOne(new LambdaQueryWrapper<TAddress>()
- .eq(TAddress::getMerchantId, merchantId)
- .eq(TAddress::getIsDefault, 1)
- .eq(TAddress::getIsDelete, NOT_DELETED));
- if (ObjectUtil.isNull(address)) {
- throw new ServiceException("无法获取商户的默认地址");
- }
- // 3. 计算当前用户距离商户距离
- BigDecimal distanceStr = DistanceUtil.formatDistanceInKilometers(
- dto.getLatitude(), dto.getLongitude(),
- address.getLatitude(), address.getLongitude()
- );
- detail.setDistance(distanceStr);
- // 4. 获取商户是否被当前用户收藏
- boolean collected = this.collectService.isCollected(merchantId);
- detail.setCollected(collected);
- return detail;
- }
- /**
- * 申请开通新服务
- *
- * @param dto
- */
- private void extracted(MaProjectSaveDto dto) {
- LambdaQueryWrapper<Project> query = new LambdaQueryWrapper<>();
- query.in(Project::getId, dto.getProjectIdList());
- List<Project> projectList = projectMapper.selectList(query);
- for (Project project : projectList) {
- MaProject maProject = new MaProject();
- maProject.setProjectId(project.getId());
- maProject.setProjectName(project.getTitle());
- maProject.setProjectDescribe(project.getDetail());
- maProject.setProjectDuration(project.getStandardDuration());
- maProject.setProjectOriginalPrice(project.getPrice());
- maProject.setProjectMaxPrice(project.getPriceMax());
- maProject.setProjectLowestPrice(project.getPriceMin());
- maProject.setMerchantId(dto.getMerchantId());
- maProject.setApplyTime(DateUtils.getNowDate());
- maProject.setMerchantPhone(dto.getMerchantPhone());
- maProject.setCreateBy(dto.getMerchantId().longValue());
- maProject.setCreateTime(DateUtils.getNowDate());
- maProjectMapper.insert(maProject);
- }
- }
- /**
- * 状态切换
- *
- * @param userId
- * @param forceConfirm
- * @return Result
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public Result switchToOffline(Long userId, Boolean forceConfirm) {
- if (userId == null) {
- throw new ServiceException("商户ID不能为空");
- }
- MaTechnician technician = getTechnician(userId);
- if (technician == null) {
- throw new ServiceException("商户不存在");
- }
- if (!hasActiveSkills(userId)) {
- throw new ServiceException("请先申请开通技能");
- }
- if (!hasHomeAddress(userId)) {
- throw new ServiceException("请完善家庭地址");
- }
- // 由在线接单切换为休息状态
- if (TechnicianStatusEnum.ONLINE.getCode().equals(technician.getPostState())) {
- return switchOnlineToResting(userId, technician, Boolean.TRUE.equals(forceConfirm));
- }
- // 切换到在线接单状态
- switchRestingToOnline(userId, technician);
- return Result.ok("状态已切换成功");
- }
- /**
- * 状态切换:下线休息
- *
- * @param userId
- * @param technician
- * @param forceConfirm
- * @return Result
- */
- private Result switchOnlineToResting(Long userId, MaTechnician technician, boolean forceConfirm) {
- if (JsStatusEnum.JS_SERVICE.getCode().equals(technician.getServiceState())) {
- throw new ServiceException("您有服务中的订单,不能下岗");
- }
- MerchantDailyAttendance currentAttendance = getTodayAttendance(userId);
- if (ProjectCategoryEnum.MASSAGE.getCode().equals(technician.getServiceTag())) {
- AttendanceRule rule = getAttendanceRule();
- if (rule != null && rule.getBasicWorkHours() != null) {
- long minutesOnline = calculateTodayOnlineMinutes(userId, currentAttendance);
- long requiredMinutes = rule.getBasicWorkHours().multiply(BigDecimal.valueOf(60)).longValue();
- if (minutesOnline < requiredMinutes && !forceConfirm) {
- return Result.ok(buildOfflineConfirmMessage(requiredMinutes, minutesOnline));
- }
- }
- }
- updateStatus(userId, TechnicianStatusEnum.RESTING);
- closeTodayAttendance(currentAttendance);
- return Result.ok("状态已切换成功");
- }
- private void switchRestingToOnline(Long userId, MaTechnician technician) {
- 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);
- }
- /**
- * 计算商户今天在线时间(分钟)
- *
- * @param userId
- * @param currentAttendance
- * @return long
- */
- private long calculateTodayOnlineMinutes(Long userId, MerchantDailyAttendance currentAttendance) {
- long totalMinutes = getWorkDuration(userId, currentAttendance == null ? null : currentAttendance.getId());
- if (currentAttendance == null || currentAttendance.getAttendanceStartTime() == null) {
- return totalMinutes;
- }
- LocalDateTime startTime = toLocalDateTime(currentAttendance.getAttendanceStartTime());
- return totalMinutes + Math.max(0L, Duration.between(startTime, LocalDateTime.now()).toMinutes());
- }
- /**
- * 构建下线确认消息
- *
- * @param requiredMinutes
- * @param minutesOnline
- * @return String
- */
- private String buildOfflineConfirmMessage(long requiredMinutes, long minutesOnline) {
- long remainMinutes = Math.max(0L, requiredMinutes - minutesOnline);
- long remainHours = remainMinutes / 60;
- long remainMinutePart = remainMinutes % 60;
- String remainText = remainMinutePart == 0
- ? remainHours + "小时"
- : remainHours + "小时" + remainMinutePart + "分钟";
- return "平台对您的在线时间做了约定,每日在线需满足"
- + (requiredMinutes / 60) + "小时,距离您下线时间还剩余" + remainText
- + "不满足在线时间将收到平台处罚,是否确认下线?";
- }
- /**
- * 关闭今天商户的考勤记录
- *
- * @param attendance
- */
- private void closeTodayAttendance(MerchantDailyAttendance attendance) {
- if (attendance == null || attendance.getId() == null || attendance.getAttendanceStartTime() == null) {
- return;
- }
- LocalDateTime startTime = toLocalDateTime(attendance.getAttendanceStartTime());
- long workMinutes = Math.max(0L, Duration.between(startTime, LocalDateTime.now()).toMinutes());
- LambdaUpdateWrapper<MerchantDailyAttendance> updateWrapper = new LambdaUpdateWrapper<>();
- updateWrapper.eq(MerchantDailyAttendance::getId, attendance.getId())
- .set(MerchantDailyAttendance::getAttendanceEndTime, DateUtils.getNowDate())
- .set(MerchantDailyAttendance::getTotalWorkMinutes, Math.toIntExact(workMinutes))
- .set(MerchantDailyAttendance::getUpdateTime, DateUtils.getNowDate());
- merchantDailyAttendanceMapper.update(attendance, updateWrapper);
- }
- private LocalDateTime toLocalDateTime(Date date) {
- return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
- }
- /**
- * 获取今天商户的考勤记录
- *
- * @param userId 技师ID
- * @return MerchantDailyAttendance 考勤记录
- */
- 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
- * @param excludeAttendanceId 排除的考勤记录ID
- * @return 工作时长(分钟)
- */
- private long getWorkDuration(Long userId, Long excludeAttendanceId) {
- 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;
- return attendances.stream()
- .filter(attendance -> excludeAttendanceId == null || !excludeAttendanceId.equals(attendance.getId()))
- .filter(attendance -> attendance.getTotalWorkMinutes() != null)
- .mapToLong(MerchantDailyAttendance::getTotalWorkMinutes)
- .sum();
- }
- /**
- * 获取商户的考勤规则
- *
- * @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 boolean true: 有可用技能, false: 无
- */
- public boolean hasActiveSkills(Long userId) {
- LambdaQueryWrapper<MaProject> wrapper = new LambdaQueryWrapper<>();
- wrapper.eq(MaProject::getMerchantId, userId).eq(MaProject::getAuditStatus, 1);
- // 只要查到一条记录即返回 true
- return maProjectMapper.selectCount(wrapper) > 0;
- }
- /**
- * 判断用户是否有家庭地址(通常指设置为默认的地址)
- *
- * @param userId 技师ID
- * @return boolean true: 有地址, false: 无
- */
- public boolean hasHomeAddress(Long userId) {
- LambdaQueryWrapper<TAddress> wrapper = new LambdaQueryWrapper<>();
- wrapper.eq(TAddress::getMerchantId, userId).eq(TAddress::getUserType, 2);
- // 统计数量是否大于0
- long count = addressMapper.selectCount(wrapper);
- return count > 0;
- }
- /**
- * 获取商户信息
- *
- * @param userId 商户ID
- * @return MaTechnician 商户信息
- */
- private MaTechnician getTechnician(Long userId) {
- LambdaQueryWrapper<MaTechnician> query = new LambdaQueryWrapper<>();
- query.eq(MaTechnician::getId, userId);
- return maTechnicianMapper.selectOne(query);
- }
- /**
- * 更新商户接单状态
- *
- * @param userId 商户ID
- * @param status 商户接单状态枚举
- */
- private void updateStatus(Long userId, TechnicianStatusEnum status) {
- LambdaUpdateWrapper<MaTechnician> update = new LambdaUpdateWrapper<>();
- update.eq(MaTechnician::getId, userId);
- update.set(MaTechnician::getPostState, status.getCode());
- maTechnicianMapper.update(null, update);
- }
- /**
- * 后台待审核页面审核通过商户。
- *
- * @param id 商户ID
- * @param dto 待审核通过参数
- * @param loginUser 当前登录用户
- * @return 结果
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public int approvePendingMerchantAudit(Integer id, MaTechnicianPendingAuditSubmitDTO dto, LoginUser loginUser) {
- if (id == null) {
- throw new ServiceException("商户ID不能为空");
- }
- if (dto == null) {
- throw new ServiceException("审核参数不能为空");
- }
- String idCardFront = checkRequiredFileUrl(dto.getIdCardFront(), "身份证正面加密图片");
- String idCardBack = checkRequiredFileUrl(dto.getIdCardBack(), "身份证反面加密图片");
- String healthCertificate = checkRequiredFileUrl(dto.getHealthCertificate(), "健康证加密图片");
- String qualificationCertificate = checkRequiredFileUrl(dto.getQualificationCertificate(), "资格证加密图片");
- checkRequiredExpirationDate(dto.getIdCardExpirationDate(), "身份证到期时间");
- checkRequiredExpirationDate(dto.getHealthCertificateExpirationDate(), "健康证到期时间");
- checkRequiredExpirationDate(dto.getQualificationCertificateExpirationDate(), "资格证到期时间");
- String auditRemark = dto.getAuditRemark() == null ? "" : dto.getAuditRemark().trim();
- if (auditRemark.length() > AUDIT_REMARK_MAX_LENGTH) {
- throw new ServiceException("审核备注长度不能超过" + AUDIT_REMARK_MAX_LENGTH + "个字符");
- }
- MaTechnician existsMerchant = maTechnicianMapper.selectMerchantById(id);
- if (existsMerchant == null || !NOT_DELETED.equals(existsMerchant.getIsDelete())) {
- throw new ServiceException("商户不存在或已删除");
- }
- if (!Integer.valueOf(AUDIT_WAIT_REVIEW).equals(existsMerchant.getAuditStatus())) {
- throw new ServiceException("当前商户不是待审核状态,不能审核通过");
- }
- MaTechnician maTechnician = new MaTechnician();
- maTechnician.setId(id);
- /*maTechnician.setIdCard(String.join(",", idCardFront, idCardBack));
- maTechnician.setHealthCertificate(healthCertificate);
- maTechnician.setQualificationCertificate(qualificationCertificate);*/
- maTechnician.setIdCardExpirationDate(dto.getIdCardExpirationDate());
- maTechnician.setHealthCertificateExpirationDate(dto.getHealthCertificateExpirationDate());
- maTechnician.setQualificationCertificateExpirationDate(dto.getQualificationCertificateExpirationDate());
- maTechnician.setAuditStatus(AUDIT_APPROVED);
- maTechnician.setAuditRemark(auditRemark);
- maTechnician.setApproveTime(DateUtils.getNowDate());
- if (loginUser != null && loginUser.getUser() != null) {
- maTechnician.setUpdateBy(loginUser.getUser().getUserName());
- }
- maTechnician.setUpdateTime(DateUtils.getNowDate());
- int rows = maTechnicianMapper.approvePendingMerchantAuditById(maTechnician);
- if (rows <= 0) {
- throw new ServiceException("待审核商户审核通过失败");
- }
- return rows;
- }
- private String checkRequiredFileUrl(String value, String fieldName) {
- if (StringUtils.isBlank(value)) {
- throw new ServiceException(fieldName + "不能为空");
- }
- return value.trim();
- }
- private void checkRequiredExpirationDate(LocalDate value, String fieldName) {
- if (value == null) {
- throw new ServiceException(fieldName + "不能为空");
- }
- if (value.isBefore(LocalDate.now())) {
- throw new ServiceException(fieldName + "不能早于当前日期");
- }
- }
- /**
- * 技师待处理订单列表
- *
- * @param query
- * @return
- */
- @Override
- public List<WaitOrderDTO> listWaitOrder(WaitOrderQueryDTO query) {
- LambdaQueryWrapper<TOrder> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(TOrder::getStatus, OrderStatusEnum.WAIT_JD.getCode());
- // 1.查询所有待派未接单订单(status=待接单)
- List<TOrder> allWaitOrder = orderMapper.selectList(queryWrapper);
- if (CollectionUtils.isEmpty(allWaitOrder)) {
- return Collections.emptyList();
- }
- BigDecimal techLat = query.getTechLat();
- BigDecimal techLng = query.getTechLng();
- // 2.逐个计算两点距离(Haversine公式)
- List<WaitOrderDTO> dtoList = allWaitOrder.stream().map(order -> {
- WaitOrderDTO dto = new WaitOrderDTO();
- dto.setOrderId(order.getId());
- dto.setProjectName(getShortProjectName(order.getProjectName()));
- dto.setCustomerType("新客户");//无历史绑定默认新客,接单后再统计老客
- dto.setOrderCreateTime(order.getCreateTime());
- dto.setAppointTime(order.getAppointmentStartTime());
- dto.setTargetAddress(order.getContactAddressInfo());
- dto.setOrderLat(order.getUserLatitude());
- dto.setOrderLng(order.getUserLongitude());
- // 计算两点距离 单位:米
- BigDecimal disMeter = calcDistance(techLat, techLng, order.getUserLatitude(), order.getUserLongitude());
- dto.setDistanceMeter(disMeter);
- dto.setDistanceDesc(formatDistance(disMeter));
- return dto;
- }).collect(Collectors.toList());
- // 3.距离升序:近的排在最前面
- return dtoList.stream()
- .sorted(Comparator.comparing(WaitOrderDTO::getDistanceMeter))
- .collect(Collectors.toList());
- }
- /**
- * 接单
- *
- * @param req
- * @return
- */
- @Override
- public String acceptOrder(AcceptOrderReqDTO req) {
- Long techId = req.getTechId();
- Long orderId = req.getOrderId();
- //【校验1:订单是否已被其他技师接单】
- TOrder order = orderMapper.selectById(orderId);
- if (OrderStatusEnum.RECEIVED_ORDER.getCode().equals(order.getStatus())) {
- return OrderTipEnum.REPEAT_ORDER.getTip();
- }
- //【校验2:时间冲突校验(该技师已有已接单订单)】
- boolean isTimeConflict = checkOrderTimeConflict(techId, order);
- if (isTimeConflict) {
- String tip = String.format(OrderTipEnum.TIME_CONFLICT.getTip(),
- order.getStartTime().format(DateTimeFormatter.ofPattern("MM月dd日HH:mm")),
- order.getCompletedTime().format(DateTimeFormatter.ofPattern("MM月dd日HH:mm")));
- return tip;
- }
- //【校验3:技师休息状态】
- MaTechnician tech = maTechnicianMapper.selectById(techId);
- if (TechnicianStatusEnum.RESTING.getCode().equals(tech.getPostState())) {
- return OrderTipEnum.REST_CONFIRM.getTip();
- }
- // 正常接单,绑定技师ID到订单
- doAcceptOrder(techId, orderId);
- return OrderTipEnum.ALREADY_ACCEPT.getTip();
- }
- /**
- * 技师接单确认接单
- *
- * @param techId
- * @param orderId
- * @return
- */
- @Override
- public String confirmRestAccept(Long techId, Long orderId) {
- LambdaUpdateWrapper<MaTechnician> update = new LambdaUpdateWrapper<>();
- update.eq(MaTechnician::getId, techId);
- update.set(MaTechnician::getPostState, TechnicianStatusEnum.ONLINE.getCode());
- maTechnicianMapper.update(null, update);
- doAcceptOrder(techId, orderId);
- return OrderTipEnum.ALREADY_ACCEPT.getTip();
- }
- /**
- * 技师拒绝接单
- *
- * @param req
- * @return
- */
- @Override
- public void refuseOrder(RefuseOrderReqDTO req) {
- LambdaUpdateWrapper<TOrder> update = new LambdaUpdateWrapper<>();
- update.eq(TOrder::getId, req.getOrderId());
- update.set(TOrder::getStatus, OrderStatusEnum.REFUSE.getCode());
- update.set(TOrder::getRejectedReason, req.getRefuseReason());
- orderMapper.update(null, update);
- //拒单后订单重回待接单池,其他技师可刷到
- LambdaUpdateWrapper<TOrder> update2 = new LambdaUpdateWrapper<>();
- update2.eq(TOrder::getId, req.getOrderId());
- update2.set(TOrder::getStatus, OrderStatusEnum.WAIT_JD.getCode());
- update2.set(TOrder::getMerchantId, "");
- update2.set(TOrder::getRejectedReason, "");
- orderMapper.update(null, update2);
- }
- // =================工具方法=================
- /**
- * Haversine 计算经纬度距离 返回米
- */
- private BigDecimal calcDistance(BigDecimal lat1, BigDecimal lng1, BigDecimal lat2, BigDecimal lng2) {
- // 球面距离计算公式,地球半径6371000米
- // 可使用BigDecimal三角函数或数据库函数优化
- double latRad1 = Math.toRadians(lat1.doubleValue());
- double latRad2 = Math.toRadians(lat2.doubleValue());
- double lngRad1 = Math.toRadians(lng1.doubleValue());
- double lngRad2 = Math.toRadians(lng2.doubleValue());
- double dLat = latRad2 - latRad1;
- double dLng = lngRad2 - lngRad1;
- double a = Math.pow(Math.sin(dLat / 2), 2)
- + Math.cos(latRad1) * Math.cos(latRad2)
- * Math.pow(Math.sin(dLng / 2), 2);
- double dis = 2 * 6371000 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- return BigDecimal.valueOf(dis).setScale(2, BigDecimal.ROUND_HALF_UP);
- }
- private String getShortProjectName(String name) {
- if (name != null && name.length() > 10) {
- return name.substring(0, 8) + "...";
- }
- return name;
- }
- private String formatDistance(BigDecimal distanceMeter) {
- BigDecimal km = distanceMeter.divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP);
- if (km.compareTo(BigDecimal.ONE) > 0) {
- return km + "km";
- } else {
- return distanceMeter.intValue() + "m";
- }
- }
- /**
- * 校验技师已有订单时间冲突(只查该技师已接单数据)
- */
- private boolean checkOrderTimeConflict(Long techId, TOrder newOrder) {
- LambdaQueryWrapper<TOrder> query = new LambdaQueryWrapper<>();
- query.eq(TOrder::getMerchantId, techId);
- query.eq(TOrder::getStatus, OrderStatusEnum.RECEIVED_ORDER.getCode());
- query.eq(TOrder::getStartTime, newOrder.getStartTime());
- List<TOrder> acceptedOrders = orderMapper.selectList(query);
- LocalDate newOrderDate = newOrder.getStartTime().toLocalDate();
- LocalDateTime newStart = newOrder.getStartTime();
- for (TOrder old : acceptedOrders) {
- if (!newOrderDate.isEqual(old.getCompletedTime().toLocalDate())) {
- continue;
- }
- LocalDateTime oldEnd = old.getCompletedTime();
- if (newStart.isBefore(oldEnd) || newStart.isEqual(oldEnd)) {
- return true;
- }
- }
- return false;
- }
- /**
- * 接单:给订单赋值技师ID
- */
- private void doAcceptOrder(Long techId, Long orderId) {
- TOrder update = new TOrder();
- update.setId(orderId);
- update.setMerchantId(techId);
- update.setStatus(OrderStatusEnum.RECEIVED_ORDER.getCode());
- orderMapper.updateById(update);
- }
- }
|