ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

企业资产信息管理系统设计与实现:从台账到扫码盘点

2026/10/6 13:01:49 拓冰建站 浏览量
企业资产信息管理系统设计与实现:从台账到扫码盘点 做企业信息化这些年我接手最多的需求不是高并发商城也不是花哨的数据大屏而是看起来不起眼的企业资产信息管理系统。前阵子刚交付完一套完整的资产管理系统源码从资产台账、领用归还、调拨维修到扫码盘点功能、代码、数据库脚本一次配齐。这个方向也常年是源码类搜索里的热门原因很简单资产是每一家公司都要管的“硬账”但市面上的商业系统要么太贵要么太重很多团队最后都会自己攒一套。这篇文章把我在设计这套系统时的整体思路、数据库拆表逻辑、核心功能落地过程以及上线之后踩过的坑一次性说清楚。如果你正准备做课设、毕业设计或者公司内部想从Excel台账升级成信息系统这份整理可以直接拿去参考。1. 资产管理这件事为什么必须从“台账思维”升级成“系统思维”先别急着聊表结构和代码得先想明白一个问题为什么Excel台账越用越乱而系统能解决这个问题。想清楚这个后面的模块设计才不会跑偏。1.1 手工台账的三大硬伤滞后、失真、无追溯很多公司一开始都是用Excel管资产行政或财务维护一张总表字段无非是资产名称、编号、购买日期、价格、使用人、存放地点。刚开始几百条数据还好一旦资产超过一两千条问题马上暴露。第一是滞后。员工调岗了部门合并了资产搬走了Excel表没人及时更新。等到年底盘点拿着表格去对实物到处对不上最后只能按“大概在谁那里”重新登记一遍表格越改越失真。第二是失真。同一个资产领用人填一个名字部门负责人填另一个说法Excel里多种叫法并存根本没法汇总统计。更麻烦的是固定资产折旧财务每年要算原值、净值、折旧额Excel公式一旦拉错行整年的账都得重新核对。第三是无追溯。资产丢了、坏了说不清什么时候领的、在谁手上经过了几手、什么时候报修的。台账里只有当前一条记录历史全丢了。审计来查的时候拿不出完整链条非常被动。我做过一次项目调研客户公司1200多项资产盘点一次要三个人忙三天盘完还剩20%左右对不上。其实问题不在人懒而是工具没有约束力。Excel不会提醒你“这张表已经三个月没更新了”系统会。1.2 系统化管理之后数据能带来什么变化系统结构化之后最核心的变化是三个一是实时性。每次领用、调拨、借用操作人当场在系统里点一下资产状态立刻改变。盘点之前不用再花三天去“猜”资产在哪。二是规范性。资产分类、状态、使用部门全部下拉选择写入数据库之前强制校验。录入不规范的操作直接报错数据从一开始就是干净的。三是可追溯。每一笔变动都生成了流水记录什么时间、谁操作、从哪到哪、审批人是谁全部留痕。这个对年底审计、财务对账价值极大甚至可以说没有流水记录就不能算资产系统。1.3 什么规模的企业适合直接用这套源码说实话不到50项资产的公司用Excel完全够没必要上系统。这套源码更适合下面几类场景资产数量在300件以上靠手工表已经管不过来多部门、多楼层/多地点资产经常在部门之间调动有盘点要求希望用扫码方式替代肉眼核对财务需要每月产出一份准确的资产折旧表做课程设计或毕业设计需要一个业务闭环完整、能写进论文里的系统。系统本身不复杂核心是“台账 变动 审批 盘点”把这四件事做成闭环就已经能解决大部分企业的痛点。2. 核心功能模块解剖从入库到报废的完整业务闭环这套系统的功能模块可以分成五块资产台账、领用归还、调拨维修、处置报废、盘点管理。它们不是孤立的功能点而是围绕“一个资产的生命周期”串起来的。2.1 资产台账模块字段设计是地基台账是资产系统唯一的权威数据源字段设计必须一次想清楚。我当时设计的资产主表核心字段如下字段说明设计理由资产编码全局唯一如 ZC20250101001是二维码标签的内容也是盘点、调拨的检索依据资产名称中文名称如“联想拯救者笔记本”搜索和展示最常用的字段资产分类电子设备/办公家具/车辆/房屋分类统计、折旧策略都依赖它规格型号原文录入如 R9000P用于识别同型号资产购置日期精确到日折旧从次月开始计提原值含税价格财务计算折旧的基数使用部门部门表外键数据权限按部门隔离使用人员工ID责任到人存放地点楼栋楼层房间盘点路径规划用资产状态在库/使用中/维修中/已报废驱动列表中显示的按钮和流转范围供应商文本方便后期追踪质量问题保修截止日日期到期可自动提醒有几个字段特别容易漏。一个是取得方式是购入、捐赠还是调拨这直接影响财务入账处理另一个是备注比如“已更换过电池”“外观有磕碰”这类信息不记下来后面维修和交接很容易扯皮。2.2 领用、调拨、借用与归还变动记录是灵魂台账是静态的“当前状态”变动记录才是动态的“历史证据”。这块是整个系统最不能省的部分。领用员工申请部门负责人审批资产管理员确认发放资产状态从“在库”变为“使用中”使用人变为申请人归还员工离职或退还状态回到“在库”使用人清空调拨A部门调给B部门需要双方部门负责人审批变更部门和使用人借用短期拿走到期未归还要有“逾期提醒”任务。这套流程跑起来之后资产的状态变化就像银行存款流水一样清晰每个状态下都有对应的时间戳和操作人没人能在系统里偷偷改数据。2.3 维修保养与处置报废让数据保持“新鲜”资产不是买回来就一劳永逸。笔记本用久了要换硬盘打印机要定期加粉车辆要保养。维修保养记录的留存能帮助后续决定“这台设备是继续修还是报废换新”。处置报废则需要走审批流。我见过不少系统把报废做成“一键删除”这是错误的设计。资产报废后数据仍然保留在台账里只是状态变为“已报废”同时记录报废日期、审批编号、残值回收金额。这样资产原值、累计折旧和处置收益才能完整对账。状态流转可以整理成下面这张流转表操作原状态新状态是否有审批变更内容入库登记-在库无需生成资产编码领用在库使用中需要使用人、部门归还使用中在库可选清空使用人调拨使用中使用中需要部门、使用人借用在库借出需要预计归还日维修使用中维修中无需维修记录报废使用中/维修中已报废需要残值、处置方式3. 数据库设计的关键决策主表、流水表、审批表到底怎么拆业务流程理清了数据库设计是决定这个系统能走多远的关键。我给你讲讲我实际建表的思路和踩过的一些设计教训。3.1 资产主表只存“最新状态”不做历史追忆资产主表存储的是资产的当前事实比如当前在哪个部门、当前使用人是谁、当前状态是什么。每次资产变动时主表字段被更新为新值而旧值不会在这里保留而是写到流水表里。建表脚本MySQL 8核心部分如下CREATE TABLE asset_info ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, asset_code VARCHAR(32) NOT NULL COMMENT 资产编码全局唯一, asset_name VARCHAR(128) NOT NULL COMMENT 资产名称, category_id BIGINT NOT NULL COMMENT 资产分类ID, model VARCHAR(64) DEFAULT NULL COMMENT 规格型号, buy_date DATE NOT NULL COMMENT 购置日期, original_value DECIMAL(12,2) NOT NULL COMMENT 原值, dept_id BIGINT NOT NULL COMMENT 当前使用部门, user_id BIGINT DEFAULT NULL COMMENT 当前使用人, location VARCHAR(255) DEFAULT NULL COMMENT 存放地点, status TINYINT NOT NULL DEFAULT 0 COMMENT 0在库 1使用中 2维修中 3借出 4已报废, supplier VARCHAR(128) DEFAULT NULL COMMENT 供应商, warranty_date DATE DEFAULT NULL COMMENT 保修截止日期, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_asset_code (asset_code), KEY idx_dept_status (dept_id, status), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT资产主表;强调一个细节资产编码一定要全局唯一并且加上唯一索引。很多人喜欢直接用资产ID作为编码一旦导出Excel再导入或者系统间做数据迁移没唯一约束就会出现重复资产根本分不清谁是谁。另外编码建议规则简单一点比如“ZC 年月日 三位流水号”这样一看就知道是2025年1月之后入库的资产。3.2 资产变动流水表只追加不修改不删除流水表是整个系统的审计基础。它的设计原则和银行账单一样一次操作插入一条记录数据只增不改不删。CREATE TABLE asset_transaction ( id BIGINT NOT NULL AUTO_INCREMENT, asset_id BIGINT NOT NULL COMMENT 资产ID, asset_code VARCHAR(32) NOT NULL COMMENT 冗余资产编码方便直接查询, trans_type VARCHAR(20) NOT NULL COMMENT CREATE/ALLOCATE/RETURN/TRANSFER/REPAIR/SCRAP, from_dept_id BIGINT DEFAULT NULL COMMENT 原部门, to_dept_id BIGINT DEFAULT NULL COMMENT 新部门, from_user_id BIGINT DEFAULT NULL COMMENT 原使用人, to_user_id BIGINT DEFAULT NULL COMMENT 新使用人, remark VARCHAR(255) DEFAULT NULL COMMENT 备注, operator_id BIGINT NOT NULL COMMENT 操作人, operated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 操作时间, PRIMARY KEY (id), KEY idx_asset (asset_id), KEY idx_time (operated_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT资产变动流水表;为什么流水表里要冗余一个asset_code因为在页面列表展示时如果每次都要去关联资产主表查编码数据量大时就是个隐性的性能坑。直接在流水表冗余一份查询的时候少一次join响应明显更快。冗余可以但要保证写入逻辑一致批量操作时别漏写。3.3 审批表简单状态机还是通用流程表取决于公司规模审批的业务场景包括资产领用、调拨、报废三种。小型项目没必要引入Flowable这类工作流引擎过度设计反而是负担。我采用的方案是“业务表状态机 通用审批记录表”。每张业务单都有一个audit_status字段0草稿/待提交1待部门负责人审批2待资产管理员确认3已通过4已驳回。再配一张通用审批记录表CREATE TABLE audit_record ( id BIGINT NOT NULL AUTO_INCREMENT, biz_type VARCHAR(20) NOT NULL COMMENT 领用申请/调拨申请/报废申请, biz_id BIGINT NOT NULL COMMENT 业务单ID, audit_step VARCHAR(20) NOT NULL COMMENT 当前环节如DEPT_APPROVE/ASSET_CONFIRM, audit_action TINYINT NOT NULL COMMENT 1通过 2驳回, audit_comment VARCHAR(255) DEFAULT NULL COMMENT 审批意见, auditor_id BIGINT NOT NULL COMMENT 审批人, audited_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_biz (biz_type, biz_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT审批记录表;这样设计的好处是审批历史完整可查业务表结构又不会被审批字段污染。后面如果公司说要加一道财务审批只要在业务表的审核状态机里加一个状态再写对应的审批逻辑就行不需要动表结构。3.4 盘点明细表为什么要预生成而不是实时查询盘点模块很多人会犯一个错误盘点时直接按条件查数据库把当前在库资产列出来。这样做的坏处是盘点过程中如果有人领用了资产盘点结果就和实时数据互相冲突复盘时说不清谁对谁错。正确的做法是创建盘点任务时把符合条件的资产快照写入盘点明细表。盘点只和这份快照比对不随实时数据变化。快照表里每个资产一条记录记录盘没盘、盘盈盘亏、盘点人、盘点时间。CREATE TABLE inventory_task_asset ( id BIGINT NOT NULL AUTO_INCREMENT, task_id BIGINT NOT NULL COMMENT 盘点任务ID, asset_id BIGINT NOT NULL COMMENT 资产ID, expected_dept_id BIGINT DEFAULT NULL COMMENT 账面部门, expected_location VARCHAR(255) DEFAULT NULL COMMENT 账面地点, scan_status TINYINT NOT NULL DEFAULT 0 COMMENT 0未盘 1已盘 2盘盈 3盘亏, scan_user_id BIGINT DEFAULT NULL, scan_time DATETIME DEFAULT NULL, real_dept_id BIGINT DEFAULT NULL COMMENT 实际扫码发现部门, real_location VARCHAR(255) DEFAULT NULL COMMENT 实际扫码发现地点, PRIMARY KEY (id), KEY idx_task_scan (task_id, scan_status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT盘点任务资产明细表;这个“快照”思路是整个盘点模块不出乱子的关键后面讲盘点实现时你还会看到它的重要性。4. 源码落地的技术选型与核心功能实现扫码、导入导出、权限控制文档看到这里你大概已经清楚系统有哪些模块了。接下来是技术落地的部分。很多朋友拿到源码工程第一反应是双击index.html这个系统在交付时已经说明过它是前后端分离项目不能像静态网页那样直接打开需要先准备数据库和后端运行环境。下面说说具体怎么落地。4.1 技术栈选型这套系统为什么用 Java Vue企业内网部署的资产管理系统不追求高并发日常可能就是几十个人同时用。技术选型的核心考量是开发效率高、招人容易、部署简单、文档多。所以我最终选了后端Spring Boot 3.x MyBatis-PlusJava 17前端Vue 3 Element Plus Vite数据库MySQL 8.0二维码ZXingExcel导入导出EasyExcel如果你更熟悉PHP也可以用 ThinkPHP 或者 Laravel 做一套轻量版功能逻辑完全一致。但我个人建议用Java系因为资产系统涉及权限、审批、报表Java生态里现成的组件最多后期如果要接钉钉审批、企业微信告警也有更成熟的SDK。4.2 新增资产的核心实现编码生成 事务写入 流水留痕新增资产看似简单实际包含三个动作生成编码、插入主表、写入流水。这三个动作要放在同一个事务里否则会出现主表有数据但流水缺失的半截状态。核心代码如下Service public class AssetService { Autowired private AssetInfoMapper assetInfoMapper; Autowired private AssetTransactionMapper transactionMapper; Transactional(rollbackFor Exception.class) public Long createAsset(AssetCreateDTO dto) { // 1. 生成资产编码ZC 日期 当日序号 String code generateAssetCode(dto.getCategoryId()); AssetInfo asset new AssetInfo(); asset.setAssetCode(code); asset.setAssetName(dto.getAssetName()); asset.setCategoryId(dto.getCategoryId()); asset.setBuyDate(dto.getBuyDate()); asset.setOriginalValue(dto.getOriginalValue()); asset.setDeptId(dto.getDeptId()); asset.setStatus(0); // 在库 assetInfoMapper.insert(asset); // 2. 写入入库流水 AssetTransaction trans new AssetTransaction(); trans.setAssetId(asset.getId()); trans.setAssetCode(code); trans.setTransType(CREATE); trans.setToDeptId(dto.getDeptId()); trans.setRemark(新购入入库); trans.setOperatorId(LoginUser.getUserId()); transactionMapper.insert(trans); return asset.getId(); } private String generateAssetCode(Long categoryId) { String dateStr LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); Integer seq assetInfoMapper.countTodaySeq(dateStr); return ZC dateStr String.format(%03d, seq 1); } }Transactional一定要加在入口方法上而不是内部方法上否则事务不生效。这是个小细节但我在实际排查问题时见过太多次事务失效的情况。4.3 Excel批量导入模板先行别让用户自由发挥企业里的资产数据大部分都在旧Excel表里手工一条条录入不现实批量导入是刚需。我的做法是提供一个标准导入模板字段与资产主表一一对应用户按模板填好之后上传。用EasyExcel实现很简单public void importAssets(MultipartFile file) { ListAssetImportRow rows EasyExcel.read(file.getInputStream()) .head(AssetImportRow.class) .sheet() .doReadSync(); for (AssetImportRow row : rows) { if (StringUtils.isBlank(row.getAssetName())) { throw new BusinessException(第 row.getRowNum() 行资产名称为空); } createAsset(convertToDto(row)); } }导入最容易踩的坑有三个日期格式问题Excel里“2025/1/1”会被读成数字EasyExcel需要用DateTimeFormat(yyyy-MM-dd)标注日期字段编码冲突模板里如果填写了已有编码必须提示并跳过不能静默覆盖数据量过大一次导入超过500条建议分批提交否则接口超时、内存飙升。我一般每200条flush一次配合事务边界控制。4.4 二维码标签生成与打印让每一台设备都有身份证盘点能不能快很大程度取决于资产标签。我用ZXing把资产编码生成二维码再配合一个打印页面按A4纸排版每张标签包含二维码、资产编码、资产名称。核心生成代码public BufferedImage generateQrCode(String assetCode, int width, int height) { MultiFormatWriter writer new MultiFormatWriter(); MapEncodeHintType, Object hints new HashMap(); hints.put(EncodeHintType.CHARACTER_SET, UTF-8); // 容错级别调高一点防止标签磨损后扫不出来 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); BitMatrix matrix writer.encode(assetCode, BarcodeFormat.QR_CODE, width, height, hints); return MatrixToImageWriter.toBufferedImage(matrix); }这里特别说一下容错级别。打印标签的铜版纸不干胶贴在设备上时间久了难免有划痕、脏污、卷边。容错级别从 L 调到 H同一个码多点污渍也能扫出来。这个是我在客户现场被教训出来的经验最初用M级容错结果一批贴了两年的标签报废率超过三成全部门重新贴了一遍。另外标签材质建议用铜版纸不干胶而不是普通办公A4纸A4纸贴设备上一个月就烂了扫描时还会反复误读。打印机用热敏标签打印机最合适不需要碳带成本也最低。4.5 前端列表页与权限控制怎么配合前端页面上资产列表要有编码、名称、分类、部门、使用人、状态、操作按钮。操作按钮要根据权限动态显示比如普通员工只能看“申请领用”部门管理员能看到“调拨、维修”资产管理员才能看到“报废、导入、标签打印”。前端Vue里我封装了一个权限指令按钮按权限码控制el-button v-permissionasset:scrap typedanger报废/el-button el-button v-permissionasset:import typewarning批量导入/el-button后端则必须做双重校验接口上通过PreAuthorize(hasAuthority(asset:scrap))控制前端按钮只是界面友好真正的安全保障在后端。前后端权限漏配一环就会出现“按钮看不到但接口能调”的安全漏洞。数据权限方面部门管理员默认只能看到本部门资产超级管理员和资产管理员看全部。实现方式是MyBatis-Plus的拦截器自动追加dept_id过滤条件比在每个查询里手写where dept_id ?干净得多也避免漏掉某个接口造成越权。5. 盘点模块的完整实现从任务创建到盘盈盘亏处理盘点资产管理系统里功能价值最高、又最容易出问题的模块。这里我把完整流程和实现要点拆开讲。5.1 盘点任务创建支持按部门、地点、分类三个维度盘点不是每次都要全公司盘点。年底全面盘点一次平时可能是某个部门轮流抽盘。所以任务创建时范围要灵活可配按部门选择多个部门系统自动把该部门当前所有“在库 使用中”的资产加入任务按地点比如“三层办公区”通过存放地点匹配按分类比如只盘电子设备全量盘点以上都不选就是全部资产。创建任务时前端展示一个范围预览本次任务涉及多少项资产、原值总额、分布在哪些部门。这个预览特别有用项目经理确认范围时不用拍脑袋也知道这次盘点的体量。5.2 扫码盘点的实现方式H5扫码和手持终端怎么选扫码盘点有两种主流实现方式。第一种是手机浏览器H5扫码。后端生成一个盘点页面盘点人员登录后进入任务详情点击扫码按钮调用摄像头识别二维码。优点是不用安装App微信/浏览器里就能用缺点是手机摄像头连续扫码效率一般适合资产数量在2000以内的场景。实现上可以用html5-qrcode这个前端库接入很快。script srchttps://unpkg.com/html5-qrcode/script div idreader/div script const scanner new Html5Qrcode(reader); scanner.start( { facingMode: environment }, { fps: 10, qrbox: { width: 250, height: 250 } }, (decodedText) { // decodedText 就是资产编码 submitScanResult(decodedText); scanner.stop(); } ); /script第二种是工业手持终端。就是快递小哥用的那种带扫描头的PDA走Android系统。优点是连续扫描效率极高一秒钟可以扫好几下适合几千上万资产的大规模盘点缺点是要额外采购硬件一套也要一千多。我们系统预留了PDA调用接口终端通过HTTP接口把扫码结果提交回来逻辑和H5扫码完全一样。5.3 扫码后端的处理逻辑快照比对 去重扫码提交到后端的处理逻辑是盘点模块的核心代码。接到一个扫码结果之后要做四件事判断这个资产编码是否在当前盘点任务的快照表里不在说明扫到了任务范围外的资产记录为“盘盈”在把该条明细更新为“已盘”记录盘点人和盘点时间如果该资产已经被扫过一次提示“重复扫码”不重复计数。核心逻辑Transactional(rollbackFor Exception.class) public ScanResult scanAsset(Long taskId, String assetCode) { AssetInfo asset assetInfoMapper.selectByCode(assetCode); if (asset null) { throw new BusinessException(该资产编码不存在请核对标签); } InventoryTaskAsset detail inventoryTaskAssetMapper.selectByTaskAndAsset(taskId, asset.getId()); if (detail null) { // 任务外资产记录盘盈 inventoryTaskAssetMapper.insertExtraAsset(taskId, asset, 盘盈); return ScanResult.EXTRA; } if (detail.getScanStatus() 1) { return ScanResult.DUPLICATE; } detail.setScanStatus(1); detail.setScanUserId(LoginUser.getUserId()); detail.setScanTime(new Date()); inventoryTaskAssetMapper.updateById(detail); return ScanResult.SUCCESS; }这里就体现了之前谈到的快照表的价值。实时查询数据库的方式做不到“重复扫码提示”和“盘盈记录”因为在任务创建之后数据已经变了。5.4 盘点报表盘盈、盘亏、未盘一目了然盘点结束之后报表要回答三个问题账面数是多少、实盘数是多少、差异在哪里。我的做法是把快照表按scan_status分组统计状态含义数量原值0未盘到1235600.001已盘正常10851204600.502盘盈34200.003盘亏58700.00盘亏资产要能一键生成“资产处置/追究责任”的流程单盘盈资产则自动进入待入库列表再走一次入库登记。财务依据这份差异表做固定资产盘盈盘亏的账务处理整个过程在系统里是闭环的不会出现“盘完就完事、差异悄悄吞掉”的情况。6. 权限模型与多部门协作让每个人只看到该看的、只操作该操作的资产系统的权限如果做不好轻则数据混乱重则越权操作。这一块设计时我专门花了时间因为不同角色对系统的诉求完全不同。6.1 角色权限模型四类角色边界清晰我按企业实际分工设计了四种角色覆盖绝大多数使用场景角色数据范围核心操作超级管理员全部数据系统配置、部门/用户管理、审批流设置资产管理员全部数据资产维护、领用/调拨/报废审批、盘点任务、导入导出部门管理员本部门数据部门资产查看、发起调拨、审批本部门领用普通员工涉及本人的数据查看本人名下资产、发起领用申请、借用申请权限控制的粒度要细化到操作级而不是角色级。比如同样都是资产管理员小公司的资产管理员可能兼任财务能看资产原值集团企业里资产管理和财务是分开的就不能让资产管理岗位看到所有财务字段。所以权限模型是“角色 权限点”的组合一个角色拥有一组权限点给不同人配不同角色组合即可。6.2 数据权限的实现部门隔离不是SQL里加个条件那么简单数据权限最容易出漏洞的地方就是某些接口忘记加部门条件。举个例子普通员工理论上只能看自己名下的资产但如果查询接口没有强制过滤懂点技术的员工完全可以调接口看到全公司资产清单。我在系统里用MyBatis-Plus的DataPermissionHandler统一处理数据权限代码层面全部查询都会自动拼接当前用户的部门范围。这样业务代码里不需要每个查询都考虑“我是谁”权限规则集中在一处维护不会漏。public class DeptDataPermissionHandler implements DataPermissionHandler { Override public Expression getSqlSegment(TableInfo table, Expression where, String mappedStatementId) { // 从上下文取当前登录人判断角色给表追加 dept_id 或 user_id 条件 return new ComparisonExpression(...); } }前端展示也同步做了隔离部门管理员登录后只能看到自己部门的资产卡片和统计图切换到其他部门Id去请求数据接口时后端返回的结果还是被数据权限拦截后的内容。前端隐藏只是体验优化后端拦截才是安全底线。6.3 审批链路的两种模式固定审批和动态审批资产系统的审批流多数时候是固定链路部门负责人 → 资产管理员 → 归档。但实际企业里也会出现特殊情况比如部门负责人请假得有个临时授权或者资产金额过大需要总经理加签。我的处理方式是支持两种模式并存固定流程部门负责人审批然后资产管理员确认。动态加签审批人可以在“通过”的同时增加一个下一步审批人。比如部门负责人审批通过后加签给分管副总。动态加签的实现不复杂在审批记录表里给每一步记录next_auditor_id字段就行。但要注意加签人不能是自己不能形成无限循环每单最多加签两层这些限制在代码里要写死。7. 部署上线与长期维护源码工程如何从开发环境落到真实使用源码交付只是第一步真正让系统跑起来、用得好还有大量部署和运维功课。这块我总结一些真实项目里的实践经验按部署顺序写下来。7.1 部署环境的完整准备数据库、后端、前端三个环节源码工程拿到手之后不要着急启动先把环境准备好。我的标准部署步骤如下安装MySQL 8.0导入db_init.sql初始化脚本注意字符集必须设置为utf8mb4否则中文和生僻字会存报错CREATE DATABASE asset_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;修改后端application.yml里的数据库连接、文件上传路径、二维码打印模板路径后端打包mvn clean package -DskipTests生成 jar 包前端执行npm install npm run build生成 dist 静态目录Nginx 配置/api反向代理到后端 8080 端口其他请求指向前端 dist 目录。Nginx 的简化配置server { listen 80; server_name asset.example.com; root /data/asset_manage/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /uploads/ { try_files $uri $uri/ /index.html; } }这里有个非常容易踩的坑Vue Router 如果是history模式刷新页面时 Nginx 直接返回404。需要在 Nginx 里加一个 fallback把所有非文件请求回退到index.html。很多同学部署完发现首页正常、点刷新就白屏基本都是这个原因。7.2 我在真实项目里踩过的几个高频坑部署和使用的过程中我总结出几个高频问题每个都是从现场带回来的真实经验坑一Excel导入时日期变成一串数字按我之前说的用DateTimeFormat注解也只能解决一部分问题还要注意模板里的单元格格式必须是“文本”或“日期”不能是“常规”。否则用户随便填个格式后端读出来全是浮点数。我后来在导入模板第一行加了格式说明并在校验代码里做了日期格式双保险才彻底解决。坑二二维码标签打出来扫不动除了容错级别要设成H还有一个容易忽略的点二维码内容不要包含中文。中文编码后的二维码密度非常大打印精度稍差一点就扫不出来。我的做法是二维码内容只存assetCode显示用的中文名称放在二维码下方文字里清晰又稳妥。坑三扫码枪 / 手机扫码自动带上回车和换行盘点现场用USB扫码枪时很多扫码枪默认会在扫码后发送回车键。如果不处理前端输入框里会出现换行符导致编码校验失败。解决办法是在前端处理扫码输入时过滤掉\r\n再提交。let code decodedText.replace(/[\r\n]/g, ).trim();坑四盘点任务创建之后资产才被调走这个场景很常见你建了一个盘点是按当前数据快照生成的结果盘点期间有人领用了资产。因为盘点明细是快照盘点结果依然以任务创建时为准不会出现扫码一条然后状态跳来跳去的情况。建议在项目启动会上跟使用方讲明白这个规则避免误解。7.3 长期维护的几条实用建议系统上线不是结束数据治理才刚刚开始。结合我服务过的客户给你几条实在的建议每季度做一次小范围抽盘不要等到年底一次性盘全年。抽盘能及时发现标签脱落、资产移动等问题修复成本低得多。定期检查系统里的“无主资产”也就是部门为空、使用人为空、状态还是“使用中”的异常资产这类数据往往是当年导入历史数据时留下的尾巴越拖越难清理。给操作人员做一次20分钟的培训重点讲清楚“领用要审批、调拨要走流程、报废不能删”。系统功能再好没有使用习惯也是白搭。我个人的体会是资产管理系统真正难的从来不是写代码而是让每一台设备、每一个操作在系统里都有据可查。源码工程给你的是一个可靠的地基后续门窗怎么装、油漆怎么刷需要根据自己公司的组织架构和流程习惯慢慢调。如果你正在参考这套企业资产信息管理系统的源码做部署或二次开发建议先把资产台账、领用归还、盘点三个模块跑顺再逐步放开维修、报废和审批链这样业务人员接受度最高数据质量也最容易稳住。