CRMEB Pro 二开入门后台接口如何按分层结构扩展做 CRMEB Pro 二开时最容易踩坑的地方不是“代码能不能写出来”而是扩展点放错层级Controller 里堆业务、Services 里直接查库、Dao 没有封装查询最后接口能跑但后续维护、排错、升级都会变得很痛苦。这篇先从后台接口的分层结构讲起适合作为二开前的基础规范文档。一、先看项目的后端分层CRMEB Pro 后端整体是 ThinkPHP 项目后台接口常见目录大致如下app/controller/admin 后台控制器 app/services 业务服务层 app/dao 数据访问层 app/model 数据模型 app/validate 参数验证器 route/admin.php 后台路由入口二开时建议始终按照下面的链路理解接口route - Controller - Services - Dao - Model也就是说路由负责把 URL 映射到控制器方法。Controller 负责接收参数、处理登录身份、调用 Services、返回统一响应。Services 负责业务编排比如权限判断、状态流转、事务、跨模块调用。Dao 负责查询条件、分页、统计、列表等数据访问。Model 负责表映射、搜索器、关联和字段处理。这个分层不是形式主义。对于商品、订单、库存、分销这类核心业务如果查询和业务混在一起后面加条件、改权限、查问题都会非常难。二、从路由找到接口入口后台路由一般从route/admin.php开始看。比如后台接口通常挂在adminapi分组下并通过中间件统一处理跨域、登录态、权限和日志。常见结构类似Route::group(adminapi,function(){Route::group(function(){// 登录、验证码、版权、公共配置等无需授权接口});Route::group(function(){// 需要后台登录、权限校验、日志记录的业务接口})-middleware([AllowOriginMiddleware::class,AdminAuthTokenMiddleware::class,AdminCkeckRoleMiddleware::class,AdminLogMiddleware::class,]);});二开新增后台接口时建议先确认三件事这个接口是否需要后台登录。是否需要权限菜单控制。是否需要记录后台操作日志。如果是商品、订单、用户、分销等后台管理接口通常不要绕过原有中间件。三、Controller 只做请求和响应以商品模块为例控制器位于app/controller/admin/v1/product目录。控制器中常见做法是使用getMore或postMore收集参数。根据当前管理员身份补充必要条件。调用注入的 Services 方法。使用success/fail返回统一格式。简化示例/** * 获取商品列表头部统计 * return mixed */publicfunctiontype_header(){$where$this-request-getMore([[store_name,],[product_type,],[cate_id,],[type,1,,status],]);$list$this-service-getHeader(0,$where);return$this-success(compact(list));}这里要注意Controller 不适合写复杂查询也不适合直接拼 SQL。它应该像一个“接口门面”把请求参数整理干净然后交给 Services。四、Services 负责业务编排Services 是二开最常用的扩展位置。比如商品服务中getHeader会根据门店、供应商、平台商品等条件组织统计逻辑再调用 Dao 获取数量。简化理解如下/** * 获取顶部标签统计 * param int $store_id * param array $where * return array[] */publicfunctiongetHeader(int$store_id0,array$where[]){// 根据业务身份补充查询条件if($store_id){$where[type]1;$where[relation_id]$store_id;}else{$where[pid]0;}$onsale$this-dao-getCount([status1]$where);$forsale$this-dao-getCount([status2]$where);return[[type1,name销售中,count$onsale],[type2,name仓库中,count$forsale],];}Services 层适合处理当前管理员、供应商、门店等身份差异。订单、库存、金额、返佣等状态变更。跨模块调用比如商品列表里补分类名、供应商名、门店名。数据库事务。队列、缓存、事件等业务协作。如果一个接口会影响订单、库存、余额、积分、优惠券等核心数据建议在 Services 层把边界条件写清楚并配合事务处理。五、Dao 专门封装查询Dao 层的价值是把查询集中起来。比如统计数量、分页列表、按条件查询、按字段取列都应该尽量放到 Dao 中。二开时常见错误是直接在 Controller 或 Services 里写Db::name(store_product)-where(...)-select();这类写法短期看很快长期会带来几个问题搜索条件分散后续改字段容易漏。权限条件容易漏加。分页、软删、状态筛选不统一。很难复用已有查询方法。更推荐的方式是// Services 中调用 Dao$count$this-dao-getCount($where);$list$this-dao-getList($where,$page,$limit);如果已有 Dao 方法能满足就优先复用如果不能满足再在对应 Dao 中新增查询方法。六、Model 负责表映射和搜索器Model 层主要处理数据表映射、字段类型、搜索器、关联关系。二开新增筛选条件时可以先看 Model 是否已有搜索器避免在多个地方重复写同样的 where 条件。常见方向包括商品名称、分类、品牌、状态等搜索器。用户、订单、门店、供应商等关联关系。字段类型转换。软删除或状态字段处理。如果搜索逻辑会在多个列表复用放到 Model 搜索器或 Dao 查询封装里会更稳。七、一个后台接口的二开流程以“新增一个商品扩展统计接口”为例可以按这个步骤做在route/admin.php或对应路由分组中新增路由。在对应 Controller 中新增方法只负责收参、身份条件和响应。在对应 Services 中新增业务方法处理统计逻辑和跨模块调用。在对应 Dao 中新增查询方法集中封装数据库访问。如需新增字段同时维护完整安装 SQL 和升级 SQL并给字段补充 COMMENT。使用后台登录态测试接口确认权限、中间件、返回结构和异常处理一致。推荐返回方式return$this-success($data);不推荐在业务接口里临时返回returnjson([code200,data$data]);因为这样会破坏项目统一响应结构也不利于前端统一处理错误。八、二开时的几个实用建议第一先找相邻模块。比如做商品扩展就先看product目录下已有 Controller、Services、Dao、Model而不是重新设计一套结构。第二核心数据不要随意写脚本直接改。订单、库存、余额、积分、优惠券、分销关系都属于高风险数据改动前要先确认影响范围、备份和回滚方式。第三缓存和队列要走项目已有封装。不要临时裸连 Redis也不要随意开启本地队列消费去跑线上数据。第四新增方法要写清楚 PHPDoc。尤其是权限判断、身份绑定、兼容旧数据、订单金额和库存处理要用简洁注释说明业务原因。第五SQL 升级脚本要考虑已有客户环境。新增字段要有 COMMENT升级语句要尽量可重复执行删除字段要特别谨慎。总结CRMEB Pro 二开的关键不是把功能“塞进去”而是放到正确层级里。后台接口建议始终按Controller - Services - Dao - Model走Controller 轻、Services 稳、Dao 集中、Model 清晰。后续如果继续写这个系列可以按模块展开商品二开、订单售后、分销关系、库存同步、后台权限、接口文档生成等。每个模块都先从现有实现入手再做最小范围扩展这样升级和维护成本会低很多。
CRMEB Pro 二开入门:后台接口如何按分层结构扩展
发布时间:2026/6/10 22:47:24
CRMEB Pro 二开入门后台接口如何按分层结构扩展做 CRMEB Pro 二开时最容易踩坑的地方不是“代码能不能写出来”而是扩展点放错层级Controller 里堆业务、Services 里直接查库、Dao 没有封装查询最后接口能跑但后续维护、排错、升级都会变得很痛苦。这篇先从后台接口的分层结构讲起适合作为二开前的基础规范文档。一、先看项目的后端分层CRMEB Pro 后端整体是 ThinkPHP 项目后台接口常见目录大致如下app/controller/admin 后台控制器 app/services 业务服务层 app/dao 数据访问层 app/model 数据模型 app/validate 参数验证器 route/admin.php 后台路由入口二开时建议始终按照下面的链路理解接口route - Controller - Services - Dao - Model也就是说路由负责把 URL 映射到控制器方法。Controller 负责接收参数、处理登录身份、调用 Services、返回统一响应。Services 负责业务编排比如权限判断、状态流转、事务、跨模块调用。Dao 负责查询条件、分页、统计、列表等数据访问。Model 负责表映射、搜索器、关联和字段处理。这个分层不是形式主义。对于商品、订单、库存、分销这类核心业务如果查询和业务混在一起后面加条件、改权限、查问题都会非常难。二、从路由找到接口入口后台路由一般从route/admin.php开始看。比如后台接口通常挂在adminapi分组下并通过中间件统一处理跨域、登录态、权限和日志。常见结构类似Route::group(adminapi,function(){Route::group(function(){// 登录、验证码、版权、公共配置等无需授权接口});Route::group(function(){// 需要后台登录、权限校验、日志记录的业务接口})-middleware([AllowOriginMiddleware::class,AdminAuthTokenMiddleware::class,AdminCkeckRoleMiddleware::class,AdminLogMiddleware::class,]);});二开新增后台接口时建议先确认三件事这个接口是否需要后台登录。是否需要权限菜单控制。是否需要记录后台操作日志。如果是商品、订单、用户、分销等后台管理接口通常不要绕过原有中间件。三、Controller 只做请求和响应以商品模块为例控制器位于app/controller/admin/v1/product目录。控制器中常见做法是使用getMore或postMore收集参数。根据当前管理员身份补充必要条件。调用注入的 Services 方法。使用success/fail返回统一格式。简化示例/** * 获取商品列表头部统计 * return mixed */publicfunctiontype_header(){$where$this-request-getMore([[store_name,],[product_type,],[cate_id,],[type,1,,status],]);$list$this-service-getHeader(0,$where);return$this-success(compact(list));}这里要注意Controller 不适合写复杂查询也不适合直接拼 SQL。它应该像一个“接口门面”把请求参数整理干净然后交给 Services。四、Services 负责业务编排Services 是二开最常用的扩展位置。比如商品服务中getHeader会根据门店、供应商、平台商品等条件组织统计逻辑再调用 Dao 获取数量。简化理解如下/** * 获取顶部标签统计 * param int $store_id * param array $where * return array[] */publicfunctiongetHeader(int$store_id0,array$where[]){// 根据业务身份补充查询条件if($store_id){$where[type]1;$where[relation_id]$store_id;}else{$where[pid]0;}$onsale$this-dao-getCount([status1]$where);$forsale$this-dao-getCount([status2]$where);return[[type1,name销售中,count$onsale],[type2,name仓库中,count$forsale],];}Services 层适合处理当前管理员、供应商、门店等身份差异。订单、库存、金额、返佣等状态变更。跨模块调用比如商品列表里补分类名、供应商名、门店名。数据库事务。队列、缓存、事件等业务协作。如果一个接口会影响订单、库存、余额、积分、优惠券等核心数据建议在 Services 层把边界条件写清楚并配合事务处理。五、Dao 专门封装查询Dao 层的价值是把查询集中起来。比如统计数量、分页列表、按条件查询、按字段取列都应该尽量放到 Dao 中。二开时常见错误是直接在 Controller 或 Services 里写Db::name(store_product)-where(...)-select();这类写法短期看很快长期会带来几个问题搜索条件分散后续改字段容易漏。权限条件容易漏加。分页、软删、状态筛选不统一。很难复用已有查询方法。更推荐的方式是// Services 中调用 Dao$count$this-dao-getCount($where);$list$this-dao-getList($where,$page,$limit);如果已有 Dao 方法能满足就优先复用如果不能满足再在对应 Dao 中新增查询方法。六、Model 负责表映射和搜索器Model 层主要处理数据表映射、字段类型、搜索器、关联关系。二开新增筛选条件时可以先看 Model 是否已有搜索器避免在多个地方重复写同样的 where 条件。常见方向包括商品名称、分类、品牌、状态等搜索器。用户、订单、门店、供应商等关联关系。字段类型转换。软删除或状态字段处理。如果搜索逻辑会在多个列表复用放到 Model 搜索器或 Dao 查询封装里会更稳。七、一个后台接口的二开流程以“新增一个商品扩展统计接口”为例可以按这个步骤做在route/admin.php或对应路由分组中新增路由。在对应 Controller 中新增方法只负责收参、身份条件和响应。在对应 Services 中新增业务方法处理统计逻辑和跨模块调用。在对应 Dao 中新增查询方法集中封装数据库访问。如需新增字段同时维护完整安装 SQL 和升级 SQL并给字段补充 COMMENT。使用后台登录态测试接口确认权限、中间件、返回结构和异常处理一致。推荐返回方式return$this-success($data);不推荐在业务接口里临时返回returnjson([code200,data$data]);因为这样会破坏项目统一响应结构也不利于前端统一处理错误。八、二开时的几个实用建议第一先找相邻模块。比如做商品扩展就先看product目录下已有 Controller、Services、Dao、Model而不是重新设计一套结构。第二核心数据不要随意写脚本直接改。订单、库存、余额、积分、优惠券、分销关系都属于高风险数据改动前要先确认影响范围、备份和回滚方式。第三缓存和队列要走项目已有封装。不要临时裸连 Redis也不要随意开启本地队列消费去跑线上数据。第四新增方法要写清楚 PHPDoc。尤其是权限判断、身份绑定、兼容旧数据、订单金额和库存处理要用简洁注释说明业务原因。第五SQL 升级脚本要考虑已有客户环境。新增字段要有 COMMENT升级语句要尽量可重复执行删除字段要特别谨慎。总结CRMEB Pro 二开的关键不是把功能“塞进去”而是放到正确层级里。后台接口建议始终按Controller - Services - Dao - Model走Controller 轻、Services 稳、Dao 集中、Model 清晰。后续如果继续写这个系列可以按模块展开商品二开、订单售后、分销关系、库存同步、后台权限、接口文档生成等。每个模块都先从现有实现入手再做最小范围扩展这样升级和维护成本会低很多。