@hkyhy/marsun-components-core 0.1.56 → 0.1.58

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
@@ -70,11 +70,11 @@ AgentHub / File 预览 / Llm 走子路径,避免无相关产品首包拖入重
70
70
 
71
71
  包根仍 re-export L2(迁移期 `@deprecated`);新代码请用子路径。
72
72
 
73
- ### Layout(v0.1.56+)
73
+ ### Layout(v0.1.57+)
74
74
 
75
75
  `AgentAppShell` 侧栏折叠改为边缘竖条 tab(主题色);`UserProfileCard` / brand 折叠态水平居中。
76
76
 
77
- > 0.1.54/0.1.55 因 typecheck 未发布;以 **0.1.56** 为准。
77
+ > 0.1.54/0.1.55 因 typecheck 未发布;0.1.56 修 showcase;**0.1.57** PermissionBindPanel 勾选性能。
78
78
 
79
79
  项目可在 `src/styles/tokens.css` 扩展领域变量,详见 showcase 内 `frontend-dev-spec` → `theme.md`。
80
80
 
@@ -1,43 +1,43 @@
1
- import { jsx as m, jsxs as y, Fragment as j } from "react/jsx-runtime";
2
- import { Empty as A, Row as F, Col as G, Typography as I, Checkbox as M } from "antd";
3
- import { useMemo as v, useEffect as L, useState as H } from "react";
4
- function U(d, f) {
5
- const r = /* @__PURE__ */ new Set(), l = [], n = [];
6
- for (const t of d.modules) {
7
- const s = [], c = [], g = [];
8
- for (const a of t.categories) {
9
- const k = [];
10
- for (const i of a.leaves) {
11
- r.add(i.code);
12
- const p = f.get(i.code), b = !!i.defaultGranted;
13
- k.push({
14
- code: i.code,
15
- label: i.label,
16
- defaultGranted: b,
1
+ import { jsx as h, jsxs as y, Fragment as D } from "react/jsx-runtime";
2
+ import { Empty as W, Row as K, Col as R, Typography as T, Checkbox as G } from "antd";
3
+ import { useMemo as w, useCallback as E, useEffect as j, startTransition as A, useState as Y, memo as _ } from "react";
4
+ function J(c, a) {
5
+ const r = /* @__PURE__ */ new Set(), s = [], n = [];
6
+ for (const t of c.modules) {
7
+ const m = [], f = [], l = [];
8
+ for (const u of t.categories) {
9
+ const b = [];
10
+ for (const d of u.leaves) {
11
+ r.add(d.code);
12
+ const p = a.get(d.code), g = !!d.defaultGranted;
13
+ b.push({
14
+ code: d.code,
15
+ label: d.label,
16
+ defaultGranted: g,
17
17
  perm: p
18
- }), p && (c.push(p), b && (l.push(p.id), g.push(p.id)));
18
+ }), p && (f.push(p), g && (s.push(p.id), l.push(p.id)));
19
19
  }
20
- k.length && s.push({ key: a.key, label: a.label, leaves: k });
20
+ b.length && m.push({ key: u.key, label: u.label, leaves: b });
21
21
  }
22
- s.length && n.push({
22
+ m.length && n.push({
23
23
  key: t.key,
24
24
  label: t.label,
25
25
  requiresSystemEntry: !!t.requiresSystemEntry,
26
- categories: s,
27
- perms: c,
28
- lockedPermIds: g
26
+ categories: m,
27
+ perms: f,
28
+ lockedPermIds: l
29
29
  });
30
30
  }
31
- return { modules: n, usedCodes: r, lockedIds: l };
31
+ return { modules: n, usedCodes: r, lockedIds: s };
32
32
  }
33
- function D(d) {
34
- const f = /* @__PURE__ */ new Map();
35
- for (const r of d) {
36
- const l = r.code.includes(":") ? r.code.split(":")[0] : "_other", n = f.get(l) || [];
37
- n.push(r), f.set(l, n);
33
+ function N(c) {
34
+ const a = /* @__PURE__ */ new Map();
35
+ for (const r of c) {
36
+ const s = r.code.includes(":") ? r.code.split(":")[0] : "_other", n = a.get(s) || [];
37
+ n.push(r), a.set(s, n);
38
38
  }
39
- return [...f.entries()].map(([r, l]) => {
40
- const n = [...l].sort((t, s) => t.code.localeCompare(s.code));
39
+ return [...a.entries()].map(([r, s]) => {
40
+ const n = [...s].sort((t, m) => t.code.localeCompare(m.code));
41
41
  return {
42
42
  key: r,
43
43
  label: r,
@@ -59,12 +59,12 @@ function D(d) {
59
59
  };
60
60
  });
61
61
  }
62
- function W(d, f, r) {
63
- const l = f.filter((t) => !r.has(t.code));
64
- if (!l.length) return d;
65
- const n = [...l].sort((t, s) => t.code.localeCompare(s.code));
62
+ function Q(c, a, r) {
63
+ const s = a.filter((t) => !r.has(t.code));
64
+ if (!s.length) return c;
65
+ const n = [...s].sort((t, m) => t.code.localeCompare(m.code));
66
66
  return [
67
- ...d,
67
+ ...c,
68
68
  {
69
69
  key: "uncategorized",
70
70
  label: "未分类",
@@ -86,112 +86,129 @@ function W(d, f, r) {
86
86
  }
87
87
  ];
88
88
  }
89
- function N({
90
- catalog: d,
91
- permissions: f,
89
+ function O({
90
+ catalog: c,
91
+ permissions: a,
92
92
  value: r,
93
- onChange: l,
93
+ onChange: s,
94
94
  systemEntryCodes: n = [],
95
95
  readOnly: t = !1,
96
- className: s,
97
- style: c,
98
- height: g = 420
96
+ className: m,
97
+ style: f,
98
+ height: l = 420
99
99
  }) {
100
- const a = v(() => f.filter((e) => e.layer !== "RESOURCE"), [f]), k = v(() => {
100
+ const u = w(() => a.filter((e) => e.layer !== "RESOURCE"), [a]), b = w(() => {
101
101
  const e = /* @__PURE__ */ new Map();
102
- for (const o of a) e.set(o.code, o);
102
+ for (const o of u) e.set(o.code, o);
103
103
  return e;
104
- }, [a]), { modules: i, lockedIds: p } = v(() => {
104
+ }, [u]), { modules: d, lockedIds: p } = w(() => {
105
105
  var e;
106
- if ((e = d == null ? void 0 : d.modules) != null && e.length) {
107
- const o = U(d, k);
106
+ if ((e = c == null ? void 0 : c.modules) != null && e.length) {
107
+ const o = J(c, b);
108
108
  return {
109
- modules: W(o.modules, a, o.usedCodes),
109
+ modules: Q(o.modules, u, o.usedCodes),
110
110
  lockedIds: o.lockedIds
111
111
  };
112
112
  }
113
- return { modules: D(a), lockedIds: [] };
114
- }, [d, k, a]), b = v(() => new Set(p), [p]), w = v(() => {
113
+ return { modules: N(u), lockedIds: [] };
114
+ }, [c, b, u]), g = w(() => new Set(p), [p]), x = w(() => new Set(r), [r]), S = w(() => {
115
115
  if (t || !n.length) return !0;
116
- const e = a.filter((o) => n.includes(o.code)).map((o) => o.id);
117
- return e.length ? e.some((o) => r.includes(o)) : !0;
118
- }, [t, n, a, r]), P = (e) => w ? [.../* @__PURE__ */ new Set([...e, ...p])] : e;
119
- L(() => {
120
- if (t || !w || !p.length) return;
121
- p.filter((o) => !r.includes(o)).length && l(P(r));
122
- }, [p.join("|"), w, t]);
123
- const [T, C] = H("");
124
- L(() => {
125
- if (!i.length) {
126
- C("");
116
+ const e = u.filter((o) => n.includes(o.code)).map((o) => o.id);
117
+ return e.length ? e.some((o) => x.has(o)) : !0;
118
+ }, [t, n, u, x]), M = E(
119
+ (e) => S ? [.../* @__PURE__ */ new Set([...e, ...p])] : e,
120
+ [S, p]
121
+ );
122
+ j(() => {
123
+ if (t || !S || !p.length) return;
124
+ p.filter((o) => !x.has(o)).length && A(() => s(M(r)));
125
+ }, [p.join("|"), S, t]);
126
+ const [P, B] = Y("");
127
+ j(() => {
128
+ if (!d.length) {
129
+ B("");
127
130
  return;
128
131
  }
129
- i.some((e) => e.key === T) || C(i[0].key);
130
- }, [i, T]);
131
- const u = i.find((e) => e.key === T) || i[0], q = (e) => !!(e != null && e.requiresSystemEntry && !w), E = (e) => {
132
- t || l(P(e));
133
- }, z = (e, o) => {
134
- t || w && b.has(e) || E(o ? [...r, e] : r.filter((x) => x !== e));
135
- }, R = (e, o) => {
136
- if (t) return;
137
- const x = e.perms.filter((h) => !b.has(h.id)).map((h) => h.id);
138
- if (o) E([...r, ...x]);
139
- else {
140
- const h = new Set(x);
141
- E(r.filter((S) => !h.has(S)));
142
- }
143
- };
144
- if (!i.length)
145
- return /* @__PURE__ */ m(A, { description: "暂无权限点", className: s, style: c });
146
- const B = q(u);
132
+ d.some((e) => e.key === P) || B(d[0].key);
133
+ }, [d, P]);
134
+ const i = d.find((e) => e.key === P) || d[0], L = (e) => !!(e != null && e.requiresSystemEntry && !S), v = E(
135
+ (e) => {
136
+ if (t) return;
137
+ const o = M(e);
138
+ A(() => s(o));
139
+ },
140
+ [t, M, s]
141
+ ), F = E(
142
+ (e, o) => {
143
+ t || S && g.has(e) || v(o ? [...r, e] : r.filter((I) => I !== e));
144
+ },
145
+ [t, S, g, v, r]
146
+ ), H = E(
147
+ (e, o) => {
148
+ if (t) return;
149
+ const I = e.perms.filter((k) => !g.has(k.id)).map((k) => k.id);
150
+ if (o) v([...r, ...I]);
151
+ else {
152
+ const k = new Set(I);
153
+ v(r.filter((C) => !k.has(C)));
154
+ }
155
+ },
156
+ [t, g, v, r]
157
+ );
158
+ if (!d.length)
159
+ return /* @__PURE__ */ h(W, { description: "暂无权限点", className: m, style: f });
160
+ const q = L(i), z = !!i && i.perms.length > 0 && i.perms.every((e) => x.has(e.id)), U = !!i && i.perms.some((e) => x.has(e.id));
147
161
  return /* @__PURE__ */ y(
148
- F,
162
+ K,
149
163
  {
150
164
  gutter: 0,
151
- className: s,
165
+ className: m,
152
166
  style: {
153
167
  border: "1px solid var(--ant-color-border, #d9d9d9)",
154
168
  borderRadius: 8,
155
- minHeight: g,
169
+ minHeight: l,
156
170
  overflow: "hidden",
157
- ...c
171
+ ...f
158
172
  },
159
173
  children: [
160
- /* @__PURE__ */ m(
161
- G,
174
+ /* @__PURE__ */ h(
175
+ R,
162
176
  {
163
177
  span: 7,
164
178
  style: {
165
179
  borderRight: "1px solid var(--ant-color-border, #d9d9d9)",
166
180
  background: "var(--ant-color-fill-quaternary, #fafafa)",
167
- maxHeight: g,
181
+ maxHeight: l,
168
182
  overflow: "auto"
169
183
  },
170
- children: i.map((e) => {
171
- const o = e.perms.filter((S) => r.includes(S.id)).length, x = e.perms.length, h = e.key === ((u == null ? void 0 : u.key) || "");
184
+ children: d.map((e) => {
185
+ let o = 0;
186
+ for (const C of e.perms)
187
+ x.has(C.id) && (o += 1);
188
+ const I = e.perms.length, k = e.key === ((i == null ? void 0 : i.key) || "");
172
189
  return /* @__PURE__ */ y(
173
190
  "div",
174
191
  {
175
192
  role: "button",
176
193
  tabIndex: 0,
177
- onClick: () => C(e.key),
178
- onKeyDown: (S) => {
179
- (S.key === "Enter" || S.key === " ") && C(e.key);
194
+ onClick: () => B(e.key),
195
+ onKeyDown: (C) => {
196
+ (C.key === "Enter" || C.key === " ") && B(e.key);
180
197
  },
181
198
  style: {
182
199
  padding: "10px 12px",
183
200
  cursor: "pointer",
184
- background: h ? "var(--ant-color-primary-bg, #e6f4ff)" : "transparent",
185
- fontWeight: h ? 600 : 400,
186
- borderLeft: h ? "3px solid var(--ant-color-primary, #1677ff)" : "3px solid transparent",
187
- opacity: q(e) && o === 0 ? 0.75 : 1
201
+ background: k ? "var(--ant-color-primary-bg, #e6f4ff)" : "transparent",
202
+ fontWeight: k ? 600 : 400,
203
+ borderLeft: k ? "3px solid var(--ant-color-primary, #1677ff)" : "3px solid transparent",
204
+ opacity: L(e) && o === 0 ? 0.75 : 1
188
205
  },
189
206
  children: [
190
- /* @__PURE__ */ m("div", { children: e.label }),
191
- /* @__PURE__ */ y(I.Text, { type: "secondary", style: { fontSize: 12 }, children: [
207
+ /* @__PURE__ */ h("div", { children: e.label }),
208
+ /* @__PURE__ */ y(T.Text, { type: "secondary", style: { fontSize: 12 }, children: [
192
209
  o,
193
210
  "/",
194
- x
211
+ I
195
212
  ] })
196
213
  ]
197
214
  },
@@ -200,7 +217,7 @@ function N({
200
217
  })
201
218
  }
202
219
  ),
203
- /* @__PURE__ */ m(G, { span: 17, style: { padding: 16, maxHeight: g, overflow: "auto" }, children: u ? /* @__PURE__ */ y(j, { children: [
220
+ /* @__PURE__ */ h(R, { span: 17, style: { padding: 16, maxHeight: l, overflow: "auto" }, children: i ? /* @__PURE__ */ y(D, { children: [
204
221
  /* @__PURE__ */ y(
205
222
  "div",
206
223
  {
@@ -211,56 +228,56 @@ function N({
211
228
  alignItems: "center"
212
229
  },
213
230
  children: [
214
- /* @__PURE__ */ m(I.Text, { strong: !0, children: u.label }),
215
- t ? null : /* @__PURE__ */ m(
216
- M,
231
+ /* @__PURE__ */ h(T.Text, { strong: !0, children: i.label }),
232
+ t ? null : /* @__PURE__ */ h(
233
+ G,
217
234
  {
218
- disabled: B || u.perms.every((e) => b.has(e.id)),
219
- checked: u.perms.length > 0 && u.perms.every((e) => r.includes(e.id)),
220
- indeterminate: u.perms.some((e) => r.includes(e.id)) && !u.perms.every((e) => r.includes(e.id)),
221
- onChange: (e) => R(u, e.target.checked),
235
+ disabled: q || i.perms.every((e) => g.has(e.id)),
236
+ checked: z,
237
+ indeterminate: U && !z,
238
+ onChange: (e) => H(i, e.target.checked),
222
239
  children: "全选本模块"
223
240
  }
224
241
  )
225
242
  ]
226
243
  }
227
244
  ),
228
- u.categories.map((e) => /* @__PURE__ */ m(
229
- K,
245
+ i.categories.map((e) => /* @__PURE__ */ h(
246
+ V,
230
247
  {
231
248
  category: e,
232
- value: r,
233
- moduleDisabled: B,
234
- lockedIdSet: b,
249
+ selectedSet: x,
250
+ moduleDisabled: q,
251
+ lockedIdSet: g,
235
252
  readOnly: t,
236
- onToggle: z
253
+ onToggle: F
237
254
  },
238
255
  e.key
239
256
  )),
240
- !t && B ? /* @__PURE__ */ m(I.Text, { type: "warning", style: { display: "block", marginTop: 12 }, children: "请先勾选 SYSTEM 入口权,再勾选业务权限。基线权限仍保持勾选。" }) : null
257
+ !t && q ? /* @__PURE__ */ h(T.Text, { type: "warning", style: { display: "block", marginTop: 12 }, children: "请先勾选 SYSTEM 入口权,再勾选业务权限。基线权限仍保持勾选。" }) : null
241
258
  ] }) : null })
242
259
  ]
243
260
  }
244
261
  );
245
262
  }
246
- function K({
247
- category: d,
248
- value: f,
249
- moduleDisabled: r,
250
- lockedIdSet: l,
251
- readOnly: n,
252
- onToggle: t
263
+ const V = _(function({
264
+ category: a,
265
+ selectedSet: r,
266
+ moduleDisabled: s,
267
+ lockedIdSet: n,
268
+ readOnly: t,
269
+ onToggle: m
253
270
  }) {
254
271
  return /* @__PURE__ */ y("div", { style: { marginBottom: 16 }, children: [
255
- /* @__PURE__ */ m(
256
- I.Text,
272
+ /* @__PURE__ */ h(
273
+ T.Text,
257
274
  {
258
275
  type: "secondary",
259
276
  style: { display: "block", marginBottom: 8, fontWeight: 500 },
260
- children: d.label
277
+ children: a.label
261
278
  }
262
279
  ),
263
- /* @__PURE__ */ m(
280
+ /* @__PURE__ */ h(
264
281
  "div",
265
282
  {
266
283
  style: {
@@ -268,39 +285,39 @@ function K({
268
285
  gridTemplateColumns: "repeat(2, minmax(0, 1fr))",
269
286
  gap: "8px 16px"
270
287
  },
271
- children: d.leaves.map((s) => {
272
- const c = s.perm;
273
- if (!c)
274
- return /* @__PURE__ */ y(M, { disabled: !0, children: [
275
- s.label,
276
- /* @__PURE__ */ y(I.Text, { type: "secondary", style: { marginLeft: 6, fontSize: 12 }, children: [
277
- s.code,
288
+ children: a.leaves.map((f) => {
289
+ const l = f.perm;
290
+ if (!l)
291
+ return /* @__PURE__ */ y(G, { disabled: !0, children: [
292
+ f.label,
293
+ /* @__PURE__ */ y(T.Text, { type: "secondary", style: { marginLeft: 6, fontSize: 12 }, children: [
294
+ f.code,
278
295
  "(未注册)"
279
296
  ] })
280
- ] }, s.code);
281
- const g = s.defaultGranted || l.has(c.id);
297
+ ] }, f.code);
298
+ const u = f.defaultGranted || n.has(l.id);
282
299
  return /* @__PURE__ */ y(
283
- M,
300
+ G,
284
301
  {
285
- disabled: n || g || r,
286
- checked: f.includes(c.id),
287
- onChange: (a) => t(c.id, a.target.checked),
302
+ disabled: t || u || s,
303
+ checked: r.has(l.id),
304
+ onChange: (b) => m(l.id, b.target.checked),
288
305
  children: [
289
- s.label || c.name,
290
- /* @__PURE__ */ y(I.Text, { type: "secondary", style: { marginLeft: 6, fontSize: 12 }, children: [
291
- c.code,
292
- s.defaultGranted ? " · 基线" : ""
306
+ f.label || l.name,
307
+ /* @__PURE__ */ y(T.Text, { type: "secondary", style: { marginLeft: 6, fontSize: 12 }, children: [
308
+ l.code,
309
+ f.defaultGranted ? " · 基线" : ""
293
310
  ] })
294
311
  ]
295
312
  },
296
- c.id
313
+ l.id
297
314
  );
298
315
  })
299
316
  }
300
317
  )
301
318
  ] });
302
- }
319
+ });
303
320
  export {
304
- N as default
321
+ O as default
305
322
  };
306
323
  //# sourceMappingURL=PermissionBindPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionBindPanel.js","sources":["../../../src/components/PermissionBindPanel/PermissionBindPanel.tsx"],"sourcesContent":["import { Checkbox, Col, Empty, Row, Typography } from 'antd';\nimport { useEffect, useMemo, useState, type CSSProperties } from 'react';\nimport type { PermissionBindCatalog, PermissionBindItem } from './types';\n\nexport type PermissionBindPanelProps = {\n /** 三栏目录;缺省时按 code 前缀扁平分组 */\n catalog?: PermissionBindCatalog | null;\n permissions: PermissionBindItem[];\n /** 已选 permissionId */\n value: string[];\n onChange: (nextIds: string[]) => void;\n /** SYSTEM 入口码;未勾时禁用 requiresSystemEntry 模块 */\n systemEntryCodes?: string[];\n /** 只读预览(如用户有效权限):勾选态展示、禁止改、左右栏仍受 height 约束 */\n readOnly?: boolean;\n className?: string;\n style?: CSSProperties;\n /** 左右栏最大高度(默认 420) */\n height?: number;\n};\n\ntype ResolvedLeaf = {\n code: string;\n label: string;\n defaultGranted: boolean;\n perm?: PermissionBindItem;\n};\n\ntype ResolvedCategory = {\n key: string;\n label: string;\n leaves: ResolvedLeaf[];\n};\n\ntype ResolvedModule = {\n key: string;\n label: string;\n requiresSystemEntry: boolean;\n categories: ResolvedCategory[];\n perms: PermissionBindItem[];\n lockedPermIds: string[];\n};\n\nfunction buildFromCatalog(\n catalog: PermissionBindCatalog,\n byCode: Map<string, PermissionBindItem>,\n): { modules: ResolvedModule[]; usedCodes: Set<string>; lockedIds: string[] } {\n const usedCodes = new Set<string>();\n const lockedIds: string[] = [];\n const modules: ResolvedModule[] = [];\n\n for (const mod of catalog.modules) {\n const categories: ResolvedCategory[] = [];\n const perms: PermissionBindItem[] = [];\n const modLocked: string[] = [];\n for (const cat of mod.categories) {\n const leaves: ResolvedLeaf[] = [];\n for (const leaf of cat.leaves) {\n usedCodes.add(leaf.code);\n const perm = byCode.get(leaf.code);\n const defaultGranted = Boolean(leaf.defaultGranted);\n leaves.push({\n code: leaf.code,\n label: leaf.label,\n defaultGranted,\n perm,\n });\n if (perm) {\n perms.push(perm);\n if (defaultGranted) {\n lockedIds.push(perm.id);\n modLocked.push(perm.id);\n }\n }\n }\n if (leaves.length) {\n categories.push({ key: cat.key, label: cat.label, leaves });\n }\n }\n if (categories.length) {\n modules.push({\n key: mod.key,\n label: mod.label,\n requiresSystemEntry: Boolean(mod.requiresSystemEntry),\n categories,\n perms,\n lockedPermIds: modLocked,\n });\n }\n }\n\n return { modules, usedCodes, lockedIds };\n}\n\nfunction buildPrefixFallback(permissions: PermissionBindItem[]): ResolvedModule[] {\n const byPrefix = new Map<string, PermissionBindItem[]>();\n for (const p of permissions) {\n const prefix = p.code.includes(':') ? p.code.split(':')[0]! : '_other';\n const arr = byPrefix.get(prefix) || [];\n arr.push(p);\n byPrefix.set(prefix, arr);\n }\n return [...byPrefix.entries()].map(([key, perms]) => {\n const sorted = [...perms].sort((a, b) => a.code.localeCompare(b.code));\n return {\n key,\n label: key,\n requiresSystemEntry: sorted.every((p) => p.layer === 'BUSINESS'),\n categories: [\n {\n key: 'all',\n label: '功能点',\n leaves: sorted.map((p) => ({\n code: p.code,\n label: p.name || p.code,\n defaultGranted: false,\n perm: p,\n })),\n },\n ],\n perms: sorted,\n lockedPermIds: [],\n };\n });\n}\n\nfunction appendUncategorized(\n modules: ResolvedModule[],\n permissions: PermissionBindItem[],\n usedCodes: Set<string>,\n): ResolvedModule[] {\n const orphans = permissions.filter((p) => !usedCodes.has(p.code));\n if (!orphans.length) return modules;\n const sorted = [...orphans].sort((a, b) => a.code.localeCompare(b.code));\n return [\n ...modules,\n {\n key: 'uncategorized',\n label: '未分类',\n requiresSystemEntry: true,\n categories: [\n {\n key: 'orphan',\n label: '未归入目录的权限点',\n leaves: sorted.map((p) => ({\n code: p.code,\n label: p.name || p.code,\n defaultGranted: false,\n perm: p,\n })),\n },\n ],\n perms: sorted,\n lockedPermIds: [],\n },\n ];\n}\n\n/**\n * 角色绑权三栏信息架构:左页面模块 · 主区按业务功能点分类分组勾选。\n * defaultGranted 叶子勾选且不可取消。\n */\nexport default function PermissionBindPanel({\n catalog,\n permissions,\n value,\n onChange,\n systemEntryCodes = [],\n readOnly = false,\n className,\n style,\n height = 420,\n}: PermissionBindPanelProps) {\n const bindable = useMemo(() => permissions.filter((p) => p.layer !== 'RESOURCE'), [permissions]);\n\n const byCode = useMemo(() => {\n const m = new Map<string, PermissionBindItem>();\n for (const p of bindable) m.set(p.code, p);\n return m;\n }, [bindable]);\n\n const { modules, lockedIds } = useMemo(() => {\n if (catalog?.modules?.length) {\n const built = buildFromCatalog(catalog, byCode);\n return {\n modules: appendUncategorized(built.modules, bindable, built.usedCodes),\n lockedIds: built.lockedIds,\n };\n }\n return { modules: buildPrefixFallback(bindable), lockedIds: [] as string[] };\n }, [catalog, byCode, bindable]);\n\n const lockedIdSet = useMemo(() => new Set(lockedIds), [lockedIds]);\n\n const systemEntryOpen = useMemo(() => {\n if (readOnly) return true;\n if (!systemEntryCodes.length) return true;\n const entryIds = bindable.filter((p) => systemEntryCodes.includes(p.code)).map((p) => p.id);\n if (!entryIds.length) return true;\n return entryIds.some((id) => value.includes(id));\n }, [readOnly, systemEntryCodes, bindable, value]);\n\n /** SYSTEM 入口打开时才强制基线;关掉入口时允许 strip 业务码 */\n const mergeLocked = (ids: string[]) =>\n systemEntryOpen ? [...new Set([...ids, ...lockedIds])] : ids;\n\n useEffect(() => {\n if (readOnly) return;\n if (!systemEntryOpen || !lockedIds.length) return;\n const missing = lockedIds.filter((id) => !value.includes(id));\n if (missing.length) onChange(mergeLocked(value));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [lockedIds.join('|'), systemEntryOpen, readOnly]);\n\n const [activeModule, setActiveModule] = useState('');\n\n useEffect(() => {\n if (!modules.length) {\n setActiveModule('');\n return;\n }\n if (!modules.some((m) => m.key === activeModule)) {\n setActiveModule(modules[0]!.key);\n }\n }, [modules, activeModule]);\n\n const active = modules.find((m) => m.key === activeModule) || modules[0];\n\n const moduleLocked = (mod: ResolvedModule | undefined) =>\n Boolean(mod?.requiresSystemEntry && !systemEntryOpen);\n\n const setIds = (next: string[]) => {\n if (readOnly) return;\n onChange(mergeLocked(next));\n };\n\n const toggleId = (id: string, on: boolean) => {\n if (readOnly) return;\n if (systemEntryOpen && lockedIdSet.has(id)) return;\n if (on) setIds([...value, id]);\n else setIds(value.filter((x) => x !== id));\n };\n\n const toggleAllInModule = (mod: ResolvedModule, on: boolean) => {\n if (readOnly) return;\n const optionalIds = mod.perms.filter((p) => !lockedIdSet.has(p.id)).map((p) => p.id);\n if (on) setIds([...value, ...optionalIds]);\n else {\n const drop = new Set(optionalIds);\n setIds(value.filter((id) => !drop.has(id)));\n }\n };\n\n if (!modules.length) {\n return <Empty description=\"暂无权限点\" className={className} style={style} />;\n }\n\n const locked = moduleLocked(active);\n\n return (\n <Row\n gutter={0}\n className={className}\n style={{\n border: '1px solid var(--ant-color-border, #d9d9d9)',\n borderRadius: 8,\n minHeight: height,\n overflow: 'hidden',\n ...style,\n }}\n >\n <Col\n span={7}\n style={{\n borderRight: '1px solid var(--ant-color-border, #d9d9d9)',\n background: 'var(--ant-color-fill-quaternary, #fafafa)',\n maxHeight: height,\n overflow: 'auto',\n }}\n >\n {modules.map((m) => {\n const selected = m.perms.filter((p) => value.includes(p.id)).length;\n const total = m.perms.length;\n const isActive = m.key === (active?.key || '');\n return (\n <div\n key={m.key}\n role=\"button\"\n tabIndex={0}\n onClick={() => setActiveModule(m.key)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') setActiveModule(m.key);\n }}\n style={{\n padding: '10px 12px',\n cursor: 'pointer',\n background: isActive ? 'var(--ant-color-primary-bg, #e6f4ff)' : 'transparent',\n fontWeight: isActive ? 600 : 400,\n borderLeft: isActive\n ? '3px solid var(--ant-color-primary, #1677ff)'\n : '3px solid transparent',\n opacity: moduleLocked(m) && selected === 0 ? 0.75 : 1,\n }}\n >\n <div>{m.label}</div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {selected}/{total}\n </Typography.Text>\n </div>\n );\n })}\n </Col>\n <Col span={17} style={{ padding: 16, maxHeight: height, overflow: 'auto' }}>\n {active ? (\n <>\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: 12,\n alignItems: 'center',\n }}\n >\n <Typography.Text strong>{active.label}</Typography.Text>\n {readOnly ? null : (\n <Checkbox\n disabled={locked || active.perms.every((p) => lockedIdSet.has(p.id))}\n checked={\n active.perms.length > 0 && active.perms.every((p) => value.includes(p.id))\n }\n indeterminate={\n active.perms.some((p) => value.includes(p.id)) &&\n !active.perms.every((p) => value.includes(p.id))\n }\n onChange={(e) => toggleAllInModule(active, e.target.checked)}\n >\n 全选本模块\n </Checkbox>\n )}\n </div>\n\n {active.categories.map((cat) => (\n <CategoryBlock\n key={cat.key}\n category={cat}\n value={value}\n moduleDisabled={locked}\n lockedIdSet={lockedIdSet}\n readOnly={readOnly}\n onToggle={toggleId}\n />\n ))}\n\n {!readOnly && locked ? (\n <Typography.Text type=\"warning\" style={{ display: 'block', marginTop: 12 }}>\n 请先勾选 SYSTEM 入口权,再勾选业务权限。基线权限仍保持勾选。\n </Typography.Text>\n ) : null}\n </>\n ) : null}\n </Col>\n </Row>\n );\n}\n\nfunction CategoryBlock({\n category,\n value,\n moduleDisabled,\n lockedIdSet,\n readOnly,\n onToggle,\n}: {\n category: ResolvedCategory;\n value: string[];\n moduleDisabled: boolean;\n lockedIdSet: Set<string>;\n readOnly: boolean;\n onToggle: (id: string, on: boolean) => void;\n}) {\n return (\n <div style={{ marginBottom: 16 }}>\n <Typography.Text\n type=\"secondary\"\n style={{ display: 'block', marginBottom: 8, fontWeight: 500 }}\n >\n {category.label}\n </Typography.Text>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',\n gap: '8px 16px',\n }}\n >\n {category.leaves.map((leaf) => {\n const perm = leaf.perm;\n if (!perm) {\n return (\n <Checkbox key={leaf.code} disabled>\n {leaf.label}\n <Typography.Text type=\"secondary\" style={{ marginLeft: 6, fontSize: 12 }}>\n {leaf.code}(未注册)\n </Typography.Text>\n </Checkbox>\n );\n }\n const isBaseline = leaf.defaultGranted || lockedIdSet.has(perm.id);\n return (\n <Checkbox\n key={perm.id}\n disabled={readOnly || isBaseline || moduleDisabled}\n checked={value.includes(perm.id)}\n onChange={(e) => onToggle(perm.id, e.target.checked)}\n >\n {leaf.label || perm.name}\n <Typography.Text type=\"secondary\" style={{ marginLeft: 6, fontSize: 12 }}>\n {perm.code}\n {leaf.defaultGranted ? ' · 基线' : ''}\n </Typography.Text>\n </Checkbox>\n );\n })}\n </div>\n </div>\n );\n}\n"],"names":["buildFromCatalog","catalog","byCode","usedCodes","lockedIds","modules","mod","categories","perms","modLocked","cat","leaves","leaf","perm","defaultGranted","buildPrefixFallback","permissions","byPrefix","p","prefix","arr","key","sorted","a","b","appendUncategorized","orphans","PermissionBindPanel","value","onChange","systemEntryCodes","readOnly","className","style","height","bindable","useMemo","m","_a","built","lockedIdSet","systemEntryOpen","entryIds","id","mergeLocked","ids","useEffect","activeModule","setActiveModule","useState","active","moduleLocked","setIds","next","toggleId","on","toggleAllInModule","optionalIds","drop","jsx","Empty","locked","jsxs","Row","Col","selected","total","isActive","e","Typography","Fragment","Checkbox","CategoryBlock","category","moduleDisabled","onToggle","isBaseline"],"mappings":";;;AA2CA,SAASA,EACPC,GACAC,GAC4E;AAC5E,QAAMC,wBAAgB,IAAA,GAChBC,IAAsB,CAAA,GACtBC,IAA4B,CAAA;AAElC,aAAWC,KAAOL,EAAQ,SAAS;AACjC,UAAMM,IAAiC,CAAA,GACjCC,IAA8B,CAAA,GAC9BC,IAAsB,CAAA;AAC5B,eAAWC,KAAOJ,EAAI,YAAY;AAChC,YAAMK,IAAyB,CAAA;AAC/B,iBAAWC,KAAQF,EAAI,QAAQ;AAC7B,QAAAP,EAAU,IAAIS,EAAK,IAAI;AACvB,cAAMC,IAAOX,EAAO,IAAIU,EAAK,IAAI,GAC3BE,IAAiB,EAAQF,EAAK;AACpC,QAAAD,EAAO,KAAK;AAAA,UACV,MAAMC,EAAK;AAAA,UACX,OAAOA,EAAK;AAAA,UACZ,gBAAAE;AAAA,UACA,MAAAD;AAAA,QAAA,CACD,GACGA,MACFL,EAAM,KAAKK,CAAI,GACXC,MACFV,EAAU,KAAKS,EAAK,EAAE,GACtBJ,EAAU,KAAKI,EAAK,EAAE;AAAA,MAG5B;AACA,MAAIF,EAAO,UACTJ,EAAW,KAAK,EAAE,KAAKG,EAAI,KAAK,OAAOA,EAAI,OAAO,QAAAC,GAAQ;AAAA,IAE9D;AACA,IAAIJ,EAAW,UACbF,EAAQ,KAAK;AAAA,MACX,KAAKC,EAAI;AAAA,MACT,OAAOA,EAAI;AAAA,MACX,qBAAqB,EAAQA,EAAI;AAAA,MACjC,YAAAC;AAAA,MACA,OAAAC;AAAA,MACA,eAAeC;AAAA,IAAA,CAChB;AAAA,EAEL;AAEA,SAAO,EAAE,SAAAJ,GAAS,WAAAF,GAAW,WAAAC,EAAA;AAC/B;AAEA,SAASW,EAAoBC,GAAqD;AAChF,QAAMC,wBAAe,IAAA;AACrB,aAAWC,KAAKF,GAAa;AAC3B,UAAMG,IAASD,EAAE,KAAK,SAAS,GAAG,IAAIA,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,IAAK,UACxDE,IAAMH,EAAS,IAAIE,CAAM,KAAK,CAAA;AACpC,IAAAC,EAAI,KAAKF,CAAC,GACVD,EAAS,IAAIE,GAAQC,CAAG;AAAA,EAC1B;AACA,SAAO,CAAC,GAAGH,EAAS,QAAA,CAAS,EAAE,IAAI,CAAC,CAACI,GAAKb,CAAK,MAAM;AACnD,UAAMc,IAAS,CAAC,GAAGd,CAAK,EAAE,KAAK,CAACe,GAAGC,MAAMD,EAAE,KAAK,cAAcC,EAAE,IAAI,CAAC;AACrE,WAAO;AAAA,MACL,KAAAH;AAAA,MACA,OAAOA;AAAA,MACP,qBAAqBC,EAAO,MAAM,CAACJ,MAAMA,EAAE,UAAU,UAAU;AAAA,MAC/D,YAAY;AAAA,QACV;AAAA,UACE,KAAK;AAAA,UACL,OAAO;AAAA,UACP,QAAQI,EAAO,IAAI,CAACJ,OAAO;AAAA,YACzB,MAAMA,EAAE;AAAA,YACR,OAAOA,EAAE,QAAQA,EAAE;AAAA,YACnB,gBAAgB;AAAA,YAChB,MAAMA;AAAA,UAAA,EACN;AAAA,QAAA;AAAA,MACJ;AAAA,MAEF,OAAOI;AAAA,MACP,eAAe,CAAA;AAAA,IAAC;AAAA,EAEpB,CAAC;AACH;AAEA,SAASG,EACPpB,GACAW,GACAb,GACkB;AAClB,QAAMuB,IAAUV,EAAY,OAAO,CAACE,MAAM,CAACf,EAAU,IAAIe,EAAE,IAAI,CAAC;AAChE,MAAI,CAACQ,EAAQ,OAAQ,QAAOrB;AAC5B,QAAMiB,IAAS,CAAC,GAAGI,CAAO,EAAE,KAAK,CAACH,GAAGC,MAAMD,EAAE,KAAK,cAAcC,EAAE,IAAI,CAAC;AACvE,SAAO;AAAA,IACL,GAAGnB;AAAA,IACH;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,qBAAqB;AAAA,MACrB,YAAY;AAAA,QACV;AAAA,UACE,KAAK;AAAA,UACL,OAAO;AAAA,UACP,QAAQiB,EAAO,IAAI,CAACJ,OAAO;AAAA,YACzB,MAAMA,EAAE;AAAA,YACR,OAAOA,EAAE,QAAQA,EAAE;AAAA,YACnB,gBAAgB;AAAA,YAChB,MAAMA;AAAA,UAAA,EACN;AAAA,QAAA;AAAA,MACJ;AAAA,MAEF,OAAOI;AAAA,MACP,eAAe,CAAA;AAAA,IAAC;AAAA,EAClB;AAEJ;AAMA,SAAwBK,EAAoB;AAAA,EAC1C,SAAA1B;AAAA,EACA,aAAAe;AAAA,EACA,OAAAY;AAAA,EACA,UAAAC;AAAA,EACA,kBAAAC,IAAmB,CAAA;AAAA,EACnB,UAAAC,IAAW;AAAA,EACX,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,QAAAC,IAAS;AACX,GAA6B;AAC3B,QAAMC,IAAWC,EAAQ,MAAMpB,EAAY,OAAO,CAACE,MAAMA,EAAE,UAAU,UAAU,GAAG,CAACF,CAAW,CAAC,GAEzFd,IAASkC,EAAQ,MAAM;AAC3B,UAAMC,wBAAQ,IAAA;AACd,eAAWnB,KAAKiB,EAAU,CAAAE,EAAE,IAAInB,EAAE,MAAMA,CAAC;AACzC,WAAOmB;AAAA,EACT,GAAG,CAACF,CAAQ,CAAC,GAEP,EAAE,SAAA9B,GAAS,WAAAD,EAAA,IAAcgC,EAAQ,MAAM;;AAC3C,SAAIE,IAAArC,KAAA,gBAAAA,EAAS,YAAT,QAAAqC,EAAkB,QAAQ;AAC5B,YAAMC,IAAQvC,EAAiBC,GAASC,CAAM;AAC9C,aAAO;AAAA,QACL,SAASuB,EAAoBc,EAAM,SAASJ,GAAUI,EAAM,SAAS;AAAA,QACrE,WAAWA,EAAM;AAAA,MAAA;AAAA,IAErB;AACA,WAAO,EAAE,SAASxB,EAAoBoB,CAAQ,GAAG,WAAW,CAAA,EAAC;AAAA,EAC/D,GAAG,CAAClC,GAASC,GAAQiC,CAAQ,CAAC,GAExBK,IAAcJ,EAAQ,MAAM,IAAI,IAAIhC,CAAS,GAAG,CAACA,CAAS,CAAC,GAE3DqC,IAAkBL,EAAQ,MAAM;AAEpC,QADIL,KACA,CAACD,EAAiB,OAAQ,QAAO;AACrC,UAAMY,IAAWP,EAAS,OAAO,CAACjB,MAAMY,EAAiB,SAASZ,EAAE,IAAI,CAAC,EAAE,IAAI,CAACA,MAAMA,EAAE,EAAE;AAC1F,WAAKwB,EAAS,SACPA,EAAS,KAAK,CAACC,MAAOf,EAAM,SAASe,CAAE,CAAC,IADlB;AAAA,EAE/B,GAAG,CAACZ,GAAUD,GAAkBK,GAAUP,CAAK,CAAC,GAG1CgB,IAAc,CAACC,MACnBJ,IAAkB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAGI,GAAK,GAAGzC,CAAS,CAAC,CAAC,IAAIyC;AAE3D,EAAAC,EAAU,MAAM;AAEd,QADIf,KACA,CAACU,KAAmB,CAACrC,EAAU,OAAQ;AAE3C,IADgBA,EAAU,OAAO,CAACuC,MAAO,CAACf,EAAM,SAASe,CAAE,CAAC,EAChD,UAAQd,EAASe,EAAYhB,CAAK,CAAC;AAAA,EAEjD,GAAG,CAACxB,EAAU,KAAK,GAAG,GAAGqC,GAAiBV,CAAQ,CAAC;AAEnD,QAAM,CAACgB,GAAcC,CAAe,IAAIC,EAAS,EAAE;AAEnD,EAAAH,EAAU,MAAM;AACd,QAAI,CAACzC,EAAQ,QAAQ;AACnB,MAAA2C,EAAgB,EAAE;AAClB;AAAA,IACF;AACA,IAAK3C,EAAQ,KAAK,CAACgC,MAAMA,EAAE,QAAQU,CAAY,KAC7CC,EAAgB3C,EAAQ,CAAC,EAAG,GAAG;AAAA,EAEnC,GAAG,CAACA,GAAS0C,CAAY,CAAC;AAE1B,QAAMG,IAAS7C,EAAQ,KAAK,CAACgC,MAAMA,EAAE,QAAQU,CAAY,KAAK1C,EAAQ,CAAC,GAEjE8C,IAAe,CAAC7C,MACpB,GAAQA,KAAA,QAAAA,EAAK,uBAAuB,CAACmC,IAEjCW,IAAS,CAACC,MAAmB;AACjC,IAAItB,KACJF,EAASe,EAAYS,CAAI,CAAC;AAAA,EAC5B,GAEMC,IAAW,CAACX,GAAYY,MAAgB;AAC5C,IAAIxB,KACAU,KAAmBD,EAAY,IAAIG,CAAE,KACjCS,EAAJG,IAAW,CAAC,GAAG3B,GAAOe,CAAE,IAChBf,EAAM,OAAO,CAAC,MAAM,MAAMe,CAAE,CADX;AAAA,EAE/B,GAEMa,IAAoB,CAAClD,GAAqBiD,MAAgB;AAC9D,QAAIxB,EAAU;AACd,UAAM0B,IAAcnD,EAAI,MAAM,OAAO,CAACY,MAAM,CAACsB,EAAY,IAAItB,EAAE,EAAE,CAAC,EAAE,IAAI,CAACA,MAAMA,EAAE,EAAE;AACnF,QAAIqC,EAAI,CAAAH,EAAO,CAAC,GAAGxB,GAAO,GAAG6B,CAAW,CAAC;AAAA,SACpC;AACH,YAAMC,IAAO,IAAI,IAAID,CAAW;AAChC,MAAAL,EAAOxB,EAAM,OAAO,CAACe,MAAO,CAACe,EAAK,IAAIf,CAAE,CAAC,CAAC;AAAA,IAC5C;AAAA,EACF;AAEA,MAAI,CAACtC,EAAQ;AACX,WAAO,gBAAAsD,EAACC,GAAA,EAAM,aAAY,SAAQ,WAAA5B,GAAsB,OAAAC,GAAc;AAGxE,QAAM4B,IAASV,EAAaD,CAAM;AAElC,SACE,gBAAAY;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,QAAQ;AAAA,MACR,WAAA/B;AAAA,MACA,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,WAAWE;AAAA,QACX,UAAU;AAAA,QACV,GAAGD;AAAA,MAAA;AAAA,MAGL,UAAA;AAAA,QAAA,gBAAA0B;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,MAAM;AAAA,YACN,OAAO;AAAA,cACL,aAAa;AAAA,cACb,YAAY;AAAA,cACZ,WAAW9B;AAAA,cACX,UAAU;AAAA,YAAA;AAAA,YAGX,UAAA7B,EAAQ,IAAI,CAACgC,MAAM;AAClB,oBAAM4B,IAAW5B,EAAE,MAAM,OAAO,CAACnB,MAAMU,EAAM,SAASV,EAAE,EAAE,CAAC,EAAE,QACvDgD,IAAQ7B,EAAE,MAAM,QAChB8B,IAAW9B,EAAE,UAASa,KAAA,gBAAAA,EAAQ,QAAO;AAC3C,qBACE,gBAAAY;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,MAAK;AAAA,kBACL,UAAU;AAAA,kBACV,SAAS,MAAMd,EAAgBX,EAAE,GAAG;AAAA,kBACpC,WAAW,CAAC+B,MAAM;AAChB,qBAAIA,EAAE,QAAQ,WAAWA,EAAE,QAAQ,QAAKpB,EAAgBX,EAAE,GAAG;AAAA,kBAC/D;AAAA,kBACA,OAAO;AAAA,oBACL,SAAS;AAAA,oBACT,QAAQ;AAAA,oBACR,YAAY8B,IAAW,yCAAyC;AAAA,oBAChE,YAAYA,IAAW,MAAM;AAAA,oBAC7B,YAAYA,IACR,gDACA;AAAA,oBACJ,SAAShB,EAAad,CAAC,KAAK4B,MAAa,IAAI,OAAO;AAAA,kBAAA;AAAA,kBAGtD,UAAA;AAAA,oBAAA,gBAAAN,EAAC,OAAA,EAAK,YAAE,MAAA,CAAM;AAAA,oBACd,gBAAAG,EAACO,EAAW,MAAX,EAAgB,MAAK,aAAY,OAAO,EAAE,UAAU,GAAA,GAClD,UAAA;AAAA,sBAAAJ;AAAA,sBAAS;AAAA,sBAAEC;AAAA,oBAAA,EAAA,CACd;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBArBK7B,EAAE;AAAA,cAAA;AAAA,YAwBb,CAAC;AAAA,UAAA;AAAA,QAAA;AAAA,QAEH,gBAAAsB,EAACK,GAAA,EAAI,MAAM,IAAI,OAAO,EAAE,SAAS,IAAI,WAAW9B,GAAQ,UAAU,OAAA,GAC/D,cACC,gBAAA4B,EAAAQ,GAAA,EACE,UAAA;AAAA,UAAA,gBAAAR;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,gBAAgB;AAAA,gBAChB,cAAc;AAAA,gBACd,YAAY;AAAA,cAAA;AAAA,cAGd,UAAA;AAAA,gBAAA,gBAAAH,EAACU,EAAW,MAAX,EAAgB,QAAM,IAAE,YAAO,OAAM;AAAA,gBACrCtC,IAAW,OACV,gBAAA4B;AAAA,kBAACY;AAAA,kBAAA;AAAA,oBACC,UAAUV,KAAUX,EAAO,MAAM,MAAM,CAAChC,MAAMsB,EAAY,IAAItB,EAAE,EAAE,CAAC;AAAA,oBACnE,SACEgC,EAAO,MAAM,SAAS,KAAKA,EAAO,MAAM,MAAM,CAAChC,MAAMU,EAAM,SAASV,EAAE,EAAE,CAAC;AAAA,oBAE3E,eACEgC,EAAO,MAAM,KAAK,CAAChC,MAAMU,EAAM,SAASV,EAAE,EAAE,CAAC,KAC7C,CAACgC,EAAO,MAAM,MAAM,CAAChC,MAAMU,EAAM,SAASV,EAAE,EAAE,CAAC;AAAA,oBAEjD,UAAU,CAAC,MAAMsC,EAAkBN,GAAQ,EAAE,OAAO,OAAO;AAAA,oBAC5D,UAAA;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAED;AAAA,YAAA;AAAA,UAAA;AAAA,UAIHA,EAAO,WAAW,IAAI,CAACxC,MACtB,gBAAAiD;AAAA,YAACa;AAAA,YAAA;AAAA,cAEC,UAAU9D;AAAA,cACV,OAAAkB;AAAA,cACA,gBAAgBiC;AAAA,cAChB,aAAArB;AAAA,cACA,UAAAT;AAAA,cACA,UAAUuB;AAAA,YAAA;AAAA,YANL5C,EAAI;AAAA,UAAA,CAQZ;AAAA,UAEA,CAACqB,KAAY8B,IACZ,gBAAAF,EAACU,EAAW,MAAX,EAAgB,MAAK,WAAU,OAAO,EAAE,SAAS,SAAS,WAAW,GAAA,GAAM,gDAE5E,IACE;AAAA,QAAA,EAAA,CACN,IACE,KAAA,CACN;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAEA,SAASG,EAAc;AAAA,EACrB,UAAAC;AAAA,EACA,OAAA7C;AAAA,EACA,gBAAA8C;AAAA,EACA,aAAAlC;AAAA,EACA,UAAAT;AAAA,EACA,UAAA4C;AACF,GAOG;AACD,2BACG,OAAA,EAAI,OAAO,EAAE,cAAc,MAC1B,UAAA;AAAA,IAAA,gBAAAhB;AAAA,MAACU,EAAW;AAAA,MAAX;AAAA,QACC,MAAK;AAAA,QACL,OAAO,EAAE,SAAS,SAAS,cAAc,GAAG,YAAY,IAAA;AAAA,QAEvD,UAAAI,EAAS;AAAA,MAAA;AAAA,IAAA;AAAA,IAEZ,gBAAAd;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,SAAS;AAAA,UACT,qBAAqB;AAAA,UACrB,KAAK;AAAA,QAAA;AAAA,QAGN,UAAAc,EAAS,OAAO,IAAI,CAAC7D,MAAS;AAC7B,gBAAMC,IAAOD,EAAK;AAClB,cAAI,CAACC;AACH,mBACE,gBAAAiD,EAACS,GAAA,EAAyB,UAAQ,IAC/B,UAAA;AAAA,cAAA3D,EAAK;AAAA,cACN,gBAAAkD,EAACO,EAAW,MAAX,EAAgB,MAAK,aAAY,OAAO,EAAE,YAAY,GAAG,UAAU,GAAA,GACjE,UAAA;AAAA,gBAAAzD,EAAK;AAAA,gBAAK;AAAA,cAAA,EAAA,CACb;AAAA,YAAA,EAAA,GAJaA,EAAK,IAKpB;AAGJ,gBAAMgE,IAAahE,EAAK,kBAAkB4B,EAAY,IAAI3B,EAAK,EAAE;AACjE,iBACE,gBAAAiD;AAAA,YAACS;AAAA,YAAA;AAAA,cAEC,UAAUxC,KAAY6C,KAAcF;AAAA,cACpC,SAAS9C,EAAM,SAASf,EAAK,EAAE;AAAA,cAC/B,UAAU,CAACuD,MAAMO,EAAS9D,EAAK,IAAIuD,EAAE,OAAO,OAAO;AAAA,cAElD,UAAA;AAAA,gBAAAxD,EAAK,SAASC,EAAK;AAAA,gBACpB,gBAAAiD,EAACO,EAAW,MAAX,EAAgB,MAAK,aAAY,OAAO,EAAE,YAAY,GAAG,UAAU,GAAA,GACjE,UAAA;AAAA,kBAAAxD,EAAK;AAAA,kBACLD,EAAK,iBAAiB,UAAU;AAAA,gBAAA,EAAA,CACnC;AAAA,cAAA;AAAA,YAAA;AAAA,YATKC,EAAK;AAAA,UAAA;AAAA,QAYhB,CAAC;AAAA,MAAA;AAAA,IAAA;AAAA,EACH,GACF;AAEJ;"}
1
+ {"version":3,"file":"PermissionBindPanel.js","sources":["../../../src/components/PermissionBindPanel/PermissionBindPanel.tsx"],"sourcesContent":["import { Checkbox, Col, Empty, Row, Typography } from 'antd';\nimport {\n memo,\n startTransition,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n} from 'react';\nimport type { PermissionBindCatalog, PermissionBindItem } from './types';\n\nexport type PermissionBindPanelProps = {\n /** 三栏目录;缺省时按 code 前缀扁平分组 */\n catalog?: PermissionBindCatalog | null;\n permissions: PermissionBindItem[];\n /** 已选 permissionId */\n value: string[];\n onChange: (nextIds: string[]) => void;\n /** SYSTEM 入口码;未勾时禁用 requiresSystemEntry 模块 */\n systemEntryCodes?: string[];\n /** 只读预览(如用户有效权限):勾选态展示、禁止改、左右栏仍受 height 约束 */\n readOnly?: boolean;\n className?: string;\n style?: CSSProperties;\n /** 左右栏最大高度(默认 420) */\n height?: number;\n};\n\ntype ResolvedLeaf = {\n code: string;\n label: string;\n defaultGranted: boolean;\n perm?: PermissionBindItem;\n};\n\ntype ResolvedCategory = {\n key: string;\n label: string;\n leaves: ResolvedLeaf[];\n};\n\ntype ResolvedModule = {\n key: string;\n label: string;\n requiresSystemEntry: boolean;\n categories: ResolvedCategory[];\n perms: PermissionBindItem[];\n lockedPermIds: string[];\n};\n\nfunction buildFromCatalog(\n catalog: PermissionBindCatalog,\n byCode: Map<string, PermissionBindItem>,\n): { modules: ResolvedModule[]; usedCodes: Set<string>; lockedIds: string[] } {\n const usedCodes = new Set<string>();\n const lockedIds: string[] = [];\n const modules: ResolvedModule[] = [];\n\n for (const mod of catalog.modules) {\n const categories: ResolvedCategory[] = [];\n const perms: PermissionBindItem[] = [];\n const modLocked: string[] = [];\n for (const cat of mod.categories) {\n const leaves: ResolvedLeaf[] = [];\n for (const leaf of cat.leaves) {\n usedCodes.add(leaf.code);\n const perm = byCode.get(leaf.code);\n const defaultGranted = Boolean(leaf.defaultGranted);\n leaves.push({\n code: leaf.code,\n label: leaf.label,\n defaultGranted,\n perm,\n });\n if (perm) {\n perms.push(perm);\n if (defaultGranted) {\n lockedIds.push(perm.id);\n modLocked.push(perm.id);\n }\n }\n }\n if (leaves.length) {\n categories.push({ key: cat.key, label: cat.label, leaves });\n }\n }\n if (categories.length) {\n modules.push({\n key: mod.key,\n label: mod.label,\n requiresSystemEntry: Boolean(mod.requiresSystemEntry),\n categories,\n perms,\n lockedPermIds: modLocked,\n });\n }\n }\n\n return { modules, usedCodes, lockedIds };\n}\n\nfunction buildPrefixFallback(permissions: PermissionBindItem[]): ResolvedModule[] {\n const byPrefix = new Map<string, PermissionBindItem[]>();\n for (const p of permissions) {\n const prefix = p.code.includes(':') ? p.code.split(':')[0]! : '_other';\n const arr = byPrefix.get(prefix) || [];\n arr.push(p);\n byPrefix.set(prefix, arr);\n }\n return [...byPrefix.entries()].map(([key, perms]) => {\n const sorted = [...perms].sort((a, b) => a.code.localeCompare(b.code));\n return {\n key,\n label: key,\n requiresSystemEntry: sorted.every((p) => p.layer === 'BUSINESS'),\n categories: [\n {\n key: 'all',\n label: '功能点',\n leaves: sorted.map((p) => ({\n code: p.code,\n label: p.name || p.code,\n defaultGranted: false,\n perm: p,\n })),\n },\n ],\n perms: sorted,\n lockedPermIds: [],\n };\n });\n}\n\nfunction appendUncategorized(\n modules: ResolvedModule[],\n permissions: PermissionBindItem[],\n usedCodes: Set<string>,\n): ResolvedModule[] {\n const orphans = permissions.filter((p) => !usedCodes.has(p.code));\n if (!orphans.length) return modules;\n const sorted = [...orphans].sort((a, b) => a.code.localeCompare(b.code));\n return [\n ...modules,\n {\n key: 'uncategorized',\n label: '未分类',\n requiresSystemEntry: true,\n categories: [\n {\n key: 'orphan',\n label: '未归入目录的权限点',\n leaves: sorted.map((p) => ({\n code: p.code,\n label: p.name || p.code,\n defaultGranted: false,\n perm: p,\n })),\n },\n ],\n perms: sorted,\n lockedPermIds: [],\n },\n ];\n}\n\n/**\n * 角色绑权三栏信息架构:左页面模块 · 主区按业务功能点分类分组勾选。\n * defaultGranted 叶子勾选且不可取消。\n */\nexport default function PermissionBindPanel({\n catalog,\n permissions,\n value,\n onChange,\n systemEntryCodes = [],\n readOnly = false,\n className,\n style,\n height = 420,\n}: PermissionBindPanelProps) {\n const bindable = useMemo(() => permissions.filter((p) => p.layer !== 'RESOURCE'), [permissions]);\n\n const byCode = useMemo(() => {\n const m = new Map<string, PermissionBindItem>();\n for (const p of bindable) m.set(p.code, p);\n return m;\n }, [bindable]);\n\n const { modules, lockedIds } = useMemo(() => {\n if (catalog?.modules?.length) {\n const built = buildFromCatalog(catalog, byCode);\n return {\n modules: appendUncategorized(built.modules, bindable, built.usedCodes),\n lockedIds: built.lockedIds,\n };\n }\n return { modules: buildPrefixFallback(bindable), lockedIds: [] as string[] };\n }, [catalog, byCode, bindable]);\n\n const lockedIdSet = useMemo(() => new Set(lockedIds), [lockedIds]);\n\n /** O(1) 勾选判定;避免左侧 N 模块 × includes 线性扫描 */\n const selectedSet = useMemo(() => new Set(value), [value]);\n\n const systemEntryOpen = useMemo(() => {\n if (readOnly) return true;\n if (!systemEntryCodes.length) return true;\n const entryIds = bindable.filter((p) => systemEntryCodes.includes(p.code)).map((p) => p.id);\n if (!entryIds.length) return true;\n return entryIds.some((id) => selectedSet.has(id));\n }, [readOnly, systemEntryCodes, bindable, selectedSet]);\n\n /** SYSTEM 入口打开时才强制基线;关掉入口时允许 strip 业务码 */\n const mergeLocked = useCallback(\n (ids: string[]) => (systemEntryOpen ? [...new Set([...ids, ...lockedIds])] : ids),\n [systemEntryOpen, lockedIds],\n );\n\n useEffect(() => {\n if (readOnly) return;\n if (!systemEntryOpen || !lockedIds.length) return;\n const missing = lockedIds.filter((id) => !selectedSet.has(id));\n if (missing.length) {\n startTransition(() => onChange(mergeLocked(value)));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [lockedIds.join('|'), systemEntryOpen, readOnly]);\n\n const [activeModule, setActiveModule] = useState('');\n\n useEffect(() => {\n if (!modules.length) {\n setActiveModule('');\n return;\n }\n if (!modules.some((m) => m.key === activeModule)) {\n setActiveModule(modules[0]!.key);\n }\n }, [modules, activeModule]);\n\n const active = modules.find((m) => m.key === activeModule) || modules[0];\n\n const moduleLocked = (mod: ResolvedModule | undefined) =>\n Boolean(mod?.requiresSystemEntry && !systemEntryOpen);\n\n const setIds = useCallback(\n (next: string[]) => {\n if (readOnly) return;\n const merged = mergeLocked(next);\n startTransition(() => onChange(merged));\n },\n [readOnly, mergeLocked, onChange],\n );\n\n const toggleId = useCallback(\n (id: string, on: boolean) => {\n if (readOnly) return;\n if (systemEntryOpen && lockedIdSet.has(id)) return;\n if (on) setIds([...value, id]);\n else setIds(value.filter((x) => x !== id));\n },\n [readOnly, systemEntryOpen, lockedIdSet, setIds, value],\n );\n\n const toggleAllInModule = useCallback(\n (mod: ResolvedModule, on: boolean) => {\n if (readOnly) return;\n const optionalIds = mod.perms.filter((p) => !lockedIdSet.has(p.id)).map((p) => p.id);\n if (on) setIds([...value, ...optionalIds]);\n else {\n const drop = new Set(optionalIds);\n setIds(value.filter((id) => !drop.has(id)));\n }\n },\n [readOnly, lockedIdSet, setIds, value],\n );\n\n if (!modules.length) {\n return <Empty description=\"暂无权限点\" className={className} style={style} />;\n }\n\n const locked = moduleLocked(active);\n const activeAllChecked =\n !!active && active.perms.length > 0 && active.perms.every((p) => selectedSet.has(p.id));\n const activeSomeChecked = !!active && active.perms.some((p) => selectedSet.has(p.id));\n\n return (\n <Row\n gutter={0}\n className={className}\n style={{\n border: '1px solid var(--ant-color-border, #d9d9d9)',\n borderRadius: 8,\n minHeight: height,\n overflow: 'hidden',\n ...style,\n }}\n >\n <Col\n span={7}\n style={{\n borderRight: '1px solid var(--ant-color-border, #d9d9d9)',\n background: 'var(--ant-color-fill-quaternary, #fafafa)',\n maxHeight: height,\n overflow: 'auto',\n }}\n >\n {modules.map((m) => {\n let selected = 0;\n for (const p of m.perms) {\n if (selectedSet.has(p.id)) selected += 1;\n }\n const total = m.perms.length;\n const isActive = m.key === (active?.key || '');\n return (\n <div\n key={m.key}\n role=\"button\"\n tabIndex={0}\n onClick={() => setActiveModule(m.key)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') setActiveModule(m.key);\n }}\n style={{\n padding: '10px 12px',\n cursor: 'pointer',\n background: isActive ? 'var(--ant-color-primary-bg, #e6f4ff)' : 'transparent',\n fontWeight: isActive ? 600 : 400,\n borderLeft: isActive\n ? '3px solid var(--ant-color-primary, #1677ff)'\n : '3px solid transparent',\n opacity: moduleLocked(m) && selected === 0 ? 0.75 : 1,\n }}\n >\n <div>{m.label}</div>\n <Typography.Text type=\"secondary\" style={{ fontSize: 12 }}>\n {selected}/{total}\n </Typography.Text>\n </div>\n );\n })}\n </Col>\n <Col span={17} style={{ padding: 16, maxHeight: height, overflow: 'auto' }}>\n {active ? (\n <>\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: 12,\n alignItems: 'center',\n }}\n >\n <Typography.Text strong>{active.label}</Typography.Text>\n {readOnly ? null : (\n <Checkbox\n disabled={locked || active.perms.every((p) => lockedIdSet.has(p.id))}\n checked={activeAllChecked}\n indeterminate={activeSomeChecked && !activeAllChecked}\n onChange={(e) => toggleAllInModule(active, e.target.checked)}\n >\n 全选本模块\n </Checkbox>\n )}\n </div>\n\n {active.categories.map((cat) => (\n <CategoryBlock\n key={cat.key}\n category={cat}\n selectedSet={selectedSet}\n moduleDisabled={locked}\n lockedIdSet={lockedIdSet}\n readOnly={readOnly}\n onToggle={toggleId}\n />\n ))}\n\n {!readOnly && locked ? (\n <Typography.Text type=\"warning\" style={{ display: 'block', marginTop: 12 }}>\n 请先勾选 SYSTEM 入口权,再勾选业务权限。基线权限仍保持勾选。\n </Typography.Text>\n ) : null}\n </>\n ) : null}\n </Col>\n </Row>\n );\n}\n\nconst CategoryBlock = memo(function CategoryBlock({\n category,\n selectedSet,\n moduleDisabled,\n lockedIdSet,\n readOnly,\n onToggle,\n}: {\n category: ResolvedCategory;\n selectedSet: Set<string>;\n moduleDisabled: boolean;\n lockedIdSet: Set<string>;\n readOnly: boolean;\n onToggle: (id: string, on: boolean) => void;\n}) {\n return (\n <div style={{ marginBottom: 16 }}>\n <Typography.Text\n type=\"secondary\"\n style={{ display: 'block', marginBottom: 8, fontWeight: 500 }}\n >\n {category.label}\n </Typography.Text>\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',\n gap: '8px 16px',\n }}\n >\n {category.leaves.map((leaf) => {\n const perm = leaf.perm;\n if (!perm) {\n return (\n <Checkbox key={leaf.code} disabled>\n {leaf.label}\n <Typography.Text type=\"secondary\" style={{ marginLeft: 6, fontSize: 12 }}>\n {leaf.code}(未注册)\n </Typography.Text>\n </Checkbox>\n );\n }\n const isBaseline = leaf.defaultGranted || lockedIdSet.has(perm.id);\n return (\n <Checkbox\n key={perm.id}\n disabled={readOnly || isBaseline || moduleDisabled}\n checked={selectedSet.has(perm.id)}\n onChange={(e) => onToggle(perm.id, e.target.checked)}\n >\n {leaf.label || perm.name}\n <Typography.Text type=\"secondary\" style={{ marginLeft: 6, fontSize: 12 }}>\n {perm.code}\n {leaf.defaultGranted ? ' · 基线' : ''}\n </Typography.Text>\n </Checkbox>\n );\n })}\n </div>\n </div>\n );\n});\n"],"names":["buildFromCatalog","catalog","byCode","usedCodes","lockedIds","modules","mod","categories","perms","modLocked","cat","leaves","leaf","perm","defaultGranted","buildPrefixFallback","permissions","byPrefix","p","prefix","arr","key","sorted","a","b","appendUncategorized","orphans","PermissionBindPanel","value","onChange","systemEntryCodes","readOnly","className","style","height","bindable","useMemo","m","_a","built","lockedIdSet","selectedSet","systemEntryOpen","entryIds","id","mergeLocked","useCallback","ids","useEffect","startTransition","activeModule","setActiveModule","useState","active","moduleLocked","setIds","next","merged","toggleId","on","x","toggleAllInModule","optionalIds","drop","jsx","Empty","locked","activeAllChecked","activeSomeChecked","jsxs","Row","Col","selected","total","isActive","e","Typography","Fragment","Checkbox","CategoryBlock","memo","category","moduleDisabled","onToggle","isBaseline"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export type { BuildLoginPathOptions } from './utils/authRedirect';
12
12
  export { DEFAULT_LAST_ACTIVITY_STORAGE_KEY, getLastActivityTime, touchLastActivity, clearLastActivity, } from './utils/sessionActivity';
13
13
  export { USER_ROLE_PERMISSIONS_KEY, PERMISSION_DEFINITIONS_KEY, PERMISSIONS_STORAGE_KEY, loadUserRolePermissions, saveUserRolePermissions, loadPermissionDefinitions, savePermissionDefinitions, getStoredUserPermissions, getStoredPermissionMap, } from './utils/permissionStorage';
14
14
  export { createMarsunRequest } from './utils/createMarsunRequest';
15
- export type { MarsunApiResponse, CreateMarsunRequestOptions, MarsunRequestClient, } from './utils/createMarsunRequest';
15
+ export type { MarsunApiResponse, CreateMarsunRequestOptions, MarsunRequestClient, MarsunRequestErrorResponse, } from './utils/createMarsunRequest';
16
16
  export type { UserRolePermissions, PermissionDefinition, PermissionDefinitionsResponse, } from './types/auth';
17
17
  export { buildDepartmentPathMapFromTree, buildDepartmentPathMapFromFlat, getDepartmentPath, buildLeafDepartmentPathMap, buildDepartmentPathMaps, mergeDepartmentPathMaps, toDepartmentPathMaps, } from './utils/department/departmentPath';
18
18
  export type { DepartmentPathMaps } from './utils/department/departmentPath';
@@ -3,6 +3,11 @@ export interface MarsunApiResponse<T = unknown> {
3
3
  message?: string;
4
4
  data?: T;
5
5
  }
6
+ export interface MarsunRequestErrorResponse {
7
+ data?: unknown;
8
+ status?: number;
9
+ config?: unknown;
10
+ }
6
11
  export interface CreateMarsunRequestOptions {
7
12
  baseURL?: string;
8
13
  timeout?: number;
@@ -14,6 +19,8 @@ export interface CreateMarsunRequestOptions {
14
19
  isPublicUrl?: (url: string) => boolean;
15
20
  isOnLoginPage?: () => boolean;
16
21
  showError?: (msg: string) => void;
22
+ /** 自定义错误信息提取;默认按 message/detail/msg 顺序兜底 */
23
+ getResponseError?: (response: MarsunRequestErrorResponse | undefined) => string;
17
24
  }
18
25
  /** 与 axios 实例兼容的请求客户端(避免对外暴露 axios 类型,消除多副本 axios 的类型冲突) */
19
26
  export interface MarsunRequestClient {
@@ -1,55 +1,60 @@
1
- import { message as C } from "antd";
1
+ import { message as j } from "antd";
2
2
  import "../node_modules/axios/index.js";
3
- import S from "../node_modules/axios/lib/axios.js";
4
- const b = "X-Skip-Error-Handler";
5
- function g(t) {
6
- return !!(t != null && t[b]);
3
+ import y from "../node_modules/axios/lib/axios.js";
4
+ const w = "X-Skip-Error-Handler";
5
+ function m(o) {
6
+ return !!(o != null && o[w]);
7
7
  }
8
- function B(t = {}) {
8
+ function v(o = {}) {
9
9
  const {
10
- baseURL: d = "/api",
10
+ baseURL: g = "/api",
11
11
  timeout: E = 3e4,
12
- successCode: P = 0,
13
- withCredentials: R = !1,
14
- getToken: r,
15
- onUnauthorized: n,
16
- isPublicUrl: j = () => !1,
17
- isOnLoginPage: w = () => !1,
18
- showError: o = (e) => C.error(e)
19
- } = t, a = S.create({
20
- baseURL: d,
12
+ successCode: R = 0,
13
+ withCredentials: b = !1,
14
+ getToken: i,
15
+ onUnauthorized: c,
16
+ isPublicUrl: d = () => !1,
17
+ isOnLoginPage: P = () => !1,
18
+ showError: f = (e) => j.error(e),
19
+ getResponseError: l
20
+ } = o, p = (e) => {
21
+ if (l) return l(e);
22
+ const r = e == null ? void 0 : e.data;
23
+ return (r == null ? void 0 : r.message) || (r == null ? void 0 : r.detail) || (r == null ? void 0 : r.msg) || "请求失败";
24
+ }, a = y.create({
25
+ baseURL: g,
21
26
  timeout: E,
22
- withCredentials: R,
27
+ withCredentials: b,
23
28
  headers: {
24
29
  "Content-Type": "application/json"
25
30
  }
26
31
  });
27
32
  return a.interceptors.request.use(
28
33
  (e) => {
29
- const s = r == null ? void 0 : r();
30
- return s && (e.headers.Authorization = `Bearer ${s}`), e;
34
+ const r = i == null ? void 0 : i();
35
+ return r && (e.headers.Authorization = `Bearer ${r}`), e;
31
36
  },
32
37
  (e) => Promise.reject(e)
33
38
  ), a.interceptors.response.use(
34
39
  (e) => {
35
- const s = e.data;
36
- return s.code !== P ? (g(e.config.headers) || o(s.message || "请求失败"), Promise.reject(new Error(s.message || "请求失败"))) : e.data;
40
+ var n;
41
+ const r = (n = e.config) == null ? void 0 : n.responseType;
42
+ if (r === "blob" || r === "arraybuffer")
43
+ return e.data;
44
+ const t = e.data;
45
+ if (!(t && typeof t == "object" && "code" in t))
46
+ return t;
47
+ const s = t;
48
+ return s.code !== R ? (m(e.config.headers) || f(s.message || "请求失败"), Promise.reject(new Error(s.message || "请求失败"))) : t;
37
49
  },
38
50
  (e) => {
39
- var i, c, u, m, f, p, l;
40
- const s = ((i = e.config) == null ? void 0 : i.url) ?? "", H = g((c = e.config) == null ? void 0 : c.headers);
41
- if (((u = e.response) == null ? void 0 : u.status) === 401)
42
- !j(s) && !w() && (n == null || n());
43
- else if (!H) {
44
- const q = ((f = (m = e.response) == null ? void 0 : m.data) == null ? void 0 : f.message) || e.message || "请求失败";
45
- o(q);
46
- }
47
- const k = ((l = (p = e.response) == null ? void 0 : p.data) == null ? void 0 : l.message) || e.message || "请求失败";
48
- return Promise.reject(new Error(k));
51
+ var u, s, n;
52
+ const r = ((u = e.config) == null ? void 0 : u.url) ?? "", t = m((s = e.config) == null ? void 0 : s.headers);
53
+ return ((n = e.response) == null ? void 0 : n.status) === 401 ? !d(r) && !P() && (c == null || c()) : t || f(p(e.response)), Promise.reject(new Error(p(e.response)));
49
54
  }
50
55
  ), a;
51
56
  }
52
57
  export {
53
- B as createMarsunRequest
58
+ v as createMarsunRequest
54
59
  };
55
60
  //# sourceMappingURL=createMarsunRequest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createMarsunRequest.js","sources":["../../src/utils/createMarsunRequest.ts"],"sourcesContent":["import { message } from 'antd';\nimport axios from 'axios';\n\nexport interface MarsunApiResponse<T = unknown> {\n code: number;\n message?: string;\n data?: T;\n}\n\nexport interface CreateMarsunRequestOptions {\n baseURL?: string;\n timeout?: number;\n successCode?: number;\n /** Cookie 会话 SSO:跨域携带凭证 */\n withCredentials?: boolean;\n getToken?: () => string | null;\n onUnauthorized?: () => void;\n isPublicUrl?: (url: string) => boolean;\n isOnLoginPage?: () => boolean;\n showError?: (msg: string) => void;\n}\n\n/** 与 axios 实例兼容的请求客户端(避免对外暴露 axios 类型,消除多副本 axios 的类型冲突) */\nexport interface MarsunRequestClient {\n get<T = unknown>(url: string, config?: unknown): Promise<T>;\n post<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n put<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n patch<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n delete<T = unknown>(url: string, config?: unknown): Promise<T>;\n request<T = unknown>(config: unknown): Promise<T>;\n}\n\nconst SKIP_ERROR_HEADER = 'X-Skip-Error-Handler';\n\nfunction getSkipHandler(headers: unknown): boolean {\n return Boolean((headers as Record<string, string> | undefined)?.[SKIP_ERROR_HEADER]);\n}\n\n/** 创建带鉴权、统一错误处理的 axios 实例 */\nexport function createMarsunRequest(options: CreateMarsunRequestOptions = {}): MarsunRequestClient {\n const {\n baseURL = '/api',\n timeout = 30000,\n successCode = 0,\n withCredentials = false,\n getToken,\n onUnauthorized,\n isPublicUrl = () => false,\n isOnLoginPage = () => false,\n showError = (msg) => message.error(msg),\n } = options;\n\n const request = axios.create({\n baseURL,\n timeout,\n withCredentials,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n request.interceptors.request.use(\n (config) => {\n const token = getToken?.();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error) => Promise.reject(error),\n );\n\n request.interceptors.response.use(\n (response) => {\n const data = response.data as MarsunApiResponse;\n if (data.code !== successCode) {\n if (!getSkipHandler(response.config.headers)) {\n showError(data.message || '请求失败');\n }\n return Promise.reject(new Error(data.message || '请求失败'));\n }\n return response.data;\n },\n (error) => {\n const url = error.config?.url ?? '';\n const skipHandler = getSkipHandler(error.config?.headers);\n\n if (error.response?.status === 401) {\n if (!isPublicUrl(url) && !isOnLoginPage()) {\n onUnauthorized?.();\n }\n } else if (!skipHandler) {\n const msg = error.response?.data?.message || error.message || '请求失败';\n showError(msg);\n }\n const msg = error.response?.data?.message || error.message || '请求失败';\n return Promise.reject(new Error(msg));\n },\n );\n\n return request as MarsunRequestClient;\n}\n"],"names":["SKIP_ERROR_HEADER","getSkipHandler","headers","createMarsunRequest","options","baseURL","timeout","successCode","withCredentials","getToken","onUnauthorized","isPublicUrl","isOnLoginPage","showError","msg","message","request","axios","config","token","error","response","data","url","_a","skipHandler","_b","_c","_e","_d","_g","_f"],"mappings":";;;AAgCA,MAAMA,IAAoB;AAE1B,SAASC,EAAeC,GAA2B;AACjD,SAAO,GAASA,KAAA,QAAAA,EAAiDF;AACnE;AAGO,SAASG,EAAoBC,IAAsC,IAAyB;AACjG,QAAM;AAAA,IACJ,SAAAC,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,aAAAC,IAAc;AAAA,IACd,iBAAAC,IAAkB;AAAA,IAClB,UAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,aAAAC,IAAc,MAAM;AAAA,IACpB,eAAAC,IAAgB,MAAM;AAAA,IACtB,WAAAC,IAAY,CAACC,MAAQC,EAAQ,MAAMD,CAAG;AAAA,EAAA,IACpCV,GAEEY,IAAUC,EAAM,OAAO;AAAA,IAC3B,SAAAZ;AAAA,IACA,SAAAC;AAAA,IACA,iBAAAE;AAAA,IACA,SAAS;AAAA,MACP,gBAAgB;AAAA,IAAA;AAAA,EAClB,CACD;AAED,SAAAQ,EAAQ,aAAa,QAAQ;AAAA,IAC3B,CAACE,MAAW;AACV,YAAMC,IAAQV,KAAA,gBAAAA;AACd,aAAIU,MACFD,EAAO,QAAQ,gBAAgB,UAAUC,CAAK,KAEzCD;AAAA,IACT;AAAA,IACA,CAACE,MAAU,QAAQ,OAAOA,CAAK;AAAA,EAAA,GAGjCJ,EAAQ,aAAa,SAAS;AAAA,IAC5B,CAACK,MAAa;AACZ,YAAMC,IAAOD,EAAS;AACtB,aAAIC,EAAK,SAASf,KACXN,EAAeoB,EAAS,OAAO,OAAO,KACzCR,EAAUS,EAAK,WAAW,MAAM,GAE3B,QAAQ,OAAO,IAAI,MAAMA,EAAK,WAAW,MAAM,CAAC,KAElDD,EAAS;AAAA,IAClB;AAAA,IACA,CAACD,MAAU;;AACT,YAAMG,MAAMC,IAAAJ,EAAM,WAAN,gBAAAI,EAAc,QAAO,IAC3BC,IAAcxB,GAAeyB,IAAAN,EAAM,WAAN,gBAAAM,EAAc,OAAO;AAExD,YAAIC,IAAAP,EAAM,aAAN,gBAAAO,EAAgB,YAAW;AAC7B,QAAI,CAAChB,EAAYY,CAAG,KAAK,CAACX,QACxBF,KAAA,QAAAA;AAAA,eAEO,CAACe,GAAa;AACvB,cAAMX,MAAMc,KAAAC,IAAAT,EAAM,aAAN,gBAAAS,EAAgB,SAAhB,gBAAAD,EAAsB,YAAWR,EAAM,WAAW;AAC9D,QAAAP,EAAUC,CAAG;AAAA,MACf;AACA,YAAMA,MAAMgB,KAAAC,IAAAX,EAAM,aAAN,gBAAAW,EAAgB,SAAhB,gBAAAD,EAAsB,YAAWV,EAAM,WAAW;AAC9D,aAAO,QAAQ,OAAO,IAAI,MAAMN,CAAG,CAAC;AAAA,IACtC;AAAA,EAAA,GAGKE;AACT;"}
1
+ {"version":3,"file":"createMarsunRequest.js","sources":["../../src/utils/createMarsunRequest.ts"],"sourcesContent":["import { message } from 'antd';\nimport axios from 'axios';\n\nexport interface MarsunApiResponse<T = unknown> {\n code: number;\n message?: string;\n data?: T;\n}\n\nexport interface MarsunRequestErrorResponse {\n data?: unknown;\n status?: number;\n config?: unknown;\n}\n\nexport interface CreateMarsunRequestOptions {\n baseURL?: string;\n timeout?: number;\n successCode?: number;\n /** Cookie 会话 SSO:跨域携带凭证 */\n withCredentials?: boolean;\n getToken?: () => string | null;\n onUnauthorized?: () => void;\n isPublicUrl?: (url: string) => boolean;\n isOnLoginPage?: () => boolean;\n showError?: (msg: string) => void;\n /** 自定义错误信息提取;默认按 message/detail/msg 顺序兜底 */\n getResponseError?: (response: MarsunRequestErrorResponse | undefined) => string;\n}\n\n/** 与 axios 实例兼容的请求客户端(避免对外暴露 axios 类型,消除多副本 axios 的类型冲突) */\nexport interface MarsunRequestClient {\n get<T = unknown>(url: string, config?: unknown): Promise<T>;\n post<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n put<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n patch<T = unknown>(url: string, data?: unknown, config?: unknown): Promise<T>;\n delete<T = unknown>(url: string, config?: unknown): Promise<T>;\n request<T = unknown>(config: unknown): Promise<T>;\n}\n\nconst SKIP_ERROR_HEADER = 'X-Skip-Error-Handler';\n\nfunction getSkipHandler(headers: unknown): boolean {\n return Boolean((headers as Record<string, string> | undefined)?.[SKIP_ERROR_HEADER]);\n}\n\n/** 创建带鉴权、统一错误处理的 axios 实例 */\nexport function createMarsunRequest(options: CreateMarsunRequestOptions = {}): MarsunRequestClient {\n const {\n baseURL = '/api',\n timeout = 30000,\n successCode = 0,\n withCredentials = false,\n getToken,\n onUnauthorized,\n isPublicUrl = () => false,\n isOnLoginPage = () => false,\n showError = (msg) => message.error(msg),\n getResponseError,\n } = options;\n\n const extractError = (response: MarsunRequestErrorResponse | undefined): string => {\n if (getResponseError) return getResponseError(response);\n const data = response?.data as { message?: string; detail?: string; msg?: string } | undefined;\n return data?.message || data?.detail || data?.msg || '请求失败';\n };\n\n const request = axios.create({\n baseURL,\n timeout,\n withCredentials,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n request.interceptors.request.use(\n (config) => {\n const token = getToken?.();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n },\n (error) => Promise.reject(error),\n );\n\n request.interceptors.response.use(\n (response) => {\n const responseType = (response.config as { responseType?: string } | undefined)?.responseType;\n if (responseType === 'blob' || responseType === 'arraybuffer') {\n return response.data;\n }\n const data = response.data;\n const isEnvelope = data && typeof data === 'object' && 'code' in data;\n if (!isEnvelope) {\n return data;\n }\n const envelope = data as MarsunApiResponse;\n if (envelope.code !== successCode) {\n if (!getSkipHandler(response.config.headers)) {\n showError(envelope.message || '请求失败');\n }\n return Promise.reject(new Error(envelope.message || '请求失败'));\n }\n return data;\n },\n (error) => {\n const url = error.config?.url ?? '';\n const skipHandler = getSkipHandler(error.config?.headers);\n\n if (error.response?.status === 401) {\n if (!isPublicUrl(url) && !isOnLoginPage()) {\n onUnauthorized?.();\n }\n } else if (!skipHandler) {\n showError(extractError(error.response));\n }\n return Promise.reject(new Error(extractError(error.response)));\n },\n );\n\n return request as MarsunRequestClient;\n}\n"],"names":["SKIP_ERROR_HEADER","getSkipHandler","headers","createMarsunRequest","options","baseURL","timeout","successCode","withCredentials","getToken","onUnauthorized","isPublicUrl","isOnLoginPage","showError","msg","message","getResponseError","extractError","response","data","request","axios","config","token","error","responseType","_a","envelope","url","skipHandler","_b","_c"],"mappings":";;;AAwCA,MAAMA,IAAoB;AAE1B,SAASC,EAAeC,GAA2B;AACjD,SAAO,GAASA,KAAA,QAAAA,EAAiDF;AACnE;AAGO,SAASG,EAAoBC,IAAsC,IAAyB;AACjG,QAAM;AAAA,IACJ,SAAAC,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,aAAAC,IAAc;AAAA,IACd,iBAAAC,IAAkB;AAAA,IAClB,UAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,aAAAC,IAAc,MAAM;AAAA,IACpB,eAAAC,IAAgB,MAAM;AAAA,IACtB,WAAAC,IAAY,CAACC,MAAQC,EAAQ,MAAMD,CAAG;AAAA,IACtC,kBAAAE;AAAA,EAAA,IACEZ,GAEEa,IAAe,CAACC,MAA6D;AACjF,QAAIF,EAAkB,QAAOA,EAAiBE,CAAQ;AACtD,UAAMC,IAAOD,KAAA,gBAAAA,EAAU;AACvB,YAAOC,KAAA,gBAAAA,EAAM,aAAWA,KAAA,gBAAAA,EAAM,YAAUA,KAAA,gBAAAA,EAAM,QAAO;AAAA,EACvD,GAEMC,IAAUC,EAAM,OAAO;AAAA,IAC3B,SAAAhB;AAAA,IACA,SAAAC;AAAA,IACA,iBAAAE;AAAA,IACA,SAAS;AAAA,MACP,gBAAgB;AAAA,IAAA;AAAA,EAClB,CACD;AAED,SAAAY,EAAQ,aAAa,QAAQ;AAAA,IAC3B,CAACE,MAAW;AACV,YAAMC,IAAQd,KAAA,gBAAAA;AACd,aAAIc,MACFD,EAAO,QAAQ,gBAAgB,UAAUC,CAAK,KAEzCD;AAAA,IACT;AAAA,IACA,CAACE,MAAU,QAAQ,OAAOA,CAAK;AAAA,EAAA,GAGjCJ,EAAQ,aAAa,SAAS;AAAA,IAC5B,CAACF,MAAa;;AACZ,YAAMO,KAAgBC,IAAAR,EAAS,WAAT,gBAAAQ,EAA2D;AACjF,UAAID,MAAiB,UAAUA,MAAiB;AAC9C,eAAOP,EAAS;AAElB,YAAMC,IAAOD,EAAS;AAEtB,UAAI,EADeC,KAAQ,OAAOA,KAAS,YAAY,UAAUA;AAE/D,eAAOA;AAET,YAAMQ,IAAWR;AACjB,aAAIQ,EAAS,SAASpB,KACfN,EAAeiB,EAAS,OAAO,OAAO,KACzCL,EAAUc,EAAS,WAAW,MAAM,GAE/B,QAAQ,OAAO,IAAI,MAAMA,EAAS,WAAW,MAAM,CAAC,KAEtDR;AAAA,IACT;AAAA,IACA,CAACK,MAAU;;AACT,YAAMI,MAAMF,IAAAF,EAAM,WAAN,gBAAAE,EAAc,QAAO,IAC3BG,IAAc5B,GAAe6B,IAAAN,EAAM,WAAN,gBAAAM,EAAc,OAAO;AAExD,eAAIC,IAAAP,EAAM,aAAN,gBAAAO,EAAgB,YAAW,MACzB,CAACpB,EAAYiB,CAAG,KAAK,CAAChB,QACxBF,KAAA,QAAAA,OAEQmB,KACVhB,EAAUI,EAAaO,EAAM,QAAQ,CAAC,GAEjC,QAAQ,OAAO,IAAI,MAAMP,EAAaO,EAAM,QAAQ,CAAC,CAAC;AAAA,IAC/D;AAAA,EAAA,GAGKJ;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkyhy/marsun-components-core",
3
- "version": "0.1.56",
3
+ "version": "0.1.58",
4
4
  "description": "Marsun pure UI component library",
5
5
  "type": "module",
6
6
  "repository": {
@@ -117,6 +117,7 @@
117
117
  "@vitejs/plugin-react": "^4.3.4",
118
118
  "antd": "^6.0.0",
119
119
  "axios": "^1.7.7",
120
+ "axios-mock-adapter": "^2.1.0",
120
121
  "dayjs": "^1.11.13",
121
122
  "eslint": "^9.39.4",
122
123
  "eslint-config-prettier": "^9.1.2",