mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 21:40:50 +00:00
- UserBillServices 新增 getIntegralSumByPm():按 category=integral + status=1 + pm 方向求和,支持时间筛选与冻结期内(is_frozen=1)统计。 - 签到页用户信息统计不再枚举 type 白名单:新增积分类型(order_give_integral、 order_gain_refund 等)无需同步维护即可正确计入累计/支出/今日; 冻结积分改为只统计积分流水中的冻结收入项。 - 用户端积分页移除 clear_time 过期提示(对应逻辑已废弃),清理 dayjs 依赖与 isTime 状态。
modules/ — 业务扩展层
层定位
modules/ 是 CRMEB v8.0 架构的业务扩展层,位于 app/ 之上,可以调用 app/ 和 crmeb/ 的所有服务。
本层存放所有可插拔的业务模块,按业务域分类组织。
目录结构
modules/
├── trade/ 交易域 —— 订单管线扩展(全部实现 TradeModeHandlerInterface)
│ ├── combination/ 拼团 activity_combination
│ ├── seckill/ 秒杀 activity_seckill
│ ├── bargain/ 砍价 activity_bargain
│ ├── integral/ 积分商城 activity_integral
├── product/ 商品域 —— 产品类型(全部实现 ProductTypeHandlerInterface)
│ ├── normal/ 实物商品 product_normal
│ ├── virtual/ 虚拟商品 product_virtual
│ └── cardkey/ 卡密商品 product_cardkey
├── marketing/ 运营域 —— 权益与奖励(纯事件观察者)
│ ├── signin/ 签到 user_signin
│ ├── lottery/ 抽奖 activity_lottery
│ ├── newuser/ 新人专区 marketing_newuser
│ ├── channel_code/ 渠道码 user_channel_code
│ └── recharge/ 充值 user_recharge(已与订单中台解耦,独立充值单)
├── agent/ 分销代理模块
└── channel/ 用户/端渠道扩展(APP/H5/小程序/公众号)
第三方驱动(支付/短信/上传等)不在
modules/下,统一位于根目录driver/{category}/{name}/, 由各app/services/driver/*/*DriverServices扫描发现,安装时按 plugin.json 的path(driver/{category}/{name})落位。
trade/(怎么卖)× product/(卖什么)是两个正交维度,可自由组合
(同一商品既能拼团卖也能秒杀卖),各自有独立注册表:
crmeb/trade/mode/TradeModeRegistry 与 crmeb/trade/product/ProductTypeRegistry。
模块内部目录规范
每个模块({域}/{type}/)内部的子目录命名与职责全 modules 统一,新增模块必须按下表搭建:
根文件(必备)
| 文件 | 职责 |
|---|---|
App.php |
模块注册入口(register() 注册处理器,boot() 加载 event.php) |
Installer.php |
安装/卸载/启用/禁用(建表/菜单/种子,幂等) |
plugin.json |
插件元数据(key/name/type/path) |
event.php |
事件监听器注册表 |
Handler.php |
产品类型处理器(仅 product/ 域模块,实现 ProductTypeHandlerInterface) |
子目录(按需,命名固定)
| 目录 | 命名 | 职责 | 备注 |
|---|---|---|---|
controller/ |
— | 控制器,固定双端结构:admin/ + user/v1/ |
|
route/ |
— | 路由文件:admin.php / user.php(manage.php 可选),自动扫描加载 |
|
service/ |
— | 服务层(类名 XxxServices) |
|
dao/ |
— | 数据访问层(类名 XxxDao) |
纯事件观察者模块(如 marketing/newuser)可缺省 |
model/ |
— | 模型层 | 同上可缺省 |
validate/ |
— | 验证器 | 按需 |
listener/ |
— | 事件监听器(类名 XxxListener,与 event.php 对应) |
|
jobs/ |
复数 | 队列任务(继承 BaseJobs) |
⚠️ 单数 job/ 已废弃(2026-08 统一迁移),禁止新建 |
handler/ |
— | 域内处理器子目录:trade/ 域放 {Mode}ActivityHandler;product/ 域放 {Type}OrderAdapter + {Type}AfterSaleHandler |
根 Handler.php 为产品类型主处理器(仅 product/ 域有) |
crontab/ |
— | 定时任务(如拼团到期、分销员解绑) | 按需 |
特殊目录(已有模块使用,新模块按需参照)
| 目录 | 使用方 | 职责 |
|---|---|---|
sdk/ + notify/ |
channel/wechat_mp、channel/wechat_mini |
第三方 SDK 封装 + 回调处理 |
pipeline/ |
product/cardkey、product/virtual |
履约管线 |
frontend/dist |
product/virtual |
模块内前端构建产物 |
边界规则(新模块放哪?)
一句话:改变一笔订单如何成交的 → trade/;决定卖什么形态商品的 → product/;
只发放权益、奖励行为、不改变成交的 → marketing/。
"牵扯订单"要拆成三种性质再判断:
| 性质 | 含义 | 判别方法 | 归属 |
|---|---|---|---|
| 改变成交 | 实现交易契约,订单管线主动调用它 | 实现 TradeModeHandlerInterface(定价/下单校验/支付前后/退款/完成等钩子) |
trade/ |
| 决定商品形态 | 决定 SKU 模型、履约方式(发货/发卡/核销)、售后规则 | 实现 ProductTypeHandlerInterface + OrderTypeAdapter |
product/ |
| 观察订单 | 监听订单事件发权益,移除后订单流程完全不受影响 | 只在 event.php 里 listen(如 OrderPayLottery) |
marketing/ |
| 自建迷你流程 | 奖品/权益发放挂在活动记录上,不创建订单 | 有自己的发放记录表,不写 eb_order_center |
marketing/ |
会员订单不在
trade/:已独立为app/层eb_member_order体系。
扩展点一览
| 扩展点 | 目录 | 解决什么 |
|---|---|---|
| 交易域 | trade/ |
怎么卖:交易模式(定价策略、成团/限量规则、订单生命周期钩子) |
| 商品域 | product/ |
卖什么:产品类型(履约形态、库存方式、售后规则) |
| 运营域 | marketing/ |
送什么:权益与奖励(签到/抽奖/新人礼/渠道码) |
| 分销代理 | agent/ |
分销员管理、分销等级、事业部、佣金结算 |
| 用户渠道 | channel/ |
用户从哪来、如何识别登录、推送消息 |
依赖铁律
modules/内各模块之间不可互相引用- 跨模块通信必须走
crmeb/核心层契约或通过事件机制(event()) - 每个目录都是独立插件包,包含
plugin.json+Installer.php+App.php+ 标准 MVC 目录结构
自动发现机制
- 路由文件放入
route/目录(admin.php/user.php/manage.php)后自动扫描加载 - 菜单生命周期由
BaseModuleInstaller统一管理 plugin.json中的type字段决定插件分类(mode→trade、product/product_type→product、marketing→marketing)
历史参考:2026-08 由
trade/mode/*拍平为trade/*、trade/product/*提升为product/*, 模块 key 不变,plugin.jsonpath已同步。