☰
Node.js + Vue全栈开发管理系统实战:从数据库设计到上线部署
2026/9/30 3:10:21 网站建设 项目流程

作为一个用 Node.js 和 Vue 写过好几套业务管理系统的老开发,这类"XXX管理系统设计与开发"的标题我一看到就会自动脑补出一整套的前后端架构、权限模型和一堆坑。最近刚好做完一个营商环境行动计划管理系统,从需求梳理到上线部署一路跟下来,踩了不少坑也沉淀了一些经验,趁热打铁把它写出来,希望给准备上手同类项目的朋友一些参考。

这套系统说白了就是一个典型的政府或园区内部使用的任务管理平台:把营商环境相关的年度行动计划录入系统,拆解成具体的任务指标,分配到各个责任单位,然后每个单位定期在系统里填报进展,管理层通过统计看板实时掌握整体推进情况。技术侧用的是前端 Vue 3 + 后端 Node.js(Express) + MySQL,标准的轻量级前后端分离架构。整个项目从零到上线大概花了一个半月,两个人的小团队搞定。

如果你正准备用 Node.js + Vue 做类似的管理系统,或者已经在开发中途遇到了一些坑,这篇文章从项目拆解、技术选型、数据库设计、前后端编码,到最后的部署上线和常见面试问题,都会尽量讲透。

1. 项目需求梳理与整体设计思路

1.1 营商环境行动计划管理系统到底要解决什么问题

这类系统的核心需求其实非常聚焦,就是解决"行动计划从制定到落地之间的断层"。一开始咱们收到的需求文档就几个字——"做一个营商环境行动计划管理系统",但真去业务现场聊一圈就会发现,里面至少包含下面四层诉求:

  • 计划管理层:年度/季度行动计划要建立台账,每个计划包含目标、责任单位、完成时限、经费预算等信息。以前是用 Excel 分发,版本混乱、更新不及时。
  • 任务执行层:计划拆解出来的具体任务,责任单位要在系统里定期填报进展,上传佐证材料,反馈存在的问题。
  • 监督考核层:管理员要能实时看到哪些任务推进缓慢、哪些已经逾期、哪个单位的红黄牌最多,需要自动化的预警统计。
  • 数据沉淀层:企业诉求、问题台账要能追溯,同一类问题反复出现的频率要能统计出来,为下一轮行动计划制定提供依据。

说白了,这不是做一个"好看的后台管理页面",而是要把一套线下工作流程完整搬到线上,让数据的流转和状态的变更形成闭环。这个理解如果不到位,后面做出来的系统大概率就是个空壳——能增删改查,但真正用不起来。

1.2 为什么选 Node.js + Vue,而不是 Spring Boot + 原生 JS

先说结论:这套组合在几十人规模使用的内部管理系统场景下,是性价比最高的选择之一。团队长期做前端,JavaScript 全栈没有语言切换成本,一个人可以从接口写到页面,不用维护两套技术栈。

  • Node.js 侧:选的是 Express 4.x,不整那些花里胡哨的框架。内部管理系统业务本质就是围绕几张核心表的 CRUD 外加一点状态流转逻辑,Express 的中间件机制完全够用,生态里要什么有什么,不需要为了"架构宏大"引入过度设计。对比过 NestJS,它的依赖注入和装饰器风格确实更工程化,但学习曲线和项目初始复杂度都不必要地高了。
  • Vue 侧:Vue 3 + Vite + Element Plus + Pinia,这是当前除了 React 之外最成熟的中后台技术组合。Vue 的模板语法对开发人员友好,Element Plus 的表格、表单、弹窗组件开箱即用,配上 Vite 的秒级热更新,开发体验真的很好。
  • Spring Boot 为什么被排除:不是不好,是太重了。对于这种量级的系统,Spring Boot 加一堆依赖、Java 环境的配置、构建时间,对比 Node.js 的"下载依赖直接跑",效率差太远了。除非团队里全是 Java 背景,否则没必要。

