常见问题
🔴 常见犯错问题
1. 时间字段使用错误类型
❌ 错误做法
sql
-- 使用 datetime 类型
CREATE TABLE `con_system_user` (
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL
);php
// Model 中使用默认配置
public $timestamps = true;✅ 正确做法
sql
-- 使用 bigint 存储 Unix 时间戳
CREATE TABLE `con_system_user` (
`createtime` bigint DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint DEFAULT NULL COMMENT '更新时间'
);php
// Model 中配置 Unix 时间戳
public $timestamps = true;
protected $dateFormat = 'U'; // Unix 时间戳格式
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';原因:CondorAdmin 统一使用 Unix 时间戳,便于跨时区处理和时间计算。
2. 表名缺少前缀
❌ 错误做法
sql
CREATE TABLE `system_notice` (
`id` int PRIMARY KEY
);✅ 正确做法
sql
CREATE TABLE `con_system_notice` (
`id` int PRIMARY KEY
);原因:统一的 con_ 前缀避免表名冲突,保持项目规范。
3. Model 未配置时间字段常量
❌ 错误做法
php
class SystemNotice extends Model
{
protected $table = 'system_notice';
// 缺少时间字段配置
}报错:Column not found: 'created_at'
✅ 正确做法
php
class SystemNotice extends Model
{
protected $table = 'system_notice';
public $timestamps = true;
protected $dateFormat = 'U';
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';
const DELETED_AT = 'deleted_at';
}4. 前端组件名未定义
❌ 错误做法
vue
<script setup lang="ts">
// 缺少 defineOptions
const config = ref({...});
</script>结果:keep-alive 缓存失效,页面重复渲染。
✅ 正确做法
vue
<script setup lang="ts">
defineOptions({ name: 'SystemNotice' }); // 必须定义
const config = ref({...});
</script>原因:Vue 3 的 setup 语法需要显式定义组件名,用于路由缓存匹配。
5. 硬编码文本未国际化
❌ 错误做法
vue
<template>
<n-button>添加</n-button> <!-- 硬编码中文 -->
</template>结果:切换语言时文本不变。
✅ 正确做法
vue
<template>
<n-button>{{ $t('common.add') }}</n-button>
</template>CondorTable 配置:
typescript
{
key: 'title',
title() { return $t('notice.title'); }, // 函数形式支持响应式
}6. $searchable 类型配置错误
❌ 错误做法
php
protected array $searchable = [
'status' => ['type' => 'string'], // 状态字段误用 string
];结果:搜索 status=1 执行了 LIKE '%1%',查不到精确数据。
✅ 正确做法
php
protected array $searchable = [
'status' => ['type' => 'int'], // 数字/状态用 int(精确)
'title' => ['type' => 'string'], // 文本用 string(模糊)
'createtime' => ['type' => 'timestamp'], // 时间用 timestamp(范围)
];类型说明:
'string'→LIKE '%value%'(模糊搜索)'int'→= value(精确匹配)'timestamp'→BETWEEN start AND end(范围查询)
7. 路由前缀不一致
❌ 错误做法
php
// 后端路由
Route::post('/api/notice/index', [NoticeController::class, 'index']);typescript
// 前端请求
urls: {
index: '/core/condoradmin/notice/index', // 路径不匹配
}结果:404 Not Found
✅ 正确做法
php
// 后端路由
Route::group('/core/condoradmin', function () {
createRoutes('/notice', NoticeController::class);
});typescript
// 前端请求
urls: {
index: '/core/condoradmin/notice/index', // 路径一致
}路由规范:
- 后台管理:
/core/condoradmin/[module] - 前端 API:
/api/condoradmin/[module]
8. CondorTable 列配置错误
❌ 错误做法
typescript
{
key: 'status',
title: '状态', // 静态字符串
form: 'false', // 字符串而非布尔值
operator: 'like', // 状态字段误用 like
}✅ 正确做法
typescript
{
key: 'status',
title() { return $t('common.status'); }, // 函数形式
form: false, // 布尔值
table: true, // 列表显示
operator: '=', // 精确搜索
value: 1, // 默认值
component: {
name: 'n-switch',
props: { checkedValue: 1, uncheckedValue: 0 }
}
}9. 菜单权限 ID 冲突
❌ 错误做法
sql
-- 使用已被占用的 ID
INSERT INTO `con_system_menu_rule` (`id`, ...)
VALUES (100, ...); -- 与系统菜单冲突结果:菜单不显示或覆盖系统菜单。
✅ 正确做法
sql
-- 使用正确的 ID 范围
INSERT INTO `con_system_menu_rule` (`id`, ...)
VALUES (5000, ...); -- 自定义插件从 5000 开始ID 分配规范:
| 插件 | ID 范围 |
|---|---|
| condoradmin | 1-999 |
| condorshop | 1000-1999 |
| condorsms | 2000-2999 |
| 自定义插件 | 5000+ |
10. Model 关联关系未定义
❌ 错误做法
php
// 直接访问关联数据
$notice = SystemNotice::find(1);
echo $notice->user->name; // 报错:Trying to get property of non-object✅ 正确做法
php
// 1. 在 Model 中定义关联
class SystemNotice extends Model
{
public function user()
{
return $this->belongsTo(SystemAdmin::class, 'admin_id');
}
}
// 2. 查询时预加载
$notice = SystemNotice::with('user')->find(1);
echo $notice->user->name; // ✅
// 3. 或在 Controller 中全局配置
protected array $with = ['user'];11. 软删除未启用
❌ 错误做法
php
class SystemNotice extends Model
{
// 缺少 SoftDeletes trait
}sql
-- 表中缺少 deleted_at 字段
CREATE TABLE `con_system_notice` (
`id` int PRIMARY KEY
);结果:删除数据无法恢复。
✅ 正确做法
php
use Illuminate\Database\Eloquent\SoftDeletes;
class SystemNotice extends Model
{
use SoftDeletes;
const DELETED_AT = 'deleted_at';
}sql
CREATE TABLE `con_system_notice` (
`id` int PRIMARY KEY,
`deleted_at` bigint DEFAULT NULL COMMENT '软删除时间'
);12. 权限按钮 is_keep 未设置
❌ 错误做法
sql
-- 按钮权限的 is_keep 为 NULL
INSERT INTO `con_system_menu_rule`
(`id`, `is_keep`, `pid`, `menu_type`, ...) VALUES
(201, NULL, 200, 0, ...); -- 应为 1结果:权限控制失效。
✅ 正确做法
sql
-- 页面菜单
(200, NULL, 1, 1, ...), -- is_keep=NULL, menu_type=1
-- 按钮权限
(201, 1, 200, 0, ...), -- is_keep=1, menu_type=0
(202, 1, 200, 0, ...),规则:
- 页面菜单:
is_keep=NULL,menu_type=1 - 按钮权限:
is_keep=1,menu_type=0,pid=页面ID
13. Controller 未实例化 Model
❌ 错误做法
php
class NoticeController extends Backend
{
protected $model = SystemNotice::class; // 类名字符串
}结果:CRUD 操作失败。
✅ 正确做法
php
class NoticeController extends Backend
{
protected $model;
public function __construct()
{
$this->model = new SystemNotice(); // 实例化对象
parent::__construct();
}
}14. 前端路由未生成
❌ 错误做法
bash
# 直接启动,未生成路由
pnpm dev结果:页面 404。
✅ 正确做法
bash
# 方法1:手动生成
pnpm sa gen-route
pnpm dev
# 方法2:开发模式自动生成
pnpm dev # Vite 监听文件变化自动触发15. 数据权限字段未配置
❌ 错误做法
php
class OrderController extends Backend
{
protected $dataLimit = 'auth';
// 缺少 $dataLimitField
}结果:所有用户看到所有数据,权限失效。
✅ 正确做法
php
class OrderController extends Backend
{
protected $dataLimit = 'auth'; // 或 'personal'
protected $dataLimitField = 'admin_id'; // 必须指定
protected $createdByField = 'admin_id'; // 自动填充
}🔧 调试技巧
后端调试
php
// 1. 打印 SQL 查询
\DB::enableQueryLog();
$result = SystemNotice::where('status', 1)->get();
dd(\DB::getQueryLog());
// 2. 打印日志
use support\Log;
Log::info('Debug', ['data' => $data]);
// 3. 查看日志文件
tail -f runtime/logs/webman.log前端调试
typescript
// 1. 打印响应
console.log('Response:', data);
// 2. 查看 Store
import { useAuthStore } from '@/store';
console.log('Auth:', useAuthStore());
// 3. 查看路由
import { useRoute } from 'vue-router';
console.log('Route:', useRoute());
// 4. 网络面板
// Chrome DevTools → Network → 查看请求详情📋 开发检查清单
后端检查
- [ ] 表名有
con_前缀 - [ ] 时间字段:
bigint+createtime/updatetime - [ ] Model 配置:
$dateFormat = 'U' - [ ] Model 常量:
CREATED_AT/UPDATED_AT/DELETED_AT - [ ] Controller:构造函数实例化
$model - [ ] 配置:
$searchable、$sortable - [ ] 路由前缀:
/core/condoradmin/或/api/condoradmin/ - [ ] 软删除:
SoftDeletestrait +deleted_at字段
前端检查
- [ ] 组件名:
defineOptions({ name: 'xxx' }) - [ ] 国际化:所有文本用
$t() - [ ] CondorTable 列:
title()函数形式 - [ ] API 路径:与后端路由一致
- [ ] 路由生成:
pnpm sa gen-route - [ ] 类型定义:完整的 TypeScript 类型
权限检查
- [ ] 菜单 ID:在正确范围(5000+ 自定义)
- [ ] 页面菜单:
is_keep=NULL,menu_type=1 - [ ] 按钮权限:
is_keep=1,menu_type=0 - [ ] 权限路径:与后端 API 路径一致
❓ 常见报错解决
错误 1:Column not found: 'created_at'
原因:Model 未配置时间字段常量。
解决:
php
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';错误 2:404 Not Found
原因1:路由未生成
解决:pnpm sa gen-route
原因2:路由前缀不一致
解决:检查前后端路由路径
错误 3:Token 过期
原因:Token 失效或未携带。
解决:
- 重新登录获取 Token
- 检查请求头:
Authorization: Bearer {token} - 检查 Redis 中 Token 是否存在
错误 4:权限不足
原因:用户角色缺少对应权限。
解决:
- 检查菜单权限 SQL 是否执行
- 检查用户角色是否分配权限
- 检查权限标识是否正确
错误 5:Keep-alive 缓存失效
原因:组件名未定义或与路由名不匹配。
解决:
vue
<script setup>
defineOptions({ name: 'SystemNotice' }); // 必须与路由 name 一致
</script>🚀 性能优化建议
- 数据库索引:为常用搜索字段添加索引
- 关联预加载:使用
with()避免 N+1 查询 - 分页限制:限制每页最大 500 条
- Redis 缓存:缓存字典数据、配置项
- 前端防抖:搜索输入使用 debounce
📖 相关文档
- 🤖 AI 辅助开发
- 📄 新增页面开发
- 🔌 插件开发指南
- 📦 Backend 控制器
- 🎨 状态管理