新增模块开发
本文以在租户后台新增一个「产品管理」模块为例,介绍从数据库到前端的完整开发流程。
1. 创建数据表
编写迁移文件:
bash
cd server
php think make:migration create_products_table编写迁移内容:
php
public function up()
{
$this->table('products')
->addColumn('tenant_id', 'integer', ['default' => 0, 'comment' => '租户ID'])
->addColumn('name', 'string', ['limit' => 100, 'comment' => '名称'])
->addColumn('price', 'decimal', ['precision' => 10, 'scale' => 2, 'default' => 0])
->addColumn('status', 'integer', ['tiny' => true, 'default' => 1])
->addColumn('sort', 'integer', ['default' => 0])
->addColumn('created_at', 'datetime', ['null' => true])
->addColumn('updated_at', 'datetime', ['null' => true])
->addColumn('deleted_at', 'datetime', ['null' => true])
->addIndex('tenant_id')
->create();
}多租户注意
所有租户级业务表必须包含 tenant_id 字段,Repository 基类的 query() 方法会自动注入 where('tenant_id', TenantContext::id())。
执行迁移:
bash
php think migrate:run2. 生成 CRUD 代码
bash
php think make:crud products --module=product --model=Product自动生成:
后端:
app/model/product/Product.php— 模型app/repository/product/ProductRepository.php— 数据访问层app/service/product/ProductService.php— 业务逻辑层app/tenantapi/controller/v1/product/ProductController.php— 控制器app/tenantapi/validate/v1/product/ProductValidate.php— 验证器app/tenantapi/route/product.php— 路由
前端:
tenant/src/api/product.ts— API 接口tenant/src/views/product/index.vue— 列表页tenant/src/views/product/components/ProductForm.vue— 表单组件
3. 添加菜单权限
在管理后台「系统管理 → 菜单管理」中添加:
- 目录菜单 — 产品管理(type=1)
- 页面菜单 — 产品列表(type=2,组件:
product/index,权限:product.view) - 按钮权限 — 新增/编辑/删除(type=3,权限:
product.store/product.update/product.destroy)
4. 自定义业务逻辑
Repository 层 — 查询条件
php
// app/repository/product/ProductRepository.php
public function getSearchList(array $params, int $page = 1, int $size = 20): array
{
$query = $this->query(); // 自动带 tenant_id 过滤
if (!empty($params['keyword'])) {
$query->whereLike('name', "%{$params['keyword']}%");
}
if (isset($params['status']) && $params['status'] !== '') {
$query->where('status', (int) $params['status']);
}
return $query->order('sort', 'asc')
->order('id', 'desc')
->paginate(['page' => $page, 'list_rows' => $size])
->toArray();
}Service 层 — 业务编排
php
// app/service/product/ProductService.php
public function createProduct(array $data): array
{
// 业务校验...
$product = $this->productRepository->create($data);
// 触发事件(可选)
$this->trigger('product.created', ['product_id' => $product['id']]);
return $product;
}Controller 层 — 请求处理
php
// app/tenantapi/controller/v1/product/ProductController.php
#[Permission('product.store')]
public function store(): Json
{
$data = $this->request->post();
$this->validate($data, ProductValidate::class);
$result = $this->productService->createProduct($data);
return $this->success('创建成功', $result);
}5. 前端开发
API 定义
ts
// tenant/src/api/product.ts
import { myRequest } from '@/utils/request'
export const productApi = {
list: (params: any) => myRequest.get('/tenantapi/products', { params }),
show: (id: number) => myRequest.get(`/tenantapi/products/${id}`),
create: (data: any) => myRequest.post('/tenantapi/products', data),
update: (id: number, data: any) => myRequest.put(`/tenantapi/products/${id}`, data),
destroy: (id: number) => myRequest.delete(`/tenantapi/products/${id}`),
}列表页 hooks
列表页推荐使用 useListPage hook 简化分页、搜索、删除逻辑:
ts
const { list, loading, pagination, searchForm, getList, handleSearch, handleDelete } =
useListPage({
fetchFn: (params) => productApi.list(params),
deleteFn: (id) => productApi.destroy(id),
defaultSearchForm: { keyword: '', status: '' },
})6. 验证
- 执行数据库迁移
- 在菜单管理中添加菜单
- 分配角色权限
- 访问页面测试 CRUD 功能