从性能角度说,Node.js 处理这种几十个人同时在线、每天几千次接口调用的场景绰绰有余,单线程事件循环在这种低计算量、高 I/O 的业务型系统里反而很适合。

1.3 系统整体架构与核心模块划分

整个系统划分为三个端:

  • 管理后台(Vue Web):管理员、责任单位填报人员使用,PC 端浏览器访问,包含计划管理、任务管理、进展填报、统计看板、系统管理五个子模块。
  • 后端服务(Node.js API):提供 RESTful API,承载权限校验、业务逻辑、数据读写、文件上传。
  • 数据库(MySQL):所有结构化数据的存储中心,外加 Redis 做会话缓存和验证码存储。

核心模块大概是这样:

模块核心功能关键要点
系统管理用户管理、角色管理、菜单权限使用 RBAC 权限模型,动态路由
行动计划管理年/季度计划建档、编辑、发布计划状态机(草稿-已发布-执行中-已归档)
任务管理任务拆解、责任分配、时间节点设置支持任务与子任务两级结构
进展填报填报内容、佐证材料上传、审核确认填报后进入审核流,审核人可退回
统计看板完成率、逾期率、单位排名、趋势图ECharts 数据可视化,接口聚合统计
企业诉求台账诉求登记、分发、办结、满意度评价类似工单系统的轻量版

2. 数据库设计与接口规划

2.1 核心表结构与字段设计

这套系统我设计了五张核心业务表:plans(行动计划表)、tasks(任务表)、task_progress(进展填报记录表)、appeals(诉求台账表)、users(用户表),外加关联表如plan_responsible_units、user_roles。不追求太高的范式,有些冗余字段是为了查询效率。

以tasks表为例,核心字段包括:

  • id:主键
  • plan_id:所属计划 ID,外键关联 plans 表
  • task_no:任务编号,业务上要是给人看的,比如"YS-2024-001"
  • title:任务名称
  • content:任务内容描述
  • responsible_unit:责任单位名称,这里直接存名称而不是单位表外键,因为责任单位其实做一张独立表更规范,实际开发时我们最初用了外键,后来发现政府侧人员流动大、单位调整频繁,直接存名称反而省了一堆连表和变更逻辑
  • deadline:完成时限
  • status:任务状态(0-未开始,1-进行中,2-已完成,3-已逾期,4-已退回)
  • priority:优先级(1-普通,2-重要,3-紧急)
  • progress_percent:进度百分比,0-100
  • created_at/updated_at:记录创建和更新时间

这里特别说下status字段的设计,一定要预估好未来的扩展。最开始我只设计了未开始、进行中、已完成三个状态,后来业务方说逾期和退回这两个状态也必须单独列出来,因为需要在看板上专门统计逾期数据。所以现在这个字段的值从 0 到 4,好在刚开始就用了整数类型加代码注释,改动成本不大。

2.2 接口设计规范与统一响应格式

后端接口设计遵循一个很朴素的规范:URL 用名词复数,请求方式表达动作。

  • GET /api/plans:获取计划列表
  • POST /api/plans:新建计划
  • PUT /api/plans/:id:修改计划
  • DELETE /api/plans/:id:删除计划
  • GET /api/plans/:id/tasks:获取某计划下的任务列表
  • POST /api/tasks/:id/progress:提交任务进展

所有接口统一返回这样的 JSON 结构:

{ "code": 0, "message": "success", "data": { "items": [], "total": 120 } }

code是业务状态码,0 代表成功,非 0 代表各种错误。前端每个请求拦截器里统一判断 code,是 0 就直接返回 data,否则弹错误提示。这样前端不用每个接口都写重复的错误判断逻辑,省事很多。

2.3 文件上传方案:本地存储还是云存储

进展填报里需要上传佐证材料,就是一些 PDF、图片、压缩包。这个环节看似简单,坑其实不少。

我们最初做的是本地磁盘存储:上传的文件放在服务器的/uploads目录下,接口返回文件的访问路径。这种方式在小规模内网使用没问题,但一旦线上部署用 Nginx 做反向代理,就需要额外配置静态文件映射,而且在多实例部署的情况下,文件会出现存储不一致的问题。

