Appearance
系统消息中心 - 实施进展
状态: 阶段2(公告广播+事件接入+公告管理页)+ 阶段3(删 user 旧 Notify)+ 阶段4(channel/platform 公告发布面 + uniapp 消息 widget)代码完成,待部署验证 日期: 2026-07-19(阶段0: 2026-07-05,阶段2/3: 2026-07-18) 版本: Phase 4 - Full-Hierarchy Announcements & User-Facing Widgets
已完成
后端 (Java)
1. 模块创建 ✓
hiapi-system-basic-message-entity— 消息模型hiapi-system-basic-message-service— 消息服务hiapi-system-basic-message-api— API 控制层
2. 数据模型 ✓
MsgNotification.java— JPA 实体,含收件箱字段、分类、已读标记- 索引优化:
(receiverType, receiverId, readFlag, created)加速列表查询 - 去重保障:
(templateCode, bizId, receiverType, receiverId)联合唯一防重复投递
- 索引优化:
MsgCategory.java— 枚举 (TRADE/DEVICE/AUDIT/SECURITY/SYSTEM/MARKETING)
3. 业务逻辑 ✓
MsgNotificationService.java— 核心方法saveNotification()— 写入收件箱 + 去重 + Redis 未读计数增加read(ids)— 批量标记已读 + Redis 计数减少readAll()— 清空所有未读 + 删除 Redis 计数 keyunreadCount()— 读 Redis 优先,缓存未命中从 DB 自愈回源 + 7 天 TTL 过期
4. API 层 ✓
四账户类型 Controller (merchant/channel/platform/user)
- 各自直接
extends BasicQueryController<MsgNotification,...>,注入共享NotificationControllerSupportbean 委托 setQuery/toListVo/toDataVo/read/readAll/unreadCount(详见下方"已修复问题") - 自动从 Token 提取身份信息
- 统一路由:
/merchant/message/notification/*,/channel/message/notification/*等
- 各自直接
标准 HTTP 端点
GET /query— 分页列表,支持 category/readFlag/properties/directionPOST /read— 批量标记已读POST /read-all— 全部已读GET /unread-count— 返回{notification: count, announcement: 0}
Query/VO 类型
MsgNotificationQuery— 查询包装器,支持多维过滤MsgNotificationVo— 响应值对象
5. 事件监听 ✓
EventSystemNotifyReceipt.java— 监听SYSTEM_NOTIFY事件,存入收件箱- 其他事件监听(FINANCE_PAY_SUCCESS/USER_REGISTER)暂时省略,留作第 2 期实现
6. Maven 集成 ✓
- 三个子模块加入 hiapi-system-basic-core
<modules> - 依赖管理加入 hiapi-fast-frame pom.xml
- hiapi-cloud-public-app 依赖引入 message-api
- 编译通过 ✓ (clean install -DskipTests 成功)
前端 (Admin Dashboard)
1. 组件 ✓
MessageBell.vue— 顶部消息铃- 后台 60s 轮询未读数 (showError: false 静默失败)
- 下拉显示最近 5 条未读消息
- "全部已读"按钮
- 自动路由导航到消息中心
2. 页面 ✓
views/message/index.vue— 消息管理页- TablePage 组件 (自带分页/搜索/排序)
- 分类过滤 + 已读状态过滤
- 详情弹窗 (打开时自动标记已读)
- 全部已读批量操作
3. 国际化 ✓
- 中英文翻译文件 (
src/i18n/zh-cn/message.json,src/i18n/en/message.json) - 覆盖: bell 组件、分类标签、表格列、过滤器、按钮文案
4. API 路径更新 ✓
- MessageBell:
/api/cloud-api/{accountType}/message/notification/... - Message Index: 同上
- 四账户类型路由:
/message,/channel/message,/platform/message
文档与规划
1. 总体规划文档 ✓
- 更新模块位置 (独立 → 集成到 hiapi-system-basic-core)
- 更新网关前缀 (/cloud-message → /cloud-api)
- 路由流向详细说明
2. 项目记忆 ✓
/Users/adinz/.claude/projects/*/memory/project_message_center.md已更新
待完成 (后续阶段)
第 1 阶段: 公告系统
- [ ]
MsgAnnouncement实体 (一对多,拉模式) - [ ] 公告查询、发布、过期管理 API
- [ ] 前端公告弹窗组件
第 2 阶段: 多渠道派发
- [ ] 模板两层架构 (业务模板 + 渠道模板)
- [ ] ISenderService 集成 (SMS/EMAIL 复用现有体系)
- [ ] MQ 事件分发 (NotifyEvent/FinanceEvent/UserEvent 监听)
- [ ] Outbox 模式 + 重试机制
第 3 阶段: 社交渠道
- [ ] 微信公众号/小程序集成
- [ ] UniPush 2.0 推送
第 4 阶段: 统计与运营
- [ ] 消息统计表 (发送数/成功数/失败率)
- [ ] 后台运营面板
验证清单
本地编译
- [x]
mvn clean install -DskipTests通过,生成 message-entity/service/api 三个 JAR
部署
- [ ] docker-compose 启动 MySQL、Redis、后端应用
- [ ] 后端日志确认无异常
功能测试
后端
- [ ] 新建消息:
POST /api/cloud-api/merchant/message/notification(需关联 NotifyEvent 发送) - [ ] 查询列表:
GET /api/cloud-api/merchant/message/notification/query?page=1&size=10 - [ ] 未读数:
GET /api/cloud-api/merchant/message/notification/unread-count→{notification: N, announcement: 0} - [ ] 标记已读:
POST /api/cloud-api/merchant/message/notification/read单条/批量 - [ ] 全部已读:
POST /api/cloud-api/merchant/message/notification/read-all - [ ] 多账户隔离: platform/channel/user 账户只能读自己的消息
前端
- [ ] MessageBell 显示未读数 (红点 badge)
- [ ] 60s 轮询自动刷新
- [ ] 下拉菜单显示最近 5 条
- [ ] 点击条目进入消息中心详情
- [ ] 消息中心分类/已读过滤
- [ ] 全部已读按钮功能
性能验证
- [ ] Redis 未读计数命中率 > 90%
- [ ] 单用户查询响应 < 100ms
- [ ] 未读计数 API 响应 < 50ms (Redis hit 情况)
关键代码位置
| 模块 | 关键文件 |
|---|---|
| 后端实体 | hiapi-system-basic-message-entity/src/main/java/cn/hiapi/system/basic/message/entity/MsgNotification.java |
| 后端服务 | hiapi-system-basic-message-service/src/main/java/cn/hiapi/system/basic/message/service/MsgNotificationService.java |
| 后端 API 共享逻辑 | hiapi-system-basic-message-api/src/main/java/cn/hiapi/system/basic/message/api/NotificationControllerSupport.java |
| 后端控制器 | hiapi-system-basic-message-api/.../MerchantNotificationController.java (×4 账户类型,各自直接 extends BasicQueryController,委托给 NotificationControllerSupport) |
| 前端组件 | hiapi-cloud-admin-ts/src/components/MessageBell.vue |
| 前端页面 | hiapi-cloud-admin-ts/src/views/message/index.vue |
| 前端 i18n | hiapi-cloud-admin-ts/src/i18n/{zh-cn,en}/message.json |
| Maven 配置 | hiapi-system-basic-core/pom.xml + hiapi-cloud-public-app/pom.xml |
已知限制与 TODO
- [ ] 事件监听器 (EventFinancePayNotifyReceipt/EventUserRegisterNotifyReceipt) 暂未实现,等第 2 阶段多渠道派发时完善
- [ ] 公告(Announcement)表结构已规划,代码未开发,留作第 1 阶段
- [ ] 渠道配置管理 API 未开发 (第 2 阶段)
- [ ] 订阅偏好表 (msg_user_preference) 未开发 (第 2 阶段)
已修复问题
启动期 BeanCreationException (2026-07-05)
现象: 应用启动时 4 个 NotificationController(Merchant/Channel/Platform/User)全部报 Constructor threw exception → ClassCastException。
根因: BasicQueryController 构造函数用反射拿实体类型:
java
Type type = getClass().getGenericSuperclass();
this.tClass = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];这只看直接父类的泛型参数。原设计加了一层 AbsNotificationController extends BasicQueryController<MsgNotification,...>(非泛型,硬编码具体类型),四个账户控制器再 extends AbsNotificationController——此时它们的直接父类是非泛型的 AbsNotificationController,getGenericSuperclass() 拿到的是普通 Class 而非 ParameterizedType,强转必然抛出 ClassCastException。
(已用 Explore 子代理确认:整个代码库中没有"中间抽象类保持泛型透传"的先例,唯一同类模式即本次踩坑的实现;其余多账户控制器都是直接 extends BasicQueryController<Concrete,...>,没有中间层。)
修复: 去掉 AbsNotificationController 继承层,改为组合复用:
- 新增
NotificationControllerSupport(普通@Component,非 Controller),承载原来的setQuery/toListVo/toDataVo/read/readAll/unreadCount共享逻辑。 - 四个账户控制器改为直接
extends BasicQueryController<MsgNotification, Long, MsgNotificationVo, MsgNotificationQuery>,构造函数多注入一个NotificationControllerSupport,各端点/覆写方法都是一行委托。
验证: mvn clean install -DskipTests 在 hiapi-cloud-public 目录下退出码 0,无编译错误(尚未做运行时 Spring 上下文启动验证,建议部署到测试环境后确认 4 个 Controller Bean 均能正常创建)。
商户手动发消息给用户 (2026-07-05)
背景: 部署验证时发现,原设计里写入消息的唯一入口是 NotifyEvent(业务事件自动转通知),但代码库里没有任何地方发布过这个事件,商户后台也没有任何"发消息"的功能——商户完全没有办法主动给用户发一条站内信。
新增:
- 后端
NotificationControllerSupport.send(mid, receiverType, MsgSendRequest):批量对receiverIds逐个调用saveNotification(不传 templateCode/bizId,不做幂等去重,每次都新增)。 MerchantNotificationController新增POST /merchant/message/notification/send,固定receiverType=user、mid=当前商户,请求体{receiverIds:[], title, content, category?}(category 缺省MARKETING)。- 前端
views/user/index.vue(商户用户管理页):- 新增
selection多选列 + 头部"群发消息"按钮(对勾选用户批量发) - 行内新增"发消息"按钮(单个用户)
- 发送对话框:接收人数 + 标题 + 内容,提交调
POST /cloud-api/merchant/message/notification/send
- 新增
顺带修复的 pom 问题: 编译时发现 hiapi-cloud-public-app 依赖 hiapi-system-basic-message-api 缺版本号。根因不在 hiapi-system-basic-core/pom.xml(该聚合 pom 的 dependencyManagement 对 sibling 模块不生效),而是 hiapi-cloud-public 的实际 Maven parent 是已安装到本地仓库的 hiapi-fast-frame(<relativePath/> 从仓库查找),其 pom.xml 里虽然已经声明了这个依赖的版本,但本地 ~/.m2 缓存的是加了这条声明之前的旧版本 POM。执行 cd hiapi-fast-frame && mvn install -N -q 重新安装父 POM 后,hiapi-cloud-public 的 mvn clean install -DskipTests 才恢复正常(退出码 0)。
仍未做: channel/platform 账户是否也需要"发消息给自己下面的商户/渠道"能力(如平台运营手动通知某商户)——本次只做了商户→用户这一条路径,按需再加。
阶段2:公告广播 + 事件接入修复 + 公告管理页 (2026-07-18)
背景决策:user 服务的旧 Notify{Body,Target,Type} 体系确定废弃,全系统用户消息/公告统一由消息中心承载(删除动作另行执行,见 hiapi-docs/TODO.md 0 号待办)。
1. 公告广播(拉模式,补齐 announcement 恒 0 的缺口)
模型:一条公告一行,不逐用户 fan-out;接收端用"生效中公告 + 个人已读游标"合并计算未读。
MsgAnnouncement(表hiapi_msg_announcement):mid + receiverType + category + title/content/extra + status(1上架/0下架) + startTime/endTime + sort。endTime入参 <=0 表示永久,落库统一转哨兵值FOREVER=4102415999000(2099-12-31),避免查询出现OR endTime=0。索引(mid, receiverType, status, created)。MsgAnnouncementCursor(表hiapi_msg_announcement_cursor):每接收者一行的已读游标lastReadTime,唯一键(receiverType, mid, receiverId)。未读数 = 生效中公告里created > lastReadTime的条数;read-all 推进游标(upsert,并发插入冲突退化为 update),不做逐条已读。- Service:
MsgAnnouncementService(activeWrapper/unreadCount/readAll)+MsgAnnouncementCursorService(getCursorTime/touch)。 - 接口:
- 商户管理
/merchant/message/announcement:GET /query、POST /add、POST /edit(含 status 上下架)、DELETE|GET /delete(BasicCurdController,receiverType 固定 user,mid/receiverType/created 不可改)。 - 用户端
/user/message/announcement:GET /query(只出生效中的,每条带 readFlag)、POST /read-all、GET /unread-count。 NotificationControllerSupport.unreadCount的announcement从恒 0 改为真实值(对四类账户通用)。
- 商户管理
2. 事件接入修复(发现并修复一个"永远收不到"的 bug)
根因:旧 EventSystemNotifyReceipt 用 Spring 本地 @EventListener,而全系统跨服务事件走 RabbitMQ(IEventMessageListener + RabbitConfig 在 boot 期 postProcessBeanDefinitionRegistry 注册队列/绑定)——本地监听器根本收不到 MQ 消息,这就是"业务事件自动通知未接入"的真正原因。
修复与新增(全部放在 hiapi-system-basic-message-service 的 event/ 包——该模块已依赖 hiapi-core-event-sdk,且为 boot 期依赖,监听器 bean 在队列注册阶段可见;参照同服务 OperationLogListener 先例;不注入字段依赖,统一在 onMessage 里 dispatchContext.getServiceOne(...),因为 RabbitConfig 在 BeanDefinitionRegistryPostProcessor 阶段就会实例化监听器):
| 监听器 | 队列 | routingKey | 行为 |
|---|---|---|---|
EventSystemNotifyListener(替代旧 Receipt) | hiapi-cloud-public-message-system-notify | SYSTEM_NOTIFY | 通用通道:业务方发 NotifyEvent 即落站内信 |
EventFinancePaySuccessListener | hiapi-cloud-public-message-finance-pay | FINANCE_PAY_SUCCESS_ALL(通配) | 支付成功→用户 TRADE 通知,templateCode=PAY_SUCCESS,bizId=payCode(finance Outbox 重投不重复) |
EventUserRegisterListener | hiapi-cloud-public-message-user-register | USER_REGISTER | 注册→SYSTEM 欢迎信,bizId=uid |
生产方无需改动:finance 已经在发 PaymentSuccessEvent(FinancePaymentLogic,经 Outbox),user 已经在发 UserRegisterEvent(UserAccountService)。
已知缺口:提现审核没有对应事件(event-shared 里无 WITHDRAW key),接入需 finance 先补事件发布,留待后续。
3. 商户后台公告管理页(admin-ts)
- 新页
views/user/announcement/index.vue,双 Tab:- 公告管理:TablePage CRUD(标题/分类/状态筛选,发布/编辑弹窗:标题+分类+内容+生效/失效时间+排序+状态开关;失效时间留空=永久;行内 编辑/上下架/删除)。
- 发送记录:
GET /merchant/message/notification/sent(后端本次新增,mid+receiverType=user 倒序分页),前端按 time-ka 模式回填接收用户资料(/cloud-user/merchant/user/user-list?ids=,try/catch 失败只显示 ID)。
- 菜单
pages.ts50503000「公告消息」由死链/user/notify改指/user/announcement,路由注册,删除空壳views/user/notify/index.vue。 - i18n:
message.jsonzh/en 新增announcement.*/sent.*。
4. 验证状态
hiapi-cloud-publicmvn compileBUILD SUCCESS(产物核对过时间戳;首次编译曾因NotificationControllerSupport漏 import 失败,已修复)。- admin-ts
vue-tsc --noEmit通过。 - 未做运行时验证:MQ 队列创建/绑定、三张新表 DDL(JPA 自动建表)、公告端到端读写,需部署到测试环境确认。
5. 阶段2未含(后续)
删除 user 服务旧 Notify 体系→ 见阶段3- uniapp-design 用户端消息中心 widget(列表/未读红点/公告)
- 提现审核事件接入(依赖 finance 补事件)
- channel/platform 的公告发布面(实体已带 receiverType,扩展即可)
阶段3:删除 user 服务旧 Notify 体系 (2026-07-18)
阶段2 落地后,用户消息/公告已完全由消息中心承载,hiapi-cloud-user 里的旧 Notify{Body,Target,Type} 体系不再有新增使用场景,予以删除。
删前核查(两处均确认干净,才动手删):
uniapp-design全仓库搜索/user/notify:无引用。admin-ts用户列表页「发送消息」(views/user/index.vue的sendMsg):已在阶段0 切到POST /cloud-api/merchant/message/notification/send,核实确认无误。- 全仓库搜索
NotifyBody/NotifyTarget/NotifyType/NotifyBodyService/NotifyTargetService/NotifyTypeService的跨服务引用:无。
删除范围(hiapi-cloud-user,共 19 个文件):
- C端
NotifyController(/user/notify)+NotifyQuery+NotifyVo/NotifyTypeVo(hiapi-user-api) - 商户后台
NotifyController/NotifyTypeController+NotifyQuery/NotifyTypeQuery+NotifyVo/NotifyTypeVo(hiapi-user-merchant-api) - 实体
NotifyBody/NotifyTarget/NotifyType(hiapi-user-entity) NotifyBodyJpa/NotifyTargetJpa/NotifyTypeJpa+NotifyBodyService/NotifyTargetService/NotifyTypeService(hiapi-user-service)
数据库旧表(hiapi_core_notify_*)保留不动,只下线代码,不做迁移/清库。
验证:hiapi-cloud-user 目录 mvn compile 全 9 个子模块 BUILD SUCCESS(产物时间戳核对过)。
阶段4:channel/platform 公告发布面 + 用户端消息 widget(2026-07-19)
1. 公告扩展到全层级(platform ↔ merchant/channel)
阶段2 的公告只做了 merchant→user 一条方向。本阶段补齐平台向下广播:
- 模型不变,新增两种 receiverType 用法:
MsgAnnouncement.mid在 merchant→user 场景是"发布方商户的 mid"(租户内广播);平台广播新增用法——mid 固定 0,表示"全局,不区分商户/渠道"。已读游标MsgAnnouncementCursor的receiverId在这种场景下 = 商户/渠道自己的 mid(用于区分"谁读过"),但游标的mid参数固定传 0(与公告落库的 mid 对齐,不是商户自己的 mid)——这一点容易搞混,踩过一次坑:一开始想复用"query 用 getMid() 注入" 的通用逻辑,发现如果 getMid() 返回商户自己的 mid,查询条件eq(mid, 该值)永远查不到 mid=0 的平台公告行,必须让接收平台公告的 controller 的getMid()硬编码返回 0。 - 发布端:新增
PlatformAnnouncementController(/platform/message/announcement,BasicCurdController),receiverType由管理员在创建表单选择merchant或channel(校验合法值),mid 固定 0,编辑时 mid/receiverType/created 不可改(避免已读游标语义错乱)。 - 接收端:抽取
AnnouncementControllerSupport(仿照阶段0NotificationControllerSupport的组合复用先例,见 [[project_basicquerycontroller_generic_reflection]]/decisions/0005),把阶段2UserAnnouncementController里内联的"查询注入+VO转换+已读游标"逻辑抽出来复用,同时重构UserAnnouncementController改为委托调用。新增MerchantPlatformAnnouncementController(/merchant/message/platform-announcement)、ChannelPlatformAnnouncementController(/channel/message/platform-announcement),两者getMid()都硬编码返回 0,receiverId()用TokenGet.getMid()(该账户类型自己的身份 id)做已读游标区分。 - 未接入通用未读铃铛:
MerchantNotificationController.unread-count现有的announcement字段查询用的是"商户自己的 mid"(用于 merchant→user 场景的公告),不会匹配 mid=0 的平台公告,因此平台公告的未读数走各自独立的/merchant\|channel/message/platform-announcement/unread-count,前端需要另外拉取并自行合并到红点数字里,没有动阶段0 已上线的铃铛聚合逻辑(降低回归风险)。 - 不做的:channel→merchant(渠道只广播给自己名下商户)。仓库里确有
ChannelMerchant(channelId+mid)关系表,但要支持"仅本渠道商户可见"需要给MsgAnnouncement加 channelId 维度 + 查询侧关联,属于 schema 变更,超出本次"扩展即可"的量级,留待真有需求再做。 - 前端 admin-ts:
views/message/index.vue(merchant/channel 共用的消息中心页)加"平台公告"Tab(showAnnouncementTab按 accountType 显示);新增views/platform/announcement/index.vue(平台发布 CRUD,含接收对象 merchant/channel 选择器,发布后不可改),菜单pages.ts新增 100700000「公告管理」。
2. 用户端消息中心 widget(hiapi-cloud-public-web)
关键发现:目标不是 uniapp-design(顶层文件夹的 package.json name 实际是 hiapi-cloud-vem,是 VEM 项目的装修组件源,和 hiapi-cloud-vem/vem-web 内容一致);消息中心属于 hiapi-cloud-public 服务,正确的装修组件家目录是 hiapi-cloud-public/hiapi-cloud-public-web/src/components/hiapi-public/(appId: 'A-10000',已有 swiper/notice/balance 等组件的项目)。
顺带发现并修复一个阻断性 bug:该项目下 src/pages/user-center/message.vue 早已存在一个相当完整的消息列表页(分类 Tab、未读红点、全部已读、详情弹层),但请求前缀写的是 /cloud-message/user/message/notification——/cloud-message 这个网关前缀根本不存在(见 CLAUDE.md 网关路由表,只有 /cloud-api 才路由到 hiapi-cloud-public),这个页面此前完全打不通。已改为 /cloud-api/user/message/notification。
在此基础上完成:
message.vue加「消息 / 公告」顶部大 Tab(公告是阶段2/4 新增的独立资源,不能塞进 notification 的 category 枚举里)。公告没有逐条已读接口,只有read-all,页面据此不对公告条目发起单条已读请求。两个 Tab 的未读数复用同一次/user/message/notification/unread-count调用(接口本就同时返回{notification, announcement}两个真实值,不需要多打一次请求)。支持onLoadquery 参数?mode=announcement直接定位到公告页。- 新增
hiapi-public-message-entrywidget:图标+标题+未读红点(notification+announcement 求和),点击跳/pages/user-center/message,可放入个人中心装修页。 - 新增
hiapi-public-announcement-barwidget:滚动展示生效中公告(仿 VEMalarm-bar的轮播实现),点击跳/pages/user-center/message?mode=announcement。 - 两个 widget 都遵循已验证的 vem widget 模式:
HiapiUtils.getEnv()==='DESIGN'时走 mock 数据(供装修编辑器预览),onShow拉取真实数据,HiapiUtils.buildStyle处理外层样式。已在src/components/index.ts注册(appId: 'A-10000', project: 'hiapi-cloud-public')。
验证状态:hiapi-cloud-public 后端 mvn compile BUILD SUCCESS。hiapi-cloud-public-web 前端未能跑通 vue-tsc——这个子项目本身缺 @uni-helper/uni-types/@mini-types/alipay 等类型包(node_modules/@hiapi/hiapi-cloud-web-basic 目录是空的,pnpm install 后依然缺失),是环境既有问题、与本次改动无关(用 git status 核对过,这些包从未被本次改动触碰)。已用 HiapiUtils 真实类型签名(从 hiapi-cloud-web-basic/src/index.ts 源码核对 get/post/href/buildStyle 签名)人工核对新增代码,未跑运行时联调。
3. 阶段4未含(后续)
channel→merchant 定向公告见阶段5,已完成- 平台公告未读数并入通用消息铃铛聚合接口
- 提现审核事件接入(见
hiapi-cloud-finance/docs/completion-plan.md§P3 第11项) hiapi-cloud-public-web子项目本身的类型依赖缺失(与本功能无关,建议单独排查)
阶段5:channel→merchant 定向公告(2026-07-21)
补齐阶段4 留下的缺口:渠道只想给自己名下商户发公告,而不是全平台商户都收到。
- 模型:
MsgAnnouncement新增channelId字段(long,0=平台全局广播,>0=该渠道专属,仅receiverType=merchant时有意义),复合索引idx_msg_ann_channel(mid,receiverType,channelId)。 - 发布端:新增
ChannelAnnouncementController(/channel/message/announcement,@Secured(AccountType.Channel))。公告落库mid依然固定 0(和平台公告共享同一个"面向商户广播"的 mid 空间),真正归属靠channelId区分——channelId = TokenGet.getFid()(渠道账号登录后Token.mid恒为 0,身份信息在fid里,这是ChannelPlatformAnnouncementController阶段4 就踩过的坑,见下)。关键点:因为归属字段是channelId不是框架默认用来做隔离的mid,BasicCurdController的edit/delete默认实现完全不做 mid 校验(只按主键过滤),必须手动覆写buildWhere()(edit 场景)和deleteBeforeIntercept()(delete 场景)补上channelId归属校验,否则渠道 A 能改/删渠道 B 发布的公告。 - 接收端:
MerchantPlatformAnnouncementController原来只查mid=0 + receiverType=merchant拉全部平台公告,现在改成查channelId in (0, 该商户所属渠道id)——商户所属渠道靠ChannelMerchantService.getByMid(商户mid)查(ChannelMerchant表阶段4 调研时就已发现,一直没用上)。MsgAnnouncementUserQuery新增channelIds: List<Long>字段配合QueryWrapper.in()。hiapi-system-basic-message-api模块因此新增了对hiapi-merchant-service的编译期依赖(之前两个子系统只在运行时同容器,没有 Java 代码级依赖)。 - 顺手修复一个阶段4 遗留 bug:
ChannelPlatformAnnouncementController.receiverId()一直用的是TokenGet.getMid(),但渠道账号登录后Token.mid恒为 0——导致所有渠道账号的"平台公告已读游标"其实共用同一行(渠道 A 读了会让渠道 B 也变成已读)。改成TokenGet.getFid()。 - 前端:新增
views/channel/announcement/index.vue(照抄views/user/announcement/index.vue的公告管理 Tab,去掉发送记录 Tab,因为渠道端没有"定向消息"概念;不需要 receiverType 选择器,固定发给 merchant),菜单pages.ts新增300500000「公告管理」(渠道端)。商户端views/message/index.vue的"平台公告" Tab 加一列"来源"标签(平台/所属渠道),MsgAnnouncementVo相应暴露channelId字段。 - 验证状态:
hiapi-cloud-public后端mvn compileBUILD SUCCESS,hiapi-cloud-admin-ts前端vue-tsc --noEmit通过。菜单已直接执行 SQL 插入hiapi_core_system_menu(menu_id=300500000),未走完整的应用重装/reloadMenus流程。待部署验证:建表(channelId新列走ddl-auto: update自动加)、渠道发公告→商户能收到且其他渠道商户收不到的端到端联调。
后续工作建议
- 立即: 部署验证阶段2~5(建表/队列/公告闭环、user 服务删除后正常启动、channel/platform/merchant 三端公告发布与接收、message.vue 联调)
- 下周: 平台公告未读数并入通用消息铃铛聚合接口、
hiapi-cloud-public-web类型依赖修复 - 三周后: 多渠道派发(短信/邮件复用 ISenderService)与社交渠道集成