@qiqb/message-domain 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,16 @@
4
4
 
5
5
  包输出 ESM JavaScript、TypeScript 声明和 LESS;不依赖 Umi/Max、宿主 `.umi`、`@prokeeper-bip/shared` 或平台管理页面包。React、React DOM、Ant Design、Pro Components 和图标是 peerDependencies,由消费宿主安装和提供主题。宿主需支持导入包内 LESS,页面和组件已自行引用对应样式。
6
6
 
7
+ ## 从 0.1.4 升级到 0.2.0
8
+
9
+ 本次发布包含公开类型和权限码调整,宿主应配合当前消息服务接口升级:
10
+
11
+ - 移除运行时配置和 `MessageTopic` 的 `sourceSystem`;`InboxMessage.sourceSystem` 改为可选且允许 `null`,展示时需处理空来源。
12
+ - 移除 `MessageCondition`、`MessageSubscription.conditions` 和 `SubscriptionMetadata.operators`,订阅覆盖主题全部消息,只配置通知渠道。
13
+ - 页面和管理按钮权限码统一使用 `QiqbPlatformMessage` 前缀,宿主授权数据需同步;已有菜单仍通过菜单管理更新,内置初始化不覆盖人工修改。
14
+
15
+ 安装指定版本:`pnpm add @qiqb/message-domain@0.2.0`。默认路由继续使用 `/p/message/*`,运行时注入、提醒 renderer 和双模式路由入口沿用现有接入方式。
16
+
7
17
  ## 运行时装配
8
18
 
9
19
  宿主启动时、消息页面和组件挂载前调用一次配置。注入函数中可以使用宿主的 React hook;不要在挂载后更换 hook 实现。