考虑到这个项目只是一台服务器的量级,最终决定用本地存储 + Nginx 静态映射组合,路径通过配置文件统一设置。如果后续量大了再切云存储,接口层做一层封装就行,不影响业务逻辑。

接口设计成POST /api/upload,支持单文件上传,返回文件 ID 和 URL。前端用 Element Plus 的el-upload组件对接,设置action属性指向这个接口,并带上认证 token。

3. 后端 Node.js 关键功能实现

3.1 技术栈与工程结构布局

后端用 Express 4.x,ORM 用 Sequelize 6.x。选 Sequelize 而不是直接写 SQL,主要原因是这个项目的表关系比较复杂,模型关联、查询条件组合很多,手写 SQL 容易出错而且代码量翻倍。但 Sequelize 有个缺点是学习门槛不低,尤其是关联查询的写法。实际开发中遇到复杂统计我直接写原生 SQL 然后包装成 Sequelize 的sequelize.query()调用,怎么方便怎么来。

工程目录结构是这样的:

server/ ├── app.js # 入口文件,初始化 Express ├── config/ │ └── db.js # 数据库配置 ├── routes/ # 路由定义 │ ├── plan.routes.js │ ├── task.routes.js │ ├── auth.routes.js │ └── upload.routes.js ├── controllers/ # 业务逻辑控制器 │ ├── plan.controller.js │ ├── task.controller.js │ └── auth.controller.js ├── services/ # 相对独立的服务层 │ ├── statistics.service.js │ └── reminder.service.js ├── models/ # Sequelize 模型定义 ├── middlewares/ # 中间件 │ ├── auth.middleware.js │ ├── error.middleware.js │ └── rate.limit.middleware.js └── utils/ # 工具函数

这个结构对于业务型管理系统来说足够清晰了,Routes 只做路由分发不写业务逻辑,Controllers 里写业务流程控制,复杂的数据聚合逻辑放到 Services 层,避免 Controller 过于臃肿。

3.2 登录鉴权与权限控制的实现思路

权限这块用的是经典的 RBAC 模型:用户 -> 角色 -> 权限点。数据库里对应users、roles、permissions、user_roles、role_permissions五张表。

JWT 鉴权的流程是:

  1. 登录成功后后端签发一个有效期 2 小时的 JWT token
  2. 前端把 token 存储到 localStorage,并在 axios 请求拦截器里统一加上Authorization: Bearer <token>请求头
  3. 后端写一个auth中间件,每个请求先解析 token 验证身份,通过后把用户信息挂载到req.user上

权限点控制的是接口访问,比如"删除计划"需要plan:delete权限点。中间件里检查当前用户的权限列表,不包含就直接返回 403。

这里有个值得分享的点:政府类系统对密码强度的校验比较关注,我们设置了最少 8 位且必须包含字母和数字的校验规则。密码存储用bcryptjs哈希,不存明文。

3.3 任务逾期自动预警与统计看板接口

逾期预警是这套系统的灵魂功能之一。传统的人工催办方式效率太低,系统里我用node-cron写了一个定时任务,每天早上 9 点执行:

