package com.tourguide.modules.user.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.tourguide.common.api.PageResponse;
|
import com.tourguide.common.exception.BusinessException;
|
import com.tourguide.modules.user.dto.GuideAutoDisableConfigRequest;
|
import com.tourguide.modules.user.dto.GuideAutoDisableConfigResponse;
|
import com.tourguide.modules.user.dto.GuideProfileUpdateRequest;
|
import com.tourguide.modules.user.dto.GuideScenicConfigResponse;
|
import com.tourguide.modules.user.dto.GuideUserCreateRequest;
|
import com.tourguide.modules.user.dto.GuideUserDetailResponse;
|
import com.tourguide.modules.user.dto.GuideUserDetailUpdateRequest;
|
import com.tourguide.modules.user.dto.GuideUserResponse;
|
import com.tourguide.modules.user.entity.GuideAutoDisableConfig;
|
import com.tourguide.modules.user.entity.GuideApplication;
|
import com.tourguide.modules.user.entity.GuideScenicConfig;
|
import com.tourguide.modules.user.entity.GuideTeam;
|
import com.tourguide.modules.user.entity.GuideTeamScenicConfig;
|
import com.tourguide.modules.user.entity.GuideUser;
|
import com.tourguide.modules.user.mapper.GuideAutoDisableConfigMapper;
|
import com.tourguide.modules.user.mapper.GuideScenicConfigMapper;
|
import com.tourguide.modules.user.mapper.GuideTeamMapper;
|
import com.tourguide.modules.user.mapper.GuideTeamScenicConfigMapper;
|
import com.tourguide.modules.user.mapper.GuideUserMapper;
|
import com.tourguide.modules.user.mapper.GuideApplicationMapper;
|
import com.tourguide.modules.operation.entity.OperationCity;
|
import com.tourguide.modules.operation.entity.OperationScenicSpot;
|
import com.tourguide.modules.operation.mapper.OperationCityMapper;
|
import com.tourguide.modules.operation.mapper.OperationScenicSpotMapper;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
import java.time.DateTimeException;
|
import java.time.LocalDate;
|
import java.time.format.DateTimeFormatter;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.UUID;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
import java.util.stream.Collectors;
|
|
/** 仅处理导游端账号,避免导游身份与游客或后台管理员混用。 */
|
@Service
|
public class GuideUserService {
|
public static final int STATUS_DISABLED = 0;
|
public static final int STATUS_ENABLED = 1;
|
public static final int STATUS_PENDING = 2;
|
public static final int STATUS_CANCELLED = 3;
|
private static final String DEFAULT_GUIDE_PASSWORD = "123456";
|
private static final Pattern WORK_YEAR_START_PATTERN = Pattern.compile("^(\\d+)");
|
private final GuideUserMapper userMapper;
|
private final GuideTeamMapper teamMapper;
|
private final GuideApplicationMapper applicationMapper;
|
private final GuideTeamScenicConfigMapper teamScenicConfigMapper;
|
private final GuideScenicConfigMapper scenicConfigMapper;
|
private final GuideAutoDisableConfigMapper autoDisableConfigMapper;
|
private final OperationScenicSpotMapper scenicSpotMapper;
|
private final OperationCityMapper cityMapper;
|
private final PasswordEncoder passwordEncoder;
|
|
public GuideUserService(GuideUserMapper userMapper, GuideTeamMapper teamMapper,
|
GuideScenicConfigMapper scenicConfigMapper,
|
GuideAutoDisableConfigMapper autoDisableConfigMapper,
|
OperationScenicSpotMapper scenicSpotMapper,
|
OperationCityMapper cityMapper,
|
PasswordEncoder passwordEncoder) {
|
this(userMapper, teamMapper, null, null, scenicConfigMapper, autoDisableConfigMapper,
|
scenicSpotMapper, cityMapper, passwordEncoder);
|
}
|
|
public GuideUserService(GuideUserMapper userMapper, GuideTeamMapper teamMapper,
|
GuideApplicationMapper applicationMapper,
|
GuideScenicConfigMapper scenicConfigMapper,
|
GuideAutoDisableConfigMapper autoDisableConfigMapper,
|
OperationScenicSpotMapper scenicSpotMapper,
|
OperationCityMapper cityMapper,
|
PasswordEncoder passwordEncoder) {
|
this(userMapper, teamMapper, applicationMapper, null, scenicConfigMapper, autoDisableConfigMapper,
|
scenicSpotMapper, cityMapper, passwordEncoder);
|
}
|
|
@Autowired
|
public GuideUserService(GuideUserMapper userMapper, GuideTeamMapper teamMapper,
|
GuideApplicationMapper applicationMapper,
|
GuideTeamScenicConfigMapper teamScenicConfigMapper,
|
GuideScenicConfigMapper scenicConfigMapper,
|
GuideAutoDisableConfigMapper autoDisableConfigMapper,
|
OperationScenicSpotMapper scenicSpotMapper,
|
OperationCityMapper cityMapper,
|
PasswordEncoder passwordEncoder) {
|
this.userMapper = userMapper;
|
this.teamMapper = teamMapper;
|
this.applicationMapper = applicationMapper;
|
this.teamScenicConfigMapper = teamScenicConfigMapper;
|
this.scenicConfigMapper = scenicConfigMapper;
|
this.autoDisableConfigMapper = autoDisableConfigMapper;
|
this.scenicSpotMapper = scenicSpotMapper;
|
this.cityMapper = cityMapper;
|
this.passwordEncoder = passwordEncoder;
|
}
|
|
public GuideUser findEnabledById(Long id) {
|
GuideUser user = userMapper.selectById(id);
|
if (user == null || user.getStatus() == null || user.getStatus() != STATUS_ENABLED) {
|
throw new BusinessException(401, "导游用户不存在或已停用");
|
}
|
return user;
|
}
|
|
public GuideUser findWorkbenchAccessibleById(Long id) {
|
GuideUser user = findById(id);
|
if (user.getStatus() == null || user.getStatus() == STATUS_CANCELLED) {
|
throw new BusinessException(401, "导游用户不存在或已注销");
|
}
|
return user;
|
}
|
|
public GuideUser findByUsername(String username) {
|
return userMapper.selectOne(new LambdaQueryWrapper<GuideUser>().eq(GuideUser::getUsername, username).last("LIMIT 1"));
|
}
|
|
public GuideUser findByPhone(String phone) {
|
return userMapper.selectOne(new LambdaQueryWrapper<GuideUser>()
|
.and(query -> query.eq(GuideUser::getUsername, phone).or().eq(GuideUser::getMobile, phone))
|
.orderByDesc(GuideUser::getId)
|
.last("LIMIT 1"));
|
}
|
|
public PageResponse<GuideUserResponse> page(long page, long size, String keyword, Integer status,
|
LocalDate startDate, LocalDate endDate, String ratingLevel,
|
String teamType, Boolean whitelisted) {
|
LambdaQueryWrapper<GuideUser> query = new LambdaQueryWrapper<GuideUser>();
|
if (StringUtils.hasText(keyword)) {
|
String searchKeyword = keyword.trim();
|
query.and(wrapper -> wrapper.like(GuideUser::getUsername, searchKeyword)
|
.or().like(GuideUser::getRealName, searchKeyword)
|
.or().like(GuideUser::getMobile, searchKeyword)
|
.or().like(GuideUser::getCertificateNo, searchKeyword));
|
}
|
query.eq(status != null, GuideUser::getStatus, status)
|
.ne(GuideUser::getStatus, STATUS_PENDING)
|
.eq(whitelisted != null, GuideUser::getAutoDisableWhitelisted, Boolean.TRUE.equals(whitelisted) ? 1 : 0)
|
.ge(startDate != null, GuideUser::getCreatedAt, startDate == null ? null : startDate.atStartOfDay())
|
.lt(endDate != null, GuideUser::getCreatedAt, endDate == null ? null : endDate.plusDays(1).atStartOfDay());
|
if ("personal".equals(teamType)) query.isNull(GuideUser::getTeamId);
|
if ("team".equals(teamType)) query.isNotNull(GuideUser::getTeamId);
|
if ("high".equals(ratingLevel)) query.ge(GuideUser::getRating, 4);
|
if ("medium".equals(ratingLevel)) query.ge(GuideUser::getRating, 3).lt(GuideUser::getRating, 4);
|
if ("low".equals(ratingLevel)) query.lt(GuideUser::getRating, 3);
|
query.orderByDesc(GuideUser::getId);
|
Page<GuideUser> result = userMapper.selectPage(new Page<GuideUser>(page, size), query);
|
Map<Long, String> teamNames = loadTeamNames(result.getRecords());
|
return new PageResponse<GuideUserResponse>(result.getRecords().stream()
|
.map(user -> GuideUserResponse.from(user, teamNames.get(user.getTeamId())))
|
.collect(Collectors.toList()),
|
result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
public GuideUserDetailResponse detail(Long id) {
|
GuideUser user = findById(id);
|
GuideTeam team = user.getTeamId() == null ? null : teamMapper.selectById(user.getTeamId());
|
List<GuideScenicConfig> scenicConfigs = scenicConfigMapper.selectList(
|
new LambdaQueryWrapper<GuideScenicConfig>().eq(GuideScenicConfig::getGuideId, id).orderByAsc(GuideScenicConfig::getId));
|
GuideApplication application = findLatestApplication(user);
|
LocalDate birthDate = user.getBirthDate();
|
Integer workYears = user.getWorkYears();
|
if (birthDate == null || workYears == null) {
|
if (birthDate == null && application != null) birthDate = parseBirthDate(application.getIdCardNo());
|
if (workYears == null && application != null) workYears = parseWorkYears(application.getWorkYearRange());
|
}
|
return new GuideUserDetailResponse(user, team == null ? null : team.getTeamName(), scenicConfigs,
|
birthDate, workYears,
|
application == null ? null : application.getAgeRange(),
|
application == null ? null : application.getWorkYearRange());
|
}
|
|
private GuideApplication findLatestApplication(GuideUser user) {
|
if (applicationMapper == null) return null;
|
if (StringUtils.hasText(user.getIdCardNo())) {
|
GuideApplication application = applicationMapper.selectOne(new LambdaQueryWrapper<GuideApplication>()
|
.eq(GuideApplication::getIdCardNo, user.getIdCardNo().trim())
|
.in(GuideApplication::getAuditStatus, 0, 1)
|
.orderByDesc(GuideApplication::getId)
|
.last("LIMIT 1"));
|
if (application != null) return application;
|
}
|
if (!StringUtils.hasText(user.getMobile())) return null;
|
return applicationMapper.selectOne(new LambdaQueryWrapper<GuideApplication>()
|
.eq(GuideApplication::getMobile, user.getMobile().trim())
|
.in(GuideApplication::getAuditStatus, 0, 1)
|
.orderByDesc(GuideApplication::getId)
|
.last("LIMIT 1"));
|
}
|
|
@Transactional
|
public List<GuideScenicConfigResponse> addScenicConfig(Long guideId, Long scenicSpotId) {
|
GuideUser guide = findById(guideId);
|
OperationScenicSpot scenicSpot = scenicSpotMapper.selectById(scenicSpotId);
|
if (scenicSpot == null || scenicSpot.getStatus() == null || scenicSpot.getStatus() != 1) {
|
throw new BusinessException(404, "景区不存在或未启用");
|
}
|
OperationCity city = scenicSpot.getCityId() == null ? null : cityMapper.selectById(scenicSpot.getCityId());
|
ensureScenicBelongsToGuideTeam(guide, scenicSpot);
|
GuideScenicConfig config = new GuideScenicConfig();
|
config.setGuideId(guideId);
|
config.setScenicName(scenicSpot.getScenicName());
|
config.setCityName(city == null ? null : city.getCityName());
|
scenicConfigMapper.upsert(config);
|
return scenicConfigs(guideId);
|
}
|
|
private void ensureScenicBelongsToGuideTeam(GuideUser guide, OperationScenicSpot scenicSpot) {
|
if (guide.getTeamId() == null) return;
|
long configured = teamScenicConfigMapper.selectCount(
|
new LambdaQueryWrapper<GuideTeamScenicConfig>()
|
.eq(GuideTeamScenicConfig::getTeamId, guide.getTeamId())
|
.eq(GuideTeamScenicConfig::getScenicName, scenicSpot.getScenicName()));
|
if (configured == 0) {
|
throw new BusinessException(400, "只能配置所属讲解队下的景区");
|
}
|
}
|
|
@Transactional
|
public List<GuideScenicConfigResponse> deleteScenicConfig(Long guideId, Long configId) {
|
findById(guideId);
|
GuideScenicConfig config = scenicConfigMapper.selectById(configId);
|
if (config == null || !guideId.equals(config.getGuideId())) {
|
throw new BusinessException(404, "导游景区配置不存在");
|
}
|
scenicConfigMapper.deleteById(configId);
|
return scenicConfigs(guideId);
|
}
|
|
private List<GuideScenicConfigResponse> scenicConfigs(Long guideId) {
|
return scenicConfigMapper.selectList(new LambdaQueryWrapper<GuideScenicConfig>()
|
.eq(GuideScenicConfig::getGuideId, guideId)
|
.orderByAsc(GuideScenicConfig::getId))
|
.stream().map(GuideScenicConfigResponse::new).collect(Collectors.toList());
|
}
|
|
public GuideUser findById(Long id) {
|
GuideUser user = userMapper.selectById(id);
|
if (user == null) { throw new BusinessException(404, "导游用户不存在"); }
|
return user;
|
}
|
|
private Map<Long, String> loadTeamNames(List<GuideUser> users) {
|
Set<Long> teamIds = users.stream().map(GuideUser::getTeamId).filter(id -> id != null).collect(Collectors.toSet());
|
if (teamIds.isEmpty()) return Collections.emptyMap();
|
Map<Long, String> names = new HashMap<Long, String>();
|
for (GuideTeam team : teamMapper.selectBatchIds(teamIds)) names.put(team.getId(), team.getTeamName());
|
return names;
|
}
|
|
@Transactional
|
public GuideUserResponse create(GuideUserCreateRequest request) {
|
if (userMapper.selectCount(new LambdaQueryWrapper<GuideUser>().eq(GuideUser::getUsername, request.getUsername())) > 0) {
|
throw new BusinessException(409, "导游用户名已存在");
|
}
|
GuideUser user = new GuideUser();
|
user.setUsername(request.getUsername());
|
user.setPassword(passwordEncoder.encode(request.getPassword()));
|
user.setRealName(request.getRealName());
|
user.setMobile(request.getMobile());
|
user.setCertificateNo(request.getCertificateNo());
|
user.setStatus(1);
|
user.setDeleted(0);
|
userMapper.insert(user);
|
return GuideUserResponse.from(user);
|
}
|
|
/** 审核通过后创建正式导游账号,申请手机号作为登录用户名。 */
|
@Transactional
|
public GuideUserResponse createFromApprovedApplication(GuideApplication application) {
|
if (!StringUtils.hasText(application.getMobile())) {
|
throw new BusinessException(400, "申请手机号不能为空");
|
}
|
String username = application.getMobile().trim();
|
GuideUser existingUser = findByPhone(username);
|
if (existingUser != null && existingUser.getStatus() == STATUS_CANCELLED) {
|
anonymizeCancelledGuide(existingUser);
|
existingUser = null;
|
}
|
if (existingUser != null && (existingUser.getStatus() == null || existingUser.getStatus() != 2)) {
|
throw new BusinessException(409, "该手机号已存在导游账号");
|
}
|
ensureUniqueGuideIdentity(application, existingUser);
|
if (existingUser != null) {
|
copyApplicationProfile(existingUser, application);
|
existingUser.setStatus(1);
|
userMapper.updateById(existingUser);
|
return GuideUserResponse.from(existingUser);
|
}
|
GuideUser user = new GuideUser();
|
user.setUsername(username);
|
user.setPassword(passwordEncoder.encode(DEFAULT_GUIDE_PASSWORD));
|
copyApplicationProfile(user, application);
|
user.setStatus(1);
|
user.setDeleted(0);
|
userMapper.insert(user);
|
return GuideUserResponse.from(user);
|
}
|
|
@Transactional
|
public GuideUserResponse createPendingFromApplication(GuideApplication application) {
|
GuideUser user = findByPhone(application.getMobile());
|
if (user != null && user.getStatus() == STATUS_CANCELLED) {
|
anonymizeCancelledGuide(user);
|
user = null;
|
}
|
if (user == null) {
|
user = new GuideUser();
|
user.setUsername(application.getMobile().trim());
|
user.setPassword(passwordEncoder.encode(DEFAULT_GUIDE_PASSWORD));
|
user.setStatus(2);
|
user.setDeleted(0);
|
} else if (user.getStatus() == null
|
|| (user.getStatus() != STATUS_PENDING && user.getStatus() != STATUS_CANCELLED)) {
|
throw new BusinessException(409, "该手机号已存在导游账号");
|
}
|
ensureUniqueGuideIdentity(application, user);
|
copyApplicationProfile(user, application);
|
if (user.getId() == null) userMapper.insert(user); else userMapper.updateById(user);
|
return GuideUserResponse.from(user);
|
}
|
|
private void anonymizeCancelledGuide(GuideUser user) {
|
String deletedUsername = "deleted_" + UUID.randomUUID().toString().replace("-", "").substring(0, 24);
|
userMapper.anonymizeCancelledGuide(user.getId(), deletedUsername);
|
}
|
|
private void ensureUniqueGuideIdentity(GuideApplication application, GuideUser existingUser) {
|
if (StringUtils.hasText(application.getIdCardNo())) {
|
String idCardNo = application.getIdCardNo().trim().toUpperCase();
|
// 兼容旧注销数据:释放已注销账号占用的身份证唯一索引。
|
userMapper.clearCancelledIdentityByIdCard(idCardNo);
|
// 兼容旧驳回数据:释放待审核账号占用的身份证唯一索引,避免其阻塞重新注册。
|
userMapper.clearPendingIdentityByIdCard(idCardNo);
|
}
|
if (StringUtils.hasText(application.getCertificateNo())
|
&& userMapper.selectCount(new LambdaQueryWrapper<GuideUser>()
|
.eq(GuideUser::getCertificateNo, application.getCertificateNo())
|
.ne(GuideUser::getStatus, STATUS_CANCELLED)
|
.ne(existingUser != null && existingUser.getId() != null,
|
GuideUser::getId, existingUser == null ? null : existingUser.getId())) > 0) {
|
throw new BusinessException(409, "该导游证号已存在导游账号");
|
}
|
if (StringUtils.hasText(application.getIdCardNo())
|
&& userMapper.selectCount(new LambdaQueryWrapper<GuideUser>()
|
.eq(GuideUser::getIdCardNo, application.getIdCardNo().trim().toUpperCase())
|
.ne(GuideUser::getStatus, STATUS_CANCELLED)
|
.ne(existingUser != null && existingUser.getId() != null,
|
GuideUser::getId, existingUser == null ? null : existingUser.getId())) > 0) {
|
throw new BusinessException(409, "该身份证号已存在导游账号");
|
}
|
}
|
|
/** 申请被驳回后释放待审核账号占用的身份证/导游证唯一索引,避免其阻塞重新注册。 */
|
public void releaseIdentityForRejectedApplication(String mobile) {
|
if (!StringUtils.hasText(mobile)) return;
|
GuideUser user = findByPhone(mobile);
|
if (user != null && Integer.valueOf(STATUS_PENDING).equals(user.getStatus())) {
|
userMapper.releasePendingIdentity(user.getId());
|
}
|
}
|
|
private void copyApplicationProfile(GuideUser user, GuideApplication application) {
|
user.setRealName(application.getRealName());
|
user.setMobile(application.getMobile());
|
user.setGender(application.getGender());
|
user.setBirthDate(parseBirthDate(application.getIdCardNo()));
|
user.setWorkYears(parseWorkYears(application.getWorkYearRange()));
|
user.setCertificateNo(application.getCertificateNo());
|
user.setIdCardNo(application.getIdCardNo());
|
user.setIdCardFrontUrl(application.getIdCardFrontUrl());
|
user.setIdCardBackUrl(application.getIdCardBackUrl());
|
user.setGuideCertificateUrl(application.getCertificateUrl());
|
user.setQualificationCertificateUrl(application.getQualificationCertificateUrl());
|
user.setTeamId(application.getTeamId());
|
}
|
|
private LocalDate parseBirthDate(String idCardNo) {
|
if (!StringUtils.hasText(idCardNo)) return null;
|
String normalized = idCardNo.trim().toUpperCase();
|
if (normalized.length() < 14) return null;
|
try {
|
return LocalDate.parse(normalized.substring(6, 14), DateTimeFormatter.BASIC_ISO_DATE);
|
} catch (DateTimeException exception) {
|
return null;
|
}
|
}
|
|
private Integer parseWorkYears(String workYearRange) {
|
if (!StringUtils.hasText(workYearRange)) return null;
|
String normalized = workYearRange.trim();
|
Matcher matcher = WORK_YEAR_START_PATTERN.matcher(normalized);
|
if (!matcher.find()) return null;
|
try {
|
int startYears = Integer.parseInt(matcher.group(1));
|
if (startYears > 100) return null;
|
return startYears == 1 && normalized.indexOf('-') < 0 ? 0 : startYears;
|
} catch (NumberFormatException exception) {
|
return null;
|
}
|
}
|
|
@Transactional
|
public GuideUserResponse updateProfile(Long id, GuideProfileUpdateRequest request) {
|
GuideUser user = findEnabledById(id);
|
user.setRealName(request.getRealName());
|
user.setAvatar(request.getAvatar());
|
user.setCertificateNo(request.getCertificateNo());
|
userMapper.updateById(user);
|
return GuideUserResponse.from(user);
|
}
|
|
@Transactional
|
public GuideUserResponse updateAvatar(Long id, String avatar) {
|
GuideUser user = findEnabledById(id);
|
user.setAvatar(avatar);
|
userMapper.updateById(user);
|
return GuideUserResponse.from(user);
|
}
|
|
@Transactional
|
public GuideUserResponse updateAvatarByAdmin(Long id, String avatar) {
|
GuideUser user = findById(id);
|
user.setAvatar(avatar);
|
userMapper.updateById(user);
|
return GuideUserResponse.from(user);
|
}
|
|
public boolean supportsDocumentType(String documentType) {
|
return "idCardFrontUrl".equals(documentType)
|
|| "idCardBackUrl".equals(documentType)
|
|| "guideCertificateUrl".equals(documentType)
|
|| "qualificationCertificateUrl".equals(documentType);
|
}
|
|
@Transactional
|
public String updateDocumentByAdmin(Long id, String documentType, String documentUrl) {
|
GuideUser user = findById(id);
|
if ("idCardFrontUrl".equals(documentType)) {
|
user.setIdCardFrontUrl(documentUrl);
|
} else if ("idCardBackUrl".equals(documentType)) {
|
user.setIdCardBackUrl(documentUrl);
|
} else if ("guideCertificateUrl".equals(documentType)) {
|
user.setGuideCertificateUrl(documentUrl);
|
} else if ("qualificationCertificateUrl".equals(documentType)) {
|
user.setQualificationCertificateUrl(documentUrl);
|
} else {
|
throw new BusinessException(400, "不支持的证件类型");
|
}
|
userMapper.updateById(user);
|
return documentUrl;
|
}
|
|
public void ensurePhoneAvailable(Long currentGuideId, String phone) {
|
GuideUser existing = findByPhone(phone);
|
if (existing != null && !existing.getId().equals(currentGuideId)) {
|
throw new BusinessException(409, "该手机号已绑定其他导游账号");
|
}
|
}
|
|
@Transactional
|
public GuideUserResponse changeMobile(Long id, String newPhone) {
|
GuideUser user = findEnabledById(id);
|
updateMobileAndLoginUsername(user, newPhone);
|
userMapper.updateById(user);
|
return GuideUserResponse.from(user);
|
}
|
|
@Transactional
|
public GuideUserDetailResponse updateDetail(Long id, GuideUserDetailUpdateRequest request) {
|
GuideUser user = userMapper.selectForUpdate(id);
|
if (user == null) throw new BusinessException(404, "导游用户不存在");
|
if (!java.util.Objects.equals(user.getTeamId(), request.getTeamId())
|
&& teamMapper.selectCount(new LambdaQueryWrapper<GuideTeam>()
|
.eq(GuideTeam::getCollectionGuideId, id)) > 0) {
|
throw new BusinessException(409, "该导游已配置为讲解队收款导游,请先更换收款导游");
|
}
|
updateMobileAndLoginUsername(user, request.getMobile());
|
user.setRealName(request.getRealName());
|
user.setAvatar(request.getAvatar());
|
user.setCertificateNo(request.getCertificateNo());
|
user.setGender(request.getGender());
|
user.setBirthDate(request.getBirthDate());
|
user.setWorkYears(request.getWorkYears());
|
user.setIdCardNo(request.getIdCardNo());
|
user.setIdCardFrontUrl(request.getIdCardFrontUrl());
|
user.setIdCardBackUrl(request.getIdCardBackUrl());
|
user.setGuideCertificateUrl(request.getGuideCertificateUrl());
|
user.setQualificationCertificateUrl(request.getQualificationCertificateUrl());
|
user.setTeamId(request.getTeamId());
|
user.setWechatOpenId(request.getWechatOpenId());
|
userMapper.updateById(user);
|
|
return detail(id);
|
}
|
|
private void updateMobileAndLoginUsername(GuideUser user, String newPhone) {
|
String oldPhone = user.getMobile();
|
if (!java.util.Objects.equals(oldPhone, newPhone) && StringUtils.hasText(newPhone)) {
|
ensurePhoneAvailable(user.getId(), newPhone);
|
}
|
user.setMobile(newPhone);
|
if (oldPhone != null && oldPhone.equals(user.getUsername()) && StringUtils.hasText(newPhone)) {
|
user.setUsername(newPhone);
|
}
|
}
|
|
@Transactional
|
public void updateWhitelist(Long id, boolean enabled) {
|
GuideUser user = findById(id);
|
user.setAutoDisableWhitelisted(enabled ? 1 : 0);
|
// 将因自动禁用规则停用的导游加入白名单后,立即恢复账号状态。
|
// 仅处理 autoDisabled 标记,避免误启用管理员手动停用的导游。
|
if (enabled
|
&& Integer.valueOf(STATUS_DISABLED).equals(user.getStatus())
|
&& Integer.valueOf(1).equals(user.getAutoDisabled())) {
|
user.setStatus(STATUS_ENABLED);
|
user.setAutoDisabled(0);
|
}
|
userMapper.updateById(user);
|
}
|
|
@Transactional
|
public void updatePremiumPermission(Long id, boolean enabled) {
|
GuideUser user = findById(id);
|
user.setPremiumEnabled(enabled ? 1 : 0);
|
userMapper.updateById(user);
|
}
|
|
public GuideAutoDisableConfigResponse getAutoDisableConfig() {
|
GuideAutoDisableConfig config = autoDisableConfigMapper.selectById(1);
|
if (config == null) {
|
config = new GuideAutoDisableConfig();
|
config.setId(1);
|
config.setOrderThreshold(1);
|
config.setRatingThreshold(new java.math.BigDecimal(3.00));
|
autoDisableConfigMapper.insert(config);
|
}
|
return new GuideAutoDisableConfigResponse(config);
|
}
|
|
@Transactional
|
public GuideAutoDisableConfigResponse updateAutoDisableConfig(GuideAutoDisableConfigRequest request) {
|
GuideAutoDisableConfig config = autoDisableConfigMapper.selectById(1);
|
if (config == null) {
|
config = new GuideAutoDisableConfig();
|
config.setId(1);
|
config.setOrderThreshold(request.getOrderThreshold());
|
config.setRatingThreshold(request.getRatingThreshold());
|
autoDisableConfigMapper.insert(config);
|
} else {
|
config.setOrderThreshold(request.getOrderThreshold());
|
config.setRatingThreshold(request.getRatingThreshold());
|
autoDisableConfigMapper.updateById(config);
|
}
|
return new GuideAutoDisableConfigResponse(autoDisableConfigMapper.selectById(1));
|
}
|
|
@Transactional
|
public void updateStatus(Long id, Integer status) {
|
GuideUser user = userMapper.selectForUpdate(id);
|
if (user == null) { throw new BusinessException(404, "导游用户不存在"); }
|
if (!Integer.valueOf(STATUS_ENABLED).equals(status)
|
&& teamMapper.selectCount(new LambdaQueryWrapper<GuideTeam>()
|
.eq(GuideTeam::getCollectionGuideId, id)) > 0) {
|
throw new BusinessException(409, "该导游已配置为讲解队收款导游,请先更换收款导游");
|
}
|
if (user.getStatus() != null && user.getStatus() == STATUS_CANCELLED) {
|
throw new BusinessException(409, "已注销导游账号不可重新启用");
|
}
|
if (Integer.valueOf(STATUS_ENABLED).equals(status)
|
&& Integer.valueOf(1).equals(user.getAutoDisabled())
|
&& !Integer.valueOf(1).equals(user.getAutoDisableWhitelisted())) {
|
throw new BusinessException(409, "该导游由自动禁用规则停用,请先在自动禁用设置中添加白名单后再启用");
|
}
|
user.setStatus(status);
|
user.setAutoDisabled(0);
|
userMapper.updateById(user);
|
}
|
}
|