办公设备管理系统OAMS源码实战:从台账混乱到扫码即用
简介办公设备管理系统OAMS是一套面向企事业单位设备管理员与信息化开发者的全生命周期管理解决方案覆盖采购、入库、领用、维修、报废等核心环节适合需要落地资产台账、审批流程与统计报表的Java Web项目学习与二次开发。资源包共451个文件约6.71MB以gif界面素材、jsp页面、java源码与class编译文件为主辅以xml配置、jar依赖、tld标签库及少量数据库与设计文件完整呈现了StrutsHibernate技术栈下的分层结构。已有272人学习下载。读者可从中获取设备信息录入与唯一标识、按部门类型分类管理、使用率与维修费用报表生成、电子化领用归还审批、故障报修跟踪及报废评估等模块的实现思路并参考Action、DAO、Biz等类的组织方式理解业务分层与数据流转适合作为课程设计或企业设备管理系统的参考原型。1. 办公设备管理系统OAMS从台账混乱到扫码即用的落地路径行政部月底盘点的场景很多同行都经历过三张 Excel 表对不上打印机在谁工位上全靠回忆新采购的笔记本还没贴标签就已经被领走。办公设备管理系统 OAMS 要解决的就是这类问题——把设备从入库、领用、调拨、维修到报废的全生命周期搬进一个可查询、可追溯的数据库里。它适合中小企业行政、IT 运维和固定资产管理员也适合想拿一套完整业务系统练手全栈开发的人。这套源码包的核心价值在于业务闭环完整不是那种只有增删改查的玩具项目权限、审批、状态流转都有真实设计。下面按「它怎么跑起来、数据怎么设计、坑在哪」的顺序拆开讲。2. 环境搭建与数据库设计把设备台账跑起来的第一步拿到一套管理系统源码最怕的是环境装到一半报错或者数据库表结构看不懂导致后面所有功能都调不通。OAMS 这类设备管理系统的技术栈通常不会太花哨主流做法是后端 Spring Boot 或 Node.js 配 MySQL前端 Vue 或 React 加一套 UI 组件库。我一般会先确认三件事JDK 或 Node 版本、MySQL 版本、以及有没有 Redis 依赖。版本对不上是新手翻车最多的地方比如 Spring Boot 3.x 强制要求 JDK 17你拿 JDK 8 去跑启动直接给你看一堆看不懂的类加载异常。2.1 后端服务启动与依赖检查先看配置文件里数据库连接、端口、文件上传路径这几项。设备管理系统通常会有图片上传需求比如设备照片、维修单据所以上传目录的读写权限要提前给足。下面是一段典型的 Spring Boot 配置片段我把它拆开说明每个参数的作用。server: port: 8080 # 后端服务端口前端代理要对应改 spring: datasource: url: jdbc:mysql://localhost:3306/oams?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB # 设备照片单文件上限太大容易拖慢列表加载 max-request-size: 20MB file: upload-path: /data/oams/upload/ # 上传目录Linux 下注意 chown 给运行用户serverTimezone这个参数不写MySQL 8 连接时会报时区错误这是高频坑。max-file-size别设太大设备照片一般 2MB 以内够用设成 50MB 只会让上传接口变慢。upload-path在 Windows 下写D:/oams/upload/Linux 下要确保运行服务的用户对这个目录有写权限否则上传功能会静默失败——接口返回成功但文件没落盘这种问题排查起来很费时间。启动命令用 Maven 或 Gradle 都行我习惯先跑一次mvn clean package -DskipTests确认能编译通过再java -jar启动。如果启动日志里出现Table oams.xxx doesnt exist说明数据库脚本没执行完整去src/main/resources下找.sql文件手动导入。2.2 设备台账表结构与状态字段设计OAMS 的数据模型核心是设备主表加几张关联表。设备主表存基本信息领用记录表存流转历史维修表存故障处理报废表存退出记录。这里重点说设备主表的状态字段它是整个系统流转的枢纽。CREATE TABLE asset_device ( id bigint NOT NULL AUTO_INCREMENT, asset_code varchar(64) NOT NULL COMMENT 资产编号唯一建议规则类型缩写年份流水号, device_name varchar(128) NOT NULL COMMENT 设备名称, category_id int NOT NULL COMMENT 分类ID关联字典表, status tinyint NOT NULL DEFAULT 0 COMMENT 0在库 1领用 2维修 3报废 4调拨中, keeper_id bigint DEFAULT NULL COMMENT 当前保管人ID, dept_id bigint DEFAULT NULL COMMENT 所属部门ID, purchase_date date DEFAULT NULL COMMENT 采购日期, price decimal(10,2) DEFAULT NULL COMMENT 采购金额, location varchar(128) DEFAULT NULL COMMENT 存放位置, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_asset_code (asset_code), KEY idx_status (status), KEY idx_keeper (keeper_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT设备主表;status用 tinyint 而不是字符串查询效率高但前端展示要维护一份映射关系。asset_code加唯一索引是必须的否则同一台设备可能被重复录入。idx_status和idx_keeper这两个索引在设备列表按状态筛选、按保管人查询时作用明显数据量上万后不加索引查询会明显变慢。price用 decimal 不用 float金额计算不能有精度丢失。领用记录表要记录每次流转的完整轨迹包括操作人、操作时间、前后状态。这样设备卡片上能直接看到「谁在什么时候领走的、什么时候还回来的」比只存一个当前保管人要有用得多。维修表里建议加一个fault_desc字段存故障描述再加handle_result存处理结果方便后续统计哪些设备故障率高。提示导入 SQL 脚本时如果报外键约束错误先检查字典表、部门表、用户表的数据是否已经插入有外键依赖的表要按顺序导入。3. 核心功能实现领用审批、二维码标签与状态流转环境跑通、表建好之后真正决定这套系统好不好用的是三个功能领用审批流程、二维码标签生成、以及状态流转的约束逻辑。很多设备管理系统 demo 在这三块做得潦草导致实际用起来还是靠微信沟通系统沦为摆设。3.1 领用审批接口与状态机约束领用不是简单地把设备状态改成「已领用」中间要经过申请、审批、确认三个环节。常见做法是建一张asset_apply表记录申请单审批通过后再去更新设备主表的状态和保管人。这里的关键是状态机约束只有「在库」状态的设备才能被申请领用审批通过后状态变成「领用」审批驳回则状态不变。// 领用审批核心逻辑伪代码形式说明状态流转 public Result approve(Long applyId, Boolean pass, Long approverId) { AssetApply apply applyMapper.selectById(applyId); // 校验申请单状态防止重复审批 if (apply.getStatus() ! ApplyStatus.PENDING) { return Result.fail(该申请已处理请勿重复操作); } AssetDevice device deviceMapper.selectById(apply.getDeviceId()); // 关键约束只有在库设备才能被领用 if (device.getStatus() ! DeviceStatus.IN_STOCK) { return Result.fail(设备当前状态不可领用可能已被他人领走); } if (pass) { device.setStatus(DeviceStatus.IN_USE); device.setKeeperId(apply.getApplicantId()); device.setDeptId(apply.getDeptId()); deviceMapper.updateById(device); apply.setStatus(ApplyStatus.APPROVED); } else { apply.setStatus(ApplyStatus.REJECTED); } apply.setApproverId(approverId); apply.setApproveTime(new Date()); applyMapper.updateById(apply); return Result.success(); }这段逻辑里有两个容易忽略的点。一是审批前要重新查一次设备状态不能直接用申请时缓存的设备信息否则两个人同时申请同一台设备时会出现并发问题。二是申请单本身也要有状态防止同一个申请被审批多次。如果系统并发量不大用数据库行锁或乐观锁版本号就能解决如果不想引入锁至少要在更新时加status 0的条件靠影响行数判断是否更新成功。3.2 二维码标签生成与扫码查询设备贴二维码标签是 OAMS 区别于纯台账系统的实用功能。每台设备生成一个二维码扫码后直接跳转到设备详情页行政盘点时不用再对着编号一个个搜。二维码内容一般就是设备详情页的 URL带上asset_code参数。// 前端生成二维码标签使用 qrcode 库 import QRCode from qrcode; async function generateDeviceQR(assetCode, deviceName) { // 扫码后跳转的详情页地址部署后替换成实际域名 const baseUrl window.location.origin; const detailUrl ${baseUrl}/device/detail?code${assetCode}; const canvas document.createElement(canvas); await QRCode.toCanvas(canvas, detailUrl, { width: 200, margin: 1, color: { dark: #000000, light: #ffffff } }); // 标签上同时打印设备名称和编号方便肉眼识别 return { canvas, label: ${deviceName} | ${assetCode} }; }二维码尺寸建议 200x200 以上太小了手机扫不出来。margin设 1 到 2留白太少识别率会下降。打印标签时把设备名称和编号一起打上因为扫码之前人眼需要先确认拿对了设备。批量生成时不要一次性渲染几百个 canvas内存会爆常见做法是分页生成或者用服务端生成图片返回。扫码查询接口要注意权限不是所有人都能看所有设备。普通员工扫码应该只能看到设备基本信息和当前状态看不到采购金额这类敏感字段。这个在接口层做字段过滤别指望前端隐藏。3.3 设备调拨与维修记录的状态回写调拨和维修是设备使用过程中的高频操作。调拨改变保管人和部门维修改变设备状态但保管人不变。这两个操作都要往流转记录表里写一条日志方便追溯。维修流程一般是设备出现故障 → 使用人提交维修申请 → 管理员确认 → 设备状态改为「维修」→ 维修完成后状态改回「在库」或「领用」。这里有个细节维修期间设备保管人是否保留我的建议是保留因为修好后大概率还是同一个人用清空保管人反而增加操作步骤。但状态要改成「维修」这样别人申请领用时会因为状态校验被拦住。调拨则要同时更新设备主表的dept_id和keeper_id并记录调拨前后的部门。如果公司有资产归属核算需求调拨记录就是分摊依据。调拨审批流可以和领用共用一套审批框架只是业务类型不同。注意状态回写一定要用数据库事务包住设备主表更新和流转记录插入要么都成功要么都失败否则会出现设备状态变了但查不到流转记录的脏数据。4. 避坑与排查OAMS 部署和运行中的五个高频问题这套系统从代码到真正跑在办公室环境里中间会踩不少坑。下面五条是我在实际部署和调试中反复遇到的按「现象 → 原因 → 解决」整理能帮你省下不少排查时间。现象一前端页面能打开但所有接口返回 401。原因通常是 JWT token 没带上或者过期了也可能是后端跨域配置没生效导致预检请求被拦截。解决方法是先看浏览器 Network 面板里请求头有没有Authorization字段没有就检查前端请求拦截器有的话看后端跨域配置是否允许了前端域名和Authorization头。开发环境图省事可以临时关掉跨域限制但上线前必须配好白名单。现象二设备列表加载特别慢数据量才几千条就卡。原因多半是 N1 查询比如列表里每条设备都去查一次分类名称和保管人姓名。解决方法是把分类和用户信息一次性查出来做内存映射或者用 JOIN 查询直接带出来。另外检查status和keeper_id字段有没有索引没索引的全表扫描在数据量上来后是灾难。现象三上传设备照片成功但详情页显示裂图。原因是上传目录没有对外暴露静态资源映射或者 Nginx 没配对应的 location。Spring Boot 里要加WebMvcConfigurer把上传目录映射到 URL 路径Nginx 部署时也要加一条location /upload/指向实际目录。另外注意文件名里的中文和特殊字符存盘时最好重命名成 UUID避免 URL 编码问题。现象四审批通过后设备状态没变但申请单显示已通过。这是典型的事务问题设备更新和申请单更新不在同一个事务里或者设备更新时状态校验失败但没抛异常。解决方法是把两个更新放在同一个Transactional方法里并且设备更新要用条件更新where status 在库根据影响行数判断是否成功失败就回滚整个事务。现象五二维码扫码后跳转 404。原因是二维码里存的 URL 是开发环境的localhost部署后域名变了但二维码没重新生成。解决方法是二维码内容用相对路径或者配置化的域名部署后批量重新生成一次标签。如果设备已经贴出去了可以在扫码落地页做一次重定向把旧地址映射到新地址。提示部署到 Linux 服务器后注意文件上传目录的权限和磁盘空间。磁盘满了会导致上传失败但接口可能返回成功因为异常被全局捕获后没正确传递。5. 进阶技巧用定时任务做设备维保提醒与数据导出系统跑起来之后真正拉开效率差距的是两个进阶功能维保到期自动提醒和台账一键导出。设备管理不只是记录谁在用还要提前知道哪些设备该保养了、哪些保修快到期了。这部分我用一个定时任务加一个导出接口来实现代码不复杂但很实用。维保提醒的思路是在设备表里加warranty_end_date和next_maintain_date两个字段然后用 Spring 的Scheduled每天凌晨跑一次查出 30 天内到期的设备往消息表里插提醒记录或者直接发邮件。Component public class MaintainReminderTask { Autowired private AssetDeviceMapper deviceMapper; Autowired private NotifyService notifyService; // 每天凌晨 2 点执行cron 表达式按需调整 Scheduled(cron 0 0 2 * * ?) public void checkMaintainDeadline() { LocalDate today LocalDate.now(); LocalDate deadline today.plusDays(30); // 查询 30 天内维保到期的设备状态排除已报废 ListAssetDevice devices deviceMapper.selectList( new QueryWrapperAssetDevice() .le(next_maintain_date, deadline) .ge(next_maintain_date, today) .ne(status, DeviceStatus.SCRAPPED) ); for (AssetDevice device : devices) { // 避免重复提醒先查当天是否已发过 if (!notifyService.existsToday(device.getId(), MAINTAIN)) { notifyService.sendMaintainRemind(device); } } } }cron表达式0 0 2 * * ?表示每天 2 点执行服务器时区要确认是东八区否则会在奇怪的时间触发。查询条件里ge和le把范围卡在「今天到 30 天后」避免把已经过期的也捞出来重复提醒。existsToday这个去重判断很重要否则定时任务重跑或者多实例部署时会发重复通知。数据导出用 EasyExcel 或 POI 都行我倾向 EasyExcel内存占用低。导出字段建议做成可配置的行政要的字段和财务要的字段不一样。导出时注意把状态码转成中文描述别把0/1/2直接导出去否则拿到表格的人还得对照文档看。导出场景建议字段注意事项行政盘点资产编号、名称、状态、保管人、位置按部门分组排序财务对账资产编号、采购日期、金额、折旧年限金额保留两位小数维保计划资产编号、名称、维保到期日、供应商只导未报废设备导出接口要做权限控制普通员工不能导出全量数据。数据量大时用异步导出先返回任务 ID前端轮询下载链接避免请求超时。从那以后我每次部署这类管理系统都会先把定时任务的时区和去重逻辑检查一遍再手动触发一次导出验证字段映射。这两个地方出问题不会报错但会悄悄产生错误数据等发现时已经积累了一堆。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