cron.schedule('0 9 * * *', async () => { const overduedTasks = await Task.findAll({ where: { status: { [Op.ne]: 2 }, deadline: { [Op.lt]: new Date() } } }); // 更新状态为逾期 // 生成待办提醒通知相关责任人 });

统计看板的接口是典型的数据聚合操作。前端 ECharts 图表需要的无非是这些数据:各单位任务总数、完成数、逾期数、按期完成率。我写了一个单独的统计数据接口,用原生 SQL 通过GROUP BY和CASE WHEN一次性聚合出列表数据,效率比在 Node.js 里循环处理高得多。

SELECT responsible_unit, COUNT(*) AS total, SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS completed, SUM(CASE WHEN status = 3 THEN 1 ELSE 0 END) AS overdued, ROUND(SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) / COUNT(*) * 100, 1) AS rate FROM tasks GROUP BY responsible_unit ORDER BY rate DESC;

3.4 定时提醒与消息通知

除了看板,任务到期前的提醒也很重要。我设定在任务截止时间前 3 天和当天分别发送提醒。提醒方式目前是系统内部的通知中心(待办消息),在系统顶部的铃铛图标上会显示未读数量。以后可以扩展短信或企业微信通知,接口层已经做了预留。

消息通知表结构基本是这样:notifications(标题、内容、接收人 ID、是否已读、跳转链接)。生成提醒时直接批量插入记录,前端轮询未读数量,这个实现很简单但也非常实用。

4. 前端 Vue 3 + Element Plus 页面开发

4.1 前端工程化搭建与目录结构

前端用的是 Vue 3 + Vite 5 + Element Plus + Pinia + Vue Router 4。这里特别注意 Vue 3 的项目不能用 Vue 2 的写法,刚开始用 Composition API(<script setup>语法)会有些不习惯,但习惯后代码组织确实比 Options API 清晰得多。

路由和菜单的处理是我在前端开发中最想强调的部分。系统有管理员、责任单位填报员、普通查看者三种角色,菜单展示不能做成写死的。我做了动态路由:

  1. 用户登录后,后端返回当前用户拥有的菜单权限列表(这是一个树形结构)
  2. 前端把菜单数据存到 Pinia 里,动态生成侧边栏导航
  3. 对于无需权限的公共页面(登录页、404页)用静态路由,业务页面全部动态挂载
// 动态添加路由 const modules = import.meta.glob('../views/**/*.vue'); function createRoutesFromMenus(menus) { const routes = []; menus.forEach(menu => { if (menu.component) { routes.push({ path: menu.path, name: menu.name, component: modules[`../views/${menu.component}.vue`] }); } if (menu.children) { routes.push(...createRoutesFromMenus(menu.children)); } }); return routes; }

4.2 状态管理:为什么用 Pinia

这个项目用 Pinia 管理三类全局数据:用户信息、菜单权限列表、系统字典数据。Pinia 比 Vuex 4 好在哪?简单说就是更轻、TypeScript 支持更好、去掉了 mutations 直接可以在 actions 里修改 state,心智负担小很多。

状态管理在管理系统里最重要的场景之一就是字典数据。前端经常要显示状态的中文名称,比如任务状态字段值为 2,页面上要显示"已完成"。我把这些字典从后端接口拉一次,之后全局调用,不用每次请求都带状态码到前端翻译。这个看起来小,但管理系统的体验好坏全在这些细节。

4.3 核心页面组件设计与实现细节

计划列表页是典型的"查询列表 + 新增/编辑弹窗"结构。用 Element Plus 的el-table展示,配合el-pagination分页,搜索区放el-input、el-select、el-date-picker。这个页面写起来不难,但要注意筛选条件的数据结构定义,提交查询时是用的GET参数还是 POST body,前后端约定一致就行。

任务详情页是整个系统交互最复杂的页面。左侧展示任务基本信息,右侧是进展填报记录的时间线(el-timeline)。填报人每次提交,都会在这条时间线上新增一条记录,包含填报内容、附件列表、填报人和填报时间。审核人可以看到完整的历史轨迹,这点比在 Excel 里改来改去强太多了。

统计看板页用 ECharts 画了三个图表:任务完成率环形图、各单位进度条形图、近期进展趋势折线图。ECharts 在 Vue 3 下的使用方式是通过echarts.init()获取实例,然后设置option,在组件卸载时记得调用dispose()释放资源避免内存泄漏。

4.4 Axios 封装与拦截器处理

前端与后端通信统一封装了一个request.js工具模块。做的事情包括:

  • 设置基础 URL(通过 Vite 的环境变量读取)
  • 请求拦截器:自动附带 token
  • 响应拦截器:统一处理业务错误码、401 跳转登录页、500 提示服务器异常
service.interceptors.request.use(config => { const { userStore } = usePiniaStore(); if (userStore.token) { config.headers.Authorization = `Bearer ${userStore.token}`; } return config; }); service.interceptors.response.use( response => { const res = response.data; if (res.code !== 0) { ElMessage.error(res.message || '请求失败'); return Promise.reject(new Error(res.message)); } return res.data; }, error => { if (error.response?.status === 401) { router.push('/login'); } else { ElMessage.error(error.message); } return Promise.reject(error); } );

5. 开发环境配置与常见问题排查

5.1 Node.js 安装与环境变量配置

在 Windows 上开发 Node.js 项目,第一步就是安装 Node.js。这里有一个非常容易出现的问题——搜索引擎里大量关于"npm : 无法加载文件 ...\npm.ps1,因为在此系统上禁止运行脚本"的报错,几乎每个 Node 新手都会遇到一次。

这个报错出现的原因是 Windows PowerShell 默认的执行策略是Restricted,不允许运行任何脚本文件,包括 npm 的包装脚本。解决办法有三种:

  • 以管理员身份打开 PowerShell,执行Set-ExecutionPolicy RemoteSigned,然后输入 Y 确认
  • 或者用Set-ExecutionPolicy -Scope CurrentUser RemoteSigned,只对当前用户生效
  • 或者干脆在 CMD 里运行 npm 命令,CMD 不受 PowerShell 执行策略影响

Node.js 安装完成后,环境变量一般会自动配置好,但偶尔会有之前装过其他版本残留的环境变量指向旧路径的情况。安装完建议用node -v和npm -v验证一下,如果版本不对,手动检查系统环境变量里的 PATH 是否指向了正确的 Node.js 安装目录。

官方下载的 Node.js 自带 npm,但在国内下载 npm 包的速度会让你怀疑人生。我强烈建议安装完成后立刻换淘宝镜像源:

npm config set registry https://registry.npmmirror.com

这样后续安装依赖的速度会从分钟级降到秒级。

5.2 npm 配置文件与依赖安装技巧

package.json里的scripts字段是项目开发的入口配置。我的开发环境配置大致是这样的:

{ "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" } }

