ARTICLE DETAIL

资讯详情

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

校园流浪动物救助平台:Node.js+Vue+Express全栈开发实战详解

校园流浪动物救助平台:Node.js+Vue+Express全栈开发实战详解 我做过不少前后端分离的项目但真正把 Node.js、Vue 和 Express 三个技术栈揉进一个完整业务场景还是这个校园流浪动物救助平台。这个项目不是一般的管理系统 CRUD它涉及信息发布、领养审批、救助记录、图片上传、状态流转等一系列真实业务非常适合拿来练手或作为毕业设计。今天我会从项目拆解、技术选型、数据库设计、前后端实现到部署排查把整个平台的完整思路和关键代码都写清楚希望能给正在做类似项目的朋友一些参考。1. 平台整体设计与技术选型1.1 为什么选择 Node.js Vue Express 这套组合校园流浪动物救助这个场景核心需求无非是三类让师生能够发现并上报流浪动物信息让救助组织或管理员能够跟进处理让普通用户能够申请领养。这个业务模型不算特别复杂但对信息流转和状态管理的要求很明确用 Node.js Express 做后端 API用 Vue 做前端 SPA是典型的轻量级前后端分离架构。选择这套技术栈有几个现实考量。第一JavaScript 全栈可以统一语言前端写 Vue后端写 Express类型思维和工具链都能复用省去切换语言的心智负担。第二Express 作为 Node.js 生态里最成熟的 Web 框架中间件机制非常灵活像用户认证、文件上传、日志记录这些横切关注点都可以用中间件优雅处理。第三Vue 本身对中小型项目非常友好响应式数据和单文件组件让页面开发效率很高加上 Element UI 这类组件库后台管理界面很快就能搭出来。如果团队里有人熟悉 JavaScript这个组合在校园项目或中小型系统中确实很能打。1.2 核心功能模块拆解我在做需求分析的时候没有一上来就写代码而是先把用户角色和业务链路捋清楚。这个平台涉及三类角色普通学生用户、管理员通常是社团或后勤人员、系统维护者。不同角色看到的功能完全不一样。普通用户端围绕“发现 - 上报 - 查看 - 申请领养”这条主线展开首页是动物卡片墙可以看到待领养动物的照片、性格描述、救助状态详情页有完整的救助记录时间线用户可以在线提交救助上报上传照片和位置信息对心仪的动物可以发起领养申请并跟踪申请状态。管理端则复杂一些核心是审核和流转上报信息审核、动物信息编辑包括是否开放领养、健康状况更新、领养申请审批、公告维护、用户管理。这些功能如果做成一个个散落的接口前端会很难维护所以我把接口路径按照资源维度做了统一设计后面会详细说并且用状态机约束动物信息的流转方向。1.3 项目目录结构与工程化约定工程化是多人协作或后续扩展的基础。下面是我实际使用的目录结构比较清晰也方便以后拆分微服务时做迁移project-root/ ├── client/ # Vue 前端工程 │ ├── src/ │ │ ├── api/ # 接口请求模块 │ │ ├── assets/ │ │ ├── components/ # 公共组件 │ │ ├── router/ # 路由配置 │ │ ├── store/ # 状态管理Vuex/Pinia │ │ ├── views/ # 页面组件 │ │ ├── App.vue │ │ └── main.js │ ├── package.json │ └── vue.config.js ├── server/ # Express 后端工程 │ ├── config/ # 数据库及全局配置 │ ├── controllers/ # 业务控制器 │ ├── middleware/ # 中间件auth、upload等 │ ├── models/ # 数据模型 │ ├── routes/ # 路由定义 │ ├── utils/ # 工具函数 │ ├── app.js # 应用入口 │ └── package.json └── README.md这里有一个容易被忽视的点前端的api/目录和后端的routes/目录要尽可能保持对应关系。我见过很多项目前端请求路径和后端路由各写各的排查问题时非常痛苦。我个人的习惯是前端api/animal.js里的方法名和后端routes/animal.js里的接口一一对应接口路径也统一用/api/xxx前缀这样联调时效率高很多。2. 数据库设计与核心接口设计2.1 数据表设计思路校园流浪动物救助平台的数据模型说简单也简单说复杂也有不少细节。核心表包括用户表、动物信息表、救助记录表、领养申请表、公告表、图片资源表。其中最容易设计失误的是动物信息表和领养申请表。动物信息表不能只存基本属性还要保存状态。我设计的状态字段取值如下reported已上报待审核published已发布可领养adopted已被领养followup治疗/观察中archived已归档为什么要单独做状态字段而不是用布尔值因为在真实场景中一只流浪猫可能被上报后先进入观察期治疗康复后才开放领养期间还会有健康记录。状态字段配合操作时间戳可以清晰追溯整个救助链路。领养申请表是另一个关键它不能只存申请人和动物 ID。我增加了application_status字段取值有pending待审核、approved通过、rejected拒绝、completed已完成。管理员审批后系统要联动更新动物信息表的状态比如批准领养后动物状态要变为adopted。这两个表之间的状态联动是业务逻辑里最需要留意的地方。用户表设计也有个细节用户角色我直接用role字段区分0是普通用户1是管理员不做单独的角色表。对于校园项目这个体量单表足够查角色时少一次关联查询接口响应更快。下面是精简后的建表 SQL 参考以 MySQL 为例CREATE TABLE user ( id INT NOT NULL AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, nickname VARCHAR(50) DEFAULT , phone VARCHAR(20) DEFAULT , role TINYINT DEFAULT 0, avatar VARCHAR(255) DEFAULT , create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE animal ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, category VARCHAR(20) DEFAULT cat, -- cat / dog / other gender TINYINT DEFAULT 0, -- 0未知 1公 2母 age VARCHAR(50) DEFAULT , color VARCHAR(100) DEFAULT , health_status VARCHAR(255) DEFAULT , location VARCHAR(255) DEFAULT , description TEXT, status VARCHAR(20) DEFAULT reported, cover_image VARCHAR(255) DEFAULT , reporter_id INT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;2.2 Express 接口设计规范与实践接口设计我遵循一个简单的原则资源导向、语义化路径、统一响应格式。比如动物相关的接口这样定义GET /api/animal/list 分页获取动物列表 GET /api/animal/:id 获取动物详情 POST /api/animal/create 新建上报 PUT /api/animal/:id 更新动物信息管理员 PUT /api/animal/:id/status 更新动物状态 DELETE /api/animal/:id 删除软删除标记 archived统一响应格式是我强烈建议坚持的前后端联调时能省很多口舌。我的响应结构固定为{ code: 200, message: 操作成功, data: {} }所有接口都走这个格式前端 Axios 拦截器里统一判断code。这样后端不用为每个接口单独处理异常前端也只需要写一份错误提示逻辑。很多人项目做到一半出现前端“拿到数据却不知道成没成功”的问题基本都是响应格式不统一惹的祸。后端代码分层上我用了最经典的 Controller Service Model 三层。Controller 只做参数接收和响应包装Service 放业务逻辑Model 层用 Sequelize 或 mysql 库操作数据库。有的同学图省事把所有逻辑都堆在路由回调里刚开始觉得很快等业务复杂起来一个接口几百行根本没法维护。// routes/animal.js 示例 const express require(express); const router express.Router(); const animalController require(../controllers/animalController); const authMiddleware require(../middleware/auth); router.get(/list, animalController.getList); router.get(/:id, animalController.getDetail); router.post(/create, authMiddleware, animalController.create); router.put(/:id, authMiddleware, animalController.update); router.put(/:id/status, authMiddleware, animalController.updateStatus); module.exports router;这样路由配置非常直观新成员接手项目时看一遍路由就能理解整个系统的能力边界。2.3 JWT 登录认证与权限控制用户认证我选择 JWTJSON Web Token方案而不是传统的 Session。原因有两点一是前后端分离架构下JWT 天然无状态服务端不需要维护会话信息扩展时很方便二是 Vue 前端可以很方便地把 token 存在 localStorage 里每次请求通过 Axios 拦截器附带在 Authorization 头中。JWT 的签发在用户登录接口完成const jwt require(jsonwebtoken); const generateToken (user) { return jwt.sign( { id: user.id, username: user.username, role: user.role }, process.env.JWT_SECRET, { expiresIn: 7d } ); };后端的authMiddleware做统一鉴权这是保护接口的第一道防线。有几个接口需要管理员权限比如更新动物状态、审批领养申请我就再包一层adminMiddleware。要注意的是JWT 的密钥一定不能写死在代码里。我用.env文件管理环境变量同时把JWT_SECRET设得足够复杂。另外实际项目中密码存储必须用 bcrypt 或 argon2 做哈希明文密码是绝对红线哪怕只是练手项目也应该养成这个习惯。3. 前端实现Vue 项目全流程开发3.1 前端环境搭建与依赖安装前端开发第一步是准备环境。Node.js 和 npm 的安装其实不算难但我发现很多新手在 Windows 上安装时会遇到一个经典问题在终端执行npm命令时提示“无法加载文件 ...npm.ps1因为在此系统上禁止运行脚本”。这个报错本质是 PowerShell 的执行策略限制了脚本运行解决方案是Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser这个命令的作用是允许运行本地脚本同时要求远程下载的脚本必须有数字签名安全性有保障。执行之后npm命令就能正常使用了。前端项目我直接用 Vue CLI 创建vue create client这里有个小建议项目名不要用中文或大写后面构建部署时比较容易出问题。创建过程中选择手动配置按需勾选 Vue Router 和 Vuex/Pinia。我习惯把路由和状态管理都选上虽然初期项目不一定都用得上但后续扩展时不用再折腾配置。依赖安装方面除了 Vue 自带的核心依赖我额外安装了几个高频使用的包npm install axios element-ui vuex4 vue-router4Axios 用来发 HTTP 请求Element UI 提供后台管理所需的各种组件表格、表单、弹窗、上传Vuex 管理全局共享的用户信息和应用状态。3.2 Vue 项目结构与路由设计前端路由是整个 SPA 的地图。游客、普通用户、管理员能看到的路由不同我在路由配置里通过“路由守卫”做访问控制// router/index.js const routes [ { path: /, name: Home, component: () import(../views/Home.vue) }, { path: /animal/:id, name: AnimalDetail, component: () import(../views/AnimalDetail.vue) }, { path: /report, name: Report, component: () import(../views/Report.vue), meta: { requiresAuth: true } }, { path: /admin, name: Admin, component: () import(../views/admin/AdminHome.vue), meta: { requiresAuth: true, requiresAdmin: true } } ];路由守卫里我做了三层判断先看需不需要登录再看需不需要管理员权限最后检查用户状态是否过期。凡是requiresAuth为 true 的页面没有 token 就统一跳转到登录页。管理员路由多一层requiresAdmin从 token 解出来的 role 不为 1 就拒绝访问。3.3 Axios 封装与 API 调用实践接口请求不能每写一个页面就axios.get(...)一次那样既不好维护也没法统一处理异常。我在api/request.js里封装了一个 Axios 实例统一做了三件事设置 baseURL、请求拦截器附带 token、响应拦截器统一处理错误码。// api/request.js import axios from axios; import { ElMessage } from element-ui; import router from ../router; const request axios.create({ baseURL: process.env.VUE_APP_BASE_API || /api, timeout: 10000 }); request.interceptors.request.use( config { const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }, error Promise.reject(error) ); request.interceptors.response.use( response { const res response.data; if (res.code ! 200) { ElMessage.error(res.message || 请求出错); return Promise.reject(new Error(res.message)); } return res; }, error { if (error.response error.response.status 401) { ElMessage.error(登录状态已过期请重新登录); localStorage.removeItem(token); router.push(/login); } else { ElMessage.error(error.message || 网络异常); } return Promise.reject(error); } ); export default request;然后每个资源模块一个文件比如api/animal.jsimport request from ./request; export function getAnimalList(params) { return request({ url: /animal/list, method: get, params }); } export function getAnimalDetail(id) { return request({ url: /animal/${id}, method: get }); } export function createAnimal(data) { return request({ url: /animal/create, method: post, data }); }这样做的最大好处是页面里无需关心请求细节只需调用对应方法代码非常干净。排查问题时也只需要看api/目录就能知道当前系统调了哪些接口。3.4 核心页面实现动物卡片流与详情页动物卡片墙是整个平台的门面。我在 Home.vue 里通过masonry布局展示卡片每张卡片包含封面图、名称、状态标签和简要介绍。数据加载用分页参数page, pageSize配合“触底加载更多”的交互体验比传统分页按钮更流畅。这里的核心逻辑是只有当动物状态为published时才会出现在公开列表里管理员上报但未审核的动物不会展示。前端展示判断是次要的更可靠的还是在后端接口查询时做状态过滤。详情页则像一个时间线从上到下展示动物的基本信息、救助故事、健康记录、领养按钮。领养按钮的点击事件会打开一个表单弹窗让用户填写申请理由、居住情况、养宠经验等信息。提交后这些数据进入领养申请表状态为pending。3.5 管理后台实现数据表格与状态流转管理后台是管理员的核心工作台我沿用了后台管理系统中常见的“左侧菜单 右侧内容”布局。左侧菜单项包括动物审核、领养审批、公告管理、用户管理。动物审核页面用 Element UI 的el-table展示所有上报记录每行有“通过”“拒绝”“查看详情”等操作按钮。这里有个我踩过坑的细节表格里的图片列如果直接渲染原图性能会很差。我把封面图处理成缩略图地址并把表格图片列宽度固定用el-image的preview-src-list属性支持点击预览大图。领养审批页面相对复杂一点。它涉及两个实体的联动审批通过后要同时更新领养申请状态为approved并更新对应动物状态为adopted或进入followup流程。这个操作必须保证事务性。在后端 Service 层我手动开启事务确保两步操作要么同时成功要么同时回滚。如果只更新了申请状态而忘了动物状态前端页面就会出现“领养已通过但动物还在领养列表里”的尴尬场景。4. 前后端联调与核心业务实现4.1 跨域问题与开发环境代理前后端分离开发时跨域是最常见也最容易让人头疼的问题。前端跑在http://localhost:8080后端跑在http://localhost:3000浏览器默认会拦截跨源请求。解决跨域的方式有两种最推荐的是在开发环境用 Vue CLI 的代理功能。在vue.config.js里配置module.exports { devServer: { port: 8080, proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } } };配置完成后前端代码里请求/api/xxx时开发服务器会把这个请求转发到http://localhost:3000浏览器角度是同源请求不会触发跨域限制。这种方式的优势是生产环境也不需要改动前端请求路径只要让 Nginx 同样把/api反向代理到后端服务即可。另外一种方案是在后端启用cors中间件设置允许的跨域来源。这个方案配置更简单但安全性需要额外关注生产环境我一般不会把所有来源都放开。4.2 图片上传与静态资源管理动物信息上报和编辑都要上传图片这是所有内容发布类项目的标配功能但实现的坑不少。我选择了multer这个成熟的上传中间件。Express 端基本配置如下const multer require(multer); const path require(path); const fs require(fs); const uploadDir path.join(__dirname, ../uploads); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } const storage multer.diskStorage({ destination: (req, file, cb) cb(null, uploadDir), filename: (req, file, cb) { const uniqueName ${Date.now()}-${Math.round(Math.random() * 1e9)}${path.extname(file.originalname)}; cb(null, uniqueName); } }); const upload multer({ storage, limits: { fileSize: 5 * 1024 * 1024 }, fileFilter: (req, file, cb) { const allowedTypes /jpeg|jpg|png|gif|webp/; const extname allowedTypes.test(path.extname(file.originalname).toLowerCase()); const mimetype allowedTypes.test(file.mimetype); if (extname mimetype) { return cb(null, true); } cb(new Error(仅支持图片文件上传)); } });文件命名用时间戳 随机数 扩展名的方式避免文件名冲突。限制文件大小为 5MB并且只允许常见图片格式否则接口就会被超大文件或恶意脚本拖垮。上传接口返回的应该是可访问的 URL。开发环境我用 Express 静态资源中间件来映射上传目录app.use(/uploads, express.static(path.join(__dirname, uploads)));这样前端拿到类似/uploads/1712345678901-abcd.jpg的路径就能直接展示。生产环境部署时我会在 Nginx 配置一个独立的location /uploads/指向这个目录避免让 Node 服务承担不必要的文件传输压力。4.3 领养审批的状态联动领养审批是业务逻辑里最需要小心处理的环节。前面提到过审批操作涉及两个表的状态更新。我在 Sequelize 里用事务来实现const sequelize require(../config/db); const Adoption require(../models/Adoption); const Animal require(../models/Animal); exports.approveAdoption async (req, res) { const { id } req.params; const t await sequelize.transaction(); try { const adoption await Adoption.findByPk(id, { transaction: t }); if (!adoption) { await t.rollback(); return res.status(404).json({ code: 404, message: 领养申请不存在 }); } adoption.application_status approved; await adoption.save({ transaction: t }); const animal await Animal.findByPk(adoption.animal_id, { transaction: t }); if (animal) { animal.status adopted; await animal.save({ transaction: t }); } await t.commit(); res.json({ code: 200, message: 审批通过 }); } catch (error) { await t.rollback(); res.status(500).json({ code: 500, message: 审批失败 }); } };事务看着简单但它解决了一个非常典型的并发一致性问题。如果没有事务万一更新动物状态失败管理员看到的结果是“领养审批已通过”但动物信息还停留在“待领养”状态用户会以为动物还在继续申请领养整个流程就乱了。凡是涉及多表写操作的接口都应该认真考虑加事务。4.4 搜索、筛选与分页列表页的搜索和筛选功能我前后端两侧联动实现。前端把筛选条件放进请求参数category猫/狗/其他、status领养状态、keyword关键字搜索。后端接口接收这些参数拼 SQL 查询条件。// controllers/animalController.js exports.getList async (req, res) { const { page 1, pageSize 10, category , status published, keyword } req.query; const offset (page - 1) * pageSize; const where {}; if (category) where.category category; if (status) where.status status; if (keyword) { where.name { [Op.like]: %${keyword}% }; } try { const { count, rows } await Animal.findAndCountAll({ where, offset, limit: pageSize, order: [[create_time, DESC]] }); res.json({ code: 200, data: { list: rows, total: count, page: Number(page), pageSize: Number(pageSize) } }); } catch (error) { res.status(500).json({ code: 500, message: error.message }); } };分页参数用page和pageSize而不是 SQL 里的offset和limit原因是在前端语义更清晰。前端拿到响应后更新列表数据和总条数Element UI 的el-pagination组件直接绑定这两个值即可。5. 常见问题与排查技巧实录5.1 npm 脚本执行策略问题这个问题在 Windows 环境几乎人人会遇到。执行npm或vue create时报错npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本。原因前面说过是 PowerShell 执行策略导致的。解决办法就两条以管理员身份打开 PowerShell执行Set-ExecutionPolicy RemoteSigned或者直接改用 CMD 或 Git Bash 来执行 npm 命令我后来统一用 Git Bash 做前端开发终端既避免了 PowerShell 的脚本策略问题又能使用 Linux 风格的命令ls、pwd体验好很多。5.2 后端端口占用与杀进程Express 服务默认跑在 3000 端口有时候代码改崩了终端重启服务时报“端口被占用”或直接没反应。排查步骤如下# 查看端口占用Windows netstat -ano | findstr :3000 # 根据 PID 杀死进程 taskkill /PID PID /FMac/Linux 下则是lsof -i :3000 kill -9 PID端口这类问题本身很简单难的是很多人看到报错就慌其实只要先看端口有没有被残留进程占用然后按上面的命令处理就能解决。5.3 图片上传返回 404 或无法访问上传接口返回成功但前端拿着返回的 URL 访问图片时 404。这种问题几乎都是静态资源映射没有配置或者路径不对。我调试时习惯先直接访问http://localhost:3000/uploads/xxx.jpg如果 404第一时间检查 Express 的静态资源目录配置。生产环境则还要检查 Nginx 配置的alias路径是否正确。另外一个容易忽略的点图片 URL 不要存绝对路径比如http://localhost:3000/uploads/xxx.jpg要存相对路径/uploads/xxx.jpg。否则部署到服务器后数据库里的图片地址全部指向 localhost图片全部裂掉。这个坑我踩过一次最后靠 SQL 批量替换才修复。5.4 Vue 打包后接口路径错误开发环境通过代理跑得好好的npm run build之后部署到服务器接口全部 404。排查思路如下先看打包后的dist文件里接口请求路径是相对路径还是绝对路径。如果请求发到了http://your-server/api/xxx但后端没在这一层看看 Nginx 的反向代理配置是否正确。如果是通用部署建议前端统一用相对路径/api/xxx后端统一接收/api前缀然后通过 Nginx 把/api转发到 Express 服务。我的 Nginx 配置通常长这样server { listen 80; server_name your-domain.com; root /var/www/client/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /uploads/ { alias /var/www/server/uploads/; } }注意location /里的try_files是 Vue Router 使用 history 模式的标配否则刷新子路由页面时会出现 404。这一步经常有人忽略但非常关键。5.5 数据库连接失败的常见排查后端启动时报数据库连接失败我按这个顺序排查效率最高确认 MySQL 服务已启动systemctl status mysql或用服务面板查看。确认数据库账号密码正确且有远程或本地访问权限。检查数据库连接配置里的 host、port、数据库名是否都填对。用命令行工具直接连接一次确认不是后端代码问题而是数据库本身不通。有些校园项目用校园网环境MySQL 如果限制了绑定 IP也会出现后端服务器能连本地但其他机器连不上需要检查bind-address配置。6. 项目部署与环境配置6.1 环境准备Node.js 与 npm服务器上运行这个项目第一步是装好 Node.js 环境。我倾向于用nvmNode Version Manager管理 Node 版本这样多个项目共存时互不干扰。安装命令大致如下curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash nvm install 18 nvm use 18 node -v npm -v生产环境 Node 版本我选 LTS 版本目前用 18 或 20 都比较稳不要盲目追求最新版本稳定优先。6.2 后端部署从克隆到启动后端部署流程就三条命令git clone your-repo-url cd server cp .env.example .env # 修改数据库连接、JWT密钥等 npm install --production npm start # 或者用 pm2 start app.js进程管理我用 PM2它自带了日志记录、自动重启、负载均衡等功能非常适合 Node 服务。常用命令pm2 start app.js --name animal-server pm2 save pm2 startup # 配置开机自启同一台服务器跑多个 Node 项目时PM2 的优势尤其明显互相之间隔离一个挂了不会影响另一个。6.3 前端部署构建与 Nginx 托管前端部署分两步本地或 CI 环境构建产物然后让 Nginx 托管静态文件。cd client npm install npm run build构建完成后dist/目录就是需要部署的全部内容。把它上传到服务器的/var/www/client/dist再配合上文 Nginx 配置即可。6.4 环境变量与数据库连接配置环境变量是部署过程中最容易出错的地方。我用.env文件统一管理后端配置PORT3000 DB_HOST127.0.0.1 DB_PORT3306 DB_NAMEanimal_welfare DB_USERroot DB_PASSWORDyour_password JWT_SECRETyour_jwt_secret这段配置里有两点值得强调第一生产环境的数据库密码和 JWT 密钥绝对不能和本地开发环境一样也不能提交到代码仓库——.env文件必须在.gitignore里第二.env.example要提交到仓库里面只写字段名不写真值方便新成员快速创建自己的配置。7. 项目经验总结与后续扩展这个项目从零到跑通我前后用了将近两周时间但真正宝贵的不是代码量而是对“完整业务闭环”的理解。一个校园流浪动物救助平台虽然不算大但它覆盖了用户认证、内容发布、状态流转、文件上传、权限控制、前后端联调、服务器部署这些所有 Web 项目都会遇到的通用环节把这些吃透了后面做任何系统都会快很多。对准备拿这个项目当毕业设计或求职项目的朋友我额外建议在几个容易出彩的扩充点上花点精力增加公告通知的站内信功能管理员发布领养成功公告时自动推送给申请用户。将救助记录做成时间线组件配合 ECharts 显示每月救助数据统计。加入消息中心用户提交上报或申请后状态变化时给用户发送系统消息。考虑接入地图组件展示校园内流浪动物的分布热点。最后提醒一句技术栈只是手段真正有价值的是把救助流程跑顺、让用户用得舒服。我在做的时候反复问自己“如果我是想领养一只猫的学生我希望这个平台帮我解决什么问题” 以这个视角去打磨产品细节比堆砌任何新奇酷炫的技术都重要。
返回列表