EMI智慧SOP看板(安灯)— 速记版
📋 速记表(面试前快速扫)
| 题 | 一句话结论 | 关键词 |
|---|---|---|
| Q1 | 事件驱动消息+45s心跳,但自动重连被注释 | 事件驱动 心跳 重连被注 |
| Q2 | Web Serial 控塔灯,0x协议,错误分支 catch | WebSerial baud9600 私有协议 |
| Q3 | MediaDevices 多摄像头,Canvas 取帧转 Blob | enumerateDevices drawImage toBlob |
| Q4 | 微信 OAuth 扫码绑定,URL query/hash 分工 | 扫码绑定 OAuth hash路由 |
| Q5 | v-scale-screen 等比缩放,键盘弹顶特殊处理 | 等比缩放 transform 键盘 |
| Q6 | Pinia websocket store + flags 布尔位 | flags watch storeToRefs |
| Q7 | 多环境工厂函数 + ip.json | 工厂函数 环境 分网 |
| Q8 | 自研 MediaViewer 图+视频混播 | 从零 viewer 视频混播 |
| Q9 | SOP 树形模板 + SortableJS 行拖拽 | 树形 拖拽 transform冲突 |
Q1: WebSocket 实时双向通信
面试官可能问:WebSocket 怎么设计的?断线怎么办?
🗣️ 口述稿:
WebSocket 是通信中枢,事件驱动。定义几类消息:incomingRequest/pendingRequest(来新活提示跳处理页,5 秒倒计时自动跳)、towerLight(解析成十六进制指令控塔灯)、serialPort(串口状态)、heart(45 秒心跳)、close(被挤下线)。URL 拼工位 ID,后端就知道把请求推给哪个工位。
💡 关键词提示:事件驱动 45s心跳 工位ID
⚠️ 备注:
- [重要] README/简历写"自动重连",但代码
reconnect()在onclose里是被注释掉的,实际是"弹窗确认后 location.reload 整页刷新"。别吹已实现自动重连 - 被问为什么注释:自动重连会和"用户切工位"冲突,旧连接弹回来带旧工位身份乱跳,所以宁可让用户确认 reload 也不脚本乱来
- 重连那段确实写了指数退避(1s→30s)思路和 reconnect() 方法,但没启用——可当"做过又踩坑暂缓"
追问①:为什么当初注释掉自动重连?
自动重连和用户切工位冲突,若换工位后旧连接自动回来带旧身份乱跳,所以宁可用户确认 reload。
追问②:要改回自动重连注意什么?
先分"真断线"还是"主动切工位",用 flags.webSocketUserIdChanged 区分:用户 ID 变了就不重连、没变才重连。这个区分条件讲出来说明不是无脑加回。
Q2: Web Serial + PLC 塔灯
面试官可能问:浏览器怎么控制塔灯?
🗣️ 口述稿:
用 Web Serial API 做浏览器↔PLC 串口通信。navigator.serial.requestPort() 弹选择器选 USB,open({baudRate:9600}) 打开,writable.getWriter() 写十六进制指令。私有协议两位十六进制:第一位操作(1亮/4闪/2灭)、第二位目标(1红/2黄/4绿/8蜂鸣),如 11=红灯亮、42=黄灯闪。
💡 关键词提示:WebSerial baud9600 私有协议 getWriter
⚠️ 备注:
- 难点在错误处理:open() 报错五花八门(Access denied/port already open/open in progress/device failed),全做分支 catch 给中文提示并引导回设置页+不再提示
- 为什么不用 Node serialport:纯前端 SPA、无 Electron 主进程,Web Serial 是 Chrome 89+ 原生零依赖
- [需自行确认]:"延迟低于 500ms"代码没埋点,按体感讲别当实测
- 只 Chrome 支持是最大局限,非 Chrome 就得 Electron+serialport
追问①:为什么不用 Node serialport?
纯前端 Vue SPA 没主进程,Web Serial 是 Chrome 原生零依赖;转折点是它只 Chrome 支持,客户换浏览器就废,后续该评估 Electron。
追问②:非 Chrome 浏览器怎么办?
直接不支持,我用 'serial' in navigator 先判断给提示。真要可靠得上 Electron+serialport,但当时够用。边界说清比吹稳好。
Q3: 多摄像头 + 拍照上传
面试官可能问:多摄像头怎么管理、拍照怎么上传?
🗣️ 口述稿:
用 MediaDevices:enumerateDevices() 列出视频输入过滤 videoinput,切换时先 stop() 旧流再按新 deviceId 重建。拍照 video→Canvas drawImage 取帧→toDataURL 预览→toBlob 转二进制→FormData 上传。
💡 关键词提示:enumerateDevices drawImage toBlob FormData
⚠️ 备注:
- 为什么经 Canvas 不直接截 video:drawImage 精确控尺寸、toBlob 可指定压缩格式/质量、为裁剪标注留余地
- 体验细节:加载 Loading、失败按"未找到/权限拒/其他"分类+刷新、拍照后变"重拍/确认上传"
- 权限被拒和真是没设备要区分文案
追问①:getUserMedia 权限被拒怎么提示?
区分"用户拒绝"和"真没设备",分别给权限类和设备类文案,不是一把 try-catch 完事。
追问②:多路同时开会不会压垮平板?
会,切换时不关旧流多路很伤,我尽量同一时刻只开一路并回收流,有内存意识。
Q4: 动态二维码 + 微信绑定
面试官可能问:微信扫码绑定怎么实现?
🗣️ 口述稿:
用 qrcodejs2 生成二维码,URL 拼微信 OAuth:redirect_uri=...&response_type=code&scope=snsapi_userinfo&state=...#wechat_redirect,工位信息放 query、路由放 hash。用户扫码→微信回调带 code 回 /wechat→前端取 code+工位信息调 /andon/wechat/bind→之后能在微信收推送。
💡 关键词提示:OAuth扫码 redirect_uri query/hash分工
⚠️ 备注:
- 最有含金量:redirect_uri 怎么同时塞工位信息和路由——项目用 createWebHashHistory,微信只认
?前 path 忽略#,所以工位放 query、路由留 hash 两边不丢 - [需自行确认]:"从 5 分钟缩到 20 秒"是体验描述没精确计时,别当硬数据
追问①:为什么工位信息放 query、路由留 hash?
项目路由在 hash 后,微信只认 ? 前 path 忽略 #。工位放 query、路由留 hash,两边都不丢。
追问②:绑定以前为什么 5 分钟?
以前人工纸质登记再管理员录入;现在扫码带 openid、表单预填、补手机号姓名就确认。
Q5: 工业平板屏幕适配
面试官可能问:分辨率五花八门怎么适配?
🗣️ 口述稿:
用 v-scale-screen 等比缩放,固定设计 1080×1920(竖屏)。监听容器 resize,按实际/设计比例算 transform:scale() 等比。特殊处理软键盘弹出把页面顶上去的问题:给 v-screen-box 设 minWidth/minHeight 为实际屏尺寸,防键盘 resize 挤压。
💡 关键词提示:等比缩放 transform:scale 键盘顶起
⚠️ 备注:
- 最值得讲:键盘弹出触发 resize 导致缩放乱跳——移动端不监听 resize、只在 DOM 加载完设一次尺寸,专避键盘 resize
- 追问会套到 transform scale 后鼠标坐标反算(同数字孪生/v-zoom-up 同款坑)
- 为什么不用 rem:等比缩放保证逐像素一致不破版,rem 是自适应非等比
追问①:transform scale 后点击坐标怎么对?
要用 scale 系数反算真实坐标,这和数字孪生、v-zoom-up 是同一个坑,说明你这方面有连续心智。
追问②:为什么不用 rem?
等比缩放保证和设计稿逐像素一致绝不破版,rem 是自适应不是等比,大屏要的是所见即得。
Q6: Pinia WebSocket Store
面试官可能问:把 WS/串口/消息路由塞进一个 store 怎么组织?
🗣️ 口述稿:
用 Pinia Composition API 风格(defineStore+setup)写 webSocket store 当状态中心:管 ws 实例、serialPort、flags 布尔位、定时器引用;方法有 webSocketConnect/sendMessageToSerialPort/openSerialPortConnection 等;onmessage 按 type 分发到统一入口。
💡 关键词提示:defineStore setup flags 统一分发
⚠️ 备注:为什么 flags 一个 ref 包一组布尔位——为了 storeToRefs 解构后前端 watch(flags.value.refreshRequestMap) 精确监听某一位。
追问①:页面卸载怎么清理?
window.onbeforeunload 里 ws.close()+清心跳/重连定时器+设 isUnloading 防止 onclose 触发重连逻辑。
追问②:为什么消息走 store 方法不走全局改?
统一收敛到入口,方便在消息路由处统一日志/状态/分发,不散在组件。
Q7: 多环境 API 配置
面试官可能问:开发和线上 API 怎么区分?
🗣️ 口述稿:
src/api/utils.ts 封装四类工厂函数:baseURLApi(REST)、wsApi(WebSocket)、baseURL(页面基地址)、wechatAppId;内部 switch 分 dev/test/prod/demo/trial 五种环境。开发走本机/局域网 IP、线上走 goomaker。
💡 关键词提示:工厂函数 五环境 分网IP
⚠️ 备注:为什么 API 和页面 baseURL 分开——前端静态在 /andon-system/、API 独立后端走 /andon-test-api/、开发后端可能在别人本机。
追问①:ip.json 干嘛用?
团队协作时后端 IP 不同,抽到 gitignore 的 ip.json 每人填自己的,不用改代码。这体现全栈团队意识。
Q8: 自定义 MediaViewer
面试官可能问:图片/视频预览为什么自己写?
🗣️ 口述稿:
基于 el-image-viewer 源码改造支持图片+视频混播:el-image-viewer 只支持图片,安灯类型说明要视频。urlList 每项带 type、v-show 切 img/video;teleport to body + z-index 9999 避免父容器裁切。
💡 关键词提示:自研 图+视频混播 teleport
⚠️ 备注:为什么不用现成 viewer.js/photoswipe——都不支持视频且包体积敏感(viewer 带 jQuery、photoswipe 偏重);自研零依赖但工作量+责任自担。
追问①:自研有没有代价?
有——自己维护键盘/滚轮/拖拽交互,工作量不小、边界处理不如现成库。自研=控体积但责任自担,成熟。
Q9: SOP 模板 + 拖拽排序
面试官可能问:SOP 模板和排序怎么实现?
🗣️ 口述稿:
安灯类型按车间分不同模板(织造/印染各一套),用树形 templateTableData + el-table 的 tree-props 展示;行排序用 SortableJS,handle 只允许专门手柄拖,拖完调后端更新 oldIndex→newIndex。
💡 关键词提示:树形模板 SortableJS transform冲突
⚠️ 备注:
- 最值钱的真实坑:SortableJS 的 ghost 元素在 v-scale-screen 的 transform:scale 环境下定位异常,用全局 CSS 覆盖 sortable-chosen/ghost 为 position:relative!important 修
- 为什么不用 EP 自带:EP 只有列拖拽没行拖拽,SortableJS 是标准方案还能编辑态禁拖
追问①:排序为什么不用 Element Plus 自带?
EP 只有列拖拽没行拖拽;SortableJS 是标准方案、动画好、兼容好,还能用 disabled/pointer-events-none 在编辑状态禁拖。
🎙️ 行为面试
为什么做这个项目?
公司给纺织厂做数智化改造。传统安灯靠物理按钮+对讲机:慢、没记录、无法追溯。老板要做数字化版,工人点平板发起请求、处理人实时收到、全程有记录。我从 0 独立搭前端,后端 Java 同事配合。
💡 关键词:安灯数字化 慢无记录 独立前端
⚠️ 备注:后端是 Java,不是全栈项目这个,别答成"我也写了后端"。
最大难点?
- Web Serial 调试——浏览器控串口冷门、资料少报错不友好,我在产线枚举各种异常做成分类引导
- v-scale-screen 和 SortableJS 的 transform 冲突,调几小时定位到 ghost 的 position 问题
💡 关键词:串口异常枚举 transform碰拖拽
⚠️ 备注:挑 1-2 个"坑+怎么磨"讲,别报菜名。
遗憾/弯路?
- WebSocket 自动重连被我注释掉了——遇工位切换冲突降级成弹窗确认+整页刷新,坑没回来收
- 没写单元测试(WS/WebSerial 要 mock 环境没搭)
- 强依赖 Chrome(Web Serial 只有 Chrome)+ 推送只微信有频率限制,并发大要加页面播报兜底
💡 关键词:重连被注 零测试 依赖Chrome
⚠️ 备注:第 1 条呼应 Q1 修正,讲它比掩着加分。
怎么跟后端协作?
后端 Java 写的。我先和后端定死 WebSocket 消息结构({type,msg})和 REST 接口定义,开发用本地 Mock+Vite 代理联调。先静态契约后联调是标准姿势。
💡 关键词:先契约后联调 Mock+Vite
⚠️ 备注:讲"连接口含义先定、再各自开发"这套协作节奏。
为什么叫安灯?
Andon 来自丰田生产模式——产线拉绳亮灯、班组长看到就处理。我们把它数字化:拉绳变成点平板、请求变成实时通知。既讲业务又讲技术,一箭双雕。
💡 关键词:丰田Andon 拉绳→点平板
⚠️ 备注:短,但讲"业务+技术各一半"很完。
🃏 极简速记卡(面试前5分钟看)
- Q1 WebSocket:事件驱动+45s心跳,但自动重连被注释
- Q2 塔灯:WebSerial baud9600,私有协议,错误分支
- Q3 摄像:enumerateDevices+Canvas取帧toBlob
- Q4 绑定:OAuth扫码,工位query路由hash
- Q5 适配:等比缩放+键盘弹顶处理
- Q6 store:Pinia websocket+flags布尔位
- Q7 环境:工厂函数五环境+ip.json
- Q8 viewer:自研图+视频混播
- Q9 SOP:树形模板+SortableJS拖拽
- 行为 动机:安灯数字化;难点:串口异常+transform冲突;遗憾:重连被注+零测试
上一篇:04-惠东移动(微信小程序) 下一篇:06-EMI数字孪生平台