后端项目一般用一个叫nodemon的工具做热重载。nodemon监听文件变化自动重启 Node 服务,比每次改代码手动node app.js再刷新接口地址要舒服得多。开发时执行nodemon app.js,部署时用node app.js。

依赖安装时有一个小技巧:npm 现在有 package-lock.json 锁版本,多人协作时不要手动删掉这个文件,否则哪天依赖更新了个大版本,代码很可能就运行不起来了。团队里遇到奇怪的问题,第一反应就是先检查环境版本是否一致。

5.3 开发代理配置与前后端联调

前后端分离开发时,最大的痛点是跨域问题。前端跑在http://localhost:5173,后端跑在http://localhost:3000,浏览器会拦截非同源的请求。

解决办法很多,项目中我选择了 Vite 的代理配置,在vite.config.js里设置:

export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } } });

这个配置的意思是:前端发的/api开头的请求,会被 Vite 开发服务器转发到http://localhost:3000,这样浏览器看到的请求是同源的,不会触发跨域拦截。生产环境同样的问题由 Nginx 反向代理解决,后面会讲到。

5.4 前端调试工具 Vue Devtools 的使用心得

第一次接触 Vue 生态的开发者必须安装 Vue Devtools 浏览器插件。在 Chrome 的扩展商店直接搜索安装就行。这个插件能做什么?举例来说:

  • 页面上的组件树一清二楚,哪个组件用了哪个数据一目了然
  • 可以直接在 Devtools 的 Vue 面板里修改组件数据,看页面即时变化,排查"为什么数据变了但页面没更新"这类问题特别好用
  • 查看 Pinia/Vuex 的状态变更历史,定位是哪个 action 改掉了全局数据
  • 查看路由配置和当前路由参数

刚接触 Vue 的开发者,调试时经常在代码里写一堆console.log,有了 Devtools 这个工具,大部分问题可以直接在浏览器里定位,调试效率提升了一个档次。

