加班统计工具【1】七夕还在加班?基于Vue+AI实现加班统计工具开发
作为程序员,“加班” 是常见职场场景 —— 不少朋友在换工作时,因缺乏目标公司的加班情况参考,容易陷入 “踩坑” 困境。此前有类似加班数据参考项目,但受外部环境影响,访问便利性下降。
基于此,我决定开发一款轻量化加班统计在线工具,核心是 “用技术提供客观职场数据参考”,且全程注重合规设计(无排名、不对比,仅做数据收集展示)。本文分享工具的技术实现细节,包括前端交互逻辑、AI 辅助开发技巧、合规性技术设计。
一、项目背景:为什么做这款工具?
- 职场需求驱动:身边很多同事换工作时,希望提前了解目标公司的加班频率、工作压力,但缺乏可信的参考渠道,因此需要一款 “数据真实、功能轻量化” 的工具;
- 技术落地场景:此前创业时注册过公司(目前闲置),可借助企业资质推进合规备案,避免个人开发的合规风险;同时,用 Vue 做前端、AI 辅助生成基础代码,能快速实现核心功能,降低开发成本。
二、核心功能设计:合规优先,极简实用
工具 V1 版本聚焦 “数据真实 + 合规安全”,仅保留 2 个核心功能,所有设计均围绕 “符合相关法规” 展开:
1. 手机号短信认证:确保数据源头真实
- 技术逻辑:用户进入工具后,需完成手机号短信验证(前端做格式校验,后端做验证码有效性验证),避免恶意刷数据;
- 合规细节:手机号存储采用 “MD5 脱敏 + 数据库加密”,仅在验证时临时存储明文,验证后立即销毁,符合《个人信息保护法》对 “敏感个人信息” 的处理要求。
2. 加班数据结构化填写:提供客观参考维度
用户认证后,可填写 4 类核心数据(均为下拉选择或数值输入,减少主观描述偏差):
数据维度 |
选项 / 输入规则 |
设计目的 |
公司名称 |
手动输入(需填写全称,如 “XX 科技有限公司”) |
确保查询时精准匹配 |
加班频率 |
几乎不加班 / 每周 1-2 天 / 每周 3-4 天 / 每周 5-6 天 / 每天加班 |
标准化频率描述 |
每日加班时长 |
1 小时内 / 1-2 小时 / 2-3 小时 / 3 小时以上 |
避免 “模糊表述”(如 “经常加班”) |
工作压力评分 |
1-10 分(1 = 无压力,10 = 极度焦虑) |
量化主观感受,提高参考性 |
3. 合规性技术兜底:不做 “敏感功能”
- 无任何 “公司排名”“加班时长 PK” 模块,仅支持 “按公司名称查询历史填写数据”;
- 数据展示时隐藏 “填写人信息”,仅显示 “脱敏后的统计结果”(如 “XX 公司:近 30 天有 12 人填写,60% 选择‘每周 3-4 天加班’”),避免隐私泄露。
三、技术实现:Vue + AI 辅助开发(附核心代码)
作为个人开发,用 AI 生成基础代码框架(如表单校验、短信倒计时逻辑),再手动优化合规与安全细节,大幅提升开发效率。以下是核心模块的技术实现代码(已做安全加固):
1. 技术选型理由
- 前端框架:选 Vue 2.x(CDN 引入,无需构建环境,轻量化),适配工具 “极简功能” 定位;
- 交互工具:Axios 做接口请求(封装拦截器,处理请求加密);
- 安全措施:手机号脱敏用 md5.js(前端临时加密,后端存储加密后的数据),避免明文传输。
2. 核心模块代码实现
(1)短信认证组件(含手机号脱敏 + 格式校验)
<!-- 短信认证组件:Vue 2.x + CDN 实现 --> <template> <div class="auth-container"> <h3>职场数据参考工具 - 身份验证</h3> <form @submit.prevent="handleAuth"> <!-- 手机号输入 --> <div class="form-item"> <label>手机号:</label> <input type="tel" v-model="phoneNum" placeholder="请输入11位手机号" @input="formatPhone" <!-- 实时格式化(脱敏显示) --> required > <p class="tip" v-if="phoneNum.length>0">{{ formattedPhone }}</p> </div> <!-- 验证码输入 --> <div class="form-item"> <label>验证码:</label> <div class="code-group"> <input type="text" v-model="verifyCode" placeholder="请输入6位验证码" maxlength="6" required > <button type="button" class="get-code-btn" @click="getVerifyCode" :disabled="isCodeSending" > {{ isCodeSending ? `倒计时${countDown}s` : '获取验证码' }} </button> </div> </div> <button type="submit" class="submit-btn">验证通过,进入填写</button> </form> </div> </template> <script> // 引入 md5 用于手机号脱敏(CDN 引入,无需安装) import md5 from 'https://cdn.jsdelivr.net/npm/md5@2.3.0/dist/md5.min.js'; export default { data() { return { phoneNum: '', // 原始手机号(仅前端临时存储,不落地) formattedPhone: '', // 脱敏后手机号(如:138****5678) verifyCode: '', isCodeSending: false, countDown: 60 } }, methods: { // 手机号脱敏格式化 formatPhone() { const phone = this.phoneNum.replace(/\D/g, ''); // 过滤非数字 if (phone.length <= 3) { this.formattedPhone = phone; } else if (phone.length <= 7) { this.formattedPhone = `${phone.slice(0,3)}****${phone.slice(3)}`; } else { this.formattedPhone = `${phone.slice(0,3)}****${phone.slice(7)}`; } }, // 获取验证码(模拟接口请求,实际需对接后端) getVerifyCode() { // 1. 手机号格式校验 const phoneReg = /^1[3-9]\d{9}$/; if (!phoneReg.test(this.phoneNum.replace(/\D/g, ''))) { alert('请输入正确的11位手机号'); return; } // 2. 模拟发送验证码(实际项目中,此处需传“脱敏后的手机号”给后端) this.isCodeSending = true; const timer = setInterval(() => { this.countDown--; if (this.countDown <= 0) { clearInterval(timer); this.isCodeSending = false; this.countDown = 60; } }, 1000); // 3. 后端请求示例(传脱敏后的数据,避免明文) // axios.post('/api/send-code', { // phone: md5(this.phoneNum) // 前端临时 md5 脱敏,后端需对应解密逻辑 // }).then(res => { // if (res.data.code !== 200) alert('验证码发送失败,请重试'); // }); }, // 提交验证(模拟跳转) handleAuth() { if (this.verifyCode.length !== 6) { alert('请输入6位验证码'); return; } // 验证通过:存储“已认证”状态(仅前端临时存储,不落地用户信息) localStorage.setItem('isAuth', 'true'); this.$router.push('/fill-data'); // 跳转至数据填写页 } } } </script> <style scoped> .auth-container { max-width: 500px; margin: 2rem auto; padding: 2rem; border: 1px solid #eee; border-radius: 8px; } .form-item { margin-bottom: 1.5rem; } .code-group { display: flex; gap: 1rem; } .code-group input { flex: 1; } .get-code-btn { padding: 0.5rem 1rem; background: #409eff; color: #fff; border: none; border-radius: 4px; cursor: pointer; } .submit-btn { width: 100%; padding: 0.8rem; background: #67c23a; color: #fff; border: none; border-radius: 4px; cursor: pointer; } .tip { color: #999; font-size: 0.875rem; margin-top: 0.3rem; } </style> |
(2)加班数据填写组件(含合规校验)
<!-- 数据填写组件:结构化输入+合规校验 --> <template> <div class="fill-container"> <h3>职场加班情况填写(仅做客观参考)</h3> <form @submit.prevent="submitData"> <!-- 公司名称(必填,需全称) --> <div class="form-item"> <label>公司全称 <span class="required">*</span></label> <input type="text" v-model="formData.companyName" placeholder="如:XX科技有限公司(需准确全称)" required > <p class="tip">填写全称可提高数据查询准确性</p> </div> <!-- 加班频率(下拉选择,标准化) --> <div class="form-item"> <label>平均加班频率 <span class="required">*</span></label> <select v-model="formData.frequency" required> <option value="">请选择</option> <option value="几乎不加班">几乎不加班(每月≤2次)</option> <option value="每周1-2天">每周1-2天</option> <option value="每周3-4天">每周3-4天</option> <option value="每周5-6天">每周5-6天</option> <option value="每天加班">每天均需加班</option> </select> </div> <!-- 加班时长(下拉选择) --> <div class="form-item"> <label>每日加班时长 <span class="required">*</span></label> <select v-model="formData.duration" required> <option value="">请选择</option> <option value="1小时内">1小时内</option> <option value="1-2小时">1-2小时</option> <option value="2-3小时">2-3小时</option> <option value="3小时以上">3小时以上</option> </select> </div> <!-- 压力评分(数值输入,量化) --> <div class="form-item"> <label>工作压力评分(1-10分) <span class="required">*</span></label> <input type="number" v-model="formData.stressScore" min="1" max="10" placeholder="1=无压力,10=极度焦虑" required > </div> <!-- 补充说明(可选) --> <div class="form-item"> <label>补充说明(可选)</label> <textarea v-model="formData.remark" rows="3" placeholder="如:是否有加班费、是否双休等" ></textarea> </div> <button type="submit" class="submit-btn">提交数据(仅用于客观参考)</button> </form> </div> </template> <script> import axios from 'https://cdn.jsdelivr.net/npm/axios@0.27.2/dist/axios.min.js'; export default { data() { return { formData: { companyName: '', frequency: '', duration: '', stressScore: '', remark: '' } } }, mounted() { // 校验是否已认证(未认证则跳转) if (localStorage.getItem('isAuth') !== 'true') { this.$router.push('/auth'); } }, methods: { submitData() { // 1. 基础数据校验 if (!this.formData.companyName.trim()) { alert('请填写公司全称'); return; } // 2. 提交数据(实际项目需加密请求) axios.post('/api/submit-overtime', { ...this.formData, submitTime: new Date().getTime() // 增加提交时间戳,避免重复提交 }).then(res => { if (res.data.code === 200) { alert('数据提交成功!感谢你的客观分享'); // 重置表单 this.formData = { companyName: '', frequency: '', duration: '', stressScore: '', remark: '' }; } else { alert('提交失败,请稍后重试'); } }).catch(err => { console.error('提交异常:', err); alert('网络异常,请检查网络后重试'); }); } } } </script> <style scoped> .fill-container { max-width: 500px; margin: 2rem auto; padding: 2rem; border: 1px solid #eee; border-radius: 8px; } .form-item { margin-bottom: 1.5rem; } .required { color: #f56c6c; } .submit-btn { width: 100%; padding: 0.8rem; background: #67c23a; color: #fff; border: none; border-radius: 4px; cursor: pointer; } .tip { color: #999; font-size: 0.875rem; margin-top: 0.3rem; } </style> |
四、项目合规性与技术优化方向
1. 已落地的合规措施
- 数据收集:仅收集 “必要且最小范围” 的信息(手机号用于验证,加班数据用于参考),无冗余收集;
- 数据展示:无任何公司排名、加班时长对比功能,仅支持 “按公司名称查询历史填写结果”,且隐藏提交人信息;
- 资质合规:借助企业资质推进备案,避免个人开发的合规风险,后续上线后会公示备案信息。
2. 后续技术优化计划
- 后端安全加固:增加 IP 限制(单 IP 每日最多提交 3 条数据),防止恶意刷量;
- 前端体验优化:用 Vuex 管理全局状态,替代 localStorage 存储认证状态,提升安全性;
- 数据可视化:后续增加 “行业加班趋势图表”(如 “互联网行业平均加班频率”),用 ECharts 实现,提供更直观的参考。
五、项目现状与技术交流
目前工具已完成前端核心功能开发,后端正在推进合规备案与接口开发,后续上线后会在我的 CSDN 主页更新技术文档与演示地址。
如果有 Vue 表单优化、数据加密相关的技术建议,欢迎在评论区交流 —— 个人开发精力有限,希望通过技术协作,让工具更实用、更安全。
更多推荐
所有评论(0)