| | |
| | | package com.ruoyi.web.controller.api; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.core.domain.entity.SysDept; |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.system.domain.Employee; |
| | | import com.ruoyi.system.domain.SysVisitArea; |
| | | import com.ruoyi.system.domain.SysVisitorRecord; |
| | | import com.ruoyi.system.domain.vo.AreasList; |
| | | import com.ruoyi.system.dto.SysVisitAreaTreeRequest; |
| | | import com.ruoyi.system.dto.SysVisitorIdCardOutRequest; |
| | | import com.ruoyi.system.dto.SysVisitorRecordAddRequest; |
| | | import com.ruoyi.system.mapper.EmployeeMapper; |
| | | import com.ruoyi.system.mapper.SysDeptMapper; |
| | | import com.ruoyi.system.mapper.SysVisitAreaMapper; |
| | | import com.ruoyi.system.mapper.SysVisitorRecordMapper; |
| | | import com.ruoyi.system.service.ISysVisitAreaService; |
| | | import com.ruoyi.system.utils.EmployeePhoneCrypto; |
| | | import com.ruoyi.system.vo.SysVisitAreaVO; |
| | | import com.ruoyi.web.controller.service.SysVisitorRecordService; |
| | | import com.ruoyi.web.controller.service.VisitorRegisterSyncService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import io.swagger.annotations.ApiParam; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | |
| | | import java.util.Date; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | @RestController |
| | | @RequestMapping("/api/visitorRecord") |
| | | @Api(tags = "访客登记") |
| | | @Api(tags = "现场访客登记-签离") |
| | | public class SysApiVisitorRecordController extends BaseController { |
| | | |
| | | @Autowired |
| | | private VisitorRegisterSyncService visitorRegisterSyncService; |
| | | @Autowired |
| | | private SysVisitorRecordService sysVisitorRecordService; |
| | | @Autowired |
| | | private SysVisitorRecordMapper visitorRecordMapper; |
| | | @Autowired |
| | | private SysVisitAreaMapper sysVisitAreaMapper; |
| | | @Autowired |
| | | private EmployeeMapper employeeMapper; |
| | | @Autowired |
| | | private SysDeptMapper sysDeptMapper; |
| | | |
| | | @PostMapping("/add") |
| | | @ApiOperation(value = "访客登记", notes = "现场访客登记") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult add( |
| | | @RequestBody |
| | | @ApiParam(value = "访客登记信息", required = true) |
| | |
| | | return AjaxResult.error("被访人不能为空"); |
| | | } |
| | | |
| | | List<Employee> employeeISList = employeeMapper.selectEnabledByEmployeeName(request.getIntervieweeName()); |
| | | if (employeeISList.isEmpty()) { |
| | | throw new ServiceException("被访人不存在,请联系工作人员"); |
| | | }else { |
| | | //重名 |
| | | if (StringUtils.isNotEmpty(request.getBeVisitorPhone())) { |
| | | String phoneHash = StringUtils.isEmpty(request.getBeVisitorPhone()) ? null : EmployeePhoneCrypto.hash(request.getBeVisitorPhone()); |
| | | |
| | | Employee employee = employeeMapper.selectOne(new LambdaQueryWrapper<Employee>().eq(Employee::getContactPhoneHash, phoneHash)); |
| | | if (employee == null) { |
| | | throw new ServiceException("被访人不存在,请联系工作人员"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 签离的当天不能再次进入 签到 |
| | | LambdaQueryWrapper<SysVisitorRecord> yqwrapper = new LambdaQueryWrapper<>(); |
| | | Date todayStart = DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH); // 当天 00:00:00 |
| | | Date todayEnd = DateUtils.addMilliseconds(DateUtils.addDays(todayStart, 1), -1); // 当天 23:59:59 |
| | | yqwrapper.eq(SysVisitorRecord::getIdCard, request.getIdCard()) |
| | | .eq(SysVisitorRecord::getStatus, "VISITING") |
| | | .ge(SysVisitorRecord::getSignTime, todayStart) //签离时间 >= 00:00:00 |
| | | .le(SysVisitorRecord::getSignTime, todayEnd) //签离时间 <= 23:59:59 |
| | | .orderByDesc(SysVisitorRecord::getRegisterTime) |
| | | .last("limit 1"); |
| | | SysVisitorRecord sysVisitorRecordYQ = visitorRecordMapper.selectOne(yqwrapper); |
| | | if (sysVisitorRecordYQ != null) { |
| | | throw new ServiceException("权限已回收,当天不可再次访问"); |
| | | } |
| | | |
| | | if (StringUtils.isNotBlank(request.getIdCard())) { |
| | | |
| | | LambdaQueryWrapper<SysVisitorRecord> wrapper = Wrappers.lambdaQuery(); |
| | | |
| | | wrapper.eq(SysVisitorRecord::getIdCard, request.getIdCard()) |
| | | .eq(SysVisitorRecord::getVisitorName, request.getVisitorName()) |
| | | .eq(SysVisitorRecord::getDelFlag, "0") |
| | | .in(SysVisitorRecord::getStatus, |
| | | "VISITING", |
| | |
| | | SysVisitorRecord record = new SysVisitorRecord(); |
| | | BeanUtils.copyProperties(request, record); |
| | | |
| | | record.setRegisterNo(generateRegisterNo()); |
| | | record.setRegisterType("ONSITE"); |
| | | //查询地区 |
| | | List<AreasList> areasList = null; |
| | | |
| | | //查询地区 |
| | | if (StringUtils.isNotEmpty(request.getVisitAreaIds())) { |
| | | String[] visitAreaIds = request.getVisitAreaIds().split(","); |
| | | String visitArea = Arrays.stream(visitAreaIds) |
| | | .map(id -> { |
| | | SysVisitArea area = sysVisitAreaMapper.selectById(Long.parseLong(id.trim())); |
| | | if (area == null || "1".equals(area.getDelFlag())) { |
| | | throw new ServiceException("访问区域不存在,请联系工作人员"); |
| | | } |
| | | return area != null ? area.getAreaName() : null; |
| | | }) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | // ====== 新增:构建 areas 数组 ====== |
| | | areasList = Arrays.stream(visitAreaIds) |
| | | .map(String::trim) |
| | | .filter(StringUtils::isNotEmpty) |
| | | .map(id -> { |
| | | SysVisitArea area = sysVisitAreaMapper.selectById(Long.parseLong(id)); |
| | | if (area == null) { |
| | | throw new ServiceException("访问区域不存在,请联系工作人员"); |
| | | } |
| | | AreasList areas = new AreasList(); |
| | | areas.setAreaCode(area.getAreaCode()); |
| | | areas.setAreaName(area.getAreaName()); |
| | | return areas; |
| | | }) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (!areasList.isEmpty()) { |
| | | record.setAreasList(areasList); |
| | | } |
| | | |
| | | // 使用 visitArea |
| | | if (StringUtils.isNotEmpty(visitArea)) { |
| | | record.setVisitAreaNames(visitArea); |
| | | record.setRemark("来访中,允许访问区域:" + visitArea); |
| | | } |
| | | } |
| | | |
| | | // 如果 visitAreaIds 为空,但 visitAreaNames 不为空,根据名称查询填充 visitAreaIds |
| | | else if (StringUtils.isNotEmpty(request.getVisitAreaNames())) { |
| | | String[] visitAreaNames = request.getVisitAreaNames().split(","); |
| | | |
| | | // 根据区域名称查询对应的ID,构建ID字符串 |
| | | String visitAreaIdsStr = Arrays.stream(visitAreaNames) |
| | | .map(String::trim) |
| | | .filter(StringUtils::isNotEmpty) |
| | | .map(name -> { |
| | | // 根据区域名称查询区域信息(这里假设您有根据名称查询的方法) |
| | | SysVisitAreaTreeRequest query = new SysVisitAreaTreeRequest(); |
| | | query.setAreaName(name); |
| | | List<SysVisitAreaVO> area = sysVisitAreaMapper.selectAreaTreeList(query); |
| | | return area != null ? String.valueOf(area.get(0).getAreaId()) : null; |
| | | }) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.joining(",")); |
| | | |
| | | if (StringUtils.isNotEmpty(visitAreaIdsStr)) { |
| | | record.setVisitAreaIds(visitAreaIdsStr); |
| | | } |
| | | |
| | | // 同时构建 areas 数组 |
| | | areasList = Arrays.stream(visitAreaNames) |
| | | .map(String::trim) |
| | | .filter(StringUtils::isNotEmpty) |
| | | .map(name -> { |
| | | SysVisitAreaTreeRequest query = new SysVisitAreaTreeRequest(); |
| | | query.setAreaName(name); |
| | | List<SysVisitAreaVO> area = sysVisitAreaMapper.selectAreaTreeList(query); |
| | | if (area == null || area.isEmpty()) { |
| | | return null; |
| | | } |
| | | AreasList areas = new AreasList(); |
| | | areas.setAreaCode(area.get(0).getAreaCode()); |
| | | areas.setAreaName(area.get(0).getAreaName()); |
| | | return areas; |
| | | }) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (!areasList.isEmpty()) { |
| | | record.setAreasList(areasList); |
| | | record.setRemark("来访中,允许访问区域:" + record.getVisitAreaNames()); |
| | | } |
| | | } |
| | | |
| | | //查询接待人的部门 |
| | | if (StringUtils.isNotEmpty(record.getIntervieweeName())) { |
| | | List<Employee> employee = employeeMapper.selectEnabledByEmployeeName(record.getIntervieweeName()); |
| | | if (!employee.isEmpty()) { |
| | | Employee employeeNo1 = employee.get(0); |
| | | if (employeeNo1.getDeptId() != null) { |
| | | SysDept sysDept = sysDeptMapper.selectDeptById(employeeNo1.getDeptId()); |
| | | if (sysDept != null) { |
| | | record.setIntervieweeDept(sysDept.getDeptName()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | record.setRegisterNo(generateRegisterNo());//登记编号 |
| | | // record.setRegisterType("ONSITE");//现场登记 |
| | | record.setRegisterSource("访客机"); |
| | | record.setStatus("VISITING"); |
| | | record.setStatus("VISITING");//来访中 |
| | | record.setRegisterTime(new Date()); |
| | | record.setCreateTime(new Date()); |
| | | record.setDelFlag("0"); |
| | | |
| | | // ================= 同步到对端服务器 ================= |
| | | try { |
| | | AjaxResult syncResult = visitorRegisterSyncService.syncVisitorRegister(record); |
| | | |
| | | if (syncResult.isSuccess()) { |
| | | logger.info("访客登记数据已同步到对端,远程ID:{}", syncResult.get("data")); |
| | | // 可将远程ID保存到本地记录 |
| | | // record.setRemoteId(syncResult.getRemoteId()); |
| | | UpdateWrapper<SysVisitorRecord> wrapper = new UpdateWrapper<>(); |
| | | wrapper.eq("record_id", record.getRecordId()); // 指定ID条件 |
| | | visitorRecordMapper.update(record, wrapper); |
| | | } else { |
| | | String msg = (String) syncResult.get("msg"); |
| | | logger.error("访客登记同步失败:{}", msg); |
| | | // 可选择是否允许本地登记成功但同步失败 |
| | | // 如果要保证数据一致性,这里可以抛出异常回滚事务 |
| | | throw new ServiceException(msg); |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("访客登记同步异常", e); |
| | | throw new ServiceException("服务器登记失败"); |
| | | } |
| | | |
| | | int rows = visitorRecordMapper.insert(record); |
| | | |
| | | sysVisitorRecordService.registerVisitor(record); |
| | | |
| | | if (rows > 0) { |
| | | return AjaxResult.success(record.getRegisterNo()); |
| | | return AjaxResult.success(record); |
| | | } |
| | | |
| | | return AjaxResult.error("登记失败"); |
| | | } |
| | | |
| | | |
| | | @PostMapping("/add1") |
| | | @ApiOperation(value = "身份证签离", notes = "身份证签离") |
| | | public AjaxResult idCardOut( |
| | | @PostMapping("/idCardSingOut") |
| | | @ApiOperation(value = "访客身份证签离", notes = "访客身份证签离") |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public AjaxResult idCardSingOut( |
| | | @RequestBody |
| | | @ApiParam(value = "", required = true) |
| | | SysVisitorRecordAddRequest request){ |
| | | @ApiParam(value = "访客身份证签离", required = true) |
| | | SysVisitorIdCardOutRequest request){ |
| | | |
| | | if (StringUtils.isEmpty(request.getIdCard())) { |
| | | throw new ServiceException("请刷身份证"); |
| | | } |
| | | |
| | | //todo 身份证号签离逻辑 |
| | | LambdaQueryWrapper<SysVisitorRecord> wrapper = new LambdaQueryWrapper<>(); |
| | | wrapper.eq(SysVisitorRecord::getIdCard, request.getIdCard()) |
| | | .eq(SysVisitorRecord::getStatus, "VISITING") // status = 'VISITING' |
| | | .orderByDesc(SysVisitorRecord::getRegisterTime) // register_time 倒序 |
| | | .last("limit 1"); // 只取第一条 |
| | | |
| | | SysVisitorRecord record = visitorRecordMapper.selectOne(wrapper); |
| | | |
| | | if (record == null) { |
| | | throw new ServiceException("请使用签到身份证"); |
| | | } |
| | | |
| | | // 2. 校验状态 - 只有来访中或逾期滞留才能签离 |
| | | String status = record.getStatus(); |
| | | if (!"VISITING".equals(status) && !"PENDING_CONFIRM".equals(status)) { |
| | | throw new ServiceException("当前状态不允许签离,状态为:" + status); |
| | | } |
| | | |
| | | // 3. 校验有效期(可选:检查是否在有效期内) |
| | | Date now = new Date(); |
| | | if (record.getValidEndTime() != null && now.after(record.getValidEndTime())) { |
| | | // 如果已过期,自动转为逾期签离状态 |
| | | record.setStatus("OVERDUE_AUTO_SIGNED_OUT"); |
| | | } else { |
| | | record.setStatus("SIGNED_OUT"); |
| | | } |
| | | |
| | | SysVisitorRecord visitorRecord = new SysVisitorRecord(); |
| | | BeanUtils.copyBeanProp(visitorRecord, request); |
| | | visitorRecord.setSignVerifyMethod(request.getSignVerifyMethod()); |
| | | visitorRecord.setStatus(record.getStatus()); |
| | | visitorRecord.setRecordId(record.getRecordId()); |
| | | visitorRecord.setSignTime(new Date()); |
| | | |
| | | UpdateWrapper<SysVisitorRecord> wrapperUpdate = new UpdateWrapper<>(); |
| | | wrapperUpdate.eq("record_id", visitorRecord.getRecordId()); // 指定ID条件 |
| | | visitorRecordMapper.update(visitorRecord, wrapperUpdate); |
| | | |
| | | return success(); |
| | | } |
| | | |
| | |
| | | * VIS20260707123456 |
| | | */ |
| | | private String generateRegisterNo() { |
| | | |
| | | String date = |
| | | new java.text.SimpleDateFormat("yyyyMMddHHmmss") |
| | | .format(new Date()); |
| | | |
| | | String random = |
| | | String.valueOf((int)((Math.random() * 900000) + 100000)); |
| | | |
| | | String date = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); |
| | | String random = String.valueOf((int)((Math.random() * 900000) + 100000)); |
| | | return "VIS" + date + random; |
| | | } |
| | | } |