6. 上线部署与性能优化实战

6.1 服务器环境准备与部署策略

这个项目最终部署在一台 4核8G 的云服务器上,操作系统用的 CentOS 7。部署前做了下面几件事:

  • 安装 Node.js 16 LTS(使用nvm安装,方便切换版本)
  • 安装 MySQL 8.0,创建业务数据库和用户名
  • 安装 Nginx 作为 Web 服务器和反向代理
  • 安装 PM2 用于 Node.js 进程守护

后端启动命令非常简单:

pm2 start app.js --name gsyy-api --max-memory-restart 512M

pm2 save保存当前进程列表,再执行pm2 startup配置开机自启。有了 PM2 以后,进程崩溃会自动重启,不用再担心半夜服务挂掉没人知道。设置--max-memory-restart是为了防止内存泄漏导致的服务器卡死,实测一条命令多一层保障。

6.2 Nginx 配置与域名解析

前端打包产物是纯静态文件,可以用 Nginx 直接托管,同时把/api开头的请求反向代理到后端接口服务。Nginx 配置的核心片段是:

server { listen 80; server_name your-domain.com; # 托管前端静态文件 root /var/www/gsyy/dist; index index.html; # 前端路由刷新时回退到 index.html location / { try_files $uri $uri/ /index.html; } # API 请求反向代理到 Node.js location /api/ { proxy_pass http://127.0.0.1:3000/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 上传文件访问路径 location /uploads/ { alias /var/www/gsyy/uploads/; } }

这个配置里最关键的try_files $uri $uri/ /index.html;是这个思路:Vue Router 默认使用 history 模式,如果直接访问https://your-domain.com/task/1刷新页面,Nginx 会去磁盘上找task/1这个文件,当然找不到。加上这个配置后,找不到文件就回退到index.html,让前端路由自己接管 URL 解析。

6.3 上线前的体检与常见隐患

上线前我习惯给系统做一次全面体检,重点检查这些隐患:

  • 数据库连接的并发上限是否够用,Node.js 层的连接池配置是否合理
  • 定时任务是否会出现重复执行(PM2 集群模式下注意:不要在每个实例里都跑同一份定时任务)
  • 文件上传大小限制是否配置了,multer默认限制可能不够
  • 页面首次加载体积,Vite 构建后是否做了代码分割和组件懒加载

说到组件懒加载,这是 Vue 管理系统首屏优化最立竿见影的手段。Vue Router 里不要直接 import 所有页面组件,而是用动态导入的方式:

component: () => import('../views/plan/PlanList.vue')

这样首屏只加载登录页和公共布局代码,每个业务页面在首次访问时才加载对应 JS,首屏体积能减少一半甚至更多。

6.4 服务器性能优化与安全加固

另外还有几个实践细节供大家参考:

  • MySQL 的查询日志在生产环境要关闭,不然日志文件会急剧膨胀,磁盘被写满的事故我真实遇到过
  • 接口要做频率限制,登录接口尤其重要,防止暴力破解。Express 里用express-rate-limit中间件,对/api/auth接口设置每分钟最多 10 次请求
  • 所有接口统一加了请求体大小限制,express.json({ limit: '2mb' }),防止恶意超大数据拖垮服务器
  • Nginx 配置了 gzip 压缩,前端构建产物里的 JS/CSS 能压缩掉 70% 以上体积

7. 开发踩坑实录与问题速查表

7.1 前后端联调时遇到的经典问题

问题一:vue 项目启动后访问不到接口。

排查过程是这样的:先看浏览器 Network 里请求的状态码,如果是 404,大概率是 Vite 代理的 target 地址配置错误;如果是 CORS 报错,说明代理没生效,检查请求 URL 是不是以/api开头;如果是 500,去服务器上看 PM2 日志定位具体错误。

问题二:npm 安装依赖一直报 ERESOLVE 错误。

这基本可以判定是依赖版本冲突。npm install失败的另一个常见原因是使用了本地缓存的旧版本包,执行npm cache clean --force清缓存,然后删掉node_modules和package-lock.json重新安装。再不行就明确指定版本号。

问题三:表格分页后数据错乱。

这是管理系统开发里特别典型的一个低级但常见的错误——前端分页时只把当前页数据传给后端,但切换页码时查询条件没有带上。排查思路很简单:检查请求参数里pageNum、pageSize和查询条件是否都正确传递,检查后端接口里是否真的用了这些参数做分页查询。

7.2 Vue 组件数据不更新的典型场景

Vue 3 中修改reactive对象的数组内容时,直接用索引赋值会导致响应式丢失,比如state.list[0] = newItem页面不刷新。正确做法是用splice替换。这是个非常隐蔽又让新手百思不得其解的问题。

还有一类问题——数据明明变了但页面没变化——大多是因为直接用ref包裹了深度对象,修改内层属性时没有通过.value访问。我在项目里习惯把列表数据用ref([])声明,后续更新时直接list.value = response.data,整个数组替换,基本不会踩响应式丢失的坑。

7.3 常见报错与解决速查表

下面整理一下这个项目开发里最常遇到的报错,每个都是我自己踩过或者看同事踩过的坑:

错误现象核心原因解决办法
npm 无法加载文件 npm.ps1,禁止运行脚本PowerShell 执行策略限制管理员执行Set-ExecutionPolicy RemoteSigned
Cannot find module 'xxx'依赖没安装或版本不匹配删除 node_modules 和 package-lock.json,重新 npm install
接口 404路由路径错误或代理配置错误检查后端路由定义和 Vite/Nginx 代理配置
跨域 CORS 报错请求源与接口源不一致开发环境配代理,生产环境配 Nginx 反向代理
登录后 token 消失localStorage 被清理,或刷新页面时状态丢失确认 token 持久化存储的位置,检查路由守卫逻辑
前端页面刷新后 404history 模式下 Nginx 没配置 fallbackNginx 配置try_files $uri $uri/ /index.html;
上传文件报 413Nginx 请求大小限制client_max_body_size 20m;

7.4 我的几个独家小经验

最后一个话题,说几个平时文档里很难搜到的经验。

第一,字典数据一定要做缓存。前端把后端返回的字典数据存储在 Pinia 里,应用生命周期内只请求一次。如果不这样做,每个下拉框都要单独发一个请求,系统的接口数量会爆炸式增长。

第二,后端接口设计时最好带一个keyword通用搜索字段。很多管理页面都有搜索需求,但一开始说不全搜索条件。接口层预留一个 keyword 参数,后端做模糊查询,前端搜索框里只需要输入一个值。后续需求方说要加搜索功能,前端配置一行代码就行,不用改后端接口。

第三,时间字段统一用时间戳或标准日期格式存储,不要用字符串拼接。统计看板里"本月完成率"这类需求,最后都要落到 SQL 的日期函数上,如果数据库里存的是乱七八糟的字符串格式,统计功能够你喝一壶。

第四,再忙也要写接口文档。哪怕用最简单的 Markdown 表格,把每个接口的 URL、请求参数、响应结构写清楚。这个项目两个人开发,只有我在写后端,如果不留文档,联调时前端同事三天两头来问字段含义,沟通成本根本不是写文档的十倍。

写在最后

这段时间做下来,我最大的感受是:Node.js + Vue 这套技术组合,非常适合内部管理系统这类业务逻辑清晰但功能点繁多的项目。Node.js 的生态能让后端开发像写前端一样顺畅,Vue 3 的组件化开发让很多复用页面只要写一次就能到处用,尤其适合需要快速响应需求变化的内部系统。

如果你正准备上手这样一套系统,我的建议是别把精力浪费在追求"框架先进"上。项目能跑、能维护、能帮业务方真正解决问题,比用什么技术栈重要一百倍。先想想数据怎么流转、状态怎么变化、谁在用这个系统、有哪些权限边界,这些想清楚了,代码层面的东西都是水到渠成的事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询