SpringBoot2+Vue3流浪宠物管理系统:前后端分离架构实战解析

SpringBoot2+Vue3流浪宠物管理系统:前后端分离架构实战解析

1. 这个系统解决的是什么问题:流浪宠物救助的数字化盲区说实话,市面上打着"宠物管理系统"旗号的项目源码并不少,但真正能落地到流浪动物救助场景的却不多。大部分所谓管理系统要么是单纯的前端页面堆砌,要么后端只做了简…

2026/10/14 4:00:41 阅读更多 →
Matlab实现CNN-GRU多特征分类预测:从数据准备到模型落地

Matlab实现CNN-GRU多特征分类预测:从数据准备到模型落地

涉及到用Matlab做时序或者多维特征数据的分类预测时,CNN-GRU这个组合近年来出镜率非常高。一方面卷积结构擅长局部特征提取,另一方面GRU门控循环单元对序列依赖关系的建模能力又比普通前馈网络强很多,两个搭在一起后,既能处理多维…

2026/10/14 4:00:41 阅读更多 →
Claude Code + git worktree 多分支并行开发实战指南

Claude Code + git worktree 多分支并行开发实战指南

最近半年我一直在重度使用 Claude Code 做日常开发,手头同时维护好几个功能分支是常有的事。一开始我还是老一套:开一个终端窗口,在一个工作目录里反复git checkout切换分支,切来切去不仅脑子乱,更麻烦的是 Claude Cod…

