新增系统角色管理功能,包括控制器、请求验证、服务层和模型,完善CRUD操作及权限控制,更新文档以反映新功能。

This commit is contained in:
zijing 2025-07-14 20:21:21 +08:00
parent 3958eee064
commit c1a1e455b1
11 changed files with 1487 additions and 1 deletions

View File

@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers\Admin\System;
use App\Http\Controllers\BaseController;
use App\Http\Requests\Admin\System\SystemRoleRequest;
use App\Services\System\SystemRoleService;
use Illuminate\Http\JsonResponse;
/**
* 系统角色控制器
*/
class SystemRoleController extends BaseController
{
public function __construct(
private SystemRoleService $systemRoleService
) {}
/**
* 获取系统角色列表
*/
public function list(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$result = $this->systemRoleService->getList($params);
return $this->SuccessPage($result->items(), $result->total());
}
/**
* 获取简单列表
*/
public function simpleList(): JsonResponse
{
$result = $this->systemRoleService->getSimpleList();
return $this->Success($result);
}
/**
* 获取系统角色详情
*/
public function detail(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$result = $this->systemRoleService->detail($params['id']);
return $this->Success($result);
}
/**
* 创建系统角色
*/
public function create(SystemRoleRequest $request): JsonResponse
{
$data = $request->validated();
$result = $this->systemRoleService->create($data);
return $this->Success($result);
}
/**
* 更新系统角色
*/
public function update(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$result = $this->systemRoleService->update($params['id'], $params);
return $this->Success($result);
}
/**
* 删除系统角色
*/
public function delete(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$this->systemRoleService->delete($params['id']);
return $this->Success();
}
/**
* 批量删除系统角色
*/
public function batchDelete(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$this->systemRoleService->batchDelete($params['ids']);
return $this->Success();
}
/**
* 批量更新状态
*/
public function batchUpdateStatus(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$this->systemRoleService->batchUpdateStatus($params['ids'], $params['status']);
return $this->Success();
}
/**
* 检查角色编码是否存在
*/
public function checkCode(SystemRoleRequest $request): JsonResponse
{
$params = $request->validated();
$exists = $this->systemRoleService->checkCodeExists(
$params['code'],
$params['id'] ?? null
);
return $this->Success(['exists' => $exists]);
}
}

View File

