From 3ee306e4a8db75680960f5eb4eec9fb7d05b5f29 Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期五, 24 七月 2026 16:21:54 +0800
Subject: [PATCH] Merge branch 'master' into electron_dev

---
 ruoyi-ui/src/views/visitor-admin/record/detail.vue                                               |    4 
 ruoyi-admin/src/main/resources/application-test.yml                                              |    2 
 ruoyi-ui/src/views/visitor-admin/record/visitor.vue                                              |  113 +++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorRecord.java                         |   10 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java                          |    7 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/VisitorRegisterSyncService.java      |  191 ++++++
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSignOutDataService.java       |   14 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java                   |    6 
 ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorMachineVO.java                          |    2 
 ruoyi-ui/src/assets/styles/visitor-admin.scss                                                    |   53 -
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java       |  159 +++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorMachine.java                        |    3 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/api/ApiSysVisitorRecord.java                  |  102 +++
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordManageController.java |  169 ++++++
 ruoyi-ui/.env.production                                                                         |    2 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/ImageUtil.java                          |   62 +
 ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml                                 |    4 
 doc/sql/20260706_t_visitor_machine.sql                                                           |    1 
 visitor-admin-ui/pages/dashboard.html                                                            |    4 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java            |   19 
 ruoyi-ui/src/views/visitor-admin/system/version.vue                                              |    5 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorConfigServiceImpl.java        |    2 
 ruoyi-ui/src/views/visitor-admin/organization/employee.vue                                       |   18 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java               |    2 
 visitor-admin-ui/pages/platform-admin.html                                                       |    4 
 ruoyi-system/src/main/resources/mapper/system/SysVisitAreaMapper.xml                             |   10 
 visitor-admin-ui/pages/visitor-machine.html                                                      |    5 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java                           |    5 
 ruoyi-ui/vue.config.js                                                                           |    4 
 visitor-admin-ui/css/visitor-machine.css                                                         |    6 
 ruoyi-applet/src/main/resources/application-test.yml                                             |    6 
 ruoyi-ui/src/layout/components/Navbar.vue                                                        |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorMachineRequest.java                    |    3 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSingInDataService.java        |   12 
 ruoyi-ui/.env.development                                                                        |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorRecordServiceImpl.java        |   67 ++
 visitor-admin-ui/pages/role-management.html                                                      |    4 
 visitor-admin-ui/pages/visitor-record-detail.html                                                |    4 
 visitor-admin-ui/pages/system-config.html                                                        |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java       |    4 
 visitor-admin-ui/css/version-update.css                                                          |   64 --
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorSignoutTemp.java                    |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVersionUpdateMapper.java                   |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitAreaMapper.java                       |    2 
 ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml                         |   12 
 visitor-admin-ui/js/role-form.js                                                                 |    2 
 visitor-admin-ui/js/version-update.js                                                            |    5 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVersionUpdateServiceImpl.java        |    6 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java         |    8 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorRecordController.java           |   16 
 ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java                  |   19 
 ruoyi-system/src/main/resources/mapper/system/SysVersionUpdateMapper.xml                         |    7 
 visitor-admin-ui/js/visitor-machine.js                                                           |    1 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiProtocolConfigController.java      |   51 +
 ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecordSinginRequest.java               |   14 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AreasList.java                             |    9 
 ruoyi-ui/src/views/visitor-admin/device/index.vue                                                |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java            |    4 
 visitor-admin-ui/pages/role-form.html                                                            |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecodeSingoutRequest.java              |   10 
 ruoyi-system/src/main/resources/mapper/system/SysVisitorMachineMapper.xml                        |   37 +
 visitor-admin-ui/pages/department-management.html                                                |    4 
 visitor-admin-ui/pages/protocol-config.html                                                      |    4 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java                                 |    2 
 ruoyi-applet/src/main/java/com/ruoyi/RuoYiAppletApplication.java                                 |    2 
 ruoyi-ui/src/components/ImageUpload/index.vue                                                    |   69 ++
 ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorIdCardOutRequest.java                  |   24 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/api/SysApiVisitorRecordMapper.java            |   27 
 ruoyi-system/src/main/java/com/ruoyi/system/dto/EmployeeDto.java                                 |    6 
 ruoyi-ui/src/utils/request.js                                                                    |   32 -
 visitor-admin-ui/js/visitor-record.js                                                            |   10 
 visitor-admin-ui/pages/door-management.html                                                      |    4 
 visitor-admin-ui/pages/employee-management.html                                                  |    4 
 ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorConfigController.java       |   53 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitArea.java                             |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVersionUpdateService.java                |    2 
 visitor-admin-ui/pages/visitor-record.html                                                       |    4 
 visitor-admin-ui/pages/version-update.html                                                       |    4 
 ruoyi-ui/src/api/visitor-admin/record.js                                                         |    9 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorRecordService.java                |    4 
 ruoyi-ui/src/views/visitor-admin/system/config.vue                                               |    8 
 81 files changed, 1,327 insertions(+), 323 deletions(-)

