# visitor **Repository Path**: chanchaw/visitor ## Basic Information - **Project Name**: visitor - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-17 - **Last Updated**: 2026-02-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: wechat-mini ## README ## 安装与部署 部署在染厂云服务器上,制作了守护进程,通过命令 `systemctl start visitor.service` 启动后台服务 项目所在绝对路径 `/projs/visitor/` ## 业务流程 ### 访客注册 1. 扫描访客注册专用永久二维码,是服务号 `SHOWA精工` 中生成的二维码 2. 用户扫描后先关注服务号,然后会收到引导关注用的模板消息,特别注意如果此前用户已经关注了服务号需要先取消关注重新扫描 3. 点击模板消息跳转到小程序 `showa常熟` 的访客注册页面 4. 填写注册信息保存即可 **异常情况** 2025年3月29日 之前允许访客不注册就可以在小程序中制作访单,在生成访单之前后台会先创建该微信用户 ### 制作访单 在小程序首页 ## 异常数据 ### 注册信息 表 `user_weixin` 是用户注册表,字段 `sys_remark = '服务号菜单项【新用户注册】新增本数据'` 表示用户点击了服务号菜单项 “新用户注册” 而不是点击注册用模板消息进入小程序,如果该数据中字段 `mini_id` 为空表示用户最终没有点击小程序注册页面的提交按钮。2025年3月14日 查看小程序注册页面代码提交函数中会检测 `unionId` 如果不存在会先请求获得数据后再请求后端进行注册,同时做了双保险,后端在写入用户表 `user_weixin` 时如果检测到 `unonId` 为空会向日志表 `log_mini` 中写入数据 `page=小程序新增用户时异常`。所以看到此类数据可以不予理会 - 用户没有注册。 ## 开发规范 页面标题UI组件 `view` 的类名使用 `page-title`,要求使用统一的字体样式,副标题类名为 `sub-title`,样式代码如下: ```css .page-title { font-size: 50rpx; font-weight: bold; color: #91a0c1; } ``` ## API ### 概述 请求本系统生成二维码携带的参数类型如:`{"permanent":1,"type":0,"sceneData":"10"}` 3个属性依次:1表示永久二维码0表示临时二维码,0表示关注用二维码,10表示普通访客。即属性 `sceneData` 是真正的二维码内容数据,本系统后台将3个属性依次以英文逗号连接作为场景值请求微信服务器生成二维码。 下面所有 url 前面使用的域名是 `https://showawx.染厂云域名/visitorbe/` 所有方法默认使用 `post json` 方式 | 用处 | url | 参数 | 备注 | | ---------------------------- | ------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- | | 请求登录用二维码 | /wxmp/qrCodeUrl | {"permanent":0,"type":3,"sceneData":"这里填写UUID"} | | | 验证UUID是否已登录 | /loginQrLog/isLogged/{uuid} | uuid拼接在路径后面 | | | 请求普通访客注册用二维码 | /wxmp/qrCodeUrl | {"permanent":1,"type":0,"sceneData":"10"} | 参数中3个属性依次表示:永久二维码,关注用二维码,普通访客 | | 受访单位普通用户关注用二维码 | /wxmp/qrCodeUrl | {"permanent":1,"type":0,"sceneData":"20"} | 参数中3个属性依次表示:永久二维码,关注用二维码,普通受访者 | | 门卫管理访单数据源 | /visit/getVisit4Doorman | 没有参数 | | | 进行中的访单 | /visit/getVisitInProgress | 没有参数 | | | 已完成的访单 | /visit/getVisitFinishedProgress | {"sdate":"2024-12-01","edate":"2025-01-20"} | | | 审核/驳回访单 | /visit/auditReject | {"unionId":微信用户unionId,"id":访单主键=visit.id,"audit":1审核0驳回} | | | 完工/取消完工 | /visit/setFinished | {"id":3,"finished":0,"finishedUnionId":"xxxx"} | | | 门卫管理访单扫码后请求后台 | visit/scanEntryQrcode | 0,4,11 | 字符串内元素依次表示:临时二维码,扫描入场用,访单主键 | ### API列表 下面所有 API 前面拼接的域名地址是:`https://showawx.染厂云域名/visitorbe`,例如第一个API拼接后是: `https://showawx.染厂云域名/visitorbe//wxmp/qrCodeUrl` ```json // 请求登录用二维码 url: /wxmp/qrCodeUrl 参数:{"permanent":0,"type":3,"sceneData":"这里填写UUID"} method: post json // 验证UUID是否已登录 url:/loginQrLog/isLogged/{uuid} 参数:例如上面 uuid拼接在路径后面 method: post json // 请求普通访客注册用二维码 url:/wxmp/qrCodeUrl 参数:{"permanent":1,"type":0,"sceneData":"10"} method: post json // 受访单位普通用户关注用二维码 url: /wxmp/qrCodeUrl 参数:{"permanent":1,"type":0,"sceneData":"20"} method: post json // 门卫管理访单数据源 url:/visit/getVisit4Doorman 参数:没有参数 method: post json 存储过程:usp_getVisit8Progress,最初的设计要传入参数,后来保留了传入参数但是没有实际用处 // 进行中的访单 url: /visit/getVisitInProgress 参数:没有参数 method: post json 存储过程:usp_getVisitInProgress // 已完成的访单 url: /visit/getVisitFinishedProgress 参数:{"sdate":"2024-12-01","edate":"2025-01-20"} method: post json 存储过程:usp_getVisitFinishedProgress // 已驳回的访单 /call/getRejectVisit 存储过程:usp_getRejectVisit // 审核 url: visit/audit 参数:{'unionId':'xxx','id':11} method: post json 属性 unionId = 审核人的 unionId,即触发本操作的微信用户的 unionId 属性 id = visit.id // 完工/取消完工 url: /visit/setFinished 参数:{"id":3,"finished":【1设置为完工,0取消完工】,"finishedUnionId":"xxxx"} method: post json // 门卫扫码获取访单 url: https://showawx.xdfznh.club/visitorbe/visit/scanEntryQrcode 参数:0,4,11 method: post json 注意: 扫码枪获取到的字符串类似:0,4,11 发送post请求时不需要用 JSON.stringify() // 查询指定日期段内的所有被驳回的访单 url: /call/getRejectVisit 参数:{"sdate":"2025-01-01","edate":"2025-01-30"} method: post json // 设置离场 url:https://showawx.xdfznh.club/visitorbe/visit/setLeave/4 参数:路径传参 - 路径后面追加主键 method: post json ``` ## 开发规范与架构 ### 数据库 * 由于使用了 `mybatis-flex` 的逻辑删除,并在源码的 `MybatisFlexConfig.java` 中设置了全局删除标识字段 `is_delete`,所有表(不管基础资料表、业务表、日志表)都要带有该字段,INT 类型默认0表示没有删除,表新增该字段的脚本是 ```sql alter TABLE visit add COLUMN is_delete INT DEFAULT 0 NULL comment 'mybatis-flex逻辑删除标识'; ``` ## 微信小程序 ### 制作访单 * 自动注册新用户 有新用户没有主动注册就直接制作访单,后台在新增访单之前会先向表 `user_weixin` 中新增用户后再新增访单,并会在 `user_weixin.insert_type` 中写入 `新增访单之前新增用户` ,用来表示此种情况。 ## 微信服务号 ### 模板消息 **受访者 - 待审核** ```bash 模板ID:KfpmTCldXiOzdPkniY1npl9B2ujE6XsE_U6c8_QOpWs # 点击待审核的模板消息会跳转到小程序页面,传递参数是访单的主键 点击跳转:pages/billqr/billqr?id=11 # 调用方法: TemplateMsgUtils.java 的方法 pushInterviewee2Audit,传递访单作为参数 # 通过下面方法调用API立即推送给受访者提醒审核的模板消息 http://localhost:17073/visitorbedev/test/pushInterviewee2Audit/261 ``` **访客 - 访单已被审核通过** ```bash # 调用下面API发送访客已审核通过的模板消息 http://localhost:17073/visitorbedev/test/pushVisitorAudited/261 ``` ### accessToken * 项目启动后不会自动立即获取 `accessToken`,在执行业务逻辑时用到时会先从缓存中获取,如果已经过期则会请求新的 `accessToken` ### 访单二维码 2024年12月31日 设计所有二维码内容类似关注用二维码 `1,0,10`,依次表示:1 - 永久二维码,0 - 关注用二维码,10 - 普通访客 那么访单二维码的内容是 `0,4,1134`,依次表示:0 - 临时二维码,4 - 访单二维码,1134 - 访单主键 = visit.id 在门卫管理页面扫描二维码用的文本框处可通过录入 `0,4,1123` 然后回车来模拟扫码的动作,正常情况下会弹出该访单的信息 `2025年3月17日 20:01:48` 在门卫处新增快捷通道二维码 `1,1,0` 三个数字依次表示:永久二维码,访单二维码,获取本微信用户当天最后一个待进场的访单,访客微信扫描该二维码后跳转到 “当天最后一个待进场” 的访单的详情页面 - 很多访客在门卫处找服务号、小程序要找半天。后台查询访单的状态由高到低依次是:已进场、待进场 ### 永久二维码 #### 概述 所有 `API` 见源码下文件 `doc\软件设计与API.xlsx` 数据库设计中字段 `user_weixin.type` 的设计从10开始,使一位数为保留字。初步设计角色如下: ```sql 默认10表示普通访客,11贵宾访客 20被访单位普通用户,21被访单位管理层,22被访单位总经理,23被访单位管理员, 30保安公司普通员工,31保安公司管理层,32保安公司总经理,33保安公司管理员, 40开发人员,41软件公司管理层,42软件公司总经理,43管理员,44me ``` 2024年11月30日 09:06:28 最终设计请求创建二维码票据的对象模型如下 ```java public class CreateQrTicketReqParam implements Serializable { private static final long serialVersionUID = 1L; private Integer permanent;// 0临时二维码,1永久二维码 private Integer type;// 二维码用途:0用于关注的二维码,1用于传输数据,2用于跳转连接 private String sceneData;// 二维码场景值,用字符串表示各种数据类型:数组、对象、数字等。在具体场景使用时要先转换数据类型 // 关注用二维码的 sceneData 对应对象模型 FollowQr。其他用途的二维码会对应其他模型 } public class FollowQr implements Serializable { private static final long serialVersionUID = 1L; private String site;// 二维码所在场所,实现同一个功能的二维码所在场地不同 private String create_user;// 创建人 private LocalDateTime create_time;// 创建时间,要求格式是:2024-11-30 09:16:42 private String sceneData;// 场景值,有实际业务意义的数据。其他属性都是用于描述二维码本身 } ``` 根据模型,创建普通访客的参数如下,属性 `sceneData` 对应模型 `FollowQr` 其中的 `roleType=10` 表示普通访客。 ```json { "permanent":1, "type":0, "sceneData":"{"site":"门卫","create_user":"开发人员","create_time":"2024-11-30 09:19:54","roleType":"10"}" } ``` #### 列表 普通访客 ```bash # 请求ticket的参数 {"permanent":1,"type":0,"sceneData":"10"} # ticket gQEz8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyZHBoYjVSUU84Sl8xMDAwME0wN0YAAgTwxEpnAwQAAAAA # 二维码图片地址 https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQEz8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyZHBoYjVSUU84Sl8xMDAwME0wN0YAAgTwxEpnAwQAAAAA ``` 贵宾访客 ```bash # 请求ticket的参数 {"permanent":1,"type":0,"sceneData":"11"} # ticket gQFf8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyaDlWbzRvUU84Sl8xMDAwMGcwNzkAAgTSxUpnAwQAAAAA ``` 开发人员 ```bash {"permanent":1,"type":0,"sceneData":"40"} gQHD8TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAydVZWMDRjUU84Sl8xMDAwMGcwN0MAAgSExkpnAwQAAAAA ``` 特权受访者关注用二维码 ```javascript # 请求参数 {"permanent":1,"type":0,"sceneData":"21"} # 二维码连接 https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQFq8jwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyWFRGRzRiUU84Sl8xMDAwMGcwN3EAAgSBz4hnAwQAAAAA ``` 访客扫描后跳转到当天最后一个待进场访单详情页面 ```bash # 请求参数 {"permanent":1,"type":1,"sceneData":"0"} # ticket: # 二维码连接: ``` ## 开发工具 ### 资料 ```javascript 陈潼乐微信号 union_id: oRY9t6_R8WiBBlTc42skrc65yEQ8 陈彤悦微信号 union_id: oRY9t620nAB61TkMgZU_uoDlzK_o 我的 union_id: oRY9t60-AJybBBEZPCWu9Y59tkyo ``` ### 删除指定用户 给存储过程 `usp_delUser` 传入 `openId` 会删除指定用户的所有访单信息以及该用户数据 ### 清除业务数据 ```sql TRUNCATE TABLE user_weixin; TRUNCATE TABLE visit; TRUNCATE TABLE log_error; TRUNCATE TABLE log_mini; TRUNCATE TABLE log_login; TRUNCATE TABLE log_scan_qrcode; TRUNCATE TABLE login_qr_log; ``` ### sql ```sql ``` ## 改善计划 * 访单登记页面 * 自动填充当前微信用户上一次访单的内容,起始和终止日期要使用当前的日期 * 添加按钮,用户可主动选择填充上一单的内容 * 在服务号、小程序获取到的 `openId` 分别写入到 `user_weixin` 的不同字段上,注意同时写入 `unonId` * 2024年12月28日 13:57:31 * 注册成功的响应:注册成功!,再次注册则提示:修改成功。两个角色的注册功能都这样 * 小程序中制作访单的页面下拉动作刷新微信用户的信息(测试时转换微信用户的角色类型) * 访客注册成功后在注册的按钮上面显示注册成功的消息 * 整理微信更新需求 * 制作访单的手机号码、身份证号必填,显示为星号 X * 制作访单时默认填充上一次的内容 * 访客的注册类型:供应商/物流/客户/政府机关/个人/其他 * 不需要部门职务,取消昵称 * 内部员工页面中为客户制作访单 X * 制作访单后立即显示二维码 X * 连续点击制作访单 X * 访客注册页面手机号、身份证号要求必填 X * 访客申请中身份证号码还没有设置为必填,没有自动填充手机号码 X * 内部员工页面驳回、审核操作后都要刷新统计数据 X * 制作访单时姓名变更自动填充其最后一笔访单的数据(代位申请时有用) X * 代位申请中自动填充当前微信用户的信息到受访者信息中,访客的信息填写上次代位的访客信息或者留空 X * 2025年1月10日 14:13:56 测试 * 企业内部员工注册页面打开焦点默认在姓名上,上面添加提示文案:输入您的真实姓名后系统会匹配您所在的部门 X * 微信调用键盘后整体页面高度缩小到可以显示出提交按钮的高度 * 注册成功后在提交按钮上显示文案:您已于 2025年1月10日 14:15:47 注册成功。(这里显示的时间要求是DB新增行后的字段 create_time) X * 本厂员工资料中没有该姓名......的提示事件调整为5秒钟 X * 制作访单页面,公司名称、身份证号后面的留空太多 * 张俊已经注册,制作访单时仍提示其没有注册 * 2025年1月13日 14:38:07 改善计划 * 保存访单时检测结束日期时间必须大于等于开始时间 * 进入访单页面没有自动填充上一次访单信息 ## 开发记录 * 2024年12月9日 13:06:35,待测试项目 * 进入制作扫码进场功能,要测试该API * 2024年12月5日 09:58:50 1. 新增小程序运行日志 `log_mini` ## 更新日志 ### 2025年3月17日 小程序上传签字图片以及对应的后端接口使用请求签名,本次更新只应用这一个接口请求签名,待使用几天观察效果后再推广到其他接口 ### 2025年3月2日 1. 制作访单的 “起始时间” 不可小于当前时间 2. “终止时间” 必须大于 “起始时间”,两个时间要求为同一天 3. 来访类型添加:提货 4. 设置 “来访缘由” 为必填项 5. 门卫扫码只允许当日的访单,不可提前或延后 6. 添加要素 “开车进场”,默认 “是” 此时要求车牌号必填,修改为 “否” 后车牌号调整为可选项 7. 点击通知审核的模板消息跳转到访单的详情页面,显示完整的访单信息 ![](./doc/img/访单详情页面显示完整的访单信息01.jpg) 8. 门卫扫码后显示访单信息,要求手动点击 “入场”,再次扫描二维码状态更换为 “离场”,需要手动点击确认离场 ![](./doc/img/扫码设置状态.png)