package com.sinata.appointment.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.alibaba.excel.EasyExcel;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.sinata.appointment.constants.BizErrorCode;
|
import com.sinata.appointment.constants.CacheNames;
|
import com.sinata.appointment.constants.AppointmentBizConstants;
|
import com.sinata.appointment.constants.FieldConfigLockedCodes;
|
import com.sinata.appointment.constants.SystemSettingKeys;
|
import com.sinata.appointment.dto.BookingSettingsSaveRequest;
|
import com.sinata.appointment.dto.BookingSettingsVo;
|
import com.sinata.appointment.dto.ContentSettingsSaveRequest;
|
import com.sinata.appointment.dto.ContentSettingsVo;
|
import com.sinata.appointment.dto.FieldConfigPatchRequest;
|
import com.sinata.appointment.dto.SensitiveWordCreateRequest;
|
import com.sinata.appointment.dto.SensitiveWordEnabledPatchRequest;
|
import com.sinata.appointment.dto.SensitiveWordImportResultVo;
|
import com.sinata.appointment.dto.SensitiveWordListVo;
|
import com.sinata.appointment.dto.SensitiveWordUpdateRequest;
|
import com.sinata.appointment.dto.VisitReasonCreateRequest;
|
import com.sinata.appointment.dto.VisitReasonListVo;
|
import com.sinata.appointment.dto.VisitReasonUpdateRequest;
|
import com.sinata.appointment.entity.BizApprovalNodeConfig;
|
import com.sinata.appointment.entity.BizFieldConfig;
|
import com.sinata.appointment.entity.BizHolidayDate;
|
import com.sinata.appointment.entity.BizSensitiveWord;
|
import com.sinata.appointment.entity.BizVisitReason;
|
import com.sinata.appointment.entity.SysBizSetting;
|
import com.sinata.appointment.entity.SysDept;
|
import com.sinata.appointment.exception.BizException;
|
import com.sinata.appointment.mapper.BizApprovalNodeConfigMapper;
|
import com.sinata.appointment.mapper.BizFieldConfigMapper;
|
import com.sinata.appointment.mapper.BizHolidayDateMapper;
|
import com.sinata.appointment.mapper.BizSensitiveWordMapper;
|
import com.sinata.appointment.mapper.BizVisitReasonMapper;
|
import com.sinata.appointment.mapper.SysBizSettingMapper;
|
import com.sinata.appointment.mapper.SysDeptMapper;
|
import com.sinata.appointment.util.UuidAssert;
|
import java.io.ByteArrayOutputStream;
|
import java.io.IOException;
|
import java.time.LocalDate;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeParseException;
|
import java.util.ArrayList;
|
import java.util.Comparator;
|
import java.util.HashSet;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.UUID;
|
import java.util.stream.Collectors;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.cache.Cache;
|
import org.springframework.cache.CacheManager;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
import org.springframework.web.multipart.MultipartFile;
|
|
@Service
|
@RequiredArgsConstructor
|
public class ConfigApplicationService {
|
|
private static final TypeReference<List<String>> STRING_LIST_TYPE = new TypeReference<>() {};
|
|
private final BizVisitReasonMapper bizVisitReasonMapper;
|
private final BizFieldConfigMapper bizFieldConfigMapper;
|
private final BizApprovalNodeConfigMapper bizApprovalNodeConfigMapper;
|
private final BizHolidayDateMapper bizHolidayDateMapper;
|
private final BizSensitiveWordMapper bizSensitiveWordMapper;
|
private final SysBizSettingMapper sysBizSettingMapper;
|
private final SysDeptMapper sysDeptMapper;
|
private final SysBizSettingCacheService sysBizSettingCacheService;
|
private final BizHolidayDateCacheService bizHolidayDateCacheService;
|
private final SensitiveWordFilterService sensitiveWordFilterService;
|
private final CacheManager cacheManager;
|
private final ObjectMapper objectMapper;
|
|
public List<BizVisitReason> listVisitReasons() {
|
return bizVisitReasonMapper.selectList(
|
new LambdaQueryWrapper<BizVisitReason>()
|
.eq(BizVisitReason::getDelFlag, 0)
|
.eq(BizVisitReason::getEnabled, 1)
|
.orderByAsc(BizVisitReason::getSortOrder));
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveVisitReason(BizVisitReason entity) {
|
if (entity.getId() == null) {
|
bizVisitReasonMapper.insert(entity);
|
} else {
|
bizVisitReasonMapper.updateById(entity);
|
}
|
evictMiniVisitReasonCache();
|
}
|
|
public IPage<VisitReasonListVo> pageVisitReasons(long page, long size) {
|
Page<BizVisitReason> pg =
|
bizVisitReasonMapper.selectPage(
|
new Page<>(page, size),
|
new LambdaQueryWrapper<BizVisitReason>()
|
.eq(BizVisitReason::getDelFlag, 0)
|
.orderByAsc(BizVisitReason::getSortOrder)
|
.orderByAsc(BizVisitReason::getId));
|
return pg.convert(this::toVisitReasonListVo);
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void createVisitReason(VisitReasonCreateRequest req) {
|
String reasonName = req.getReasonName().trim();
|
assertReasonNameUnique(reasonName, null);
|
BizVisitReason row = new BizVisitReason();
|
row.setReasonName(reasonName);
|
row.setReasonCode("VR_" + UUID.randomUUID().toString().replace("-", ""));
|
row.setEnabled(1);
|
row.setSortOrder(normalizeSortOrder(req.getSortOrder()));
|
bizVisitReasonMapper.insert(row);
|
evictMiniVisitReasonCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void updateVisitReason(Long id, VisitReasonUpdateRequest req) {
|
BizVisitReason row = loadActiveVisitReason(id, req.getUuid());
|
String reasonName = req.getReasonName().trim();
|
assertReasonNameUnique(reasonName, id);
|
row.setReasonName(reasonName);
|
row.setSortOrder(normalizeSortOrder(req.getSortOrder()));
|
bizVisitReasonMapper.updateById(row);
|
evictMiniVisitReasonCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteVisitReason(Long id, String uuid) {
|
loadActiveVisitReason(id, uuid);
|
bizVisitReasonMapper.deleteById(id);
|
evictMiniVisitReasonCache();
|
}
|
|
public IPage<SensitiveWordListVo> pageSensitiveWords(long page, long size, String keyword) {
|
String normalizedKeyword = trimToNull(keyword);
|
Page<BizSensitiveWord> pg =
|
bizSensitiveWordMapper.selectPage(
|
new Page<>(page, size),
|
new LambdaQueryWrapper<BizSensitiveWord>()
|
.eq(BizSensitiveWord::getDelFlag, 0)
|
.like(StringUtils.hasText(normalizedKeyword), BizSensitiveWord::getWord, normalizedKeyword)
|
.orderByDesc(BizSensitiveWord::getCreateTime)
|
.orderByDesc(BizSensitiveWord::getId));
|
return pg.convert(this::toSensitiveWordListVo);
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void createSensitiveWord(SensitiveWordCreateRequest req) {
|
String word = normalizeSensitiveWord(req.getWord());
|
assertSensitiveWordUnique(word, null);
|
BizSensitiveWord row = new BizSensitiveWord();
|
row.setWord(word);
|
row.setEnabled(1);
|
bizSensitiveWordMapper.insert(row);
|
sensitiveWordFilterService.evictCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void updateSensitiveWord(Long id, SensitiveWordUpdateRequest req) {
|
BizSensitiveWord row = loadActiveSensitiveWord(id, req.getUuid());
|
String word = normalizeSensitiveWord(req.getWord());
|
assertSensitiveWordUnique(word, id);
|
row.setWord(word);
|
bizSensitiveWordMapper.updateById(row);
|
sensitiveWordFilterService.evictCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void updateSensitiveWordEnabled(Long id, SensitiveWordEnabledPatchRequest req) {
|
BizSensitiveWord row = loadActiveSensitiveWord(id, req.getUuid());
|
row.setEnabled(req.getEnabled());
|
bizSensitiveWordMapper.updateById(row);
|
sensitiveWordFilterService.evictCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteSensitiveWord(Long id, String uuid) {
|
loadActiveSensitiveWord(id, uuid);
|
bizSensitiveWordMapper.deleteById(id);
|
sensitiveWordFilterService.evictCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public SensitiveWordImportResultVo importSensitiveWords(MultipartFile file) {
|
if (file == null || file.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "导入文件不能为空");
|
}
|
String filename = file.getOriginalFilename() == null ? "" : file.getOriginalFilename().toLowerCase();
|
if (!filename.endsWith(".xlsx") && !filename.endsWith(".xls")) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请上传 xls 或 xlsx 文件");
|
}
|
|
List<Map<Integer, String>> rows;
|
try {
|
rows = EasyExcel.read(file.getInputStream()).sheet().headRowNumber(0).doReadSync();
|
} catch (IOException ex) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "读取导入文件失败");
|
}
|
|
SensitiveWordImportResultVo result = new SensitiveWordImportResultVo();
|
Set<String> fileWords = new LinkedHashSet<>();
|
Set<String> existingWords = loadExistingSensitiveWords();
|
int rowNo = 0;
|
for (Map<Integer, String> row : rows) {
|
rowNo++;
|
String raw = row == null ? null : row.get(0);
|
if (rowNo == 1 && isSensitiveWordHeader(raw)) {
|
continue;
|
}
|
if (!StringUtils.hasText(raw)) {
|
continue;
|
}
|
result.setTotalRows(result.getTotalRows() + 1);
|
String word;
|
try {
|
word = normalizeSensitiveWord(raw);
|
} catch (BizException ex) {
|
result.setInvalidCount(result.getInvalidCount() + 1);
|
addImportError(result, "第" + rowNo + "行:" + ex.getMessage());
|
continue;
|
}
|
if (fileWords.contains(word) || existingWords.contains(word)) {
|
result.setDuplicateCount(result.getDuplicateCount() + 1);
|
continue;
|
}
|
BizSensitiveWord entity = new BizSensitiveWord();
|
entity.setWord(word);
|
entity.setEnabled(1);
|
bizSensitiveWordMapper.insert(entity);
|
fileWords.add(word);
|
existingWords.add(word);
|
result.setSuccessCount(result.getSuccessCount() + 1);
|
}
|
if (result.getSuccessCount() > 0) {
|
sensitiveWordFilterService.evictCache();
|
}
|
return result;
|
}
|
|
public byte[] sensitiveWordImportTemplateExcel() {
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
List<List<String>> head = List.of(List.of("敏感词"));
|
List<List<String>> rows = List.of(List.of("示例敏感词"));
|
EasyExcel.write(bos).head(head).sheet("敏感词导入").doWrite(rows);
|
return bos.toByteArray();
|
} catch (IOException ex) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "生成导入模板失败");
|
}
|
}
|
|
public List<BizFieldConfig> listFieldConfigs() {
|
return bizFieldConfigMapper.selectList(
|
new LambdaQueryWrapper<BizFieldConfig>()
|
.eq(BizFieldConfig::getDelFlag, 0)
|
.orderByAsc(BizFieldConfig::getSortOrder));
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveFieldConfig(BizFieldConfig entity) {
|
if (entity.getId() == null) {
|
bizFieldConfigMapper.insert(entity);
|
} else {
|
bizFieldConfigMapper.updateById(entity);
|
}
|
evictMiniFieldConfigCache();
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void patchFieldConfig(Long id, FieldConfigPatchRequest req) {
|
if (req.getVisible() == null && req.getRequiredFlag() == null) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请至少提交一项修改");
|
}
|
BizFieldConfig e = bizFieldConfigMapper.selectById(id);
|
if (e == null || (e.getDelFlag() != null && e.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "字段配置不存在");
|
}
|
UuidAssert.match(e, req.getUuid());
|
if (FieldConfigLockedCodes.isLocked(e.getFieldCode())) {
|
e.setVisible(1);
|
e.setRequiredFlag(1);
|
bizFieldConfigMapper.updateById(e);
|
return;
|
}
|
if (req.getVisible() != null) {
|
e.setVisible(req.getVisible());
|
}
|
if (e.getVisible() != null && e.getVisible() == 0) {
|
e.setRequiredFlag(0);
|
} else if (req.getRequiredFlag() != null) {
|
e.setRequiredFlag(req.getRequiredFlag());
|
}
|
bizFieldConfigMapper.updateById(e);
|
evictMiniFieldConfigCache();
|
}
|
|
public BookingSettingsVo getBookingSettings() {
|
BookingSettingsVo vo = new BookingSettingsVo();
|
String mode =
|
getSettingOrDefault(
|
SystemSettingKeys.BOOKING_RANGE_MODE,
|
AppointmentBizConstants.TIME_MODE_SINGLE)
|
.trim()
|
.toUpperCase();
|
if (!AppointmentBizConstants.TIME_MODE_SINGLE.equals(mode)
|
&& !AppointmentBizConstants.TIME_MODE_MULTI.equals(mode)) {
|
mode = AppointmentBizConstants.TIME_MODE_SINGLE;
|
}
|
vo.setRangeMode(mode);
|
String days = getSettingOrDefault(SystemSettingKeys.BOOKING_MAX_CONSECUTIVE_DAYS, "7");
|
int md = 7;
|
try {
|
md = Math.max(1, Integer.parseInt(days.trim()));
|
} catch (NumberFormatException ignored) {
|
// keep default
|
}
|
vo.setMaxConsecutiveDays(md);
|
vo.setHolidayDates(listHolidayDates());
|
String gate = getSettingOrDefault(SystemSettingKeys.VEHICLE_BARRIER_GATE_ENABLED, "0");
|
vo.setVehicleBarrierEnabled("1".equals(gate.trim()));
|
return vo;
|
}
|
|
public ContentSettingsVo getContentSettings() {
|
ContentSettingsVo vo = new ContentSettingsVo();
|
vo.setAboutUsHtml(getSettingOrDefault(SystemSettingKeys.CONTENT_ABOUT_US_HTML, ""));
|
vo.setParkNoticeHtml(getSettingOrDefault(SystemSettingKeys.CONTENT_PARK_NOTICE_HTML, ""));
|
vo.setParkFlowHtml(getSettingOrDefault(SystemSettingKeys.CONTENT_PARK_FLOW_HTML, ""));
|
vo.setAboutUsEnabled("1".equals(getSettingOrDefault(SystemSettingKeys.CONTENT_ABOUT_US_ENABLED, "0").trim()));
|
return vo;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveBookingSettings(BookingSettingsSaveRequest req) {
|
String mode = req.getRangeMode().trim().toUpperCase();
|
if (!AppointmentBizConstants.TIME_MODE_SINGLE.equals(mode)
|
&& !AppointmentBizConstants.TIME_MODE_MULTI.equals(mode)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "预约时段类型无效");
|
}
|
if (AppointmentBizConstants.TIME_MODE_MULTI.equals(mode)) {
|
if (req.getMaxConsecutiveDays() == null || req.getMaxConsecutiveDays() < 1) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请输入最长连续预约天数(正整数)");
|
}
|
if (req.getMaxConsecutiveDays() > 999) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "最长连续预约天数不能超过 999");
|
}
|
upsertSetting(SystemSettingKeys.BOOKING_MAX_CONSECUTIVE_DAYS, String.valueOf(req.getMaxConsecutiveDays()));
|
}
|
upsertSetting(SystemSettingKeys.BOOKING_RANGE_MODE, mode);
|
List<String> hol = req.getHolidayDates() == null ? List.of() : req.getHolidayDates();
|
List<String> normalized = normalizeHolidayDates(hol);
|
replaceHolidayDates(normalized);
|
bizHolidayDateCacheService.evictAllHolidayDates();
|
// 兼容旧实现:避免 setting_value 持续变大,保存后清空 JSON
|
upsertSetting(SystemSettingKeys.BOOKING_HOLIDAY_DATES, "[]");
|
upsertSetting(
|
SystemSettingKeys.VEHICLE_BARRIER_GATE_ENABLED,
|
Boolean.TRUE.equals(req.getVehicleBarrierEnabled()) ? "1" : "0");
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void toggleHolidayDate(String date, boolean holiday) {
|
LocalDate target = parseDate(date);
|
if (holiday) {
|
Long exists =
|
bizHolidayDateMapper.selectCount(
|
new LambdaQueryWrapper<BizHolidayDate>()
|
.eq(BizHolidayDate::getDelFlag, 0)
|
.eq(BizHolidayDate::getHolidayDate, target));
|
if (exists == null || exists == 0L) {
|
BizHolidayDate row = new BizHolidayDate();
|
row.setHolidayDate(target);
|
bizHolidayDateMapper.insert(row);
|
}
|
} else {
|
bizHolidayDateMapper.deleteByHolidayDates(List.of(target));
|
}
|
bizHolidayDateCacheService.evictAllHolidayDates();
|
upsertSetting(SystemSettingKeys.BOOKING_HOLIDAY_DATES, "[]");
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void addMonthWeekends(String month) {
|
YearMonth yearMonth;
|
try {
|
yearMonth = YearMonth.parse(month.trim());
|
} catch (Exception ex) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "非法月份: " + month);
|
}
|
Set<LocalDate> existsSet =
|
bizHolidayDateMapper.selectList(
|
new LambdaQueryWrapper<BizHolidayDate>()
|
.eq(BizHolidayDate::getDelFlag, 0)
|
.ge(BizHolidayDate::getHolidayDate, yearMonth.atDay(1))
|
.le(BizHolidayDate::getHolidayDate, yearMonth.atEndOfMonth()))
|
.stream()
|
.map(BizHolidayDate::getHolidayDate)
|
.collect(Collectors.toSet());
|
|
for (int d = 1; d <= yearMonth.lengthOfMonth(); d++) {
|
LocalDate current = yearMonth.atDay(d);
|
int dayOfWeek = current.getDayOfWeek().getValue(); // 1..7 (Mon..Sun)
|
if (dayOfWeek != 6 && dayOfWeek != 7) {
|
continue;
|
}
|
if (existsSet.contains(current)) {
|
continue;
|
}
|
BizHolidayDate row = new BizHolidayDate();
|
row.setHolidayDate(current);
|
bizHolidayDateMapper.insert(row);
|
}
|
bizHolidayDateCacheService.evictAllHolidayDates();
|
upsertSetting(SystemSettingKeys.BOOKING_HOLIDAY_DATES, "[]");
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveContentSettings(ContentSettingsSaveRequest req) {
|
upsertSetting(SystemSettingKeys.CONTENT_ABOUT_US_HTML, normalizeHtml(req.getAboutUsHtml()));
|
upsertSetting(SystemSettingKeys.CONTENT_PARK_NOTICE_HTML, normalizeHtml(req.getParkNoticeHtml()));
|
upsertSetting(SystemSettingKeys.CONTENT_PARK_FLOW_HTML, normalizeHtml(req.getParkFlowHtml()));
|
upsertSetting(SystemSettingKeys.CONTENT_ABOUT_US_ENABLED, Boolean.TRUE.equals(req.getAboutUsEnabled()) ? "1" : "0");
|
}
|
|
private List<String> listHolidayDates() {
|
List<BizHolidayDate> rows =
|
bizHolidayDateMapper.selectList(
|
new LambdaQueryWrapper<BizHolidayDate>()
|
.eq(BizHolidayDate::getDelFlag, 0)
|
.orderByAsc(BizHolidayDate::getHolidayDate));
|
if (rows != null && !rows.isEmpty()) {
|
return rows.stream()
|
.map(BizHolidayDate::getHolidayDate)
|
.filter(x -> x != null)
|
.map(LocalDate::toString)
|
.collect(Collectors.toList());
|
}
|
// 兜底:旧版本存于 setting_value(JSON);若存在则读出来返回
|
String holJson = getSettingOrDefault(SystemSettingKeys.BOOKING_HOLIDAY_DATES, "[]");
|
try {
|
List<String> raw = objectMapper.readValue(holJson, STRING_LIST_TYPE);
|
if (raw != null && !raw.isEmpty()) {
|
return normalizeHolidayDates(raw);
|
}
|
} catch (Exception ignored) {
|
// ignore
|
}
|
return List.of();
|
}
|
|
private void replaceHolidayDates(List<String> normalized) {
|
List<BizHolidayDate> existing =
|
bizHolidayDateMapper.selectList(
|
new LambdaQueryWrapper<BizHolidayDate>()
|
.eq(BizHolidayDate::getDelFlag, 0)
|
.orderByAsc(BizHolidayDate::getHolidayDate));
|
|
Set<LocalDate> existingSet =
|
existing.stream()
|
.map(BizHolidayDate::getHolidayDate)
|
.filter(x -> x != null)
|
.collect(Collectors.toSet());
|
|
Set<LocalDate> targetSet =
|
normalized.stream().map(LocalDate::parse).collect(Collectors.toCollection(java.util.LinkedHashSet::new));
|
|
// 删除:存在但目标不包含的
|
List<LocalDate> toDelete =
|
existingSet.stream().filter(d -> !targetSet.contains(d)).collect(Collectors.toList());
|
if (!toDelete.isEmpty()) {
|
bizHolidayDateMapper.deleteByHolidayDates(toDelete);
|
}
|
|
// 新增:目标包含但不存在的
|
for (LocalDate d : targetSet) {
|
if (existingSet.contains(d)) {
|
continue;
|
}
|
BizHolidayDate row = new BizHolidayDate();
|
row.setHolidayDate(d);
|
bizHolidayDateMapper.insert(row);
|
}
|
}
|
|
public List<BizApprovalNodeConfig> listApprovalNodes() {
|
return bizApprovalNodeConfigMapper.selectList(
|
new LambdaQueryWrapper<BizApprovalNodeConfig>()
|
.eq(BizApprovalNodeConfig::getDelFlag, 0)
|
.orderByAsc(BizApprovalNodeConfig::getSortOrder));
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveApprovalNode(BizApprovalNodeConfig entity) {
|
if (entity.getId() == null) {
|
bizApprovalNodeConfigMapper.insert(entity);
|
} else {
|
bizApprovalNodeConfigMapper.updateById(entity);
|
}
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void updateApprovalNodeEnabled(Long id, String uuid, int enabled) {
|
BizApprovalNodeConfig e = bizApprovalNodeConfigMapper.selectById(id);
|
if (e == null || (e.getDelFlag() != null && e.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "节点不存在");
|
}
|
UuidAssert.match(e, uuid);
|
e.setEnabled(enabled);
|
bizApprovalNodeConfigMapper.updateById(e);
|
}
|
|
public Long getVisitCompetentDeptId() {
|
String raw = getSettingOrDefault(SystemSettingKeys.VISIT_COMPETENT_DEPT_ID, null);
|
if (!StringUtils.hasText(raw)) {
|
return null;
|
}
|
try {
|
long v = Long.parseLong(raw.trim());
|
return v > 0 ? v : null;
|
} catch (NumberFormatException ex) {
|
return null;
|
}
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void saveVisitCompetentDept(Long deptId) {
|
if (deptId != null && deptId > 0) {
|
SysDept d = sysDeptMapper.selectById(deptId);
|
if (d == null || (d.getDelFlag() != null && d.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.DEPT_PARENT_INVALID, "部门不存在或已删除");
|
}
|
}
|
String val = (deptId != null && deptId > 0) ? String.valueOf(deptId) : null;
|
upsertSetting(SystemSettingKeys.VISIT_COMPETENT_DEPT_ID, val);
|
}
|
|
private String getSettingOrDefault(String key, String defaultVal) {
|
String value = sysBizSettingCacheService.getValue(key);
|
if (!StringUtils.hasText(value)) {
|
return defaultVal;
|
}
|
return value;
|
}
|
|
private static String normalizeHtml(String html) {
|
return html == null ? "" : html;
|
}
|
|
private static String trimToNull(String value) {
|
if (!StringUtils.hasText(value)) {
|
return null;
|
}
|
return value.trim();
|
}
|
|
private void upsertSetting(String key, String value) {
|
SysBizSetting s =
|
sysBizSettingMapper.selectOne(
|
new LambdaQueryWrapper<SysBizSetting>().eq(SysBizSetting::getSettingKey, key));
|
if (s == null) {
|
SysBizSetting row = new SysBizSetting();
|
row.setSettingKey(key);
|
row.setSettingValue(value);
|
sysBizSettingMapper.insert(row);
|
} else {
|
s.setSettingValue(value);
|
sysBizSettingMapper.updateById(s);
|
}
|
sysBizSettingCacheService.evict(key);
|
}
|
|
private static List<String> normalizeHolidayDates(List<String> raw) {
|
LinkedHashSet<String> set = new LinkedHashSet<>();
|
for (String s : raw) {
|
if (!StringUtils.hasText(s)) {
|
continue;
|
}
|
String t = s.trim();
|
try {
|
LocalDate.parse(t);
|
} catch (DateTimeParseException ex) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "非法日期: " + t);
|
}
|
set.add(t);
|
}
|
return set.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
|
}
|
|
private LocalDate parseDate(String date) {
|
try {
|
return LocalDate.parse(date.trim());
|
} catch (Exception ex) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "非法日期: " + date);
|
}
|
}
|
|
private BizVisitReason loadActiveVisitReason(Long id, String uuid) {
|
BizVisitReason row = bizVisitReasonMapper.selectById(id);
|
if (row == null || (row.getDelFlag() != null && row.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "来访事由不存在");
|
}
|
// 兼容历史脏数据:若库中 uuid 为空,则仅按 id 处理;正常数据仍做 id+uuid 校验
|
if (StringUtils.hasText(row.getUuid())) {
|
UuidAssert.match(row, uuid);
|
}
|
return row;
|
}
|
|
private BizSensitiveWord loadActiveSensitiveWord(Long id, String uuid) {
|
BizSensitiveWord row = bizSensitiveWordMapper.selectById(id);
|
if (row == null || (row.getDelFlag() != null && row.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "敏感词不存在");
|
}
|
UuidAssert.match(row, uuid);
|
return row;
|
}
|
|
private void assertSensitiveWordUnique(String word, Long excludeId) {
|
LambdaQueryWrapper<BizSensitiveWord> q =
|
new LambdaQueryWrapper<BizSensitiveWord>()
|
.eq(BizSensitiveWord::getDelFlag, 0)
|
.eq(BizSensitiveWord::getWord, word);
|
if (excludeId != null) {
|
q.ne(BizSensitiveWord::getId, excludeId);
|
}
|
if (bizSensitiveWordMapper.selectCount(q) > 0) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "敏感词已存在");
|
}
|
}
|
|
private String normalizeSensitiveWord(String word) {
|
String normalized = trimToNull(word);
|
if (!StringUtils.hasText(normalized)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "敏感词不能为空");
|
}
|
if (normalized.length() > 50) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "敏感词不能超过50个字");
|
}
|
return normalized;
|
}
|
|
private Set<String> loadExistingSensitiveWords() {
|
List<BizSensitiveWord> rows =
|
bizSensitiveWordMapper.selectList(
|
new LambdaQueryWrapper<BizSensitiveWord>()
|
.eq(BizSensitiveWord::getDelFlag, 0)
|
.select(BizSensitiveWord::getWord));
|
Set<String> words = new HashSet<>();
|
for (BizSensitiveWord row : rows) {
|
if (StringUtils.hasText(row.getWord())) {
|
words.add(row.getWord().trim());
|
}
|
}
|
return words;
|
}
|
|
private boolean isSensitiveWordHeader(String value) {
|
if (!StringUtils.hasText(value)) {
|
return false;
|
}
|
String text = value.trim();
|
return "敏感词".equals(text) || "敏感词库".equals(text) || "word".equalsIgnoreCase(text);
|
}
|
|
private void addImportError(SensitiveWordImportResultVo result, String message) {
|
if (result.getErrorMessages().size() < 20) {
|
result.getErrorMessages().add(message);
|
}
|
}
|
|
private void assertReasonNameUnique(String reasonName, Long excludeId) {
|
LambdaQueryWrapper<BizVisitReason> q =
|
new LambdaQueryWrapper<BizVisitReason>()
|
.eq(BizVisitReason::getDelFlag, 0)
|
.eq(BizVisitReason::getReasonName, reasonName);
|
if (excludeId != null) {
|
q.ne(BizVisitReason::getId, excludeId);
|
}
|
if (bizVisitReasonMapper.selectCount(q) > 0) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "来访事由已存在");
|
}
|
}
|
|
private int normalizeSortOrder(Integer sortOrder) {
|
return sortOrder == null ? 0 : Math.max(0, sortOrder);
|
}
|
|
private VisitReasonListVo toVisitReasonListVo(BizVisitReason e) {
|
VisitReasonListVo vo = new VisitReasonListVo();
|
vo.setId(e.getId());
|
vo.setUuid(e.getUuid());
|
vo.setReasonCode(e.getReasonCode());
|
vo.setReasonName(e.getReasonName());
|
vo.setSortOrder(e.getSortOrder());
|
vo.setCreateTime(e.getCreateTime());
|
return vo;
|
}
|
|
private SensitiveWordListVo toSensitiveWordListVo(BizSensitiveWord e) {
|
SensitiveWordListVo vo = new SensitiveWordListVo();
|
vo.setId(e.getId());
|
vo.setUuid(e.getUuid());
|
vo.setWord(e.getWord());
|
vo.setEnabled(e.getEnabled());
|
vo.setCreateTime(e.getCreateTime());
|
return vo;
|
}
|
|
private void evictMiniVisitReasonCache() {
|
Cache cache = cacheManager.getCache(CacheNames.MINI_LOOKUP);
|
if (cache != null) {
|
cache.evict(CacheNames.MINI_LOOKUP_VISIT_REASONS_KEY);
|
}
|
}
|
|
private void evictMiniFieldConfigCache() {
|
Cache cache = cacheManager.getCache(CacheNames.MINI_LOOKUP);
|
if (cache != null) {
|
cache.evict(CacheNames.MINI_LOOKUP_FIELD_CONFIGS_KEY);
|
}
|
}
|
}
|