diff --git a/doc/sql/20260706_t_visitor_machine.sql b/doc/sql/20260706_t_visitor_machine.sql
index 33c7a64..33537d5 100644
--- a/doc/sql/20260706_t_visitor_machine.sql
+++ b/doc/sql/20260706_t_visitor_machine.sql
@@ -7,6 +7,7 @@
   `device_id` varchar(100) NOT NULL COMMENT '设备ID',
   `enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
   `online_status` varchar(32) NOT NULL DEFAULT 'UNACTIVATED' COMMENT '在线状态:UNACTIVATED未激活 ONLINE在线 OFFLINE离线',
+  `fingerprint` varchar(255) DEFAULT NULL COMMENT '百度SDK指纹',
   `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标识,0正常 1删除',
   `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
   `create_time` datetime DEFAULT NULL COMMENT '创建时间',
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorRecordController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorRecordController.java
index c70e70e..610f084 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorRecordController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/SysVisitorRecordController.java
@@ -24,6 +24,8 @@
 @RequestMapping("/system/visitor/record")
 public class SysVisitorRecordController extends BaseController
 {
+    private static final int EXPORT_PAGE_SIZE = 10000;
+
     @Autowired
     private ISysVisitorRecordService visitorRecordService;
 
@@ -39,6 +41,20 @@
     }
 
     /**
+     * 导出访客登记记录
+     */
+    @Log(title = "访客登记记录", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('visitor:record:export')")
+    @PostMapping("/export")
+    public AjaxResult export(@RequestBody(required = false) SysVisitorRecordPageRequest request)
+    {
+        SysVisitorRecordPageRequest query = request == null ? new SysVisitorRecordPageRequest() : request;
+        query.setPageNum(1);
+        query.setPageSize(EXPORT_PAGE_SIZE);
+        return success(visitorRecordService.pageList(query).getRecords());
+    }
+
+    /**
      * 查看访客登记详情
      */
     @Log(title = "访客登记记录", businessType = BusinessType.SELECT)
diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml
index 9e8eebb..e26e741 100644
--- a/ruoyi-admin/src/main/resources/application-test.yml
+++ b/ruoyi-admin/src/main/resources/application-test.yml
@@ -17,7 +17,7 @@
   # 部署模式:standalone单机版 cluster集群版
   deploymentMode: cluster
   # 集群版是否对接中台:true对接 false不对接
-  middlePlatformEnabled: true
+  middlePlatformEnabled: false
 # 开发环境配置
 server:
   # 服务器的HTTP端口,默认为8080
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/RuoYiAppletApplication.java b/ruoyi-applet/src/main/java/com/ruoyi/RuoYiAppletApplication.java
index 86b7bf9..157704c 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/RuoYiAppletApplication.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/RuoYiAppletApplication.java
@@ -29,8 +29,6 @@
 public class RuoYiAppletApplication
 {
     public static void main(String[] args) {
-
-
         ConfigurableApplicationContext application = SpringApplication.run(RuoYiAppletApplication.class, args);
         try {
             Environment env = application.getEnvironment();
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java
index 4fc7cc3..447ee8d 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/EmployeeVerifyController.java
@@ -16,6 +16,7 @@
 import com.ruoyi.system.mapper.SysVisitorMachineMapper;
 import com.ruoyi.system.service.EmployeeVerifyService;
 import com.ruoyi.system.service.ISysVisitorMachineService;
+import com.ruoyi.system.utils.EmployeePhoneCrypto;
 import com.ruoyi.system.vo.SysVisitorMachineVO;
 import com.ruoyi.web.controller.tool.ImageUtil;
 import io.swagger.annotations.Api;
@@ -62,12 +63,12 @@
      * 刷卡验证:现场读卡器读取卡号后调用本接口,与接待人绑定的卡号比对。
      */
     @PostMapping("/allEmployee")
-    @ApiOperation(value = "查询所有员工接口", notes = "必传设备ID")
-    public AjaxResult getAllEmployee(@RequestBody @Valid ApiVisitorMachineRequest request) {
-        SysVisitorMachine detail = visitorMachineMapper.checkDeviceIdUnique(request.getMachineId(),null);
-        if (detail == null || !detail.getEnabled()) {
-            throw new ServiceException("未找到有效设备");
-        }
+    @ApiOperation(value = "查询所有员工接口")
+    public AjaxResult getAllEmployee() {
+//        SysVisitorMachine detail = visitorMachineMapper.checkDeviceIdUnique(request.getMachineId(),null);
+//        if (detail == null || !detail.getEnabled()) {
+//            throw new ServiceException("未找到有效设备");
+//        }
 
         List<Employee> employees = employeeMapper.selectAllEnabled();
         if (employees == null || employees.isEmpty()) {
@@ -85,6 +86,12 @@
                         dto.setFaceImage(base64);
                     }
 
+                    if (StringUtils.isNotEmpty(employee.getContactPhoneCipher())) {
+                        String phone = EmployeePhoneCrypto.decrypt(employee.getContactPhoneCipher());
+                        dto.setPhone(phone);
+                    }
+                    dto.setContactPhoneCipher(null);
+
                     return dto;
                 })
                 .collect(Collectors.toList());
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java
index 486ecf1..8839b42 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiDoorMachineController.java
@@ -4,6 +4,8 @@
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.system.dto.*;
 import com.ruoyi.system.service.ISysVisitorMachineService;
 import io.swagger.annotations.Api;
@@ -36,7 +38,11 @@
     @PostMapping("/activate")
     @ApiOperation(value = "激活访客机设备")
     public AjaxResult activate(@Valid @RequestBody ApiVisitorMachineRequest request) {
-        int result = visitorMachineService.activateDevice(request.getMachineId());
+        if (StringUtils.isEmpty(request.getFingerprint())) {
+            throw new ServiceException("缺少参数");
+        }
+
+        int result = visitorMachineService.activateDevice(request.getMachineId(), request.getFingerprint());
         return result > 0 ? success("设备激活成功") : error("设备激活失败");
     }
 
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiProtocolConfigController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiProtocolConfigController.java
new file mode 100644
index 0000000..f985ead
--- /dev/null
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiProtocolConfigController.java
@@ -0,0 +1,51 @@
+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.SysProtocolConfigDetailRequest;
+import com.ruoyi.system.dto.SysProtocolConfigSaveRequest;
+import com.ruoyi.system.service.ISysProtocolConfigService;
+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.security.access.prepost.PreAuthorize;
+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;
+
+/**
+ * 入园承诺
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/api/admission")
+@Api(tags = "入园承诺" , value = "入园承诺")
+public class SysApiProtocolConfigController extends BaseController
+{
+    @Autowired
+    private ISysProtocolConfigService protocolConfigService;
+
+    /**
+     * 入园承诺
+     */
+    @Log(title = "入园承诺", businessType = BusinessType.SELECT)
+    @PostMapping("/detail")
+    @ApiOperation(value = "入园承诺")
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "操作成功", response = SysProtocolConfigDetailRequest.class),
+            @ApiResponse(code = 500, message = "操作失败")
+    })
+    public AjaxResult<SysProtocolConfigDetailRequest> detail()
+    {
+        SysProtocolConfigDetailRequest request = new SysProtocolConfigDetailRequest();
+        request.setProtocolType("ENTRY_COMMITMENT");//入园承诺
+        return success(protocolConfigService.selectConfig(request));
+    }
+
+}
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorConfigController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorConfigController.java
new file mode 100644
index 0000000..ec4934a
--- /dev/null
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorConfigController.java
@@ -0,0 +1,53 @@
+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.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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+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;
+
+/**
+ * 访客系统配置接口
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/api/visitorconfig")
+@Api(tags = "访客系统配置接口")
+public class SysApiVisitorConfigController extends BaseController
+{
+    @Autowired
+    private ISysVisitorConfigService visitorConfigService;
+
+    /**
+     * 查询当前配置
+     */
+    @Log(title = "访客系统配置", businessType = BusinessType.SELECT)
+    @PostMapping("/detail")
+    @ApiOperation(
+            value = "查询访客系统配置",
+            notes = "获取当前访客系统的配置信息,包括访客登记、审批流程等设置",
+            response = SysVisitorConfigVO.class
+    )
+    @ApiResponses({
+            @ApiResponse(code = 200, message = "查询成功", response = SysVisitorConfigVO.class),
+            @ApiResponse(code = 500, message = "查询失败")
+    })
+    public AjaxResult<SysVisitorConfigVO> detail()
+    {
+        SysVisitorConfigVO data = visitorConfigService.selectConfig();
+        return new AjaxResult<>(200, "操作成功", data);
+    }
+}
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java
index 5824e49..dd8a1bc 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordController.java
@@ -1,6 +1,8 @@
 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;
@@ -12,6 +14,8 @@
 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;
@@ -19,26 +23,29 @@
 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.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Objects;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping("/api/visitorRecord")
 @Api(tags = "现场访客登记-签离")
 public class SysApiVisitorRecordController extends BaseController {
+    @Autowired
+    private VisitorRegisterSyncService visitorRegisterSyncService;
     @Autowired
     private SysVisitorRecordService sysVisitorRecordService;
     @Autowired
@@ -52,6 +59,7 @@
 
     @PostMapping("/add")
     @ApiOperation(value = "访客登记", notes = "现场访客登记")
+    @Transactional(rollbackFor = Exception.class)
     public AjaxResult add(
             @RequestBody
             @ApiParam(value = "访客登记信息", required = true)
@@ -64,6 +72,21 @@
 
         if (StringUtils.isBlank(request.getIntervieweeName())) {
             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("被访人不存在,请联系工作人员");
+                }
+            }
         }
 
         // 签离的当天不能再次进入 签到
@@ -103,15 +126,42 @@
         BeanUtils.copyProperties(request, record);
 
         //查询地区
-        if (StringUtils.isNotEmpty(record.getVisitAreaIds())) {
-            String[] visitAreaIds = record.getVisitAreaIds().split(",");
+        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)) {
@@ -120,37 +170,112 @@
             }
         }
 
+        // 如果 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())) {
-            Employee employee = employeeMapper.selectEnabledByEmployeeName(record.getIntervieweeName());
-            if (employee != null && employee.getDeptId() != null) {
-                SysDept sysDept = sysDeptMapper.selectDeptById(employee.getDeptId());
-                if (sysDept != null) {
-                    record.setIntervieweeDept(sysDept.getDeptName());
+            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.setRegisterType("ONSITE");//现场登记
         record.setRegisterSource("访客机");
         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);
         }
+
         return AjaxResult.error("登记失败");
     }
 
-
     @PostMapping("/idCardSingOut")
     @ApiOperation(value = "访客身份证签离", notes = "访客身份证签离")
+    @Transactional(rollbackFor = Exception.class)
     public AjaxResult idCardSingOut(
             @RequestBody
             @ApiParam(value = "访客身份证签离", required = true)
@@ -187,15 +312,17 @@
         } else {
             record.setStatus("SIGNED_OUT");
         }
-        record.setSignVerifyMethod("MANUAL");
 
         SysVisitorRecord visitorRecord = new SysVisitorRecord();
         BeanUtils.copyBeanProp(visitorRecord, request);
-        visitorRecord.setSignVerifyMethod(record.getSignVerifyMethod());
+        visitorRecord.setSignVerifyMethod(request.getSignVerifyMethod());
         visitorRecord.setStatus(record.getStatus());
         visitorRecord.setRecordId(record.getRecordId());
         visitorRecord.setSignTime(new Date());
-        visitorRecordMapper.updateById(visitorRecord);
+
+        UpdateWrapper<SysVisitorRecord> wrapperUpdate = new UpdateWrapper<>();
+        wrapperUpdate.eq("record_id", visitorRecord.getRecordId());  // 指定ID条件
+        visitorRecordMapper.update(visitorRecord, wrapperUpdate);
 
         return success();
     }
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordManageController.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordManageController.java
index d9dacb0..0459fc0 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordManageController.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/api/SysApiVisitorRecordManageController.java
@@ -5,18 +5,33 @@
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.system.dto.SysVisitorRecordDetailRequest;
 import com.ruoyi.system.dto.SysVisitorRecordPageRequest;
+import com.ruoyi.system.service.ISysVersionUpdateService;
 import com.ruoyi.system.service.ISysVisitorRecordService;
+import com.ruoyi.system.vo.SysVersionUpdateVO;
 import com.ruoyi.system.vo.SysVisitorRecordDetailVO;
 import com.ruoyi.system.vo.SysVisitorRecordVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 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.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.List;
 
 /**
  * 管理侧访客记录接口
@@ -30,6 +45,9 @@
 {
     @Autowired
     private ISysVisitorRecordService visitorRecordService;
+
+    @Autowired
+    private ISysVersionUpdateService versionUpdateService;
 
     /**
      * 分页查询访客记录
@@ -55,6 +73,135 @@
     }
 
     /**
+     * 导出访客记录
+     */
+    @ApiOperation(
+            value = "导出访客记录",
+            notes = "按分页查询接口的筛选条件查询全部访客记录并导出 Excel,不进行分页"
+    )
+    @PostMapping("/export")
+    public void export(HttpServletResponse response,
+                       @RequestBody(required = false) SysVisitorRecordPageRequest request) throws IOException
+    {
+        List<SysVisitorRecordVO> records = visitorRecordService.list(request);
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        String fileName = URLEncoder.encode("访客记录", "UTF-8").replace("+", "%20");
+        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+
+        SXSSFWorkbook workbook = new SXSSFWorkbook(500);
+        try
+        {
+            writeVisitorRecordSheet(workbook, records);
+            workbook.write(response.getOutputStream());
+            response.flushBuffer();
+        }
+        finally
+        {
+            workbook.dispose();
+            workbook.close();
+        }
+    }
+
+    private void writeVisitorRecordSheet(SXSSFWorkbook workbook, List<SysVisitorRecordVO> records)
+    {
+        String[] headers = {
+                "登记编号", "访客姓名", "证件号码", "登记类型", "被访人", "被访部门", "访问区域",
+                "车牌号", "来访事由", "有效期开始时间", "有效期结束时间", "状态", "登记时间"
+        };
+        int[] columnWidths = {20, 16, 24, 16, 16, 20, 24, 16, 24, 22, 22, 20, 22};
+        Sheet sheet = workbook.createSheet("访客记录");
+        sheet.createFreezePane(0, 1);
+        CellStyle headerStyle = createHeaderStyle(workbook);
+        Row headerRow = sheet.createRow(0);
+        for (int index = 0; index < headers.length; index++)
+        {
+            Cell cell = headerRow.createCell(index);
+            cell.setCellValue(headers[index]);
+            cell.setCellStyle(headerStyle);
+            sheet.setColumnWidth(index, columnWidths[index] * 256);
+        }
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        for (int index = 0; index < records.size(); index++)
+        {
+            SysVisitorRecordVO record = records.get(index);
+            Row row = sheet.createRow(index + 1);
+            setCellValue(row, 0, record.getRegisterNo());
+            setCellValue(row, 1, record.getVisitorName());
+            setCellValue(row, 2, record.getIdCard());
+            setCellValue(row, 3, registerTypeName(record.getRegisterType()));
+            setCellValue(row, 4, record.getIntervieweeName());
+            setCellValue(row, 5, record.getIntervieweeDept());
+            setCellValue(row, 6, record.getVisitAreaNames());
+            setCellValue(row, 7, record.getPlateNo());
+            setCellValue(row, 8, record.getVisitReason());
+            setCellValue(row, 9, formatDate(dateFormat, record.getValidStartTime()));
+            setCellValue(row, 10, formatDate(dateFormat, record.getValidEndTime()));
+            setCellValue(row, 11, statusName(record.getStatus()));
+            setCellValue(row, 12, formatDate(dateFormat, record.getRegisterTime()));
+        }
+    }
+
+    private CellStyle createHeaderStyle(SXSSFWorkbook workbook)
+    {
+        Font font = workbook.createFont();
+        font.setBold(true);
+        CellStyle style = workbook.createCellStyle();
+        style.setFont(font);
+        style.setAlignment(HorizontalAlignment.CENTER);
+        return style;
+    }
+
+    private void setCellValue(Row row, int columnIndex, String value)
+    {
+        row.createCell(columnIndex).setCellValue(value == null ? "" : value);
+    }
+
+    private String formatDate(SimpleDateFormat dateFormat, java.util.Date date)
+    {
+        return date == null ? "" : dateFormat.format(date);
+    }
+
+    private String registerTypeName(String registerType)
+    {
+        if ("APPOINTMENT".equalsIgnoreCase(registerType))
+        {
+            return "预约登记";
+        }
+        if ("ONSITE".equalsIgnoreCase(registerType))
+        {
+            return "现场登记";
+        }
+        return registerType;
+    }
+
+    private String statusName(String status)
+    {
+        if ("VISITING".equalsIgnoreCase(status))
+        {
+            return "来访中";
+        }
+        if ("SIGNED_OUT".equalsIgnoreCase(status))
+        {
+            return "已签离";
+        }
+        if ("PENDING_CONFIRM".equalsIgnoreCase(status))
+        {
+            return "逾期滞留";
+        }
+        if ("OVERDUE_AUTO_SIGNED_OUT".equalsIgnoreCase(status))
+        {
+            return "超期自动签离";
+        }
+        if ("CANCELLED".equalsIgnoreCase(status))
+        {
+            return "已取消";
+        }
+        return status;
+    }
+
+    /**
      * 查询访客记录详情
      */
     @ApiOperation(
@@ -75,4 +222,26 @@
     {
         return success(visitorRecordService.detail(request));
     }
+
+    /**
+     * 获取最新版本信息
+     */
+    @ApiOperation(
+            value = "获取最新版本信息",
+            notes = "返回最新一条未删除的版本更新记录",
+            response = SysVersionUpdateVO.class
+    )
+    @ApiResponses({
+            @ApiResponse(
+                    code = 200,
+                    message = "成功",
+                    response = AjaxResult.class,
+                    responseContainer = "Data"
+            )
+    })
+    @PostMapping("/latestVersion")
+    public AjaxResult<SysVersionUpdateVO> latestVersion()
+    {
+        return success(versionUpdateService.latest());
+    }
 }
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSignOutDataService.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSignOutDataService.java
index c69a294..f41526e 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSignOutDataService.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSignOutDataService.java
@@ -63,7 +63,7 @@
 
                 // 1. 参数校验
                 if (!StringUtils.hasText(request.getIdCard())) {
-                    log.warn("身份证号为空,已跳过,设备编号: {}", request.getDeviceNo());
+                    log.warn("身份证号为空,已跳过,人员姓名: {}", request.getIntervieweeName());
                     errorCount++;
                     continue;
                 }
@@ -73,12 +73,12 @@
                     request.setSignImageUrl(url);
                 }
 
-                // 2. 防重校验(基于设备编号+身份证号+签离时间)
+                // 2. 防重校验(身份证号+签离时间)
                 String uniqueKey = generateUniqueKey(request);
                 String redisKey = "offline:signout:" + uniqueKey;
                 if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
-                    log.warn("签离数据重复,已跳过, 设备编号: {}, 身份证号: {}, 签离时间: {}",
-                            request.getDeviceNo(), request.getIdCard(), request.getSignTime());
+                    log.warn("签离数据重复,已跳过, 身份证号: {}, 签离时间: {}",
+                            request.getIdCard(), request.getSignTime());
                     skipCount++;
                     continue;
                 }
@@ -94,8 +94,8 @@
                 }
 
             } catch (Exception e) {
-                log.error("处理签离数据失败, 身份证号: {}, 设备编号: {}",
-                        request.getIdCard(), request.getDeviceNo(), e);
+                log.error("处理签离数据失败, 身份证号: {}",
+                        request.getIdCard(), e);
                 errorCount++;
             }
         }
@@ -362,7 +362,7 @@
      */
     private String generateUniqueKey(ApiVisitorRecodeSingoutRequest request) {
         StringBuilder sb = new StringBuilder();
-        sb.append(request.getDeviceNo()).append(":");
+//        sb.append(request.getDeviceNo()).append(":");
         sb.append(request.getIdCard()).append(":");
         sb.append(request.getSignTime() != null ?
                 request.getSignTime().getTime() : System.currentTimeMillis());
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSingInDataService.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSingInDataService.java
index ac7d319..bea4674 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSingInDataService.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/ApiPullSingInDataService.java
@@ -59,7 +59,7 @@
 
                 // 1. 参数校验
                 if (!StringUtils.hasText(request.getIdCard())) {
-                    log.warn("身份证号为空,已跳过,设备编号: {}", request.getDeviceNo());
+                    log.warn("身份证号为空,已跳过,访问人姓名: {}", request.getVisitorName());
                     errorCount++;
                     continue;
                 }
@@ -73,8 +73,8 @@
                 String uniqueKey = generateUniqueKey(request);
                 String redisKey = "offline:signin:" + uniqueKey;
                 if (Boolean.TRUE.equals(redisTemplate.hasKey(redisKey))) {
-                    log.warn("签到数据重复,已跳过, 设备编号: {}, 身份证号: {}, 登记时间: {}",
-                            request.getDeviceNo(), request.getIdCard(), request.getRegisterTime());
+                    log.warn("签到数据重复,已跳过, 身份证号: {}, 登记时间: {}",
+                            request.getIdCard(), request.getRegisterTime());
                     skipCount++;
                     continue;
                 }
@@ -135,7 +135,7 @@
         BeanUtils.copyProperties(request, record);
         record.setRegisterTime(registerTime);
         record.setRegisterSource("访客机");
-        record.setRegisterType("ONSITE");
+//        record.setRegisterType("ONSITE");
         record.setCreateTime(new Date());
         record.setDelFlag("0");
         record.setRegisterNo(generateRegisterNo());
@@ -148,8 +148,6 @@
         // 4. 如果有未关联的签离数据,直接关联
         if (signoutTemp != null) {
             // 设置签离信息
-
-
 
             record.setSignTime(signoutTemp.getSignTime());
             record.setSignReceiverName(signoutTemp.getSignReceiverName());
@@ -321,7 +319,7 @@
      */
     private String generateUniqueKey(ApiVisitorRecordSinginRequest request) {
         StringBuilder sb = new StringBuilder();
-        sb.append(request.getDeviceNo()).append(":");
+//        sb.append(request.getDeviceNo()).append(":");
         sb.append(request.getIdCard()).append(":");
         sb.append(request.getRegisterTime() != null ?
                 request.getRegisterTime().getTime() : System.currentTimeMillis());
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/VisitorRegisterSyncService.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/VisitorRegisterSyncService.java
new file mode 100644
index 0000000..34bf06f
--- /dev/null
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/service/VisitorRegisterSyncService.java
@@ -0,0 +1,191 @@
+package com.ruoyi.web.controller.service;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.ContentType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.system.domain.SysVisitorRecord;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 访客登记同步服务
+ * 将本地访客登记数据同步到对端服务器
+ */
+@Slf4j
+@Service
+public class VisitorRegisterSyncService {
+
+    @Value("${visitor.sync.url:}")
+    private String syncUrl;
+
+    @Value("${visitor.sync.enabled:false}")
+    private Boolean syncEnabled;
+
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    private static final DateTimeFormatter DATE_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     * 同步访客登记信息到对端服务器
+     *
+     * @param record 本地访客登记记录
+     * @return 同步结果
+     */
+    public AjaxResult syncVisitorRegister(SysVisitorRecord record) {
+        // 检查同步开关
+        if (!syncEnabled) {
+            log.info("访客登记同步已关闭,跳过同步");
+            return AjaxResult.success("同步功能未开启");
+        }
+
+        if (StringUtils.isBlank(syncUrl)) {
+            log.warn("同步URL未配置,跳过同步");
+            return AjaxResult.warn("同步URL未配置");
+        }
+
+        try {
+            // 1. 构建同步请求参数
+            Map<String, Object> requestBody = buildSyncRequest(record);
+
+            String jsonBody = objectMapper.writeValueAsString(requestBody);
+            log.info("同步访客登记数据:{}", jsonBody);
+
+            // 2. 发送HTTP请求
+            HttpResponse response = HttpRequest.post(syncUrl)
+                    .header("Content-Type", ContentType.JSON.getValue())
+                    .body(jsonBody)
+                    .timeout(30000)
+                    .execute();
+
+            // 3. 解析响应
+            String responseBody = response.body();
+            log.info("同步响应:{}", responseBody);
+
+            JsonNode jsonNode = objectMapper.readTree(responseBody);
+            boolean success = jsonNode.has("success") && jsonNode.get("success").asBoolean();
+
+            if (success) {
+                String remoteId = jsonNode.has("data") && jsonNode.get("data").has("id")
+                        ? jsonNode.get("data").get("id").asText() : null;
+                log.info("访客登记同步成功,远程ID:{}", remoteId);
+                return AjaxResult.success(remoteId);
+            } else {
+                String errorMsg = jsonNode.has("description")
+                        ? jsonNode.get("description").asText() : "未知错误";
+                log.error("访客登记同步失败:{}", errorMsg);
+                return AjaxResult.error(errorMsg);
+            }
+        } catch (Exception e) {
+            log.error("访客登记同步异常", e);
+            return AjaxResult.error("同步异常:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 构建同步请求参数
+     */
+    private Map<String, Object> buildSyncRequest(SysVisitorRecord record) {
+        Map<String, Object> params = new HashMap<>();
+
+        // 必填字段
+        params.put("name", record.getVisitorName());
+        params.put("certType", "111");
+        params.put("certNo", record.getIdCard());
+//        params.put("qrCode", generateQrCode(record));
+        params.put("person", record.getIntervieweeName());
+        params.put("reason", StringUtils.isNotBlank(record.getVisitReason())
+                ? record.getVisitReason() : "来访");
+        params.put("estimatedTimeStart", formatTime(record.getValidStartTime()));
+        params.put("estimatedTimeEnd", formatTime(record.getValidEndTime()));
+
+        if (record.getAreasList() != null && !record.getAreasList().isEmpty()) {
+            params.put("areas", record.getAreasList());
+        }
+
+        // 可选字段
+//        params.put("gender", convertGender(record.getGender()));
+//        params.put("phone", record.getPhone());
+        params.put("licensePlateNumber", record.getPlateNo());
+//        params.put("visitorDept", record.getVisitorCompany());
+        params.put("dept", record.getIntervieweeDept());
+        params.put("areaName", record.getVisitAreaNames());
+        params.put("registerGate", record.getRegisterSource());
+        params.put("registerMachineCode", record.getDeviceId());
+        params.put("status", "1"); // 1-已登记
+
+        // 如果有证件照片或现场照片,可以传递
+        // params.put("idPhoto", record.getIdCardPhoto());
+         params.put("pic", record.getFaceImageUrl());
+
+        return params;
+    }
+
+    /**
+     * 转换证件类型:本地字典 → 对方字典值
+     */
+    private String convertCertType(String localCertType) {
+        if (StringUtils.isBlank(localCertType)) {
+            return "111"; // 默认身份证
+        }
+        // 根据实际情况映射
+        switch (localCertType) {
+            case "ID_CARD": return "111";      // 居民身份证
+            case "PASSPORT": return "414";     // 护照
+            case "DRIVER_LICENSE": return "335"; // 驾驶证
+            case "HK_MACAU_PASS": return "337";  // 港澳通行证
+            default: return "111";
+        }
+    }
+
+    /**
+     * 转换性别:本地字典 → 对方字典值
+     */
+    private String convertGender(String localGender) {
+        if (StringUtils.isBlank(localGender)) {
+            return null;
+        }
+        switch (localGender) {
+            case "MALE": return "1";
+            case "FEMALE": return "2";
+            default: return null;
+        }
+    }
+
+    /**
+     * 格式化时间
+     */
+    private String formatTime(Date date) {
+        if (date == null) {
+            return null;
+        }
+        LocalDateTime localDateTime = date.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+        return localDateTime.format(DATE_FORMATTER);
+    }
+
+    /**
+     * 生成二维码内容
+     * 格式:vms:visitor:{日期}:{登记编号}
+     */
+    private String generateQrCode(SysVisitorRecord record) {
+        String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+        String registerNo = record.getRegisterNo();
+        return String.format("vms:visitor:%s:%s", dateStr, registerNo);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/ImageUtil.java b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/ImageUtil.java
index be6c283..b1c2d95 100644
--- a/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/ImageUtil.java
+++ b/ruoyi-applet/src/main/java/com/ruoyi/web/controller/tool/ImageUtil.java
@@ -1,14 +1,19 @@
 package com.ruoyi.web.controller.tool;
 
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.utils.file.FileUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.binary.Base64;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.nio.file.Files;
 
 @Slf4j
 @Component
@@ -25,20 +30,21 @@
             return null;
         }
 
+        String imagePath = RuoYiConfig.getUploadPath() + imageUrl.replace("/profile/upload", "");
+
         InputStream inputStream = null;
         ByteArrayOutputStream outputStream = null;
 
         try {
-            // 1. 创建URL连接
-            URL url = new URL(imageUrl);
-            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-            connection.setRequestMethod("GET");
-            connection.setConnectTimeout(5000);
-            connection.setReadTimeout(10000);
-            connection.setDoInput(true);
+            // 1. 获取本地文件
+            File imageFile = new File(imagePath);
+            if (!imageFile.exists()) {
+                log.error("图片文件不存在:{}", imagePath);
+                return null;
+            }
 
-            // 2. 获取图片数据
-            inputStream = connection.getInputStream();
+            // 2. 读取图片数据
+            inputStream = Files.newInputStream(imageFile.toPath());
             outputStream = new ByteArrayOutputStream();
 
             byte[] buffer = new byte[8192];
@@ -51,16 +57,12 @@
             byte[] imageBytes = outputStream.toByteArray();
             String base64 = Base64.encodeBase64String(imageBytes);
 
-            // 4. 根据图片类型添加前缀
-            String contentType = connection.getContentType();
-            if (contentType != null && contentType.startsWith("image/")) {
-                return "data:" + contentType + ";base64," + base64;
-            }
-
-            return "data:image/jpeg;base64," + base64;
+            // 4. 根据文件扩展名添加前缀
+            String contentType = getContentType(imagePath);
+            return "data:" + contentType + ";base64," + base64;
 
         } catch (Exception e) {
-            log.error("图片转Base64失败,URL:{}", imageUrl, e);
+            log.error("本地图片转Base64失败,路径:{}", imagePath, e);
             return null;
         } finally {
             try {
@@ -75,4 +77,30 @@
             }
         }
     }
+
+    /**
+     * 根据文件扩展名获取Content-Type
+     */
+    private static String getContentType(String imagePath) {
+        if (StringUtils.isEmpty(imagePath)) {
+            return "image/jpeg";
+        }
+        String ext = imagePath.substring(imagePath.lastIndexOf(".") + 1).toLowerCase();
+        switch (ext) {
+            case "png":
+                return "image/png";
+            case "gif":
+                return "image/gif";
+            case "bmp":
+                return "image/bmp";
+            case "webp":
+                return "image/webp";
+            case "svg":
+                return "image/svg+xml";
+            case "jpg":
+            case "jpeg":
+            default:
+                return "image/jpeg";
+        }
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-applet/src/main/resources/application-test.yml b/ruoyi-applet/src/main/resources/application-test.yml
index 98efa96..b92c9e3 100644
--- a/ruoyi-applet/src/main/resources/application-test.yml
+++ b/ruoyi-applet/src/main/resources/application-test.yml
@@ -32,6 +32,12 @@
       # Tomcat启动初始化的线程数,默认值10
       min-spare: 100
 
+# 访客登记同步配置
+visitor:
+  sync:
+    enabled: false  # 是否启用同步
+    url: http://对方服务器IP:端口/event-center/security-protection/visitor-register
+
 # 日志配置
 logging:
   level:
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
index f2dfa92..de8a61e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -44,16 +44,16 @@
     private String remark;
 
     @ApiModelProperty(value = "禁用备注")
-    @TableField("disable_remark")
+    @TableField(value = "disable_remark" ,exist = false)
     private String disableRemark;
 
     @ApiModelProperty(value = "操作时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    @TableField("operating_time")
+    @TableField(value = "operating_time" ,exist = false)
     private LocalDateTime operatingTime;
 
     @ApiModelProperty(value = "操作人  登录名(登录账号)")
-    @TableField("operating_person")
+    @TableField(value = "operating_person",exist = false)
     private String operatingPerson;
 
     public String getDisableRemark() {
@@ -82,6 +82,7 @@
 
     /** 请求参数 */
     @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    @TableField(exist = false)
     private Map<String, Object> params;
 
     public String getSearchValue()
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java
index eb68c6a..8be326c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/Employee.java
@@ -3,6 +3,7 @@
 
 import java.time.LocalDateTime;
 
+import com.baomidou.mybatisplus.annotation.TableName;
 import io.swagger.annotations.Api;
 import lombok.Data;
 
@@ -10,6 +11,7 @@
  * 员工实体(对应 t_employee 表)
  */
 @Data
+@TableName("t_employee")
 public class Employee {
 
     private Long employeeId;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitArea.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitArea.java
index bfaa147..3dd27d5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitArea.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitArea.java
@@ -1,5 +1,6 @@
 package com.ruoyi.system.domain;
 
+import com.baomidou.mybatisplus.annotation.TableName;
 import com.ruoyi.common.core.domain.BaseEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -11,6 +12,7 @@
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
+@TableName("t_visit_area")
 public class SysVisitArea extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorMachine.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorMachine.java
index a40c704..638c368 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorMachine.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorMachine.java
@@ -38,4 +38,7 @@
 
     /** 删除标识,0正常 1删除 */
     private String delFlag;
+
+    /** 百度SDK指纹 */
+    private String fingerprint;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorRecord.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorRecord.java
index bfc946a..249252a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorRecord.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorRecord.java
@@ -1,10 +1,14 @@
 package com.ruoyi.system.domain;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
 import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.system.domain.vo.AreasList;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.util.Date;
+import java.util.List;
 
 /**
  * 访客登记记录 t_visitor_record
@@ -13,6 +17,7 @@
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
+@TableName("t_visitor_record")
 public class SysVisitorRecord extends BaseEntity
 {
     private static final long serialVersionUID = 1L;
@@ -88,4 +93,9 @@
 
     /** 删除标识:0正常 1删除 */
     private String delFlag;
+
+    @TableField(exist = false)
+    private List<AreasList> areasList;
+    @TableField(exist = false)
+    private String deviceId;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorSignoutTemp.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorSignoutTemp.java
index 8c516d7..efbe5c9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorSignoutTemp.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysVisitorSignoutTemp.java
@@ -1,6 +1,7 @@
 package com.ruoyi.system.domain;
 
 import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
@@ -47,6 +48,7 @@
      * 签离时间
      */
     @TableField("sign_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date signTime;
 
     /**
@@ -95,12 +97,14 @@
      * 创建时间
      */
     @TableField(value = "create_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date createTime;
 
     /**
      * 更新时间
      */
     @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date updateTime;
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/api/ApiSysVisitorRecord.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/api/ApiSysVisitorRecord.java
new file mode 100644
index 0000000..17b94e6
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/api/ApiSysVisitorRecord.java
@@ -0,0 +1,102 @@
+package com.ruoyi.system.domain.api;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.system.domain.vo.AreasList;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 访客登记记录 t_visitor_record
+ *
+ * @author ruoyi
+ */
+@Data
+@TableName("t_visitor_record")
+public class ApiSysVisitorRecord
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 访客登记记录主键 */
+    private Long recordId;
+
+    /** 登记编号 */
+    private String registerNo;
+
+    /** 访客姓名 */
+    private String visitorName;
+
+    /** 访客身份证号 */
+    private String idCard;
+
+    /** 登记类型:APPOINTMENT预约登记 ONSITE现场登记 */
+    private String registerType;
+
+    /** 被访人 */
+    private String intervieweeName;
+
+    /** 被访人部门 */
+    private String intervieweeDept;
+
+    /** 登记接待人 */
+    private String receiverName;
+
+    /** 接待人验证方式 */
+    private String receiverVerifyMethod;
+
+    /** 访问区域ID,英文逗号分隔 */
+    private String visitAreaIds;
+
+    /** 访问区域名称,英文逗号分隔 */
+    private String visitAreaNames;
+
+    /** 车牌号 */
+    private String plateNo;
+
+    /** 来访事由 */
+    private String visitReason;
+
+    /** 有效期开始时间 */
+    private Date validStartTime;
+
+    /** 有效期结束时间 */
+    private Date validEndTime;
+
+    /** 登记状态 */
+    private String status;
+
+    /** 登记时间 */
+    private Date registerTime;
+
+    /** 登记来源 */
+    private String registerSource;
+
+    /** 访客人像地址 */
+    private String faceImageUrl;
+
+    /** 签离时间 */
+    private Date signTime;
+
+    /** 签离接待人 */
+    private String signReceiverName;
+
+    /** 签离验证方式 */
+    private String signVerifyMethod;
+
+    /** 签离人像地址 */
+    private String signImageUrl;
+
+    /** 删除标识:0正常 1删除 */
+    private String delFlag;
+
+    @TableField(exist = false)
+    private List<AreasList> areasList;
+    @TableField(exist = false)
+    private String deviceId;
+    private String remark;
+    private Date createTime;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AreasList.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AreasList.java
new file mode 100644
index 0000000..0928616
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/AreasList.java
@@ -0,0 +1,9 @@
+package com.ruoyi.system.domain.vo;
+
+import lombok.Data;
+
+@Data
+public class AreasList {
+    private String areaCode;
+    private String areaName;
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorMachineRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorMachineRequest.java
index d330f9b..4738086 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorMachineRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorMachineRequest.java
@@ -17,4 +17,7 @@
     @ApiModelProperty("设备ID")
     @NotNull(message = "未找到该设备")
     private String machineId;
+
+    @ApiModelProperty("百度指纹")
+    private String fingerprint;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecodeSingoutRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecodeSingoutRequest.java
index 10bc726..41d90d5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecodeSingoutRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecodeSingoutRequest.java
@@ -1,5 +1,6 @@
 package com.ruoyi.system.dto;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -16,8 +17,8 @@
 @ApiModel(value = "ApiVisitorRecodeSingoutRequest", description = "离线上传的访客身份证签离")
 public class ApiVisitorRecodeSingoutRequest
 {
-    @NotBlank(message = "设备编号不能为空")
-    @ApiModelProperty(value = "设备编号")
+//    @NotBlank(message = "设备编号不能为空")
+    @ApiModelProperty(value = "设备编号,非必填")
     private String deviceNo;
 
     /**
@@ -42,8 +43,13 @@
 
     /** 签离时间 */
     @ApiModelProperty(value = "签离时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date signTime;
 
+//    @NotBlank(message = "登记类型不能为空")
+//    @ApiModelProperty(value = "登记类型:APPOINTMENT预约登记 ONSITE现场登记")
+//    private String registerType;
+
     /** 签离接待人 */
     @ApiModelProperty(value = "签离接待人")
     private String signReceiverName;
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecordSinginRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecordSinginRequest.java
index 6a5f67b..dc27c59 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecordSinginRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/ApiVisitorRecordSinginRequest.java
@@ -17,8 +17,8 @@
 @ApiModel(value = "ApiVisitorRecordSinginRequest", description = "离线模式签到数据")
 public class ApiVisitorRecordSinginRequest
 {
-    @NotBlank(message = "设备编号不能为空")
-    @ApiModelProperty(value = "设备编号")
+//    @NotBlank(message = "设备编号不能为空")
+    @ApiModelProperty(value = "设备编号,非必填")
     private String deviceNo;
 
     /**
@@ -48,6 +48,10 @@
     @ApiModelProperty(value = "接待人验证方式")
     private String receiverVerifyMethod;
 
+    @NotBlank(message = "登记类型不能为空")
+    @ApiModelProperty(value = "登记类型:APPOINTMENT预约登记 ONSITE现场登记")
+    private String registerType;
+
     /**
      * 访问区域ID,英文逗号分隔
      */
@@ -70,21 +74,21 @@
      * 有效期开始时间
      */
     @ApiModelProperty(value = "有效期开始时间")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyyMMddHHmmss")
     private Date validStartTime;
 
     /**
      * 有效期结束时间
      */
     @ApiModelProperty(value = "有效期结束时间")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyyMMddHHmmss")
     private Date validEndTime;
 
     /**
      * 登记时间
      */
     @ApiModelProperty(value = "登记时间")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyyMMddHHmmss")
     private Date registerTime;
 
     /**
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/EmployeeDto.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/EmployeeDto.java
index dcee6ea..219187c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/EmployeeDto.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/EmployeeDto.java
@@ -25,4 +25,10 @@
 
     @ApiModelProperty("人像图片")
     private String faceImage;
+
+    @ApiModelProperty("手机号")
+    private String phone;
+
+    // 手机号加密的
+    private String contactPhoneCipher;
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorIdCardOutRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorIdCardOutRequest.java
index 83e3a7d..c6166dd 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorIdCardOutRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorIdCardOutRequest.java
@@ -22,18 +22,18 @@
     @ApiModelProperty(value = "访客身份证号")
     private String idCard;
 
-    /**
-     * 被访人
-     */
-    @NotBlank(message = "被访人不能为空")
-    @ApiModelProperty(value = "被访人")
-    private String intervieweeName;
-
-    /**
-     * 接待人验证方式
-     */
-    @ApiModelProperty(value = "接待人验证方式")
-    private String receiverVerifyMethod;
+//    /**
+//     * 被访人
+//     */
+//    @NotBlank(message = "被访人不能为空")
+//    @ApiModelProperty(value = "被访人")
+//    private String intervieweeName;
+//
+//    /**
+//     * 接待人验证方式
+//     */
+//    @ApiModelProperty(value = "接待人验证方式")
+//    private String receiverVerifyMethod;
 
     /** 签离接待人 */
     @ApiModelProperty(value = "签离接待人")
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java
index 39d97f3..718c833 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/dto/SysVisitorRecordAddRequest.java
@@ -20,11 +20,21 @@
 public class SysVisitorRecordAddRequest
 {
     /**
+     * 设备编号
+     */
+    @ApiModelProperty(value = "设备编号,非必传")
+    private String deviceId;
+
+    /**
      * 访客姓名
      */
     @NotBlank(message = "访客姓名不能为空")
     @ApiModelProperty(value = "访客姓名")
     private String visitorName;
+
+    @NotBlank(message = "登记类型不能为空")
+    @ApiModelProperty(value = "登记类型:APPOINTMENT预约登记 ONSITE现场登记")
+    private String registerType;
 
     /**
      * 访客身份证号
@@ -40,18 +50,27 @@
     @ApiModelProperty(value = "被访人")
     private String intervieweeName;
 
+    @ApiModelProperty(value = "被访人电话")
+    private String beVisitorPhone;
+
     /**
      * 接待人验证方式
      */
     @ApiModelProperty(value = "接待人验证方式")
     private String receiverVerifyMethod;
 
+    @ApiModelProperty(value = "登记接待人")
+    private String receiverName;
+
     /**
      * 访问区域ID,英文逗号分隔
      */
     @ApiModelProperty(value = "访问区域ID,英文逗号分隔")
     private String visitAreaIds;
 
+    @ApiModelProperty(value = "访问区域名称,英文逗号分隔")
+    private String visitAreaNames;
+
     /**
      * 车牌号
      */
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java
index 12b5237..2b7f67d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/EmployeeMapper.java
@@ -1,6 +1,7 @@
 package com.ruoyi.system.mapper;
 
 
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.system.domain.Employee;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
@@ -8,7 +9,7 @@
 import java.util.List;
 
 @Mapper
-public interface EmployeeMapper {
+public interface EmployeeMapper extends BaseMapper<Employee> {
 
     /**
      * 按主键查询启用且未删除的接待人。
@@ -19,7 +20,7 @@
     /**
      * 根据员工姓名精准查询启用的员工
      */
-    Employee selectEnabledByEmployeeName(@Param("employeeName") String employeeName);
+    List<Employee> selectEnabledByEmployeeName(@Param("employeeName") String employeeName);
 
     List<Employee> selectAllEnabled();
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVersionUpdateMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVersionUpdateMapper.java
index cd9ffb6..2a3f0e5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVersionUpdateMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVersionUpdateMapper.java
@@ -20,6 +20,8 @@
     public List<SysVersionUpdateVO> pageList(@Param("query") SysVersionUpdatePageRequest query,
                                              @Param("pageInfo") PageInfo<SysVersionUpdateVO> pageInfo);
 
+    public SysVersionUpdateVO selectLatest();
+
     public SysVersionUpdateVO selectById(Long updateId);
 
     public int insertVersionUpdate(SysVersionUpdate versionUpdate);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitAreaMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitAreaMapper.java
index bbe754a..199d57c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitAreaMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitAreaMapper.java
@@ -35,5 +35,7 @@
     public int updateChildrenAncestors(@Param("areaId") Long areaId, @Param("oldAncestors") String oldAncestors,
                                        @Param("newAncestors") String newAncestors);
 
+    public int countChildrenByParentIds(@Param("parentIds") List<Long> parentIds);
+
     public int deleteByIds(@Param("areaIds") List<Long> areaIds, @Param("updateBy") String updateBy);
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java
index 2978fec..f5011ed 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysVisitorRecordMapper.java
@@ -21,9 +21,15 @@
 @Mapper
 public interface SysVisitorRecordMapper extends BaseMapper<SysVisitorRecord>
 {
+    // 显式覆盖 updateById 方法
+    @Override
+    int updateById(@Param("et") SysVisitorRecord entity);
+
     public List<SysVisitorRecordVO> pageList(@Param("query") SysVisitorRecordPageRequest query,
                                              @Param("pageInfo") PageInfo<SysVisitorRecordVO> pageInfo);
 
+    public List<SysVisitorRecordVO> list(@Param("query") SysVisitorRecordPageRequest query);
+
     public SysVisitorRecordDetailVO selectDetailById(Long recordId);
 
     public List<SysVisitorPassRecordVO> selectPassRecordsByRecordId(Long recordId);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/api/SysApiVisitorRecordMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/api/SysApiVisitorRecordMapper.java
new file mode 100644
index 0000000..7f7a44a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/api/SysApiVisitorRecordMapper.java
@@ -0,0 +1,27 @@
+package com.ruoyi.system.mapper.api;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.basic.PageInfo;
+import com.ruoyi.system.domain.SysVisitorRecord;
+import com.ruoyi.system.domain.api.ApiSysVisitorRecord;
+import com.ruoyi.system.dto.SysVisitorRecordPageRequest;
+import com.ruoyi.system.vo.SysVisitorPassRecordVO;
+import com.ruoyi.system.vo.SysVisitorRecordDetailVO;
+import com.ruoyi.system.vo.SysVisitorRecordVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 访客登记记录数据层
+ *
+ * @author ruoyi
+ */
+@Repository
+public interface SysApiVisitorRecordMapper extends BaseMapper<ApiSysVisitorRecord>
+{
+
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVersionUpdateService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVersionUpdateService.java
index aaec81d..85fed0f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVersionUpdateService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVersionUpdateService.java
@@ -16,6 +16,8 @@
 {
     public PageInfo<SysVersionUpdateVO> pageList(SysVersionUpdatePageRequest request);
 
+    public SysVersionUpdateVO latest();
+
     public SysVersionUpdateVO detail(SysVersionUpdateDetailRequest request);
 
     public int add(SysVersionUpdateAddRequest request, String username);
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java
index 14d95dc..dfa0607 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorMachineService.java
@@ -37,7 +37,7 @@
      * @param deviceId 设备ID
      * @return 影响行数
      */
-    int activateDevice(String deviceId);
+    int activateDevice(String deviceId, String fingerprint);
 
     /**
      * 注销设备
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorRecordService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorRecordService.java
index 6343cad..93f84ff 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorRecordService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysVisitorRecordService.java
@@ -7,6 +7,8 @@
 import com.ruoyi.system.vo.SysVisitorRecordDetailVO;
 import com.ruoyi.system.vo.SysVisitorRecordVO;
 
+import java.util.List;
+
 /**
  * 访客登记记录服务
  *
@@ -16,6 +18,8 @@
 {
     public PageInfo<SysVisitorRecordVO> pageList(SysVisitorRecordPageRequest request);
 
+    public List<SysVisitorRecordVO> list(SysVisitorRecordPageRequest request);
+
     public SysVisitorRecordDetailVO detail(SysVisitorRecordDetailRequest request);
 
     public int refreshVisitorStatus();
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVersionUpdateServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVersionUpdateServiceImpl.java
index 9db3283..0f1fb7e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVersionUpdateServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVersionUpdateServiceImpl.java
@@ -39,6 +39,12 @@
     }
 
     @Override
+    public SysVersionUpdateVO latest()
+    {
+        return versionUpdateMapper.selectLatest();
+    }
+
+    @Override
     public SysVersionUpdateVO detail(SysVersionUpdateDetailRequest request)
     {
         if (request == null || request.getUpdateId() == null)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java
index 810c3fa..493f77f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitAreaServiceImpl.java
@@ -138,6 +138,10 @@
         {
             getRequiredAreaId(areaId);
         }
+        if (visitAreaMapper.countChildrenByParentIds(request.getAreaIds()) > 0)
+        {
+            throw new ServiceException("存在下级区域");
+        }
         return visitAreaMapper.deleteByIds(request.getAreaIds(), username);
     }
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorConfigServiceImpl.java
index 2f0e42b..4789ad8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorConfigServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorConfigServiceImpl.java
@@ -44,6 +44,8 @@
         labels.put("plateNo", "车牌号");
         labels.put("visitReason", "来访事由");
         labels.put("visitArea", "访问区域");
+        labels.put("receiverName", "接待人");
+        labels.put("registerTime", "登记时间");
         PRINT_FIELD_LABELS = Collections.unmodifiableMap(labels);
     }
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java
index 187d2ab..cc3d2da 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorMachineServiceImpl.java
@@ -153,7 +153,7 @@
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public int activateDevice(String deviceId) {
+    public int activateDevice(String deviceId, String fingerprint) {
         // 1. 根据deviceId查询设备
         SysVisitorMachine device = visitorMachineMapper.checkDeviceIdUnique(deviceId, null);
         if (device == null || device.getDelFlag().equals("1")) {
@@ -175,7 +175,7 @@
         update.setMachineId(device.getMachineId());
         update.setOnlineStatus("ONLINE");  // 或 "ACTIVATED",根据你的枚举定义
         update.setUpdateTime(new Date());
-
+        update.setFingerprint(fingerprint);
         return visitorMachineMapper.updateMachine(update);
     }
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorRecordServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorRecordServiceImpl.java
index 98fe869..3d3f1fc 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorRecordServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysVisitorRecordServiceImpl.java
@@ -7,6 +7,8 @@
 import com.ruoyi.system.dto.SysVisitorRecordDeleteRequest;
 import com.ruoyi.system.dto.SysVisitorRecordDetailRequest;
 import com.ruoyi.system.dto.SysVisitorRecordPageRequest;
+import com.ruoyi.system.domain.SysVisitArea;
+import com.ruoyi.system.mapper.SysVisitAreaMapper;
 import com.ruoyi.system.mapper.SysVisitorRecordMapper;
 import com.ruoyi.system.service.ISysVisitorRecordService;
 import com.ruoyi.system.vo.SysVisitorRecordDetailVO;
@@ -34,24 +36,25 @@
     @Autowired
     private SysVisitorRecordMapper visitorRecordMapper;
 
+    @Autowired
+    private SysVisitAreaMapper visitAreaMapper;
+
     @Override
     public PageInfo<SysVisitorRecordVO> pageList(SysVisitorRecordPageRequest request)
     {
         refreshVisitorStatus();
-        SysVisitorRecordPageRequest query = request == null ? new SysVisitorRecordPageRequest() : request;
-        query.setIntervieweeName(StringUtils.trim(query.getIntervieweeName()));
-        query.setIntervieweeKeyword(StringUtils.trim(query.getIntervieweeKeyword()));
-        query.setIntervieweeDept(StringUtils.trim(query.getIntervieweeDept()));
-        query.setVisitAreaKeyword(StringUtils.trim(query.getVisitAreaKeyword()));
-        query.setStatus(StringUtils.trim(query.getStatus()));
-        query.setVisitorName(StringUtils.trim(query.getVisitorName()));
-        query.setVisitorKeyword(StringUtils.trim(query.getVisitorKeyword()));
-        query.setVisitReason(StringUtils.trim(query.getVisitReason()));
-        query.setRegisterType(StringUtils.trim(query.getRegisterType()));
+        SysVisitorRecordPageRequest query = normalizeQuery(request);
         PageInfo<SysVisitorRecordVO> pageInfo = new PageInfo<SysVisitorRecordVO>(query.getPageNum(), query.getPageSize());
         List<SysVisitorRecordVO> list = visitorRecordMapper.pageList(query, pageInfo);
         pageInfo.setRecords(list);
         return pageInfo;
+    }
+
+    @Override
+    public List<SysVisitorRecordVO> list(SysVisitorRecordPageRequest request)
+    {
+        refreshVisitorStatus();
+        return visitorRecordMapper.list(normalizeQuery(request));
     }
 
     @Override
@@ -96,15 +99,42 @@
 
     private void fillDetailDisplayFields(SysVisitorRecordDetailVO detail)
     {
+        List<String> visitAreaNames = resolveVisitAreaNames(detail);
         detail.setIdCardMask(maskIdCard(detail.getIdCard()));
         detail.setRegisterTypeName(registerTypeName(detail.getRegisterType()));
         detail.setStatusName(statusName(detail.getStatus()));
         detail.setReceiverVerifyMethodName(verifyMethodName(detail.getReceiverVerifyMethod()));
         detail.setSignVerifyMethodName(verifyMethodName(detail.getSignVerifyMethod()));
-        detail.setVisitAreaNameList(splitNames(detail.getVisitAreaNames()));
+        detail.setVisitAreaNameList(visitAreaNames);
+        detail.setVisitAreaNames(String.join(",", visitAreaNames));
         detail.setValidTimeText(validTimeText(detail.getValidStartTime(), detail.getValidEndTime()));
         detail.setRegisterCollectTime(detail.getRegisterTime());
         detail.setSignCollectTime(detail.getSignTime());
+    }
+
+    private List<String> resolveVisitAreaNames(SysVisitorRecordDetailVO detail)
+    {
+        List<String> names = splitNames(detail.getVisitAreaNames());
+        if (!names.isEmpty() || StringUtils.isBlank(detail.getVisitAreaIds()))
+        {
+            return names;
+        }
+        for (String areaIdText : detail.getVisitAreaIds().split(","))
+        {
+            try
+            {
+                SysVisitArea area = visitAreaMapper.selectById(Long.valueOf(StringUtils.trim(areaIdText)));
+                if (area != null && StringUtils.isNotBlank(area.getAreaName()))
+                {
+                    names.add(area.getAreaName());
+                }
+            }
+            catch (NumberFormatException ignored)
+            {
+                continue;
+            }
+        }
+        return names;
     }
 
     private String maskIdCard(String idCard)
@@ -259,4 +289,19 @@
         }
         return recordId;
     }
+
+    private SysVisitorRecordPageRequest normalizeQuery(SysVisitorRecordPageRequest request)
+    {
+        SysVisitorRecordPageRequest query = request == null ? new SysVisitorRecordPageRequest() : request;
+        query.setIntervieweeName(StringUtils.trim(query.getIntervieweeName()));
+        query.setIntervieweeKeyword(StringUtils.trim(query.getIntervieweeKeyword()));
+        query.setIntervieweeDept(StringUtils.trim(query.getIntervieweeDept()));
+        query.setVisitAreaKeyword(StringUtils.trim(query.getVisitAreaKeyword()));
+        query.setStatus(StringUtils.trim(query.getStatus()));
+        query.setVisitorName(StringUtils.trim(query.getVisitorName()));
+        query.setVisitorKeyword(StringUtils.trim(query.getVisitorKeyword()));
+        query.setVisitReason(StringUtils.trim(query.getVisitReason()));
+        query.setRegisterType(StringUtils.trim(query.getRegisterType()));
+        return query;
+    }
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorMachineVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorMachineVO.java
index 6e7bd4b..840e55f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorMachineVO.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/vo/SysVisitorMachineVO.java
@@ -25,6 +25,8 @@
 
     private String deviceId;
 
+    private String fingerprint;
+
     private Boolean enabled;
 
     private String onlineStatus;
diff --git a/ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml b/ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml
index cf0ab93..a5f5621 100644
--- a/ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/EmployeeMapper.xml
@@ -22,7 +22,7 @@
 
     <!-- 人脸图片不参与本接口逻辑,且 longtext 体积较大,列表中排除,减少不必要的数据传输 -->
     <sql id="Base_Column_List">
-        employee_id, dept_id, employee_name, employee_no, contact_phone_cipher,
+        employee_id, dept_id, employee_name, face_image, employee_no, contact_phone_cipher,
         contact_phone_hash, `position`, card_no, enabled, del_flag,
         create_by, create_time, update_by, update_time
     </sql>
@@ -50,7 +50,7 @@
         SELECT
         <include refid="Base_Column_List"/>
         FROM t_employee
-        AND enabled = 1
+        where enabled = 1
         AND del_flag = '0'
     </select>
 
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysVersionUpdateMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysVersionUpdateMapper.xml
index bcb75c6..97d39d2 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysVersionUpdateMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysVersionUpdateMapper.xml
@@ -42,6 +42,13 @@
           and del_flag = '0'
     </select>
 
+    <select id="selectLatest" resultMap="SysVersionUpdateVOResult">
+        <include refid="selectVersionUpdateVo" />
+        where del_flag = '0'
+        order by create_time desc, update_id desc
+        limit 1
+    </select>
+
     <insert id="insertVersionUpdate" parameterType="SysVersionUpdate" useGeneratedKeys="true" keyProperty="updateId">
         insert into t_version_update (
             version_no,
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysVisitAreaMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysVisitAreaMapper.xml
index 0ff1cf3..8931ba5 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysVisitAreaMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysVisitAreaMapper.xml
@@ -147,6 +147,16 @@
           and find_in_set(#{areaId}, ancestors)
     </update>
 
+    <select id="countChildrenByParentIds" resultType="int">
+        select count(1)
+        from t_visit_area
+        where del_flag = '0'
+          and parent_id in
+          <foreach collection="parentIds" item="parentId" open="(" separator="," close=")">
+              #{parentId}
+          </foreach>
+    </select>
+
     <update id="deleteByIds">
         update t_visit_area
         set del_flag = '1',
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysVisitorMachineMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysVisitorMachineMapper.xml
index 917ff20..89d55c5 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysVisitorMachineMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysVisitorMachineMapper.xml
@@ -12,6 +12,7 @@
         <result property="deviceId"     column="device_id" />
         <result property="enabled"      column="enabled" />
         <result property="onlineStatus" column="online_status" />
+        <result property="fingerprint"  column="fingerprint" />
         <result property="delFlag"      column="del_flag" />
         <result property="remark"       column="remark" />
         <result property="createBy"     column="create_by" />
@@ -27,6 +28,7 @@
         <result property="deviceName"   column="device_name" />
         <result property="brand"        column="brand" />
         <result property="deviceId"     column="device_id" />
+        <result property="fingerprint"  column="fingerprint" />
         <result property="enabled"      column="enabled" />
         <result property="onlineStatus" column="online_status" />
         <result property="remark"       column="remark" />
@@ -41,6 +43,7 @@
                device_id,
                enabled,
                online_status,
+               fingerprint,
                del_flag,
                remark,
                create_by,
@@ -57,6 +60,7 @@
                m.device_name,
                m.brand,
                m.device_id,
+               m.fingerprint,
                m.enabled,
                m.online_status,
                m.remark,
@@ -141,14 +145,35 @@
 
     <update id="updateMachine" parameterType="SysVisitorMachine">
         update t_visitor_machine
-        set area_id = #{areaId},
-            device_name = #{deviceName},
-            brand = #{brand},
-            device_id = #{deviceId},
-            enabled = #{enabled},
-            remark = #{remark},
+        <set>
+            <if test="areaId != null and areaId != ''">
+                area_id = #{areaId},
+            </if>
+            <if test="deviceName != null and deviceName != ''">
+                device_name = #{deviceName},
+            </if>
+            <if test="brand != null and brand != ''">
+                brand = #{brand},
+            </if>
+            <if test="deviceId != null and deviceId != ''">
+                device_id = #{deviceId},
+            </if>
+            <if test="enabled != null">
+                enabled = #{enabled},    <!-- 注意:enabled 可能是 Boolean 或 Integer,若允许 false 或 0,则只判 null -->
+            </if>
+            <if test="onlineStatus != null and onlineStatus != ''">
+                online_status = #{onlineStatus},
+            </if>
+            <if test="fingerprint != null and fingerprint != ''">
+                fingerprint = #{fingerprint},
+            </if>
+            <if test="remark != null and remark != ''">
+                remark = #{remark},
+            </if>
+            <!-- 以下两个字段始终更新,不加 if -->
             update_by = #{updateBy},
             update_time = sysdate()
+        </set>
         where machine_id = #{machineId}
           and del_flag = '0'
     </update>
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml
index a48a365..baf2d35 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysVisitorRecordMapper.xml
@@ -86,7 +86,7 @@
         from t_visitor_record
     </sql>
 
-    <select id="pageList" resultMap="SysVisitorRecordVOResult">
+    <sql id="selectVisitorRecordList">
         <include refid="selectVisitorRecordBase" />
         <where>
             and del_flag = '0'
@@ -124,13 +124,21 @@
                 )
             </if>
             <if test="query.visitReason != null and query.visitReason != ''">
-                and visit_reason = #{query.visitReason}
+                and visit_reason like concat('%', #{query.visitReason}, '%')
             </if>
             <if test="query.registerType != null and query.registerType != ''">
                 and register_type = #{query.registerType}
             </if>
         </where>
         order by register_time desc, record_id desc
+    </sql>
+
+    <select id="pageList" resultMap="SysVisitorRecordVOResult">
+        <include refid="selectVisitorRecordList" />
+    </select>
+
+    <select id="list" resultMap="SysVisitorRecordVOResult">
+        <include refid="selectVisitorRecordList" />
     </select>
 
     <select id="selectDetailById" parameterType="Long" resultMap="SysVisitorRecordDetailVOResult">
diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development
index 79db8a6..fb1678b 100644
--- a/ruoyi-ui/.env.development
+++ b/ruoyi-ui/.env.development
@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE = 运营活动管理平台
+VUE_APP_TITLE = 访客机自助登记管理平台
 
 # 开发环境配置
 ENV = 'development'
@@ -9,7 +9,7 @@
 
 # 访客后台前端部署模式:standalone 单机版需要输入IP,cluster 集群版不输入IP
 VUE_APP_VISITOR_FRONTEND_MODE = 'cluster'
-VUE_APP_VISITOR_MIDDLE_PLATFORM_ENABLED = 'true'
+VUE_APP_VISITOR_MIDDLE_PLATFORM_ENABLED = 'false'
 # VUE_APP_VISITOR_LOGIN_MIDDLE_PLATFORM_ENABLED 未配置时默认跟随 VUE_APP_VISITOR_MIDDLE_PLATFORM_ENABLED
 
 # 开发环境通过 /dev-api 代理到本地 9098
diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production
index 21b0536..1da49c7 100644
--- a/ruoyi-ui/.env.production
+++ b/ruoyi-ui/.env.production
@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE = 运营活动管理平台
+VUE_APP_TITLE = 访客机自助登记管理平台
 
 # 生产环境配置
 ENV = 'production'
diff --git a/ruoyi-ui/src/api/visitor-admin/record.js b/ruoyi-ui/src/api/visitor-admin/record.js
index bac0c5d..ed871fb 100644
--- a/ruoyi-ui/src/api/visitor-admin/record.js
+++ b/ruoyi-ui/src/api/visitor-admin/record.js
@@ -5,11 +5,15 @@
 }
 
 export function getVisitorRecord(recordId) {
-  return request({ url: '/system/visitor/record/detail', method: 'post', data: { recordId } })
+  return request({ url: '/system/visitor/record/detail', method: 'post', data: { recordId }})
 }
 
 export function delVisitorRecord(recordIds) {
-  return request({ url: '/system/visitor/record/delete', method: 'post', data: { recordIds } })
+  return request({ url: '/system/visitor/record/delete', method: 'post', data: { recordIds }})
+}
+
+export function exportVisitorRecord(data) {
+  return request({ url: '/system/visitor/record/export', method: 'post', data })
 }
 
 export function listOperationLog(data) {
@@ -19,4 +23,3 @@
 export function exportOperationLog(data) {
   return request({ url: '/system/operation/log/export', method: 'post', data })
 }
-
diff --git a/ruoyi-ui/src/assets/styles/visitor-admin.scss b/ruoyi-ui/src/assets/styles/visitor-admin.scss
index c028729..d06c309 100644
--- a/ruoyi-ui/src/assets/styles/visitor-admin.scss
+++ b/ruoyi-ui/src/assets/styles/visitor-admin.scss
@@ -92,9 +92,9 @@
       min-width: 0 !important;
       height: 36px !important;
       line-height: 36px !important;
-      margin: 0;
+      margin: 0 0 4px;
       padding: 0 0 0 48px !important;
-      border-radius: 0;
+      border-radius: 13px;
       color: rgba(255, 255, 255, 0.92) !important;
       background: transparent !important;
       font-size: 12px;
@@ -128,11 +128,13 @@
       background-color: rgba(255, 255, 255, 0.14) !important;
     }
 
+    .theme-dark .el-submenu .el-menu-item:hover,
+    .theme-dark .el-submenu .el-menu-item.is-active,
     .el-submenu .el-menu-item:hover,
     .el-submenu .el-menu-item.is-active {
       color: #fff !important;
-      background: transparent !important;
-      background-color: transparent !important;
+      background: rgba(255, 255, 255, 0.14) !important;
+      background-color: rgba(255, 255, 255, 0.14) !important;
     }
 
     > .el-scrollbar > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu > .el-menu-item.is-active,
@@ -1596,49 +1598,6 @@
   text-overflow: ellipsis;
   white-space: nowrap;
   vertical-align: middle;
-}
-
-.content-preview {
-  position: absolute;
-  left: -16px;
-  top: 38px;
-  z-index: 10;
-  width: 204px;
-  min-height: 102px;
-  display: none;
-  padding: 0 10px 12px;
-  border: 1px solid #f0bc2d;
-  border-radius: 2px;
-  background: #fff;
-  box-shadow: 0 4px 12px rgba(15, 35, 70, 0.12);
-}
-
-.version-content-cell:hover .content-preview {
-  display: block;
-}
-
-.preview-index {
-  height: 16px;
-  margin: 0 -10px 12px;
-  padding-left: 9px;
-  color: #111827;
-  background: #ffd753;
-  font-weight: 700;
-  line-height: 16px;
-}
-
-.preview-content {
-  min-height: 42px;
-  color: #111827;
-  font-weight: 700;
-  line-height: 18px;
-  word-break: break-word;
-}
-
-.preview-foot {
-  margin-top: 26px;
-  color: #8a9ab0;
-  font-size: 11px;
 }
 
 .table-actions {
diff --git a/ruoyi-ui/src/components/ImageUpload/index.vue b/ruoyi-ui/src/components/ImageUpload/index.vue
index 0df8408..b6d1730 100644
--- a/ruoyi-ui/src/components/ImageUpload/index.vue
+++ b/ruoyi-ui/src/components/ImageUpload/index.vue
@@ -68,6 +68,11 @@
     isShowTip: {
       type: Boolean,
       default: true
+    },
+    // 是否在上传前压缩图片
+    compress: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -140,15 +145,63 @@
         this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
         return false;
       }
-      if (this.fileSize) {
-        const isLt = file.size / 1024 / 1024 < this.fileSize;
-        if (!isLt) {
-          this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
-          return false;
+      const compressedFile = this.compress ? this.compressImage(file) : Promise.resolve(file);
+      return compressedFile.then(uploadFile => {
+        if (this.fileSize) {
+          const isLt = uploadFile.size / 1024 / 1024 < this.fileSize;
+          if (!isLt) {
+            throw new Error("FILE_SIZE_EXCEEDED");
+          }
         }
-      }
-      this.$modal.loading("正在上传图片,请稍候...");
-      this.number++;
+        this.$modal.loading("正在上传图片,请稍候...");
+        this.number++;
+        return uploadFile;
+      }).catch(error => {
+        const message = error && error.message === "FILE_SIZE_EXCEEDED"
+          ? `上传头像图片大小不能超过 ${this.fileSize} MB!`
+          : "图片压缩失败,请重试";
+        this.$modal.msgError(message);
+        return Promise.reject(error);
+      });
+    },
+    // 将人脸图片限制在合理尺寸并转为 JPEG,减少上传和设备同步数据量
+    compressImage(file) {
+      return new Promise((resolve, reject) => {
+        const reader = new FileReader();
+        reader.onload = event => {
+          const image = new Image();
+          image.onload = () => {
+            const maxWidth = 1280;
+            const maxHeight = 1280;
+            const scale = Math.min(1, maxWidth / image.width, maxHeight / image.height);
+            const resized = scale < 1;
+            const canvas = document.createElement("canvas");
+            canvas.width = Math.max(1, Math.round(image.width * scale));
+            canvas.height = Math.max(1, Math.round(image.height * scale));
+            const context = canvas.getContext("2d");
+            if (!context) {
+              resolve(file);
+              return;
+            }
+            context.drawImage(image, 0, 0, canvas.width, canvas.height);
+            canvas.toBlob(blob => {
+              if (!blob || (!resized && blob.size >= file.size)) {
+                resolve(file);
+                return;
+              }
+              const fileName = file.name.replace(/\.[^.]+$/, "") + ".jpg";
+              resolve(new File([blob], fileName, {
+                type: "image/jpeg",
+                lastModified: Date.now()
+              }));
+            }, "image/jpeg", 0.82);
+          };
+          image.onerror = reject;
+          image.src = event.target.result;
+        };
+        reader.onerror = reject;
+        reader.readAsDataURL(file);
+      });
     },
     // 文件个数超出
     handleExceed() {
diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
index a33e30d..dd3cd9c 100644
--- a/ruoyi-ui/src/layout/components/Navbar.vue
+++ b/ruoyi-ui/src/layout/components/Navbar.vue
@@ -120,7 +120,7 @@
       },
       passwordRules: {
         oldPassword: [{ required: true, message: '请输入原密码', trigger: 'blur' }],
-        newPassword: [{ validator: strongPassword, trigger: 'blur' }],
+        newPassword: [{ required: true, validator: strongPassword, trigger: 'blur' }],
         confirmPassword: [{ required: true, message: '请确认新密码', trigger: 'blur' }, { validator: confirmPassword, trigger: 'blur' }]
       }
     }
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index f7c0235..b6a39fb 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -4,7 +4,6 @@
 import { getToken } from '@/utils/auth'
 import errorCode from '@/utils/errorCode'
 import { tansParams, blobValidate } from "@/utils/ruoyi";
-import cache from '@/plugins/cache'
 import { saveAs } from 'file-saver'
 import visitorAdminConfig from '@/config/visitor-admin'
 
@@ -84,8 +83,6 @@
   config.baseURL = getVisitorApiBaseUrl()
   // 是否需要设置 token
   const isToken = (config.headers || {}).isToken === false
-  // 是否需要防止数据重复提交
-  const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
   if (getToken() && !isToken) {
     config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
   }
@@ -95,35 +92,6 @@
     url = url.slice(0, -1);
     config.params = {};
     config.url = url;
-  }
-  if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
-    const requestObj = {
-      url: config.url,
-      data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
-      time: new Date().getTime()
-    }
-    const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
-    const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
-    if (requestSize >= limitSize) {
-      console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
-      return config;
-    }
-    const sessionObj = cache.session.getJSON('sessionObj')
-    if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
-      cache.session.setJSON('sessionObj', requestObj)
-    } else {
-      const s_url = sessionObj.url;                  // 请求地址
-      const s_data = sessionObj.data;                // 请求数据
-      const s_time = sessionObj.time;                // 请求时间
-      const interval = 1000;                         // 间隔时间(ms),小于此时间视为重复提交
-      if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
-        const message = '数据正在处理,请勿重复提交';
-        console.warn(`[${s_url}]: ` + message)
-        return Promise.reject(new Error(message))
-      } else {
-        cache.session.setJSON('sessionObj', requestObj)
-      }
-    }
   }
   return config
 }, error => {
diff --git a/ruoyi-ui/src/views/visitor-admin/device/index.vue b/ruoyi-ui/src/views/visitor-admin/device/index.vue
index 3f133a9..0f6f4dd 100644
--- a/ruoyi-ui/src/views/visitor-admin/device/index.vue
+++ b/ruoyi-ui/src/views/visitor-admin/device/index.vue
@@ -60,6 +60,7 @@
             <el-table-column label="设备名称" prop="deviceName" min-width="120" show-overflow-tooltip />
             <el-table-column label="品牌" prop="brand" min-width="100" show-overflow-tooltip />
             <el-table-column label="设备ID" prop="deviceId" min-width="150" show-overflow-tooltip />
+            <el-table-column v-if="deviceType === 'machine'" label="百度SDK指纹" prop="fingerprint" min-width="160" show-overflow-tooltip />
             <el-table-column label="所属区域" prop="areaName" min-width="130" show-overflow-tooltip />
             <el-table-column label="启用状态" align="center" width="100">
               <template slot-scope="scope">
diff --git a/ruoyi-ui/src/views/visitor-admin/organization/employee.vue b/ruoyi-ui/src/views/visitor-admin/organization/employee.vue
index 721e0be..2885e87 100644
--- a/ruoyi-ui/src/views/visitor-admin/organization/employee.vue
+++ b/ruoyi-ui/src/views/visitor-admin/organization/employee.vue
@@ -142,8 +142,8 @@
             </el-form-item>
           </el-col>
         </el-row>
-        <el-form-item label="人脸图片" prop="faceImage">
-          <el-input v-model="form.faceImage" placeholder="请输入人脸图片地址" />
+        <el-form-item label="人脸图片" prop="faceImage" class="employee-face-upload">
+          <image-upload v-model="form.faceImage" :limit="1" :file-size="5" :is-show-tip="false" :compress="true" />
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -314,7 +314,8 @@
       this.title = '新增员工'
       this.form = {
         deptId: this.queryParams.deptId,
-        enabled: true
+        enabled: true,
+        faceImage: ''
       }
       this.open = true
     },
@@ -423,4 +424,15 @@
 .employee-add-col .el-button {
   border-radius: 8px;
 }
+
+.employee-face-upload ::v-deep .el-upload--picture-card,
+.employee-face-upload ::v-deep .el-upload-list--picture-card .el-upload-list__item {
+  width: 96px;
+  height: 96px;
+  line-height: 96px;
+}
+
+.employee-face-upload ::v-deep .el-upload--picture-card {
+  border-radius: 8px;
+}
 </style>
diff --git a/ruoyi-ui/src/views/visitor-admin/record/detail.vue b/ruoyi-ui/src/views/visitor-admin/record/detail.vue
index c1f0881..ddb220a 100644
--- a/ruoyi-ui/src/views/visitor-admin/record/detail.vue
+++ b/ruoyi-ui/src/views/visitor-admin/record/detail.vue
@@ -125,7 +125,9 @@
   computed: {
     // 目的:把详情访问区域拆成标签数组,适配中英文逗号和数组格式。
     visitAreaTags() {
-      const value = this.detail.visitAreaNames
+      const value = this.detail.visitAreaNameList && this.detail.visitAreaNameList.length
+        ? this.detail.visitAreaNameList
+        : this.detail.visitAreaNames
       if (Array.isArray(value)) {
         return value.map(item => String(item || '').trim()).filter(Boolean)
       }
diff --git a/ruoyi-ui/src/views/visitor-admin/record/visitor.vue b/ruoyi-ui/src/views/visitor-admin/record/visitor.vue
index deca794..cd9c201 100644
--- a/ruoyi-ui/src/views/visitor-admin/record/visitor.vue
+++ b/ruoyi-ui/src/views/visitor-admin/record/visitor.vue
@@ -4,7 +4,7 @@
       <header class="visitor-header">
         <h1>访客登记记录</h1>
       </header>
-    <el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true" class="visitor-query">
+    <el-form ref="queryForm" :model="queryParams" size="small" :inline="true" class="visitor-query">
       <el-form-item label="访客姓名" prop="visitorName">
         <el-input v-model="queryParams.visitorName" placeholder="请输入访客姓名" clearable @keyup.enter.native="handleQuery" />
       </el-form-item>
@@ -13,6 +13,9 @@
       </el-form-item>
       <el-form-item label="被访部门" prop="intervieweeDept">
         <el-input v-model="queryParams.intervieweeDept" placeholder="请输入被访部门" clearable @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item label="来访事由" prop="visitReason">
+        <el-input v-model="queryParams.visitReason" placeholder="请输入来访事由" clearable @keyup.enter.native="handleQuery" />
       </el-form-item>
       <el-form-item label="访问区域" prop="areaId">
         <treeselect v-model="queryParams.areaId" :options="areaOptions" placeholder="请选择区域" clearable class="query-tree" />
@@ -44,16 +47,21 @@
     </el-form>
 
     <el-row :gutter="10" class="mb8">
-      <el-col v-if="!isMiddlePlatformReadonly" v-hasPermi="['visitor:record:remove']" :span="1.5">
-        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete()">删除</el-button>
+      <el-col v-hasPermi="['visitor:record:export']" :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
       </el-col>
-      <right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
+      <el-col v-if="!isMiddlePlatformReadonly" v-hasPermi="['visitor:record:remove']" :span="1.5">
+        <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete">批量删除</el-button>
+      </el-col>
     </el-row>
 
     <el-table v-loading="loading" class="visitor-table" :data="recordList" @selection-change="handleSelectionChange">
       <el-table-column v-if="!isMiddlePlatformReadonly" type="selection" width="50" align="center" />
       <el-table-column label="登记编号" prop="registerNo" min-width="150" show-overflow-tooltip />
       <el-table-column label="访客姓名" prop="visitorName" min-width="150" />
+      <el-table-column label="身份证" min-width="150" show-overflow-tooltip>
+        <template slot-scope="scope">{{ maskIdCard(scope.row.idCard) }}</template>
+      </el-table-column>
       <el-table-column label="登记类型" align="center" min-width="150">
         <template slot-scope="scope">{{ optionLabel(registerTypes, scope.row.registerType) }}</template>
       </el-table-column>
@@ -61,6 +69,10 @@
       <el-table-column label="被访部门" prop="intervieweeDept" min-width="150" show-overflow-tooltip />
       <el-table-column label="访问区域" prop="visitAreaNames" min-width="150" show-overflow-tooltip />
       <el-table-column label="车牌号" prop="plateNo" min-width="150" />
+      <el-table-column label="来访事由" prop="visitReason" min-width="150" show-overflow-tooltip />
+      <el-table-column label="有效期" min-width="260" show-overflow-tooltip>
+        <template slot-scope="scope">{{ validTimeText(scope.row.validStartTime, scope.row.validEndTime) }}</template>
+      </el-table-column>
       <el-table-column label="状态" align="center" min-width="150">
         <template slot-scope="scope">
           <span class="record-status-pill" :class="statusClass(scope.row.status)">{{ optionLabel(statusOptions, scope.row.status) }}</span>
@@ -69,10 +81,9 @@
       <el-table-column label="登记时间" align="center" prop="registerTime" min-width="150">
         <template slot-scope="scope">{{ parseTime(scope.row.registerTime) }}</template>
       </el-table-column>
-      <el-table-column label="操作" align="center" width="150" fixed="right" class-name="small-padding fixed-width">
+      <el-table-column label="操作" align="center" width="90" fixed="right" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-view" @click="handleDetail(scope.row)">详情</el-button>
-          <el-button v-if="!isMiddlePlatformReadonly" v-hasPermi="['visitor:record:remove']" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -83,10 +94,11 @@
 </template>
 
 <script>
+import { saveAs } from 'file-saver'
 import Treeselect from '@riophae/vue-treeselect'
 import '@riophae/vue-treeselect/dist/vue-treeselect.css'
 import { treeArea } from '@/api/visitor-admin/area'
-import { listVisitorRecord, delVisitorRecord } from '@/api/visitor-admin/record'
+import { listVisitorRecord, delVisitorRecord, exportVisitorRecord } from '@/api/visitor-admin/record'
 import { getResponseData, getPageRows, getPageTotal, normalizeAreaOptions, toIdArray } from '@/utils/visitor-admin'
 
 export default {
@@ -96,7 +108,6 @@
   data() {
     return {
       loading: false,
-      showSearch: true,
       multiple: true,
       ids: [],
       total: 0,
@@ -197,6 +208,24 @@
       }
       return 'is-neutral'
     },
+    // 目的:列表只展示身份证前四位和后四位,中间内容统一脱敏。
+    maskIdCard(value) {
+      const text = String(value || '')
+      if (!text) {
+        return '-'
+      }
+      if (text.length <= 8) {
+        return text
+      }
+      return text.slice(0, 4) + '*'.repeat(text.length - 8) + text.slice(-4)
+    },
+    // 目的:把有效期开始和结束时间合并成列表展示文本。
+    validTimeText(start, end) {
+      if (!start && !end) {
+        return '-'
+      }
+      return (this.parseTime(start) || '-') + ' 至 ' + (this.parseTime(end) || '-')
+    },
     // 目的:从第一页重新执行访客记录查询。
     handleQuery() {
       this.queryParams.pageNum = 1
@@ -208,6 +237,66 @@
       this.resetForm('queryForm')
       this.handleQuery()
     },
+    // 目的:导出当前筛选条件下的访客登记记录。
+    handleExport() {
+      exportVisitorRecord(this.buildQuery()).then(res => {
+        const rows = Array.isArray(getResponseData(res)) ? getResponseData(res) : []
+        const blob = new Blob([this.buildExcelXml(rows)], { type: 'application/vnd.ms-excel;charset=utf-8' })
+        saveAs(blob, `访客登记记录_${this.parseTime(new Date(), '{y}{m}{d}{h}{i}{s}')}.xls`)
+      })
+    },
+    // 目的:把访客登记记录转换成 Excel 2003 XML,保持与操作日志导出方式一致。
+    buildExcelXml(rows) {
+      const columns = [
+        { title: '登记编号', key: 'registerNo', width: 150 },
+        { title: '访客姓名', key: 'visitorName', width: 100 },
+        { title: '证件号码', key: 'idCard', width: 170 },
+        { title: '登记类型', value: row => this.optionLabel(this.registerTypes, row.registerType), width: 90 },
+        { title: '被访人', key: 'intervieweeName', width: 100 },
+        { title: '被访部门', key: 'intervieweeDept', width: 130 },
+        { title: '访问区域', key: 'visitAreaNames', width: 150 },
+        { title: '车牌号', key: 'plateNo', width: 100 },
+        { title: '来访事由', key: 'visitReason', width: 180 },
+        { title: '有效期开始时间', value: row => this.parseTime(row.validStartTime) || '', width: 150 },
+        { title: '有效期结束时间', value: row => this.parseTime(row.validEndTime) || '', width: 150 },
+        { title: '状态', value: row => this.optionLabel(this.statusOptions, row.status), width: 100 },
+        { title: '登记时间', value: row => this.parseTime(row.registerTime) || '', width: 150 }
+      ]
+      const columnXml = columns.map(column => `<Column ss:Width="${column.width}"/>`).join('')
+      const headerXml = `<Row>${columns.map(column => this.excelCell(column.title, 'Header')).join('')}</Row>`
+      const bodyXml = rows.map(row => `<Row>${columns.map(column => {
+        const value = column.value ? column.value(row) : row[column.key]
+        return this.excelCell(value)
+      }).join('')}</Row>`).join('')
+      return `<?xml version="1.0" encoding="UTF-8"?>
+<?mso-application progid="Excel.Sheet"?>
+<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
+ xmlns:o="urn:schemas-microsoft-com:office:office"
+ xmlns:x="urn:schemas-microsoft-com:office:excel"
+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
+ <Styles>
+  <Style ss:ID="Header"><Font ss:Bold="1"/><Interior ss:Color="#EAF1F9" ss:Pattern="Solid"/></Style>
+ </Styles>
+ <Worksheet ss:Name="访客登记记录">
+  <Table>${columnXml}${headerXml}${bodyXml}</Table>
+ </Worksheet>
+</Workbook>`
+    },
+    // 目的:生成 Excel 文本单元格并按需应用表头样式。
+    excelCell(value, styleId) {
+      const style = styleId ? ` ss:StyleID="${styleId}"` : ''
+      return `<Cell${style}><Data ss:Type="String">${this.escapeXml(value)}</Data></Cell>`
+    },
+    // 目的:转义 Excel XML 特殊字符,避免访客数据破坏文件结构。
+    escapeXml(value) {
+      return String(value == null ? '' : value).replace(/[<>&'"]/g, char => ({
+        '<': '&lt;',
+        '>': '&gt;',
+        '&': '&amp;',
+        "'": '&apos;',
+        '"': '&quot;'
+      }[char]))
+    },
     // 目的:同步表格勾选状态,控制批量删除按钮可用性。
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.recordId)
@@ -217,14 +306,14 @@
     handleDetail(row) {
       this.$router.push(`/visitor/record/detail/${row.recordId}`)
     },
-    // 目的:删除访客记录;中台只读模式下禁止本地删除。
-    handleDelete(row) {
+    // 目的:批量删除已勾选的访客记录;中台只读模式下禁止本地删除。
+    handleDelete() {
       if (this.isMiddlePlatformReadonly) {
         this.denyMiddlePlatformWrite()
         return
       }
-      const ids = row ? [row.recordId] : toIdArray(this.ids)
-      this.$modal.confirm('是否确认删除选中的访客登记记录?').then(() => delVisitorRecord(ids)).then(() => {
+      const ids = toIdArray(this.ids)
+      this.$modal.confirm(`是否确认批量删除选中的 ${ids.length} 条访客登记记录?`).then(() => delVisitorRecord(ids)).then(() => {
         this.$modal.msgSuccess('删除成功')
         this.getList()
       })
diff --git a/ruoyi-ui/src/views/visitor-admin/system/config.vue b/ruoyi-ui/src/views/visitor-admin/system/config.vue
index d657e63..aeb0039 100644
--- a/ruoyi-ui/src/views/visitor-admin/system/config.vue
+++ b/ruoyi-ui/src/views/visitor-admin/system/config.vue
@@ -211,7 +211,9 @@
         { fieldCode: 'visitAreaNames', fieldName: '访问区域' },
         { fieldCode: 'validTime', fieldName: '有效期' },
         { fieldCode: 'plateNo', fieldName: '车牌号' },
-        { fieldCode: 'visitReason', fieldName: '来访事由' }
+        { fieldCode: 'visitReason', fieldName: '来访事由' },
+        { fieldCode: 'receiverName', fieldName: '接待人' },
+        { fieldCode: 'registerTime', fieldName: '登记时间' }
       ]
     }
   },
@@ -225,7 +227,9 @@
         visitAreaNames: 'A区 / 办公楼',
         validTime: '2026-07-07 09:00~18:00',
         plateNo: '苏A12345',
-        visitReason: '商务拜访'
+        visitReason: '商务拜访',
+        receiverName: '王五',
+        registerTime: '2026-07-23 09:00'
       }
       return this.printFieldOptions
         .filter(item => this.form.printFields.indexOf(item.fieldCode) !== -1)
diff --git a/ruoyi-ui/src/views/visitor-admin/system/version.vue b/ruoyi-ui/src/views/visitor-admin/system/version.vue
index 0f19d6a..8c42ae2 100644
--- a/ruoyi-ui/src/views/visitor-admin/system/version.vue
+++ b/ruoyi-ui/src/views/visitor-admin/system/version.vue
@@ -22,11 +22,6 @@
             <td>v{{ row.versionNo }}</td>
             <td class="version-content-cell">
               <span class="version-content-text">{{ row.updateContent || '-' }}</span>
-              <div class="content-preview">
-                <div class="preview-index">{{ index + 1 }}</div>
-                <div class="preview-content">{{ row.updateContent || '暂无更新内容' }}</div>
-                <div class="preview-foot">{{ parseTime(row.createTime) || '-' }}</div>
-              </div>
             </td>
             <td>{{ parseTime(row.createTime) }}</td>
             <td v-if="!isMiddlePlatformReadonly && $auth.hasPermi('visitor:version:remove')">
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 1f30345..87fc7a3 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -36,14 +36,14 @@
     proxy: {
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
-        target: `http://localhost:9098`,
+        target: `http://221.182.45.100:9799`,
         changeOrigin: true,
         pathRewrite: {
           ['^' + process.env.VUE_APP_BASE_API]: ''
         }
       },
       '/profile': {
-        target: `http://localhost:9098`,
+        target: `http://221.182.45.100:9799`,
         changeOrigin: true
       }
     },
diff --git a/visitor-admin-ui/css/version-update.css b/visitor-admin-ui/css/version-update.css
index 34f0dd9..294f8d4 100644
--- a/visitor-admin-ui/css/version-update.css
+++ b/visitor-admin-ui/css/version-update.css
@@ -110,70 +110,6 @@
   vertical-align: middle;
 }
 
-.content-preview {
-  position: absolute;
-  left: -62px;
-  top: 38px;
-  z-index: 10;
-  width: 204px;
-  min-height: 102px;
-  display: none;
-  padding: 0 10px 12px;
-  border: 1px solid #f0bc2d;
-  border-radius: 2px;
-  background: #fff;
-  box-shadow: 0 4px 12px rgba(15, 35, 70, 0.12);
-}
-
-.content-preview::before {
-  content: "";
-  position: absolute;
-  left: 46px;
-  top: -188px;
-  width: 1px;
-  height: 188px;
-  background: #dca51f;
-}
-
-.content-preview::after {
-  content: "";
-  position: absolute;
-  left: 42px;
-  top: -191px;
-  width: 8px;
-  height: 8px;
-  border-radius: 50%;
-  background: #dca51f;
-}
-
-.version-content-cell:hover .content-preview {
-  display: block;
-}
-
-.preview-index {
-  height: 16px;
-  margin: 0 -10px 12px;
-  padding-left: 9px;
-  color: #111827;
-  background: #ffd753;
-  font-weight: 700;
-  line-height: 16px;
-}
-
-.preview-content {
-  min-height: 42px;
-  color: #111827;
-  font-weight: 700;
-  line-height: 18px;
-  word-break: break-word;
-}
-
-.preview-foot {
-  margin-top: 26px;
-  color: #8a9ab0;
-  font-size: 11px;
-}
-
 .table-actions {
   display: flex;
   align-items: center;
diff --git a/visitor-admin-ui/css/visitor-machine.css b/visitor-admin-ui/css/visitor-machine.css
index 2c5f9c4..d86ae20 100644
--- a/visitor-admin-ui/css/visitor-machine.css
+++ b/visitor-admin-ui/css/visitor-machine.css
@@ -1020,6 +1020,8 @@
 .machine-table th:nth-child(8),
 .machine-table td:nth-child(8),
 .machine-table th:nth-child(9),
-.machine-table td:nth-child(9) {
-  width: 11.111%;
+.machine-table td:nth-child(9),
+.machine-table th:nth-child(10),
+.machine-table td:nth-child(10) {
+  width: 10%;
 }
diff --git a/visitor-admin-ui/js/role-form.js b/visitor-admin-ui/js/role-form.js
index 63821ad..49717df 100644
--- a/visitor-admin-ui/js/role-form.js
+++ b/visitor-admin-ui/js/role-form.js
@@ -89,7 +89,7 @@
     } else if (state.mode === "detail") {
       title = "角色详情";
     }
-    document.title = title + " - 运营活动管理平台";
+    document.title = title + " - 访客机自助登记管理平台";
     document.getElementById("pageTitle").textContent = title;
     document.getElementById("pageTab").textContent = title;
     document.getElementById("formActions").hidden = state.mode === "detail";
diff --git a/visitor-admin-ui/js/version-update.js b/visitor-admin-ui/js/version-update.js
index 33bfd5b..d6a1d95 100644
--- a/visitor-admin-ui/js/version-update.js
+++ b/visitor-admin-ui/js/version-update.js
@@ -155,11 +155,6 @@
         '  <td>' + escapeHtml(item.versionNo || "-") + '</td>',
         '  <td class="version-content-cell">',
         '    <span class="version-content-text">' + escapeHtml(item.updateContent || "-") + '</span>',
-        '    <div class="content-preview">',
-        '      <div class="preview-index">' + rowIndex + '</div>',
-        '      <div class="preview-content">' + escapeHtml(item.updateContent || "-") + '</div>',
-        '      <div class="preview-foot">' + escapeHtml(item.packageName || "安装包") + ' ' + escapeHtml(shortDate(item.createTime)) + '</div>',
-        '    </div>',
         '  </td>',
         '  <td>' + escapeHtml(item.createTime || "-") + '</td>',
         '  <td><div class="table-actions">',
diff --git a/visitor-admin-ui/js/visitor-machine.js b/visitor-admin-ui/js/visitor-machine.js
index 951ab40..3ad8a83 100644
--- a/visitor-admin-ui/js/visitor-machine.js
+++ b/visitor-admin-ui/js/visitor-machine.js
@@ -232,6 +232,7 @@
         '  <td>' + escapeHtml(item.deviceName || "-") + '</td>',
         '  <td>' + escapeHtml(item.brand || "-") + '</td>',
         '  <td>' + escapeHtml(item.deviceId || "-") + '</td>',
+        '  <td title="' + escapeHtml(item.fingerprint || "") + '">' + escapeHtml(item.fingerprint || "-") + '</td>',
         '  <td>' + escapeHtml(item.areaName || "-") + '</td>',
         '  <td>' + renderEnabledStatus(item.enabled) + '</td>',
         '  <td>' + renderOnlineStatus(item.onlineStatus) + '</td>',
diff --git a/visitor-admin-ui/js/visitor-record.js b/visitor-admin-ui/js/visitor-record.js
index 6c2bae2..a03492b 100644
--- a/visitor-admin-ui/js/visitor-record.js
+++ b/visitor-admin-ui/js/visitor-record.js
@@ -476,7 +476,15 @@
     if (text.length < 8) {
       return text || "-";
     }
-    return text.slice(0, 6) + "********" + text.slice(-4);
+    return text.slice(0, 4) + repeatString("*", text.length - 8) + text.slice(-4);
+  }
+
+  function repeatString(value, count) {
+    var result = "";
+    for (var index = 0; index < count; index++) {
+      result += value;
+    }
+    return result;
   }
 
   function toServerDateTime(value) {
diff --git a/visitor-admin-ui/pages/dashboard.html b/visitor-admin-ui/pages/dashboard.html
index 94f3857..6bbcf57 100644
--- a/visitor-admin-ui/pages/dashboard.html
+++ b/visitor-admin-ui/pages/dashboard.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>首页 - 运营活动管理平台</title>
+  <title>首页 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
 </head>
@@ -12,7 +12,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/department-management.html b/visitor-admin-ui/pages/department-management.html
index 6edc492..30eabdd 100644
--- a/visitor-admin-ui/pages/department-management.html
+++ b/visitor-admin-ui/pages/department-management.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>部门管理 - 运营活动管理平台</title>
+  <title>部门管理 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/department-management.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/door-management.html b/visitor-admin-ui/pages/door-management.html
index f63ac5e..6b68543 100644
--- a/visitor-admin-ui/pages/door-management.html
+++ b/visitor-admin-ui/pages/door-management.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>门禁设备管理 - 运营活动管理平台</title>
+  <title>门禁设备管理 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/door-management.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/employee-management.html b/visitor-admin-ui/pages/employee-management.html
index f835611..86299db 100644
--- a/visitor-admin-ui/pages/employee-management.html
+++ b/visitor-admin-ui/pages/employee-management.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>员工管理 - 运营活动管理平台</title>
+  <title>员工管理 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/employee-management.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/platform-admin.html b/visitor-admin-ui/pages/platform-admin.html
index bcb29b2..4c79f24 100644
--- a/visitor-admin-ui/pages/platform-admin.html
+++ b/visitor-admin-ui/pages/platform-admin.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>平台管理员 - 运营活动管理平台</title>
+  <title>平台管理员 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/platform-admin.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
       <nav class="menu" aria-label="主菜单">
         <a class="menu-item" href="./dashboard.html"><span class="menu-icon home"></span><span>首页</span></a>
diff --git a/visitor-admin-ui/pages/protocol-config.html b/visitor-admin-ui/pages/protocol-config.html
index caa5fa0..d765607 100644
--- a/visitor-admin-ui/pages/protocol-config.html
+++ b/visitor-admin-ui/pages/protocol-config.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>入园承诺 - 运营活动管理平台</title>
+  <title>入园承诺 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/protocol-config.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/role-form.html b/visitor-admin-ui/pages/role-form.html
index a99189c..c07b24a 100644
--- a/visitor-admin-ui/pages/role-form.html
+++ b/visitor-admin-ui/pages/role-form.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>角色 - 运营活动管理平台</title>
+  <title>角色 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/role-management.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
       <nav class="menu" aria-label="主菜单">
         <a class="menu-item" href="./dashboard.html"><span class="menu-icon home"></span><span>首页</span></a>
diff --git a/visitor-admin-ui/pages/role-management.html b/visitor-admin-ui/pages/role-management.html
index 6521429..c388dfd 100644
--- a/visitor-admin-ui/pages/role-management.html
+++ b/visitor-admin-ui/pages/role-management.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>角色管理 - 运营活动管理平台</title>
+  <title>角色管理 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/role-management.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
       <nav class="menu" aria-label="主菜单">
         <a class="menu-item" href="./dashboard.html"><span class="menu-icon home"></span><span>首页</span></a>
diff --git a/visitor-admin-ui/pages/system-config.html b/visitor-admin-ui/pages/system-config.html
index a569604..777ae29 100644
--- a/visitor-admin-ui/pages/system-config.html
+++ b/visitor-admin-ui/pages/system-config.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>信息配置 - 运营活动管理平台</title>
+  <title>信息配置 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/system-config.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/version-update.html b/visitor-admin-ui/pages/version-update.html
index 22c6187..f9e3c71 100644
--- a/visitor-admin-ui/pages/version-update.html
+++ b/visitor-admin-ui/pages/version-update.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>访客机版本更新 - 运营活动管理平台</title>
+  <title>访客机版本更新 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/version-update.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
diff --git a/visitor-admin-ui/pages/visitor-machine.html b/visitor-admin-ui/pages/visitor-machine.html
index 8f0e611..6923830 100644
--- a/visitor-admin-ui/pages/visitor-machine.html
+++ b/visitor-admin-ui/pages/visitor-machine.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>访客机管理 - 运营活动管理平台</title>
+  <title>访客机管理 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/visitor-machine.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
 
       <nav class="menu" aria-label="主菜单">
@@ -154,6 +154,7 @@
                     <th>设备名称</th>
                     <th>品牌</th>
                     <th>设备ID</th>
+                    <th>百度SDK指纹</th>
                     <th>所属区域</th>
                     <th>启用状态</th>
                     <th>在线状态</th>
diff --git a/visitor-admin-ui/pages/visitor-record-detail.html b/visitor-admin-ui/pages/visitor-record-detail.html
index 4c1f295..4e2405a 100644
--- a/visitor-admin-ui/pages/visitor-record-detail.html
+++ b/visitor-admin-ui/pages/visitor-record-detail.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>预约详情 - 运营活动管理平台</title>
+  <title>预约详情 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/visitor-record.css">
@@ -11,7 +11,7 @@
 <body>
   <div class="app-shell">
     <aside class="sidebar">
-      <div class="brand"><img src="../assets/login-avatar.svg" alt=""><strong>运营活动管理平台</strong></div>
+      <div class="brand"><img src="../assets/login-avatar.svg" alt=""><strong>访客机自助登记管理平台</strong></div>
       <nav class="menu" aria-label="主菜单">
         <a class="menu-item" href="./dashboard.html"><span class="menu-icon home"></span><span>首页</span></a>
         <section class="menu-group open">
diff --git a/visitor-admin-ui/pages/visitor-record.html b/visitor-admin-ui/pages/visitor-record.html
index 8b27922..e1721ad 100644
--- a/visitor-admin-ui/pages/visitor-record.html
+++ b/visitor-admin-ui/pages/visitor-record.html
@@ -3,7 +3,7 @@
 <head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <title>访客登记记录 - 运营活动管理平台</title>
+  <title>访客登记记录 - 访客机自助登记管理平台</title>
   <link rel="stylesheet" href="../css/dashboard.css">
   <link rel="stylesheet" href="../css/components.css">
   <link rel="stylesheet" href="../css/visitor-record.css">
@@ -13,7 +13,7 @@
     <aside class="sidebar">
       <div class="brand">
         <img src="../assets/login-avatar.svg" alt="">
-        <strong>运营活动管理平台</strong>
+        <strong>访客机自助登记管理平台</strong>
       </div>
       <nav class="menu" aria-label="主菜单">
         <a class="menu-item" href="./dashboard.html"><span class="menu-icon home"></span><span>首页</span></a>

--
Gitblit v1.7.1