@@ -17,7 +27,6 @@ configureMessageDomainRuntime({
17
27
  useLocation, // 返回 { search: string },支持 receiptId 查询参数打开详情
18
28
  useAccess, // 返回 { verifyElementPermission(code, projectCode) }
19
29
  projectCode: 'qiqb_platform',
20
- sourceSystem: 'qiqb_platform', // 平台宿主新增主题的来源;业务宿主填写实际发布方编码
21
30
  apiPrefix: '/api/qiqb_platform/message',
22
31
  inboxPath: '/p/message/inbox',
23
32
  receiptQueryParam: 'receiptId',
@@ -28,9 +37,7 @@ configureMessageDomainRuntime({
28
37
 
29
38
  `request` 由宿主继续处理 token、超时及鉴权。默认 fetch 只提供同源 JSON 请求,适合无框架预览;正式接入应注入现有请求层。页面使用 `WebResp<T> { success, message?, data? }` 与 `PageInfo<T> { total, records?, current?, size? }`。消息领域自行提示业务失败,传入 `skipErrorHandler: true`,避免宿主重复弹出相同错误。
30
39
 
31
- 新增主题的 `sourceSystem` 由宿主在页面挂载前配置,表单不再要求手填,保存请求和后端字段继续保留。该编码必须与业务发布参数 `MessagePublishParam.sourceSystem` 完全一致,大小写保留;例如发布方使用 `wmp`,业务宿主就配置 `sourceSystem: 'wmp'`。它表示发布方,与按钮授权使用的 `projectCode` 独立,领域包不从权限项目或应用名称推断来源,也不提供默认来源。
32
-
33
- 来源格式与后端一致:以英文字母开头,后续仅允许英文字母、数字、下划线、点或短横线,最多 64 个字符。宿主未配置或配置不合法时,页面提示原因并禁止新增主题;已有主题仍按原记录编辑。编辑时只读展示并保留该主题的原来源,平台宿主管理其他系统的主题时也不会改成当前宿主来源。
40
+ 消息主题不配置来源系统,新增、编辑、列表和订阅选项均不包含该字段,也无需宿主注入。消息本身的 `sourceSystem` 仍由发布方可选传入,原样保存,不传时为空;默认展示在空值时不补来源标签。
34
41
 
35
42
  ### 可选实时订阅
36
43
 
@@ -64,9 +71,9 @@ HTTP 刷新,同时每 60 秒完整对账;断线或未注入实时能力时
64
71
  业务已读。后台页面暂停查询,恢复可见立即补查;卸载、退出或换账号释放当前订阅租约,不断开其他
65
72
  业务模块共享的连接。
66
73
 
67
- 默认权限项目为 `qiqb_platform`,按钮授权显式传递该项目编码,不随当前导航项目漂移。缺少 `useAccess` 时主题及角色管理操作默认不可用;角色订阅的列表查询及写操作统一要求 `MessageRoleSubscriptionManageBtn`。我的订阅由服务端绑定当前账号,只提供查询、筛选和启停;新增、编辑、删除由主题策略与角色配置维护。页面入口和后端接口权限继续由宿主及服务端校验,按钮隐藏不能替代服务端鉴权。
74
+ 默认权限项目为 `qiqb_platform`,按钮授权显式传递该项目编码,不随当前导航项目漂移。缺少 `useAccess` 时主题及角色管理操作默认不可用;角色订阅的列表查询及写操作统一要求 `QiqbPlatformMessageRoleSubscriptionManageBtn`。我的订阅由服务端绑定当前账号,只提供查询、筛选和启停;新增、编辑、删除由主题策略与角色配置维护。页面入口和后端接口权限继续由宿主及服务端校验,按钮隐藏不能替代服务端鉴权。
68
75
 
69
- 主题使用 `subscriptionMode` 指定订阅策略,默认 `ALL_ACCOUNTS`(全量账户订阅),创建时为有效账户绑定订阅;`ROLE`(角色订阅)主题通过角色配置,在账户绑定角色时生成我的订阅。模式选项由 `/topic/subscription_modes` 动态返回,支持服务端扩展。主题的“同步订阅”调用 `/topic/sync_subscriptions` 补齐账户订阅,复用 `MessageTopicSaveBtn` 权限并显示新增数量。页面不配置可过滤字段或订阅条件,角色订阅保存时传递空条件列表,默认使用站内消息渠道。
76
+ 主题使用 `subscriptionMode` 指定订阅策略,默认 `ALL_ACCOUNTS`(全量账户订阅),创建时为有效账户绑定订阅;`ROLE`(角色订阅)主题通过角色配置,在账户绑定角色时生成我的订阅。模式选项由 `/topic/subscription_modes` 动态返回,支持服务端扩展。主题的“同步订阅”调用 `/topic/sync_subscriptions` 补齐账户订阅,复用 `QiqbPlatformMessageTopicSaveBtn` 权限并显示新增数量。订阅覆盖主题全部消息,前端类型与请求已移除过滤条件字段(`conditions`、`metadata.operators`);角色订阅默认使用站内消息渠道,编辑时主题与角色均不可修改(服务端同样拒绝)。删除主题不再要求先删除角色配置,主题删除提交后由服务端按订阅模式解除订阅(角色模式先解除角色订阅再解除个人订阅,其它模式解除个人订阅),删除确认框会提示该影响。
70
77
 
71
78
  ## 路由
72
79
 
@@ -192,7 +199,6 @@ configureMessageDomainRuntime({
192
199
  useLocation,
193
200
  useAccess,
194
201
  projectCode: 'prokeeper_bip',
195
- // sourceSystem: messageSourceSystem, // 填实际业务发布来源,与发布参数一致
196
202
  apiPrefix: '/api/qiqb_platform/message', // 消息服务迁入平台;如过渡服务另有地址可显式覆盖
197
203
  storageNamespace: 'prokeeper-bip',
198
204
  });
@@ -216,6 +222,6 @@ corepack pnpm --filter @qiqb/message-domain test:routes
216
222
  corepack pnpm pack:message-domain
217
223
  ```
218
224
 
219
- 打包到 `/private/tmp/qiqb-message-domain-0.1.4.tgz`,可通过 `pnpm add /private/tmp/qiqb-message-domain-0.1.4.tgz` 在消费仓库安装验证。构建仅清理本包 `build/`,输出 ESM 的相对 `.js` 导入、界面 `.d.ts`、独立路由 `.cjs`/`.d.cts` 和按源路径复制的 `.less`。包内容只包含 `build/`、README 和 package.json,不包含源代码、测试、依赖缓存或宿主生成文件。
225
+ 打包到 `/private/tmp/qiqb-message-domain-0.2.0.tgz`,可通过 `pnpm add /private/tmp/qiqb-message-domain-0.2.0.tgz` 在消费仓库安装验证。构建仅清理本包 `build/`,输出 ESM 的相对 `.js` 导入、界面 `.d.ts`、独立路由 `.cjs`/`.d.cts` 和按源路径复制的 `.less`。包内容只包含 `build/`、README 和 package.json,不包含源代码、测试、依赖缓存或宿主生成文件。
220
226
 
221
227
  `publish:message-domain` 与包内 `publish:official` 默认发布到 npm 官方仓库,使用公开 scoped 包;`publish:private/publish:local/publish:nexus` 保留为显式私服入口。它们不会在 build/pack 时自动执行;只有明确要发布时再运行。验证和打包不启动宿主应用、不部署后端、不远程发布。
@@ -345,9 +345,9 @@ export default function MessageReminderDisplay({ messages, carouselTarget, onDis
345
345
  if (!event.currentTarget.contains(event.relatedTarget)) {
346
346
  setCarouselFocused(false);
347
347
  }
348
- }, children: _jsx(Alert, { className: "qiqb-message-reminder-carousel", type: levelType(messageLevel(carouselMessage)), banner: true, showIcon: true, icon: _jsx(LevelIcon, { level: messageLevel(carouselMessage) }), message: _jsxs("div", { className: "qiqb-message-reminder-carousel-content", children: [_jsx("span", { className: "qiqb-message-reminder-carousel-level", children: levelLabels[messageLevel(carouselMessage)] }), _jsxs("div", { className: "qiqb-message-reminder-carousel-viewport", "aria-live": "polite", "aria-atomic": "true", children: [_jsx("div", { className: "qiqb-message-reminder-carousel-message is-current", children: renderCarouselContent(carouselMessage) }, receiptId(carouselMessage)), departingCarousel && (_jsx("div", { className: "qiqb-message-reminder-carousel-message is-departing", "aria-hidden": "true", children: renderCarouselContent(departingCarousel) }, `departing:${receiptId(departingCarousel)}`))] })] }), action: _jsxs("div", { className: "qiqb-message-reminder-carousel-actions", children: [_jsx(Button, { className: "qiqb-message-reminder-carousel-view", type: "text", size: "small", loading: confirmingIds.includes(receiptId(carouselMessage)), disabled: confirmingIds.includes(receiptId(carouselMessage)), onClick: () => onOpen(carouselMessage), children: "\u67E5\u770B" }), carousel.length > 1 && (_jsxs("div", { className: "qiqb-message-reminder-carousel-navigation", "aria-label": "\u5207\u6362\u6D88\u606F", children: [_jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0A\u4E00\u6761\u63D0\u9192", icon: _jsx(LeftOutlined, {}), onClick: () => changeCarousel(-1) }), _jsxs("span", { className: "qiqb-message-reminder-counter", children: [carouselIndex + 1, " / ", carousel.length] }), _jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0B\u4E00\u6761\u63D0\u9192", icon: _jsx(RightOutlined, {}), onClick: () => changeCarousel(1) })] })), _jsx(Button, { className: "qiqb-message-reminder-carousel-close", type: "text", size: "small", "aria-label": "\u5173\u95ED\u5F53\u524D\u8F6E\u64AD\u63D0\u9192", icon: _jsx(CloseOutlined, {}), onClick: () => onDismiss(receiptId(carouselMessage)) })] }) }) }) }), carouselTarget), createPortal(_jsxs("div", { className: "qiqb-message-reminders", style: themeStyle, children: [floatingMessage && (_jsx("section", { className: "qiqb-message-reminder-floating-stack", "aria-label": "\u6D6E\u52A8\u6D88\u606F\u63D0\u9192", hidden: hasFullscreen, children: _jsxs(Card, { className: "qiqb-message-reminder-floating-card", size: "small", "data-level": messageLevel(floatingMessage), title: _jsxs(_Fragment, { children: [_jsx(BellOutlined, {}), " \u6D88\u606F\u63D0\u9192"] }), extra: _jsx(Button, { type: "text", size: "small", "aria-label": `关闭提醒:${floatingMessage.title}`, icon: _jsx(CloseOutlined, {}), onClick: () => onDismiss(receiptId(floatingMessage)) }), children: [_jsxs("article", { role: "status", "aria-live": "polite", children: [_jsxs("div", { className: "qiqb-message-reminder-floating-header", children: [_jsxs(Tag, { color: levelTagColor(messageLevel(floatingMessage)), children: [_jsx(LevelIcon, { level: messageLevel(floatingMessage) }), ' ', levelLabels[messageLevel(floatingMessage)]] }), _jsx("h3", { children: floatingMessage.title })] }), _jsx("p", { className: "qiqb-message-reminder-floating-summary", children: floatingMessage.content })] }, visibleFloatingId), _jsxs("div", { className: "qiqb-message-reminder-floating-footer", children: [_jsx("span", { children: floatingMessage.sourceSystem || '业务消息' }), _jsx(Button, { type: "link", size: "small", loading: confirmingIds.includes(receiptId(floatingMessage)), disabled: confirmingIds.includes(receiptId(floatingMessage)), onClick: () => onOpen(floatingMessage), children: "\u67E5\u770B\u6D88\u606F" })] }), floating.length > 1 && (_jsxs("div", { className: "qiqb-message-reminder-floating-navigation", "aria-label": "\u5207\u6362\u6D6E\u52A8\u6D88\u606F", children: [_jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0A\u4E00\u6761\u6D6E\u52A8\u63D0\u9192", icon: _jsx(LeftOutlined, {}), onClick: () => changeFloating(-1) }), _jsxs("span", { className: "qiqb-message-reminder-counter", children: [floatingIndex + 1, " / ", floating.length] }), _jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0B\u4E00\u6761\u6D6E\u52A8\u63D0\u9192", icon: _jsx(RightOutlined, {}), onClick: () => changeFloating(1) })] }))] }) })), _jsx(Modal, { open: hasFullscreen, centered: true, width: 640, rootClassName: "qiqb-message-reminders",
348
+ }, children: _jsx(Alert, { className: "qiqb-message-reminder-carousel", type: levelType(messageLevel(carouselMessage)), banner: true, showIcon: true, icon: _jsx(LevelIcon, { level: messageLevel(carouselMessage) }), message: _jsxs("div", { className: "qiqb-message-reminder-carousel-content", children: [_jsx("span", { className: "qiqb-message-reminder-carousel-level", children: levelLabels[messageLevel(carouselMessage)] }), _jsxs("div", { className: "qiqb-message-reminder-carousel-viewport", "aria-live": "polite", "aria-atomic": "true", children: [_jsx("div", { className: "qiqb-message-reminder-carousel-message is-current", children: renderCarouselContent(carouselMessage) }, receiptId(carouselMessage)), departingCarousel && (_jsx("div", { className: "qiqb-message-reminder-carousel-message is-departing", "aria-hidden": "true", children: renderCarouselContent(departingCarousel) }, `departing:${receiptId(departingCarousel)}`))] })] }), action: _jsxs("div", { className: "qiqb-message-reminder-carousel-actions", children: [_jsx(Button, { className: "qiqb-message-reminder-carousel-view", type: "text", size: "small", loading: confirmingIds.includes(receiptId(carouselMessage)), disabled: confirmingIds.includes(receiptId(carouselMessage)), onClick: () => onOpen(carouselMessage), children: "\u67E5\u770B" }), carousel.length > 1 && (_jsxs("div", { className: "qiqb-message-reminder-carousel-navigation", "aria-label": "\u5207\u6362\u6D88\u606F", children: [_jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0A\u4E00\u6761\u63D0\u9192", icon: _jsx(LeftOutlined, {}), onClick: () => changeCarousel(-1) }), _jsxs("span", { className: "qiqb-message-reminder-counter", children: [carouselIndex + 1, " / ", carousel.length] }), _jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0B\u4E00\u6761\u63D0\u9192", icon: _jsx(RightOutlined, {}), onClick: () => changeCarousel(1) })] })), _jsx(Button, { className: "qiqb-message-reminder-carousel-close", type: "text", size: "small", "aria-label": "\u5173\u95ED\u5F53\u524D\u8F6E\u64AD\u63D0\u9192", icon: _jsx(CloseOutlined, {}), onClick: () => onDismiss(receiptId(carouselMessage)) })] }) }) }) }), carouselTarget), createPortal(_jsxs("div", { className: "qiqb-message-reminders", style: themeStyle, children: [floatingMessage && (_jsx("section", { className: "qiqb-message-reminder-floating-stack", "aria-label": "\u6D6E\u52A8\u6D88\u606F\u63D0\u9192", hidden: hasFullscreen, children: _jsxs(Card, { className: "qiqb-message-reminder-floating-card", size: "small", "data-level": messageLevel(floatingMessage), title: _jsxs(_Fragment, { children: [_jsx(BellOutlined, {}), " \u6D88\u606F\u63D0\u9192"] }), extra: _jsx(Button, { type: "text", size: "small", "aria-label": `关闭提醒:${floatingMessage.title}`, icon: _jsx(CloseOutlined, {}), onClick: () => onDismiss(receiptId(floatingMessage)) }), children: [_jsxs("article", { role: "status", "aria-live": "polite", children: [_jsxs("div", { className: "qiqb-message-reminder-floating-header", children: [_jsxs(Tag, { color: levelTagColor(messageLevel(floatingMessage)), children: [_jsx(LevelIcon, { level: messageLevel(floatingMessage) }), ' ', levelLabels[messageLevel(floatingMessage)]] }), _jsx("h3", { children: floatingMessage.title })] }), _jsx("p", { className: "qiqb-message-reminder-floating-summary", children: floatingMessage.content })] }, visibleFloatingId), _jsxs("div", { className: "qiqb-message-reminder-floating-footer", children: [floatingMessage.sourceSystem && (_jsx("span", { children: floatingMessage.sourceSystem })), _jsx(Button, { type: "link", size: "small", loading: confirmingIds.includes(receiptId(floatingMessage)), disabled: confirmingIds.includes(receiptId(floatingMessage)), onClick: () => onOpen(floatingMessage), children: "\u67E5\u770B\u6D88\u606F" })] }), floating.length > 1 && (_jsxs("div", { className: "qiqb-message-reminder-floating-navigation", "aria-label": "\u5207\u6362\u6D6E\u52A8\u6D88\u606F", children: [_jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0A\u4E00\u6761\u6D6E\u52A8\u63D0\u9192", icon: _jsx(LeftOutlined, {}), onClick: () => changeFloating(-1) }), _jsxs("span", { className: "qiqb-message-reminder-counter", children: [floatingIndex + 1, " / ", floating.length] }), _jsx(Button, { type: "text", size: "small", "aria-label": "\u4E0B\u4E00\u6761\u6D6E\u52A8\u63D0\u9192", icon: _jsx(RightOutlined, {}), onClick: () => changeFloating(1) })] }))] }) })), _jsx(Modal, { open: hasFullscreen, centered: true, width: 640, rootClassName: "qiqb-message-reminders",
349
349
  // Ant Design 5 读取 rootStyle,6 的语义样式以 styles.root 为准。
350
350
  rootStyle: themeStyle, styles: { root: themeStyle }, className: "qiqb-message-reminder-fullscreen", zIndex: token.zIndexPopupBase + 100,
351
351
  // 正式全屏不能用关闭、遮罩或 Escape 绕过阅读确认。
352
- closable: false, maskClosable: false, keyboard: false, "aria-describedby": bodyId, title: fullscreenMessage && (_jsxs("div", { className: "qiqb-message-reminder-fullscreen-header", children: [_jsx(BellOutlined, {}), " \u6D88\u606F\u63D0\u9192", _jsx(Tag, { color: levelTagColor(messageLevel(fullscreenMessage)), children: levelLabels[messageLevel(fullscreenMessage)] }), _jsxs("span", { className: "qiqb-message-reminder-fullscreen-count", children: ["\u5F85\u786E\u8BA4 ", fullscreen.length, " \u6761"] })] })), footer: fullscreenMessage ? (_jsxs("div", { className: "qiqb-message-reminder-fullscreen-footer", children: [_jsx("span", { children: "\u786E\u8BA4\u4EC5\u8868\u793A\u4F60\u5DF2\u9605\u8BFB\u8FD9\u6761\u6D88\u606F\u3002" }), _jsxs("div", { children: [_jsx(Button, { loading: confirmingIds.includes(receiptId(fullscreenMessage)), disabled: confirmBusy, onClick: () => onOpen(fullscreenMessage), children: "\u67E5\u770B\u8BE6\u60C5" }), _jsx(Button, { type: "primary", loading: confirmBusy, onClick: () => void confirm(), children: "\u6211\u5DF2\u77E5\u6653" })] })] })) : null, children: fullscreenMessage && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "qiqb-message-reminder-fullscreen-scroll", tabIndex: 0, role: "document", children: [_jsx("h2", { children: fullscreenMessage.title }), _jsxs("div", { className: "qiqb-message-reminder-fullscreen-meta", children: [_jsxs("span", { children: ["\u6765\u6E90\uFF1A", fullscreenMessage.sourceSystem || '业务消息'] }), _jsxs("span", { children: ["\u65F6\u95F4\uFF1A", displayTime(fullscreenMessage)] })] }), _jsx("div", { className: "qiqb-message-reminder-fullscreen-body", id: bodyId, children: fullscreenMessage.content })] }), (confirmError || localConfirmError) && (_jsx(Alert, { className: "qiqb-message-reminder-confirm-error", type: "error", showIcon: true, message: confirmError || localConfirmError }))] })) })] }), portalTarget)] }));
352
+ closable: false, maskClosable: false, keyboard: false, "aria-describedby": bodyId, title: fullscreenMessage && (_jsxs("div", { className: "qiqb-message-reminder-fullscreen-header", children: [_jsx(BellOutlined, {}), " \u6D88\u606F\u63D0\u9192", _jsx(Tag, { color: levelTagColor(messageLevel(fullscreenMessage)), children: levelLabels[messageLevel(fullscreenMessage)] }), _jsxs("span", { className: "qiqb-message-reminder-fullscreen-count", children: ["\u5F85\u786E\u8BA4 ", fullscreen.length, " \u6761"] })] })), footer: fullscreenMessage ? (_jsxs("div", { className: "qiqb-message-reminder-fullscreen-footer", children: [_jsx("span", { children: "\u786E\u8BA4\u4EC5\u8868\u793A\u4F60\u5DF2\u9605\u8BFB\u8FD9\u6761\u6D88\u606F\u3002" }), _jsxs("div", { children: [_jsx(Button, { loading: confirmingIds.includes(receiptId(fullscreenMessage)), disabled: confirmBusy, onClick: () => onOpen(fullscreenMessage), children: "\u67E5\u770B\u8BE6\u60C5" }), _jsx(Button, { type: "primary", loading: confirmBusy, onClick: () => void confirm(), children: "\u6211\u5DF2\u77E5\u6653" })] })] })) : null, children: fullscreenMessage && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "qiqb-message-reminder-fullscreen-scroll", tabIndex: 0, role: "document", children: [_jsx("h2", { children: fullscreenMessage.title }), _jsxs("div", { className: "qiqb-message-reminder-fullscreen-meta", children: [fullscreenMessage.sourceSystem && (_jsxs("span", { children: ["\u6765\u6E90\uFF1A", fullscreenMessage.sourceSystem] })), _jsxs("span", { children: ["\u65F6\u95F4\uFF1A", displayTime(fullscreenMessage)] })] }), _jsx("div", { className: "qiqb-message-reminder-fullscreen-body", id: bodyId, children: fullscreenMessage.content })] }), (confirmError || localConfirmError) && (_jsx(Alert, { className: "qiqb-message-reminder-confirm-error", type: "error", showIcon: true, message: confirmError || localConfirmError }))] })) })] }), portalTarget)] }));
353
353
  }
@@ -227,7 +227,7 @@ export default function InboxPage() {
227
227
  void loadDetail(id);
228
228
  // URL 定位来自全局提醒;只有地址变化才加载,普通列表状态更新不能反复读取详情。
229
229
  }, [location.search]);
230
- const reader = (_jsx("section", { className: "qiqb-inbox-reader", "aria-label": "\u6D88\u606F\u8BE6\u60C5", "aria-busy": detailLoading, children: detailLoading && !detail ? (_jsx("div", { className: "qiqb-inbox-reader-body", children: _jsx(Skeleton, { active: true, title: { width: '60%' }, paragraph: { rows: 8 } }) })) : detail ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "qiqb-inbox-reader-top", children: [_jsxs("div", { className: "qiqb-inbox-reader-heading", children: [_jsxs("h2", { className: "qiqb-inbox-reader-title", children: [detail.title, ' ', _jsx("span", { className: "qiqb-inbox-reader-topic", children: topicName(detail) })] }), (isInternalMessagePath(detail.targetPath) || !detail.readAt) && (_jsxs(Space, { className: "qiqb-inbox-reader-actions", size: 8, wrap: true, children: [isInternalMessagePath(detail.targetPath) && (_jsx(Button, { type: "primary", size: "small", icon: _jsx(ArrowRightOutlined, {}), onClick: () => navigate(detail.targetPath), children: "\u67E5\u770B\u76F8\u5173\u4E1A\u52A1" })), !detail.readAt && (_jsx(Button, { size: "small", icon: _jsx(CheckOutlined, {}), loading: busyIds.includes(receiptId(detail)), onClick: () => void markRead(detail), children: "\u6807\u8BB0\u5DF2\u8BFB" }))] }))] }), _jsxs("div", { className: "qiqb-inbox-reader-info", children: [_jsxs(Space, { size: [8, 4], wrap: true, children: [messageLevelTag(detail), _jsx("span", { children: detail.sourceSystem.toUpperCase() }), _jsxs("span", { children: ["\u6536\u5230\u4E8E ", formatTime(detail.createTime)] })] }), _jsxs("span", { className: "qiqb-inbox-read-state", children: [detail.readAt ? (_jsxs(_Fragment, { children: [_jsx(CheckOutlined, {}), " \u5DF2\u8BFB"] })) : ('未读'), isExpired(detail) && _jsx(Tag, { children: "\u5DF2\u8FC7\u671F" })] })] })] }), _jsxs("div", { className: "qiqb-inbox-reader-body", children: [_jsx("div", { className: "qiqb-inbox-message-content", children: detail.content }), _jsxs("dl", { className: "qiqb-inbox-detail-meta", children: [_jsxs("div", { children: [_jsx("dt", { children: "\u53D1\u751F\u65F6\u95F4" }), _jsx("dd", { children: formatTime(detail.occurredAt) })] }), detail.businessType && (_jsxs("div", { children: [_jsx("dt", { children: "\u4E1A\u52A1\u7C7B\u578B" }), _jsx("dd", { children: detail.businessType })] })), detail.businessId && (_jsxs("div", { children: [_jsx("dt", { children: "\u4E1A\u52A1\u7F16\u53F7" }), _jsx("dd", { children: detail.businessId })] })), detail.expiresAt && (_jsxs("div", { children: [_jsx("dt", { children: "\u6709\u6548\u671F\u81F3" }), _jsx("dd", { children: formatTime(detail.expiresAt) })] }))] })] })] })) : (_jsxs("div", { className: "qiqb-message-state qiqb-inbox-reader-placeholder", children: [_jsx("span", { className: "qiqb-message-state-icon", children: _jsx(ReadOutlined, {}) }), _jsx("h3", { children: detailFailed ? '暂时无法打开这条消息' : '选择一条消息开始阅读' }), _jsx("p", { children: detailFailed
230
+ const reader = (_jsx("section", { className: "qiqb-inbox-reader", "aria-label": "\u6D88\u606F\u8BE6\u60C5", "aria-busy": detailLoading, children: detailLoading && !detail ? (_jsx("div", { className: "qiqb-inbox-reader-body", children: _jsx(Skeleton, { active: true, title: { width: '60%' }, paragraph: { rows: 8 } }) })) : detail ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "qiqb-inbox-reader-top", children: [_jsxs("div", { className: "qiqb-inbox-reader-heading", children: [_jsxs("h2", { className: "qiqb-inbox-reader-title", children: [detail.title, ' ', _jsx("span", { className: "qiqb-inbox-reader-topic", children: topicName(detail) })] }), (isInternalMessagePath(detail.targetPath) || !detail.readAt) && (_jsxs(Space, { className: "qiqb-inbox-reader-actions", size: 8, wrap: true, children: [isInternalMessagePath(detail.targetPath) && (_jsx(Button, { type: "primary", size: "small", icon: _jsx(ArrowRightOutlined, {}), onClick: () => navigate(detail.targetPath), children: "\u67E5\u770B\u76F8\u5173\u4E1A\u52A1" })), !detail.readAt && (_jsx(Button, { size: "small", icon: _jsx(CheckOutlined, {}), loading: busyIds.includes(receiptId(detail)), onClick: () => void markRead(detail), children: "\u6807\u8BB0\u5DF2\u8BFB" }))] }))] }), _jsxs("div", { className: "qiqb-inbox-reader-info", children: [_jsxs(Space, { size: [8, 4], wrap: true, children: [messageLevelTag(detail), detail.sourceSystem && _jsx("span", { children: detail.sourceSystem }), _jsxs("span", { children: ["\u6536\u5230\u4E8E ", formatTime(detail.createTime)] })] }), _jsxs("span", { className: "qiqb-inbox-read-state", children: [detail.readAt ? (_jsxs(_Fragment, { children: [_jsx(CheckOutlined, {}), " \u5DF2\u8BFB"] })) : ('未读'), isExpired(detail) && _jsx(Tag, { children: "\u5DF2\u8FC7\u671F" })] })] })] }), _jsxs("div", { className: "qiqb-inbox-reader-body", children: [_jsx("div", { className: "qiqb-inbox-message-content", children: detail.content }), _jsxs("dl", { className: "qiqb-inbox-detail-meta", children: [_jsxs("div", { children: [_jsx("dt", { children: "\u53D1\u751F\u65F6\u95F4" }), _jsx("dd", { children: formatTime(detail.occurredAt) })] }), detail.businessType && (_jsxs("div", { children: [_jsx("dt", { children: "\u4E1A\u52A1\u7C7B\u578B" }), _jsx("dd", { children: detail.businessType })] })), detail.businessId && (_jsxs("div", { children: [_jsx("dt", { children: "\u4E1A\u52A1\u7F16\u53F7" }), _jsx("dd", { children: detail.businessId })] })), detail.expiresAt && (_jsxs("div", { children: [_jsx("dt", { children: "\u6709\u6548\u671F\u81F3" }), _jsx("dd", { children: formatTime(detail.expiresAt) })] }))] })] })] })) : (_jsxs("div", { className: "qiqb-message-state qiqb-inbox-reader-placeholder", children: [_jsx("span", { className: "qiqb-message-state-icon", children: _jsx(ReadOutlined, {}) }), _jsx("h3", { children: detailFailed ? '暂时无法打开这条消息' : '选择一条消息开始阅读' }), _jsx("p", { children: detailFailed
231
231
  ? '消息详情加载失败,请重试。'
232
232
  : '在左侧查看消息,阅读详情或前往相关业务。' }), detailFailed && detailId && (_jsx(Button, { onClick: () => void loadDetail(detailId), children: "\u91CD\u65B0\u52A0\u8F7D" }))] })) }));
233
233
  return (_jsxs(MessageWorkspace, { title: "\u6211\u7684\u6D88\u606F", description: "\u96C6\u4E2D\u67E5\u770B\u4E1A\u52A1\u63D0\u9192\uFF0C\u53CA\u65F6\u8DDF\u8FDB\u4E0E\u4F60\u76F8\u5173\u7684\u6D88\u606F\u3002", icon: _jsx(InboxOutlined, {}), className: "qiqb-inbox-workspace", children: [_jsxs("div", { className: "qiqb-message-surface", children: [_jsxs("div", { className: "qiqb-message-toolbar qiqb-inbox-toolbar", children: [_jsxs("div", { className: "qiqb-inbox-filters", children: [_jsx(Segmented, { "aria-label": "\u7B5B\u9009\u9605\u8BFB\u72B6\u6001", value: query.unread === undefined
@@ -249,7 +249,7 @@ export default function InboxPage() {
249
249
  'qiqb-inbox-item',
250
250
  receiptId(record) === detailId ? 'is-selected' : '',
251
251
  !record.readAt ? 'is-unread' : '',
252
- ].join(' '), "aria-pressed": receiptId(record) === detailId, onClick: () => void loadDetail(receiptId(record)), children: [_jsxs("span", { className: "qiqb-inbox-item-heading", children: [_jsxs("span", { className: "qiqb-inbox-item-title-group", children: [_jsxs("span", { className: "qiqb-inbox-item-title", title: record.title, children: [!record.readAt && (_jsx("span", { className: "qiqb-inbox-unread-dot", "aria-label": "\u672A\u8BFB" })), record.title] }), _jsx("span", { className: "qiqb-inbox-item-topic", title: topicName(record), children: topicName(record) })] }), _jsx("time", { children: formatTime(record.createTime, true) })] }), _jsx("span", { className: "qiqb-inbox-item-preview", children: record.content || '点击查看消息详情' }), _jsxs("span", { className: "qiqb-inbox-item-footer", children: [_jsxs("span", { className: "qiqb-inbox-item-meta", children: [messageLevelTag(record), _jsx("span", { className: "qiqb-inbox-item-source", children: record.sourceSystem.toUpperCase() }), record.businessId && (_jsx("span", { className: "qiqb-inbox-item-business", title: '业务编号:' + record.businessId, children: record.businessId }))] }), _jsx("span", { className: "qiqb-inbox-item-state", children: isExpired(record)
252
+ ].join(' '), "aria-pressed": receiptId(record) === detailId, onClick: () => void loadDetail(receiptId(record)), children: [_jsxs("span", { className: "qiqb-inbox-item-heading", children: [_jsxs("span", { className: "qiqb-inbox-item-title-group", children: [_jsxs("span", { className: "qiqb-inbox-item-title", title: record.title, children: [!record.readAt && (_jsx("span", { className: "qiqb-inbox-unread-dot", "aria-label": "\u672A\u8BFB" })), record.title] }), _jsx("span", { className: "qiqb-inbox-item-topic", title: topicName(record), children: topicName(record) })] }), _jsx("time", { children: formatTime(record.createTime, true) })] }), _jsx("span", { className: "qiqb-inbox-item-preview", children: record.content || '点击查看消息详情' }), _jsxs("span", { className: "qiqb-inbox-item-footer", children: [_jsxs("span", { className: "qiqb-inbox-item-meta", children: [messageLevelTag(record), record.sourceSystem && (_jsx("span", { className: "qiqb-inbox-item-source", children: record.sourceSystem })), record.businessId && (_jsx("span", { className: "qiqb-inbox-item-business", title: '业务编号:' + record.businessId, children: record.businessId }))] }), _jsx("span", { className: "qiqb-inbox-item-state", children: isExpired(record)
253
253
  ? '已过期'
254
254
  : record.readAt
255
255
  ? '已读'
@@ -25,7 +25,7 @@ export default function SubscriptionForm({ scope, open, record, topics, roles, m
25
25
  if (!open)
26
26
  return;
27
27
  form.resetFields();
28
- form.setFieldsValue(record || { enabled: true, conditions: [], channels: ['IN_APP'] });
28
+ form.setFieldsValue(record || { enabled: true, channels: ['IN_APP'] });
29
29
  }, [open, record, form]);
30
30
  const save = async () => {
31
31
  if (!canManage ||
@@ -44,13 +44,12 @@ export default function SubscriptionForm({ scope, open, record, topics, roles, m
44
44
  await saveMessageSubscription({
45
45
  id: record?.id,
46
46
  name: values.name,
47
- topicCode: values.topicCode,
47
+ // 编辑时主题不可修改(服务端同样拒绝),始终提交原主题。
48
+ topicCode: record?.topicCode ?? values.topicCode,
48
49
  // 个人订阅由主题策略生成,本表单只配置角色与主题的绑定关系。
49
50
  subjectType: 'ROLE',
50
51
  subjectId: values.subjectId,
51
52
  enabled: values.enabled,
52
- // 页面已取消过滤条件,保存时显式清空历史条件,统一接收主题全部消息。
53
- conditions: [],
54
53
  // 本期固定使用站内消息,界面无需让用户选择唯一可用的渠道。
55
54
  channels: ['IN_APP'],
56
55
  });
@@ -92,11 +91,13 @@ export default function SubscriptionForm({ scope, open, record, topics, roles, m
92
91
  throw new Error('请选择角色订阅模式的主题');
93
92
  },
94
93
  },
95
- ], children: _jsx(Select, { loading: loading, showSearch: true, optionFilterProp: "label", placeholder: "\u9009\u62E9\u4F60\u5173\u6CE8\u7684\u6D88\u606F\u4E3B\u9898", options: topics.map((item) => ({
94
+ ], children: _jsx(Select, { loading: loading, showSearch: true,
95
+ // 订阅创建后主题固定,改挂主题需删除后重新创建。
96
+ disabled: !!record?.id, optionFilterProp: "label", placeholder: "\u9009\u62E9\u4F60\u5173\u6CE8\u7684\u6D88\u606F\u4E3B\u9898", options: topics.map((item) => ({
96
97
  label: `${item.name}(${item.code})`,
97
98
  value: item.code,
98
99
  disabled: !item.enabled || item.subscriptionMode !== 'ROLE',
99
- })) }) }), topic && (_jsxs("div", { className: "qiqb-subscription-drawer__topic-info", children: [_jsx(BellOutlined, {}), _jsxs("div", { children: [_jsx("strong", { children: topic.name }), _jsxs("span", { children: ["\u6765\u6E90\u7CFB\u7EDF\uFF1A", topic.sourceSystem] }), topic.description && _jsx("p", { children: topic.description })] })] })), roleScope ? (_jsx(Form.Item, { name: "subjectId", label: "\u8BA2\u9605\u89D2\u8272", extra: record
100
+ })) }) }), topic && (_jsxs("div", { className: "qiqb-subscription-drawer__topic-info", children: [_jsx(BellOutlined, {}), _jsxs("div", { children: [_jsx("strong", { children: topic.name }), topic.description && _jsx("p", { children: topic.description })] })] })), roleScope ? (_jsx(Form.Item, { name: "subjectId", label: "\u8BA2\u9605\u89D2\u8272", extra: record
100
101
  ? '角色归属已固定。如需更换角色,请新建订阅。'
101
102
  : '账户绑定该角色时,会自动生成对应的个人订阅。', rules: [{ required: true, message: '请选择订阅角色' }], children: _jsx(Select
102
103
  // 订阅主体创建后不能转移,避免编辑规则时改变既有规则归属。
@@ -17,7 +17,7 @@ export default function SubscriptionPage({ scope, }) {
17
17
  const roleScope = scope === 'ROLE';
18
18
  // 个人只调整自己的订阅启停;角色入口查询及所有写操作统一受管理权限保护。
19
19
  const canManage = !roleScope ||
20
- access.verifyElementPermission('MessageRoleSubscriptionManageBtn');
20
+ access.verifyElementPermission('QiqbPlatformMessageRoleSubscriptionManageBtn');
21
21
  const canConfigure = roleScope && canManage;
22
22
  const [topics, setTopics] = useState([]);
23
23
  const [roles, setRoles] = useState([]);
@@ -245,7 +245,7 @@ export default function SubscriptionPage({ scope, }) {
245
245
  const disabled = !canManage || !!busyId || recordsLoading || optionsLoading;
246
246
  return (_jsxs("article", { className: "qiqb-message-subscription-card", children: [_jsxs("div", { className: "qiqb-message-subscription-card-header", children: [_jsx("span", { className: "qiqb-message-subscription-topic-icon", children: _jsx(BellOutlined, {}) }), _jsxs("div", { className: "qiqb-message-subscription-heading", children: [_jsx("h3", { children: record.name }), _jsx("div", { className: "qiqb-message-subscription-topic", children: topicName })] }), _jsxs("div", { className: "qiqb-message-subscription-state", children: [_jsx("span", { className: record.enabled
247
247
  ? 'qiqb-message-subscription-status is-enabled'
248
- : 'qiqb-message-subscription-status', children: record.enabled ? '已启用' : '已停用' }), _jsx(Switch, { size: "small", "aria-label": `${record.name}启用状态`, checked: record.enabled, disabled: disabled, loading: busyId === record.id, onChange: (enabled) => void changeEnabled(record, enabled) })] })] }), roleScope && (_jsxs("div", { className: "qiqb-message-subscription-role", children: [_jsx(TeamOutlined, {}), _jsx("span", { children: roleName })] })), _jsxs("div", { className: "qiqb-message-subscription-conditions", children: [_jsx("div", { className: "qiqb-message-subscription-condition-label", children: "\u63A5\u6536\u8303\u56F4" }), _jsx("div", { className: "qiqb-message-subscription-all", children: "\u8BE5\u4E3B\u9898\u4E0B\u7684\u5168\u90E8\u6D88\u606F" })] }), _jsxs("div", { className: "qiqb-message-subscription-card-footer", children: [_jsxs("div", { className: "qiqb-message-subscription-channels", children: [_jsx(MessageOutlined, {}), _jsx("span", { children: (record.channels || [])
248
+ : 'qiqb-message-subscription-status', children: record.enabled ? '已启用' : '已停用' }), _jsx(Switch, { size: "small", "aria-label": `${record.name}启用状态`, checked: record.enabled, disabled: disabled, loading: busyId === record.id, onChange: (enabled) => void changeEnabled(record, enabled) })] })] }), roleScope && (_jsxs("div", { className: "qiqb-message-subscription-role", children: [_jsx(TeamOutlined, {}), _jsx("span", { children: roleName })] })), _jsxs("div", { className: "qiqb-message-subscription-scope", children: [_jsx("div", { className: "qiqb-message-subscription-scope-label", children: "\u63A5\u6536\u8303\u56F4" }), _jsx("div", { className: "qiqb-message-subscription-all", children: "\u8BE5\u4E3B\u9898\u4E0B\u7684\u5168\u90E8\u6D88\u606F" })] }), _jsxs("div", { className: "qiqb-message-subscription-card-footer", children: [_jsxs("div", { className: "qiqb-message-subscription-channels", children: [_jsx(MessageOutlined, {}), _jsx("span", { children: (record.channels || [])
249
249
  .map((channel) => metadata?.channels.find((item) => item.code === channel)?.name ||
250
250
  (channel === 'IN_APP' ? '站内消息' : channel))
251
251
  .join('、') || '未设置渠道' })] }), canConfigure && (_jsxs(Space, { size: 0, children: [_jsx(Button, { type: "text", size: "small", icon: _jsx(EditOutlined, {}), disabled: disabled ||
@@ -189,47 +189,6 @@
189
189
  }
190
190
  }
191
191
 
192
- &__condition {
193
- padding: 15px 16px 0;
194
- margin-bottom: 12px;
195
- background: var(--message-fill);
196
- border: 1px solid var(--message-border);
197
- border-radius: 10px;
198
-
199
- > .ant-form-item {
200
- margin-bottom: 17px;
201
- }
202
- }
203
-
204
- &__condition-heading {
205
- display: flex;
206
- align-items: center;
207
- justify-content: space-between;
208
- margin-bottom: 14px;
209
-
210
- strong {
211
- color: var(--message-muted);
212
- font-size: 11px;
213
- font-weight: 600;
214
- }
215
- }
216
-
217
- &__condition-fields {
218
- display: grid;
219
- grid-template-columns: minmax(0, 1fr) 150px;
220
- gap: 12px;
221
- .ant-form-item {
222
- min-width: 0;
223
- margin-bottom: 14px;
224
- }
225
- }
226
-
227
- &__add-condition {
228
- height: 38px;
229
- border-color: var(--message-border);
230
- color: var(--message-primary);
231
- background: transparent;
232
- }
233
192
  &__hint {
234
193
  margin: 10px 0 0;
235
194
  color: var(--message-muted);
@@ -326,10 +285,6 @@
326
285
  .ant-drawer-footer {
327
286
  padding: 15px 18px;
328
287
  }
329
- &__condition-fields {
330
- grid-template-columns: minmax(0, 1fr);
331
- gap: 0;
332
- }
333
288
  &__footer > span {
334
289
  max-width: 110px;
335
290
  line-height: 1.5;
@@ -137,12 +137,12 @@
137
137
  overflow-wrap: anywhere;
138
138
  }
139
139
 
140
- .qiqb-message-subscription-conditions {
140
+ .qiqb-message-subscription-scope {
141
141
  flex: 1;
142
142
  padding: 22px 0;
143
143
  }
144
144
 
145
- .qiqb-message-subscription-condition-label {
145
+ .qiqb-message-subscription-scope-label {
146
146
  margin-bottom: 10px;
147
147
  color: var(--message-muted);
148
148
  font-size: 12px;
@@ -3,7 +3,7 @@ import { EyeOutlined, PlusOutlined, SyncOutlined } from '@ant-design/icons';
3
3
  import { PageContainer, ProTable, } from '@ant-design/pro-components';
4
4
  import { Alert, Button, Col, Form, Input, Modal, Popconfirm, Row, Select, Space, Switch, Tag, Typography, message, } from 'antd';
5
5
  import { useCallback, useEffect, useRef, useState } from 'react';
6
- import { getMessageDomainRuntime, useAccess } from '../../runtime/index.js';
6
+ import { useAccess } from '../../runtime/index.js';
7
7
  import { dispatchMessageReminderPreview } from '../../runtime/reminderEvents.js';
8
8
  import { getMessageSubscriptionModes, pageMessageTopics, removeMessageTopic, saveMessageTopic, showMessageError, syncMessageTopicSubscriptions, } from '../../services/MessageController.js';
9
9
  // 两组设置各自定义完整选项,不按级别禁用提醒方式,让业务自由搭配。
@@ -37,12 +37,8 @@ export default function TopicPage() {
37
37
  const modesVersion = useRef(0);
38
38
  const syncId = useRef();
39
39
  const mounted = useRef(true);
40
- const canSave = access.verifyElementPermission('MessageTopicSaveBtn');
41
- const canRemove = access.verifyElementPermission('MessageTopicRemoveBtn');
42
- const hostSourceSystem = getMessageDomainRuntime().sourceSystem;
43
- // 沿用后端主题来源的标识格式;隐藏手填后,缺失配置不能误存成权限项目或默认来源。
44
- const hasHostSource = !!hostSourceSystem &&
45
- /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(hostSourceSystem);
40
+ const canSave = access.verifyElementPermission('QiqbPlatformMessageTopicSaveBtn');
41
+ const canRemove = access.verifyElementPermission('QiqbPlatformMessageTopicRemoveBtn');
46
42
  const loadSubscriptionModes = useCallback(async () => {
47
43
  const version = ++modesVersion.current;
48
44
  setModesLoading(true);
@@ -77,9 +73,10 @@ export default function TopicPage() {
77
73
  setEditing(record);
78
74
  form.resetFields();
79
75
  form.setFieldsValue({
80
- ...(record || {
81
- enabled: true,
82
- }),
76
+ code: record?.code,
77
+ name: record?.name,
78
+ enabled: record ? record.enabled : true,
79
+ description: record?.description,
83
80
  subscriptionMode: record?.subscriptionMode || 'ALL_ACCOUNTS',
84
81
  // 编辑历史主题时显式回填默认值,避免缺字段导致表单空选或保存丢失默认配置。
85
82
  reminderMode: record?.reminderMode || 'FLOATING',
@@ -90,12 +87,6 @@ export default function TopicPage() {
90
87
  const save = async () => {
91
88
  if (!canSave || modesLoading || modesFailed)
92
89
  return;
93
- // 来源由宿主负责提供;编辑仍使用历史来源,避免当前宿主覆盖其它系统的已有主题。
94
- const sourceSystem = editing ? editing.sourceSystem : hostSourceSystem;
95
- if (!sourceSystem || (!editing && !hasHostSource)) {
96
- message.error('当前应用未配置有效的消息来源,请联系管理员。');
97
- return;
98
- }
99
90
  // 校验失败留在表单内提示;服务失败保留已输入内容,便于修正后重试。
100
91
  const values = await form.validateFields().catch(() => undefined);
101
92
  if (!values)
@@ -103,9 +94,12 @@ export default function TopicPage() {
103
94
  setSaving(true);
104
95
  try {
105
96
  await saveMessageTopic({
106
- ...values,
97
+ // 只提交当前主题配置,避免旧响应中的已移除字段随编辑请求回传。
98
+ code: values.code,
99
+ name: values.name,
100
+ enabled: values.enabled,
101
+ description: values.description,
107
102
  id: editing?.id,
108
- sourceSystem,
109
103
  reminderMode: values.reminderMode || 'FLOATING',
110
104
  messageLevel: values.messageLevel || 'NORMAL',
111
105
  subscriptionMode: values.subscriptionMode || 'ALL_ACCOUNTS',
@@ -168,10 +162,6 @@ export default function TopicPage() {
168
162
  messageId: previewId,
169
163
  topicCode: values.code?.trim() || 'PREVIEW_TOPIC',
170
164
  topicName,
171
- // 预览沿用同一来源;未配置时仅使用示例标签,不会写入后台或充当发布来源。
172
- sourceSystem: editing
173
- ? editing.sourceSystem
174
- : hostSourceSystem || 'Platform',
175
165
  title: `提醒预览 · ${topicName}`,
176
166
  content: `这是一条${messageLevelLabels[messageLevel]}级别的示例消息,采用${reminderModeLabels[reminderMode]}展示。预览不会保存配置、发布消息或改变收件状态。`,
177
167
  createTime: now,
@@ -226,7 +216,9 @@ export default function TopicPage() {
226
216
  title: '操作',
227
217
  valueType: 'option',
228
218
  width: 260,
229
- render: (_, record) => (_jsxs(Space, { children: [canSave && _jsx("a", { onClick: () => editTopic(record), children: "\u7F16\u8F91" }), canSave && (_jsx(Button, { size: "small", type: "link", icon: _jsx(SyncOutlined, {}), loading: syncingId === record.id, disabled: !!syncingId || removingId === record.id, onClick: () => void syncSubscriptions(record), children: "\u540C\u6B65\u8BA2\u9605" })), canRemove && (_jsx(Popconfirm, { title: "\u5220\u9664\u8BE5\u6D88\u606F\u4E3B\u9898\uFF1F", description: "\u5DF2\u6709\u8BA2\u9605\u6216\u6D88\u606F\u7684\u4E3B\u9898\u53EF\u80FD\u4E0D\u5141\u8BB8\u5220\u9664\u3002", onConfirm: async () => {
219
+ render: (_, record) => (_jsxs(Space, { children: [canSave && _jsx("a", { onClick: () => editTopic(record), children: "\u7F16\u8F91" }), canSave && (_jsx(Button, { size: "small", type: "link", icon: _jsx(SyncOutlined, {}), loading: syncingId === record.id, disabled: !!syncingId || removingId === record.id, onClick: () => void syncSubscriptions(record), children: "\u540C\u6B65\u8BA2\u9605" })), canRemove && (_jsx(Popconfirm, { title: "\u5220\u9664\u8BE5\u6D88\u606F\u4E3B\u9898\uFF1F",
220
+ // 服务端删除主题后会清理其全部订阅(个人订阅与角色订阅),确认前明确提示影响范围。
221
+ description: "\u5C06\u540C\u65F6\u5220\u9664\u8BE5\u4E3B\u9898\u4E0B\u7684\u5168\u90E8\u4E2A\u4EBA\u8BA2\u9605\u4E0E\u89D2\u8272\u8BA2\u9605\uFF0C\u5DF2\u53D1\u5E03\u6D88\u606F\u4E0D\u53D7\u5F71\u54CD\u3002", onConfirm: async () => {
230
222
  setRemovingId(record.id);
231
223
  try {
232
224
  await removeMessageTopic(record.id);
@@ -242,11 +234,11 @@ export default function TopicPage() {
242
234
  }, children: _jsx(Button, { size: "small", type: "link", danger: true, loading: removingId === record.id, disabled: syncingId === record.id, children: "\u5220\u9664" }) }))] })),
243
235
  },
244
236
  ];
245
- return (_jsxs(PageContainer, { title: "\u6D88\u606F\u4E3B\u9898", children: [canSave && !hasHostSource && (_jsx(Alert, { type: "warning", showIcon: true, message: "\u5F53\u524D\u5E94\u7528\u672A\u914D\u7F6E\u6709\u6548\u7684\u6D88\u606F\u6765\u6E90\uFF0C\u6682\u65F6\u65E0\u6CD5\u65B0\u589E\u4E3B\u9898\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002" })), modesFailed && (_jsx(Alert, { type: "error", showIcon: true, message: "\u8BA2\u9605\u6A21\u5F0F\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u540E\u4FDD\u5B58\u4E3B\u9898\u3002", action: _jsx(Button, { size: "small", onClick: () => void loadSubscriptionModes(), children: "\u91CD\u8BD5" }) })), _jsx(ProTable, { rowKey: "id", actionRef: actionRef, columns: columns,
237
+ return (_jsxs(PageContainer, { title: "\u6D88\u606F\u4E3B\u9898", children: [modesFailed && (_jsx(Alert, { type: "error", showIcon: true, message: "\u8BA2\u9605\u6A21\u5F0F\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u540E\u4FDD\u5B58\u4E3B\u9898\u3002", action: _jsx(Button, { size: "small", onClick: () => void loadSubscriptionModes(), children: "\u91CD\u8BD5" }) })), _jsx(ProTable, { rowKey: "id", actionRef: actionRef, columns: columns,
246
238
  // 列表保留主题管理字段,窄屏通过横向滚动展示,避免压缩新增配置的中文标签。
247
239
  scroll: { x: 1310 }, pagination: { defaultPageSize: 20, showSizeChanger: true }, toolBarRender: () => canSave
248
240
  ? [
249
- _jsx(Button, { type: "primary", icon: _jsx(PlusOutlined, {}), disabled: !hasHostSource, onClick: () => editTopic(), children: "\u65B0\u589E\u4E3B\u9898" }, "create"),
241
+ _jsx(Button, { type: "primary", icon: _jsx(PlusOutlined, {}), onClick: () => editTopic(), children: "\u65B0\u589E\u4E3B\u9898" }, "create"),
250
242
  ]
251
243
  : [], request: async (params) => {
252
244
  try {
@@ -270,15 +262,12 @@ export default function TopicPage() {
270
262
  if (!saving)
271
263
  setOpen(false);
272
264
  }, onOk: save, confirmLoading: saving, okButtonProps: {
273
- disabled: !canSave ||
274
- modesLoading ||
275
- modesFailed ||
276
- (!editing && !hasHostSource),
265
+ disabled: !canSave || modesLoading || modesFailed,
277
266
  }, cancelButtonProps: { disabled: saving }, destroyOnHidden: true, children: _jsxs(Form, { form: form, layout: "vertical", children: [_jsx(Form.Item, { name: "code", label: "\u4E3B\u9898\u7F16\u7801", rules: [
278
267
  { required: true, whitespace: true, message: '请输入主题编码' },
279
268
  ], children: _jsx(Input, { disabled: !!editing, placeholder: "\u4F8B\u5982 ERP_APPROVAL_NOTICE", maxLength: 64 }) }), _jsx(Form.Item, { name: "name", label: "\u4E3B\u9898\u540D\u79F0", rules: [
280
269
  { required: true, whitespace: true, message: '请输入主题名称' },
281
- ], children: _jsx(Input, { maxLength: 128 }) }), editing && (_jsx(Form.Item, { label: "\u6765\u6E90\u7CFB\u7EDF", children: _jsx(Input, { value: editing.sourceSystem, readOnly: true }) })), _jsx(Form.Item, { name: "enabled", label: "\u542F\u7528", valuePropName: "checked", children: _jsx(Switch, {}) }), _jsx(Form.Item, { name: "subscriptionMode", label: "\u8BA2\u9605\u6A21\u5F0F", extra: "\u5168\u91CF\u8D26\u6237\u8BA2\u9605\u4F1A\u5728\u521B\u5EFA\u4E3B\u9898\u65F6\u7ED1\u5B9A\u6709\u6548\u8D26\u6237\uFF1B\u89D2\u8272\u8BA2\u9605\u7531\u89D2\u8272\u914D\u7F6E\u4E0E\u8D26\u6237\u7ED1\u5B9A\u5173\u7CFB\u786E\u5B9A\u3002\u540C\u6B65\u8BA2\u9605\u53EF\u8865\u9F50\u6211\u7684\u8BA2\u9605\u3002", rules: [{ required: true, message: '请选择订阅模式' }], children: _jsx(Select, { loading: modesLoading, disabled: modesLoading || modesFailed, options: subscriptionModes.map((item) => ({
270
+ ], children: _jsx(Input, { maxLength: 128 }) }), _jsx(Form.Item, { name: "enabled", label: "\u542F\u7528", valuePropName: "checked", children: _jsx(Switch, {}) }), _jsx(Form.Item, { name: "subscriptionMode", label: "\u8BA2\u9605\u6A21\u5F0F", extra: "\u5168\u91CF\u8D26\u6237\u8BA2\u9605\u4F1A\u5728\u521B\u5EFA\u4E3B\u9898\u65F6\u7ED1\u5B9A\u6709\u6548\u8D26\u6237\uFF1B\u89D2\u8272\u8BA2\u9605\u7531\u89D2\u8272\u914D\u7F6E\u4E0E\u8D26\u6237\u7ED1\u5B9A\u5173\u7CFB\u786E\u5B9A\u3002\u540C\u6B65\u8BA2\u9605\u53EF\u8865\u9F50\u6211\u7684\u8BA2\u9605\u3002", rules: [{ required: true, message: '请选择订阅模式' }], children: _jsx(Select, { loading: modesLoading, disabled: modesLoading || modesFailed, options: subscriptionModes.map((item) => ({
282
271
  value: item.code,
283
272
  label: item.name,
284
273
  })) }) }), _jsxs(Row, { gutter: 16, children: [_jsx(Col, { xs: 24, sm: 12, children: _jsx(Form.Item, { name: "reminderMode", label: "\u63D0\u9192\u65B9\u5F0F", children: _jsx(Select, { options: Object.entries(reminderModeLabels).map(([value, label]) => ({
package/build/routes.cjs CHANGED
@@ -12,25 +12,25 @@ function createMessageRoutes({ projectCode = exports.MESSAGE_PROJECT_CODE, baseP
12
12
  {
13
13
  name: '消息主题',
14
14
  path: `${base}/topics`,
15
- permissionCode: 'MessageTopicPage',
15
+ permissionCode: 'QiqbPlatformMessageTopicPage',
16
16
  component: '@qiqb/message-domain/pages/topic/TopicPage',
17
17
  },
18
18
  {
19
19
  name: '我的订阅',
20
20
  path: `${base}/my-subscriptions`,
21
- permissionCode: 'MessageSubscriptionPage',
21
+ permissionCode: 'QiqbPlatformMessageSubscriptionPage',
22
22
  component: '@qiqb/message-domain/pages/subscription/PersonalSubscriptionPage',
23
23
  },
24
24
  {
25
25
  name: '角色订阅',
26
26
  path: `${base}/role-subscriptions`,
27
- permissionCode: 'MessageRoleSubscriptionPage',
27
+ permissionCode: 'QiqbPlatformMessageRoleSubscriptionPage',
28
28
  component: '@qiqb/message-domain/pages/subscription/RoleSubscriptionPage',
29
29
  },
30
30
  {
31
31
  name: '我的消息',
32
32
  path: `${base}/inbox`,
33
- permissionCode: 'MessageInboxPage',
33
+ permissionCode: 'QiqbPlatformMessageInboxPage',
34
34
  component: '@qiqb/message-domain/pages/inbox/InboxPage',
35
35
  },
36
36
  ].map((route) => ({ ...route, projectCode, hideInMenu: true }));
package/build/routes.js CHANGED
@@ -8,25 +8,25 @@ export function createMessageRoutes({ projectCode = MESSAGE_PROJECT_CODE, basePa
8
8
  {
9
9
  name: '消息主题',
10
10
  path: `${base}/topics`,
11
- permissionCode: 'MessageTopicPage',
11
+ permissionCode: 'QiqbPlatformMessageTopicPage',
12
12
  component: '@qiqb/message-domain/pages/topic/TopicPage',
13
13
  },
14
14
  {
15
15
  name: '我的订阅',
16
16
  path: `${base}/my-subscriptions`,
17
- permissionCode: 'MessageSubscriptionPage',
17
+ permissionCode: 'QiqbPlatformMessageSubscriptionPage',
18
18
  component: '@qiqb/message-domain/pages/subscription/PersonalSubscriptionPage',
19
19
  },
20
20
  {
21
21
  name: '角色订阅',
22
22
  path: `${base}/role-subscriptions`,
23
- permissionCode: 'MessageRoleSubscriptionPage',
23
+ permissionCode: 'QiqbPlatformMessageRoleSubscriptionPage',
24
24
  component: '@qiqb/message-domain/pages/subscription/RoleSubscriptionPage',
25
25
  },
26
26
  {
27
27
  name: '我的消息',
28
28
  path: `${base}/inbox`,
29
- permissionCode: 'MessageInboxPage',
29
+ permissionCode: 'QiqbPlatformMessageInboxPage',
30
30
  component: '@qiqb/message-domain/pages/inbox/InboxPage',
31
31
  },
32
32
  ].map((route) => ({ ...route, projectCode, hideInMenu: true }));
@@ -47,8 +47,6 @@ export interface MessageDomainRuntimeAdapter {
47
47
  fieldLabel?: (field: string) => string | undefined;
48
48
  apiPrefix?: string;
49
49
  projectCode?: string;
50
- /** 宿主创建消息主题的业务来源,与发布接口的 sourceSystem 一致;不由权限项目号推断。 */
51
- sourceSystem?: string;
52
50
  inboxPath?: string;
53
51
  receiptQueryParam?: string;
54
52
  /** BIP 传入 prokeeper-bip 可沿用原来的 sessionStorage 收件标识去重记录。 */
@@ -10,8 +10,6 @@ let runtime = {
10
10
  };
11
11
  export function configureMessageDomainRuntime(adapter) {
12
12
  const next = { ...runtime, ...adapter };
13
- // 来源编码保留大小写,后端会严格核对;显式清空时不沿用其它宿主的来源。
14
- next.sourceSystem = next.sourceSystem?.trim() || undefined;
15
13
  next.apiPrefix = (adapter.apiPrefix ?? runtime.apiPrefix).replace(/\/+$/, '');
16
14
  next.projectCode = adapter.projectCode?.trim() || runtime.projectCode;
17
15
  next.storageNamespace =
@@ -6,7 +6,6 @@ export interface MessageTopic {
6
6
  id: string;
7
7
  code: string;
8
8
  name: string;
9
- sourceSystem: string;
10
9
  enabled: boolean;
11
10
  /** 模式由服务端注册并返回选项,保留 string 以支持宿主扩展订阅策略。 */
12
11
  subscriptionMode: string;
@@ -16,11 +15,6 @@ export interface MessageTopic {
16
15
  messageLevel?: MessageLevel;
17
16
  description?: string;
18
17
  }
19
- export interface MessageCondition {
20
- field: string;
21
- operator: string;
22
- values: string[];
23
- }
24
18
  export type SubscriptionScope = 'PERSONAL' | 'ROLE';
25
19
  export interface MessageSubscription {
26
20
  id: string;
@@ -31,7 +25,7 @@ export interface MessageSubscription {
31
25
  subjectId?: string;
32
26
  subjectName?: string;
33
27
  enabled: boolean;
34
- conditions: MessageCondition[];
28
+ /** 订阅总是覆盖主题全部消息,只选择通知渠道。 */
35
29
  channels: string[];
36
30
  }
37
31
  export interface MessageOption {
@@ -46,7 +40,6 @@ export interface MessageRole {
46
40
  }
47
41
  export interface SubscriptionMetadata {
48
42
  subjectTypes: MessageOption[];
49
- operators: MessageOption[];
50
43
  channels: MessageOption[];
51
44
  }
52
45
  export interface InboxMessage {
@@ -56,7 +49,8 @@ export interface InboxMessage {
56
49
  messageId: string;
57
50
  topicCode: string;
58
51
  topicName?: string;
59
- sourceSystem: string;
52
+ /** 发布方传入的可选来源;主题不配置来源,未传时保持为空。 */
53
+ sourceSystem?: string | null;
60
54
  title: string;
61
55
  content: string;
62
56
  businessId?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qiqb/message-domain",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "与宿主框架无关的 QIQB 消息主题、订阅、收件箱与全局提醒领域包",
5
5
  "sideEffects": [
6
6
  "**/*.less"