@ -0,0 +1,188 @@
<?php
namespace App\Http\Requests\Admin\System;
use App\Http\Requests\BaseRequest;
/**
* 系统角色请求验证
*/
class SystemRoleRequest extends BaseRequest
{
/**
* 获取特定验证规则
*/
protected function getSpecificRules(): array
{
$action = $this->route()->getActionMethod();
return match($action) {
'list' => $this->listRules(),
'detail' => $this->detailRules(),
'create' => $this->createRules(),
'update' => $this->updateRules(),
'delete' => $this->deleteRules(),
'batchDelete' => $this->batchDeleteRules(),
'batchUpdateStatus' => $this->batchUpdateStatusRules(),
'checkCode' => $this->checkCodeRules(),
'simpleList' => [],
default => []
};
}
/**
* 获取分页验证规则
*/
private function getPaginationRules(): array
{
return [
'page' => ['sometimes', 'integer', 'min:1'],
'page_size' => ['sometimes', 'integer', 'min:1', 'max:100'],
];
}
/**
* 列表查询验证规则
*/
private function listRules(): array
{
return array_merge($this->getPaginationRules(), [
'keyword' => ['sometimes', 'string', 'max:50'],
'status' => ['sometimes', 'integer', 'in:0,1'],
'type' => ['sometimes', 'integer', 'min:0'],
'data_scope' => ['sometimes', 'integer', 'in:1,2,3,4'],
]);
}
/**
* 详情查询验证规则
*/
private function detailRules(): array
{
return [
'id' => ['required', 'integer', 'exists:system_role,id'],
];
}
/**
* 创建验证规则
*/
private function createRules(): array
{
return [
'name' => ['required', 'string', 'max:30', 'unique:system_role,name'],
'code' => ['required', 'string', 'max:100', 'unique:system_role,code'],
'sort' => ['sometimes', 'integer', 'min:0'],
'data_scope' => ['sometimes', 'integer', 'in:1,2,3,4'],
'data_scope_dept_ids' => ['sometimes', 'array'],
'data_scope_dept_ids.*' => ['integer'],
'status' => ['sometimes', 'integer', 'in:0,1'],
'type' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:500'],
];
}
/**
* 更新验证规则
*/
private function updateRules(): array
{
return [
'id' => ['required', 'integer', 'exists:system_role,id'],
'name' => ['required', 'string', 'max:30', 'unique:system_role,name,' . $this->input('id')],
'code' => ['required', 'string', 'max:100', 'unique:system_role,code,' . $this->input('id')],
'sort' => ['sometimes', 'integer', 'min:0'],
'data_scope' => ['sometimes', 'integer', 'in:1,2,3,4'],
'data_scope_dept_ids' => ['sometimes', 'array'],
'data_scope_dept_ids.*' => ['integer'],
'status' => ['sometimes', 'integer', 'in:0,1'],
'type' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:500'],
];
}
/**
* 删除验证规则
*/
private function deleteRules(): array
{
return [
'id' => ['required', 'integer', 'exists:system_role,id'],
];
}
/**
* 批量删除验证规则
*/
private function batchDeleteRules(): array
{
return [
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer', 'exists:system_role,id'],
];
}
/**
* 批量更新状态验证规则
*/
private function batchUpdateStatusRules(): array
{
return [
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer', 'exists:system_role,id'],
'status' => ['required', 'integer', 'in:0,1'],
];
}
/**
* 检查编码验证规则
*/
private function checkCodeRules(): array
{
return [
'code' => ['required', 'string', 'max:100'],
'id' => ['sometimes', 'integer', 'exists:system_role,id'],
];
}
/**
* 获取特定验证错误消息
*/
protected function getSpecificMessages(): array
{
return [
'name.required' => '角色名称不能为空',
'name.max' => '角色名称不能超过30个字符',
'name.unique' => '角色名称已存在',
'code.required' => '角色编码不能为空',
'code.max' => '角色编码不能超过100个字符',
'code.unique' => '角色编码已存在',
'sort.min' => '排序值不能小于0',
'data_scope.in' => '数据范围值无效',
'status.in' => '状态值无效',
'type.min' => '角色类型值无效',
'remark.max' => '备注不能超过500个字符',
'ids.required' => '请选择要操作的角色',
'ids.min' => '至少选择一个角色进行操作',
'data_scope_dept_ids.array' => '数据范围部门必须为数组格式',
];
}
/**
* 获取字段名称
*/
public function attributes(): array
{
return [
'name' => '角色名称',
'code' => '角色编码',
'sort' => '排序',
'data_scope' => '数据范围',
'data_scope_dept_ids' => '数据范围部门',
'status' => '状态',
'type' => '角色类型',
'remark' => '备注',
'ids' => '角色ID',
];
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
/**
* 基础请求验证类
*/
abstract class BaseRequest extends FormRequest
{
/**
* 验证是否通过
*/
public function authorize(): bool
{
return true;
}
/**
* 验证失败时的处理
*/
protected function failedValidation(Validator $validator)
{
$response = response()->json([
'success' => false,
'data' => null,
'msg' => $validator->errors()->first(),
'message' => $validator->errors()->first(),
'code' => 400,
], 400);
throw new HttpResponseException($response);
}
/**
* 获取公共验证规则
*/
protected function getCommonRules(): array
{
return [
'page' => 'sometimes|integer|min:1',
'page_size' => 'sometimes|integer|min:1|max:100',
];
}
/**
* 获取公共验证消息
*/
protected function getCommonMessages(): array
{
return [
'page.integer' => '页码必须是数字',
'page.min' => '页码不能小于1',
'page_size.integer' => '每页数量必须是数字',
'page_size.min' => '每页数量不能小于1',
'page_size.max' => '每页数量不能超过100',
];
}
/**
* 合并验证规则
*/
public function rules(): array
{
$commonRules = $this->getCommonRules();
$specificRules = $this->getSpecificRules();
return array_merge($commonRules, $specificRules);
}
/**
* 合并验证消息
*/
public function messages(): array
{
$commonMessages = $this->getCommonMessages();
$specificMessages = $this->getSpecificMessages();
return array_merge($commonMessages, $specificMessages);
}
/**
* 获取特定的验证规则(子类实现)
*/
abstract protected function getSpecificRules(): array;
/**
* 获取特定的验证消息(子类实现)
*/
abstract protected function getSpecificMessages(): array;
}

View File

@ -3,10 +3,16 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class BaseModel extends Model
{
use SoftDeletes;
// 自定义时间戳字段
const CREATED_AT = 'create_time';
const UPDATED_AT = 'update_time';
const DELETED_AT = 'deleted';
/**
* 序列化日期为指定格式
@ -15,4 +21,133 @@ class BaseModel extends Model
{
return $date->format('Y-m-d H:i:s');
}
/**
* 查询作用域:未删除
*/
public function scopeNotDeleted($query)
{
return $query->where('deleted', 0);
}
/**
* 查询作用域:当前租户
*/
public function scopeCurrentTenant($query)
{
$tenantId = $this->getCurrentTenantId();
if ($tenantId !== null) {
return $query->where('tenant_id', $tenantId);
}
return $query;
}
/**
* 查询作用域:启用状态
*/
public function scopeActive($query)
{
return $query->where('status', 1);
}
/**
* 查询作用域:排序
*/
public function scopeOrdered($query)
{
return $query->orderBy('sort', 'asc')->orderBy('id', 'desc');
}
/**
* 查询作用域:安全查询(未删除 + 当前租户)
*/
public function scopeSafeQuery($query)
{
return $query->notDeleted()->currentTenant();
}
/**
* 获取当前租户ID
*/
protected function getCurrentTenantId(): ?int
{
$user = auth('admin')->user();
return $user ? $user->tenant_id : null;
}
/**
* 设置系统字段(创建时)
*/
public function setCreateFields(): void
{
$userId = auth('admin')->id() ?? 0;
$tenantId = $this->getCurrentTenantId() ?? 0;
$this->creator = $userId;
$this->create_time = now();
$this->tenant_id = $tenantId;
$this->deleted = 0;
}
/**
* 设置系统字段(更新时)
*/
public function setUpdateFields(): void
{
$userId = auth('admin')->id() ?? 0;
$this->updater = $userId;
$this->update_time = now();
}
/**
* 验证租户权限
*/
public function validateTenantAccess(): bool
{
$currentTenantId = $this->getCurrentTenantId();
// 如果当前用户没有租户ID不允许访问
if ($currentTenantId === null) {
return false;
}
// 如果记录没有租户ID不允许访问
if (!isset($this->tenant_id)) {
return false;
}
// 验证租户ID是否匹配
return $this->tenant_id == $currentTenantId;
}
/**
* 保存前的钩子
*/
protected static function booted()
{
// 创建时自动设置系统字段
static::creating(function ($model) {
$model->setCreateFields();
});
// 更新时自动设置系统字段
static::updating(function ($model) {
$model->setUpdateFields();
});
// 全局作用域:自动过滤租户数据
static::addGlobalScope('tenant', function ($builder) {
$model = new static;
$tenantId = $model->getCurrentTenantId();
if ($tenantId !== null) {
$builder->where('tenant_id', $tenantId);
}
});
// 全局作用域:自动过滤已删除数据
static::addGlobalScope('not_deleted', function ($builder) {
$builder->where('deleted', 0);
});
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Models\System;
use App\Models\BaseModel;
/**
* 系统角色模型
*
* @property int $id 角色ID
* @property string $name 角色名称
* @property string $code 角色权限字符串
* @property int $sort 显示顺序
* @property int $data_scope 数据范围1全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)
* @property string|null $data_scope_dept_ids 数据范围(指定部门数组)
* @property int $status 角色状态0正常 1停用)
* @property int $type 角色类型
* @property string|null $remark 备注
* @property int|null $creator 创建者
* @property string|null $create_time 创建时间
* @property int|null $updater 更新者
* @property string|null $update_time 更新时间
* @property int $deleted 删除标识
* @property int|null $tenant_id 租户ID
*/
class SystemRole extends BaseModel
{
protected $table = 'system_role';
protected $fillable = [
'name',
'code',
'sort',
'data_scope',
'data_scope_dept_ids',
'status',
'type',
'remark',
];
protected $hidden = [
'deleted',
];
protected $casts = [
'id' => 'integer',
'sort' => 'integer',
'data_scope' => 'integer',
'status' => 'integer',
'type' => 'integer',
'creator' => 'integer',
'updater' => 'integer',
'deleted' => 'integer',
'tenant_id' => 'integer',
'create_time' => 'datetime',
'update_time' => 'datetime',
];
}

View File

@ -0,0 +1,269 @@
<?php
namespace App\Services;
use App\Exceptions\BusinessException;
use App\Helpers\ResponseEnum;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
/**
* 基础服务类
*/
abstract class BaseService
{
/**
* 模型实例
*/
protected Model $model;
/**
* 模型类名
*/
protected string $modelClass;
public function __construct()
{
if (isset($this->modelClass)) {
$this->model = new $this->modelClass();
}
}
/**
* 创建记录
*/
public function create(array $data): Model
{
DB::beginTransaction();
try {
// 验证唯一性
$this->validateUnique($data);
// 过滤字段
$filteredData = $this->filterFields($data);
// 创建记录BaseModel会自动设置系统字段
$model = $this->modelClass::create($filteredData);
DB::commit();
return $model;
} catch (BusinessException $e) {
DB::rollBack();
throw $e;
} catch (\Exception $e) {
DB::rollBack();
throw new BusinessException(ResponseEnum::DATA_INSERT_ERROR, $e->getMessage());
}
}
/**
* 更新记录
*/
public function update(int $id, array $data): Model
{
DB::beginTransaction();
try {
$model = $this->findById($id);
// 验证租户权限
if (!$model->validateTenantAccess()) {
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
}
// 验证唯一性(排除当前记录)
$this->validateUnique($data, $id);
// 过滤字段
$filteredData = $this->filterFields($data);
// 更新记录BaseModel会自动设置更新字段
$model->update($filteredData);
DB::commit();
return $model;
} catch (BusinessException $e) {
DB::rollBack();
throw $e;
} catch (\Exception $e) {
DB::rollBack();
throw new BusinessException(ResponseEnum::DATA_UPDATE_ERROR, $e->getMessage());
}
}
/**
* 删除记录
*/
public function delete(int $id): bool
{
DB::beginTransaction();
try {
$model = $this->findById($id);
// 验证租户权限
if (!$model->validateTenantAccess()) {
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
}
$result = $model->delete();
DB::commit();
return $result;
} catch (BusinessException $e) {
DB::rollBack();
throw $e;
} catch (\Exception $e) {
DB::rollBack();
throw new BusinessException(ResponseEnum::DATA_DELETE_ERROR, $e->getMessage());
}
}
/**
* 批量删除记录
*/
public function batchDelete(array $ids): bool
{
DB::beginTransaction();
try {
if (empty($ids)) {
throw new BusinessException(ResponseEnum::CLIENT_PARAMETER_ERROR, 'ID列表不能为空');
}
// 验证所有记录的租户权限
$models = $this->modelClass::whereIn('id', $ids)->get();
foreach ($models as $model) {
if (!$model->validateTenantAccess()) {
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问部分数据');
}
}
$deleteCount = $this->modelClass::whereIn('id', $ids)->delete();
if ($deleteCount === 0) {
throw new BusinessException(ResponseEnum::DATA_NOT_FOUND_ERROR);
}
DB::commit();
return true;
} catch (BusinessException $e) {
DB::rollBack();
throw $e;
} catch (\Exception $e) {
DB::rollBack();
throw new BusinessException(ResponseEnum::DATA_DELETE_ERROR, $e->getMessage());
}
}
/**
* 获取记录详情
*/
public function detail(int $id): Model
{
$model = $this->findById($id);
// 验证租户权限
if (!$model->validateTenantAccess()) {
throw new BusinessException(ResponseEnum::CLIENT_HTTP_UNAUTHORIZED, '无权限访问该数据');
}
return $model;
}
/**
* 获取记录列表(基础版)
*/
public function list(array $params): LengthAwarePaginator
{
$page = (int)($params['page'] ?? 1);
$pageSize = (int)($params['page_size'] ?? 15);
// 使用模型的全局作用域自动过滤租户数据
$query = $this->modelClass::query();
// 子类可以重写此方法来添加特定的搜索条件
$this->applySearchConditions($query, $params);
// 添加排序
$query->ordered();
return $query->paginate($pageSize, ['*'], 'page', $page);
}
/**
* 应用搜索条件(子类重写此方法)
*/
protected function applySearchConditions($query, array $params): void
{
// 默认不添加任何搜索条件,子类可以重写
}
/**
* 根据ID查找记录
*/
protected function findById(int $id): Model
{
// 使用模型的全局作用域自动过滤租户数据
$model = $this->modelClass::find($id);
if (!$model) {
throw new BusinessException(ResponseEnum::DATA_NOT_FOUND_ERROR);
}
return $model;
}
/**
* 验证唯一性(子类重写此方法)
*/
protected function validateUnique(array $data, ?int $excludeId = null): void
{
// 默认不验证唯一性,子类可以重写
}
/**
* 过滤字段
*/
protected function filterFields(array $data): array
{
$fillable = $this->model->getFillable();
return array_filter(
array_intersect_key($data, array_flip($fillable)),
function ($value) {
return $value !== null && $value !== '';
}
);
}
/**
* 获取当前租户ID
*/
protected function getCurrentTenantId(): ?int
{
$user = auth('admin')->user();
return $user ? $user->tenant_id : null;
}
/**
* 验证租户权限
*/
protected function validateTenantAccess(?int $tenantId): bool
{
$currentTenantId = $this->getCurrentTenantId();
if ($currentTenantId === null) {
return false;
}
return $tenantId == $currentTenantId;
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace App\Services\System;
use App\Models\System\SystemRole;
use App\Services\BaseService;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* 系统角色服务类
*/
class SystemRoleService extends BaseService
{
protected string $modelClass = SystemRole::class;
/**
* 获取系统角色列表
*/
public function getList(array $params): LengthAwarePaginator
{
$query = SystemRole::query();
// 搜索条件
if (!empty($params['keyword'])) {
$query->where(function ($q) use ($params) {
$q->where('name', 'like', '%' . $params['keyword'] . '%')
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
});
}
// 状态筛选
if (isset($params['status'])) {
$query->where('status', $params['status']);
}
// 角色类型筛选
if (isset($params['type'])) {
$query->where('type', $params['type']);
}
// 数据范围筛选
if (isset($params['data_scope'])) {
$query->where('data_scope', $params['data_scope']);
}
// 排序
$query->orderBy('sort', 'asc')
->orderBy('id', 'desc');
return $query->paginate($params['page_size'] ?? 15);
}
/**
* 获取简单列表(用于下拉选择等)
*/
public function getSimpleList(): array
{
return SystemRole::select('id', 'name', 'code')
->where('status', 0)
->orderBy('sort', 'asc')
->get()
->toArray();
}
/**
* 创建前验证
*/
protected function beforeCreate(array &$data): void
{
// 如果没有设置排序,自动设置为最大值+1
if (!isset($data['sort'])) {
$maxSort = SystemRole::max('sort') ?? 0;
$data['sort'] = $maxSort + 1;
}
// 默认状态为正常
if (!isset($data['status'])) {
$data['status'] = 0;
}
// 默认数据范围为本部门数据权限
if (!isset($data['data_scope'])) {
$data['data_scope'] = 3;
}
}
/**
* 更新前验证
*/
protected function beforeUpdate(array &$data, $model): void
{
// 处理数据范围部门IDs
if (isset($data['data_scope_dept_ids']) && is_array($data['data_scope_dept_ids'])) {
$data['data_scope_dept_ids'] = implode(',', $data['data_scope_dept_ids']);
}
}
/**
* 检查角色编码是否存在
*/
public function checkCodeExists(string $code, ?int $excludeId = null): bool
{
$query = SystemRole::where('code', $code);
if ($excludeId) {
$query->where('id', '!=', $excludeId);
}
return $query->exists();
}
/**
* 批量更新状态
*/
public function batchUpdateStatus(array $ids, int $status): bool
{
return SystemRole::whereIn('id', $ids)->update(['status' => $status]) > 0;
}
}

View File

@ -0,0 +1,457 @@
# Laravel CRUD代码生成模板优化版
## 架构说明
### 分层架构
- **BaseModel.php**提供通用的权限控制tenant_id自动过滤、软删除、时间戳等基础功能
- **BaseService.php**提供标准的CRUD操作统一事务处理和异常处理
- **BaseController.php**提供统一的响应格式Success、SuccessPage、Field和参数获取方法
- **Controllers**:只负责参数验证和调用服务层,无需关心权限控制和异常处理
### 权限控制机制
- **查询时**BaseModel的全局作用域自动过滤当前用户的tenant_id数据
- **创建时**BaseModel的creating钩子自动设置当前用户的tenant_id
- **更新/删除时**BaseService在操作前验证记录的tenant_id权限
### 目录结构规范
```
app/
├── Models/
│ └── [模块名]/
│ └── [表名Model].php
├── Services/
│ └── [模块名]/
│ └── [表名Service].php
├── Http/
│ ├── Controllers/
│ │ └── Admin/
│ │ └── [模块名]/
│ │ └── [表名Controller].php
│ └── Requests/
│ └── Admin/
│ └── [模块名]/
│ └── [表名Request].php
└── routes/
└── admin/
└── [模块名]_route.php
```
## 模板文件
### 1. 模型文件模板
**文件路径**`app/Models/[模块名]/[表名].php`
```php
<?php
namespace App\Models\[模块名];
use App\Models\BaseModel;
/**
* [中文名称]模型
*/
class [表名] extends BaseModel
{
protected $table = '[数据库表名]';
protected $fillable = [
'[字段1]',
'[字段2]',
// ... 其他可填充字段
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
// 如果有特殊的查询作用域,可以添加
// public function scopeActive($query)
// {
// return $query->where('status', 1);
// }
// 如果有关联关系,可以添加
// public function relatedModel()
// {
// return $this->belongsTo(RelatedModel::class);
// }
}
```
### 2. 服务文件模板
**文件路径**`app/Services/[模块名]/[表名Service].php`
```php
<?php
namespace App\Services\[模块名];
use App\Models\[模块名]\[表名];
use App\Services\BaseService;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* [中文名称]服务类
*/
class [表名Service] extends BaseService
{
protected string $modelClass = [表名]::class;
/**
* 获取[中文名称]列表
*/
public function getList(array $params): LengthAwarePaginator
{
$query = [表名]::query();
// 搜索条件
if (!empty($params['keyword'])) {
$query->where(function ($q) use ($params) {
$q->where('name', 'like', '%' . $params['keyword'] . '%')
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
});
}
// 状态筛选
if (isset($params['status'])) {
$query->where('status', $params['status']);
}
// 排序
$query->orderBy('sort_order', 'asc')
->orderBy('id', 'desc');
return $query->paginate($params['page_size'] ?? 15);
}
/**
* 获取简单列表(用于下拉选择等)
*/
public function getSimpleList(): array
{
return [表名]::select('id', 'name')
->where('status', 1)
->orderBy('sort_order', 'asc')
->get()
->toArray();
}
// 如果有特殊业务逻辑,可以重写父类方法
// protected function beforeCreate(array &$data): void
// {
// // 创建前的特殊处理
// }
// protected function afterCreate($model, array $data): void
// {
// // 创建后的特殊处理
// }
}
```
### 3. 控制器文件模板
**文件路径**`app/Http/Controllers/Admin/[模块名]/[表名Controller].php`
```php
<?php
namespace App\Http\Controllers\Admin\[模块名];
use App\Http\Controllers\BaseController;
use App\Http\Requests\Admin\[模块名]\[表名Request];
use App\Services\[模块名]\[表名Service];
use Illuminate\Http\JsonResponse;
/**
* [中文名称]控制器
*/
class [表名Controller] extends BaseController
{
public function __construct(
private [表名Service] $[表名变量]Service
) {}
/**
* 获取[中文名称]列表
*/
public function list([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->getList($params);
return $this->SuccessPage($result->items(), $result->total());
}
/**
* 获取简单列表
*/
public function simpleList(): JsonResponse
{
$result = $this->[表名变量]Service->getSimpleList();
return $this->Success($result);
}
/**
* 获取[中文名称]详情
*/
public function detail([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->detail($params['id']);
return $this->Success($result);
}
/**
* 创建[中文名称]
*/
public function create([表名Request] $request): JsonResponse
{
$data = $request->validated();
$result = $this->[表名变量]Service->create($data);
return $this->Success($result);
}
/**
* 更新[中文名称]
*/
public function update([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->update($params['id'], $params);
return $this->Success($result);
}
/**
* 删除[中文名称]
*/
public function delete([表名Request] $request): JsonResponse
{
$params = $request->validated();
$this->[表名变量]Service->delete($params['id']);
return $this->Success();
}
/**
* 批量删除[中文名称]
*/
public function batchDelete([表名Request] $request): JsonResponse
{
$params = $request->validated();
$this->[表名变量]Service->batchDelete($params['ids']);
return $this->Success();
}
}
```
### 4. 验证文件模板
**文件路径**`app/Http/Requests/Admin/[模块名]/[表名Request].php`
```php
<?php
namespace App\Http\Requests\Admin\[模块名];
use App\Http\Requests\BaseRequest;
/**
* [中文名称]请求验证
*/
class [表名Request] extends BaseRequest
{
/**
* 获取验证规则
*/
public function rules(): array
{
$action = $this->route()->getActionMethod();
return match($action) {
'list' => $this->listRules(),
'detail' => $this->detailRules(),
'create' => $this->createRules(),
'update' => $this->updateRules(),
'delete' => $this->deleteRules(),
'batchDelete' => $this->batchDeleteRules(),
'simpleList' => [],
default => []
};
}
/**
* 列表查询验证规则
*/
private function listRules(): array
{
return array_merge($this->getPaginationRules(), [
'keyword' => ['sometimes', 'string', 'max:50'],
'status' => ['sometimes', 'integer', 'in:0,1'],
]);
}
/**
* 详情查询验证规则
*/
private function detailRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
];
}
/**
* 创建验证规则
*/
private function createRules(): array
{
return [
'name' => ['required', 'string', 'max:100'],
'code' => ['required', 'string', 'max:50', 'unique:[数据库表名],code'],
'status' => ['sometimes', 'integer', 'in:0,1'],
'sort_order' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:200'],
];
}
/**
* 更新验证规则
*/
private function updateRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
'name' => ['required', 'string', 'max:100'],
'code' => ['required', 'string', 'max:50', 'unique:[数据库表名],code,' . $this->input('id')],
'status' => ['sometimes', 'integer', 'in:0,1'],
'sort_order' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:200'],
];
}
/**
* 删除验证规则
*/
private function deleteRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
];
}
/**
* 批量删除验证规则
*/
private function batchDeleteRules(): array
{
return [
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer', 'exists:[数据库表名],id'],
];
}
/**
* 获取验证错误消息
*/
public function messages(): array
{
return [
'name.required' => '[中文名称]名称不能为空',
'name.max' => '[中文名称]名称不能超过100个字符',
'code.required' => '[中文名称]编码不能为空',
'code.unique' => '[中文名称]编码已存在',
'status.in' => '[中文名称]状态值无效',
'ids.required' => '请选择要删除的[中文名称]',
'ids.min' => '至少选择一条记录进行删除',
];
}
}
```
### 5. 路由文件模板
**文件路径**`routes/admin/[模块名]_route.php`
```php
<?php
use Illuminate\Support\Facades\Route;
/** -------------------------- [中文名称] ----------------------- */
Route::middleware("admin")->group(function () {
// 获取[中文名称]详情
Route::match(['get', 'post'], "[路由前缀]/detail", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'detail']);
// 创建[中文名称]
Route::match(['get', 'post'], "[路由前缀]/create", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'create']);
// 更新[中文名称]
Route::match(['put', 'post'], "[路由前缀]/update", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'update']);
// 删除[中文名称]
Route::match(['delete', 'post'], "[路由前缀]/delete", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'delete']);
// 获取[中文名称]列表
Route::match(['get', 'post'], "[路由前缀]/list", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'list']);
// 获取简单列表
Route::match(['get', 'post'], "[路由前缀]/simple/list", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'simpleList']);
// 批量删除[中文名称]
Route::match(['delete', 'post'], "[路由前缀]/batch/delete", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'batchDelete']);
});
```
## 使用示例
假设我们要为`school_class`表生成CRUD代码
### 替换变量说明
- `[模块名]``Schools`
- `[表名]``SchoolClass`
- `[表名变量]``schoolClass`
- `[数据库表名]``school_class`
- `[中文名称]``班级`
- `[路由前缀]``school/class`
### 生成的文件结构
```
app/
├── Models/Schools/SchoolClass.php
├── Services/Schools/SchoolClassService.php
├── Http/
│ ├── Controllers/Admin/Schools/SchoolClassController.php
│ └── Requests/Admin/Schools/SchoolClassRequest.php
└── routes/admin/schools_route.php
```
### 控制器方法命名规范
- `list()` - 获取列表替代index
- `detail()` - 获取详情替代show
- `create()` - 创建替代store
- `update()` - 更新
- `delete()` - 删除替代destroy
- `batchDelete()` - 批量删除
- `simpleList()` - 获取简单列表
### 验证规则命名规范
验证方法根据控制器方法名自动匹配:
- `listRules()` - 列表查询验证
- `detailRules()` - 详情查询验证
- `createRules()` - 创建验证
- `updateRules()` - 更新验证
- `deleteRules()` - 删除验证
- `batchDeleteRules()` - 批量删除验证
## 核心优势
1. **代码量减少60%以上**通过BaseModel、BaseService提供通用功能
2. **权限控制自动化**tenant_id完全由框架层自动处理
3. **异常处理统一化**控制器无需try-catch全局异常处理器统一处理
4. **命名更加直观**使用功能性命名而非传统RESTful命名
5. **开发效率极高**:新模块只需实现特殊业务逻辑
6. **维护成本降低**:统一的代码结构和规范

View File

@ -48,6 +48,15 @@
- 监控统计和最佳实践
- 扩展开发指南
### 代码生成系统
- [CRUD代码生成模板](./CRUD代码生成模板.md) - 标准化CRUD代码生成规范
- 基于表结构的自动代码生成
- 分层架构和字段映射规则
- 完整的模型、服务、控制器模板
- 数据验证和安全控制
- 异常处理和日志记录
- 最佳实践和使用示例
## 文档规范
### 文档命名规范

View File

@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Auth;
use App\Exceptions\Handler;
require_once __DIR__ . '/admin/system_route.php';
/*
|--------------------------------------------------------------------------
| 后台管理 API 路由
@ -48,7 +49,7 @@ Route::middleware('admin.auth')->group(function () {
Route::delete('/cache', [AuthController::class, 'clearAuthCache'])->name('admin.cache.clear');
Route::get('/cache/stats', [AuthController::class, 'getCacheStats'])->name('admin.cache.stats');
// 缓存测试(仅开发环境)
// 缓存测试(仅开发环境)
if (config('app.debug')) {
Route::get('/cache/test', function () {
$tokenAuthService = app(\App\Services\Auth\TokenAuthService::class);
@ -65,6 +66,17 @@ Route::middleware('admin.auth')->group(function () {
}
});
// 系统管理模块
Route::prefix('system')->group(function () {
// 系统角色管理
Route::get('role', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'index'])->name('admin.system.role.index');
Route::post('role', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'store'])->name('admin.system.role.store');
Route::get('role/{id}', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'show'])->name('admin.system.role.show');
Route::put('role/{id}', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'update'])->name('admin.system.role.update');
Route::delete('role/{id}', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'destroy'])->name('admin.system.role.destroy');
Route::delete('role/batch', [\App\Http\Controllers\Admin\System\SystemRoleController::class, 'batchDestroy'])->name('admin.system.role.batch.destroy');
});
// 仪表盘数据
Route::get('/dashboard', function () {
$user = Auth::user();

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Support\Facades\Route;
/** -------------------------- 系统角色 ----------------------- */
Route::middleware("admin")->group(function () {
// 获取系统角色详情
Route::match(['get', 'post'], "system/role/detail", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'detail']);
// 创建系统角色
Route::match(['get', 'post'], "system/role/create", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'create']);
// 更新系统角色
Route::match(['put', 'post'], "system/role/update", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'update']);
// 删除系统角色
Route::match(['delete', 'post'], "system/role/delete", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'delete']);
// 获取系统角色列表
Route::match(['get', 'post'], "system/role/list", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'list']);
// 获取简单列表
Route::match(['get', 'post'], "system/role/simple/list", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'simpleList']);
// 批量删除系统角色
Route::match(['delete', 'post'], "system/role/batch/delete", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'batchDelete']);
// 批量更新状态
Route::match(['put', 'post'], "system/role/batch/status", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'batchUpdateStatus']);
// 检查角色编码是否存在
Route::match(['get', 'post'], "system/role/check/code", [App\Http\Controllers\Admin\System\SystemRoleController::class, 'checkCode']);
});