--- description: nl-admin 后端(Laravel 13 + PHP 8.3 + 自动路由)代码规范 alwaysApply: true --- # 技术栈基线(升级后必守) - **Laravel 13**(`composer.json`:`laravel/framework: ^13.0`) - **PHP ≥ 8.3**(Laravel 13 官方最低要求;禁止按 8.2 写法或回退依赖) - 应用启动走 `bootstrap/app.php` 的 fluent API(`withRouting` / `withMiddleware` / `withExceptions`),**不要**再按旧版 `Http/Kernel` 拆分中间件与异常 - 代码风格优先 `laravel/pint`;测试栈为 PHPUnit 12 - Laravel 13 的 PHP Attribute(如 `#[Middleware]`、`#[Authorize]`、Job 的 `#[Tries]` 等)可用,但本项目的 **HTTP 谓词仍以 PHPDoc `@Method` 为准**(`autoRouteRegister` 扫描依赖它) # 基础规范(所有项目通用) 1. 写代码的时候要补充详细的中文注释(每个方法是干嘛的,为什么要这样写),如果是工作区,则所有项目都适用该规则 2. 注意不要生成太多的空行,上一部分代码和下一部分代码中间的空行不要大于 2 行 3. 有封装好的方法、组件需要复用,不要重复造轮子 4. 小程序端的抽屉全部需要用 page-container 来防止用户意外退出页面(本仓库为 API,此项约束 uniapp) 5. 数据库的(created_at、updated_at、deleted_at)统一使用时间戳,不要使用字符串,并且我在查询器中一级格式化成字符串了,无需再次格式化 # 数据库变更(强制 SQL,禁止新建 PHP Migration) - **禁止**为业务/系统表 DDL 新建 `database/migrations/*.php`(Laravel migrate 不作变更载体) - **一律**写到 `database/sql//`,文件名:`01_简短英文名.sql`、`02_...`(当天序号递增) - 例:`database/sql/2026-08-14/01_cc_carousel_add_status.sql` - 脚本尽量幂等(`information_schema` + `PREPARE`,风格对齐已有 `rbac_migrate_ddl.sql`) - 系统表结构若影响全新安装,同步回写 `public/nl_admin.sql`;业务表 `cc_*` 只放 `database/sql/`,不进 `nl_admin.sql` - 运维在目标库手动执行对应日期目录下的 SQL;不要指望 `php artisan migrate` 补列/补表 # 全局架构规范 ## 分层架构(Controller → Service → Model,禁止跨层) 严格遵循三层架构,禁止跨层调用: - **Controller**(`app/Http/Controllers/Api/` 业务接口,`app/Http/Controllers/core/` 代码生成/安装等):只做参数接收、调用 Service、统一返回(`jok/jerr`),**禁止写业务逻辑** - **Service**(业务放 `app/Service/`,通用能力放 `app/Service/common/`,代码生成等放 `app/Service/core/`):业务规则、数据组装、事务控制都在这里 - **Model**(`app/Models/*Model.php`,扁平目录):**只定义表名、连接、字段黑名单 `$guarded=[]`、访问器**,禁止写业务查询方法(如 `getXxxByCondition` 应放 Service) 跨多个 Service 共用的工具放 `app/Service/common/UtilsService.php`(已存在)或 `app/Service/common/<域>/`。 **本项目是单端管理后台骨架**,不要照搬其他项目的多端目录(`mobile` / `DoctorWx` / `ClinicAdminWx` 等)。 ## 基类强制继承(不要直接继承框架原生基类) - 控制器必须继承 `App\BaseApp\BaseController` - 需要登录态的服务继承 `App\BaseApp\BaseService`;登录等免鉴权服务继承 `App\BaseApp\BaseNotAuthService` - 调用方统一单例:`XxxService::getInstance()` - 模型必须继承 `App\BaseApp\BaseModel`(`$connection = 'mysql'`),**不要**直接继承 `Illuminate\Database\Eloquent\Model` - 本项目**没有** `BaseOldModel` / `old_mysql` 老库分层,禁止再引入 - HTTP 客户端继承 `App\BaseApp\BaseClient`,禁止在业务代码里直接 `new Client()` - 控制器构造里按需设置 `$this->service`、`$this->insertField` / `$this->updateField` / `$this->notRequest`(参考 `AdminController`) ## 通用方法封装(避免复制粘贴) - 禁止在 Controller 直接复用业务逻辑,必须抽到 Service - 禁止在多个 Service 中复制粘贴相同逻辑,必须抽到 `app/Service/common/` - 若后续引入队列:统一放 `app/Jobs/<域>/`,实现 `ShouldQueue` + `Queueable`;单 Job 可用 `->onQueue('xxx')`,多 Job 默认路由优先用 Laravel 13 的 `Queue::route(Job::class, connection: 'redis', queue: 'xxx')` 集中声明(当前仓库尚未建 Jobs,按需新增) ## 路由规范(自动注册,禁止手写业务路由) - 业务路由在 `routes/api.php` 用 `UtilsService::getInstance()->autoRouteRegister([...])` 注册 - **只建 Controller 不注册会 404**;免登录与需登录分两组 `autoRouteRegister`(见现有 `api.php`) - 映射键用 kebab-case(如 `'admin' => AdminController::class`),方法名小驼峰自动转连字符(`myInfo` → `/admin/my-info`) - 空前缀 `'' => LoginController::class` 表示根路径方法(如登录) - 控制器每个方法必须用 PHPDoc `@Method GET/POST/NO` 声明 HTTP 谓词,未声明默认 `any`,`NO` 表示跳过 - **禁止**手写业务 `Route::get/post`(安装向导等极少数例外可保留,如现有 `/sql/*`) - `helpers.php` 里的 `cc_auto_route_register` 与 Utils 方法能力类似,**新代码以 `routes/api.php` 现有写法为准** ## 第三方对接规范 - 第三方 HTTP 客户端放 `app/Service/common/`(或后续建 `common/http/`),命名 `XxxApiClient` / `XxxClient`,继承 `BaseClient` - 需要工厂/策略时定义 `XxxInterface`,实现类与接口同域存放 - 密钥走 `config/nl.php` + `.env`,**禁止在代码中硬编码** - **禁止**再引入其他项目残留约定:`config/xk.php`、`config/ase.php`、`EncryptorService`、`VipGateService`、`mes/` 等 ## 响应与异常 - 成功返回 `jok($data, $msg)`,失败返回 `jerr($msg)`(定义在 `config/response.php`) - 业务异常抛 `UtilsService::getInstance()->errorThrow($msg)`(或 Service 内 `$this->utils->errorThrow($msg)`) ## 常量管理 - 枚举值必须用 PHP native `enum`(PHP 8.3+)放 `app/Enum/`,禁止在代码中散落魔法数字 - 状态约定以现有枚举为准:`StatusEnum` / `UserStatusEnum` 为 **0=正常,1=禁用/冻结**(不要写成其他项目的 1 启用 0 禁用) - 新增状态类字段优先复用或扩展 `app/Enum/` 中的枚举 - CSRF / 请求伪造防护中间件类名以 Laravel 13 为准:`PreventRequestForgery`(旧名 `VerifyCsrfToken` 仅为兼容别名,新代码不要再写) ## 命名规范 | 维度 | 规范 | 示例 | |---|---|---| | 类名 | PascalCase | `AdminService`、`MenuController` | | 方法名 | camelCase | `getPageList`、`changePassword` | | 文件名 | 与类名同名 PascalCase | `AdminService.php` | | 命名空间 | PSR-4,目录大小写与现有一致 | `App\Http\Controllers\Api`、`App\Service\common` | | 数据库物理表 | 前缀 `nl_`(`DB_PREFIX`),全小写下划线 | `nl_admin`、`nl_menu` | | 模型 `$table` | **无前缀**表名(由 `DB_PREFIX` 拼接) | `admin`、`menu`、`role_menu_relations` | | 数据库字段 | snake_case | `created_at`、`role_id`、`nick_name` | | 配置键 | snake_case | `config('nl.xxx')` | ## 注释规范 - 每个类必须有类级注释,说明用途 - 每个 public 方法必须有详细中文注释,包括「做什么」「为什么这样写」「关键参数说明」 - 复杂的 private 方法也要注释 - 不要写「// 自增主键」这种废话注释,注释要解释**意图** ## 代码生成 - 模板在 `app/template/`:`view/`(PC Vben)与 `uniapp/`(移动端)两套并存;服务在 `app/Service/core/CodeGenerationService` - **`generate` 必须同时产出** zip 内的 `view//` 与 `uniapp//`,缺一不可 - 生成物需仍遵守本文件的分层、基类、路由注册与命名约定;生成后记得在 `routes/api.php` 的 `autoRouteRegister` 中挂上控制器(当前 `genRoute` 会自动写入) - **uniapp 模板强制约定**(与移动端规则同口径): - 必须兼容 **微信小程序 + App + H5** - 交互必须是 **list → detail → form 三页**;禁止底部抽屉做主 CRUD;禁止 PC 宽表 - 复用:`AppCardList` / `AppFilterBar` / `AppDetailHero` / `AppInfoGroup` / `AppBottomBar` / `AppPageForm` - 粘贴落点:`nl-admin-uniapp/src/pages-sub/my-gen//`,并同步 `pages.json`(三页)与 `features.ts`