常见问题
本章按问题链路组织排查入口。遇到问题时先看浏览器 Network 和 Console,再看相关源码,不要先通过删除校验、放开权限或回退到 Mock 来掩盖错误。
安装与启动
依赖安装失败怎么办?
依次确认:
node --version
pnpm --version项目要求 Node.js >= 20.19.0、pnpm >= 8.8.0。确认使用 pnpm install,没有混用 npm 或 Yarn。CI 中建议使用:
pnpm install --frozen-lockfile端口 3000 被占用怎么办?
修改 .env:
VITE_PORT = 3001重新运行 pnpm dev。
修改环境变量为什么没生效?
Vite 在启动时读取环境文件。停止开发服务并重新运行 pnpm dev。同时确认变量以 VITE_ 开头,且修改的是当前模式对应文件。
登录与会话
项目是否完全不需要后端?
不是。登录、退出和当前用户使用真实 API。业务页面可以暂时读取预置数据,但系统至少需要:
POST /api/v1/auth/signin
POST /api/v1/auth/logout
GET /api/v1/user/info登录接口成功,为什么仍提示登录失败?
检查统一响应是否为:
{
"code": 200,
"msg": "登录成功",
"data": {
"accessToken": "non-empty-token"
}
}accessToken 必须是非空字符串。检查 Network 中返回值,不要只看 HTTP 200。
登录后为什么进入 500 页面?
常见原因:
/api/v1/user/info缺少id、username或email。roles、buttons不是字符串数组。buttons同时包含*和其他权限码。- 远程菜单结构不合法。
Console 会输出更具体的校验错误。
刷新页面后为什么回到登录页?
项目会恢复本地 Access Token,然后重新请求 /api/v1/user/info。检查:
- Token 是否写入应用 LocalStorage。
- 请求是否携带
Authorization: Bearer <token>。 - 当前用户接口是否接受该 Token。
- Token 是否已经过期。
当前没有 Refresh Token 协议,过期后返回登录页是预期行为。
如何接入 Refresh Token?
需要在 src/api/auth.ts 中增加刷新接口,并修改请求层和用户 Store,集中处理令牌保存、并发失败请求和刷新失败登出。不要在页面或 Service 中定义刷新接口,也不要让每个 API 分别刷新 Token。
接口与代理
开发环境接口 404 怎么排查?
检查 .env.development:
VITE_API_URL = /
VITE_API_PROXY_URL = http://localhost:13000确认后端真实路径包含 /api/...,并检查 vite.config.ts 的代理是否符合后端路径。修改环境变量后重启开发服务。
为什么出现 CORS 错误?
开发环境优先使用相对路径和 Vite 代理。生产环境优先使用同源网关。如果必须直接跨域,后端需要正确返回允许源、方法和请求头。
使用 Bearer Token 时通常保持:
VITE_WITH_CREDENTIALS = false只有使用跨域 Cookie 会话且后端已正确配置时才开启。
接口返回了数据,页面为什么拿不到?
统一请求层会从 { code, msg, data } 中返回 data。如果后端使用其他格式,需要在 src/utils/http 统一适配。不要让页面再读取 response.data.data。
能否让接口失败时自动显示预置数据?
不建议。这样会掩盖生产接口故障,让用户看到与服务端不一致的数据。页面必须显式选择 src/mock 或 src/api。
菜单与权限
本地菜单和远程菜单怎么选?
- 菜单结构跟随前端版本发布:使用
local。 - 后端需要按账号、租户动态下发完整菜单:使用
remote。
配置:
VITE_MENU_SOURCE = local本地菜单为什么少了一部分?
检查当前用户 roles 与路由 meta.roles。未声明角色的路由默认可见,非空数组要求至少匹配一项,空数组表示不允许任何用户访问。
远程菜单为什么注册失败?
检查:
data是否为数组。name是否非空且全局唯一。- 子路由是否误用
/开头。 component是否为src/views下的安全路径。meta.title是否存在。- 外链是否为 HTTP(S)。
- 空目录是否没有页面、子节点、外链或 iframe。
菜单能看到,按钮为什么不显示?
确认路由配置:
meta: {
permissionPrefix: 'system:user',
authList: [{ title: '新增', authMark: 'add' }]
}用户接口应返回:
{
"buttons": ["system:user:add"]
}页面再使用 v-auth="'add'" 或 hasAuth('add')。
隐藏按钮是否已经足够安全?
不够。用户可以手工请求接口。后端必须重新检查身份、权限、数据范围和资源归属。
本地数据与写操作
为什么新增、编辑、删除后没有保存?
这是未接后端页面的预期行为。项目明确提示“当前不会写入服务端”,避免浏览器伪持久化掩盖接口缺失。按接口接入迁移对应写接口。
能否用 LocalStorage 保存业务表数据?
不建议。LocalStorage 不具备服务端鉴权、事务、审计、备份和多用户一致性,也不适合保存敏感业务数据。
什么时候可以删除 src/mock?
当对应业务域的查询和写操作都已迁移,项目中不再导入该目录,并完成空状态、错误和权限验收后再删除。按业务域逐步清理,不要一次删除全部预置数据。
表格与页面
替换 API 后表格为空怎么办?
检查列表和总数字段是否能被适配。常见列表字段有 records、list、items、rows,总数字段有 total、count。单页差异使用 responseAdapter。
搜索后页码为什么没有回到第一页?
使用 useTable 的 replaceSearchParams,不要直接修改查询参数后执行普通刷新。
页面为什么出现两个滚动条?
标准列表页使用 art-full-height 与 art-table-card。检查是否额外添加固定高度、多层卡片或外层 overflow。
表头搜索历史可以保存手机号吗?
不可以默认保存。手机号、证件号、邮箱、账号、订单号等敏感或可识别信息不应进入搜索历史。搜索历史默认关闭。
主题与配置
修改 SETTING_DEFAULT_CONFIG 后为什么界面没变化?
浏览器恢复了已持久化的 setting Store。通过设置面板重置,或清理本应用命名空间下的设置键。不要执行 localStorage.clear()。
暗色模式为什么还有白色区块?
搜索页面中硬编码的 #fff、white 和只支持亮色的第三方样式。替换为项目表面 Token,并检查 Element Plus 是否误导入默认 CSS。
如何修改 Logo、系统名称和登录欢迎语?
系统基础名称位于 src/config/index.ts,站点公共信息由 siteSettingsStore 获取,默认数据在 src/mock/system/site-setting.ts。需要后台管理时迁移到真实 API,不要在多个页面分别硬编码。
构建与部署
pnpm build 为什么失败?
pnpm build 先执行 vue-tsc --noEmit。先查看最前面的 TypeScript 错误,再处理 Vite 构建问题。正式发布建议直接执行:
pnpm release:check部署后页面空白怎么排查?
重点检查:
- Console 中的 JS 错误。
index.html中静态资源路径。- 动态 Chunk 是否 404。
VITE_BASE_URL是否与部署目录一致。- 服务器是否返回了错误的 MIME 类型或 HTML 错误页。
子目录部署为什么资源 404?
构建前设置:
VITE_BASE_URL = /admin/重新构建,并让服务器把 /admin/ 正确映射到整个 dist 目录。不能只移动已经按根路径构建的产物。
为什么新版本发布后用户仍看到旧页面?
检查 index.html 和 version.json 是否被长期缓存。带 Hash 的静态资源可以 immutable 缓存,但入口 HTML 和版本文件应使用短缓存或 no-store。
Hash 路由还需要 Nginx 回退吗?
Hash 后的业务路径不会发送给服务器,通常不依赖每条业务路由的回退。保留 try_files $uri $uri/ /index.html 有助于处理站点入口和其他静态路径。
安全与交付
可以把 API Key 放进 .env.production 吗?
不可以。所有 VITE_ 环境变量都会进入浏览器构建产物。AI、对象存储、支付和签名密钥必须放在服务端。
为什么安全检查禁止直接使用 v-html?
动态 HTML 可能带来 XSS。业务页面应通过 ArtSafeHtml 和 DOMPurify 白名单渲染,后端也需要在写入和输出阶段校验内容。
交付前最少执行什么?
pnpm release:check然后按构建部署完成生产预览、权限账号、业务写操作、移动端、暗色主题和发布后验收。
