@hkyhy/marsun-components-core 0.1.100 → 0.1.102

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.
Files changed (56) hide show
  1. package/dist/components/Editor/VariablePicker.js +13 -13
  2. package/dist/components/Editor/VariablePicker.js.map +1 -1
  3. package/dist/components/FormInfo/RichTextField/index.js +46 -69
  4. package/dist/components/FormInfo/RichTextField/index.js.map +1 -1
  5. package/dist/components/FormInfo/VariableMentionInput/index.d.ts +1 -0
  6. package/dist/components/FormInfo/VariableMentionInput/index.js +53 -47
  7. package/dist/components/FormInfo/VariableMentionInput/index.js.map +1 -1
  8. package/dist/components/FormInfo/VariableMentionInput/style.module.scss.js +6 -5
  9. package/dist/components/FormInfo/VariableMentionInput/style.module.scss.js.map +1 -1
  10. package/dist/components/Tools/Inbox/InboxBell/InboxBell.d.ts +3 -0
  11. package/dist/components/Tools/Inbox/InboxBell/InboxBell.js +59 -49
  12. package/dist/components/Tools/Inbox/InboxBell/InboxBell.js.map +1 -1
  13. package/dist/components/Tools/Inbox/InboxBell/style.module.scss.js +20 -18
  14. package/dist/components/Tools/Inbox/InboxBell/style.module.scss.js.map +1 -1
  15. package/dist/components/Tools/Inbox/index.d.ts +1 -0
  16. package/dist/components/Tools/Inbox/sanitizeInboxHtml.d.ts +5 -0
  17. package/dist/components/Tools/Inbox/sanitizeInboxHtml.js +14 -0
  18. package/dist/components/Tools/Inbox/sanitizeInboxHtml.js.map +1 -0
  19. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/List/columns.d.ts +1 -1
  20. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/List/columns.js +3 -3
  21. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/List/columns.js.map +1 -1
  22. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/MessageTemplateAdmin.js +160 -145
  23. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/MessageTemplateAdmin.js.map +1 -1
  24. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/Modal/TemplateFormModal.js +100 -99
  25. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/Modal/TemplateFormModal.js.map +1 -1
  26. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/PushRulesPanel/index.d.ts +2 -2
  27. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/PushRulesPanel/index.js +140 -129
  28. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/PushRulesPanel/index.js.map +1 -1
  29. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/VariablesPanel/index.d.ts +2 -2
  30. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/VariablesPanel/index.js +78 -78
  31. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/VariablesPanel/index.js.map +1 -1
  32. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/index.d.ts +2 -2
  33. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/types.d.ts +26 -0
  34. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/types.js +47 -19
  35. package/dist/components/Tools/MessageCenter/MessageTemplateAdmin/types.js.map +1 -1
  36. package/dist/components/Tools/MessageCenter/MsgCenterAppSwitcher/MsgCenterAppSwitcher.d.ts +22 -0
  37. package/dist/components/Tools/MessageCenter/MsgCenterAppSwitcher/MsgCenterAppSwitcher.js +64 -0
  38. package/dist/components/Tools/MessageCenter/MsgCenterAppSwitcher/MsgCenterAppSwitcher.js.map +1 -0
  39. package/dist/components/Tools/MessageCenter/MsgCenterAppSwitcher/index.d.ts +2 -0
  40. package/dist/components/Tools/MessageCenter/index.d.ts +7 -1
  41. package/dist/components/Tools/MessageCenter/msgCenterAppSwitch.d.ts +39 -0
  42. package/dist/components/Tools/MessageCenter/msgCenterAppSwitch.js +94 -0
  43. package/dist/components/Tools/MessageCenter/msgCenterAppSwitch.js.map +1 -0
  44. package/dist/components/Tools/MessageCenter/useMsgCenterAppKey.d.ts +2 -0
  45. package/dist/components/Tools/MessageCenter/useMsgCenterAppKey.js +18 -0
  46. package/dist/components/Tools/MessageCenter/useMsgCenterAppKey.js.map +1 -0
  47. package/dist/components/Tools/index.d.ts +3 -2
  48. package/dist/index.js +653 -636
  49. package/dist/index.js.map +1 -1
  50. package/dist/marsun-components-core.css +1 -1
  51. package/dist/node_modules/dompurify/dist/purify.es.js +908 -0
  52. package/dist/node_modules/dompurify/dist/purify.es.js.map +1 -0
  53. package/dist/node_modules/isomorphic-dompurify/dist/browser.js +17 -0
  54. package/dist/node_modules/isomorphic-dompurify/dist/browser.js.map +1 -0
  55. package/dist/styles/global.css +1 -1
  56. package/package.json +2 -1
@@ -1,29 +1,30 @@
1
1
  import { jsxs as b, jsx as a } from "react/jsx-runtime";
2
- import { Badge as $, Button as A, Drawer as F, Space as L, message as _ } from "antd";
3
- import E from "classnames";
4
- import { useState as n, useCallback as x, useEffect as T, useMemo as D } from "react";
5
- import r from "./style.module.scss.js";
2
+ import { Badge as R, Button as U, Drawer as W, Space as $, message as A } from "antd";
3
+ import x from "classnames";
4
+ import { useState as n, useCallback as E, useEffect as T, useMemo as F } from "react";
5
+ import { sanitizeInboxHtml as D } from "../sanitizeInboxHtml.js";
6
+ import t from "./style.module.scss.js";
6
7
  import { Bell as K } from "../../../Icons/Bell.js";
7
8
  import Y from "../../../StateBar/StateBar.js";
8
9
  import q from "../../../SegmentedRadio/SegmentedRadio.js";
9
10
  import G from "../../../Layout/PageSpin/index.js";
