> 2026年6月26日 | 作者:石像鬼 | 分类:AI编程 · 经验总结
写了16套ERP系统之后,回头看那些反复出现的bug,发现90%的问题都在同一个地方——三个文件的写法不一致。
这篇文章把所有坑列出来,下次再写新系统直接避雷。
// 错误 — FastAPI StaticFiles不支持
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({ history: createWebHistory(), routes })
// 正确
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({ history: createWebHashHistory(), routes })
为什么:FastAPI用app.mount("/", StaticFiles(...))挂载前端。HTML5 History模式的URL是/products,浏览器刷新时直接请求后端,后端没有这个路由返回404。Hash模式的URL是/#/products,始终先加载index.html再由Vue接管。
教训:任何用FastAPI静态文件部署的Vue项目,一律用Hash路由。
undefined
根因:
// 错误 — 返回完整axios响应对象
http.interceptors.response.use(res => res)
// 视图调用
const r = await api.get('/products')
console.log(r.items) // undefined!因为r是axios response,不是data
// 正确 — 返回res.data
http.interceptors.response.use(res => res.data)
教训:拦截器统一返回res.data,所有地方保持一致。
// Login.vue 只存了token
localStorage.setItem('token', r.token)
// router.js 检查的是user
const user = localStorage.getItem('user')
if (!user) next('/login') // 永远进不去
要么统一存token,要么统一存user,不要混用。
api.login is not a function
根因:有三种常见写法,混用就炸:
// 写法A:默认导出axios实例
export default axios.create({baseURL:'/api'})
// Login.vue: import api from '../api'
// api.login → undefined(axios实例上没有.login方法)
// 写法B:默认导出方法对象
export default { login: (d) => http.post('/auth/login', d) }
// Login.vue: import api from '../api'
// api.login → 正常 ✔
// 写法C:命名导出
export const api = { login: (d) => ... }
// Login.vue: import { api } from '../api'
// api.login → 正常 ✔
教训:在所有系统中统一使用一种模式。
# 错误 — 所有订单都是今天
Order(order_date=date.today())
# 正确 — 订单分散在30天内
for i in range(30):
Order(order_date=date.today() - timedelta(days=i))
教训:日期、金额、状态都要随机分散,看板才有趋势可看。
"MedicineBox" is not exported by "@element-plus/icons-vue"
根因:不同版本的Element Plus图标名称不同,MedicineBox在有些版本不存在,用FirstAidKit替代。
教训:构建前先跑一遍build,图标导入错误是编译时就能发现的。
- 先给子Agent读api.js和后端响应示例
- 子Agent写的代码必须验证
- 核心文件(api.js/router.js/App.vue)必须自己写
[Errno 10048]
根因:之前的进程没有杀干净,端口被占用。
# 快速清理
taskkill /F /IM python.exe
教训:写个统一的启停脚本。
if db.query(User).count()==0的判断,旧数据库文件还在就没重新seeded。
教训:改seed.py之前先删数据库文件。
SyntaxError: invalid non-printable character U+FEFF
根因:某些编辑器保存文件时加了UTF-8 BOM头。
$c = Get-Content main.py -Raw -Encoding UTF8
$c = $c -replace '', ''
[System.IO.File]::WriteAllText("main.py", $c, [System.Text.UTF8Encoding]::new($false))
教训:Python文件不要用BOM。
现在我的每套新系统都从这几步开始:
1. 复制一套已验证的系统作为模板
2. 修改database.py里的数据库名
3. 修改main.py里的端口号
4. 修改models.py里的业务模型
5. 写seed.py——50+条真实分散的数据
6. 修改Login.vue里的系统名/图标/功能亮点/配色
7. 修改App.vue里的侧边栏菜单
8. 修改router.js里的路由表
9. pip install + npm install + npx vite build
10. 跑一遍E2E:登录→看板→各模块列表→新增→编辑→删除
16套系统,这套流程从3小时优化到了30分钟。
觉得有用?分享给更多人