ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

餐饮连锁管理系统设计与实现:Spring Boot+Vue前后端分离毕业设计

餐饮连锁管理系统设计与实现:Spring Boot+Vue前后端分离毕业设计 很多做毕设的同学跟我聊到餐饮管理系统的选题时第一反应都是“这不就是个增删改查吗”。说对了一半但如果只是把它当普通 CRUD 做答辩的时候很容易被问住。餐饮连锁店管理系统真正难的地方在于门店和总部的关系怎么设计、订单和库存怎么联动、不同门店的数据怎么隔离、前端菜单权限怎么跟后端接口权限配合。这几个点一旦想清楚系统整体质量会拉开一大截。这个项目采用 Spring Boot Vue 前后端分离架构配套 MySQL 数据库和完整开发文档适合计算机相关专业毕业生作为毕业设计也适合刚入门全栈开发的人拿来练手。它覆盖了一条完整业务链路总部维护门店和菜品、门店接收订单、订单自动扣减库存、经营数据汇总到总部后台同时包含角色权限、会员管理、报表统计等常见模块。下面我按自己实际开发这类系统的经验把核心设计、表结构、代码思路和踩过的坑完整拆开讲一遍。1. 项目概述与核心功能拆解1.1 餐饮连锁店管理系统到底要解决什么问题单店餐饮系统市面上很多客如云、美团收银这类 SaaS 产品也做得很成熟。连锁店跟单店最大的差异在于“多门店协同”。一家店自己记账容易十家店同时营业总部却看不到哪家店卖得好、哪家原材料库存快见底、哪个店长上报的数据可信度如何这就不是 Excel 能解决的问题了。连锁管理系统至少需要解决四个层面的问题。第一个是统一基础数据菜品、分类、口味标签、价格策略都由总部统一下发门店不能随便改核心菜单。第二个是数据隔离门店店长只能看到本店订单和库存总部能看到全部门店汇总。第三个是业务流程闭环从用户下单、门店接单、厨房制作到库存扣减、采购补货每个环节要有记录。第四个是经营分析各门店营业额、客单价、菜品销量排行要有统一口径方便做门店考核。毕设系统不需要做到 SaaS 级别但上述四点在架构上都要有对应设计这样才能在论文和答辩里讲出“业务理解”。很多同学只做一张订单表和一张菜品表把价格写死库存完全不联动这其实丢掉了餐饮系统最有价值的部分。1.2 毕业设计版本的系统功能清单我建议把系统划分成总部端和门店端两个视角再加上一个简单的收银/点餐端。这套功能划分也是很多餐饮管理系统毕设项目的常见结构便于论文分章节描述。从角色角度拆分系统包含三类核心用户。系统管理员负责系统初始化、创建门店账号、分配角色权限。总部人员负责菜品管理、门店管理、员工管理、全部门店的经营报表查看。门店店长和收银员则负责本门店的点餐开单、订单管理、库存查看和简单的本店统计。从模块角度拆分核心功能集中在六个模块。用户登录模块包含验证码、JWT 令牌、角色路由权限门店模块包含门店增删改查、门店启停用、门店地址和联系方式维护菜品模块包含菜品分类、菜品信息、规格口味、上下架状态、图片上传订单模块包含点餐下单、订单状态流转、订单明细、订单退款/取消库存模块包含原料库存、入库出库记录、订单自动扣减库存、库存预警报表模块包含营业额趋势、菜品销量排行、门店经营对比。这套功能列表看起来常规但每一条背后都有可深挖的点。比如订单状态不是简单一个字段而是要定义待支付、已支付、制作中、已完成、已取消菜品上下架要跟门店关联不是总部改了立即全部门店生效而是支持按门店单独控制。这些细节后期在实操环节会逐个说明。2. 技术选型与整体架构思路2.1 为什么选 Spring Boot Vue选型永远是答辩时第一个被问到的问题所以不能只回答“网上教程多”。Spring Boot 的优势在于快速整合生态内嵌 Tomcat起步依赖简化配置适合快速搭建 RESTful 后端服务。Vue 的优势在于组件化开发和响应式数据绑定Element Plus 这类组件库可以快速拼出管理系统界面开发效率非常高。前后端分离也是当前企业级项目的主流形态。后端只提供 JSON 接口前端负责页面渲染和交互两者通过 HTTP 通信。这样分工清晰前端开发可以基于 Mock 数据并行推进后端也可以直接用 Swagger 接口文档给前端联调。毕业设计采用这种方式更容易体现对现代开发模式的理解。真正动手的时候很多同学纠结用 Vue2 还是 Vue3。建议直接用 Vue3 Vite。Vue2 虽然教程多但 Element UI 已经停止维护新项目没必要往老技术栈上靠。Vue3 组合式 API 配合script setup写起来更简洁Vite 冷启动和热更新速度也比 Webpack 快很多。后端框架版本用 Spring Boot 2.7 或者 3.x 都行如果 Java 版本是 17用 3.x 比较顺手如果还是习惯 Java 8就用 2.7.x两者在毕设功能层面差别不大。2.2 前后端分离的整体架构与关键依赖清单整个系统架构可以概括为“一个后端服务 一个前端应用 一个 MySQL 数据库”。后端按 Controller、Service、Mapper 分层前端按页面、组件、API 封装、状态管理分层。这里我用表格把主要技术选型和依赖列出来方便大家照着自己搭环境。层次技术选型主要作用后端基础框架Spring Boot 2.7.x 或 3.x提供 Web 服务、IOC 容器持久层框架MyBatis Plus单表 CRUD 免写 SQL复杂查询用注解数据库MySQL 8.x存储业务数据鉴权方案Sa-Token 或 JWT 拦截器登录状态校验和角色权限控制接口文档Knife4j / Swagger自动生成接口文档方便联调对象存储本地文件存储或 MinIO菜品图片、门店头像上传前端框架Vue3 Vite单页应用开发UI 组件Element Plus表格、表单、弹窗、消息提示状态管理Pinia保存用户信息和菜单权限HTTP 请求Axios调用后端接口统一处理 token图表ECharts营业额趋势、菜品排行等可视化这套组合最大的好处是每一层都有成熟方案出问题几乎都能搜到解决方案。数据库连接池用 HikariCPSpring Boot 默认就是它性能足够。项目结构上后端分为controller、service、mapper、entity、dto、vo、config、common这几个包前端src下分为api、views、router、store、components、utils。只要按这个结构放文件不管是自己写还是照着网上的开源项目改心里都会非常有底。3. 数据库设计与表结构落地方案3.1 连锁模型的核心门店与总部的数据关系数据库设计是整个系统的地基也是最值得在论文里花篇幅写的部分。餐饮连锁模型里最核心的关系是“总部-门店-业务数据”三层结构。菜品和门店之间是多对多关系因为总部维护了一个总菜品池每个门店可以决定哪些菜品上架销售。如果一个菜品不同门店价格不一样就需要一张中间表来记录门店维度的价格和上下架状态。员工和门店之间也是多对多关系因为员工可能调店一个店长可能临时管理多家门店。但为了降低毕设复杂度通常做成一对多也就是每个员工归属一个门店员工表里存store_id。这样既满足连锁场景又不会引入过于复杂的关联逻辑。订单和门店之间的关系要非常清晰订单表必须冗余一个store_id字段而不是通过其他表间接推出来。为什么因为后续所有报表统计都要按门店分组如果每次都要关联查询性能差不说SQL 也会很啰嗦。冗余这个字段虽然违背了某些范式原则但在业务系统里是高性价比的做法。3.2 核心表结构设计与字段说明我建议核心表控制在十张以内但不该省的字段必须留好。以我实际项目经验下面这些字段是经常被遗漏但很重要的用户表用来放登录账号、密码密文、姓名、手机号、角色、所属门店。密码不要明文存储用 BCrypt 加密。角色可以用role字段区分也可以引入角色表毕设用简单字符串字段即可。门店表放门店编号、名称、地址、联系电话、营业状态。门店编号建议用业务编码比如ST001比自增主键更容易识别和展示。菜品分类表单表存储分类名称和排序号菜品表和分类表外键关联。菜品表包含菜品名称、图片、分类、单价、成本价、描述、上下架状态。成本价不要随便暴露给前端后端接口做 VO 转换时要把敏感字段剔除。订单表是整张库最核心的表包含订单编号、门店 ID、餐桌号或取餐号、订单类型堂食/外卖/自取、订单金额、实付金额、支付方式、订单状态、下单时间、支付时间、完成时间、创建人。订单明细表记录每个菜品购买数量、单价、小计一张订单对应多条明细。库存表的粒度要明确是按原料库存还是按菜品库存。毕设建议直接按菜品原料做一张inventory表字段包括食材名称、库存量、单位、预警值、门店 ID。每次订单完成后根据订单明细里的菜品去扣减对应原料库存。这里需要一张菜品和原料的绑定关系表如果不想引入第三张表可以退一步让菜品直接关联一个原料 ID。会员表可以做也可以不做但如果想体现营销业务就加一张member表包含手机号、会员等级、积分、余额、创建门店。会员点餐时用手机号识别身份消费后积分累加。3.3 订单与库存的数据一致性设计订单和库存是连锁餐饮系统里最容易出 bug 的地方。用户下单、支付成功、后厨出餐每个动作都会影响库存如果不做控制超卖和库存负数的问题会直接暴露在演示环节。我的做法是订单状态流转到“已支付”时才扣减库存而不是创建订单时立刻扣。原因很简单订单可能被取消或支付超时提前扣库存会造成库存虚减。如果要更严谨可以在下单时锁定库存支付后确认扣减但这对毕设来说过分复杂。选择“支付成功再扣减”的状态机方案实现简单且能向答辩老师讲清楚业务规则。扣减库存要用数据库行锁来保证并发安全。用 MyBatis Plus 时直接UPDATE inventory SET stock stock - #{num} WHERE store_id #{storeId} AND item_id #{itemId} AND stock #{num}这条 SQL 通过stock num条件防止扣成负数返回受影响行数来判断是否扣减成功。如果失败说明库存不足需要抛出业务异常并回滚整个下单事务。这里有个很容易犯的错在 Java 代码里先查询库存数量判断是否足够再执行更新。两个步骤之间有时间差并发时会出现两个请求同时查询到库存 5同时扣 3结果库存变成 2而实际应该剩 1。必须用扣减条件带stock 的方式让数据库自己判断这算是我在这个项目里最有价值的实践经验之一。4. 后端核心功能实现与编码思路4.1 项目初始化与分层结构后端项目创建并不复杂但初始化的细节决定后期开发是否顺畅。我建议直接用 Spring Initializr 生成基础工程然后手动添加所需依赖而不是从零搭 Maven 工程。依赖上必须包含spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-j、lombok、spring-boot-starter-validation、knife4j-openapi3-jakarta-spring-boot-starter。项目结构按照controller - service - mapper竖向分层同时增加common包存放统一返回结果、异常处理、工具类。统一返回结果里我自定义一个ResultT类包含code、msg、data三个字段。接口成功返回code200业务失败返回code500或自定义错误码这样前端 Axios 拦截器可以统一判断。异常处理一定要做全局切面否则每个 Controller 都写 try-catch 会疯掉。用RestControllerAdvice定义一个全局异常处理器业务异常和参数校验异常统一拦截返回规范格式。这样控制器里只写业务逻辑代码可读性会高很多。一个非常实用的习惯是把常量也统一管理。比如订单状态0 待支付、1 已支付、2 制作中、3 已完成、4 已取消、菜品状态0 下架、1 上架这些数字散落在代码里会让后续维护非常痛苦。写一个OrderStatus或者CommonStatus常量类所有判断都用常量引用既减少魔法值也能在答辩时展示代码规范意识。4.2 登录鉴权与门店数据权限后端安全设计是答辩时容易被追问的部分。我采用的方案是 JWT 无状态认证用户登录成功后后端签发一个 token 返回前端存在本地存储每次请求在请求头Authorization里携带。后端用一个拦截器统一校验 token解析用户 ID、角色、门店 ID 等信息存入 ThreadLocal 供后续逻辑使用。Spring Boot 里启用拦截器很简单写一个JwtInterceptor实现HandlerInterceptor在preHandle里校验 token然后在 WebMvcConfigurer 里注册拦截路径。不需要额外引入 Spring Security 的复杂过滤器链因为对毕设系统来说JWT 拦截器已经足够清晰而且占的篇幅少。数据权限要比登录鉴权复杂一点但理解后一句话就能说明白不同的角色看不同范围的数据。系统管理员看所有门店总部人员可以选择门店查看门店店长只能看自己门店。实现上我是在表结构里冗余store_id查询时根据当前登录用户角色自动拼接过滤条件。比如店长用户的 SQL 查询会自动带上AND store_id 当前用户门店ID这个逻辑抽成一个查询工具类或者写在 AOP 切面里都行。想清楚角色矩阵再动手能少走很多弯路。我用一个简单表格列出了后端接口在三种角色下的可见范围接口类型超级管理员总部运营门店店长门店管理全部门店全部门店仅本店查看菜品管理全部菜品管理菜品池管理本店上架订单查询全部门店全部门店仅本店库存管理全部门店全部门店仅本店及预警处理经营报表全局汇总全局汇总本店数据这里我踩过一个坑最初店长登录后调通用查询接口接口没有根据角色拼门店条件导致一个店长能查到其他门店的订单和营业额演示时相当尴尬。这个数据权限规则后来我放在 Service 层统一处理所有订单和报表查询都走同一个带权限判断的方法再没出过类似问题。4.3 订单流程与库存扣减的落地代码思路订单流程建议设计成接口组合而不是一个大接口全做完。核心接口包括创建订单、支付订单、取消订单、完成订单、查询订单详情。我用一个创建订单的简化代码来演示核心逻辑Transactional public OrderVO createOrder(OrderCreateDTO dto) { // 1. 查询门店和菜品信息 Store store storeService.getById(dto.getStoreId()); if (store null) { throw new BizException(门店不存在); } // 2. 计算订单金额 BigDecimal totalAmount BigDecimal.ZERO; for (OrderItemCreateDTO item : dto.getItems()) { Menu menu menuService.getById(item.getMenuId()); if (menu null || menu.getStatus() ! 1) { throw new BizException(菜品不存在或已下架: item.getMenuId()); } totalAmount totalAmount.add(menu.getPrice().multiply(BigDecimal.valueOf(item.getNum()))); } // 3. 生成订单主数据和明细 Order order new Order(); order.setOrderNo(generateOrderNo()); order.setStoreId(dto.getStoreId()); order.setTotalAmount(totalAmount); order.setStatus(OrderStatus.PENDING_PAY); orderMapper.insert(order); // 先计算明细金额再批量插入 ListOrderItem orderItems buildOrderItems(dto, order.getId()); orderItemService.saveBatch(orderItems); return convertToVO(order); }这个流程有几个关键点。订单金额一定要在服务端计算不能信任前端传的金额否则用户可以改价格。菜品状态必须是上架状态下架菜品不能点单。生成订单编号用“日期 随机序列”的方式比如20250601120000123保证时间维度上的可读性也能避免并发主键冲突。支付成功后的库存扣减我单独写了一个StockService.deductStockByOrder(orderId)方法方法内部先查订单明细再逐条执行带条件的更新 SQL。整个支付接口上加Transactional如果某条明细扣减失败整个事务回滚订单状态不会停在“已支付”却库存没扣。事务理解到位了这类系统的核心风险就控住了一半。5. 前端 Vue 实现与页面交互细节5.1 前端项目结构与路由权限控制Vue 前端项目建议直接用 Vite 创建命令是npm create vitelatest frontend -- --template vue。创建完成后安装element-plus、element-plus/icons-vue、axios、pinia、vue-router、echarts这几项覆盖了管理系统的全部基础需求。前端目录结构上我把api文件夹按业务模块拆分每个模块一个文件例如store.js、menu.js、order.js、report.js、auth.js。每个文件导出对应的请求函数内部统一使用封装好的request实例。request.js里用 Axios 创建实例设置baseURL添加请求拦截器自动携带 token添加响应拦截器统一处理业务错误码和 401 跳转登录页。路由权限控制是前端比较容易漏掉的功能。简单做法是在路由表里给每个路由配置meta: { roles: [admin, store] }登录后从后端返回当前用户的角色和动态菜单用这个信息过滤路由表。更简单一点的做法是只用本地静态路由表进去之后根据角色隐藏无权限菜单。毕设用后者已经足够但动态路由在答辩时更亮眼。Pinia 在这里的作用是保存登录用户信息、token、菜单列表、门店 ID。注意不要把 token 只存在 Pinia 里要同时写入 localStorage刷新页面后重新读取。很多同学踩过刷新后登录态丢失的坑就是因为只存了内存没有做持久化。我习惯在 Pinia 里封装一个initUserFromStorage()方法应用启动时调用一次读不到 token 就跳登录页。5.2 表格、表单和图表页面的关键实现后台管理系统页面无非是“左侧菜单 顶部栏 表格 弹窗表单”的排列组合。Element Plus 的el-table、el-form、el-dialog、el-pagination是主力组件把这几个组件的交互细节处理好页面质量就很稳。门店管理页面是一个标准的表格页。页面加载时调用listStore接口表格绑定tableData分页组件绑定page和size。新增和编辑弹窗共用同一个表单组件通过dialogMode区分是新增还是编辑。提交表单前用el-form的rules校验必填项校验通过后调保存接口再刷新表格。这段逻辑看起来普通但代码组织好了后面扩展会非常顺。订单页面建议增加筛选条件状态 tabs、日期范围、门店下拉框总部用户可见、订单号模糊搜索。筛选条件变化时重新请求第一页数据。这里要跟后端接口设计对齐列表接口统一接收pageNum、pageSize、storeId、status、startDate、endDate、keyword这些参数用 MyBatis Plus 的分页插件处理。图表页用 ECharts 展示营业额趋势。前端根据筛选条件请求后端接口后端返回按日期统计的营业额数组前端用echarts.init初始化图表并setOption。有一点需要提醒ECharts 图表在 el-dialog 或隐藏的 tab 里渲染经常宽度为 0解决办法是渲染后调用chart.resize()或者等元素可见后再初始化。图片上传在前端也比较常见。Element Plus 的el-upload组件配合后端文件上传接口上传成功后把返回的图片 URL 存到表单字段里。注意后端文件接口返回的 URL 需要是完整可访问路径不要只返回一个相对路径uploads/xxx.jpg否则前端el-image直接使用时可能拼接错前缀。6. 部署、打包与常见问题排查6.1 本地运行到上线部署的操作步骤毕设项目最终都要能演示我先讲本地运行步骤再讲部署。后端运行前要确保本地安装 JDK、Maven、MySQL、Node.js。数据库先执行项目提供的sql初始化脚本脚本通常包含建库、建表、初始化管理员账号和演示数据。然后用 IDE 打开后端工程修改application.yml里的数据库用户名密码直接运行主类即可启动。前端运行相对简单命令行切到frontend目录执行npm install安装依赖然后npm run dev启动开发服务器。浏览器访问 Vite 输出的本地地址用初始化脚本里的管理员账号登录。这里提醒一句npm install如果报错大概率是 node 版本问题Vite 5 需要 Node 18 以上老版本 Node 会装依赖失败。打包部署时前端先执行npm run build生成dist静态文件目录把dist部署到 Nginx 的html目录。后端执行mvn clean package -DskipTests打包成 jar在服务器上运行java -jar xxx.jar。如果你的服务器只有一台Nginx 里把/api开头的请求反向代理到本地 8080 端口同时配置前端 history 路由的 try_files 回退刷新页面就不会 404。这是部署环节最容易翻车的地方很多人前端刷新报 404就是这个配置没写。6.2 高频报错与解决方案速查表我总结几个做这个项目时几乎必踩的问题做成速查表按出现频率排序。这些问题在任何一个 Java Vue 的 CSDN 博客里可能都有零散记录但集中整理一份会更省时间。报错或现象根本原因解决方案启动报Failed to configure a DataSource没配置数据库连接或没有 mysql 驱动检查application.yml的 url、用户名、密码确认引入 mysql 驱动接口返回 404Controller 路径、前端请求路径不一致检查后端RequestMapping和前端 api 文件里的 url 是否对应前端请求跨域报错前后端端口不同未配置跨域后端加 CORS 配置类或用 Nginx 代理统一域名Knife4j 页面打不开依赖版本和 Spring Boot 版本不匹配确认 springdoc 和 knife4j 版本兼容登录后接口 401token 未携带或过期检查request.js请求拦截器是否把 token 放入请求头中文乱码数据库字符集不是 utf8mb4建库时指定utf8mb4连接串加characterEncodingutf8表格分页数据总对不上前端页码从 0 开始后端从 1 开始统一页码约定建议前端传pageNumcurrent1前端 build 后接口地址 404baseURL 配的是/api部署环境没代理Nginx 配置反向代理或将 baseURL 改为完整后端地址6.3 一个容易被忽视的问题前端打包后的接口路径这个问题我想单独拎出来说因为它属于那种“本地好好的部署就挂”的典型问题。开发环境下Vite 配置了proxy代理前端请求的/api自动转发到http://localhost:8080所以一切正常。但打包之后Vite 的 proxy 不再生效前端请求直接发送到部署服务器的 80 端口。如果后端 jar 在 8080Nginx 又没有配置/api反向代理接口就会 404。所以打包前要么确认 Nginx 配置了/api转发要么修改request.js里的baseURL为完整的后端地址。我通常喜欢用 Nginx 代理方案原因是不用改前端代码而且生产环境前后端共用域名更安全还能顺便解决跨域。Nginx 关键配置大致如下server { listen 80; server_name yourdomain.com; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } }如果你不想用 Nginx也可以在application.yml里配置spring.web.resources.add-mappings并开启静态资源映射把前端 dist 文件复制到后端 resources/static 下直接访问 8080 端口。这个方案适合演示用但我个人不推荐作为正式部署方式因为前后端彻底耦合了后续改动很不灵活。还有一个经常被问到的问题只有 jar 包没有源码怎么反编译成项目。如果哪天你拿到一个编译好的 jar 又丢了源码可以用cfr或jd-gui这类反编译工具把 jar 里的 class 反编译成 Java 文件再手动搭回 Maven 工程结构。不过反编译出来的代码可读性较差变量名和方法体基本能看注释全丢应急参考可以不能当成源码直接改。这里也提醒一下毕设文档一定提前备份好源码别等到答辩前才到处找。7. 对毕设答辩和扩展的实用建议7.1 答辩时怎么讲这个系统才有说服力答辩和写代码是两回事很多同学代码写得不错讲的时候却总在念功能列表。我建议准备一张系统架构图和一页核心业务流程图重点讲清三件事系统解决了什么问题、你自己做了哪些设计、遇到过什么难点怎么解决的。第一件事很好讲就是连锁门店数据不统一、库存不透明、报表汇总困难。第二件事要讲设计亮点比如门店与菜品多对多关系、订单状态机、库存扣减的并发控制、JWT 鉴权。第三件事一定要讲真实经历比如你被跨域问题卡了半天最后用 Nginx 代理解决或者你被并发扣库存的问题问到最后用带条件更新解决。真实项目经验比任何背诵都更能打动老师。这里有个沟通技巧讲到数据库设计时主动解释为什么订单表要冗余store_id为什么数据权限要在 Service 层统一处理而不是在每个 Controller 里分别写。主动暴露设计思考能展示你不是在“照抄”而是在“做设计”分数通常会有明显差别。7.2 后续可扩展的方向如果时间和精力允许在毕设版本上再做几个可落地的扩展项目含金量会完全不同。第一个扩展是做 Android / H5 点餐端复用后端接口前端技术栈用 Vant 组件库开发移动端只做点餐和支付流程工作量可控。第二个扩展是引入 Redis 缓存菜品列表和 Token体现性能优化意识。第三个扩展是接入支付宝或微信的模拟支付接口用沙箱环境完成支付回调处理这样订单和库存的闭环更真实。这三个扩展不是必须做但有时间可以做一两个。扩展在论文里可以写进“系统优化与展望”章节答辩被问到“系统还有什么不足”时你能立刻答出具体改进方案而不是支支吾吾说感觉还有提升空间。这一点在所有毕业设计答辩里都非常加分。我个人在做了几个这类项目之后的体会是餐饮连锁管理系统的难点从来不在某个单一技术上而在于把多个技术点串成一个能跑通业务闭环的整体。后端接口设计要前置考虑前端调用前端页面设计要回过来验证后端接口的合理性。如果能自己独立从数据库设计一路做到前后端联调、部署上线你对 Spring Boot 和 Vue 的理解一定会上一个台阶答辩时也能真正讲出自己的东西。
返回列表