10
- import H from "../../../Empty/Empty.js";
11
- const J = [
11
+ import J from "../../../Empty/Empty.js";
12
+ const Q = [
12
13
  { key: "", label: "全部" },
13
14
  { key: "alert", label: "预警" },
14
15
  { key: "action", label: "行动" },
15
16
  { key: "remind", label: "提醒" }
16
- ], se = ({
17
+ ], ie = ({
17
18
  fetchInbox: o,
18
19
  markRead: M,
19
20
  onNavigate: v,
20
21
  pollMs: m = 6e4,
21
22
  pageSize: w = 50,
22
- className: P,
23
- title: j = "站内信"
23
+ className: H,
24
+ title: I = "站内信"
24
25
  }) => {
25
- const [p, i] = n(!1), [B, k] = n(!1), [u, N] = n(""), [S, y] = n([]), [s, f] = n(0), [C, O] = n({}), [h, I] = n(""), [d, R] = n("all"), z = x(async () => {
26
- k(!0), N("");
26
+ const [p, i] = n(!1), [B, N] = n(!1), [u, k] = n(""), [S, y] = n([]), [s, f] = n(0), [C, z] = n({}), [h, P] = n(""), [d, _] = n("all"), O = E(async () => {
27
+ N(!0), k("");
27
28
  try {
28
29
  const e = await o({
29
30
  currentPage: 1,
@@ -32,16 +33,16 @@ const J = [
32
33
  unreadOnly: d === "unread" || void 0,
33
34
  readOnly: d === "read" || void 0
34
35
  });
35
- y((e == null ? void 0 : e.itemList) || []), f(typeof (e == null ? void 0 : e.unreadTotal) == "number" ? e.unreadTotal : 0), O((e == null ? void 0 : e.unreadByMessageType) || {});
36
+ y((e == null ? void 0 : e.itemList) || []), f(typeof (e == null ? void 0 : e.unreadTotal) == "number" ? e.unreadTotal : 0), z((e == null ? void 0 : e.unreadByMessageType) || {});
36
37
  } catch (e) {
37
- y([]), N(e instanceof Error ? e.message : String(e));
38
+ y([]), k(e instanceof Error ? e.message : String(e));
38
39
  } finally {
39
- k(!1);
40
+ N(!1);
40
41
  }
41
- }, [o, h, w, d]), c = x(async () => {
42
+ }, [o, h, w, d]), c = E(async () => {
42
43
  try {
43
44
  const e = await o({ currentPage: 1, pageSize: 1 });
44
- f(typeof (e == null ? void 0 : e.unreadTotal) == "number" ? e.unreadTotal : 0), O((e == null ? void 0 : e.unreadByMessageType) || {});
45
+ f(typeof (e == null ? void 0 : e.unreadTotal) == "number" ? e.unreadTotal : 0), z((e == null ? void 0 : e.unreadByMessageType) || {});
45
46
  } catch {
46
47
  }
47
48
  }, [o]);
@@ -54,54 +55,54 @@ const J = [
54
55
  }, m);
55
56
  return () => window.clearInterval(e);
56
57
  }, [m, c]), T(() => {
57
- p && z();
58
- }, [p, z]);
59
- const U = D(
60
- () => J.map((e) => {
61
- const t = e.key ? C[e.key] || 0 : s;
58
+ p && O();
59
+ }, [p, O]);
60
+ const j = F(
61
+ () => Q.map((e) => {
62
+ const r = e.key ? C[e.key] || 0 : s;
62
63
  return {
63
64
  key: e.key || "all",
64
- label: t > 0 ? `${e.label} (${t})` : e.label
65
+ label: r > 0 ? `${e.label} (${r})` : e.label
65
66
  };
66
67
  }),
67
68
  [C, s]
68
- ), W = async (e) => {
69
+ ), L = async (e) => {
69
70
  if (!e.read)
70
71
  try {
71
72
  await M(e.id), y((l) => l.map((g) => g.id === e.id ? { ...g, read: !0 } : g)), f((l) => Math.max(0, l - 1));
72
73
  } catch (l) {
73
- _.error(l instanceof Error ? l.message : "标记已读失败");
74
+ A.error(l instanceof Error ? l.message : "标记已读失败");
74
75
  return;
75
76
  }
76
- const t = String(e.href || "").trim();
77
- if (t) {
77
+ const r = String(e.href || "").trim();
78
+ if (r) {
78
79
  if (v) {
79
- v(t, e), i(!1);
80
+ v(r, e), i(!1);
80
81
  return;
81
82
  }
82
- t.startsWith("http://") || t.startsWith("https://") ? window.open(t, "_blank", "noopener,noreferrer") : window.location.assign(t), i(!1);
83
+ r.startsWith("http://") || r.startsWith("https://") ? window.open(r, "_blank", "noopener,noreferrer") : window.location.assign(r), i(!1);
83
84
  }
84
85
  };
85
- return /* @__PURE__ */ b("div", { className: E(r.bellWrap, P), children: [
86
- /* @__PURE__ */ a($, { count: s, size: "small", overflowCount: 99, offset: [-4, 4], children: /* @__PURE__ */ a(
87
- A,
86
+ return /* @__PURE__ */ b("div", { className: x(t.bellWrap, H), children: [
87
+ /* @__PURE__ */ a(R, { count: s, size: "small", overflowCount: 99, offset: [-4, 4], children: /* @__PURE__ */ a(
88
+ U,
88
89
  {
89
90
  type: "text",
90
- className: r.bellBtn,
91
+ className: t.bellBtn,
91
92
  icon: /* @__PURE__ */ a(K, { size: 16, "aria-hidden": !0 }),
92
93
  "aria-label": s > 0 ? `站内信,${s} 条未读` : "站内信",
93
94
  onClick: () => i(!0)
94
95
  }
95
96
  ) }),
96
97
  /* @__PURE__ */ b(
97
- F,
98
+ W,
98
99
  {
99
- title: j,
100
+ title: I,
100
101
  open: p,
101
102
  onClose: () => i(!1),
102
103
  size: 420,
103
104
  destroyOnClose: !1,
104
- className: r.drawer,
105
+ className: t.drawer,
105
106
  styles: {
106
107
  header: { padding: "12px 16px" },
107
108
  body: { padding: "12px 16px" }
@@ -110,20 +111,20 @@ const J = [
110
111
  /* @__PURE__ */ a(
111
112
  Y,
112
113
  {
113
- className: r.typeTabs,
114
+ className: t.typeTabs,
114
115
  size: "small",
115
116
  activeKey: h || "all",
116
- onChange: (e) => I(e === "all" ? "" : e),
117
- stateOption: U,
117
+ onChange: (e) => P(e === "all" ? "" : e),
118
+ stateOption: j,
118
119
  isInner: !0
119
120
  }
120
121
  ),
121
- /* @__PURE__ */ a("div", { className: r.filterRow, children: /* @__PURE__ */ a(
122
+ /* @__PURE__ */ a("div", { className: t.filterRow, children: /* @__PURE__ */ a(
122
123
  q,
123
124
  {
124
125
  size: "small",
125
126
  value: d,
126
- onChange: (e) => R(e),
127
+ onChange: (e) => _(e),
127
128
  options: [
128
129
  { value: "all", label: "全部" },
129
130
  { value: "unread", label: "未读" },
@@ -131,17 +132,26 @@ const J = [
131
132
  ]
132
133
  }
133
134
  ) }),
134
- u ? /* @__PURE__ */ a("p", { className: r.error, children: u }) : null,
135
- /* @__PURE__ */ a(G, { spinning: B, children: !B && !u && S.length === 0 ? /* @__PURE__ */ a(H, { description: "暂无站内信" }) : /* @__PURE__ */ a("ul", { className: r.list, children: S.map((e) => /* @__PURE__ */ a("li", { children: /* @__PURE__ */ a(
135
+ u ? /* @__PURE__ */ a("p", { className: t.error, children: u }) : null,
136
+ /* @__PURE__ */ a(G, { spinning: B, children: !B && !u && S.length === 0 ? /* @__PURE__ */ a(J, { description: "暂无站内信" }) : /* @__PURE__ */ a("ul", { className: t.list, children: S.map((e) => /* @__PURE__ */ a("li", { children: /* @__PURE__ */ a(
136
137
  "button",
137
138
  {
138
139
  type: "button",
139
- className: E(r.item, !e.read && r.itemUnread),
140
- onClick: () => void W(e),
141
- children: /* @__PURE__ */ b(L, { orientation: "vertical", size: 2, style: { width: "100%" }, children: [
142
- /* @__PURE__ */ a("span", { className: r.itemTitle, children: e.title || "(无标题)" }),
143
- e.summary ? /* @__PURE__ */ a("span", { className: r.itemSummary, children: e.summary }) : null,
144
- /* @__PURE__ */ a("span", { className: r.itemMeta, children: [e.messageType, e.createdAt].filter(Boolean).join(" · ") || "—" })
140
+ className: x(t.item, !e.read && t.itemUnread),
141
+ onClick: () => void L(e),
142
+ children: /* @__PURE__ */ b($, { orientation: "vertical", size: 2, style: { width: "100%" }, children: [
143
+ /* @__PURE__ */ a("span", { className: t.itemTitle, children: e.title || "(无标题)" }),
144
+ (() => {
145
+ const r = D(e.bodyHtml);
146
+ return r ? /* @__PURE__ */ a(
147
+ "div",
148
+ {
149
+ className: t.itemBodyHtml,
150
+ dangerouslySetInnerHTML: { __html: r }
151
+ }
152
+ ) : e.summary ? /* @__PURE__ */ a("span", { className: t.itemSummary, children: e.summary }) : null;
153
+ })(),
154
+ /* @__PURE__ */ a("span", { className: t.itemMeta, children: [e.messageType, e.createdAt].filter(Boolean).join(" · ") || "—" })
145
155
  ] })
146
156
  }
147
157
  ) }, e.id)) }) })
@@ -151,6 +161,6 @@ const J = [
151
161
  ] });
152
162
  };
153
163
  export {
154
- se as default
164
+ ie as default
155
165
  };
156
166
  //# sourceMappingURL=InboxBell.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InboxBell.js","sources":["../../../../../src/components/Tools/Inbox/InboxBell/InboxBell.tsx"],"sourcesContent":["import { Badge, Button, Drawer, Space, message } from 'antd';\nimport classNames from 'classnames';\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Empty } from '@/components/Empty';\nimport { Bell } from '@/components/Icons';\nimport { PageSpin } from '@/components/Layout';\nimport { SegmentedRadio } from '@/components/SegmentedRadio';\nimport { StateBar } from '@/components/StateBar';\nimport styles from './style.module.scss';\n\nexport type InboxBellMessageType = 'alert' | 'action' | 'remind' | string;\n\nexport type InboxBellItem = {\n id: string;\n title?: string;\n summary?: string;\n read?: boolean;\n messageType?: InboxBellMessageType;\n href?: string;\n createdAt?: string;\n level?: string;\n};\n\nexport type InboxBellListResult = {\n itemList: InboxBellItem[];\n total?: number;\n unreadTotal?: number;\n unreadByMessageType?: Partial<Record<string, number>>;\n};\n\nexport type InboxBellListParams = {\n unreadOnly?: boolean;\n readOnly?: boolean;\n messageType?: InboxBellMessageType;\n currentPage?: number;\n pageSize?: number;\n};\n\nexport type InboxBellProps = {\n /** 拉取站内信(业务注入;须带 JWT 身份,禁止无身份全表) */\n fetchInbox: (params: InboxBellListParams) => Promise<InboxBellListResult>;\n /** 标记已读 */\n markRead: (id: string) => Promise<void | InboxBellItem>;\n /** 点击条目:默认用 window.location / 业务 navigate */\n onNavigate?: (href: string, item: InboxBellItem) => void;\n /** 轮询未读角标(ms);≤0 关闭 */\n pollMs?: number;\n pageSize?: number;\n className?: string;\n /** Drawer 标题 */\n title?: string;\n};\n\nconst TYPE_TABS: Array<{ key: string; label: string }> = [\n { key: '', label: '全部' },\n { key: 'alert', label: '预警' },\n { key: 'action', label: '行动' },\n { key: 'remind', label: '提醒' },\n];\n\n/**\n * 通用站内信铃铛:列表 / 已读 / Tab / 角标。\n * 不含认领、行动等业务动作;由注入的 fetchInbox / markRead / onNavigate 对接消息服务。\n */\nconst InboxBell: React.FC<InboxBellProps> = ({\n fetchInbox,\n markRead,\n onNavigate,\n pollMs = 60_000,\n pageSize = 50,\n className,\n title = '站内信',\n}) => {\n const [open, setOpen] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [items, setItems] = useState<InboxBellItem[]>([]);\n const [unreadTotal, setUnreadTotal] = useState(0);\n const [unreadByType, setUnreadByType] = useState<Partial<Record<string, number>>>({});\n const [messageType, setMessageType] = useState<string>('');\n const [readFilter, setReadFilter] = useState<'all' | 'unread' | 'read'>('all');\n\n const load = useCallback(async () => {\n setLoading(true);\n setError('');\n try {\n const res = await fetchInbox({\n currentPage: 1,\n pageSize,\n messageType: messageType || undefined,\n unreadOnly: readFilter === 'unread' || undefined,\n readOnly: readFilter === 'read' || undefined,\n });\n setItems(res?.itemList || []);\n setUnreadTotal(typeof res?.unreadTotal === 'number' ? res.unreadTotal : 0);\n setUnreadByType(res?.unreadByMessageType || {});\n } catch (e) {\n setItems([]);\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoading(false);\n }\n }, [fetchInbox, messageType, pageSize, readFilter]);\n\n const refreshBadge = useCallback(async () => {\n try {\n const res = await fetchInbox({ currentPage: 1, pageSize: 1 });\n setUnreadTotal(typeof res?.unreadTotal === 'number' ? res.unreadTotal : 0);\n setUnreadByType(res?.unreadByMessageType || {});\n } catch {\n /* 角标失败不打断 UI */\n }\n }, [fetchInbox]);\n\n useEffect(() => {\n void refreshBadge();\n }, [refreshBadge]);\n\n useEffect(() => {\n if (pollMs <= 0) return undefined;\n const t = window.setInterval(() => {\n void refreshBadge();\n }, pollMs);\n return () => window.clearInterval(t);\n }, [pollMs, refreshBadge]);\n\n useEffect(() => {\n if (open) void load();\n }, [open, load]);\n\n const typeTabOptions = useMemo(\n () =>\n TYPE_TABS.map((t) => {\n const n = t.key ? unreadByType[t.key] || 0 : unreadTotal;\n return {\n key: t.key || 'all',\n label: n > 0 ? `${t.label} (${n})` : t.label,\n };\n }),\n [unreadByType, unreadTotal],\n );\n\n const handleOpenItem = async (item: InboxBellItem) => {\n if (!item.read) {\n try {\n await markRead(item.id);\n setItems((prev) => prev.map((x) => (x.id === item.id ? { ...x, read: true } : x)));\n setUnreadTotal((n) => Math.max(0, n - 1));\n } catch (e) {\n message.error(e instanceof Error ? e.message : '标记已读失败');\n return;\n }\n }\n const href = String(item.href || '').trim();\n if (!href) return;\n if (onNavigate) {\n onNavigate(href, item);\n setOpen(false);\n return;\n }\n if (href.startsWith('http://') || href.startsWith('https://')) {\n window.open(href, '_blank', 'noopener,noreferrer');\n } else {\n window.location.assign(href);\n }\n setOpen(false);\n };\n\n return (\n <div className={classNames(styles.bellWrap, className)}>\n <Badge count={unreadTotal} size=\"small\" overflowCount={99} offset={[-4, 4]}>\n <Button\n type=\"text\"\n className={styles.bellBtn}\n icon={<Bell size={16} aria-hidden />}\n aria-label={unreadTotal > 0 ? `站内信,${unreadTotal} 条未读` : '站内信'}\n onClick={() => setOpen(true)}\n />\n </Badge>\n <Drawer\n title={title}\n open={open}\n onClose={() => setOpen(false)}\n size={420}\n destroyOnClose={false}\n className={styles.drawer}\n styles={{\n header: { padding: '12px 16px' },\n body: { padding: '12px 16px' },\n }}\n >\n <StateBar\n className={styles.typeTabs}\n size=\"small\"\n activeKey={messageType || 'all'}\n onChange={(k) => setMessageType(k === 'all' ? '' : k)}\n stateOption={typeTabOptions}\n isInner\n />\n <div className={styles.filterRow}>\n <SegmentedRadio<'all' | 'unread' | 'read'>\n size=\"small\"\n value={readFilter}\n onChange={(v) => setReadFilter(v)}\n options={[\n { value: 'all', label: '全部' },\n { value: 'unread', label: '未读' },\n { value: 'read', label: '已读' },\n ]}\n />\n </div>\n {error ? <p className={styles.error}>{error}</p> : null}\n <PageSpin spinning={loading}>\n {!loading && !error && items.length === 0 ? (\n <Empty description=\"暂无站内信\" />\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li key={item.id}>\n <button\n type=\"button\"\n className={classNames(styles.item, !item.read && styles.itemUnread)}\n onClick={() => void handleOpenItem(item)}\n >\n <Space orientation=\"vertical\" size={2} style={{ width: '100%' }}>\n <span className={styles.itemTitle}>{item.title || '(无标题)'}</span>\n {item.summary ? (\n <span className={styles.itemSummary}>{item.summary}</span>\n ) : null}\n <span className={styles.itemMeta}>\n {[item.messageType, item.createdAt].filter(Boolean).join(' · ') || '—'}\n </span>\n </Space>\n </button>\n </li>\n ))}\n </ul>\n )}\n </PageSpin>\n </Drawer>\n </div>\n );\n};\n\nexport default InboxBell;\n"],"names":["TYPE_TABS","InboxBell","fetchInbox","markRead","onNavigate","pollMs","pageSize","className","title","open","setOpen","useState","loading","setLoading","error","setError","items","setItems","unreadTotal","setUnreadTotal","unreadByType","setUnreadByType","messageType","setMessageType","readFilter","setReadFilter","load","useCallback","res","refreshBadge","useEffect","t","typeTabOptions","useMemo","n","handleOpenItem","item","prev","x","e","message","href","classNames","styles","jsx","Badge","Button","Bell","jsxs","Drawer","StateBar","k","SegmentedRadio","v","PageSpin","Empty","Space"],"mappings":"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"}
1
+ {"version":3,"file":"InboxBell.js","sources":["../../../../../src/components/Tools/Inbox/InboxBell/InboxBell.tsx"],"sourcesContent":["import { Badge, Button, Drawer, Space, message } from 'antd';\nimport classNames from 'classnames';\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { Empty } from '@/components/Empty';\nimport { Bell } from '@/components/Icons';\nimport { PageSpin } from '@/components/Layout';\nimport { SegmentedRadio } from '@/components/SegmentedRadio';\nimport { StateBar } from '@/components/StateBar';\nimport { sanitizeInboxHtml } from '../sanitizeInboxHtml';\nimport styles from './style.module.scss';\n\nexport type InboxBellMessageType = 'alert' | 'action' | 'remind' | string;\n\nexport type InboxBellItem = {\n id: string;\n title?: string;\n /** 纯文本摘要(列表兼容) */\n summary?: string;\n /** 已渲染 HTML 正文;空则主摘要位回落 summary */\n bodyHtml?: string | null;\n read?: boolean;\n messageType?: InboxBellMessageType;\n href?: string;\n createdAt?: string;\n level?: string;\n};\n\nexport type InboxBellListResult = {\n itemList: InboxBellItem[];\n total?: number;\n unreadTotal?: number;\n unreadByMessageType?: Partial<Record<string, number>>;\n};\n\nexport type InboxBellListParams = {\n unreadOnly?: boolean;\n readOnly?: boolean;\n messageType?: InboxBellMessageType;\n currentPage?: number;\n pageSize?: number;\n};\n\nexport type InboxBellProps = {\n /** 拉取站内信(业务注入;须带 JWT 身份,禁止无身份全表) */\n fetchInbox: (params: InboxBellListParams) => Promise<InboxBellListResult>;\n /** 标记已读 */\n markRead: (id: string) => Promise<void | InboxBellItem>;\n /** 点击条目:默认用 window.location / 业务 navigate */\n onNavigate?: (href: string, item: InboxBellItem) => void;\n /** 轮询未读角标(ms);≤0 关闭 */\n pollMs?: number;\n pageSize?: number;\n className?: string;\n /** Drawer 标题 */\n title?: string;\n};\n\nconst TYPE_TABS: Array<{ key: string; label: string }> = [\n { key: '', label: '全部' },\n { key: 'alert', label: '预警' },\n { key: 'action', label: '行动' },\n { key: 'remind', label: '提醒' },\n];\n\n/**\n * 通用站内信铃铛:列表 / 已读 / Tab / 角标。\n * 不含认领、行动等业务动作;由注入的 fetchInbox / markRead / onNavigate 对接消息服务。\n */\nconst InboxBell: React.FC<InboxBellProps> = ({\n fetchInbox,\n markRead,\n onNavigate,\n pollMs = 60_000,\n pageSize = 50,\n className,\n title = '站内信',\n}) => {\n const [open, setOpen] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [items, setItems] = useState<InboxBellItem[]>([]);\n const [unreadTotal, setUnreadTotal] = useState(0);\n const [unreadByType, setUnreadByType] = useState<Partial<Record<string, number>>>({});\n const [messageType, setMessageType] = useState<string>('');\n const [readFilter, setReadFilter] = useState<'all' | 'unread' | 'read'>('all');\n\n const load = useCallback(async () => {\n setLoading(true);\n setError('');\n try {\n const res = await fetchInbox({\n currentPage: 1,\n pageSize,\n messageType: messageType || undefined,\n unreadOnly: readFilter === 'unread' || undefined,\n readOnly: readFilter === 'read' || undefined,\n });\n setItems(res?.itemList || []);\n setUnreadTotal(typeof res?.unreadTotal === 'number' ? res.unreadTotal : 0);\n setUnreadByType(res?.unreadByMessageType || {});\n } catch (e) {\n setItems([]);\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n setLoading(false);\n }\n }, [fetchInbox, messageType, pageSize, readFilter]);\n\n const refreshBadge = useCallback(async () => {\n try {\n const res = await fetchInbox({ currentPage: 1, pageSize: 1 });\n setUnreadTotal(typeof res?.unreadTotal === 'number' ? res.unreadTotal : 0);\n setUnreadByType(res?.unreadByMessageType || {});\n } catch {\n /* 角标失败不打断 UI */\n }\n }, [fetchInbox]);\n\n useEffect(() => {\n void refreshBadge();\n }, [refreshBadge]);\n\n useEffect(() => {\n if (pollMs <= 0) return undefined;\n const t = window.setInterval(() => {\n void refreshBadge();\n }, pollMs);\n return () => window.clearInterval(t);\n }, [pollMs, refreshBadge]);\n\n useEffect(() => {\n if (open) void load();\n }, [open, load]);\n\n const typeTabOptions = useMemo(\n () =>\n TYPE_TABS.map((t) => {\n const n = t.key ? unreadByType[t.key] || 0 : unreadTotal;\n return {\n key: t.key || 'all',\n label: n > 0 ? `${t.label} (${n})` : t.label,\n };\n }),\n [unreadByType, unreadTotal],\n );\n\n const handleOpenItem = async (item: InboxBellItem) => {\n if (!item.read) {\n try {\n await markRead(item.id);\n setItems((prev) => prev.map((x) => (x.id === item.id ? { ...x, read: true } : x)));\n setUnreadTotal((n) => Math.max(0, n - 1));\n } catch (e) {\n message.error(e instanceof Error ? e.message : '标记已读失败');\n return;\n }\n }\n const href = String(item.href || '').trim();\n if (!href) return;\n if (onNavigate) {\n onNavigate(href, item);\n setOpen(false);\n return;\n }\n if (href.startsWith('http://') || href.startsWith('https://')) {\n window.open(href, '_blank', 'noopener,noreferrer');\n } else {\n window.location.assign(href);\n }\n setOpen(false);\n };\n\n return (\n <div className={classNames(styles.bellWrap, className)}>\n <Badge count={unreadTotal} size=\"small\" overflowCount={99} offset={[-4, 4]}>\n <Button\n type=\"text\"\n className={styles.bellBtn}\n icon={<Bell size={16} aria-hidden />}\n aria-label={unreadTotal > 0 ? `站内信,${unreadTotal} 条未读` : '站内信'}\n onClick={() => setOpen(true)}\n />\n </Badge>\n <Drawer\n title={title}\n open={open}\n onClose={() => setOpen(false)}\n size={420}\n destroyOnClose={false}\n className={styles.drawer}\n styles={{\n header: { padding: '12px 16px' },\n body: { padding: '12px 16px' },\n }}\n >\n <StateBar\n className={styles.typeTabs}\n size=\"small\"\n activeKey={messageType || 'all'}\n onChange={(k) => setMessageType(k === 'all' ? '' : k)}\n stateOption={typeTabOptions}\n isInner\n />\n <div className={styles.filterRow}>\n <SegmentedRadio<'all' | 'unread' | 'read'>\n size=\"small\"\n value={readFilter}\n onChange={(v) => setReadFilter(v)}\n options={[\n { value: 'all', label: '全部' },\n { value: 'unread', label: '未读' },\n { value: 'read', label: '已读' },\n ]}\n />\n </div>\n {error ? <p className={styles.error}>{error}</p> : null}\n <PageSpin spinning={loading}>\n {!loading && !error && items.length === 0 ? (\n <Empty description=\"暂无站内信\" />\n ) : (\n <ul className={styles.list}>\n {items.map((item) => (\n <li key={item.id}>\n <button\n type=\"button\"\n className={classNames(styles.item, !item.read && styles.itemUnread)}\n onClick={() => void handleOpenItem(item)}\n >\n <Space orientation=\"vertical\" size={2} style={{ width: '100%' }}>\n <span className={styles.itemTitle}>{item.title || '(无标题)'}</span>\n {(() => {\n const safeHtml = sanitizeInboxHtml(item.bodyHtml);\n if (safeHtml) {\n return (\n <div\n className={styles.itemBodyHtml}\n dangerouslySetInnerHTML={{ __html: safeHtml }}\n />\n );\n }\n return item.summary ? (\n <span className={styles.itemSummary}>{item.summary}</span>\n ) : null;\n })()}\n <span className={styles.itemMeta}>\n {[item.messageType, item.createdAt].filter(Boolean).join(' · ') || '—'}\n </span>\n </Space>\n </button>\n </li>\n ))}\n </ul>\n )}\n </PageSpin>\n </Drawer>\n </div>\n );\n};\n\nexport default InboxBell;\n"],"names":["TYPE_TABS","InboxBell","fetchInbox","markRead","onNavigate","pollMs","pageSize","className","title","open","setOpen","useState","loading","setLoading","error","setError","items","setItems","unreadTotal","setUnreadTotal","unreadByType","setUnreadByType","messageType","setMessageType","readFilter","setReadFilter","load","useCallback","res","refreshBadge","useEffect","t","typeTabOptions","useMemo","n","handleOpenItem","item","prev","x","e","message","href","classNames","styles","jsx","Badge","Button","Bell","jsxs","Drawer","StateBar","k","SegmentedRadio","v","PageSpin","Empty","Space","safeHtml","sanitizeInboxHtml"],"mappings":"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"}
@@ -1,30 +1,32 @@
1
- const t = "_bellWrap_5qboz_1", e = "_drawer_5qboz_9", _ = "_bellBtn_5qboz_16", o = "_typeTabs_5qboz_35", r = "_filterRow_5qboz_42", i = "_error_5qboz_50", l = "_list_5qboz_56", s = "_item_5qboz_65", b = "_itemUnread_5qboz_79", m = "_itemTitle_5qboz_84", a = "_itemSummary_5qboz_92", n = "_itemMeta_5qboz_100", c = {
1
+ const t = "_bellWrap_1t9v6_1", e = "_drawer_1t9v6_9", _ = "_bellBtn_1t9v6_16", r = "_typeTabs_1t9v6_35", i = "_filterRow_1t9v6_42", m = "_error_1t9v6_50", l = "_list_1t9v6_56", o = "_item_1t9v6_65", s = "_itemUnread_1t9v6_79", a = "_itemTitle_1t9v6_84", n = "_itemSummary_1t9v6_92", c = "_itemBodyHtml_1t9v6_100", v = "_itemMeta_1t9v6_120", d = {
2
2
  bellWrap: t,
3
3
  drawer: e,
4
4
  bellBtn: _,
5
- typeTabs: o,
6
- filterRow: r,
7
- error: i,
5
+ typeTabs: r,
6
+ filterRow: i,
7
+ error: m,
8
8
  list: l,
9
- item: s,
10
- itemUnread: b,
11
- itemTitle: m,
12
- itemSummary: a,
13
- itemMeta: n
9
+ item: o,
10
+ itemUnread: s,
11
+ itemTitle: a,
12
+ itemSummary: n,
13
+ itemBodyHtml: c,
14
+ itemMeta: v
14
15
  };
15
16
  export {
16
17
  _ as bellBtn,
17
18
  t as bellWrap,
18
- c as default,
19
+ d as default,
19
20
  e as drawer,
20
- i as error,
21
- r as filterRow,
22
- s as item,
23
- n as itemMeta,
24
- a as itemSummary,
25
- m as itemTitle,
26
- b as itemUnread,
21
+ m as error,
22
+ i as filterRow,
23
+ o as item,
24
+ c as itemBodyHtml,
25
+ v as itemMeta,
26
+ n as itemSummary,
27
+ a as itemTitle,
28
+ s as itemUnread,
27
29
  l as list,
28
- o as typeTabs
30
+ r as typeTabs
29
31
  };
30
32
  //# sourceMappingURL=style.module.scss.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"style.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"style.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
@@ -1,2 +1,3 @@
1
1
  export { InboxBell } from './InboxBell';
2
2
  export type { InboxBellItem, InboxBellListResult, InboxBellListParams, InboxBellProps, InboxBellMessageType, } from './InboxBell';
3
+ export { sanitizeInboxHtml } from './sanitizeInboxHtml';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 站内信 bodyHtml → 安全 HTML(isomorphic-dompurify,浏览器与 Node/单测一致)。
3
+ * 空串返回 ''。
4
+ */
5
+ export declare function sanitizeInboxHtml(raw: string | null | undefined): string;
@@ -0,0 +1,14 @@
1
+ import e from "../../../node_modules/isomorphic-dompurify/dist/browser.js";
2
+ const i = {
3
+ ALLOWED_TAGS: ["p", "br", "strong", "b", "em", "i", "u", "ul", "ol", "li", "span", "div", "a"],
4
+ ALLOWED_ATTR: ["style", "class", "href", "target", "rel"],
5
+ ALLOW_DATA_ATTR: !1
6
+ };
7
+ function s(t) {
8
+ const r = String(t || "").trim();
9
+ return r ? e.sanitize(r, i) : "";
10
+ }
11
+ export {
12
+ s as sanitizeInboxHtml
13
+ };
14
+ //# sourceMappingURL=sanitizeInboxHtml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sanitizeInboxHtml.js","sources":["../../../../src/components/Tools/Inbox/sanitizeInboxHtml.ts"],"sourcesContent":["import DOMPurify from 'isomorphic-dompurify';\nimport type { Config } from 'dompurify';\n\n/** CKEditor 常用标签白名单;禁 script / 事件属性 */\nconst INBOX_HTML_CONFIG: Config = {\n ALLOWED_TAGS: ['p', 'br', 'strong', 'b', 'em', 'i', 'u', 'ul', 'ol', 'li', 'span', 'div', 'a'],\n ALLOWED_ATTR: ['style', 'class', 'href', 'target', 'rel'],\n ALLOW_DATA_ATTR: false,\n};\n\n/**\n * 站内信 bodyHtml → 安全 HTML(isomorphic-dompurify,浏览器与 Node/单测一致)。\n * 空串返回 ''。\n */\nexport function sanitizeInboxHtml(raw: string | null | undefined): string {\n const src = String(raw || '').trim();\n if (!src) return '';\n return DOMPurify.sanitize(src, INBOX_HTML_CONFIG);\n}\n"],"names":["INBOX_HTML_CONFIG","sanitizeInboxHtml","raw","src","DOMPurify"],"mappings":";AAIA,MAAMA,IAA4B;AAAA,EAChC,cAAc,CAAC,KAAK,MAAM,UAAU,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,MAAM,QAAQ,OAAO,GAAG;AAAA,EAC7F,cAAc,CAAC,SAAS,SAAS,QAAQ,UAAU,KAAK;AAAA,EACxD,iBAAiB;AACnB;AAMO,SAASC,EAAkBC,GAAwC;AACxE,QAAMC,IAAM,OAAOD,KAAO,EAAE,EAAE,KAAA;AAC9B,SAAKC,IACEC,EAAU,SAASD,GAAKH,CAAiB,IAD/B;AAEnB;"}
@@ -1,7 +1,7 @@
1
1
  import { ColumnsType } from 'antd/es/table';
2
2
  import { MessageTemplateAdminItem } from '../types';
3
3
  export declare function buildTemplateColumns(opts: {
4
- canWrite: boolean;
4
+ canUpdate: boolean;
5
5
  eventLabel: (eventKey?: string) => string;
6
6
  onEdit: (row: MessageTemplateAdminItem) => void;
7
7
  onToggleEnabled: (row: MessageTemplateAdminItem, enabled: boolean) => void;
@@ -5,8 +5,8 @@ const m = {
5
5
  action: "行动跟踪",
6
6
  remind: "任务提醒"
7
7
  };
8
- function p(d) {
9
- const { canWrite: i, eventLabel: l, onEdit: r, onToggleEnabled: a } = d;
8
+ function b(d) {
9
+ const { canUpdate: i, eventLabel: l, onEdit: r, onToggleEnabled: a } = d;
10
10
  return [
11
11
  {
12
12
  title: "编号",
@@ -51,6 +51,6 @@ function p(d) {
51
51
  ];
52
52
  }
53
53
  export {
54
- p as buildTemplateColumns
54
+ b as buildTemplateColumns
55
55
  };
56
56
  //# sourceMappingURL=columns.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"columns.js","sources":["../../../../../../src/components/Tools/MessageCenter/MessageTemplateAdmin/List/columns.tsx"],"sourcesContent":["import type { ColumnsType } from 'antd/es/table';\nimport { Button, Switch } from 'antd';\nimport type { MessageTemplateAdminItem } from '../types';\n\nconst TYPE_LABELS: Record<string, string> = {\n alert: '预警消息',\n action: '行动跟踪',\n remind: '任务提醒',\n};\n\nexport function buildTemplateColumns(opts: {\n canWrite: boolean;\n eventLabel: (eventKey?: string) => string;\n onEdit: (row: MessageTemplateAdminItem) => void;\n onToggleEnabled: (row: MessageTemplateAdminItem, enabled: boolean) => void;\n}): ColumnsType<MessageTemplateAdminItem> {\n const { canWrite, eventLabel, onEdit, onToggleEnabled } = opts;\n return [\n {\n title: '编号',\n dataIndex: 'code',\n width: 150,\n render: (v: string) => <code>{v || '—'}</code>,\n },\n {\n title: '场景',\n key: 'scenario',\n render: (_, r) => r.scenario || r.label || '—',\n },\n {\n title: '事件',\n key: 'event',\n width: 160,\n render: (_, r) => eventLabel(r.eventKey),\n },\n {\n title: '类型',\n width: 100,\n render: (_, r) => TYPE_LABELS[r.messageType || ''] || r.messageType || '—',\n },\n {\n title: '启用',\n width: 90,\n render: (_, r) => (\n <Switch\n size=\"small\"\n checked={r.enabled !== false}\n disabled={!canWrite}\n onChange={(checked) => onToggleEnabled(r, checked)}\n />\n ),\n },\n {\n title: '操作',\n width: 100,\n render: (_, r) => (\n <Button type=\"link\" size=\"small\" disabled={!canWrite} onClick={() => onEdit(r)}>\n 编辑\n </Button>\n ),\n },\n ];\n}\n"],"names":["TYPE_LABELS","buildTemplateColumns","opts","canWrite","eventLabel","onEdit","onToggleEnabled","v","jsx","_","r","Switch","checked","Button"],"mappings":";;AAIA,MAAMA,IAAsC;AAAA,EAC1C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,SAASC,EAAqBC,GAKK;AACxC,QAAM,EAAE,UAAAC,GAAU,YAAAC,GAAY,QAAAC,GAAQ,iBAAAC,MAAoBJ;AAC1D,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,MACP,QAAQ,CAACK,MAAc,gBAAAC,EAAC,QAAA,EAAM,eAAK,IAAA,CAAI;AAAA,IAAA;AAAA,IAEzC;AAAA,MACE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,QAAQ,CAACC,GAAGC,MAAMA,EAAE,YAAYA,EAAE,SAAS;AAAA,IAAA;AAAA,IAE7C;AAAA,MACE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MAAMN,EAAWM,EAAE,QAAQ;AAAA,IAAA;AAAA,IAEzC;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MAAMV,EAAYU,EAAE,eAAe,EAAE,KAAKA,EAAE,eAAe;AAAA,IAAA;AAAA,IAEzE;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MACV,gBAAAF;AAAA,QAACG;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAASD,EAAE,YAAY;AAAA,UACvB,UAAU,CAACP;AAAA,UACX,UAAU,CAACS,MAAYN,EAAgBI,GAAGE,CAAO;AAAA,QAAA;AAAA,MAAA;AAAA,IACnD;AAAA,IAGJ;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACH,GAAGC,MACV,gBAAAF,EAACK,GAAA,EAAO,MAAK,QAAO,MAAK,SAAQ,UAAU,CAACV,GAAU,SAAS,MAAME,EAAOK,CAAC,GAAG,UAAA,KAAA,CAEhF;AAAA,IAAA;AAAA,EAEJ;AAEJ;"}
1
+ {"version":3,"file":"columns.js","sources":["../../../../../../src/components/Tools/MessageCenter/MessageTemplateAdmin/List/columns.tsx"],"sourcesContent":["import type { ColumnsType } from 'antd/es/table';\nimport { Button, Switch } from 'antd';\nimport type { MessageTemplateAdminItem } from '../types';\n\nconst TYPE_LABELS: Record<string, string> = {\n alert: '预警消息',\n action: '行动跟踪',\n remind: '任务提醒',\n};\n\nexport function buildTemplateColumns(opts: {\n canUpdate: boolean;\n eventLabel: (eventKey?: string) => string;\n onEdit: (row: MessageTemplateAdminItem) => void;\n onToggleEnabled: (row: MessageTemplateAdminItem, enabled: boolean) => void;\n}): ColumnsType<MessageTemplateAdminItem> {\n const { canUpdate, eventLabel, onEdit, onToggleEnabled } = opts;\n return [\n {\n title: '编号',\n dataIndex: 'code',\n width: 150,\n render: (v: string) => <code>{v || '—'}</code>,\n },\n {\n title: '场景',\n key: 'scenario',\n render: (_, r) => r.scenario || r.label || '—',\n },\n {\n title: '事件',\n key: 'event',\n width: 160,\n render: (_, r) => eventLabel(r.eventKey),\n },\n {\n title: '类型',\n width: 100,\n render: (_, r) => TYPE_LABELS[r.messageType || ''] || r.messageType || '—',\n },\n {\n title: '启用',\n width: 90,\n render: (_, r) => (\n <Switch\n size=\"small\"\n checked={r.enabled !== false}\n disabled={!canUpdate}\n onChange={(checked) => onToggleEnabled(r, checked)}\n />\n ),\n },\n {\n title: '操作',\n width: 100,\n render: (_, r) => (\n <Button type=\"link\" size=\"small\" disabled={!canUpdate} onClick={() => onEdit(r)}>\n 编辑\n </Button>\n ),\n },\n ];\n}\n"],"names":["TYPE_LABELS","buildTemplateColumns","opts","canUpdate","eventLabel","onEdit","onToggleEnabled","v","jsx","_","r","Switch","checked","Button"],"mappings":";;AAIA,MAAMA,IAAsC;AAAA,EAC1C,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,SAASC,EAAqBC,GAKK;AACxC,QAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,QAAAC,GAAQ,iBAAAC,MAAoBJ;AAC3D,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,MACP,QAAQ,CAACK,MAAc,gBAAAC,EAAC,QAAA,EAAM,eAAK,IAAA,CAAI;AAAA,IAAA;AAAA,IAEzC;AAAA,MACE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,QAAQ,CAACC,GAAGC,MAAMA,EAAE,YAAYA,EAAE,SAAS;AAAA,IAAA;AAAA,IAE7C;AAAA,MACE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MAAMN,EAAWM,EAAE,QAAQ;AAAA,IAAA;AAAA,IAEzC;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MAAMV,EAAYU,EAAE,eAAe,EAAE,KAAKA,EAAE,eAAe;AAAA,IAAA;AAAA,IAEzE;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACD,GAAGC,MACV,gBAAAF;AAAA,QAACG;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAASD,EAAE,YAAY;AAAA,UACvB,UAAU,CAACP;AAAA,UACX,UAAU,CAACS,MAAYN,EAAgBI,GAAGE,CAAO;AAAA,QAAA;AAAA,MAAA;AAAA,IACnD;AAAA,IAGJ;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,QAAQ,CAACH,GAAGC,MACV,gBAAAF,EAACK,GAAA,EAAO,MAAK,QAAO,MAAK,SAAQ,UAAU,CAACV,GAAW,SAAS,MAAME,EAAOK,CAAC,GAAG,UAAA,KAAA,CAEjF;AAAA,IAAA;AAAA,EAEJ;AAEJ;"}