wenminjie
2026-07-10 c14fd6f05f96c36693db8b3058be2ceb8e7c87d1
访客机侧代码
1个文件已删除
12个文件已添加
30个文件已修改
1190 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiVisitAreaController.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorConfigController.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/webSocket/WebSocketAuthHandler.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-applet/src/main/java/com/ruoyi/web/controller/webSocket/WebSocketController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/CardVerifyRequest.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysDoorDeviceDetailRequest.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorMachineDetailRequest.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/enums/VerifyResultEnum.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/EmployeeVerifyService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDoorDeviceService.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitAreaService.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EmployeeVerifyServiceImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDoorDeviceServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/IndexLookDataVo.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/PositioningDetailVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitAreaVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorConfigVO.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TAppUserDetailVO.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TAppUserPageVo.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionAssignRuleVO.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionReassignVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionVO.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java
New file
@@ -0,0 +1,39 @@
package com.ruoyi.web.controller.api;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.dto.CardVerifyRequest;
import com.ruoyi.system.service.EmployeeVerifyService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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 javax.annotation.Resource;
import javax.validation.Valid;
/**
 * 接待人(被访者)刷卡验证接口。
 * 数据源:t_employee 员工管理表(含内部员工及已授权的外部人员)。
 */
@Api(tags = "接待人验证接口")
@RestController
@RequestMapping("/api/employee/verify")
public class EmployeeVerifyController extends BaseController {
    @Resource
    private EmployeeVerifyService employeeVerifyService;
    /**
     * 刷卡验证:现场读卡器读取卡号后调用本接口,与接待人绑定的卡号比对。
     */
    @PostMapping("/card")
    @ApiOperation(value = "接待人刷卡验证", notes = "根据传入的卡号与接待人(employeeId)绑定的卡号进行比对,"
            + "仅对启用且未删除的接待人生效")
    public AjaxResult verifyByCard(@RequestBody @Valid CardVerifyRequest request) {
        return employeeVerifyService.verifyByCard(request);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java
New file
@@ -0,0 +1,54 @@
package com.ruoyi.web.controller.api;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.dto.*;
import com.ruoyi.system.service.ISysVisitorMachineService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.validation.Valid;
/**
 * 访客机设备激活/注销
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/api/visitmachine")
@Api(tags = "访客机设备激活、注销" , value = "访客机设备激活、注销")
public class SysApiDoorMachineController extends BaseController
{
    @Autowired
    private ISysVisitorMachineService visitorMachineService;
    /**
     * 激活设备
     */
    @Log(title = "访客机设备", businessType = BusinessType.UPDATE)
    @PostMapping("/activate")
    @ApiOperation(value = "激活访客机设备")
    public AjaxResult activate(@Valid @RequestBody SysVisitorMachineDetailRequest request) {
        int result = visitorMachineService.activateDevice(request.getMachineId());
        return result > 0 ? success("设备激活成功") : error("设备激活失败");
    }
    /**
     * 注销设备
     */
    @Log(title = "访客机设备", businessType = BusinessType.UPDATE)
    @PostMapping("/deactivate")
    @ApiOperation(value = "注销访客机设备")
    public AjaxResult deactivate(@Valid @RequestBody SysVisitorMachineDetailRequest request) {
        int result = visitorMachineService.deactivateDevice(request.getMachineId());
        return result > 0 ? success("设备注销成功") : error("设备注销失败");
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiVisitAreaController.java
New file
@@ -0,0 +1,56 @@
package com.ruoyi.web.controller.api;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.dto.*;
import com.ruoyi.system.service.ISysVisitAreaService;
import com.ruoyi.system.vo.SysVisitAreaVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
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.List;
/**
 * 访问区域管理接口
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/api/visitArea")
@Api(tags = "访问区域管理")
public class SysApiVisitAreaController extends BaseController
{
    @Autowired
    private ISysVisitAreaService visitAreaService;
    /**
     * 查询访问区域树
     */
    @ApiOperation(
            value = "查询访问区域树",
            notes = "返回所有访问区域树形结构",
            response = SysVisitAreaVO.class,
            responseContainer = "List"
    )
    @ApiResponses({
            @ApiResponse(
                    code = 200,
                    message = "成功",
                    response = AjaxResult.class,
                    responseContainer = "List"
            )
    })
    @PostMapping("/tree")
    public AjaxResult<List<SysVisitAreaVO>> tree() {
        return success(visitAreaService.tree(null));
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java
New file
@@ -0,0 +1,105 @@
package com.ruoyi.web.controller.api;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.system.domain.SysVisitorRecord;
import com.ruoyi.system.dto.SysVisitorRecordAddRequest;
import com.ruoyi.system.dto.SysVisitorRecordPageRequest;
import com.ruoyi.system.mapper.SysVisitorRecordMapper;
import com.ruoyi.system.service.ISysVisitorRecordService;
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.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;
@RestController
@RequestMapping("/api/visitorRecord")
@Api(tags = "访客登记")
public class SysApiVisitorRecordController extends BaseController {
    @Autowired
    private SysVisitorRecordMapper visitorRecordMapper;
    @PostMapping("/add")
    @ApiOperation(value = "访客登记", notes = "现场访客登记")
    public AjaxResult add(
            @RequestBody
            @ApiParam(value = "访客登记信息", required = true)
            SysVisitorRecordAddRequest request) {
        // ================= 参数校验 =================
        if (StringUtils.isBlank(request.getVisitorName())) {
            return AjaxResult.error("访客姓名不能为空");
        }
        if (StringUtils.isBlank(request.getIntervieweeName())) {
            return AjaxResult.error("被访人不能为空");
        }
        if (StringUtils.isNotBlank(request.getIdCard())) {
            LambdaQueryWrapper<SysVisitorRecord> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(SysVisitorRecord::getIdCard, request.getIdCard())
                    .eq(SysVisitorRecord::getDelFlag, "0")
                    .in(SysVisitorRecord::getStatus,
                            "VISITING",
                            "PENDING_CONFIRM")
                    .last("limit 1");
            SysVisitorRecord oldRecord = visitorRecordMapper.selectOne(wrapper);
            if (oldRecord != null) {
                return AjaxResult.error("该访客当前已有未结束的登记,请勿重复登记");
            }
        }
        // ================= 保存 =================
        SysVisitorRecord record = new SysVisitorRecord();
        BeanUtils.copyProperties(request, record);
        record.setRegisterNo(generateRegisterNo());
        record.setRegisterType("ONSITE");
        record.setRegisterSource("访客机");
        record.setStatus("VISITING");
        record.setRegisterTime(new Date());
        record.setDelFlag("0");
        int rows = visitorRecordMapper.insert(record);
        if (rows > 0) {
            return AjaxResult.success(record.getRegisterNo());
        }
        return AjaxResult.error("登记失败");
    }
    /**
     * 生成登记编号
     * 格式:
     * VIS + 年月日 + 6位随机数
     * 例如:
     * VIS20260707123456
     */
    private String generateRegisterNo() {
        String date =
                new java.text.SimpleDateFormat("yyyyMMddHHmmss")
                        .format(new Date());
        String random =
                String.valueOf((int)((Math.random() * 900000) + 100000));
        return "VIS" + date + random;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorConfigController.java
@@ -6,6 +6,12 @@
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.dto.SysVisitorConfigSaveRequest;
import com.ruoyi.system.service.ISysVisitorConfigService;
import com.ruoyi.system.vo.SysVisitorConfigVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
@@ -20,6 +26,7 @@
 */
@RestController
@RequestMapping("/system/visitor/config")
@Api(tags = "访客系统配置接口")
public class SysVisitorConfigController extends BaseController
{
    @Autowired
@@ -31,9 +38,15 @@
    @Log(title = "访客系统配置", businessType = BusinessType.SELECT)
    @PreAuthorize("@ss.hasPermi('visitor:config:view')")
    @PostMapping("/detail")
    public AjaxResult detail()
    @ApiOperation(value = "查询访客系统配置")
    @ApiResponses({
            @ApiResponse(
                    code = 200, message = "查询成功", response = SysVisitorConfigVO.class, responseContainer = "Data"  // 指定数据在 data 字段中
            )
    })
    public AjaxResult<SysVisitorConfigVO> detail()
    {
        return success(visitorConfigService.selectConfig());
        return AjaxResult.success(visitorConfigService.selectConfig());
    }
    /**
@@ -42,8 +55,13 @@
    @Log(title = "访客系统配置", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('visitor:config:edit')")
    @PostMapping("/save")
    @ApiOperation(
            value = "设置访客系统配置",
            response = AjaxResult.class
    )
    public AjaxResult save(@RequestBody SysVisitorConfigSaveRequest request)
    {
        return success(visitorConfigService.saveConfig(request, getUsername()));
        visitorConfigService.saveConfig(request, getUsername());
        return success();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -4,6 +4,9 @@
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,6 +31,7 @@
 */
@RestController
@RequestMapping("/common")
@Api(tags = "图片上传接口")
public class CommonController
{
    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@@ -73,6 +77,7 @@
     * 通用上传请求(单个)
     */
    @PostMapping("/upload")
    @ApiOperation(value = "上传图片 MultipartFile file")
    public AjaxResult uploadFile(MultipartFile file) throws Exception
    {
        try
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -10,7 +10,6 @@
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.system.dto.SysRoleDTO;
import com.ruoyi.system.query.SysRoleQuery;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.vo.RoleInfoVO;
@@ -148,54 +147,6 @@
    public AjaxResult roleInfoFromUserId(@RequestParam Long userId)
    {
        return AjaxResult.success(roleService.roleInfoFromUserId(userId));
    }
    /**
     * 新增角色
     */
//    @PreAuthorize("@ss.hasPermi('system:role:add')")
    @ApiOperation(value = "新增角色")
    @Log(title = "角色信息-新增角色", businessType = BusinessType.INSERT)
    @PostMapping("/system/role/add")
    public AjaxResult add(@Validated @RequestBody SysRoleDTO dto)
    {
        Boolean flag= roleService.isExit(dto.getRoleId(),dto.getRoleName());
        if(flag){
            return error("新增角色'" + dto.getRoleName() + "'失败,角色名称已存在");
        }
        roleService.saveRole(dto);
        return AjaxResult.success();
    }
    /**
     * 修改保存角色
     */
//    @PreAuthorize("@ss.hasPermi('system:role:edit')")
    @ApiOperation(value = "编辑角色",response = SysRoleDTO.class)
    @Log(title = "角色信息-编辑角色", businessType = BusinessType.UPDATE)
    @PostMapping("/api/system/role/edit")
    public R<String> edit(@RequestBody String param)
    {
        SysRoleDTO dto = JSON.parseObject(param, SysRoleDTO.class);
        Boolean flag= roleService.isExit(dto.getRoleId(),dto.getRoleName());
        if (flag){
            return R.fail("修改角色'" + dto.getRoleName() + "'失败,角色名称已存在");
        }
        if (roleService.editRole(dto) > 0)
        {
            // 更新缓存用户权限
            LoginUser loginUser = getLoginUser();
            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
            {
                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
                tokenService.setLoginUser(loginUser);
            }
            return R.ok();
        }
        return R.fail("修改角色'" + dto.getRoleName() + "'失败,请联系管理员");
    }
    /**
ruoyi-admin/src/main/java/com/ruoyi/web/controller/task/TaskUtil.java
File was deleted
ruoyi-applet/src/main/java/com/ruoyi/web/controller/webSocket/WebSocketAuthHandler.java
@@ -3,8 +3,6 @@
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUserApplet;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.service.TAppUserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
@@ -23,9 +21,7 @@
@Slf4j
public class WebSocketAuthHandler {
    @Autowired
    private TAppUserService appUserService;
    @Autowired
    private RedisCache redisCache;
    
@@ -33,48 +29,7 @@
    @Value("${token.secret}")
    private String secret;
    /**
     * 验证用户认证信息
     * @param appUserId 用户ID
     * @param token 认证令牌(可选)
     * @return 认证结果
     */
    public AuthResult authenticateUser(String appUserId, String token) {
        try {
            if (appUserId == null || appUserId.trim().isEmpty()) {
                return AuthResult.failure("用户ID不能为空");
            }
            // 查询用户信息
            TAppUser appUser = appUserService.getById(appUserId);
            if (appUser == null) {
                return AuthResult.failure("用户不存在");
            }
            // 检查用户状态
            if (appUser.getStatus() == null || appUser.getStatus() != 1) {
                return AuthResult.failure("用户已被禁用");
            }
            // 检查用户审核状态
            if (appUser.getState() == null || appUser.getState() != 1) {
                return AuthResult.failure("用户未通过审核");
            }
            // 这里可以添加token验证逻辑
            if (token != null && !token.trim().isEmpty()) {
                // 验证token的有效性
                if (!validateToken(appUserId, token)) {
                    return AuthResult.failure("认证令牌无效");
                }
            }
            return AuthResult.success(appUser);
        } catch (Exception e) {
            log.error("用户认证失败,用户ID: {}, 错误: {}", appUserId, e.getMessage(), e);
            return AuthResult.failure("认证过程中发生错误: " + e.getMessage());
        }
    }
    /**
     * 验证token
@@ -165,40 +120,7 @@
        return com.ruoyi.common.constant.CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }
    /**
     * 认证结果类
     */
    public static class AuthResult {
        private final boolean success;
        private final String message;
        private final TAppUser appUser;
        private AuthResult(boolean success, String message, TAppUser appUser) {
            this.success = success;
            this.message = message;
            this.appUser = appUser;
        }
        public static AuthResult success(TAppUser appUser) {
            return new AuthResult(true, "认证成功", appUser);
        }
        public static AuthResult failure(String message) {
            return new AuthResult(false, message, null);
        }
        public boolean isSuccess() {
            return success;
        }
        public String getMessage() {
            return message;
        }
        public TAppUser getAppUser() {
            return appUser;
        }
    }
    /**
     * 从认证消息中提取用户信息
ruoyi-applet/src/main/java/com/ruoyi/web/controller/webSocket/WebSocketController.java
@@ -3,7 +3,7 @@
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.model.TMissionReassign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@@ -38,7 +38,7 @@
     * @return 操作结果
     */
    @PostMapping("/user/send/{appUserId}")
    @ApiOperation(value = "发送信息", response = TMissionReassign.class)
    @ApiOperation(value = "发送信息")
    public R<String> sendMessageToUser(@PathVariable String appUserId, @RequestBody Map<String, String> request) {
        try {
            String message = JSONObject.toJSONString(request);
@@ -59,7 +59,7 @@
    }
    @GetMapping("/user/send1/{appUserId}")
    @ApiOperation(value = "发送信息", response = TMissionReassign.class)
    @ApiOperation(value = "发送信息")
    public R<String> sendMessageToUser1(@PathVariable String appUserId) {
        try {
            String message = "{\"type\":\"mission_push\",\"content\":\"{\\\"missionId\\\":\\\"1983875114637811713\\\"}\",\"timestamp\":\"2025-10-27T09:22:45.681\"}";
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -112,11 +112,11 @@
                .authorizeRequests()
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                .antMatchers("/getPrivacyAgreement/{agreementType}",
                        "/applet/queryProtocolConfigByType","/api/loginApp",
                        "/applet/queryProtocolConfigByType","/api/loginApp","/common/upload",
                        "/api/login","/api/middle-platform/login","/open/login","/applet/queryProtocolConfigByType",
                        "/register","/applet/getCode","/applet/loginCode",
                        "/applet/changepwd", "/captchaImage","/getCode","/loginCode",
                        "/operations/getBySingleNum/**",
                        "/operations/getBySingleNum/**","/api/**","/system/visitor/config/**",
                        "/user/getUserInfoByNumber/**","/open/t-app-user/test",
                        "/wxLogin/**","/cos/get/**","/t-mission/**","/api/t-app-user/**","/open/file/**","/open/t-data-statistics/**","/open/pushMessageSolo/**",
                        "/open/t-mission/sendMission","/open/websocket/**"
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -18,10 +18,9 @@
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TAppUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
@@ -57,8 +56,6 @@
    private ISysConfigService configService;
    @Autowired
    private SysPermissionService permissionService;
    @Autowired
    private TAppUserService appUserService;
    public LoginUser loginByTrustedUsername(String username, String loginSource, String middlePlatformToken)
    {
@@ -154,18 +151,7 @@
        }
        // 用户验证
        Authentication authentication = null;
        // 用户验证
        TAppUser appUser = appUserService.getOne(Wrappers.<TAppUser>lambdaQuery().eq(TAppUser::getAccount,account));
        if (StringUtils.isNull(appUser)){
            log.info("登录用户:{} 不存在.", account);
            throw new ServiceException(MessageUtils.message("user.not.exists"));
        } else if (appUser.getDisabled()) {
            log.info("登录用户:{} 已被删除.", account);
            throw new ServiceException(MessageUtils.message("user.password.delete"));
        } else if (2 == appUser.getStatus()) {
            log.info("登录用户:{} 已被停用.", account);
            throw new ServiceException(MessageUtils.message("user.blocked"));
        }
        try
        {
            String userName = account + "_2";
@@ -360,8 +346,6 @@
     */
    public void recordAppLoginInfo(String userId)
    {
        TAppUser appUser = new TAppUser();
        appUser.setId(userId);
//        sysUser.setLoginIp(IpUtils.getIpAddr());
//        sysUser.setLoginDate(DateUtils.getNowDate());
//        userService.updateUserProfile(sysUser);
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
@@ -11,7 +11,6 @@
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
import com.ruoyi.system.model.TAppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
@@ -80,45 +79,8 @@
            clearLoginRecordCache(username);
        }
    }
    public void validateApp(TAppUser user)
    {
        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
        String username = usernamePasswordAuthenticationToken.getName();
        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
        Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
        if (retryCount == null)
        {
            retryCount = 0;
        }
        if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
        {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
                    MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime)));
            throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
        }
        if (!matchesApp(user, password))
        {
            retryCount = retryCount + 1;
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
                    MessageUtils.message("user.password.retry.limit.count", retryCount)));
            redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
            throw new UserPasswordNotMatchException();
        }
        else
        {
            clearLoginRecordCache(username);
        }
    }
    public boolean matches(SysUser user, String rawPassword)
    {
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
    }
    public boolean matchesApp(TAppUser user, String rawPassword)
    {
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
    }
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
@@ -9,9 +9,7 @@
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.TAppUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
@@ -34,9 +32,6 @@
    @Autowired
    private ISysUserService userService;
    @Autowired
    private TAppUserService appUserService;
    @Autowired
    private SysPasswordService passwordService;
    @Autowired
@@ -47,52 +42,27 @@
    {
        String[] split = username.split("_");
        username = split[0];
        String type = split[1];
        if("1".equals(type)){
            SysUser user = userService.selectUserByUserName(username);
            if (StringUtils.isNull(user))
            {
                log.info("登录用户:{} 不存在.", username);
                throw new ServiceException(MessageUtils.message("user.not.exists"));
            }
            else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
            {
                log.info("登录用户:{} 已被删除.", username);
                throw new ServiceException(MessageUtils.message("user.password.delete"));
            }
            else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
            {
                log.info("登录用户:{} 已被停用.", username);
                throw new ServiceException(MessageUtils.message("user.blocked"));
            }
            passwordService.validate(user);
            return createLoginUser(user);
        }else {
            TAppUser user = appUserService.getOne(Wrappers.<TAppUser>lambdaQuery().eq(TAppUser::getAccount,username));
            if (StringUtils.isNull(user))
            {
                log.info("登录用户:{} 不存在.", username);
                throw new ServiceException(MessageUtils.message("user.not.exists"));
            }
            else if (user.getDisabled())
            {
                log.info("登录用户:{} 已被删除.", username);
                throw new ServiceException(MessageUtils.message("user.password.delete"));
            }
            else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
            {
                log.info("登录用户:{} 已被停用.", username);
                throw new ServiceException(MessageUtils.message("user.blocked"));
            }
            passwordService.validateApp(user);
            TAppUserResp appUserResp = new TAppUserResp();
            BeanUtils.copyProperties(user,appUserResp);
            return createLoginUserApp(appUserResp);
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user))
        {
            log.info("登录用户:{} 不存在.", username);
            throw new ServiceException(MessageUtils.message("user.not.exists"));
        }
        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
        {
            log.info("登录用户:{} 已被删除.", username);
            throw new ServiceException(MessageUtils.message("user.password.delete"));
        }
        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
        {
            log.info("登录用户:{} 已被停用.", username);
            throw new ServiceException(MessageUtils.message("user.blocked"));
        }
        passwordService.validate(user);
        return createLoginUser(user);
    }
    public UserDetails createLoginUser(SysUser user)
ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java
New file
@@ -0,0 +1,45 @@
package com.ruoyi.system.domain;
import java.time.LocalDateTime;
import lombok.Data;
/**
 * 员工实体(对应 t_employee 表)
 */
@Data
public class Employee {
    private Long employeeId;
    private Long deptId;
    private String employeeName;
    private String employeeNo;
    private String contactPhoneCipher;
    private String contactPhoneHash;
    /** EMPLOYEE员工 / DEPT_MANAGER部门负责人 */
    private String position;
    /** 绑定卡号,可能为空 */
    private String cardNo;
    private String faceImage;
    private Boolean enabled;
    /** 0正常 1删除 */
    private String delFlag;
    private String createBy;
    private LocalDateTime createTime;
    private String updateBy;
    private LocalDateTime updateTime;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/CardVerifyRequest.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.system.dto;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * 刷卡验证请求:
 * employeeId 为业务上下文中已确定的"接待人"(如访客预约单/登记时选定的被访者);
 * cardNo 为现场读卡器读取到的卡号原文。
 */
@Data
@ApiModel(value = "CardVerifyRequest", description = "接待人刷卡验证请求")
public class CardVerifyRequest {
    @ApiModelProperty(value = "现场读卡器读取到的卡号原文", required = true, example = "0123456789")
    @NotBlank(message = "卡号不能为空")
    private String cardNo;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysDoorDeviceDetailRequest.java
@@ -3,6 +3,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
 * 门禁设备详情请求
 *
@@ -11,7 +13,10 @@
@Data
public class SysDoorDeviceDetailRequest
{
    /** 门禁设备主键 */
    /**
     * 门禁设备主键
     */
    @ApiModelProperty("门禁设备主键")
    @NotBlank(message = "设备ID不能为空")
    private Long doorId;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorMachineDetailRequest.java
@@ -3,6 +3,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
 * 访客机详情请求
 *
@@ -13,5 +15,6 @@
{
    /** 访客机主键 */
    @ApiModelProperty("访客机主键")
    @NotNull(message = "设备ID不能为空")
    private Long machineId;
}
ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java
New file
@@ -0,0 +1,86 @@
package com.ruoyi.system.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import java.util.Date;
/**
 * 访客登记
 *
 * @author ruoyi
 */
@Data
@ApiModel(value = "SysVisitorRecordAddRequest", description = "访客登记")
public class SysVisitorRecordAddRequest
{
    /**
     * 访客姓名
     */
    @NotBlank(message = "访客姓名不能为空")
    @ApiModelProperty(value = "访客姓名")
    private String visitorName;
    /**
     * 访客身份证号
     */
    @NotBlank(message = "访客身份证号不能为空")
    @ApiModelProperty(value = "访客身份证号")
    private String idCard;
    /**
     * 被访人
     */
    @NotBlank(message = "被访人不能为空")
    @ApiModelProperty(value = "被访人")
    private String intervieweeName;
    /**
     * 接待人验证方式
     */
    @ApiModelProperty(value = "接待人验证方式")
    private String receiverVerifyMethod;
    /**
     * 访问区域ID,英文逗号分隔
     */
    @ApiModelProperty(value = "访问区域ID,英文逗号分隔")
    private String visitAreaIds;
    /**
     * 车牌号
     */
    @ApiModelProperty(value = "车牌号")
    private String plateNo;
    /**
     * 来访事由
     */
    @ApiModelProperty(value = "来访事由")
    private String visitReason;
    /**
     * 有效期开始时间
     */
    @ApiModelProperty(value = "有效期开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date validStartTime;
    /**
     * 有效期结束时间
     */
    @ApiModelProperty(value = "有效期结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date validEndTime;
    /**
     * 访客人像地址
     */
    @ApiModelProperty(value = "访客人像地址")
    private String faceImageUrl;
}
ruoyi-system/src/main/java/com/ruoyi/system/enums/VerifyResultEnum.java
New file
@@ -0,0 +1,32 @@
package com.ruoyi.system.enums;
/**
 * 接待人刷卡验证结果码
 */
public enum VerifyResultEnum {
    SUCCESS( "验证通过"),
    PARAM_INVALID( "请求参数不合法"),
    /** 不存在 / 已停用 / 已删除统一走这个码,避免向前端泄露具体是哪种情况 */
    RECEPTIONIST_UNAVAILABLE( "接待人不存在或已停用"),
    CARD_NOT_BOUND( "该接待人尚未绑定卡号,请联系管理员"),
    CARD_NOT_MATCH( "卡号与接待人不匹配,请核实后重试"),
    VERIFY_LOCKED( "验证失败次数过多,请稍后重试或联系前台"),
    SYSTEM_ERROR( "系统繁忙,请稍后重试");
    private final String message;
    VerifyResultEnum(String message) {
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java
New file
@@ -0,0 +1,16 @@
package com.ruoyi.system.mapper;
import com.ruoyi.system.domain.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface EmployeeMapper {
    /**
     * 按主键查询启用且未删除的接待人。
     * 若返回 null,说明该员工不存在 / 已停用 / 已删除中的某一种情况(SQL 层已合并过滤)。
     */
    Employee selectEnabledByCardNo(@Param("cardNo") String cardNo);
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java
@@ -1,6 +1,8 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.system.domain.SysVisitorRecord;
import com.ruoyi.system.dto.SysVisitorRecordPageRequest;
import com.ruoyi.system.vo.SysVisitorPassRecordVO;
import com.ruoyi.system.vo.SysVisitorRecordDetailVO;
@@ -16,7 +18,7 @@
 * @author ruoyi
 */
@Mapper
public interface SysVisitorRecordMapper
public interface SysVisitorRecordMapper extends BaseMapper<SysVisitorRecord>
{
    public List<SysVisitorRecordVO> pageList(@Param("query") SysVisitorRecordPageRequest query,
                                             @Param("pageInfo") PageInfo<SysVisitorRecordVO> pageInfo);
@@ -26,4 +28,6 @@
    public List<SysVisitorPassRecordVO> selectPassRecordsByRecordId(Long recordId);
    public int deleteByIds(@Param("recordIds") List<Long> recordIds, @Param("updateBy") String updateBy);
    public int insert(SysVisitorRecord record);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/EmployeeVerifyService.java
New file
@@ -0,0 +1,13 @@
package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.dto.CardVerifyRequest;
public interface EmployeeVerifyService {
    /**
     * 刷卡验证:比对现场读到的卡号与该接待人绑定的卡号是否一致。
     */
    AjaxResult verifyByCard(CardVerifyRequest request);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDoorDeviceService.java
@@ -30,4 +30,5 @@
    public int logout(SysDoorDeviceLogoutRequest request, String username);
    public int delete(SysDoorDeviceDeleteRequest request, String username);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
@@ -7,7 +7,6 @@
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.dto.SysRoleDTO;
import com.ruoyi.system.query.SysRoleQuery;
/**
@@ -221,17 +220,7 @@
    String selectByUserId(Long user_id);
    void saveRole(SysRoleDTO dto);
    PageInfo<SysRole> selectPageList(SysRoleQuery query);
    /**
     * 修改保存角色信息
     *
     * @param dto 角色信息
     * @return 结果
     */
    public int editRole(SysRoleDTO dto);
    List<SysRole> selectRoleByUserIds(List<String> roleIds);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitAreaService.java
@@ -25,4 +25,5 @@
    public int edit(SysVisitAreaEditRequest request, String username);
    public int delete(SysVisitAreaDeleteRequest request, String username);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java
@@ -30,4 +30,20 @@
    public int logout(SysVisitorMachineLogoutRequest request, String username);
    public int delete(SysVisitorMachineDeleteRequest request, String username);
    /**
     * 激活设备
     *
     * @param deviceId 设备ID
     * @return 影响行数
     */
    int activateDevice(Long deviceId);
    /**
     * 注销设备
     *
     * @param deviceId 设备ID
     * @return 影响行数
     */
    int deactivateDevice(Long deviceId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EmployeeVerifyServiceImpl.java
New file
@@ -0,0 +1,62 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.Employee;
import com.ruoyi.system.dto.CardVerifyRequest;
import com.ruoyi.system.enums.VerifyResultEnum;
import com.ruoyi.system.mapper.EmployeeMapper;
import com.ruoyi.system.service.EmployeeVerifyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class EmployeeVerifyServiceImpl implements EmployeeVerifyService {
    private static final Logger log = LoggerFactory.getLogger(EmployeeVerifyServiceImpl.class);
    @Resource
    private EmployeeMapper employeeMapper;
    // TODO: 注入验证日志Mapper / Redis,用于失败次数统计与锁定(见 recordAndReturn 方法说明)
    @Override
    public AjaxResult verifyByCard(CardVerifyRequest request) {
        Employee employee = employeeMapper.selectEnabledByCardNo(request.getCardNo());
        if (employee == null) {
            return recordAndReturn(VerifyResultEnum.RECEPTIONIST_UNAVAILABLE);
        }
        String boundCardNo = employee.getCardNo();
        if (boundCardNo == null || boundCardNo.trim().isEmpty()) {
            return recordAndReturn(VerifyResultEnum.CARD_NOT_BOUND);
        }
        String inputCardNo = request.getCardNo() == null ? "" : request.getCardNo().trim();
        if (!boundCardNo.trim().equalsIgnoreCase(inputCardNo)) {
            return recordAndReturn(VerifyResultEnum.CARD_NOT_MATCH);
        }
        return recordAndReturn(VerifyResultEnum.SUCCESS);
    }
    /**
     * 统一出口:记录验证流水(成功/失败均记录)并返回结果。
     * TODO: 落库到 t_employee_verify_log(建表脚本见 sql/verify_log.sql),字段建议包含:
     *       employee_id, result_code, client_ip, device_no, create_time。
     * TODO: 结合 Redis 按 employeeId + 来源IP/设备号 做滑动窗口计数,连续失败N次后返回
     *       VERIFY_LOCKED 并锁定一段时间,防止对某个接待人反复试卡的暴力破解/撞库。
     */
    private AjaxResult recordAndReturn(VerifyResultEnum result) {
        if (VerifyResultEnum.SUCCESS.equals(result)) {
            log.info("接待人刷卡验证成功");
            return AjaxResult.success();
        }
        log.warn("接待人刷卡验证失败,  result={}", result.getMessage());
        return AjaxResult.error(result.getMessage());
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDoorDeviceServiceImpl.java
@@ -18,8 +18,10 @@
import com.ruoyi.system.vo.SysDoorDeviceVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.Date;
import java.util.List;
/**
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -12,7 +12,6 @@
import com.ruoyi.system.domain.SysRoleDept;
import com.ruoyi.system.domain.SysRoleMenu;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.dto.SysRoleDTO;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.query.SysRoleQuery;
import com.ruoyi.system.service.ISysRoleService;
@@ -557,57 +556,11 @@
    }
    @Override
    public void saveRole(SysRoleDTO dto) {
        // 添加角色
        SysRole sysRole = new SysRole();
        sysRole.setRoleName(dto.getRoleName());
        sysRole.setPostType(dto.getPostType());
        sysRole.setRemark(dto.getRemark());
        roleMapper.insertRole(sysRole);
        // 添加角色权限中间表
        List<Long> menuIds = dto.getMenuIds();
        List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
        for (Long menuId : menuIds) {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(sysRole.getRoleId());
            sysRoleMenu.setMenuId(menuId);
            sysRoleMenus.add(sysRoleMenu);
        }
        roleMenuMapper.batchRoleMenu(sysRoleMenus);
    }
    @Override
    public PageInfo<SysRole> selectPageList(SysRoleQuery query) {
        PageInfo<SysRole> pageInfo = new PageInfo<>(query.getPageNum(), query.getPageSize());
        List<SysRole> list = roleMapper.selectPageList(query,pageInfo);
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public int editRole(SysRoleDTO dto) {
        // 修改角色信息
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(dto.getRoleId());
        sysRole.setRoleName(dto.getRoleName());
        sysRole.setPostType(dto.getPostType());
        sysRole.setRemark(dto.getRemark());
        roleMapper.updateRole(sysRole);
        // 删除角色与菜单关联
        roleMenuMapper.deleteRoleMenuByRoleId(dto.getRoleId());
        // 添加角色权限中间表
        List<Long> menuIds = dto.getMenuIds();
        List<SysRoleMenu> sysRoleMenus = new ArrayList<>();
        for (Long menuId : menuIds) {
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setRoleId(dto.getRoleId());
            sysRoleMenu.setMenuId(menuId);
            sysRoleMenus.add(sysRoleMenu);
        }
        return roleMenuMapper.batchRoleMenu(sysRoleMenus);
    }
    @Override
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java
@@ -13,6 +13,7 @@
import com.ruoyi.system.vo.SysVisitAreaVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java
@@ -3,6 +3,7 @@
import com.ruoyi.common.basic.PageInfo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysDoorDevice;
import com.ruoyi.system.domain.SysVisitArea;
import com.ruoyi.system.domain.SysVisitorMachine;
import com.ruoyi.system.dto.SysVisitorMachineAddRequest;
@@ -18,8 +19,10 @@
import com.ruoyi.system.vo.SysVisitorMachineVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.Date;
import java.util.List;
/**
@@ -148,6 +151,57 @@
        return machine;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int activateDevice(Long deviceId) {
        // 1. 根据deviceId查询设备
        SysVisitorMachine device = visitorMachineMapper.selectById(deviceId);
        if (device == null || device.getDelFlag().equals("1")) {
            throw new ServiceException("设备不存在,请先添加设备");
        }
        // 2. 检查是否已激活
        if ("ONLINE".equals(device.getOnlineStatus()) || "ACTIVATED".equals(device.getOnlineStatus())) {
            throw new ServiceException("设备已激活,无需重复操作");
        }
        // 3. 检查设备是否启用
        if (device.getEnabled() == null || !device.getEnabled()) {
            throw new ServiceException("设备未启用,请先在后台启用设备");
        }
        // 4. 更新状态为激活/在线
        SysVisitorMachine update = new SysVisitorMachine();
        update.setMachineId(device.getMachineId());
        update.setOnlineStatus("ONLINE");  // 或 "ACTIVATED",根据你的枚举定义
        update.setUpdateTime(new Date());
        return visitorMachineMapper.updateMachine(update);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deactivateDevice(Long deviceId) {
        // 1. 根据deviceId查询设备
        SysVisitorMachine device = visitorMachineMapper.selectById(deviceId);
        if (device == null || device.getDelFlag().equals("1")) {
            throw new ServiceException("设备不存在");
        }
        // 2. 检查是否已注销
        if ("OFFLINE".equals(device.getOnlineStatus()) || "UNACTIVATED".equals(device.getOnlineStatus())) {
            throw new ServiceException("设备已注销,无需重复操作");
        }
        // 3. 更新状态为离线/未激活
        SysVisitorMachine update = new SysVisitorMachine();
        update.setMachineId(deviceId);
        update.setOnlineStatus("OFFLINE");  // 或 "UNACTIVATED"
        update.setUpdateTime(new Date());
        return visitorMachineMapper.updateMachine(update);
    }
    private Long getRequiredAreaId(Long areaId)
    {
        if (areaId == null || areaId <= 0)
ruoyi-system/src/main/java/com/ruoyi/system/vo/IndexLookDataVo.java
@@ -1,6 +1,5 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TMission;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -20,10 +19,6 @@
    @ApiModelProperty("一般任务数")
    private Integer regularMissionNum=0;
    @ApiModelProperty("带指派任务")
    private List<TMission> missions;
    @ApiModelProperty("用户信息")
    private List<IndexLookDataUserVo> userInfos;
ruoyi-system/src/main/java/com/ruoyi/system/vo/PositioningDetailVO.java
@@ -1,13 +1,12 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TAppUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "人员分布轨迹详情PositioningDetailVO")
public class PositioningDetailVO extends TAppUser {
public class PositioningDetailVO {
    @ApiModelProperty(value = "轨迹")
    private String realTimePositioning;
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitAreaVO.java
@@ -1,6 +1,7 @@
package com.ruoyi.system.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -14,6 +15,7 @@
 * @author ruoyi
 */
@Data
@ApiModel(value = "SysVisitAreaVO", description = "访问区域")
public class SysVisitAreaVO
{
    /** 区域主键 */
ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorConfigVO.java
@@ -1,5 +1,7 @@
package com.ruoyi.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@@ -10,35 +12,52 @@
 * @author ruoyi
 */
@Data
@ApiModel(value = "访客系统配置返回对象", description = "访客系统的全部配置信息")
public class SysVisitorConfigVO
{
    @ApiModelProperty(value = "配置主键ID", example = "1")
    private Long configId;
    @ApiModelProperty(value = "现场登记开关", example = "true", allowableValues = "true,false")
    private Boolean onsiteRegistrationEnabled;
    @ApiModelProperty(value = "预约登记开关", example = "true", allowableValues = "true,false")
    private Boolean appointmentRegistrationEnabled;
    @ApiModelProperty(value = "登记需接待人确认", example = "true", allowableValues = "true,false")
    private Boolean registerReceiverConfirmEnabled;
    @ApiModelProperty(value = "签离需接待人确认", example = "true", allowableValues = "true,false")
    private Boolean signReceiverConfirmEnabled;
    @ApiModelProperty(value = "人像对比开关", example = "true", allowableValues = "true,false")
    private Boolean faceCompareEnabled;
    @ApiModelProperty(value = "全方位人脸采集开关", example = "true", allowableValues = "true,false")
    private Boolean faceCaptureEnabled;
    @ApiModelProperty(value = "允许手动输入身份证", example = "true", allowableValues = "true,false")
    private Boolean manualIdCardEnabled;
    @ApiModelProperty(value = "凭条打印字段列表(按顺序打印)",
            example = "visitorName,idCard,appointmentTimeRange,interviewee   '凭条打印字段,英文逗号分隔并按顺序打印‘ ")
    private List<String> printFields;
    @ApiModelProperty(value = "打印字段选项列表(前端展示用)")
    private List<PrintFieldOptionVO> printFieldOptions;
    @ApiModelProperty(value = "系统名称", example = "自主访客登记管理平台")
    private String systemName;
    @ApiModelProperty(value = "Logo图片地址", example = "https://example.com/logo.png")
    private String logoUrl;
    @ApiModelProperty(value = "服务厂家", example = "科世达科技有限公司")
    private String serviceProvider;
    @ApiModelProperty(value = "技术支持电话", example = "400-888-9999")
    private String supportPhone;
    @ApiModelProperty(value = "访客机管理入口开关", example = "true", allowableValues = "true,false")
    private Boolean visitorMachineEntryEnabled;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TAppUserDetailVO.java
@@ -1,8 +1,5 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.model.TAppUserSkill;
import com.ruoyi.system.model.TUserMajor;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -11,12 +8,6 @@
@Data
@ApiModel("人员管理详情TAppUserDetailVO")
public class TAppUserDetailVO extends TAppUser {
    @ApiModelProperty(value = "用户专业")
    private List<TUserMajor> userMajors;
    @ApiModelProperty(value = "用户职业技能")
    private TAppUserSkill appUserSkill;
public class TAppUserDetailVO {
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TAppUserPageVo.java
@@ -1,13 +1,12 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TAppUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("人员管理Vo")
public class TAppUserPageVo extends TAppUser {
public class TAppUserPageVo  {
    @ApiModelProperty(value = "分队名称")
    private String teamName;
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionAssignRuleVO.java
@@ -1,7 +1,5 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TMissionAssignRule;
import com.ruoyi.system.model.TMissionAssignRuleIndicator;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -10,9 +8,6 @@
@Data
@ApiModel(value = "TMissionAssignRuleVO对象", description = "任务指派规则视图对象")
public class TMissionAssignRuleVO extends TMissionAssignRule {
    @ApiModelProperty(value = "任务指派指标列表")
    private List<TMissionAssignRuleIndicator> missionAssignRuleIndicators;
public class TMissionAssignRuleVO {
}
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionReassignVO.java
@@ -1,13 +1,12 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TMissionReassign;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "任务支援、改派TMissionReassignVO")
public class TMissionReassignVO extends TMissionReassign {
public class TMissionReassignVO  {
    @ApiModelProperty(value = "负责人")
    private String chargePerson;
ruoyi-system/src/main/java/com/ruoyi/system/vo/TMissionVO.java
@@ -1,9 +1,5 @@
package com.ruoyi.system.vo;
import com.ruoyi.system.model.TAppUser;
import com.ruoyi.system.model.TMission;
import com.ruoyi.system.model.TMissionOperation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -12,7 +8,7 @@
@Data
@ApiModel(value = "任务管理对象TMissionVO")
public class TMissionVO extends TMission {
public class TMissionVO  {
    @ApiModelProperty(value = "负责人")
    private String chargePerson;
@@ -26,10 +22,5 @@
    @ApiModelProperty(value = "完成时间差")
    private Double finishTimePoor;
    @ApiModelProperty(value = "任务人员")
    private List<TAppUser> appUsers;
    @ApiModelProperty(value = "任务操作记录")
    private List<TMissionOperation> missionOperations;
}
ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml
New file
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.EmployeeMapper">
    <resultMap id="BaseResultMap" type="com.ruoyi.system.domain.Employee">
        <id column="employee_id" property="employeeId"/>
        <result column="dept_id" property="deptId"/>
        <result column="employee_name" property="employeeName"/>
        <result column="employee_no" property="employeeNo"/>
        <result column="contact_phone_cipher" property="contactPhoneCipher"/>
        <result column="contact_phone_hash" property="contactPhoneHash"/>
        <result column="position" property="position"/>
        <result column="card_no" property="cardNo"/>
        <result column="face_image" property="faceImage"/>
        <result column="enabled" property="enabled"/>
        <result column="del_flag" property="delFlag"/>
        <result column="create_by" property="createBy"/>
        <result column="create_time" property="createTime"/>
        <result column="update_by" property="updateBy"/>
        <result column="update_time" property="updateTime"/>
    </resultMap>
    <!-- 人脸图片不参与本接口逻辑,且 longtext 体积较大,列表中排除,减少不必要的数据传输 -->
    <sql id="Base_Column_List">
        employee_id, dept_id, employee_name, employee_no, contact_phone_cipher,
        contact_phone_hash, `position`, card_no, enabled, del_flag,
        create_by, create_time, update_by, update_time
    </sql>
    <select id="selectEnabledByCardNo" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM t_employee
        WHERE card_no = #{cardNo}
        AND enabled = 1
        AND del_flag = '0'
    </select>
</mapper>
ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml
@@ -152,4 +152,49 @@
            #{recordId}
        </foreach>
    </update>
    <insert id="insert"
            parameterType="com.ruoyi.system.domain.SysVisitorRecord"
            useGeneratedKeys="true"
            keyProperty="recordId">
        insert into t_visitor_record
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="registerNo != null">register_no,</if>
            <if test="visitorName != null">visitor_name,</if>
            <if test="idCard != null">id_card,</if>
            <if test="registerType != null">register_type,</if>
            <if test="intervieweeName != null">interviewee_name,</if>
            <if test="receiverVerifyMethod != null">receiver_verify_method,</if>
            <if test="visitAreaIds != null">visit_area_ids,</if>
            <if test="plateNo != null">plate_no,</if>
            <if test="visitReason != null">visit_reason,</if>
            <if test="validStartTime != null">valid_start_time,</if>
            <if test="validEndTime != null">valid_end_time,</if>
            <if test="status != null">status,</if>
            <if test="registerTime != null">register_time,</if>
            <if test="faceImageUrl != null">face_image_url,</if>
            <if test="delFlag != null">del_flag,</if>
            create_time
        </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="registerNo != null">#{registerNo},</if>
            <if test="visitorName != null">#{visitorName},</if>
            <if test="idCard != null">#{idCard},</if>
            <if test="registerType != null">#{registerType},</if>
            <if test="intervieweeName != null">#{intervieweeName},</if>
            <if test="receiverVerifyMethod != null">#{receiverVerifyMethod},</if>
            <if test="visitAreaIds != null">#{visitAreaIds},</if>
            <if test="plateNo != null">#{plateNo},</if>
            <if test="visitReason != null">#{visitReason},</if>
            <if test="validStartTime != null">#{validStartTime},</if>
            <if test="validEndTime != null">#{validEndTime},</if>
            <if test="status != null">#{status},</if>
            <if test="registerTime != null">#{registerTime},</if>
            <if test="faceImageUrl != null">#{faceImageUrl},</if>
            <if test="delFlag != null">#{delFlag},</if>
            now()
        </trim>
    </insert>
</mapper>