简介:这份微信小程序4s店管理系统源码数据库.zip,是面向毕业设计及微信小程序学习者的完整项目包。系统覆盖客户、车辆、销售、售后、库存等4S店核心业务模块,前端采用WXML、WXSS、JavaScript编写,后端包含Java、JSP、ASP、PHP等多种实现文件,同时提供SQL数据库文件与API接口示例,可帮助理解前后端联调与角色权限控制。压缩包共698个文件,约73.16MB,主要类型包括js、jar、java、class、xml、html、json、wxss、wxml、png、gif等,其中gif演示图便于查看功能流程,jar与class为后端依赖及编译产物,结构化目录便于按模块学习。数据库部分涉及客户表、车辆表、订单表、服务记录表等设计,配合RESTful风格接口可以实现登录验证、数据请求与角色权限配置。目前已有130人浏览学习,适合希望从零搭建微信小程序管理系统、完成毕业设计答辩或提升综合开发能力的开发者。通过该项目可以完整走通数据库设计、接口开发、后台管理和小程序端交互的全链路,获得可直接运行的参考实现。
1. 微信小程序 4S 店管理系统源码包:毕业设计最该先搞懂调用链
答辩前一周拿到这套微信小程序 4S 店管理系统源码数据库.zip,十个有八个第一反应是先把模拟器跑起来,截图扔进论文,然后祈祷别被问到技术细节。这个思路在评审现场几乎必翻车——老师问的往往不是「界面好不好看」,而是「预约接口怎么防重复提交」「库存预警的阈值写在哪」「客户表为什么这么拆」。这套资源的价值恰好在这里:小程序前端、后端接口、数据库三件套齐全,客户管理、车型管理、销售订单、售后预约、库存预警五个模块都有对应的页面和表结构,适合拿来做毕业设计二开,也适合快速搭一个 4S 店数字化业务的演示 Demo。
但拆包之后你会发现文件有点杂:.asp 脚本、.ashx 处理程序、Java 的 .class 工具类混在一起,第一次见的人很容易懵。这篇笔记先把文件骨架理一遍,再把登录、车型列表、预约提交三条主链路逐个讲透,最后给出部署和答辩演示的实操建议。适合正在做毕业设计、需要把项目讲出设计深度的同学,也适合想快速复用业务 Demo、不想从零写前后端的开发者。
2. 先拆包看骨架:文件角色、目录结构与一条请求的完整链路
压缩包到手,第一件事不是双击运行,而是把所有文件摊开看一遍。这套包的根目录里躺着十几个看起来毫不相关的文件,.asp 和 .ashx 各有一套上传入口,Java 工具类以 .class 编译产物的形式出现。按技术类型分个类,结构一下就清楚了。
2.1 文件角色划分:两套上传入口、一个上传类和一个 JSON 辅助类
先从文件名能一眼认出的文件开始:
| 文件 | 技术类型 | 在系统里的角色 |
|---|---|---|
| upload_json.asp / upload_json.ashx | ASP / .NET | 图片与文件上传的统一入口,上传成功返回 JSON 格式的路径 |
| file_manager_json.asp / file_manager_json.ashx | ASP / .NET | 文件管理,列出已上传文件并支持删除 |
| UpLoad_Class.asp | 经典 ASP | 封装了表单二进制流解析的上传类 |
| JSON_2.0.4.asp | 经典 ASP | JSON 编码与解码辅助类 |
| demo.asp / demo.aspx | ASP / .NET | 上传组件的前端演示页 |
| DateUtil.class / StringUtil.class | Java 编译产物 | 时间格式化与字符串处理工具类 |
这里最显眼的是 upload 和 file_manager 各出现了两次,一边是 .asp,一边是 .ashx。说明打包者把同一套上传逻辑在 ASP 和 .NET 两种运行环境下各实现了一遍。部署时按服务器环境二选一就行,两个都配会出现功能重复,而且文件路径可能冲突。demo.asp 和 demo.aspx 是同一份演示页的两种版本,作用只是告诉你这个上传组件怎么调用,小程序端真正走的是 upload_json.asp 这个接口。
DateUtil.class 和 StringUtil.class 是 Java 编译后的字节码,包里没附源码。在 Java 后端里能直接调用,但一旦换 JDK 版本或者想改方法逻辑,就会卡住。常见做法是先用 javap 反编译看方法签名,再按签名补一份同名源码重新编译,保证编译环境一致。这个后面避坑章节会再展开。
2.2 小程序端目录与后端接口的一一对应关系
拿到包后先把小程序工程结构梳理出来。常见的小程序目录结构是这样的:
miniprogram/ ├─ app.js # 全局逻辑,存放 openid 与请求封装 ├─ app.json # 页面注册与窗口配置 ├─ app.wxss # 全局样式 ├─ pages/ │ ├─ login/ # 微信登录 │ ├─ index/ # 首页:车型展示与库存看板 │ ├─ car/ # 车辆列表与详情 │ ├─ appointment/ # 售后预约(保养/维修/保险) │ ├─ customer/ # 客户信息与标签管理 │ └─ mine/ # 个人中心与角色切换 ├─ components/ # 公用组件,如车型卡片 └─ utils/ └─ request.js # wx.request 的 Promise 封装如果包里的页面命名和上面不完全一致也没关系,把每个页面里 wx.request 的 url 抠出来,就能反推出后端接口清单。我一般会先建一张映射表,改接口的时候只动一处:
| 小程序页面 | 后端接口(常见约定) | 作用 |
|---|---|---|
| 登录页 | POST /api/user_login.asp | 用 code 换 openid / token |
| 首页 | GET /api/car/list.asp | 车型列表与库存数 |
| 车辆详情 | GET /api/car/detail.asp?vin=xxx | 单台车配置与价格 |
| 预约页 | POST /api/appointment/create.asp | 写入售后预约单 |
| 客户页 | GET /api/customer/list.asp | 客户分页列表 |
| 订单页 | GET /api/order/statistics.asp | 销售报表 |
这套接口路径是常见的 RESTful 风格约定,资源包内部的文件名不一定完全一致,但作用等价。重点是把「页面 → 接口 → 数据表」这条线连起来,后面所有排查都沿着这条线走。
2.3 一次请求从按钮到数据库的完整链路
用户在小程序里点「提交预约」,到数据落库,中间经过四步:页面 JS 里 wx.request 发起 POST 请求;后端脚本接收表单参数;脚本用 ADODB 连接数据库执行 INSERT;再用 JSON_2.0.4.asp 把结果序列化成 JSON 返回给小程序。微信小程序的 wx.request 只支持 HTTPS 域名,开发期可以暂时用「不校验合法域名」绕过,但真机预览和上线必须配白名单。
请求封装我一般放在 utils/request.js 里统一处理:
// utils/request.js const BASE_URL = 'https://api.example.com'; // 部署后换成你的域名 function request(path, method = 'GET', data = {}) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + path, method, data, header: { 'Content-Type': 'application/x-www-form-urlencoded' }, success: (res) => { if (res.data.code === 0) { resolve(res.data.data); } else { reject(new Error(res.data.msg || 'request failed')); } }, fail: reject }); }); } module.exports = { request, BASE_URL };这段封装做了三件事:统一域名前缀、统一错误处理、把回调改成 Promise。页面里只需要request('/api/appointment/create.asp', 'POST', {...}),可读性好很多。参数说明:header 的 Content-Type 一定要用application/x-www-form-urlencoded,因为后端 ASP 脚本是用Request.Form读参数的;如果改成application/json,ASP 端会读不到字段,接口直接返回参数缺失。这一点是前后端联调最常见的坑,先记住,后面避坑章节还会提。
3. 从源码到跑通:登录、车型列表与预约提交的三段改法
目录理顺之后,下一步就是把三个最常被问到的功能改到能跑:登录、车型列表、预约提交。这三个环节覆盖了 wx.login、列表渲染、表单提交三类最基本的微信小程序用法,也正好是毕业设计答辩里最容易被打断的地方。
3.1 登录与鉴权:wx.login 换出来的 openid 不能当密码用
登录页的逻辑基本都是这个套路:wx.login 拿临时 code,后端用 code 换 openid,再返回给小程序端存储。
// pages/login/login.js const { request } = require('../../utils/request'); Page({ data: { loading: false }, onLoad() { this.login(); }, login() { this.setData({ loading: true }); wx.login({ success: async (res) => { try { const session = await request('/api/user_login.asp', 'POST', { code: res.code }); wx.setStorageSync('openid', session.openid); wx.setStorageSync('token', session.token); wx.switchTab({ url: '/pages/index/index' }); } catch (e) { wx.showToast({ title: '登录失败', icon: 'none' }); } }, complete: () => this.setData({ loading: false }) }); } });代码逻辑说明:wx.login 返回的 code 有效期 5 分钟且只能用一次,后端拿 code 去微信接口换 openid。拿到 openid 后,后端应该生成一个自定义 token 一并返回,小程序端把 token 存起来,后续请求都带 token。openid 只是用户唯一标识,不是会话凭证,把它直接当密码用,接口被伪造的风险很高。真实项目里二次请求都应验 token,而不是每回都查 openid。
参数说明:个人开发环境常常没有正规服务器,可以在后端先 mock 一个固定 openid 返回,把登录流程跑通,但论文里要写明线上会替换成真实的微信接口调用。另外wx.switchTab只能跳到 app.json 里注册为 tabBar 的页面,如果 index 没配 tabBar,这里要改成wx.redirectTo。
3.2 车型列表与详情页:WXML 渲染和数据字段约定
车型列表是首页的核心,WXML 里用 wx:for 渲染数组,每个卡片展示品牌、型号、价格和库存状态:
<!-- pages/index/index.wxml --> <view class="car-card" wx:for="{{carList}}" wx:key="id"> <image src="{{item.cover}}" mode="aspectFill" lazy-load="{{true}}" /> <view class="car-info"> <text class="car-name">{{item.brand}} {{item.series}}</text> <text class="car-price">指导价 ¥{{item.priceText}}</text> <text class="car-stock {{item.stock < item.warnStock ? 'warn' : ''}}"> 库存 {{item.stock}} 台 </text> </view> </view>对应的 JS 逻辑:
// pages/index/index.js const { request } = require('../../utils/request'); Page({ data: { carList: [], loading: true }, onLoad() { this.loadCarList(); }, async loadCarList() { try { const list = await request('/api/car/list.asp', 'GET'); this.setData({ carList: list.map(item => ({ ...item, // 后端价格以“分”为单位存储,前端展示时转成元 priceText: (item.price / 100).toFixed(2) })), loading: false }); } catch (e) { wx.showToast({ title: e.message, icon: 'none' }); } } });这段代码的三个细节值得注意。第一,wx:key用数据里的 id 而不是 index,列表增删时不会渲染错位。第二,价格字段在后端以「分」为单位存整数,前端展示时再除以 100,避免浮点误差——这是从账单系统沿袭下来的习惯,4S 店的车价动辄几十万,精确到分很重要。第三,库存预警的样式通过三元表达式绑定了warn这个 class,当stock小于warnStock时卡片变黄,至于warnStock存在哪,第 4 章会讲清楚。
3.3 预约提交与按钮节流:前端校验只是降低误触概率
预约页是整个系统里业务逻辑最重的一个页面,表单要提交 VIN 码、服务类型和预约时间:
// pages/appointment/appointment.js Page({ data: { form: { vin: '', serviceType: '', time: '' }, submitting: false }, submitAppointment() { const { vin, serviceType, time } = this.data.form; if (!vin || !serviceType || !time) { wx.showToast({ title: '请完整填写预约信息', icon: 'none' }); return; } // 按钮节流:重复点击时直接丢弃,避免重复提交 if (this.submitting) return; this.submitting = true; wx.request({ url: 'https://api.example.com/api/appointment/create.asp', method: 'POST', data: { openid: wx.getStorageSync('openid'), vin, serviceType, appointmentTime: time }, success: (res) => { if (res.data.code === 0) { wx.redirectTo({ url: '/pages/order/detail?id=' + res.data.data.id }); } else { wx.showToast({ title: res.data.msg, icon: 'none' }); } }, complete: () => { this.submitting = false; } }); } });这里的校验分了三层:本地非空校验只挡明显漏填;submitting节流标志挡双击误触;真正防止重复数据要靠后端和数据库的唯一约束。前端节流只是降低概率的 UX 手段,不是安全手段,弱网环境下小程序可能自动重发请求,这层标志根本拦不住。后端必须做幂等处理:同一个用户、同一台车、同一个预约时间,数据库里只能有一条记录。具体做法见下章的唯一索引。成功后用wx.redirectTo跳详情页,不要用wx.navigateTo,否则每次提交都会往页面栈里压一层,返回时要点很多次。
4. 数据库与接口设计:三范式、索引与 RESTful 接口约定
代码跑起来之后,评审老师的第二个问题通常落在「数据库为什么这么设计」。这套系统的核心数据域是四张表:客户、车辆、销售订单、服务记录。表之间用外键连接,不冗余重复字段,这就是第三范式的基本要求。但范式不是万能的,查询性能要靠索引撑。
4.1 四张核心表的建表逻辑与范式边界
按常见设计,四张表的建表语句可以落到这样的结构:
CREATE TABLE customer ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, phone VARCHAR(20) NOT NULL, wechat VARCHAR(50), demand TEXT, -- 购车需求描述 tag VARCHAR(100), -- 客户分类标签,如:高意向 / 置换 created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE vehicle ( id INT AUTO_INCREMENT PRIMARY KEY, brand VARCHAR(30) NOT NULL, series VARCHAR(50) NOT NULL, config VARCHAR(100), -- 配置版本:豪华型 / 旗舰型 stock INT DEFAULT 0, warn_stock INT DEFAULT 5, -- 库存预警阈值,可配 price DECIMAL(10,2) ); CREATE TABLE sales_order ( id INT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) UNIQUE, customer_id INT NOT NULL, vehicle_id INT NOT NULL, status TINYINT DEFAULT 0, -- 0 待跟进 1 已签约 2 已交付 3 已取消 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_order_customer FOREIGN KEY (customer_id) REFERENCES customer(id), CONSTRAINT fk_order_vehicle FOREIGN KEY (vehicle_id) REFERENCES vehicle(id) ); CREATE TABLE service_record ( id INT AUTO_INCREMENT PRIMARY KEY, customer_id INT NOT NULL, vehicle_id INT NOT NULL, service_type VARCHAR(20), -- 保养 / 维修 / 保险 / 事故 appointment_time DATETIME, status TINYINT DEFAULT 0, FOREIGN KEY (customer_id) REFERENCES customer(id) );拆表的逻辑要能讲清楚:sales_order 只存 customer_id 和 vehicle_id 两个外键,不冗余客户姓名和车型名称。这样客户改手机号、车辆改价格,历史订单不受影响,数据一致性由外键约束保证,而不是靠代码里同步更新。service_record 和 sales_order 必须分开,因为售后服务的维度是「车 + 时间 + 服务类型」,销售订单的维度是「客户 + 车 + 价格」,混在一张表里字段会大量为空。
warn_stock 放在 vehicle 表里不算违反第三范式,它是车的实体属性,表示「这台车库存低于多少台要预警」,每个车型的阈值可以不同。如果把它写死在代码里,4S 店想调整阈值还得找开发者改代码,这就没做到数据驱动。
4.2 预约接口的完整实现:从请求参数到返回 JSON
预约接口是整条链路的核心。先约定接口契约:
| 项目 | 约定 |
|---|---|
| 端点 | POST /api/appointment/create.asp |
| 请求参数 | openid、vin、serviceType、appointmentTime |
| 成功返回 | {"code":0,"msg":"ok","data":{"id":1024}} |
| 失败返回 | 1001 参数缺失 / 1002 车辆不存在 / 1003 该时段已满 |
后端实现常见做法是直接用包里的 JSON_2.0.4.asp 做序列化,核心逻辑如下:
<% Response.ContentType = "application/json; charset=utf-8" Response.CodePage = 65001 Dim openid, vin, serviceType, appTime openid = Trim(Request.Form("openid")) vin = Trim(Request.Form("vin")) serviceType = Trim(Request.Form("serviceType")) appTime = Trim(Request.Form("appointmentTime")) If openid = "" Or vin = "" Then Response.Write "{""code"":1001,""msg"":""参数缺失""}" Response.End End If ' 连接数据库,先查车辆是否存在 Dim conn, rs, sql Set conn = Server.CreateObject("ADODB.Connection") conn.Open "Provider=SQLOLEDB;Data Source=.;Initial Catalog=car4s;User ID=sa;Password=******" sql = "SELECT id FROM vehicle WHERE vin = '" & vin & "'" Set rs = conn.Execute(sql) If rs.EOF Then Response.Write "{""code"":1002,""msg"":""车辆不存在""}" Response.End End If ' 插入服务记录并返回新记录 ID Dim newId sql = "INSERT INTO service_record (customer_id, vehicle_id, service_type, appointment_time) VALUES (" & _ GetCustomerId(openid) & ", " & rs("id") & ", '" & serviceType & "', '" & appTime & "')" conn.Execute sql newId = conn.Execute("SELECT @@IDENTITY")(0) Response.Write "{""code"":0,""msg"":""ok"",""data"":{""id"":" & newId & "}}" %>逻辑说明:先做参数非空校验,再做业务校验(车辆是否存在),最后才写库。每步返回不同的错误码,小程序端拿到 code 后直接弹对应的 toast。这里故意用了字符串拼接 SQL,只是为了让流程直观;真实部署必须换成参数化命令或存储过程,否则 SQL 注入风险极高,尤其 vin 是用户在页面上手输的,攻击面很大。
参数说明:取新记录 ID 用了 @@IDENTITY,这是经典 ASP 里常见做法。如果表上有触发器,@@IDENTITY 可能返回触发器产生的 ID,生产环境建议改用 SCOPE_IDENTITY()。Response.ContentType 里带 charset=utf-8,是为了配合 CodePage 65001,防止返回的中文在真机上变成乱码。
4.3 索引、字符集与角色权限:三个影响二开深度的细节
索引设计直接决定这套代码在数据量上来之后还能不能跑。外键列 customer_id、vehicle_id 一定要建普通索引,因为销售报表和售后列表会频繁按客户或车辆维度聚合查询。order_no 要建唯一索引,保证订单号不重复。service_record 要建(vehicle_id, appointment_time, service_type)联合唯一索引,这是防重复预约的数据库层兜底。对 status 这类只有几个取值的字段不要建单列索引,区分度太低,查询优化器大概率不走。
字符集问题容易被忽略。数据库、数据表、ASP 页面三处都必须统一成 UTF-8。建库时用 utf8mb4,连接串里带上 charset 参数,ASP 文件头部加Response.CodePage = 65001。三处但凡有一处不一致,小程序端看到的中文就是乱码。
角色权限要按 admin、sales、customer 三层设计。小程序端用户只对应 customer 角色,管理端的订单审核、客户编辑、库存调整接口必须独立部署,不能和小程序端共用同一个接口全集。常见做法是两个登录入口,共用数据库但接口分开,服务端对每个接口做角色校验。如果评审老师问权限控制,这套口径能答得比较完整。
5. 避坑清单:部署这套源码最容易翻车的五个地方
这套包我前后跑过好几轮,有些坑是文件本身带来的,有些是微信小程序平台规则带来的。挑五个最常见的记录如下,每条按现象、原因、解决的顺序写,照着排查能省很多时间。
5.1 真机请求全部失败:域名白名单没配
现象:开发者工具里一切正常,一上真机预览,所有 wx.request 全部 fail,console 里报url not in domain list。
原因:小程序正式环境要求请求域名必须在后台配置为 request 合法域名,并且域名要备案、支持 HTTPS。开发者工具里勾选的「不校验合法域名」只对本地模拟器生效,真机不认。
解决:开发期在开发者工具里勾「不校验合法域名」能跑通模拟器,但要真机预览,需要在项目配置里打开「开发环境不校验合法域名」,或者把预览二维码对应的调试开关打开。上线前把接口域名加到后台白名单,注意 http 和 https 不能混用,url 必须和白名单完全一致,不能一个带 www 一个不带。
5.2 图片上传报 500:目录权限和返回格式同时出问题
现象:小程序端选完图片,upload 接口返回 500,控制台里看到后端返回的是一大段 HTML,而不是 JSON。
原因:upload 目录没有写权限,IIS 默认给的是只读权限,文件写不进去直接抛异常;后端抛异常时返回的是 HTML 错误页,小程序端按 JSON 解析自然失败。
解决:先给 upload 目录加上 IIS 的写权限,账户一般用 IUSR;然后用浏览器直接访问 upload_json.asp,确认它能正常输出 JSON,再回小程序端调。小程序端上传图片要用 wx.uploadFile,不要用 wx.request 手动拼 multipart 数据,否则文件名和二进制流的格式会出问题。
5.3 编译产物撑场子:DateUtil.class 一换环境就翻车
现象:Java 后端在本地跑得好好的,部署到服务器上启动报UnsupportedClassVersionError。
原因:DateUtil.class 和 StringUtil.class 是编译后的字节码,编译时用的 JDK 版本比服务器高,低版本 JVM 读不了高版本编译产物。更麻烦的是包里没有源码,想改逻辑都无从下手。
解决:用javap -c DateUtil反编译拿到方法签名,按签名写一个同名同方法结构的 Java 源文件,替换进源码目录重新编译。如果业务里只用到简单的日期格式化和字符串拼接,直接换成System.currentTimeMillis()+SimpleDateFormat实现,绕开这两个类,反而更干净。演示项目里不建议依赖没有源码的编译产物,这是黑匣子。
5.4 同一时间段出现两条预约记录:后端没做幂等
现象:弱网环境下用户点了两次提交,service_record 里出现了两条一模一样的预约记录,时间和车辆完全相同。
原因:前端按钮节流只挡正常连点,网络超时后小程序自动重发请求,节流标志已经复位,拦不住。后端没有做重复性校验,两条 INSERT 都执行成功。
解决:给 service_record 建(vehicle_id, appointment_time, service_type)联合唯一索引,数据库层面保证同一台车同一时间同一服务只能有一条记录。后端在插入前先按这三个条件 SELECT 一次,查到就返回 1003「该时段已满」,查不到才执行 INSERT,两个操作放进一个事务里。很多从培训班出来的代码只做了前端校验,这份源码如果后端也没有唯一约束,二开时一定要自己补上。
5.5 中文显示成乱码:三处字符集只改了一处
现象:预约记录里「保养」在小程序端显示成乱码,数据库里用客户端查出来却是正常的。
原因:数据库是 utf8,但 ASP 页面输出时没设 CodePage,IIS 按本机默认的 GB2312 解析了表单提交的中文,写进数据库的字节已经错了。或者反过来,数据库是 GBK,页面按 UTF-8 输出,读出来也是乱的。
解决:三处必须一致。ASP 文件头部加Response.CodePage = 65001和Session.CodePage = 65001;Response.ContentType 里带 charset=utf-8;数据库连接串加 charset 参数。改完重启站点,再重新提交一遍数据,别拿旧数据测,旧数据如果已经以错误编码写入,改配置也救不回来。
6. 答辩前把 Demo 调成「能讲出设计」的演示版本
6.1 演示数据编排与角色走位
代码能跑只是及格线,答辩演示要讲出设计深度,数据编排很关键。我一般会在数据库里预置三组演示数据:三个客户,一个做过保养的老客户,service_record 里有真实记录可查;一个刚注册的新客户,tag 为空,正好演示客户标签的冷启动;一个高意向客户,tag 标成「置换」,demand 里写清楚旧车信息。五台在售车型,其中一台把 stock 压到 warn_stock 以下,演示时库存卡片会自动变黄,评审问「预警怎么实现的」,直接打开 vehicle 表指着 warn_stock 字段回答。再放两张销售订单,一张已交付、一张待签约,销售报表页才有数据可看。
演示路径按角色走:先用 customer 身份登录,走一遍「浏览车型 → 提交保养预约」的流程,然后切到 sales 身份,进后台看到刚提交的预约记录,审核通过后库存减一。切换角色时补一句「小程序端只暴露了 customer 角色接口,管理端用的是另一套入口」,这句话能挡住一半的权限追问。
最好准备一份兜底脚本。现场网络一旦不稳,所有接口都会失败,这时把接口返回的 JSON 打印成纸质附录带到现场,演示时说「这是预约接口的返回结构,code 0 表示成功」,依然能完整讲完数据链路,不至于冷场。
有一回我帮同学模拟答辩,演示到一半,登录用的测试账号被之前调试时的会话顶掉了,页面白屏了三十秒,当场翻车。从那以后我每次演示前都强制走一遍完整流程:清缓存、登出、按演示脚本从头点一遍、截图留底。这份源码包下载下来之后,建议你也按这个顺序先跑一遍完整链路,把每个接口的返回截图存档,答辩的时候心里有底。希望帮到你。
本文还有配套的精品资源,点击获取