MySQL+Java轻量仓库系统设计与落地实践
简介这是一套面向计算机、电子信息及数学类专业学生的课程设计与毕业设计参考项目基于MySQL数据库与Java语言实现的轻量级仓库管理系统聚焦库存管理、商品出入库、用户权限等核心业务场景。资源包含完整可运行源码、建库SQL脚本及配套配置文件覆盖后端逻辑7个Java类、界面层3个FXML界面文件、数据持久化9个XML配置文件及数据库初始化脚本1个SQL文件共26个文件压缩包仅960KB结构紧凑、便于快速部署与二次开发。已有342人学习下载适合初学Java Web开发的学生理解MVC分层结构、JDBC连接MySQL、FXML界面绑定等关键技术点。读者可直接导入IDEA运行通过清晰的模块划分如drug.iml工程配置、warehouse-idea目录结构快速掌握项目组织方式并基于现有代码拓展报表统计、多角色权限等功能。1. 为什么一个“课设级”的MySQLJava仓库管理系统反而成了企业初期落地最稳的库存底座你可能不信某高校实验室给本地中小制造厂做的一个课设级仓库系统上线半年后没换架构直接撑住了日均300出入库单、SKU从87个扩到426个、并发操作峰值达12人的真实业务。它没用Spring Boot自动装配没上Redis缓存甚至没做微服务拆分——核心就是MySQL 5.7 Java SE 8 Swing桌面客户端 一套手写的JDBC连接池。这不是怀旧而是验证了一个被低估的事实在库存逻辑清晰、流程固定、数据量中等10万条主表记录、团队无云运维能力的场景下“朴素但可控”的技术栈比“先进但黑盒”的方案更抗压、更易调、更少翻车。这个项目不是教你怎么炫技而是告诉你当你要快速交付一个能真正管住货、对得上账、经得起盘的仓库系统时怎么用最少的依赖、最直的链路、最可读的代码把“入库→上架→领用→盘点→报表”这条主干跑通、跑稳、跑准。它适合两类人一是需要交课设/毕设但拒绝CtrlC/V网上的残缺Demo的学生二是小公司IT岗一人身兼开发、部署、维护三职的工程师——你不需要懂K8s但必须知道executeUpdate()返回-2意味着什么。2. 从零搭起可运行骨架数据库建模与Java工程结构设计2.1 MySQL数据库设计为什么只用5张表就覆盖90%仓库核心流程这个系统不追求范式完美而追求字段可解释、关联可追溯、增删改查无歧义。所有表均采用utf8mb4字符集InnoDB引擎主键统一为BIGINT AUTO_INCREMENT避免UUID索引碎片也规避了INT溢出风险。关键设计逻辑如下warehouse_goods商品主表存储SKU基础信息。重点字段goods_code VARCHAR(32) NOT NULL UNIQUE业务编码非主键但强制唯一方便扫码枪输入、unit VARCHAR(10)单位如“件”“箱”“千克”非枚举而是自由文本因客户常需临时加“托盘”“卷”等非标单位、min_stock INT DEFAULT 0安全库存阈值用于后续预警查询。warehouse_storage库存表核心事实表记录“某商品在某库位的实时数量”。联合主键(goods_id, location_id)避免同一商品重复上架到同一库位。quantity DECIMAL(10,2)支持小数库存如化工原料按千克计。warehouse_location库位表location_code VARCHAR(20) NOT NULL UNIQUE如“A-01-01”area VARCHAR(10)分区如“成品区”“待检区”不设外键约束到storage——这是刻意为之允许库位先存在再上架避免初始化时循环依赖。warehouse_operation_log操作日志表不记录明细只记动作。字段包括op_type ENUM(IN,OUT,ADJUST,CHECK)、related_id BIGINT指向入库单/出库单ID、operator VARCHAR(20)、create_time DATETIME。日志表不参与业务计算但为审计和回溯提供依据。warehouse_in_out_order出入库单主表order_no VARCHAR(32) NOT NULL UNIQUE单据号格式如IN20240520001、order_type TINYINT1入库2出库、status TINYINT DEFAULT 00草稿1已审核2已完成3已作废状态机驱动业务流转而非靠代码硬编码判断。提示建表时务必执行SET FOREIGN_KEY_CHECKS 0;再导入SQL否则storage表因location_id外键未建会报错。全部建完再SET FOREIGN_KEY_CHECKS 1;开启约束。-- 示例创建warehouse_storage表含关键注释 CREATE TABLE warehouse_storage ( id bigint(20) NOT NULL AUTO_INCREMENT, goods_id bigint(20) NOT NULL COMMENT 关联商品ID, location_id bigint(20) NOT NULL COMMENT 关联库位ID, quantity decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 当前库存数量, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 最后更新时间, PRIMARY KEY (id), UNIQUE KEY uk_goods_location (goods_id,location_id) COMMENT 防止同一商品重复上架到同一库位, KEY idx_goods_id (goods_id), KEY idx_location_id (location_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT库存主表记录商品在库位的实时数量;这段SQL的关键在于UNIQUE KEY uk_goods_location——它用数据库层强制保证了“一物一位”的物理约束比Java层校验更可靠。update_time用ON UPDATE CURRENT_TIMESTAMP自动更新省去代码里手动设时间的步骤且避免时区问题。2.2 Java工程结构为什么放弃Maven而用纯目录管理本项目采用src/main/javasrc/main/resources的经典结构但不使用Maven或Gradle。原因很实际课设/毕设评审老师常需直接打开.java文件看逻辑而pom.xml里的依赖版本、插件配置会增加理解成本小公司现场部署时运维人员可能只会双击run.bat不会配Maven环境。我们用最原始的方式确保“拷贝即运行”。com.wms.dao数据访问对象。每个DAO类对应一张表如GoodsDao.java方法名直白insert(Goods goods)、findByCode(String code)、updateQuantity(Long goodsId, Long locationId, BigDecimal delta)。不封装通用BaseDao——因为每张表的查询条件、更新逻辑差异大强行抽象反而增加调试难度。com.wms.model纯POJO字段与数据库列一一对应全部用包装类型Long而非longBigDecimal而非double避免空值NPE。com.wms.util工具类。核心是DBConnectionPool.java——一个极简的连接池仅200行代码最大连接数设为8MySQL默认max_connections151留足余量超时等待3秒。它不处理连接泄漏但提供了closeQuietly(Connection conn)方法要求所有DAO在finally块中调用。com.wms.uiSwing界面。采用CardLayout实现主界面切换入库页/出库页/库存页/报表页所有事件监听器内联编写如btnSave.addActionListener(e - saveInOrder())不抽离为内部类——便于学生快速定位响应逻辑。注意DBConnectionPool的getConnection()方法中若获取连接超时会抛出自定义异常ConnectionTimeoutException并在UI层捕获后弹出“数据库连接繁忙请稍后再试”而非让程序崩溃。这是用户体验的关键细节。3. 核心业务闭环入库、出库、盘点三步的事务控制与数据一致性保障3.1 入库操作如何用单条SQL手动事务保证“货到、单到、账平”入库不是简单往storage表插一条记录。真实场景中一笔入库单可能包含多个商品且需同时更新商品主表的last_in_date、生成操作日志、校验库位是否已满。关键在于所有DB操作必须在一个事务中完成且事务边界由Java代码显式控制而非依赖框架。流程如下用户填写入库单单据号、供应商、日期及明细商品编码、数量、目标库位点击“保存草稿”仅插入in_out_order主表status0点击“提交审核”启动事务执行以下步骤校验所有明细中的goods_code是否存在location_code是否有效对每条明细执行INSERT ... ON DUPLICATE KEY UPDATE quantity quantity VALUES(quantity)—— 这是核心利用storage表的(goods_id, location_id)唯一索引实现“存在则累加不存在则新增”一行SQL解决两种场景更新warehouse_goods表的last_in_date为当前时间插入warehouse_operation_log记录类型为IN更新in_out_order状态为1已审核任一环节失败connection.rollback()并提示具体错误如“库位A-01-01已满剩余容量0.00”。// GoodsDao.java 中的关键方法 public void batchUpdateStorage(Connection conn, ListStorageDetail details) throws SQLException { String sql INSERT INTO warehouse_storage (goods_id, location_id, quantity) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE quantity quantity VALUES(quantity); try (PreparedStatement ps conn.prepareStatement(sql)) { for (StorageDetail detail : details) { ps.setLong(1, detail.getGoodsId()); ps.setLong(2, detail.getLocationId()); ps.setBigDecimal(3, detail.getQuantity()); ps.addBatch(); // 批量添加非逐条执行 } ps.executeBatch(); // 一次提交所有变更 } }这里ps.executeBatch()比循环ps.executeUpdate()快5倍以上且保证原子性。ON DUPLICATE KEY UPDATE是MySQL特有语法务必确认你的MySQL版本≥5.5本项目基于5.7。如果用其他数据库需改用MERGE语句或先SELECT再INSERT/UPDATE性能和并发安全性会下降。3.2 出库操作为什么“预占库存”比“扣减库存”更防超发出库最大的风险是超发——A用户查到库存100件B用户同时查到也是100件两人各申请50件结果都成功库存变成0但实际发了100件。传统方案用SELECT ... FOR UPDATE加行锁但在高并发下易死锁。本项目采用乐观锁预占机制在warehouse_storage表增加reserved_quantity DECIMAL(10,2) DEFAULT 0.00字段记录已被申请但未发货的数量出库申请时执行UPDATE warehouse_storage SET reserved_quantity reserved_quantity ? WHERE goods_id ? AND location_id ? AND (quantity - reserved_quantity) ?即仅当“可用库存quantity - reserved_quantity≥申请量”时才允许预占若executeUpdate()返回0说明库存不足提示“商品X在库位Y可用库存不足”发货完成时再执行UPDATE warehouse_storage SET quantity quantity - ?, reserved_quantity reserved_quantity - ? WHERE ...同时将reserved_quantity减回。此方案无需数据库锁吞吐量高且reserved_quantity字段本身成为业务可见的“待发量”方便仓管员统筹。3.3 盘点操作如何用“差异表”替代全量覆盖降低误操作风险传统盘点是导出全量库存用户修改后全表REPLACE INTO。一旦Excel填错整库数据覆灭。本项目采用差异驱动盘点开始时生成快照表warehouse_inventory_snapshot_20240520表名含日期结构同storage但只存当前数据用户在界面输入实际盘点数系统自动计算差异actual - snapshot.quantity提交盘点结果时只生成差异SQLUPDATE warehouse_storage SET quantity ? WHERE goods_id ? AND location_id ?仅对差异≠0的记录并插入日志op_typeCHECKremark盘盈5件/盘亏2件快照表保留30天可随时对比历史差异。这样即使用户点错也只影响几条记录而非全库。且remark字段为财务对账提供直接依据。4. 避坑指南课设/毕设中最容易栽跟头的5个致命细节4.1 现象Swing界面点击按钮无反应控制台无报错原因Swing是单线程模型Event Dispatch Thread所有UI操作必须在此线程执行。若在ActionListener中执行耗时的DB操作如查询1000条库存EDT被阻塞界面冻结且后续事件无法派发。解决用SwingWorker异步执行DB操作。在doInBackground()中查库在done()中更新UI。切记SwingWorker的publish()/process()用于进度更新get()用于获取结果不可在doInBackground()中直接setText()。4.2 现象MySQL插入中文显示为???但Navicat里正常原因JDBC连接URL未指定字符集。即使数据库、表、字段都是utf8mb4若连接时用useUnicodetruecharacterEncodingUTF-8MySQL 5.7仍可能降级为latin1。解决连接URL必须包含useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai。serverTimezone参数防止DATETIME字段因时区转换出错。4.3 现象同一笔入库单多次点击“提交审核”导致库存翻倍原因前端按钮未置灰用户连点两次后端未做幂等校验。解决在in_out_order表增加submit_hash CHAR(32)字段存单据关键字段如order_nogoods_list_md5的MD5值。提交前先SELECT COUNT(*) FROM in_out_order WHERE submit_hash ? AND status 0若大于0则拒绝。4.4 现象盘点后库存总数对不上但每条记录都检查过原因warehouse_storage表中存在quantity0但reserved_quantity0的记录如预占后取消出库但未释放预占量。这些记录在SUM统计中被计入但实际无货。解决盘点SQL中加入条件AND quantity 0或定期执行清理脚本UPDATE warehouse_storage SET reserved_quantity 0 WHERE quantity 0 AND reserved_quantity 0。4.5 现象导出Excel报表时数字列如单价显示为科学计数法1.23E05原因Apache POI默认对长数字启用科学计数法。解决设置单元格样式CellStyle style workbook.createCellStyle(); DataFormat format workbook.createDataFormat(); style.setDataFormat(format.getFormat(0.00)); // 强制两位小数 cell.setCellStyle(style); cell.setCellValue(goods.getPrice().doubleValue());5. 报表与扩展用原生SQL轻量工具做出让老板点头的可视化5.1 三张救命报表不用ECharts也能讲清库存健康度学生常陷入“一定要做个炫酷图表”的误区但业务方最关心的是三个问题哪些货快没了哪些货积压了最近谁操作最多我们用纯SQLSwing JTable实现代码少、加载快、逻辑透明。安全库存预警报表SELECT g.goods_code, g.goods_name, s.quantity, g.min_stock, (s.quantity - g.min_stock) AS diff, CASE WHEN s.quantity g.min_stock THEN ⚠️ 紧急 WHEN s.quantity g.min_stock * 1.5 THEN 关注 ELSE ✅ 正常 END AS status FROM warehouse_storage s JOIN warehouse_goods g ON s.goods_id g.id WHERE s.quantity g.min_stock * 2 ORDER BY diff ASC;关键在CASE WHEN生成状态标签JTable直接渲染emoji比文字更醒目。库龄分析按入库时间在warehouse_in_out_order表增加in_date DATE字段入库单日期用DATEDIFF(CURDATE(), in_date)算天数分组统计SELECT FLOOR(DATEDIFF(CURDATE(), in_date)/30) AS month_range, COUNT(*) FROM ... GROUP BY month_range输出“0-30天”“31-60天”等区间数量。操作员效能榜SELECT operator, COUNT(*) as op_count, SUM(quantity) as total_qty FROM warehouse_operation_log l JOIN warehouse_storage s ON l.related_id s.id WHERE l.op_type IN (IN,OUT) GROUP BY operator ORDER BY op_count DESC LIMIT 10。注意related_id在日志表中指向单据ID需JOIN库存表才能拿到quantity此处体现表设计时预留的扩展性。5.2 从课设到生产3个低成本升级路径这套系统不是终点而是起点。我带过的几个学生项目毕业后真用它接了小单升级路径非常务实升级方向具体做法成本与风险Web化用Jetty嵌入式服务器 Thymeleaf模板DAO层完全复用只重写Controller和HTML零数据库改动学习成本≈2天风险Swing的线程模型思维需切换到Servlet多线程扫码集成USB扫码枪即插即用模拟键盘输入在文本框addKeyListener监听回车事件触发查询无需SDK成本≈0风险需规范扫码格式如商品码前缀G-库位码前缀L-微信通知调用企业微信API在operation_log插入后发送消息卡片含单据号、操作人、时间需申请企业微信代码≈15行风险网络超时需加重试和本地日志落盘我的习惯是第一次部署时一定在DBConnectionPool里加一行System.out.println(DB connected: url)并把日志重定向到logs/wms.log。不是为了监控而是当客户说“打不开”时我能立刻判断是数据库没启、密码错了、还是网络不通——这比任何高大上的APM工具都管用。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

Java物资管理系统:租赁状态机驱动的多表事务实战

Java物资管理系统:租赁状态机驱动的多表事务实战

简介:本资源是一套完整的Java毕业设计项目——物资管理系统,面向计算机专业本科生及Java初学者,聚焦企业级物资采购、库存、客户与财务管理等核心业务场景,助力毕业设计选题、开发实践与答辩准备。压缩包共10个文件,含…

2026/10/19 0:19:00 阅读更多 →
Prolink串口调试实战:30分钟打通Modbus RTU通信

Prolink串口调试实战:30分钟打通Modbus RTU通信

简介:本资源是一份面向工业自动化仪表工程师与现场调试人员的ProlinkⅡ2.0软件实操指南,聚焦罗斯蒙特1700/2700系列及RFT9739型变送器的通信配置与参数调试。文档详细说明了硬件连接要求(RS-232/RS-485转换、线规与端子定义)、软件…

2026/10/19 0:18:00 阅读更多 →
CanFestival移植到STM32F4:CANopen协议栈源码详解与避坑实践

CanFestival移植到STM32F4:CANopen协议栈源码详解与避坑实践

简介:面向STM32F4嵌入式开发者的CanFestival从站移植源码包,解决CANopen Slave设备快速落地问题。资源将开源协议栈CanFestival与STM32F4结合,重点覆盖对象字典配置、定时器开启、代码结构移植三个核心环节,并基于HAL库与STM32Cub…

2026/10/19 0:18:00 阅读更多 →

最新新闻

黑通道功能安全协议:从原理到落地的完整指南

黑通道功能安全协议:从原理到落地的完整指南

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

2026/10/19 1:34:19 阅读更多 →
JavaWeb课设实战:Filter+Session权限控制与文件上传避坑指南

JavaWeb课设实战:Filter+Session权限控制与文件上传避坑指南

简介:这是一套基于JavaWeb技术栈开发的作业管理网站完整源码,面向计算机、通信、人工智能等专业的本科生及课程设计指导教师,用于支撑期末大作业、课程设计或毕业设计实践。系统采用JSPServletDruid连接池MySQL架构,涵盖用户登录、…

2026/10/19 1:34:19 阅读更多 →
助农小程序毕设技术选型:Java+MySQL+微信原生实战指南

助农小程序毕设技术选型:Java+MySQL+微信原生实战指南

简介:本资源是一套面向计算机专业本科生的毕业设计级微信小程序开发实战项目,聚焦助农扶贫场景,解决传统APP开发成本高、用户安装意愿低、存储占用大等痛点,适用于Java后端与小程序全栈学习者。压缩包共1205个文件,涵盖…

2026/10/19 1:34:19 阅读更多 →
Unity动态字体实战:用系统字体动态生成TMP SDF资产

Unity动态字体实战:用系统字体动态生成TMP SDF资产

简介:UnityNativeOSFont是一套面向Unity开发者的开源插件方案,核心解决TextMeshPro无法直接调用操作系统本地字体的问题。它通过C#脚本在运行时获取系统字体列表,并转换为TMP可用的动态字体资源,适合需要动态切换字体、本地化显示…

2026/10/19 1:34:19 阅读更多 →
嵌入式C指针入门到实践:寄存器映射、野指针与函数指针全解析

嵌入式C指针入门到实践:寄存器映射、野指针与函数指针全解析

1. 为什么要跟指针死磕:嵌入式里的那些绕不开的场景做嵌入式这行,早晚有一天你会被指针逼到墙角。我最早踩坑是在调试一块串口板卡的时候,外设寄存器手册里写着一堆偏移地址,代码里全是一长串强制类型转换的宏,不弄懂指…

2026/10/19 1:34:19 阅读更多 →
RAM盘与DISK盘真实性能对比测试方法

RAM盘与DISK盘真实性能对比测试方法

1. 项目概述:为什么一个“测速”动作值得花半天时间认真对待你有没有遇到过这样的情况:明明手里的固态硬盘标称读写速度是3500MB/s,但实际拷贝一个20GB的工程文件却要等三分钟?或者在做视频剪辑时,预览一帧要卡顿两秒&…

2026/10/19 1:33:18 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 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/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →