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.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.sinata.appointment.constants.BizErrorCode;
|
import com.sinata.appointment.constants.LocalUnitApproverType;
|
import com.sinata.appointment.constants.MiniUserType;
|
import com.sinata.appointment.dto.LocalUnitCreateRequest;
|
import com.sinata.appointment.dto.LocalUnitDetailVo;
|
import com.sinata.appointment.dto.LocalUnitListVo;
|
import com.sinata.appointment.dto.LocalUnitMemberItemVo;
|
import com.sinata.appointment.dto.LocalUnitUpdateRequest;
|
import com.sinata.appointment.entity.MpPassLocalUnit;
|
import com.sinata.appointment.entity.MpPassLocalUnitMember;
|
import com.sinata.appointment.entity.MpStaffGroup;
|
import com.sinata.appointment.entity.MpUser;
|
import com.sinata.appointment.entity.SysDept;
|
import com.sinata.appointment.exception.BizException;
|
import com.sinata.appointment.mapper.MpPassLocalUnitMapper;
|
import com.sinata.appointment.mapper.MpPassLocalUnitMemberMapper;
|
import com.sinata.appointment.mapper.MpStaffGroupMapper;
|
import com.sinata.appointment.mapper.MpUserMapper;
|
import com.sinata.appointment.mapper.SysDeptMapper;
|
import com.sinata.appointment.util.UuidAssert;
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.HashSet;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
@Service
|
public class LocalUnitManageApplicationService {
|
|
private final MpPassLocalUnitMapper mpPassLocalUnitMapper;
|
private final MpPassLocalUnitMemberMapper mpPassLocalUnitMemberMapper;
|
private final ObjectMapper objectMapper;
|
private final SysDeptMapper sysDeptMapper;
|
private final MpStaffGroupMapper mpStaffGroupMapper;
|
private final MpUserMapper mpUserMapper;
|
|
public LocalUnitManageApplicationService(
|
MpPassLocalUnitMapper mpPassLocalUnitMapper,
|
MpPassLocalUnitMemberMapper mpPassLocalUnitMemberMapper,
|
ObjectMapper objectMapper,
|
SysDeptMapper sysDeptMapper,
|
MpStaffGroupMapper mpStaffGroupMapper,
|
MpUserMapper mpUserMapper) {
|
this.mpPassLocalUnitMapper = mpPassLocalUnitMapper;
|
this.mpPassLocalUnitMemberMapper = mpPassLocalUnitMemberMapper;
|
this.objectMapper = objectMapper;
|
this.sysDeptMapper = sysDeptMapper;
|
this.mpStaffGroupMapper = mpStaffGroupMapper;
|
this.mpUserMapper = mpUserMapper;
|
}
|
|
public IPage<LocalUnitListVo> page(long page, long size, String unitName) {
|
LambdaQueryWrapper<MpPassLocalUnit> q =
|
new LambdaQueryWrapper<MpPassLocalUnit>()
|
.eq(MpPassLocalUnit::getDelFlag, 0)
|
.like(StringUtils.hasText(unitName), MpPassLocalUnit::getUnitName, trim(unitName))
|
.orderByDesc(MpPassLocalUnit::getCreateTime);
|
Page<MpPassLocalUnit> pg = mpPassLocalUnitMapper.selectPage(new Page<>(page, size), q);
|
return pg.convert(this::toListVo);
|
}
|
|
public LocalUnitDetailVo detail(Long id, String uuid) {
|
MpPassLocalUnit e = loadActive(id, uuid);
|
LocalUnitDetailVo vo = new LocalUnitDetailVo();
|
vo.setId(e.getId());
|
vo.setUuid(e.getUuid());
|
vo.setUnitName(e.getUnitName());
|
vo.setRemark(e.getRemark());
|
vo.setApproverType(e.getApproverType());
|
vo.setApproverGroupId(e.getApproverGroupId());
|
vo.setApproverDeptIds(readDeptIds(e.getApproverDeptIds()));
|
if (e.getApproverType() != null && e.getApproverType() == LocalUnitApproverType.STAFF) {
|
vo.setMembers(loadMemberItems(e.getId()));
|
}
|
return vo;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public Map<String, Object> create(LocalUnitCreateRequest req) {
|
validateApprover(req.getApproverType(), req.getApproverDeptIds(), req.getApproverGroupId(), req.getMemberIds());
|
MpPassLocalUnit e = new MpPassLocalUnit();
|
e.setUnitName(req.getUnitName().trim());
|
e.setRemark(trimToNull(req.getRemark()));
|
e.setApproverType(req.getApproverType());
|
applyApproverColumns(e, req.getApproverType(), req.getApproverDeptIds(), req.getApproverGroupId());
|
mpPassLocalUnitMapper.insert(e);
|
MpPassLocalUnit fresh = mpPassLocalUnitMapper.selectById(e.getId());
|
if (fresh == null || !StringUtils.hasText(fresh.getUuid())) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "创建后读取失败");
|
}
|
if (req.getApproverType() == LocalUnitApproverType.STAFF) {
|
saveMembers(fresh.getId(), req.getMemberIds());
|
}
|
return Map.of("id", fresh.getId(), "uuid", fresh.getUuid());
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void update(Long id, LocalUnitUpdateRequest req) {
|
MpPassLocalUnit e = loadActive(id, req.getUuid());
|
validateApprover(req.getApproverType(), req.getApproverDeptIds(), req.getApproverGroupId(), req.getMemberIds());
|
mpPassLocalUnitMemberMapper.deletePhysicalByUnitId(e.getId());
|
e.setUnitName(req.getUnitName().trim());
|
e.setRemark(trimToNull(req.getRemark()));
|
e.setApproverType(req.getApproverType());
|
applyApproverColumns(e, req.getApproverType(), req.getApproverDeptIds(), req.getApproverGroupId());
|
mpPassLocalUnitMapper.updateById(e);
|
if (req.getApproverType() == LocalUnitApproverType.STAFF) {
|
saveMembers(e.getId(), req.getMemberIds());
|
}
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void delete(Long id, String uuid) {
|
MpPassLocalUnit e = loadActive(id, uuid);
|
mpPassLocalUnitMemberMapper.deletePhysicalByUnitId(e.getId());
|
int affected = mpPassLocalUnitMapper.deleteById(e.getId());
|
if (affected <= 0) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "删除失败,请刷新后重试");
|
}
|
}
|
|
private void applyApproverColumns(
|
MpPassLocalUnit e, int type, List<Long> deptIds, Long groupId) {
|
e.setApproverDeptIds(null);
|
e.setApproverGroupId(null);
|
if (type == LocalUnitApproverType.DEPT) {
|
e.setApproverDeptIds(writeDeptIds(deptIds));
|
} else if (type == LocalUnitApproverType.STAFF_GROUP) {
|
e.setApproverGroupId(groupId);
|
}
|
}
|
|
private void validateApprover(int type, List<Long> deptIds, Long groupId, List<Long> memberIds) {
|
if (type == LocalUnitApproverType.DEPT) {
|
if (deptIds == null || deptIds.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请选择审批部门");
|
}
|
for (Long id : new LinkedHashSet<>(deptIds)) {
|
if (id == null || id <= 0) {
|
continue;
|
}
|
validateDeptExists(id);
|
}
|
} else if (type == LocalUnitApproverType.STAFF_GROUP) {
|
if (groupId == null || groupId <= 0) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请选择人员分组");
|
}
|
MpStaffGroup g = mpStaffGroupMapper.selectById(groupId);
|
if (g == null || (g.getDelFlag() != null && g.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "人员分组不存在");
|
}
|
} else if (type == LocalUnitApproverType.STAFF) {
|
if (memberIds == null || memberIds.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "请选择审批人员");
|
}
|
validateEmployees(new ArrayList<>(new LinkedHashSet<>(memberIds)));
|
} else {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "审批人员类型无效");
|
}
|
}
|
|
private void validateDeptExists(Long deptId) {
|
SysDept d = sysDeptMapper.selectById(deptId);
|
if (d == null || (d.getDelFlag() != null && d.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.DEPT_PARENT_INVALID, "部门不存在: " + deptId);
|
}
|
}
|
|
private void validateEmployees(List<Long> mpUserIds) {
|
List<String> disabledNames = new ArrayList<>();
|
for (Long id : mpUserIds) {
|
if (id == null || id <= 0) {
|
continue;
|
}
|
MpUser u = mpUserMapper.selectById(id);
|
if (u == null || (u.getDelFlag() != null && u.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "人员不存在: " + id);
|
}
|
if (!MiniUserType.EMPLOYEE.equals(u.getUserType())) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "仅可选择员工: " + id);
|
}
|
if (u.getStatus() != null && u.getStatus() == 0) {
|
disabledNames.add(firstNonBlank(trimToNull(u.getNickName()), trimToNull(u.getMobile()), String.valueOf(id)));
|
}
|
}
|
if (!disabledNames.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "以下员工已禁用,请移除后重试:" + String.join("、", disabledNames));
|
}
|
}
|
|
@SafeVarargs
|
private static String firstNonBlank(String... values) {
|
if (values == null) {
|
return null;
|
}
|
for (String value : values) {
|
if (StringUtils.hasText(value)) {
|
return value.trim();
|
}
|
}
|
return null;
|
}
|
|
private void saveMembers(Long unitId, List<Long> memberIds) {
|
if (memberIds == null) {
|
return;
|
}
|
for (Long mid : new LinkedHashSet<>(memberIds)) {
|
if (mid == null || mid <= 0) {
|
continue;
|
}
|
MpPassLocalUnitMember m = new MpPassLocalUnitMember();
|
m.setUnitId(unitId);
|
m.setMpUserId(mid);
|
mpPassLocalUnitMemberMapper.insert(m);
|
}
|
}
|
|
private List<LocalUnitMemberItemVo> loadMemberItems(Long unitId) {
|
List<MpPassLocalUnitMember> rels =
|
mpPassLocalUnitMemberMapper.selectList(
|
new LambdaQueryWrapper<MpPassLocalUnitMember>()
|
.eq(MpPassLocalUnitMember::getUnitId, unitId)
|
.eq(MpPassLocalUnitMember::getDelFlag, 0));
|
if (rels.isEmpty()) {
|
return List.of();
|
}
|
Set<Long> userIds = new HashSet<>();
|
for (MpPassLocalUnitMember r : rels) {
|
userIds.add(r.getMpUserId());
|
}
|
Map<Long, MpUser> userMap = new HashMap<>();
|
if (!userIds.isEmpty()) {
|
List<MpUser> users =
|
mpUserMapper.selectList(
|
new LambdaQueryWrapper<MpUser>()
|
.eq(MpUser::getDelFlag, 0)
|
.in(MpUser::getId, userIds));
|
for (MpUser u : users) {
|
userMap.put(u.getId(), u);
|
}
|
}
|
Set<Long> deptIds = new HashSet<>();
|
for (MpUser u : userMap.values()) {
|
if (u.getDeptId() != null) {
|
deptIds.add(u.getDeptId());
|
}
|
}
|
Map<Long, String> deptNames = new HashMap<>();
|
if (!deptIds.isEmpty()) {
|
List<SysDept> depts =
|
sysDeptMapper.selectList(
|
new LambdaQueryWrapper<SysDept>()
|
.eq(SysDept::getDelFlag, 0)
|
.in(SysDept::getId, deptIds));
|
for (SysDept d : depts) {
|
deptNames.put(d.getId(), d.getDeptName());
|
}
|
}
|
List<LocalUnitMemberItemVo> out = new ArrayList<>();
|
for (MpPassLocalUnitMember r : rels) {
|
MpUser u = userMap.get(r.getMpUserId());
|
if (u == null) {
|
continue;
|
}
|
LocalUnitMemberItemVo it = new LocalUnitMemberItemVo();
|
it.setMpUserId(u.getId());
|
it.setUuid(u.getUuid());
|
it.setRealName(u.getNickName());
|
it.setDeptName(
|
u.getDeptId() == null ? "—" : deptNames.getOrDefault(u.getDeptId(), "—"));
|
out.add(it);
|
}
|
return out;
|
}
|
|
private LocalUnitListVo toListVo(MpPassLocalUnit e) {
|
LocalUnitListVo vo = new LocalUnitListVo();
|
vo.setId(e.getId());
|
vo.setUuid(e.getUuid());
|
vo.setUnitName(e.getUnitName());
|
vo.setRemark(e.getRemark());
|
vo.setApproverSummary(buildApproverSummary(e));
|
vo.setCreateTime(e.getCreateTime());
|
return vo;
|
}
|
|
private String buildApproverSummary(MpPassLocalUnit e) {
|
Integer t = e.getApproverType();
|
if (t == null) {
|
return "—";
|
}
|
if (t == LocalUnitApproverType.DEPT) {
|
return buildDeptApproverDisplay(readDeptIds(e.getApproverDeptIds()));
|
}
|
if (t == LocalUnitApproverType.STAFF_GROUP && e.getApproverGroupId() != null) {
|
MpStaffGroup g = mpStaffGroupMapper.selectById(e.getApproverGroupId());
|
String n = (g != null && StringUtils.hasText(g.getGroupName())) ? g.getGroupName() : "—";
|
return "人员分组:" + n;
|
}
|
if (t == LocalUnitApproverType.STAFF) {
|
return buildStaffApproverDisplay(e.getId());
|
}
|
return "—";
|
}
|
|
/** 列表审批摘要:部门类型展示部门名称(按配置顺序,顿号分隔) */
|
private String buildDeptApproverDisplay(List<Long> rawIds) {
|
List<Long> ids = new ArrayList<>(new LinkedHashSet<>(rawIds));
|
ids.removeIf(x -> x == null || x <= 0);
|
if (ids.isEmpty()) {
|
return "—";
|
}
|
List<SysDept> depts =
|
sysDeptMapper.selectList(
|
new LambdaQueryWrapper<SysDept>()
|
.eq(SysDept::getDelFlag, 0)
|
.in(SysDept::getId, ids));
|
Map<Long, String> nameById = new HashMap<>();
|
for (SysDept d : depts) {
|
if (d.getId() != null && StringUtils.hasText(d.getDeptName())) {
|
nameById.put(d.getId(), d.getDeptName());
|
}
|
}
|
List<String> parts = new ArrayList<>();
|
for (Long id : ids) {
|
parts.add(nameById.getOrDefault(id, "未知部门"));
|
}
|
return String.join("、", parts);
|
}
|
|
/** 列表审批摘要:人员类型展示员工姓名(关联表顺序,顿号分隔) */
|
private String buildStaffApproverDisplay(Long unitId) {
|
List<MpPassLocalUnitMember> rels =
|
mpPassLocalUnitMemberMapper.selectList(
|
new LambdaQueryWrapper<MpPassLocalUnitMember>()
|
.eq(MpPassLocalUnitMember::getUnitId, unitId)
|
.eq(MpPassLocalUnitMember::getDelFlag, 0));
|
if (rels.isEmpty()) {
|
return "—";
|
}
|
LinkedHashSet<Long> userIds = new LinkedHashSet<>();
|
for (MpPassLocalUnitMember r : rels) {
|
if (r.getMpUserId() != null && r.getMpUserId() > 0) {
|
userIds.add(r.getMpUserId());
|
}
|
}
|
if (userIds.isEmpty()) {
|
return "—";
|
}
|
List<MpUser> users =
|
mpUserMapper.selectList(
|
new LambdaQueryWrapper<MpUser>()
|
.eq(MpUser::getDelFlag, 0)
|
.in(MpUser::getId, userIds));
|
Map<Long, String> nameById = new HashMap<>();
|
for (MpUser u : users) {
|
String label;
|
if (StringUtils.hasText(u.getNickName())) {
|
label = u.getNickName().trim();
|
} else if (StringUtils.hasText(u.getStaffNo())) {
|
label = u.getStaffNo().trim();
|
} else {
|
label = "—";
|
}
|
nameById.put(u.getId(), label);
|
}
|
List<String> parts = new ArrayList<>();
|
for (Long uid : userIds) {
|
parts.add(nameById.getOrDefault(uid, "未知人员"));
|
}
|
return String.join("、", parts);
|
}
|
|
private List<Long> readDeptIds(String json) {
|
if (!StringUtils.hasText(json)) {
|
return List.of();
|
}
|
try {
|
List<Long> list = objectMapper.readValue(json, new TypeReference<List<Long>>() {});
|
return list == null ? List.of() : list;
|
} catch (Exception ignored) {
|
return List.of();
|
}
|
}
|
|
private String writeDeptIds(List<Long> ids) {
|
if (ids == null || ids.isEmpty()) {
|
return null;
|
}
|
List<Long> distinct = new ArrayList<>(new LinkedHashSet<>(ids));
|
distinct.removeIf(x -> x == null || x <= 0);
|
if (distinct.isEmpty()) {
|
return null;
|
}
|
try {
|
return objectMapper.writeValueAsString(distinct);
|
} catch (JsonProcessingException ex) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "部门数据序列化失败");
|
}
|
}
|
|
private MpPassLocalUnit loadActive(Long id, String uuid) {
|
MpPassLocalUnit e = mpPassLocalUnitMapper.selectById(id);
|
if (e == null || (e.getDelFlag() != null && e.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.RESOURCE_VERIFY_FAILED, "资源不存在或无权访问");
|
}
|
UuidAssert.match(e, uuid);
|
return e;
|
}
|
|
private static String trim(String s) {
|
return s == null ? null : s.trim();
|
}
|
|
private static String trimToNull(String s) {
|
if (!StringUtils.hasText(s)) {
|
return null;
|
}
|
String t = s.trim();
|
return t.isEmpty() ? null : t;
|
}
|
}
|