招投标系统毕设全栈实战:从业务流程到SpringBoot+Vue实现

发布时间:2026/10/18 22:04:12

招投标系统毕设全栈实战:从业务流程到SpringBoot+Vue实现 1. 毕设选这个题是怎么想的每年到了开题季总能看到一堆人围着“XX管理系统”“XX平台”打转。我要说的是招投标系统这个题目在这么多管理类毕设里属于性价比很高的一档——业务链条足够长、角色足够多、技术点足够密集但又没有像电商秒杀、流式计算那种深不见底的并发难题非常适合用来完整展示一个全栈项目。我最初定这个题的时候其实不是冲着“招投标”三个字去的而是先想明白了一件事毕设答辩最怕什么最怕评委问一句“你这个系统的业务逻辑有没有真正闭环”很多同学做订单管理就只做了个CRUD物流状态全靠手动改数据库评委一问就露馅。招投标系统天然就有完整的流程闭环——招标公告发布、投标方报名、招标文件下载、投标文件加密上传、开标解锁、专家评标、最终定标公示每一步都牵扯上一步的状态流转你不用为了“体现业务复杂度”硬造需求流程本身就是需求。另一个选它的理由是角色权限特别清晰。招投标涉及的参与方有招标方业主、投标方供应商、评标专家、系统管理员至少四类角色每个角色看到的菜单、能做的操作完全不同。这就逼着你必须做一套像样的权限管理模块而不是前端硬写几个路由判断糊弄过去。技术栈上SpringBootVueMySQL这套是毕设圈最常见的组合网上资料多、问题好搜、答辩时评委也认可。我最后确定的整体架构是后端SpringBoot提供RESTful API前端Vue3Element Plus做单页应用MySQL存业务数据Redis做登录令牌和临时缓存文件走本地存储毕设没必要上OSS但设计上会留出接口。这篇文章我会按我实际开发顺序来讲不会只贴代码会把每块我踩过的坑和为什么这样设计的理由说清楚。整套源码包括数据库脚本、前端工程、后端工程、论文和部署文档我最后会整理出来下面从头开始拆。2. 招投标业务的底层逻辑与数据库建模2.1 先画出业务流转的主线再谈建表很多同学拿到这个题第一反应是打开Navicat建表我劝你先别急。招投标系统最忌讳的就是表建了一堆结果业务跑不通。花半天时间把业务主线理清楚后面写代码会顺畅十倍。我把这个系统的主线抽象成五个阶段招标阶段招标方创建招标项目填写项目名称、预算金额、投标截止时间、开标时间上传招标文件附件。系统自动生成招标公告并对外展示。投标阶段投标方浏览公告符合资格就可以报名下载招标文件然后在截止时间前上传加密后的投标文件。开标阶段到了开标时间点系统自动解锁投标文件公开展示各家投标人的报价信息生成开标一览表。评标阶段管理员分配专家专家登录系统给每家投标人打分系统按设置的权重自动汇总。定标阶段招标方确认评审结果系统发布中标公告整个流程归档。这个主线一出来你再看数据库就非常清晰了——每个阶段对应一到两个核心表表与表之间用项目ID串联。我最终的数据库有十几张表但核心就这几张tender_project招标项目主表存基本信息、时间节点、预算金额、当前状态。tender_notice公告表关联项目ID存公告内容和附件路径。bid_company投标方企业信息表报名时自动从用户表冗余一份企业资料过来。bid_record投标记录表这是全系统最核心的表一条记录代表一家企业投了一个标存投标报价、文件加密路径、解密密钥、上传时间、状态。review_score专家评分表存每个专家对某个投标记录的每一项打分。review_rule评标规则表不同项目可以配置不同的分项权重。2.2 投标记录表字段设计里的门道单独把bid_record拿出来讲是因为这张表设计得好不好直接决定了后面功能好不好写。我第一版设计时犯了一个错把投标报价、文件路径、上传状态全放在一张宽表里导致状态流转时经常要更新一堆字段代码里全是散落的update语句。第二版我重新梳理后字段分成了三组业务信息组project_id、company_id、bid_price投标报价用decimal存、bid_document_path投标文件路径。加密与解密组file_encrypted_flag是否已加密上传、decrypt_key密钥开标后用来解密、decrypt_time开标解密时间。这组字段是招投标系统区别于普通文件上传系统的关键。状态流转组status1待提交 2已提交 3已解密 4已评标、submit_time、bid_open_time、version乐观锁版本号。有一点我要特别提醒投标报价这个字段建议用decimal(14,2)用float可能会在计算总价时出现精度问题。虽然Java的BigDecimal能兜底但数据库层面就存精确类型省得两边来回转。另外投标文件加密这个需求毕设阶段不要真去实现全文件RSA加密——开销大、代码复杂答辩时很容易被追问细节然后卡住。我用的是文件后缀改名AES密钥加密关键信息的方式上传前把文件内容Stream加密后落盘密钥单独存数据库开标时用密钥解密。既体现了加密投标的完整思路又不至于把自己逼进密码学的大坑。2.3 权限模型怎么设计RBAC是最稳的方案招投标系统的权限设计我见过有人直接给前端角色表写死路由每个角色一套静态路由表。这个东西能做但项目稍微复杂就会出事——比如管理员想临时给某个专家加一个“导出报表”的权限静态路由方案下要改前端代码。我用的标准RBAC模型五张表sys_user、sys_role、sys_user_role、sys_menu、sys_role_menu。登录后后端根据用户角色查菜单树返回给前端前端动态生成路由后端再用SpringSecurity的注解做接口级拦截。实际上手时有个坑要提前说动态路由生成不能只刷新一次菜单要处理用户切换角色后的路由重建。我当时的做法是用户身份发生变化时调用后端的refreshUserMenu接口重新拉菜单然后前端把旧路由表全部清空、用router.addRoute重新注册。这个细节很多教程不会提但答辩时如果有评委问到“不同角色登录后菜单怎么来”你把这个流程讲出来对方会觉得你确实做过。3. 后端核心功能实现从公告发布到评标打分3.1 SpringBoot项目结构别乱建分包方式直接影响后续开发SpringBoot项目的包结构我见过很多毕设代码把所有Controller塞一个包、所有Service塞一个包几百个类堆在一起写到后面自己都找不到文件在哪。我的分包方式是按业务域划分而不是按技术层划分com.example.tender ├── controller │ ├── project招标项目相关接口 │ ├── bid投标相关接口 │ ├── review评标相关接口 │ └── auth登录注册相关接口 ├── service │ ├── project │ ├── bid │ ├── review │ └── auth ├── mapper ├── entity ├── dto ├── config └── common统一返回结果、异常处理、工具类这样做的好处很直接当你要改投标模块的功能时只需要进bid相关的文件夹影响范围一目了然。如果你是单人或小团队开发毕设基本都是这种分包方式比层层分离更能提升效率。3.2 用户认证JWT还是Session毕设中登录认证用JWT还是Session是个经常被纠结的问题。我的建议很明确用JWT但不要自己手写直接用现成依赖。理由有三点SpringSecurity整合JWT的资料多遇到问题随手能搜到。招投标系统本身就有“登录状态保持”“权限校验”的需求JWT天然无状态分布式部署方便。答辩时提到“无状态认证”对方很难挑出大问题。JWT的接入核心是三个过滤器链JwtAuthenticationFilter负责拦截请求并解析TokenRestAuthenticationEntryPoint处理未认证的请求返回401RestAccessDeniedHandler处理权限不足的请求返回403。这里踩过一个坑自定义过滤器要放在UsernamePasswordAuthenticationFilter之前Token解析和用户构造要在filter中一次完成不然每次请求都会多一次查询数据库的过程。3.3 任务调度开标时间到了系统是怎么自动解锁的招投标系统里有一个看起来很小、但一旦做成手动就很掉价的功能——开标时间自动解锁投标文件。很多同学的做法是做一个“开标”按钮让管理员手动点击然后更新状态。但真正的业务场景里开标时间到了系统应该自动执行解锁动作这才能体现出“系统化”。我用的是SpringBoot的Scheduled定时任务每分钟跑一次扫描所有status2且开标时间当前时间的投标记录批量执行解密和状态更新。Scheduled(cron 0 0/1 * * * ?) public void autoOpenBid() { ListBidRecord records bidRecordMapper.findNeedOpenRecords(); for (BidRecord record : records) { // 用密钥解密文件更新状态为已开标 String decryptedPath fileService.decryptFile(record.getBidDocumentPath(), record.getDecryptKey()); record.setStatus(3); record.setDecryptTime(new Date()); bidRecordMapper.updateById(record); } }这段代码看起来简单但隐藏了一个大坑定时任务默认单线程执行如果某次扫描处理的记录特别多下一次定时任务的触发就会被阻塞。我当时为了解决这个问题在任务方法上加了Async注解并配置了线程池让批量解密操作异步执行。还有一个更隐蔽的问题定时任务执行时如果项目刚部署Spring容器还没完全初始化任务可能会在依赖还没注入时执行导致空指针。我加了一个ApplicationReadyEvent监听器等容器启动完成才允许定时任务开始调度。3.4 评标打分模块用了策略模式之后好改了很多评标模块是招投标系统的核心业务之一也是最容易写出烂代码的地方。常见做法是在Controller里写一大坨if-else判断当前评审项目是“综合评分法”还是“最低价法”然后分别计算分数。我用策略模式重构了这个逻辑定义一个ReviewStrategy接口两种评标方法各自实现一个策略类再用Spring的依赖注入把策略集合注入到一个Context类里根据项目配置的评标方式自动选择对应策略。public interface ReviewStrategy { ReviewResult calculate(ListReviewScore scores, BidRecord record); } Component(compositeStrategy) public class CompositeScoreStrategy implements ReviewStrategy { Override public ReviewResult calculate(ListReviewScore scores, BidRecord record) { // 按规则权重计算综合得分 } } Component(lowestPriceStrategy) public class LowestPriceStrategy implements ReviewStrategy { Override public ReviewResult calculate(ListReviewScore scores, BidRecord record) { // 最低价者得高分 } }这样做的好处是以后要加一种“性价比法”只需要新写一个类不用改动已有的代码符合开闭原则。答辩时如果评委问“你的系统有没有进行可扩展性设计”你把策略模式往这一放然后举评标规则变化的例子基本就稳了。3.5 文件上传的边界问题投标文件上传这个功能表面上很简单——一个MultipartFile接收存到本地目录就完了。但招投标场景有个特殊点同一个时间段内可能有几十家企业同时上传几十MB的标书如果都用同步方式处理系统响应时间会卡到令人崩溃。我的处理方式是上传接口同步做两件事——校验文件格式和后缀名只允许PDF、Word等指定格式然后立即返回成功真正的落盘和加密操作放到异步任务里执行。为了不让用户感觉“传了但状态没变”我在前端上传后轮询查看文件的加密状态状态从“上传中”变成“已加密”才算真正成功。另外一个容易忽略的点是文件存储目录的命名规则。如果所有文件都扔到同一个uploads/目录下文件名用UUID虽然技术上没问题但排错时非常难受。我当时的做法是uploads/{projectId}/{companyId}/{timestamp}.pdf按项目和时间归档。这样哪家公司传的什么文件一眼就能看出来。4. 前端设计的几个核心思路与实现细节4.1 Vue3 Element Plus 的页面规划前端的页面规划我按角色来分。登录后先判断当前用户角色动态生成菜单和路由。主要的页面有公开页面招标公告列表、招标公告详情、投标文件上传、登录注册。招标方后台项目管理、公告管理、项目评审进度跟踪、定标操作。投标方后台我的报名、我的投标、标书上传、保证金缴纳记录。专家后台待评标项目列表、评分表填写、评标历史。管理员后台用户管理、角色管理、日志管理、系统监控。页面布局上我用的是左侧菜单右侧内容区的形式。这个东西虽然看起来老套但胜在清晰用户不需要学习成本而且每一页面的操作逻辑都直接对应一个后端接口方便联调。4.2 路由守卫和token的处理前端路由守卫是我认为整个前端代码里最重要的部分。要同时处理两件事未登录的用户跳转登录页、已登录但角色不对的用户拦截到403页面。router.beforeEach((to, from, next) { const token getToken(); const userRole getUserRole(); if (to.path /login) { token ? next(/) : next(); } else { if (!token) { next(/login?redirect${to.path}); } else { const routes generateRoutes(userRole); if (routes.includes(to.path)) { next(); } else { next(/403); } } } });这里有个细节值得单独提一下刷新页面后Vuex里的用户信息和动态路由会全部丢失。如果不做处理用户一刷新就直接掉到403。我的解决方法是在App.vue的created钩子里重新拉取一次用户信息和菜单权限存到Vuex后再放行路由。第一次做动态路由的人十有八九会踩这个坑提前写出来可以帮你省一晚上的排查时间。4.3 投标文件上传、进度条和加密状态的联调投标文件上传页是我花时间最多的地方。因为后端的解密状态要通过轮询才能反映到前端所以我把上传流程拆成了几个状态待上传 → 上传中 → 已加密 → 开标后可查看。前端用el-upload组件自定义http-request方法通过axios上传并监听进度事件把进度条显示出来。还有一个是我自己加的需求投标截止时间自动关闭上传入口。前端在后端返回的项目详情里带上截止时间用一个定时器在页面内检查当前时间是否超过截止时间一旦超过就把上传按钮禁用并提示“投标时间已截止”。这个功能部署时还能防日均十来次的手动切换系统时间绕过检查。4.4 开标一览表怎么做开标一览表说白了就是拆封完各家报价后把投标人名称、报价金额、交保证金情况等列成一张表。如果直接渲染HTML表格数据一多就卡顿而且导出Excel也不方便。我选择了在前端用表格渲染导出Excel的活交给后端做——后端用EasyExcel生成文件流前端通过window.open或者a标签直接下载。5. 部署流程与常见环境问题5.1 本地部署这套系统需要准备什么很多同学拿到一套源码后最大的障碍根本不是看代码而是跑不起来。我把部署需要的环境列一个清单照着准备就行组件版本建议备注JDK8或以上SpringBoot 2.x尽量别用JDK 17兼容性问题多MySQL5.7或8.0字符集建议utf8mb4Redis5.0以上用于登录令牌缓存Node14或16Vue CLI项目用14比较稳Maven3.6用来拉后端依赖有一个非常常见的坑我必须单独拿出来说前端静态资源打包后如果想用Nginx部署需要在Nginx配置里设置代理把/api开头的请求转发到后端服务。很多同学不配这段前端页面能打开但一登录就报404怎么排查都找不到问题。5.2 数据库初始化脚本的两个说明数据库脚本是我整个项目里最认真的部分不只是建表语句我把测试数据也准备了一些。比如两个完整的招标项目、五家公司的备案信息、若干条报名和投标记录、三个专家用户都在SQL里预置好了。为什么要做这个因为拿这套源码做毕设演示时如果演示数据是空的每次都要手动造数据很浪费时间。预置数据后登录系统直接就能看到有项目、有投标记录、有评标进度演示效果非常直观。我在数据库脚本中还预置了一个定时任务状态为“已开标”的项目这样演示时直接进入评标页面就能打分不需要等到定时任务跑完才看到效果。这个细节你可以理解为“演示优化”也是我给这套源码加的一层保鲜功能——不会出现演示到一半发现数据还没就绪的情况。注意SQL脚本里包含初始账号信息管理员账号、招标方账号、投标方账号、专家账号是分开的并且密码是加密后的密文。拿到脚本后记得先看README里的说明文件不要直接拿初始密码明文去数据库里查用户查出来的可能是密文。5.3 前后端联调时最容易遇到的三个问题联调阶段我记录了几个真实遇到的坑按出现频率排序跨域问题。前端在8080端口跑后端在8081端口跑axios请求直接发过去会被浏览器拦截。解决方法是后端写一个全局CORS配置允许前端地址来源。如果用Nginx代理就省去这块配置了。Date类型时区问题。前端传时间给后端如果JSON序列化格式不对会出现时间偏差8小时的现象。我在SpringBoot的application.yml里全局配置了spring.jackson.date-formatyyyy-MM-dd HH:mm:ss和time-zoneGMT8前后端约定统一用字符串传输时间基本可以规避。大字段导致JSON解析失败。有次投标文件路径字段里包含了反斜杠前端JSON.parse直接报错。后来把所有文件路径统一改用正斜杠存储问题就解决了。低级问题但踩过一次就记住了。6. 毕设答辩中的亮点准备与文档撰写思路6.1 准备好“为什么”的问题比背代码更有效毕设答辩评委最喜欢问的问题其实不是“代码是怎么写的”而是**“为什么这么做”**。我准备自己的答辩材料时把所有模块都过了一遍“为什么”为什么招投标文件上传后需要加密——为了保证在开标前各家投标人的报价和标书内容不被泄露防止围标串标。为什么开标要用定时任务而不是人工点击——因为招投标流程对时间有很强的法律约束力系统自动执行才能保证公开公平公正。为什么权限模型用RBAC——因为角色多、权限点多、变更频繁RBAC灵活、可维护。为什么投标状态要设计多个状态流转——因为整个招投标过程是有序的、不可跳跃的状态机可以防止越权操作和流程混乱。这些问题准备得越充分答辩越从容。核心原则是把自己当成一个真正的产品经理从业务价值角度解释每个技术选择而不是单纯背代码。6.2 论文结构怎么安排系统开发的毕设论文我建议按这个结构安排绪论背景与意义、国内外研究现状、主要工作相关技术介绍SpringBoot、Vue、MySQL、Redis等系统分析可行性分析、需求分析、用例建模系统设计架构设计、功能设计、数据库设计系统实现每个功能模块的界面和核心代码展示系统测试功能测试用例、性能测试结果总结与展望写论文时有两点经验可以直接用一是数据库设计章节不要只贴表结构截图要说明每张表为什么存在、表之间的关联关系二是测试章节一定要有真实测试记录的截图和用例表格不能只写“测试通过”四个字。我这里还整理了一套给论文更实用的写法每个功能模块配一条“该模块涉及的关键问题与解决方案”比如评标模块下写“多评标方法统一问题”投标模块写“文件安全存储与定时解密问题”。这三五行的小节花不了多少字数却能极大提升论文的原创性和专业感。6.3 演示环节的流程设计最后给一个演示环节的实用建议不要从登录页开始点直接进入招标项目列表。原因很简单演示时间有限评委想看到的是核心功能不是登录注册这种基础操作。我当时的演示流程是进入招标项目列表选择一个测试项目展示详情。切换到投标方账号展示企业信息和报名记录。展示一个即将开标的项目演示开标一览表的生成。切换到专家账号给一个项目打分展示评分汇总。展示中标公告生成。这个流程走一遍大概三分钟但是把核心业务全部覆盖了。建议你按这个思路提前用演示数据准备一条顺畅的“操作路线”不要临场想下一步点哪里。7. 这套源码能改成什么其他题目拿到这套源码后有人可能会问如果我论文题目不是“在线招投标系统”能不能改成别的当然可以而且改动成本不高。改动最简单的是往两个方向走一个是政府采购管理系统把角色改成采购人、供应商、专家招标项目字段微调即可另一个是企业竞标评审系统去掉一些招投标特有的概念如开标解密、保证金保留项目发布、材料提交、专家评分、结果公示前端页面换套文案就完工了。改动稍大一些的方向是把业务领域换到采购供应链领域增加供应商入库、绩效评价、订单分配等功能。这种情况下核心的RBAC权限、文件上传、评分计算、公告管理、状态机都不需要推翻重写只需要修改实体类、数据库脚本和前端路由。另外如果想更有亮点一些可以加入ECharts的可视化页面比如展示项目成交金额的趋势图、各评审专家平均分对比图。这类页面实现成本不高但在项目的完成度表现上能加不少分。8. 最后的最后说点实际经验整套系统从定题、设计、编码、测试到写论文、做幻灯前后花了大几周到一两个月。这个时间主要不是耗在代码上而是耗在反复琢磨业务逻辑是否严谨、数据流是否通顺上面。招投标系统的魅力也恰恰就在这它是少数几个不用虚构一个复杂场景业务本身就是一套完整流程的毕设项目。如果你准备选择这个题目或者正在做我建议三件事尽早启动第一先把数据库建好把预置数据准备好不要等到前端页面做完再来补第二把定时任务、权限、文件上传加密这三个点做扎实这是答辩时最能深入提问的地方第三部署文档一定要自己亲手照着跑一遍不要拿网上的模板直接抄跑通一遍你才知道数据库、Redis、Nginx三者配合起来有哪些坑。做毕设不是写生产环境代码不用追求面面俱到但要把关键路径走通、走扎实。这个系统做完之后我对SpringBoot的事务管理、SpringSecurity的过滤器链、EasyExcel的导入导出、以及Maven的多环境打包都有了非常具体的认知——这些是课堂上永远不会教你的东西。祝你的毕设也顺利通关。
延伸阅读

更多相关文章

2026/10/18 22:04:12

settings.json 里的六个 Slot 与四个视图怎么配

settings.json 里的六个 Slot 与四个视图怎么配 Martty 的配置面比命令表更易记混:一部分在 $MARTTY_HOME/settings.json,一部分只能通过 TUI 视图切换,还有启动参数。本文只讲「写在哪里、默认什么、何时生效」。版本口径 martty0.3.3、nod…

2026/10/18 21:59:12

大语言模型训练实战:从损失函数到DDP与混合精度全流程

上一篇我们刚把Decoder-only的骨架完整跑通,embedding、多头注意力、FFN、LayerNorm 和最后输出头的代码都已经躺在本地的仓库里。但说实话,模型结构这部分只是“看起来完整”,真正让参数变得有价值的,是接下来要讲的这一整套训练…

2026/10/18 21:59:12

QT实时频谱与瀑布图开发:信号流、绘图节拍与内存管理

简介:本资源是一套基于Qt与QCustomPlot库开发的实时信号可视化解决方案,面向嵌入式、通信及信号处理方向的Qt中级开发者,解决频谱分析与动态时频图展示的技术实现难题。压缩包共116个文件,含32个头文件(h/hpp&#xff…

2026/10/18 23:04:48

告别编辑器绑定:编码Agent的本地优先工作台实战

不用看热搜也知道,最近圈子里聊编码Agent的人分成两派:一派还在编辑器里折腾补全和对话,另一派已经把Agent当独立进程扔在终端里跑,让它自己读仓库、改文件、跑测试、迭代提交。我属于后者,而且越用越确认一个判断——…

2026/10/18 23:04:48

Graph-Engineering-第12章第60节-ADK与Vertex-AI集成-企业级部署实战

ADK 2.0与Vertex AI集成:企业级部署实战 本地跑通只是及格线——Agent Engine托管、Cloud Logging结构化日志、Monitoring告警、BigQuery成本追踪,一套企业级部署方案从零到一 本文导航 为什么"本地能跑"和"生产能活"是两回事企业级…

2026/10/18 23:04:48

STM32F407+FreeRTOS存储方案:LittleFS+SUFD+EasyLogger+RTT实战

简介:本资源面向STM32嵌入式开发者与FreeRTOS学习者,聚焦在STM32F407平台上集成LittleFS文件系统、SFUD串行Flash驱动、EasyLogger日志组件与Segger RTT调试输出,解决片外25Q64 Flash上可靠存储与实时日志调试的问题。压缩包共1515个文件&…

2026/10/18 23:04:48

SSM酒店客房预定系统毕业设计:环境配置到跑通全流程避坑指南

简介:面向Java毕业设计或课程设计场景的酒店客房预定管理系统完整项目包,基于SSM框架与JSP技术实现,按管理员、用户两类角色划分权限。管理员可完成客房类型与房态管理、预定单处理、开房记录登记、退房结账及系统公告维护;用户端…

2026/10/18 22:59:47

耳切法三角化实战:从无序点集到三角形索引的GIS处理

简介:一套基于改进耳切法(EarCut)的多边形三角化工具库源码包,面向GIS数据处理与桌面或Web图形开发场景中需要输入无序顶点、输出三角形索引的开发者。算法采用z阶曲线散列优化,能够处理带孔洞、扭曲、退化与自相交等复…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