Skip to content

常见问题

🔴 常见犯错问题

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 范围
condoradmin1-999
condorshop1000-1999
condorsms2000-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/
  • [ ] 软删除:SoftDeletes trait + 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 失效或未携带。

解决

  1. 重新登录获取 Token
  2. 检查请求头:Authorization: Bearer {token}
  3. 检查 Redis 中 Token 是否存在

错误 4:权限不足

原因:用户角色缺少对应权限。

解决

  1. 检查菜单权限 SQL 是否执行
  2. 检查用户角色是否分配权限
  3. 检查权限标识是否正确

错误 5:Keep-alive 缓存失效

原因:组件名未定义或与路由名不匹配。

解决

vue
<script setup>
defineOptions({ name: 'SystemNotice' });  // 必须与路由 name 一致
</script>

🚀 性能优化建议

  1. 数据库索引:为常用搜索字段添加索引
  2. 关联预加载:使用 with() 避免 N+1 查询
  3. 分页限制:限制每页最大 500 条
  4. Redis 缓存:缓存字典数据、配置项
  5. 前端防抖:搜索输入使用 debounce

📖 相关文档