2026/10/14 4:00:41 阅读更多 →

最新新闻

Qt Linux打包失败原因与linuxdeployqt避坑指南

Qt Linux打包失败原因与linuxdeployqt避坑指南

简介:本资源是一份面向Linux Qt开发者的技术实践指南,聚焦Ubuntu环境下使用linuxdeployqt工具完成Qt程序跨机部署的核心痛点。针对无Qt运行环境的目标机器,系统性梳理了从Qt开发环境配置、linuxdeployqt源码编译(含Ubuntu 18.04兼…

2026/10/14 4:46:57 阅读更多 →
开放权重模型:可控部署、商用微调与硬件感知推理实战

开放权重模型:可控部署、商用微调与硬件感知推理实战

1. 项目概述:一场被公开谈论的“开放权重”战略卡位战最近刷到一条消息,说英伟达正在和一家叫 Reflection AI 的初创公司洽谈收购或追加投资——这事本身不稀奇,大厂盯上潜力股是常态。但真正让我多看了两眼的,是它背后那个反复出…

2026/10/14 4:46:57 阅读更多 →
Linux系统工具pstack二进制瘦身实战:ELF优化与C语言编译精简

Linux系统工具pstack二进制瘦身实战:ELF优化与C语言编译精简

1. 一个被低估的系统工具&#xff1a;pstack 的“瘦身”为什么值得较真很多人第一次听说 pstack&#xff0c;是在某个进程卡死、CPU 疯狂打满、日志毫无输出的深夜。运维同事甩来一句&#xff1a;“快&#xff0c;pstack 看下堆栈&#xff01;”——于是你敲下pstack <pid&g…

2026/10/14 4:46:57 阅读更多 →
PS5数据管理方案:AnyPS5搞定存档备份与远程串流

PS5数据管理方案:AnyPS5搞定存档备份与远程串流

1. 为什么需要AnyPS5方案PS5入手之后&#xff0c;很多玩家都会遇到同一个问题&#xff1a;主机硬盘看着不小&#xff0c;真用起来却总是捉襟见肘。一款大型游戏动辄上百GB&#xff0c;加上截图、录像、存档备份&#xff0c;内置SSD没过多久就亮红灯。更麻烦的是&#xff0c;一旦…

2026/10/14 4:46:57 阅读更多 →
实时事件分析系统架构设计与Flink+Kafka+ClickHouse实战

实时事件分析系统架构设计与Flink+Kafka+ClickHouse实战

1. 从“rea”这个标题说起&#xff1a;一个被低估的缩写背后藏着什么第一次看到“rea”这个标题的时候&#xff0c;我脑子里蹦出来的第一反应是——这大概率又是一个被缩写玩坏的项目名。做技术的人都有个通病&#xff0c;喜欢把长名字砍成三四个字母&#xff0c;仿佛名字越短越…

2026/10/14 4:46:57 阅读更多 →
一文搞懂MySQL socket连接:原理、配置与2002/2003故障排查

一文搞懂MySQL socket连接:原理、配置与2002/2003故障排查

一次线上事故让我把socket连接这件事彻底搞明白了。当时某个项目组反馈所有本地应用突然连不上MySQL&#xff0c;我登录服务器一看&#xff0c;mysqld进程明明活着&#xff0c;3306端口也在正常监听&#xff0c;可本地应用全部报socket错误。查了半个多小时&#xff0c;最后发现…

2026/10/14 4:45:56 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起&#xff1a;它到底想解决什么问题第一次看到"AnyPS5"这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述&#xff1a;Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师&#xff0c;我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性&#xff0c;实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景&#xff0c;也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间&#xff0c;确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中&#xff0c;这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →