基于Spring Boot的连锁餐厅管理系统设计与实现
1. 连锁餐厅的运营痛点与这套系统的定位1.1 门店越多账越乱做过餐饮软件或者去连锁店消费过的人应该都有感受一家店的时候靠人盯还能盯得过来一旦门店数量上到五家、十家甚至跨区域分布纯靠 Excel 和微信群排班报菜基本就是灾难现场。我这次做的这个基于 Spring Boot 的连锁餐厅管理系统项目代号用的 715womqc最初的需求来源就是这么个背景——一个拥有多个直营门店的餐饮品牌希望把菜品维护、点单收银、会员储值、门店管理统一到一个系统里。当时对接需求时对方负责人说了句很形象的话我们不是缺生意是缺一套能把每家店每天卖了多少、还剩多少菜、谁充了多少钱都记清楚的工具。这句话基本就是这套系统的灵魂。它不是一个花哨的前台展示项目而是一个围绕总部—门店—消费者三条线展开的业务管理系统。总部要能统一维护菜品基础数据门店要能独立收银和管理菜品上下架消费者要能办会员、储值、累计积分。三股线拧在一起才称得上连锁管理系统。1.2 系统覆盖的角色与业务边界这套系统在规划的时候我把用户分成了四个角色各管一段超级管理员总部侧负责门店管理、员工账号分配、菜品统一维护、数据总览。门店店长自己门店的补货状态维护、菜品价格调整、营业数据查看。收银员日常点单、结账、会员登记和储值操作。后厨人员查看当前待制作订单标记出餐状态。有一点想特别说明的是所有功能不能在第一版全堆上去。比如库存模块很多课程设计会做成原材料的进销存但真实餐饮场景里后厨食材库存通常由独立的供应链系统在管前台系统只需要知道某道菜今日是否售罄。所以我最后把库存需求收敛成了简单的菜品上下架状态而不是复杂的出入库。这个取舍算是这套系统做下来比较务实的决定。1.3 交付物的完整构成标题里提到程序、源码、数据库、调试部署方案及开发环境这其实就是一套完整项目的交付物清单。很多人对做一套系统的理解就是写代码但实际上代码只是其中的一部分。真正能让人顺利跑起来、看懂业务、二次开发的交付内容还得包含数据库脚本、开发环境说明、部署文档、界面展示这些周边材料。后续我会在最后一章把这部分展开详细讲。2. 技术选型与工程结构2.1 为什么是 Spring Boot MyBatis-Plus标题里就写了基于 Spring Boot这基本是当前的主流选择。Spring Boot 的好处不必多言自动配置、内嵌 Tomcat、起步依赖管理能让开发者把注意力放在业务逻辑而不是繁琐的 XML 配置上。同时它的生态足够成熟遇到任何问题几乎都能搜到解决方案对新手和非科班开发者都很友好。但 ORM 选型上我在 MyBatis-Plus 和 Spring Data JPA 之间专门做了对比。最后选了 MyBatis-Plus原因有几点连锁餐饮系统的查询条件比较复杂比如多门店、多分类、多状态的组合筛选MyBatis-Plus 的 Wrapper 条件构造器写起来很直白不用拼接大量 SQL。项目里有不少自定义 SQL 的需求比如统计每张订单的金额、当日营收汇总MyBatis 的 XML 映射文件更可控。这个项目面向的学习者通常对 MyBatis 更熟悉上手成本低拿到手之后能更快读懂逻辑。前端采用的是 Vue 3 Element Plus通过 Axios 请求后端 RESTful 接口。如果你不想拆前后端也可以用 Thymeleaf 模板方案但做管理系统类项目前后端分离对后期的界面迭代会更友好这次我选的就是完整的前后端分离。2.2 包结构按业务模块划分一个 Spring Boot 项目如果包结构乱后期维护是真的痛苦。这次的项目没有用单一按层分包的方式而是采用了一种业务导向的划分方式。com.restaurant ├── common // 统一返回结果、全局异常、常量枚举 ├── config // 配置类跨域、MyBatis-Plus 分页 ├── controller // 接口层 ├── service // 业务层接口 │ └── impl // 业务层实现 ├── mapper // 数据访问层 ├── entity // 数据库实体 └── dto // 数据传输对象这里特别强调一下 dto 的价值。很多课程设计项目喜欢直接把 entity 暴露给前端这个习惯不太好。比如订单实体里有删除标记、内部备注这类字段用户端并不需要看到。用 DTO 做一层隔离之后接口返回的数据结构更干净也不会出现前端拿着一串用不上的字段发懵的情况。2.3 统一返回结构和全局异常处理我见过一些项目的 Controller 返回内容五花八门有的返回 Map有的直接返回实体有的把状态码放在 JSON body 里有的干脆用 HTTP 状态码表示业务状态。前后端联调的时候遇到这种接口是真的头疼。所以这次在项目里定义了一个统一的 Result 对象所有接口都返回它。字段就三个code 表示业务状态码message 是给前端的提示文本data 是具体数据。配合这个 Result项目里还加了一个全局异常处理器。业务代码里只需要抛出自定义的业务异常比如菜品库存不足会员余额不够这种全局处理器会自动把异常转成对应的 Result 返回给前端。这样一来Controller 里的代码非常干净只关心正常的业务流转不需要每个接口里写 try-catch 来兜底。3. 核心功能模块逐个落地3.1 菜品 SPU 与门店 SKU 的分离设计菜品管理是餐饮管理系统的基础模块。设计的时候首先要考虑一件事同一个菜品在不同门店的价格可能不同比如市中心门店租金高定价就要贵一些。如果只做一张菜品表这个场景根本没法支持。我采用的方案是两张表。菜品表管基础信息类似商品里的 SPU 概念包含菜品名称、图片、描述、口味标签、分类门店菜品表管销售属性类似 SKU 概念记录门店 ID、菜品 ID、销售价格、是否上架。总部改菜名、改图片所有门店同步生效店长调整价格、上下架状态只影响自己门店。这个设计既保证了总部管控的力度又给了门店灵活调整的空间。这也是这套系统里比较核心的一个设计点后续做多门店相关系统时可以同样套用。3.2 点单到结账的完整订单闭环订单模块是整个系统的主心骨。我设计了四个状态来走完整条链路待支付、已支付待制作、制作中、已完成外加两个终止态——已取消和已退款。收银员在前端把菜品加进购物车点击结算生成订单。订单主表存订单号、门店 ID、收银员 ID、会员 ID、总金额、状态这些汇总信息订单明细表存每一道菜的菜名、单价、数量、小计。明细表之所以单独拆出来是因为一张表存会出现大量重复的订单头信息既冗余又不利于按订单维度做统计这一点我在第四章会详细展开。支付这块初期用的是模拟支付。真实场景可以对接微信支付、支付宝但对接需要商户号和证书不适合本地演示和教学使用。模拟支付的好处是能跑通整套状态流转后面想接真实渠道只要替换支付实现类即可。3.3 会员储值与积分的事务处理连锁餐饮的会员体系比较常见的是储值和积分两块。会员表存手机号、姓名、余额、累计积分。用户储值时后端先做金额校验然后把余额更新和流水记录放进同一个数据库事务里。这个事务设计很关键。如果只更新余额而不记流水一旦出了问题根本没有对账依据。所以项目里加了 member_transaction 这张资金流水表每次充值、消费扣款、退款都会写入一条流水记录。对账时只需要按会员 ID 把流水汇总余额是否一致一目了然。积分逻辑做得相对简单消费 1 元积 1 分积分可以在结算时抵扣100 积分抵 1 元。顾客有没有会员、是否使用积分抵扣都会影响订单的最后计算动作。这些业务规则全部放在 Service 层里完成Controller 不做任何金额计算目的是让核心规则可复用、可测试。3.4 多门店权限控制方案权限这块没有直接引入 Spring Security而是自己写了一套基于拦截器的轻量方案。登录成功以后生成一个 Token 保存用户信息前端每次请求在 Header 里带上。拦截器从 Token 里解析出用户角色再去校验当前接口是否允许该角色访问。访问级别大致这样划分总部接口仅超级管理员可调门店接口要求店长或收银员角色出餐接口要求后厨角色。前端则根据角色动态渲染菜单比如后厨人员登录后只看到待制作订单页面。对课程设计级别的项目来说这个方案够用也更容易上手理解。如果后续要接入复杂权限模型比如 RBAC 细粒度权限、按钮级权限控制再逐步升级为 Spring Security JWT 也不迟。至少在这套系统里四类角色的隔离需求基本满足。4. 数据库设计里的关键决策4.1 核心表结构与业务关系表不算特别多但麻雀虽小五脏俱全。核心表大概这些表名用途关键字段store门店表门店名称、地址、联系电话employee员工表姓名、手机号、所属门店、角色dish菜品表菜品名称、分类、图片、描述store_dish门店菜品关联表门店 ID、菜品 ID、价格、上下架状态member会员表手机号、姓名、余额、积分orders订单主表订单号、门店 ID、收银员、总金额、状态order_item订单明细表订单 ID、菜品 ID、单价、数量、小计member_transaction会员资金流水表会员 ID、变动金额、类型、说明后台管理端再单独放一张管理员表和门店员工表分开避免两个体系的账号混在一起。数据量不大的时候这种关系设计够用也不容易绕晕。4.2 订单主表和明细表的拆分逻辑前面提到订单为什么要拆两张表这里展开说说。如果不拆一个订单有 5 道菜就要存 5 条记录每条记录都带上订单号、门店 ID、收银员 ID、总金额、状态这些重复信息查询某门店今天做了多少单要 GROUP BY 一整串字段性能差而且容易出错。拆成主表和明细表之后日常统计就非常简单了统计营业金额直接对 orders 表按状态过滤再 SUM 总金额。分析菜品销售排行对 order_item 表按菜品 ID 分组再 SUM 数量。订单详情展示用订单 ID 关联两张表一次查出主表信息和明细列表。这种主从表结构几乎是所有交易类系统的通用做法以后做电商订单、外卖订单、预约订单都是同一个套路。这个设计思路值得反复体会。4.3 索引、时间字段与金额类型细节虽然项目数据量不大但索引还是要建。我的原则是查询条件里频繁出现的字段建普通索引组合条件比较固定的建联合索引。比如 orders 表里store_id 加 create_time 就是典型的联合索引场景门店营业日报要按门店和时间过滤。时间字段方面创建时间、更新时间这些我用了 MyBatis-Plus 的 MetaObjectHandler 自动填充。插入时自动填 createTime 和 updateTime更新时自动修改 updateTime。这样业务代码里完全不用手动去 set 时间也避免出现这条记录的更新时间怎么是空的这种低级问题。另外一个非常想强调的细节金额字段千万别用 float。金额相关字段一律用 decimal(10,2)Java 侧对应 BigDecimal。浮点数在金额计算上会有精度问题0.1 加上 0.2 出来的结果可能不是 0.3这在收银系统里是绝对不能容忍的。这条经验也是我当年被一条怎么都对不上的流水逼出来的教训。5. 调试与部署实测中踩过的坑5.1 本地开发环境版本搭配本地开发环境版本搭配是拿到项目之后第一个要过掉的关卡。这次项目固定下来的环境是JDK 1.8对应 Spring Boot 2.7.xMySQL 8.0Maven 3.6 以上Node.js 16 以上用于前端 Vue3 开发有个细节要特别注意MySQL 8.0 的驱动名和连接串跟 5.x 不一样。驱动名是 com.mysql.cj.jdbc.Driver连接串里最好加上 serverTimezoneAsia/Shanghai否则本地一连接数据库就报时区错误。这个问题几乎每个第一次用 MySQL 8 的人都会碰到属于入门级但绕不过去的坑。5.2 启动流程与前后端联调后端启动顺序不复杂先导入数据库脚本再改 application.yml 里的账号密码然后启动后端端口默认 8080。前端用 npm install 装依赖之后npm run dev 启动开发服务器默认端口 8081。前后端分离项目必然面对跨域问题。这次的处理方式是在 Vite 配置里加一个代理前端访问 /api 开头的请求由开发服务器转发到后端的 8080 端口。这样浏览器里看到的请求是同源的跨域问题从根上规避掉。上线部署时Nginx 再承担一次类似的反向代理任务。5.3 三个印象最深的问题第一个坑是端口冲突。本地电脑上各种服务占用了 8080 或 8081 很常见。排查方法很简单Windows 上用 netstat -ano | findstr 8080Linux/macOS 上用 lsof -i:8080找到占用进程的 PID 直接结束进程或者在后端 application.yml 里改掉默认端口。第二个坑是数据库编码乱码。导入 SQL 脚本后中文字段变成问号。检查下来发现是导入时连接串里没有指定 characterEncodingUTF-8同时 MySQL 侧的表排序规则用了 utf8mb4_general_ci。两边统一之后才正常。现在部署文档里我会明确要求建库时就带上 utf8mb4 字符集。第三个坑是日期格式。前后端联调时后端返回的日期时间是一串时间戳数字前端直接显示在表格里看起来就是1685000000000这种完全没法看。后来在 application.yml 里配置了 Jackson 的日期格式化统一成 yyyy-MM-dd HH:mm:ss这个问题才真正解决。像这种细节不写进文档的话第二次复现时真的要靠经验去排除。5.4 打包部署的两种路径部署的方案提供了两种模式。本地演示直接 mvn package 打成 jar 包java -jar 启动即可。服务器部署推荐 Docker Compose一条 docker compose up -d 把 MySQL 和 Java 应用一起拉起来环境问题少很多。前端部署用 Nginx把打包后的 dist 目录拷到 Nginx 的 html 目录再配置反向代理/api 路径转发到后端服务。新手这里容易卡住我特意把 Nginx 配置示例完整放在了部署文档里包括监听端口、静态文件路径、代理地址这几个关键配置。打包时还有一个容易忽略的细节如果用了 MyBatis 的 XML 映射文件要检查打包产物里是否把 resources 目录下的 mapper XML 打进去了。否则启动没问题一访问接口就报 Invalid bound statement 错误。这个错我遇见过很多次基本都是打包配置的锅。6. 交付清单与后续扩展建议6.1 一套完整的项目交付包含什么现在很多开发者为了一套完整项目东拼西凑但真正让人省心的交付应该是从环境到代码到文档一次性给齐。这套连锁餐厅管理系统 715womqc 的完整交付可以按五块来理解后端源码Spring Boot 工程含所有 Controller、Service、Mapper、实体类。前端源码Vue3 工程含全部页面组件和路由配置。数据库脚本建库、建表、初始化数据一条龙。调试部署方案文档从本地启动到服务器部署的完整步骤、环境和配置说明。系统界面展示核心页面截图放在文档末尾作为功能对照。我个人建议拿到项目后先不要急着读代码按文档顺序走三件事装好 JDK 和 MySQL导入数据库脚本启动后端和前端。跑通之后再打开源码逐个模块对应着读。这样比躺在一堆源码里猜业务高效得多。6.2 从 715womqc 继续演进的几个方向连锁餐饮目前正处在从经验驱动转向数据驱动的阶段这套系统的业务骨架是完整的后续完全可以继续长出来接入小程序点餐把订单来源从收银台扩展到用户手机端。增加库存预警菜品原材料低于阈值时自动推送提醒。引入报表可视化用 ECharts 做每日营收曲线、菜品销售排名。总部数据大屏实时展示各门店经营数据。支付模块换成真实微信支付或支付宝通道。数据库表结构如果当初设计得合理这些功能基本都是加表、加接口的事不需要推翻重来。这也是我在设计时最看重的原则哪怕系统规模不大业务的边界感和扩展性也得立得住。做完这套系统我最大的体会是管理系统的价值不在于技术多新、界面多炫而在于它能不能把现实世界里的业务约束用代码表达准确。一套流水对得上、权限管得住、订单状态清晰的管理系统哪怕全部用的都是最常规的技术栈也比堆了一堆新技术却经不起业务推敲的演示项目有意义得多。

相关新闻

工业交换机端口分类:选型前你必须看懂的“接口语言“

工业交换机端口分类:选型前你必须看懂的“接口语言“

工业交换机端口分类:选型前你必须看懂的"接口语言"一、从一份让人犯晕的选型清单说起很多工控新人在拿到工业交换机的选型清单时,第一反应往往是"懵"——上面密密麻麻写着"8百兆电口""2千兆 SFP 光口""4M1…

2026/10/14 14:57:31 阅读更多 →
域偏移难题怎么解?TCA算法一招降维搞定迁移学习

域偏移难题怎么解?TCA算法一招降维搞定迁移学习

域偏移这个老大难,TCA算法是怎么用一招降维解决的?先讲一个让我印象特别深的场景。某公司有一套图像识别模型,在A场景采集的数据上准确率能到92%,模型表现相当漂亮;可一旦换到B场景,同样一批类别&#xff0…

2026/10/14 14:57:31 阅读更多 →
签名检测数据集解压与预处理实战指南

签名检测数据集解压与预处理实战指南

简介:本资源是面向计算机视觉开发者与AI研究者的签名检测专用目标检测数据集,聚焦文档图像中签名区域的精确定位任务,适用于YOLO系列模型(含YOLOv12等新架构)训练与验证。数据集共801张真实场景签名图像(JP…

2026/10/14 14:57:31 阅读更多 →

最新新闻

2026跨境电商新规落地后,这5个隐藏坑千万别踩,有人已亏光全年利润

2026跨境电商新规落地后,这5个隐藏坑千万别踩,有人已亏光全年利润

新规实施后的第一个完整季度,不少卖家发现账面利润和预期出现了明显偏差。有人归因于流量成本,有人怀疑汇率波动,但真正的问题往往藏在合规细节里。以下五个容易被忽略的环节,正在悄悄侵蚀利润空间。 一、低申报的“惯性操作”已进…

2026/10/14 15:34:27 阅读更多 →
毕业论文耗时最多的不是写作,而是反复格式排版!okbiye 一站式搞定论文规范

毕业论文耗时最多的不是写作,而是反复格式排版!okbiye 一站式搞定论文规范

很多同学花两三个月完成论文内容撰写,查重、逻辑修改全部完成,却栽在格式排版这最后一关。导师简单一句 “格式不符合学校规范”,整篇文档就要反复调整,页眉、页码、目录、图表、参考文献,随便一处细节出错&#xff0c…

2026/10/14 15:34:27 阅读更多 →
AVO正演C++源码实战:从模型到CDP道集与噪音控制

AVO正演C++源码实战:从模型到CDP道集与噪音控制

简介:这份资源面向石油物探方向的研究生及地震数据处理初学者,聚焦AVO正演模型实验与地震数据正演这一核心课题,帮助读者理解AVO响应特征、角度域分析以及CDP道集的形成过程。压缩包内共4个文件,全部为cpp源代码,整体约…

2026/10/14 15:34:27 阅读更多 →
Farm CLI 命令与选项全解:farm dev、build、watch、preview、clean 的参数详解与源码实现

Farm CLI 命令与选项全解:farm dev、build、watch、preview、clean 的参数详解与源码实现

前端构建构建工具开发工具 【免费下载链接】farm Extremely fast Vite-compatible web build tool written in Rust 项目地址: https://gitcode.com/gh_mirrors/fa/farm 点击查看 免费下载 本文基于 Farm 仓库的 CLI 文档 cli-api.md,系统讲解 farmfe/c…

2026/10/14 15:34:27 阅读更多 →
dplyr filter() 与 filter_out() 错误处理机制与快照测试体系深度解析

dplyr filter() 与 filter_out() 错误处理机制与快照测试体系深度解析

数据分析 【免费下载链接】dplyr dplyr: A grammar of data manipulation 项目地址: https://gitcode.com/gh_mirrors/dp/dplyr 点击查看 免费下载 导读 本文以 dplyr 仓库中的快照文件 tests/testthat/_snaps/filter.md 为核心,系统剖析 filter() 与 …

2026/10/14 15:34:27 阅读更多 →
2026年跨境卖家集体破防:这5个冷门类目正在闷声收割老外,别再死磕低价了

2026年跨境卖家集体破防:这5个冷门类目正在闷声收割老外,别再死磕低价了

当不少卖家还在宠物、服饰、3C配件里卷价格时,一些更细分的需求正在海外市场悄悄放量。它们不算热门,却对应着明确的生活场景和稳定的复购逻辑。与其在红海里反复比价,不如看看这五个类目为什么能跑出利润空间。 一、庭院微生态用品 欧美独栋…

2026/10/14 15:33:26 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

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

周新闻

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

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

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

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

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

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

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

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

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#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/14 7:53:34 阅读更多 →