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 => ({
+ '<': '<',
+ '>': '>',
+ '&': '&',
+ "'": ''',
+ '"': '"'
+ }[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