ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python Flask+Vue打造校园二手交易系统:从需求到部署全流程解析

Python Flask+Vue打造校园二手交易系统:从需求到部署全流程解析 在校园里待过几年的人大概率都有过这样的经历想买一本二手教材翻遍了十几个闲聊群也没找到想卖掉闲置的自行车发了几条朋友圈最后只能在毕业季被收废品的一起称斤拉走。我见过太多同学靠微信群做二手交易效率和体验都很糟糕——信息几分钟就被淹没价格不透明没有评价也没有担保买卖基本靠运气和自觉。所以我动手用 Python Flask Vue 做了一套校园二手闲置物品租售系统后端由 Flask 提供接口和业务逻辑前端由 Vue 构建页面交互数据落在轻量级 SQLite 数据库中。整套系统支持用户注册登录、商品发布、分类浏览、关键词搜索、收藏留言、交易确认既能本地跑通也能部署到普通 Windows 服务器上非常适合课程设计、毕业设计参考也适合刚入门的全栈学习者照着做一遍。这篇文章我会按照自己从需求分析、数据库设计、后端接口、前端页面到最终部署上线的完整过程来讲重点标注那些实际项目里才会遇到的坑尤其是 Windows 部署时附件路径错误这类问题。1. 为什么校园二手交易值得自己动手做一套1.1 二手交易的真实痛点先聊点真实的校园场景。我见过最典型的情况是考研结束那几天宿舍群里全是“出肖秀荣全套”“出英语真题附笔记”的消息刷屏速度比聊天还快真正想买的人根本来不及看想卖的人也被反复问价搞得疲劳。还有更常见的——二手群只承担“发布”功能没有搜索、没有分类、没有价格参考更没有历史记录。同一个物品有人报价 20有人报价 80买家只能靠私聊来回试探。这样的需求其实非常适合做成一个轻量化系统。二手交易的核心不是社交而是“信息的结构化匹配”你发布一条闲置系统把它拆成标题、分类、成色、价格、图片别人需要时按关键词和分类精准筛选而不是在聊天记录里往上翻几百条。另一个经常被忽视的痛点是交易信任。校园交易虽然大多线下面对面但卖家的历史记录、买家浏览过哪些商品、卖家是否及时下架已售物品这些基础信息如果完全没有记录纠纷一来就是一笔糊涂账。我决定自己做这套系统的原因也很简单市面上不是没有闲鱼但校园场景有它的特殊性——同一栋宿舍楼、同一个校区内的交易更讲究效率很多东西只在毕业季和开学季集中流动价格低、频次高、商品更新快。一套针对校园优化的轻量系统比通用二手平台更贴合这个场景。哪怕是作为练手项目它也比普通的“图书管理系统”有价值得多因为整个业务流程更真实、更完整。1.2 技术选型背后的取舍选型是动手前必须想清楚的第一步这里没有唯一正确答案只有“适不适合你当前的目标”。我最终选了 Python Flask Vue SQLite背后的判断是这样的Flask 而不是 DjangoFlask 足够轻路由、蓝图、上下文等机制很直观特别适合用来理解 Web 后端最核心的东西——HTTP 请求怎么进来、怎么路由、怎么返回 JSON。Django 功能强大但自带 Admin、ORM、中间件等一堆概念新手很容易陷入“照着教程搬但不知道在搬什么”的状态。对校园二手系统这种中等复杂度的项目Flask 完全够用。Vue 而不是 ReactVue 对中国开发者来说文档和社区更友好模板语法直观单文件组件SFC让页面结构和样式集中在一起配合 Element Plus 这类组件库写后台管理系统或者商品列表这类界面速度很快。React 的生态和灵活性也很好但如果目标是“快速看到成品”Vue 的上手曲线更平缓。SQLite 而不是 MySQL这套系统的数据量撑死几千个用户、几万条商品记录SQLite 单文件存储、零配置、备份就是复制一个文件对学生项目来说再合适不过。真到了并发写入量很大、需要多机部署的阶段再平滑切到 MySQL 也不难因为大多数代码走的是 ORM数据库方言差异被挡住了。换个角度说选型还要考虑“你最终能跑多远”。我见过很多同学一上来就上微服务、Redis、消息队列结果折腾半个月连注册登录都没跑通。决定项目成败的往往不是技术栈多先进而是你能不能把它完整地部署出来、给别人用上。下面的表格是我当时做的对比建议你也列一张对比维度Flask 方案Django 方案我的选择理由学习曲线平缓能看清底层逻辑较陡概念多想先把 Web 原理吃透项目体积精简按需扩展完整但偏重校园二手系统不需要全栈框架的重量数据库SQLite 起步可换 MySQL默认 PostgreSQL 体系SQLite 零运维压力前端配合纯 JSON API天然适合 Vue服务端模板渲染更强想练前后端分离这套选型逻辑不是唯一的但它是“用最少的时间得到一个可演示、可部署成品”的稳妥路线。如果你已经有 Django 经验用 Django 做也没问题如果后端是 Java 背景Spring Boot 同样可以。关键是先明确自己到底要练什么、要在多长时间内交出什么。2. 从需求到功能清单动手之前先画清楚业务流程2.1 核心功能模块很多人写代码失败不是不会写语法而是需求根本没想清楚就开干写着写着发现这里缺块表、那里少个状态。我在动工之前把所有功能按“交易闭环”拆了一遍用户模块注册、登录、退出密码用哈希存储Session 或 Token 管理登录态个人中心展示我发布的、我收藏的、我买到的。商品模块发布闲置标题、描述、分类、价格、原价、成色、图片、联系方式、编辑下架、商品列表、详情页、分类筛选、关键词搜索、排序。互动模块收藏商品、对商品留言、查看卖家信息、站内私信1.0 版本可以先用留言代替。交易模块买家确认“我想要”、卖家确认“已成交”、商品状态自动变为已售下架。管理模块管理员后台可审核违规商品、处理举报1.0 阶段先做最基础的商品下架能力。这五个模块不是平级的优先级差别很大。我当时给排了个序优先级功能说明P0注册登录、商品发布、商品列表、详情页没有这些系统连基本闭环都跑不通P1搜索筛选、收藏留言、状态流转提升可用性让交易可操作P2数据统计、后台管理、私信通知属于锦上添花可以后续迭代我强烈建议你不要一开始就追求功能齐全。先把“注册-发布-浏览-联系-成交-下架”这条主线跑通哪怕界面丑一点也能真实用了。有了真实用户输入的数据再谈优化和加功能方向才会对。2.2 核心流程设计需求清单只回答了“做哪些功能”流程设计则要回答“用户怎么走完一次交易”。我把核心流程画成了很朴素的路径新用户注册登录填写昵称、手机号、微信号。发布闲置选择分类、填写标题描述、上传图片、设置价格和成色。买家在首页按分类浏览或用关键词搜索按最新发布/价格排序。进入商品详情查看图片和卖家信息点击收藏或留言。买家与卖家通过站内留言或展示的微信号联系约线下交易。交易完成后买家或卖家在订单记录中标记“已成交”商品自动下架。如果商品被管理员发现违规可以强制下架并通知发布者。这里有一个很重要的设计决定为什么同时保留“站内留言”和“展示联系方式”两条通道我一开始以为学生都会用站内留言沟通省事又留痕。后来和几个同学聊了才发现大家更习惯加微信因为要看实物照片、约时间地点微信更顺手。但纯展示联系方式也有问题平台看不到交易沟通过程纠纷难以追溯。所以最好的做法是两条通道并存站内留言作为平台内的记录方便日后追溯联系方式作为线下交易辅助真正提高成交效率。这个原则很多二手平台也是这么做的你设计时不要只图“管理方便”而砍掉用户习惯的那条路。流程里还有一个容易被忽略的点商品状态机。一件商品要从“在售”变成“已下架”“已成交”“违规下架”状态必须存在数据库字段里而不是发布者删掉这条记录。否则交易历史、买家收藏、后台统计都会乱套。我建议从第一天起就设计好status字段而不是等项目跑起来再补。3. 数据库表结构和 Flask 后端接口的实现要点3.1 表结构怎么设计才够用数据库是整个系统的地基。我的原则是“宁缺毋滥但关键的关联和状态字段不能少”。全套系统用 SQLite 落库ORM 选 Flask-SQLAlchemy这里是我整理出来的核心表结构-- 用户表 CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(64) NOT NULL UNIQUE, password_hash VARCHAR(128) NOT NULL, nickname VARCHAR(64), avatar VARCHAR(255), phone VARCHAR(20), wechat VARCHAR(64), created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 商品表 CREATE TABLE items ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, title VARCHAR(100) NOT NULL, description TEXT, category VARCHAR(50), price NUMERIC(10, 2), original_price NUMERIC(10, 2), quality VARCHAR(20), -- 全新/几乎全新/轻微使用/明显使用痕迹 images TEXT, -- 存 JSON 数组或逗号分隔的图片路径 contact_wechat VARCHAR(64), contact_phone VARCHAR(20), status VARCHAR(20) DEFAULT on_sale, -- on_sale/sold/off_shelf/rejected view_count INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); -- 收藏表 CREATE TABLE favorites ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, item_id INTEGER NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_id, item_id) ); -- 留言表 CREATE TABLE messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_id INTEGER NOT NULL, user_id INTEGER NOT NULL, content TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 交易记录表 CREATE TABLE orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_id INTEGER NOT NULL, buyer_id INTEGER NOT NULL, seller_id INTEGER NOT NULL, status VARCHAR(20) DEFAULT pending, -- pending/confirmed/cancelled/completed created_at DATETIME DEFAULT CURRENT_TIMESTAMP );几个细节值得强调images字段存图片路径的 JSON 数组而不是单独建一张商品图片表。校园二手场景下一个商品 3 到 5 张图就够一张字段搞定查询也简单。如果以后要做多图集管理再拆表也不迟。price用NUMERIC(10, 2)而不是浮点数避免展示时出现 19.999999 的问题。status字段一定要加索引因为商品列表页最核心的查询就是WHERE status on_sale。UNIQUE(user_id, item_id)在收藏表里可以防止重复收藏这比在代码里判断更可靠。3.2 Flask 项目分层与接口实现Flask 项目最怕写成一个超大的app.py。我当时把项目按蓝图Blueprint拆成几个模块好处是路由和模型不会互相纠缠后期加功能也方便flask-backend/ ├── app.py # 创建 app、注册蓝图、数据库初始化 ├── config.py # 配置项数据库路径、上传目录、密钥 ├── models.py # 所有 ORM 模型 ├── requirements.txt ├── uploads/ # 用户上传的图片 └── blueprints/ ├── auth.py # 注册、登录、退出 ├── item.py # 商品 CRUD、搜索、筛选 ├── user.py # 个人中心、我发布的、我收藏的 └── order.py # 收藏、留言、订单状态流转写接口时有一个原则后端返回 JSON前端只消费 JSON。比如商品列表接口我当时的写法大概是这样from flask import Blueprint, request, jsonify from models import Item, db item_bp Blueprint(item, __name__) item_bp.get(/api/items) def list_items(): page request.args.get(page, 1, typeint) per_page request.args.get(per_page, 12, typeint) keyword request.args.get(keyword, , typestr) category request.args.get(category, , typestr) query Item.query.filter(Item.status on_sale) if keyword: query query.filter(Item.title.contains(keyword)) if category: query query.filter(Item.category category) pagination query.order_by(Item.created_at.desc()).paginate( pagepage, per_pageper_page, error_outFalse ) items [item.to_dict() for item in pagination.items] return jsonify({ items: items, total: pagination.total, page: page, pages: pagination.pages })这里有两个容易犯的低级错误第一接口返回的分页数据一定要带上total和pages前端分页组件需要它们不然不好算总页数第二列表接口不要直接给前端传 ORM 对象要有一个to_dict()方法明确告诉调用方返回了哪些字段否则容易把内部字段也暴露出去。关于密码安全要单独说一下不能用明文密码存数据库。我当时用werkzeug.security的generate_password_hash和check_password_hash注册时存哈希登录时校验哈希登录态用 Flask 的session管理开启SESSION_COOKIE_HTTPONLY。安全这块不用做得多花哨但底线必须有尤其是公开部署的项目。3.3 图片上传与静态资源路径这里埋着一个大坑商品图片是二手系统的门面但图片上传和访问路径恰恰是最容易出问题的地方。我一开始的做法很天真把上传的图片放到 Flask 项目目录下的static/uploads然后通过/static/uploads/xxx.jpg访问。本地开发一切正常部署到 Windows 服务器之后问题接踵而至。第一个坑是路径拼写。Windows 的路径分隔符是反斜杠\而浏览器 URL 用的是正斜杠/。如果你在代码里手动拼字符串比如save_path upload_dir \\ filename然后把save_path存到了数据库里那么前端拿到的图片地址就是http://host/static/uploads\xxx.jpg浏览器根本识别不了。这不是什么玄学就是路径分隔符没统一。第二个坑是动态获取路径。有些代码写成os.getcwd()拼接路径开发时项目在 D 盘某个目录部署后被移到 E 盘另一个目录图片全部 404。正确做法是让上传目录基于固定配置而不是依赖当前工作目录。我当时最终的修复方案是import os from flask import Flask BASE_DIR os.path.dirname(os.path.abspath(__file__)) UPLOAD_DIR os.path.join(BASE_DIR, uploads) ALLOWED_EXTENSIONS {png, jpg, jpeg, gif, webp} # 保存图片 def save_image(file): ext file.filename.rsplit(., 1)[-1].lower() if ext not in ALLOWED_EXTENSIONS: return None, 不支持的图片格式 filename str(uuid.uuid4()).replace(-, ) . ext file.save(os.path.join(UPLOAD_DIR, filename)) return f/uploads/{filename}, None关键点有三条用os.path.abspath(__file__)定位项目根目录不管从哪个目录启动路径都不会跑偏。上传文件名不要用用户原始文件名改用uuid生成唯一名字避免重名覆盖和路径穿越问题。数据库里存的是 URL 形式的/uploads/xxx.jpg而不是服务器磁盘路径。文件保存和 URL 访问是两回事混淆了必出问题。静态资源访问这一块Flask 需要显式指定app Flask(__name__, static_folder., static_url_path)这样做的意义是让 Flask 既能正常提供/uploads/下的图片也能在后续托管 Vue 打包后的静态文件一个服务搞定前端和后端部署时省去配 Nginx 的步骤。当然如果你有精力配 Nginx 做静态文件服务性能会更好但在校园场景和课程设计里Flask 直接托管完全足够。4. Vue 前端的关键交互实现4.1 项目初始化和目录组织前端用的是 Vue 3 Vite。我之所以不用 Vue CLI 而用 Vite是因为 Vite 基于 ES Module冷启动和热更新都比 Webpack 快非常多对开发体验改善是质的飞跃。初始化命令很简单npm create vitelatest vue-frontend -- --template vue cd vue-frontend npm install npm install vue-router4 axios element-plus项目里的目录结构我建议这样分src/ ├── api/ # axios 请求封装按模块拆分 │ ├── request.js │ ├── auth.js │ └── item.js ├── router/ # 路由配置 ├── views/ # 页面级组件 │ ├── Home.vue # 商品列表 │ ├── Login.vue │ ├── Register.vue │ ├── ItemDetail.vue │ ├── Publish.vue # 发布商品 │ └── Profile.vue # 个人中心 ├── components/ # 通用组件 └── store/ # 如果要管理登录态可以放 Pinia很多新人容易把页面逻辑全堆在一个组件里一个.vue文件几千行后期改起来非常痛苦。我的习惯是页面组件只负责布局和交互数据请求全部走api/里的模块这样接口调整时只改一处。4.2 请求封装与跨域处理axios 封装是前端项目的标配。我当时的封装思路是统一设置基础路径、自动携带 Session Cookie、统一处理错误码。登录态这东西Flask 默认用的是 Cookie Session只要前端请求带上withCredentials后端就能识别当前用户。// api/request.js import axios from axios; import { ElMessage } from element-plus; const request axios.create({ baseURL: /api, timeout: 8000, withCredentials: true }); request.interceptors.response.use( (response) response.data, (error) { const status error.response?.status; if (status 401) { ElMessage.error(请先登录); window.location.href /login; } else { ElMessage.error(error.response?.data?.message || 请求失败); } return Promise.reject(error); } ); export default request;与之配套的是 Vite 开发服务器的代理配置。开发时前端跑在 5173 端口后端跑在 5000 端口浏览器直接请求 Flask 接口必然遇到跨域问题。解决方式不是在后端装flask-cors当然那也是一种方案而是在 Vite 里配置代理所有/api开头的请求都转发到 Flask。// vite.config.js import { defineConfig } from vite; import vue from vitejs/plugin-vue; export default defineConfig({ plugins: [vue()], server: { proxy: { /api: { target: http://127.0.0.1:5000, changeOrigin: true }, /uploads: { target: http://127.0.0.1:5000, changeOrigin: true } } } });这个方案有一个额外好处开发环境前端请求的 URL 是/api/items部署后如果前端被 Flask 托管请求的 URL 还是/api/items。前后端接口路径完全一致不需要因为环境切换去改代码。我见过不少项目开发时写死了http://localhost:5000/api部署到服务器上又改配置完全是自己给自己找麻烦。4.3 商品列表、详情页和发布表单的实现思路商品列表页是整个系统流量最大的页面。我当时做了三个核心能力分类标签筛选、关键词搜索、分页加载。交互逻辑很简单筛选条件变了就重新请求第一页数据点击分页带上当前的筛选条件请求对应页的数据。为了避免频繁请求搜索框加了一个debounce防抖用户停止输入 500 毫秒后才发起请求。商品详情页需要注意图片展示和联系方式呈现的平衡。多图我会用 Element Plus 的el-carousel轮播主图大图展示下面横排缩略图。联系区域放两个按钮一个“留言咨询”弹出一个对话框填写留言一个“查看卖家微信”点击后显示微信号文本方便复制添加。要防止页面一加载就把所有图片原图加载出来轮播图建议用懒加载提升弱网环境下的打开速度。发布表单我用了 Element Plus 的el-form校验规则包括标题必填且不超过 40 字、价格必填且大于等于 0、至少上传一张图片。图片上传使用el-upload手动控制请求选择图片后先本地预览用户确认提交时再一次性把所有图片上传到后端。这里有一个细节不要把图片上传和商品信息提交拆成两步独立操作否则用户填了一半放弃会产生一批没有关联到商品的孤儿图片。更好的做法是把图片作为表单数据的一部分连同商品信息一起用FormData提交后端一次处理完整事务。5. 本地联调与部署上线Windows 服务器的实战记录5.1 本地跑通联调本地开发时我习惯开两个终端一个跑 Flask一个跑 Vite。Flask 启动要监听所有网卡方便手机在同一局域网内测试flask --app app run --host0.0.0.0 --port5000前端则执行npm run dev浏览器访问 Vite 输出的地址。因为代理已经配好页面里所有/api请求都会被转发到后端的 5000 端口前后端联调基本无感。建议你在这一步就先把“发布商品-首页可见-查看详情-留言”这条链路完整走一遍确认没问题再考虑部署免得把联调问题误当成部署问题排查。5.2 Windows 服务器部署的完整步骤这里说一下我后来在 Windows Server 上部署的实操流程。整个过程不依赖 Docker很多时候校园环境里没有现成的 Docker 环境也不用 Nginx纯靠 Python 生态自带的能力就能跑起来准备 Python 环境。服务器安装 Python 3.10 或 3.11安装时务必勾选 “Add Python to PATH”否则命令行里找不到python。上传项目文件。把后端的app.py、models.py、blueprints/、requirements.txt以及前端构建产物都传上去。创建虚拟环境cd D:\projects\campus-market python -m venv venv venv\Scripts\activate pip install -r requirements.txt构建前端。本地执行npm run build生成的dist目录整个传到服务器放到 Flask 项目的static目录关联的位置。Flask 这边需要加一个“兜底路由”让所有非/api和非/uploads的请求都返回index.htmlapp.route(/) def index(): return send_from_directory(static, index.html) app.errorhandler(404) def not_found(e): path request.path if path.startswith(/api) or path.startswith(/uploads): return jsonify({message: 资源不存在}), 404 return send_from_directory(static, index.html)这个兜底处理非常关键。Vue Router 如果是history模式直接访问/item/3这种地址时服务器是没有这个文件的必须返回index.html让前端路由接管。不然一刷新详情页就是 404。用 Waitress 启动服务。Flask 自带的开发服务器只能用于调试生产环境要换 Waitress它是 Windows 平台下非常靠谱的纯 Python WSGI 服务器pip install waitress waitress-serve --host0.0.0.0 --port80 --call app:create_app我用的是--call app:create_app的写法前提是app.py里定义了工厂函数create_app这样项目结构更干净测试和部署都方便。开机自启。Windows 服务器上不能像 Linux 一样随便用 systemd。我用 NSSM 把 Waitress 注册成了系统服务这样即使服务器重启系统也能自动恢复运行。这一步如果不想用额外工具也可以写一个.bat脚本丢进启动文件夹但 NSSM 管理服务状态、看日志都更舒服。这套流程拿到一台干净 Windows 服务器上从头到尾大概半小时能跑通。核心思路就一句话让 Flask 同时托管前端静态资源和后端 API用 Waitress 提供稳定的 WSGI 服务结构简单便于排错。5.3 附件路径错误部署时最经典的坑这部分我单独拎出来说因为太典型了。我最初在本地发布商品、上传图片一切正常。部署到 Windows 服务器后出现了一个奇怪现象新上传的图片当天能访问服务器重启后有些图片 404 了而且上传成功后如果立刻刷新页面偶尔也会显示裂图。排查过程我一步步讲第一步确认图片文件到底存到了哪。我在服务器上打开uploads目录发现文件明明存在数据库里的路径也能对上。那为什么访问不了这一步排除了“上传失败”的可能。第二步检查 URL 和磁盘路径的映射关系。问题来了。我数据库里存的是static/uploads/20250401/xxx.jpg这种相对路径而 Flask 的static路由已经配置了。我把请求 URL 和磁盘结构对比后发现本地项目根目录叫campus-market服务器上我为了整洁把项目根目录改成了market-server。代码里如果用了os.path.join(os.getcwd(), static)之类依赖“当前工作目录”的写法本地跑没错换到服务器上一启动就都不对。第三步检查 Windows 路径分隔符。发现一些图片的 URL 里带上了\就是因为存路径时用了os.path.join在 Windows 上拼出了反斜杠路径浏览器不认。最终的修复方案是在config.py里定义基于项目绝对路径的上传目录和静态目录保存图片时只存 URL 路径访问时靠 Flask 静态路由解析绝不依赖os.getcwd()也绝不在数据库里存磁盘绝对路径。修完之后图片上传、重启、刷新全部正常。这个坑的经验可以总结成一句话凡是涉及文件路径的代码必须在项目上线前做一次“换目录启动”测试。本地怎么启动服务器就怎么启动如果项目根目录换了还能正常工作才说明路径处理是健壮的。6. 上线一两周后的优化方向与个人体会6.1 搜索体验的小优化系统跑起来之后最影响日常体验的是搜索。初始版本我用的是Item.title.contains(keyword)也就是数据库LIKE模糊匹配。这个方案的问题很明显搜“高数”搜不到“高等数学”搜“山地车”也搜不到“捷安特”因为关键词对不上。我第一次优化做了两件事。第一件是搜索范围和权重调整标题命中权重最高描述命中权重其次分类命中也可以算进去。第二件是引入简单的关键词归一化把用户输入的空格、特殊符号去掉统一小写再维护一个同义词映射表比如“单车”和“自行车”能够互相匹配。这套朴素方案虽然不如向量检索那样“聪明”但在校园二手这种封闭语料环境下效果已经很好。另外一个体验点搜索结果为空时不要冷冰冰地显示“没有找到相关商品”。我当时加了“猜你想看的同类热门商品”兜底按分类推荐浏览数最高的几条用户就不会一搜不到就走。发布端也要做“无效信息过滤”的小动作比如联系方式重复、标题全是大写字母、包含明显广告词提交时直接提示修改。这不是为了刁难用户是为了保证搜索结果的质量。6.2 后续可以扩展的方向等核心闭环稳定后我会建议按用户价值从高到低去扩展而不是想到什么做什么站内私信从“留言板”升级为“一对一会话流”成交前沟通更私密流畅。消息表需要加from_user_id、to_user_id、is_read这些字段再配合 WebSocket 能做到实时提醒。信用与评价体系每次交易完成后买卖双方互评形成个人信用分。校园圈子不大信用评价对促成交易很有说服力。担保交易这个功能工程量不小需要接入支付或校内校园卡系统适合作为进阶版本。普通课程设计不必强求。微信小程序端Vue 3 的代码可以通过 uni-app 或 Taro 迁移到小程序复用大部分逻辑。学生用手机访问网站的习惯其实不如打开小程序方便如果想让项目“落地”这是最有价值的一步。6.3 我的几点心里话做完这个项目我最大的体会是千万不要一开始就过度设计。我第一版也想过是不是要用 Redis 做缓存、用 Docker 做容器化、用 Nginx 做负载均衡后来冷静下来发现一套几百人使用的校园系统根本不需要这些东西。你的时间应该花在把核心业务流程做得稳定、把页面交互做得顺手、把部署流程做得可复现上。真正的学习不是堆技术名词而是把一个系统从想法变成能被同学真实使用的产品。技术实现上有几个看似小但影响巨大的细节我再强调一遍密码必须哈希存储上传文件名必须唯一化数据库路径不能依赖当前工作目录前端路由 history 模式必须有兜底路由部署之前先做一次换目录启动测试。把这些做好了你的项目就不再是“能跑”而是“能长期用”。最后说一句题外话如果你准备拿这个项目去答辩或写进简历建议提前准备好“技术选型理由”和“遇到的最大坑及解决方案”这两个问题的答案因为这是别人最容易追问的地方。我正是因为被问过太多次才把附件路径错误和 Vite 代理跨域那两段经验沉下来写成了这篇文章。
返回列表