工程机械人机一体考勤绩效系统:从设备台账到工资条的全链路设计
设备管不住、工时算不清、工资对不拢——这三个问题叠加利润流失往往不是单点故障引言一张工资条背后的系统性难题月初发薪日前某机械租赁公司HR老张对着Excel加班到凌晨两点。40台设备、80名机手考勤记录散落在纸质签到表、微信报岗和班长手写笔记里。设备保养记录在另一个Excel里人机对应关系要靠脑记。最终出来的工资条总有人质疑工时不对、绩效少算、奖惩不明。这个场景在工程机械、施工总包、环卫市政等行业并非个例。传统“考勤打卡”工具解决不了这个问题。设备台账乱、保养跟不上、工时算不清、工资条对不拢——这四件事叠加起来流失的不是一个人一天的工时而是整个项目的利润底数。本文分享一个在工程机械现场生长出来的考勤与绩效管理平台——晋辉智机通项目代号xlhMoreApp的设计思路。它不是打卡软件加个壳而是围绕“设备管理”与“工资绩效”两大核心把考勤作为数据底座形成人、机、现场一条线的闭环系统。第一部分架构设计的起点——四大能力板块的优先级排序在动手写第一行代码之前团队花了两周跑工地、蹲租赁公司、跟班组长聊天。发现真正被高频使用的功能排序完全不同于“打卡软件”的常规设计优先级板块核心解决的问题★★★设备管理机械台账、机手绑定、保养计划——人机现场一条线★★★工资绩效考勤汇总、工资条、积分规则——算得清、奖得明★★考勤GPS打卡、拍照留痕、异常申诉——真实可追溯的底座★员工培养技能提升与积分挂钩——在干活过程中培养这个排序决定了产品设计的底层逻辑考勤是手段设备和绩效才是客户真正愿意付费的价值锚点。第二部分多租户架构——一套代码两种交付2.1 需求来源两种客户一种代码库随着客户增多需求分叉出现了中小型租赁公司希望快速上线不想自建机房按年付费即可大型国企/集团数据不能出内网要求私有化部署数据完全自主可控常规做法是维护两套代码——一套SaaS版一套私有化版。但两套代码意味着双倍维护成本、功能不同步、bug修复要两边改。解决方案在数据库层做隔离同一个Spring Boot工程通过配置切换运行模式# application.yml 核心配置 tenant: mode: shared # shared托管共享库行级隔离 | standalone私有化独立库shared模式共享MySQL数据库MyBatis拦截器自动向SQL追加tenant_id条件实现行级隔离standalone模式独立数据库单企业关闭SQL改写数据完全在客户环境内2.2 数据隔离的核心设计MyBatis拦截器 JSqlParser 自动改写SQL业务代码零侵入Intercepts({Signature(type Executor.class, method query, args {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) public class TenantInterceptor implements Interceptor { Override public Object intercept(Invocation invocation) throws Throwable { // 获取当前租户ID从ThreadLocal或请求头X-Tenant-Id String tenantId TenantContext.getCurrentTenantId(); if (StringUtils.isNotBlank(tenantId) !platform.equals(tenantId)) { // 使用JSqlParser改写SQL自动追加 AND tenant_id ? // 仅对业务表生效系统表跳过 } return invocation.proceed(); } }关键设计决策不依赖多数据源而是单数据源行级隔离。原因是托管模式下动态创建数据库不现实需要DDL权限行级隔离让新增租户零成本无需重复部署整套系统运维后台开通企业 → 生成tenant_id → 立即可用全程秒级第三部分登录链路与租户识别多企业版与单企业版最大的体验差异在登录链路。用户不是直接输入账号密码而是输入企业码如test、zhangsan-lease调用GET /Tenants/resolve?codexxx获取企业ID、API地址、品牌信息再用企业码账号密码登录后续请求通过JWT Token中的tenantId或请求头X-Tenant-Id传递租户上下文// 登录接口示例 PostMapping(/login) public Result login(RequestBody LoginDTO dto) { // 1. 根据企业码解析租户 Tenant tenant tenantService.resolveByCode(dto.getTenantCode()); if (tenant null) { return Result.error(企业码不存在请联系管理员); } // 2. 校验账号密码带租户隔离 User user userService.login(dto.getUsername(), dto.getPassword(), tenant.getId()); // 3. 生成JWT包含tenantId String token JWT.create() .withClaim(userId, user.getId()) .withClaim(tenantId, tenant.getId()) .withClaim(roleId, user.getRoleId()) .sign(Algorithm.HMAC256(tokenSecret)); return Result.ok(token); }运维管理员使用独立标识platform登录roleId100仅用于企业开通与续期管理不访问业务数据。第四部分企业品牌与服务续期的细节设计4.1 品牌展示的分区域策略多租户系统面临一个矛盾既要让企业看到自己的品牌又要保持平台统一的认知。我们的策略是分区域展示区域展示规则App登录页/注册页固定默认Logo 「晋辉智机通」不随企业配置变化管理后台登录页/左侧侧栏固定默认Logo 「晋辉智机通」管理后台登录后顶栏可配置系统名、Logo、品牌备注14种推荐背景色自定义色值App登录后首页展示企业名称若配置了企业Logo则一并展示这个策略平衡了平台统一认知与企业个性化两个需求。登录前用户看到的是平台品牌知道自己在用哪个系统登录后看到的是企业品牌归属感。4.2 服务续期提醒托管部署模式下企业服务到期前30天移动端自动弹窗提醒管理后台顶部显示黄色警示条到期后自动拦截登录引导联系晋辉续费私有化部署客户不受此约束由客户自行运维。第五部分前后端工程化实践5.1 API地址的统一管理多环境部署容易出现的坑前端配置了多个API地址打包时漏改一个就导致生产环境请求失败。管理后台utils/apiBase.js统一从环境变量读取// .env.production VUE_APP_BASE_URL https://jinhuitech.top/seaHouseApiMore/ // apiBase.js export function getApiBaseUrl() { return process.env.VUE_APP_BASE_URL || /seaHouseApiMore/; }移动端util/request/index.js集中配置// 统一API根地址所有请求通过此入口 const API_BASE_URL https://jinhuitech.top/seaHouseApiMore/; // 图片URL规范化 export function resolveImageUrl(url) { if (!url) return ; if (url.startsWith(http://) || url.startsWith(https://)) return url; return API_BASE_URL file/download?url encodeURIComponent(url); }5.2 Nginx反向代理配置# API反代 location /seaHouseApiMore/ { rewrite ^/seaHouseApiMore/(.*) /$1 break; proxy_pass http://127.0.0.1:11070; proxy_set_header X-Forwarded-Prefix /seaHouseApiMore; proxy_set_header Host $host; } # 管理后台静态资源 location /seahouseAdminMore/ { alias /etc/www/website/seahouseAdminMore/; try_files $uri $uri/ /seahouseAdminMore/index.html; }5.3 打包与部署# 后端打包 cd move-apiMorePub mvn clean package -DskipTests # 输出 target/xlhMoreApi.jar # 生产启动SaaS java -jar target/xlhMoreApi.jar --spring.profiles.activeprod # 私有化启动 java -jar target/xlhMoreApi.jar --spring.profiles.activeprodprivate环境变量通过操作系统注入不写入配置文件export TOKEN_SECRET至少32位随机字符串 export DB_URLjdbc:mysql://host:3306/sea_house_more?... export DB_USERNAME... export DB_PASSWORD... export OSS_ACCESS_KEY_IDAK export OSS_ACCESS_KEY_SECRETSK第六部分关键业务功能实现6.1 GPS打卡与拍照留痕移动端打卡时采集GPS经纬度与后台配置的打卡地点比对计算距离是否在允许范围内// 打卡校验逻辑 public boolean checkLocation(BigDecimal lat, BigDecimal lng, LocationConfig config) { double distance GeoUtils.distance( lat.doubleValue(), lng.doubleValue(), config.getLatitude(), config.getLongitude() ); return distance config.getAllowedRadius(); // 默认300米 }拍照留痕上传的图片存储到OSS返回URL后续打卡记录与图片关联确保考勤可审计。6.2 考勤汇总 → 工资条考勤数据按自然月汇总计算OT加班工时、中直中班/直落工时-- 考勤汇总核心SQL简化 SELECT user_id, SUM(CASEWHENtype normalTHENhoursELSE0END) as normal_hours, SUM(CASEWHENtype otTHENhoursELSE0END) as ot_hours, SUM(CASEWHENtype midnightTHENhoursELSE0END) as midnight_hours FROM attendance_records WHERE tenant_id #{tenantId} ANDmonth #{month} GROUPBY user_id;汇总结果 → 工资条 → 机手App端可查。6.3 积分规则与抽奖积分是绩效激励的重要载体。规则可配置-- 积分规则表 CREATE TABLE point_rule ( id BIGINT PRIMARY KEY, tenant_id VARCHAR(32), rule_name VARCHAR(100), points INT, -- 每次奖励积分 max_times INT, -- 每人每月最多次数 status TINYINT -- 启用/停用 );抽奖功能每N积分抽一次奖品概率可配支持增删改后台自动校验概率总和是否为100%。// 抽奖逻辑 public Prize drawLottery(Long userId) { // 1. 扣减用户积分 userService.deductPoints(userId, costPoints); // 2. 按概率随机抽取奖品 ListPrize prizes prizeService.getEnabledPrizes(); double rand Math.random(); double cumulative 0; for (Prize prize : prizes) { cumulative prize.getProbability(); if (rand cumulative) { return prize; } } returnnull; // 实际应兜底返回未中奖 }第七部分可扩展的场景延伸虽然产品起源于工程机械现场但能力和架构决定了它可以延伸到更多场景行业核心诉求使用方式环卫/市政片区巡检、车辆设备协同GPS打卡任务派单保养巡检物业/保洁多小区巡更、保洁任务留痕特殊任务打卡留痕班长审核仓储/物流班次考勤、计件任务移动端打卡工时汇总安装维修工单派发、上门打卡、拍照验收工单载体定位打卡积分激励第八部分架构决策复盘回顾整个设计和开发过程有几个关键决策值得复盘8.1 为什么不用多数据源做租户隔离多数据源方案需要为每个租户创建独立数据库托管模式下不可行动态创建数据库需要DDL权限且数据迁移成本高。行级隔离SQL改写方案在shared模式下更轻量新增租户只需insert一条记录。8.2 为什么JWT不包含租户ID初始版本JWT中包含了tenantId但遇到租户切换的场景如运维管理员platform需要跨租户操作。最终方案是JWT只存用户身份租户上下文通过请求头X-Tenant-Id传递更灵活。8.3 私有化部署的企业码怎么处理私有化部署虽然只有一家企业但仍然保留企业码登录链路。这样同一套App可以同时服务于SaaS和私有化客户——私有化客户只需将App的API地址指向自己的服务器企业码由客户自行分配。# 私有化部署配置 tenant.modestandalone tenant.default-tenant-codeyour-company app.public-api-base-urlhttps://your-domain.com/seaHouseApiMore/结语从一个工地的Excel工资表到覆盖设备台账、考勤留痕、绩效核算、积分激励的全链路系统这个平台的设计始终围绕三个词展开算得清、奖得明、管得住。技术层面的多租户隔离、SQL改写、JWT鉴权、OSS存储都是手段真正的价值是让一线机手能实时查工资单、让班组长能快速处理异常、让总部能一张报表看清人机现场。如果你正在管理分散的工程机械机手、环卫巡检员、物业外勤或仓储班组这个系统已经准备好了从企业码登录 → 三端实时同步 → 数据隔离 → 部署交付的完整链路。托管省心私有化安心。有需要联系晋辉科技或找你司系统管理员获取企业码。项目体验租户后台https://jinhuitech.top/seahouseAdminMore/#/login租户 testadmin1234 / newocean123456租户 test213222222222 / 123456移动端test租户:wuyujie / 123456 test2租户:chenjie / 123456安卓apk下载测试地址 https://www.pgyer.com/jinhuizhijitong-android

相关新闻

最新新闻

日新闻

周新闻

月新闻