新增页面开发
本文档基于 CondorAdmin 模块化架构,指导如何快速创建新的管理页面。
开发流程
完整流程图
1. 后端开发
├── 创建数据库表
├── 创建 Model 模型
├── 创建 Controller 控制器
├── 配置路由
└── 添加菜单权限 SQL
2. 前端开发
├── 创建页面文件
├── 定义类型接口
├── 创建翻译文件
├── 配置路由标签
└── 生成路由
3. 联调测试
└── 功能验证第一步:后端开发
1.1 创建数据库表
表命名规范:con_{plugin_name}_xxx
sql
CREATE TABLE `con_system_notice` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`title` varchar(100) NOT NULL COMMENT '标题',
`content` text COMMENT '内容',
`type` tinyint NOT NULL DEFAULT '1' COMMENT '类型(1=系统通知 2=活动公告)',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '状态(0=禁用 1=启用)',
`weigh` int NOT NULL DEFAULT '0' COMMENT '排序权重',
`createtime` bigint DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint DEFAULT NULL COMMENT '更新时间',
`deleted_at` bigint DEFAULT NULL COMMENT '软删除时间',
PRIMARY KEY (`id`),
KEY `status` (`status`),
KEY `createtime` (`createtime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统公告表';字段规范:
- ID:
int unsigned或bigint unsigned - 时间:
bigint(Unix 时间戳,非 datetime) - 状态:
tinyint NOT NULL DEFAULT 1 - 排序:
weigh int NOT NULL DEFAULT 0 - 字符集:
utf8mb4_unicode_ci
1.2 创建 Model
位置:plugin/condoradmin/app/model/SystemNotice.php
php
<?php
declare(strict_types=1);
namespace plugin\condoradmin\app\model;
use support\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class SystemNotice extends Model
{
use SoftDeletes;
protected $table = 'system_notice';
public $timestamps = true;
protected $dateFormat = 'U'; // Unix 时间戳格式
const CREATED_AT = 'createtime';
const UPDATED_AT = 'updatetime';
const DELETED_AT = 'deleted_at';
protected $guarded = []; // 或指定 $fillable
// 字段类型转换
protected $casts = [
'status' => 'integer',
'type' => 'integer',
'weigh' => 'integer',
];
}关键点:
- ✅ 继承
support\Model - ✅ 使用
SoftDeletestrait - ✅
$dateFormat = 'U'(Unix 时间戳) - ✅ 自定义时间字段常量
- ✅ 添加
declare(strict_types=1);
1.3 创建 Controller
位置:plugin/condoradmin/app/controller/NoticeController.php
php
<?php
declare(strict_types=1);
namespace plugin\condoradmin\app\controller;
use plugin\condoradmin\app\library\Backend;
use plugin\condoradmin\app\model\SystemNotice;
class NoticeController extends Backend
{
protected $model;
// 搜索字段配置
protected array $searchable = [
'title' => ['type' => 'string'], // 模糊搜索
'type' => ['type' => 'int'], // 精确搜索
'status' => ['type' => 'int'],
'createtime' => ['type' => 'timestamp'], // 时间范围
];
// 排序字段白名单
protected array $sortable = ['id', 'weigh', 'createtime'];
// 下拉选择无需权限
protected $noNeedRight = ['selectpage'];
public function __construct()
{
$this->model = new SystemNotice();
parent::__construct();
}
}配置说明:
| 配置项 | 说明 | 示例 |
|---|---|---|
$searchable | 可搜索字段 | ['field' => ['type' => 'string']] |
$sortable | 可排序字段 | ['id', 'createtime'] |
$noNeedRight | 无需权限验证的方法 | ['selectpage'] |
$dataLimit | 数据权限 | 'auth' 或 'personal' |
$hidden | 隐藏字段 | ['password'] |
searchable 类型:
| type 值 | 适用场景 | 查询方式 |
|---|---|---|
'string' | 文本字段 | LIKE 模糊查询 |
'int' | 数字、状态、外键 | = 精确查询 |
'timestamp' | 时间范围 | BETWEEN 查询 |
1.4 配置路由
位置:config/route.php
php
use Webman\Route;
use plugin\condoradmin\app\controller\NoticeController;
Route::group('/api/condoradmin', function () {
// CRUD 完整路由(自动生成 6 个方法)
createRoutes('/notice', NoticeController::class);
// 等价于手动注册:
// Route::post('/notice/index', [NoticeController::class, 'index']);
// Route::post('/notice/add', [NoticeController::class, 'add']);
// Route::post('/notice/edit', [NoticeController::class, 'edit']);
// Route::post('/notice/del', [NoticeController::class, 'del']);
// Route::post('/notice/multi', [NoticeController::class, 'multi']);
// Route::post('/notice/selectpage', [NoticeController::class, 'selectpage']);
})->middleware([
\plugin\condoradmin\app\middleware\AuthToken::class,
\plugin\condoradmin\app\middleware\AuthPermission::class,
]);只读页面(仅查看):
php
// 仅注册 index 方法
Route::post('/notice/index', [NoticeController::class, 'index']);1.5 添加菜单权限
位置:install.sql 或手动执行
sql
INSERT INTO `con_system_menu_rule`
(`id`, `is_keep`, `pid`, `name`, `title`, `icon`, `path`, `component`, `i18nkey`, `menu_type`, `weigh`, `status`, `createtime`, `updatetime`)
VALUES
-- 页面菜单
(200, NULL, 1, 'system_notice', '系统公告', '', '/system/notice', 'view.system_notice', 'route.system_notice', 1, 10, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
-- 权限按钮
(201, 1, 200, 'notice_index', '查看', '', '/api/condoradmin/notice/index', NULL, 'condor.route.view', 0, 0, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(202, 1, 200, 'notice_add', '添加', '', '/api/condoradmin/notice/add', NULL, 'condor.route.add', 0, 0, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(203, 1, 200, 'notice_edit', '编辑', '', '/api/condoradmin/notice/edit', NULL, 'condor.route.edit', 0, 0, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(204, 1, 200, 'notice_del', '删除', '', '/api/condoradmin/notice/del', NULL, 'condor.route.delete', 0, 0, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
(205, 1, 200, 'notice_multi', '批量操作', '', '/api/condoradmin/notice/multi', NULL, 'condor.route.bulk_actions', 0, 0, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());字段说明:
| 字段 | 说明 |
|---|---|
pid | 页面菜单为父菜单 ID(如 1=系统管理),按钮为页面 ID |
name | 页面用路由名,按钮用 {module}_{method} |
path | 页面为前端路由,按钮为后端 API 路径 |
component | 页面为 view.{路由名},按钮为 NULL |
menu_type | 1=菜单,0=按钮 |
is_keep | 按钮为 1,菜单为 NULL |
第二步:前端开发
2.1 创建页面文件
位置:src/views/system/notice/index.vue
vue
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
defineOptions({ name: 'SystemNotice' });
const config = ref<Condor.Table.Config>({
urls: {
index: '/api/condoradmin/notice/index',
add: '/api/condoradmin/notice/add',
edit: '/api/condoradmin/notice/edit',
del: '/api/condoradmin/notice/del',
multi: '/api/condoradmin/notice/multi'
},
rowKey(row) {
return row.id;
},
columns: [
{
type: 'selection',
key: 'id',
title: 'ID',
width: 80
},
{
key: 'title',
title() { return $t('system.notice.title'); },
operator: 'like', // 模糊搜索
rules: [
{ required: true, message: '请输入标题', trigger: 'blur' },
{ min: 2, max: 100, message: '标题长度为 2-100 个字符', trigger: 'blur' }
]
},
{
key: 'type',
title() { return $t('system.notice.type'); },
value: 1,
operator: '=',
component: {
name: 'condor-dict-radio',
props: { code: 'notice_type' }
}
},
{
key: 'content',
title() { return $t('system.notice.content'); },
table: false, // 列表不显示
component: {
name: 'condor-editor' // 富文本编辑器
}
},
{
key: 'status',
title() { return $t('condor.common.status'); },
value: 1,
operator: '=',
component: {
name: 'n-switch',
props: {
checkedValue: 1,
uncheckedValue: 0
}
}
},
{
key: 'weigh',
title() { return $t('condor.common.weigh'); },
value: 0,
operator: false, // 不作为搜索条件
component: {
name: 'n-input-number'
}
},
{
key: 'createtime',
title() { return $t('condor.common.createtime'); },
form: false, // 表单不显示
operator: 'BETWEEN', // 时间范围搜索
render: 'datetime'
},
{
type: 'operate',
title() { return $t('common.operate'); },
width: 120,
buttons: ['edit', 'del']
}
]
});
</script>
<template>
<div class="h-full">
<CondorTable :config="config" />
</div>
</template>CondorTable 列配置速查:
| 配置项 | 说明 | 示例 |
|---|---|---|
key | 字段名 | 'username' |
title() | 列标题(函数,支持 i18n) | () => $t('xxx.username') |
operator | 搜索操作符 | 'like' / '=' / 'BETWEEN' / false |
table | 是否在列表显示 | false(默认 true) |
form | 是否在表单显示 | false(默认 true) |
value | 默认值 | 1 |
rules | 表单验证规则 | [{ required: true }] |
component | 表单组件 | { name: 'n-input' } |
render | 列渲染类型 | 'datetime' / 'image' |
常用组件:
| 组件 | 用途 | 配置示例 |
|---|---|---|
n-input | 文本输入 | { name: 'n-input' } |
n-input-number | 数字输入 | { name: 'n-input-number' } |
n-switch | 开关 | { name: 'n-switch', props: { checkedValue: 1, uncheckedValue: 0 } } |
condor-dict-radio | 字典单选 | { name: 'condor-dict-radio', props: { code: 'dict_code' } } |
condor-dict-select | 字典下拉 | { name: 'condor-dict-select', props: { code: 'dict_code' } } |
condor-select | 远程下拉 | { name: 'condor-select', props: { url: '/api/xxx/selectpage' } } |
condor-editor | 富文本 | { name: 'condor-editor' } |
condor-upload | 文件上传 | { name: 'condor-upload', props: { type: 'image' } } |
2.2 定义类型接口
位置:src/views/system/notice/types/i18n.d.ts
typescript
export interface SystemNoticeSchema {
title: string;
content: string;
type: string;
status: string;
weigh: string;
createtime: string;
updatetime: string;
}注册到全局(可选):
如果需要全局类型提示,在 src/typings/i18n/index.d.ts 添加:
typescript
import type { SystemNoticeSchema } from '@/views/system/notice/types/i18n';
declare global {
namespace App.I18n {
interface PageSchema {
system: {
notice: SystemNoticeSchema;
// ... 其他页面
};
}
}
}2.3 创建翻译文件
中文翻译
位置:src/views/system/notice/locales/zh-cn.ts
typescript
import type { SystemNoticeSchema } from '../types/i18n';
const local: SystemNoticeSchema = {
title: '标题',
content: '内容',
type: '类型',
status: '状态',
weigh: '排序',
createtime: '创建时间',
updatetime: '更新时间'
};
export default local;英文翻译
位置:src/views/system/notice/locales/en-us.ts
typescript
import type { SystemNoticeSchema } from '../types/i18n';
const local: SystemNoticeSchema = {
title: 'Title',
content: 'Content',
type: 'Type',
status: 'Status',
weigh: 'Weight',
createtime: 'Create Time',
updatetime: 'Update Time'
};
export default local;翻译入口
位置:src/views/system/notice/locales/index.ts
typescript
import zhCn from './zh-cn';
import enUs from './en-us';
export default {
'zh-CN': zhCn,
'en-US': enUs
};2.4 配置路由标签
位置:src/locales/langs/zh-cn.ts 或专门的 route.ts
typescript
const locale: App.I18n.Schema = {
route: {
system_notice: '系统公告'
}
};英文:src/locales/langs/en-us.ts
typescript
const locale: App.I18n.Schema = {
route: {
system_notice: 'System Notice'
}
};2.5 生成路由
bash
# 生成路由
pnpm sa gen-route
# 类型检查
pnpm typecheck
# 代码检查
pnpm lint自动生成的文件(不要手动编辑):
src/router/elegant/routes.tssrc/router/elegant/imports.tssrc/router/elegant/transform.tssrc/typings/elegant-router.d.ts
第三步:联调测试
3.1 启动服务
bash
# 后端
cd condor-webman
php start.php start
# 前端
cd condor-admin
pnpm dev3.2 功能验证
- ✅ 菜单显示正常
- ✅ 列表查询
- ✅ 搜索过滤
- ✅ 新增数据
- ✅ 编辑数据
- ✅ 删除数据
- ✅ 批量操作
- ✅ 权限控制
高级场景
多语言表(TranslatableBackend)
后端 Controller:
php
<?php
namespace plugin\condoradmin\app\controller;
use plugin\condoradmin\app\library\TranslatableBackend;
use plugin\condoradmin\app\model\SystemNotice;
use plugin\condoradmin\app\model\SystemNoticeTranslations;
class NoticeController extends TranslatableBackend
{
protected $model;
protected $translationModel = null;
// 多语言字段
protected array $multilingualFields = ['title', 'content'];
protected array $searchable = [
'title' => ['type' => 'string'],
'status' => ['type' => 'int'],
];
protected array $sortable = ['id', 'weigh', 'createtime'];
public function __construct()
{
$this->model = new SystemNotice();
$this->translationModel = new SystemNoticeTranslations();
parent::__construct();
}
}翻译表结构:
sql
CREATE TABLE `con_system_notice_translations` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`main_id` int unsigned NOT NULL COMMENT '主表ID',
`locale` varchar(10) NOT NULL COMMENT '语言(zh-cn/en-us)',
`title` varchar(100) DEFAULT NULL COMMENT '标题',
`content` text COMMENT '内容',
PRIMARY KEY (`id`),
UNIQUE KEY `main_locale` (`main_id`,`locale`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;自定义查询
php
public function index(Request $request)
{
// 自定义查询逻辑
$query = $this->getQueryBuilder();
// 添加额外条件
$query->where('status', 1);
$query->with(['user', 'category']);
// 继续使用 Backend 的分页逻辑
return parent::index($request);
}数据权限
php
class NoticeController extends Backend
{
// 启用数据权限
protected $dataLimit = 'auth'; // 或 'personal'
// 数据权限字段
protected $dataLimitField = 'admin_id';
}最佳实践
1. 表设计
- ✅ 使用 Unix 时间戳(bigint)而非 datetime
- ✅ 添加
status、weigh标准字段 - ✅ 添加
createtime、updatetime、deleted_at - ✅ 字段名使用有意义的英文单词
- ✅ 添加字段注释
2. 控制器
- ✅
$model在构造函数中实例化 - ✅
$searchable配置可搜索字段 - ✅
$sortable限制可排序字段 - ✅ 使用
protected array类型声明
3. 前端页面
- ✅ 使用
CondorTable配置模式 - ✅ 所有标题使用
$t()国际化 - ✅ 配置合适的表单验证规则
- ✅ 选择合适的表单组件
4. 翻译
- ✅ 前后端翻译键保持一致
- ✅ 使用类型接口约束翻译内容
- ✅ 提供中英文双语
常见问题
Q1: 菜单不显示?
检查:
- SQL 菜单是否正确插入
menu_type是否为 1status是否为 1- 当前用户是否有权限
Q2: 列表查询失败?
检查:
- 后端路由是否注册
- Controller 是否继承 Backend
$model是否正确实例化- 数据库表是否存在
Q3: 表单提交失败?
检查:
- 字段名是否与数据库一致
- 验证规则是否正确
- API 路径是否正确
- 权限是否配置