@donglegeyu/company-ui 1.2.39 → 1.2.40

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.
@@ -24,6 +24,7 @@ __export(SvgIcon_exports, {
24
24
  module.exports = __toCommonJS(SvgIcon_exports);
25
25
  var import_icons = require("./icons");
26
26
  var import_jsx_runtime = require("react/jsx-runtime");
27
+ var FALLBACK_ICON = "folder-open";
27
28
  function toCssSize(size, fallback) {
28
29
  if (size === void 0 || size === null)
29
30
  return fallback;
@@ -40,7 +41,15 @@ function SvgIcon({
40
41
  onClick
41
42
  }) {
42
43
  const key = name ?? href;
43
- const icon = key ? (0, import_icons.getIconDefinition)(key) : void 0;
44
+ let icon = key ? (0, import_icons.getIconDefinition)(key) : void 0;
45
+ if (!icon && name) {
46
+ if (process.env.NODE_ENV !== "production") {
47
+ console.warn(
48
+ `[SvgIcon] 未注册的图标 name "${name}",已回退为 "${FALLBACK_ICON}"。请使用内置图标集(/icon-library 精选)中的键。`
49
+ );
50
+ }
51
+ icon = (0, import_icons.getIconDefinition)(FALLBACK_ICON);
52
+ }
44
53
  const dimension = toCssSize(size, 16);
45
54
  const mergedStyle = {
46
55
  width: dimension,
@@ -348,6 +348,12 @@ function AdminLayoutTemplate({
348
348
  (menu) => {
349
349
  var _a2;
350
350
  setActiveKey(menu.key);
351
+ const parentModule = businessMenus.find((m) => findMenuByKey(m.children ?? [], menu.key));
352
+ if (parentModule && parentModule.key !== activeFirstMenu) {
353
+ setActiveFirstMenu(parentModule.key);
354
+ setExpandedKeys(collectParentKeys(parentModule.children ?? []));
355
+ onActiveFirstMenuChange == null ? void 0 : onActiveFirstMenuChange(parentModule.key);
356
+ }
351
357
  if ((_a2 = menu.children) == null ? void 0 : _a2.length)
352
358
  return;
353
359
  if (systemMenuKeys.has(menu.key)) {
@@ -363,7 +369,18 @@ function AdminLayoutTemplate({
363
369
  openTab(menu.key, (page == null ? void 0 : page.label) ?? menu.label, (page == null ? void 0 : page.path) ?? menu.path, page == null ? void 0 : page.closable);
364
370
  onMenuOpen == null ? void 0 : onMenuOpen(menu);
365
371
  },
366
- [systemMenuKeys, homeTab, isTabActiveControlled, onActiveTabChange, onMenuOpen, pages, openTab]
372
+ [
373
+ businessMenus,
374
+ activeFirstMenu,
375
+ systemMenuKeys,
376
+ homeTab,
377
+ isTabActiveControlled,
378
+ onActiveTabChange,
379
+ onActiveFirstMenuChange,
380
+ onMenuOpen,
381
+ pages,
382
+ openTab
383
+ ]
367
384
  );
368
385
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `admin-layout-template${className ? ` ${className}` : ""}`, style, children: [
369
386
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -19,6 +19,7 @@
19
19
  display: flex;
20
20
  flex-direction: column;
21
21
  overflow: hidden;
22
+
22
23
  /* 主区灰底与 SmartListTemplate 等业务模板的 --color-bg-layout 对齐,
23
24
  页签栏与内容未充满处不露出白底 */
24
25
  background: var(--color-bg-layout, #f5f5f5);
@@ -31,6 +32,7 @@
31
32
  /* 间距契约:内容区只做滚动容器,禁止加 padding/margin/background(业务模板自带)。
32
33
  纵向 flex 让 SmartListTemplate(flex-grow:1 + align-self:stretch)充满剩余高度 */
33
34
  .admin-layout-content {
35
+ position: relative; /* 为 FormPageTemplate/DetailPageTemplate 等 absolute+inset:0 模板提供定位上下文,防止逃逸到全屏祖先 */
34
36
  flex: 1;
35
37
  min-height: 0;
36
38
  overflow: auto;
@@ -12,6 +12,7 @@ export interface FirstSidebarProps {
12
12
  businessMenus: SidebarMenuItem[];
13
13
  customNavMenus: SidebarMenuItem[];
14
14
  activeKey: string;
15
+ activeFirstMenu: string;
15
16
  visibleMenuCount?: number;
16
17
  domainPopoverOpen: boolean;
17
18
  adminPopoverOpen: boolean;
@@ -25,4 +26,4 @@ export interface FirstSidebarProps {
25
26
  onThemeSettings?: () => void;
26
27
  onLogout?: () => void;
27
28
  }
28
- export default function FirstSidebar({ domains, currentDomainId, userInfo, logo, brandName, firstMenus, systemBottomMenus, businessMenus, customNavMenus, activeKey, visibleMenuCount, domainPopoverOpen, adminPopoverOpen, onDomainPopoverOpenChange, onAdminPopoverOpenChange, onDomainChange, onMenuClick, onBusinessMenuEnter, onBusinessMenuLeave, onOpenMore, onThemeSettings, onLogout, }: FirstSidebarProps): import("react").JSX.Element;
29
+ export default function FirstSidebar({ domains, currentDomainId, userInfo, logo, brandName, firstMenus, systemBottomMenus, businessMenus, customNavMenus, activeKey, activeFirstMenu, visibleMenuCount, domainPopoverOpen, adminPopoverOpen, onDomainPopoverOpenChange, onAdminPopoverOpenChange, onDomainChange, onMenuClick, onBusinessMenuEnter, onBusinessMenuLeave, onOpenMore, onThemeSettings, onLogout, }: FirstSidebarProps): import("react").JSX.Element;
@@ -37,6 +37,7 @@ function FirstSidebar({
37
37
  businessMenus,
38
38
  customNavMenus,
39
39
  activeKey,
40
+ activeFirstMenu,
40
41
  visibleMenuCount = 6,
41
42
  domainPopoverOpen,
42
43
  adminPopoverOpen,
@@ -108,7 +109,7 @@ function FirstSidebar({
108
109
  displayMenus.map((menu) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
109
110
  "div",
110
111
  {
111
- className: `business-menu-item${activeKey === menu.key ? " active" : ""}`,
112
+ className: `business-menu-item${activeFirstMenu === menu.key || activeKey === menu.key ? " active" : ""}`,
112
113
  onClick: () => onMenuClick(menu),
113
114
  onMouseEnter: () => onBusinessMenuEnter(menu),
114
115
  onMouseLeave: onBusinessMenuLeave,
@@ -41,6 +41,24 @@ var import_menuIconMap = require("./menuIconMap");
41
41
  var import_default_logo = require("./default-logo");
42
42
  var import_index = require("./index.scss");
43
43
  var import_jsx_runtime = require("react/jsx-runtime");
44
+ function buildLeafToFirstKeyMap(menus) {
45
+ const map = /* @__PURE__ */ new Map();
46
+ const walk = (items, firstKey) => {
47
+ (items || []).forEach((item) => {
48
+ var _a;
49
+ map.set(item.key, firstKey);
50
+ if ((_a = item.children) == null ? void 0 : _a.length)
51
+ walk(item.children, firstKey);
52
+ });
53
+ };
54
+ (menus || []).forEach((menu) => {
55
+ var _a;
56
+ map.set(menu.key, menu.key);
57
+ if ((_a = menu.children) == null ? void 0 : _a.length)
58
+ walk(menu.children, menu.key);
59
+ });
60
+ return map;
61
+ }
44
62
  function DefaultFallback() {
45
63
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "company-sidebar-error", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "导航加载失败" }) });
46
64
  }
@@ -89,6 +107,17 @@ function CompanySidebar({
89
107
  const resolvedBusinessMenus = (0, import_react.useMemo)(() => (0, import_menuIconMap.resolveMenuIcons)(businessMenus), [businessMenus]);
90
108
  const resolvedSecondMenus = (0, import_react.useMemo)(() => (0, import_menuIconMap.resolveMenuIcons)(secondMenus), [secondMenus]);
91
109
  const resolvedCustomNavMenus = (0, import_react.useMemo)(() => (0, import_menuIconMap.resolveMenuIcons)(customNavMenus), [customNavMenus]);
110
+ const leafToFirstKeyMap = (0, import_react.useMemo)(() => buildLeafToFirstKeyMap(businessMenus), [businessMenus]);
111
+ const handleLeafMenuClick = (0, import_react.useCallback)(
112
+ (menu) => {
113
+ const firstKey = leafToFirstKeyMap.get(menu.key);
114
+ if (firstKey && firstKey !== activeFirstMenu) {
115
+ onFirstMenuSelect(firstKey);
116
+ }
117
+ onMenuClick(menu);
118
+ },
119
+ [leafToFirstKeyMap, activeFirstMenu, onFirstMenuSelect, onMenuClick]
120
+ );
92
121
  (0, import_react.useEffect)(() => {
93
122
  setState((prev) => ({ ...prev, localExpandedKeys: expandedKeys }));
94
123
  }, [expandedKeys]);
@@ -126,10 +155,13 @@ function CompanySidebar({
126
155
  }, [delayHideSidebar]);
127
156
  const handleFirstMenuClick = (0, import_react.useCallback)(
128
157
  (menu) => {
129
- onFirstMenuSelect(menu.key);
158
+ const firstKey = leafToFirstKeyMap.get(menu.key) || menu.key;
159
+ if (firstKey !== activeFirstMenu) {
160
+ onFirstMenuSelect(firstKey);
161
+ }
130
162
  onMenuClick(menu);
131
163
  },
132
- [onFirstMenuSelect, onMenuClick]
164
+ [leafToFirstKeyMap, activeFirstMenu, onFirstMenuSelect, onMenuClick]
133
165
  );
134
166
  const handleMoreSelect = (0, import_react.useCallback)(
135
167
  (menu, child) => {
@@ -185,6 +217,7 @@ function CompanySidebar({
185
217
  businessMenus: resolvedBusinessMenus,
186
218
  customNavMenus: resolvedCustomNavMenus,
187
219
  activeKey,
220
+ activeFirstMenu,
188
221
  visibleMenuCount,
189
222
  domainPopoverOpen: state.domainPopoverOpen,
190
223
  adminPopoverOpen: state.adminPopoverOpen,
@@ -211,7 +244,7 @@ function CompanySidebar({
211
244
  expandedKeys: state.localExpandedKeys,
212
245
  emptyImage,
213
246
  onMenuClick: (menu) => {
214
- onMenuClick(menu);
247
+ handleLeafMenuClick(menu);
215
248
  if (!secondSidebarFixed) {
216
249
  delayHideSidebar();
217
250
  }
@@ -24,6 +24,8 @@ __export(menuIconMap_exports, {
24
24
  resolveMenuIcons: () => resolveMenuIcons
25
25
  });
26
26
  module.exports = __toCommonJS(menuIconMap_exports);
27
+ var import_icons = require("../../shared-components/SvgIcon/icons");
28
+ var VALID_ICONS = new Set(import_icons.iconNames);
27
29
  var KEYWORD_ICON_MAP = [
28
30
  { keywords: ["商品", "货品", "物料", "spu", "sku", "product"], icon: "commodity" },
29
31
  { keywords: ["采购", "进货", "供应商", "purchase"], icon: "buy" },
@@ -47,8 +49,15 @@ var KEYWORD_ICON_MAP = [
47
49
  ];
48
50
  var DEFAULT_ICON = "folder-open";
49
51
  function getMenuIcon(menu) {
50
- if (menu.icon)
51
- return menu.icon;
52
+ if (menu.icon) {
53
+ if (VALID_ICONS.has(menu.icon))
54
+ return menu.icon;
55
+ if (process.env.NODE_ENV !== "production") {
56
+ console.warn(
57
+ `[CompanySidebar] 菜单 "${menu.label}" 的 icon "${menu.icon}" 不在内置图标集中,已回退为关键词匹配。内置图标键可查阅文档站 /icon-library 精选集。`
58
+ );
59
+ }
60
+ }
52
61
  const label = (menu.label || "").toLowerCase();
53
62
  for (const { keywords, icon } of KEYWORD_ICON_MAP) {
54
63
  if (keywords.some((kw) => label.includes(kw.toLowerCase()))) {
@@ -1,4 +1,5 @@
1
1
  .detail-page-template {
2
+ box-sizing: border-box; /* 消费方项目未必有全局 border-box reset,模板自持,防止 padding 撑破 inset:0 宽度 */
2
3
  position: absolute;
3
4
  inset: 0;
4
5
  width: 100%;
@@ -1,4 +1,5 @@
1
1
  .form-page-template {
2
+ box-sizing: border-box; /* 消费方项目未必有全局 border-box reset,模板自持,防止 padding 撑破 inset:0 宽度 */
2
3
  position: absolute;
3
4
  inset: 0;
4
5
  width: 100%;
@@ -171,6 +171,9 @@
171
171
  justify-content: flex-end;
172
172
  padding: calc(var(--spacing-md, 16) * 1px);
173
173
  border-top: 1px solid var(--color-border-secondary, rgba(5, 5, 5, 0.06));
174
+
175
+ /* 吸底:表格高度由 scroll.y 控制不一定填满 wrapper,margin-top:auto 保证分页器始终贴白卡底部(对齐 SmartListTemplate 视觉契约) */
176
+ margin-top: auto;
174
177
  }
175
178
  }
176
179
  }
@@ -5,7 +5,10 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
5
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
6
6
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
7
  import { getIconDefinition } from "./icons";
8
+
9
+ // 未注册图标键的兜底图标,保证任何输入都有可见输出(业务环境无 iconpark sprite,不能依赖 <use> 静默回退)
8
10
  import { jsx as _jsx } from "react/jsx-runtime";
11
+ var FALLBACK_ICON = "folder-open";
9
12
  function toCssSize(size, fallback) {
10
13
  if (size === undefined || size === null) return fallback;
11
14
  return typeof size === "number" ? "".concat(size, "px") : size;
@@ -23,6 +26,15 @@ export default function SvgIcon(_ref) {
23
26
  onClick = _ref.onClick;
24
27
  var key = name !== null && name !== void 0 ? name : href;
25
28
  var icon = key ? getIconDefinition(key) : undefined;
29
+
30
+ // name 未注册:dev 警告并兜底渲染,避免业务环境静默空白
31
+ // (href 未注册不警告,IconParkGallery 全量库走 <use> sprite 是合法路径)
32
+ if (!icon && name) {
33
+ if (process.env.NODE_ENV !== "production") {
34
+ console.warn("[SvgIcon] \u672A\u6CE8\u518C\u7684\u56FE\u6807 name \"".concat(name, "\"\uFF0C\u5DF2\u56DE\u9000\u4E3A \"").concat(FALLBACK_ICON, "\"\u3002\u8BF7\u4F7F\u7528\u5185\u7F6E\u56FE\u6807\u96C6\uFF08/icon-library \u7CBE\u9009\uFF09\u4E2D\u7684\u952E\u3002"));
35
+ }
36
+ icon = getIconDefinition(FALLBACK_ICON);
37
+ }
26
38
  var dimension = toCssSize(size, 16);
27
39
  var mergedStyle = _objectSpread(_objectSpread({
28
40
  width: dimension,
@@ -447,6 +447,18 @@ export default function AdminLayoutTemplate(_ref) {
447
447
  var handleMenuClick = useCallback(function (menu) {
448
448
  var _menu$children5, _page$label2, _page$path2;
449
449
  setActiveKey(menu.key);
450
+ // 反向同步一级菜单高亮:从收藏/更多应用/自定义导航面板点击叶子菜单时,
451
+ // activeFirstMenu 可能停留在其他模块(与 handleTabChange 的反向同步保持一致)
452
+ var parentModule = businessMenus.find(function (m) {
453
+ var _m$children2;
454
+ return findMenuByKey((_m$children2 = m.children) !== null && _m$children2 !== void 0 ? _m$children2 : [], menu.key);
455
+ });
456
+ if (parentModule && parentModule.key !== activeFirstMenu) {
457
+ var _parentModule$childre2;
458
+ setActiveFirstMenu(parentModule.key);
459
+ setExpandedKeys(collectParentKeys((_parentModule$childre2 = parentModule.children) !== null && _parentModule$childre2 !== void 0 ? _parentModule$childre2 : []));
460
+ onActiveFirstMenuChange === null || onActiveFirstMenuChange === void 0 || onActiveFirstMenuChange(parentModule.key);
461
+ }
450
462
  // 父级菜单只负责展开(展开交互由 CompanySidebar 内部处理)
451
463
  if ((_menu$children5 = menu.children) !== null && _menu$children5 !== void 0 && _menu$children5.length) return;
452
464
  // 一级系统菜单(首页/收藏/系统设置)不开页签;首页激活 homeTab
@@ -467,7 +479,7 @@ export default function AdminLayoutTemplate(_ref) {
467
479
  });
468
480
  openTab(menu.key, (_page$label2 = page === null || page === void 0 ? void 0 : page.label) !== null && _page$label2 !== void 0 ? _page$label2 : menu.label, (_page$path2 = page === null || page === void 0 ? void 0 : page.path) !== null && _page$path2 !== void 0 ? _page$path2 : menu.path, page === null || page === void 0 ? void 0 : page.closable);
469
481
  onMenuOpen === null || onMenuOpen === void 0 || onMenuOpen(menu);
470
- }, [systemMenuKeys, homeTab, isTabActiveControlled, onActiveTabChange, onMenuOpen, pages, openTab]);
482
+ }, [businessMenus, activeFirstMenu, systemMenuKeys, homeTab, isTabActiveControlled, onActiveTabChange, onActiveFirstMenuChange, onMenuOpen, pages, openTab]);
471
483
  return /*#__PURE__*/_jsxs("div", {
472
484
  className: "admin-layout-template".concat(className ? " ".concat(className) : ""),
473
485
  style: style,
@@ -19,6 +19,7 @@
19
19
  display: flex;
20
20
  flex-direction: column;
21
21
  overflow: hidden;
22
+
22
23
  /* 主区灰底与 SmartListTemplate 等业务模板的 --color-bg-layout 对齐,
23
24
  页签栏与内容未充满处不露出白底 */
24
25
  background: var(--color-bg-layout, #f5f5f5);
@@ -31,6 +32,7 @@
31
32
  /* 间距契约:内容区只做滚动容器,禁止加 padding/margin/background(业务模板自带)。
32
33
  纵向 flex 让 SmartListTemplate(flex-grow:1 + align-self:stretch)充满剩余高度 */
33
34
  .admin-layout-content {
35
+ position: relative; /* 为 FormPageTemplate/DetailPageTemplate 等 absolute+inset:0 模板提供定位上下文,防止逃逸到全屏祖先 */
34
36
  flex: 1;
35
37
  min-height: 0;
36
38
  overflow: auto;
@@ -12,6 +12,7 @@ export interface FirstSidebarProps {
12
12
  businessMenus: SidebarMenuItem[];
13
13
  customNavMenus: SidebarMenuItem[];
14
14
  activeKey: string;
15
+ activeFirstMenu: string;
15
16
  visibleMenuCount?: number;
16
17
  domainPopoverOpen: boolean;
17
18
  adminPopoverOpen: boolean;
@@ -25,4 +26,4 @@ export interface FirstSidebarProps {
25
26
  onThemeSettings?: () => void;
26
27
  onLogout?: () => void;
27
28
  }
28
- export default function FirstSidebar({ domains, currentDomainId, userInfo, logo, brandName, firstMenus, systemBottomMenus, businessMenus, customNavMenus, activeKey, visibleMenuCount, domainPopoverOpen, adminPopoverOpen, onDomainPopoverOpenChange, onAdminPopoverOpenChange, onDomainChange, onMenuClick, onBusinessMenuEnter, onBusinessMenuLeave, onOpenMore, onThemeSettings, onLogout, }: FirstSidebarProps): import("react").JSX.Element;
29
+ export default function FirstSidebar({ domains, currentDomainId, userInfo, logo, brandName, firstMenus, systemBottomMenus, businessMenus, customNavMenus, activeKey, activeFirstMenu, visibleMenuCount, domainPopoverOpen, adminPopoverOpen, onDomainPopoverOpenChange, onAdminPopoverOpenChange, onDomainChange, onMenuClick, onBusinessMenuEnter, onBusinessMenuLeave, onOpenMore, onThemeSettings, onLogout, }: FirstSidebarProps): import("react").JSX.Element;
@@ -15,6 +15,7 @@ export default function FirstSidebar(_ref) {
15
15
  businessMenus = _ref.businessMenus,
16
16
  customNavMenus = _ref.customNavMenus,
17
17
  activeKey = _ref.activeKey,
18
+ activeFirstMenu = _ref.activeFirstMenu,
18
19
  _ref$visibleMenuCount = _ref.visibleMenuCount,
19
20
  visibleMenuCount = _ref$visibleMenuCount === void 0 ? 6 : _ref$visibleMenuCount,
20
21
  domainPopoverOpen = _ref.domainPopoverOpen,
@@ -120,7 +121,7 @@ export default function FirstSidebar(_ref) {
120
121
  className: "business-menus",
121
122
  children: [displayMenus.map(function (menu) {
122
123
  return /*#__PURE__*/_jsxs("div", {
123
- className: "business-menu-item".concat(activeKey === menu.key ? " active" : ""),
124
+ className: "business-menu-item".concat(activeFirstMenu === menu.key || activeKey === menu.key ? " active" : ""),
124
125
  onClick: function onClick() {
125
126
  return onMenuClick(menu);
126
127
  },
@@ -18,9 +18,27 @@ import CustomNavPanel from "./CustomNavPanel";
18
18
  import { resolveMenuIcons } from "./menuIconMap";
19
19
  import { DEFAULT_LOGO } from "./default-logo";
20
20
  import "./index.scss";
21
+
22
+ // 反查表:任意叶子菜单 key -> 所属一级业务菜单 key(选中二级时同步高亮一级)
21
23
  import { jsx as _jsx } from "react/jsx-runtime";
22
24
  import { jsxs as _jsxs } from "react/jsx-runtime";
23
25
  import { Fragment as _Fragment } from "react/jsx-runtime";
26
+ function buildLeafToFirstKeyMap(menus) {
27
+ var map = new Map();
28
+ var walk = function walk(items, firstKey) {
29
+ (items || []).forEach(function (item) {
30
+ var _item$children;
31
+ map.set(item.key, firstKey);
32
+ if ((_item$children = item.children) !== null && _item$children !== void 0 && _item$children.length) walk(item.children, firstKey);
33
+ });
34
+ };
35
+ (menus || []).forEach(function (menu) {
36
+ var _menu$children;
37
+ map.set(menu.key, menu.key);
38
+ if ((_menu$children = menu.children) !== null && _menu$children !== void 0 && _menu$children.length) walk(menu.children, menu.key);
39
+ });
40
+ return map;
41
+ }
24
42
  function DefaultFallback() {
25
43
  return /*#__PURE__*/_jsx("div", {
26
44
  className: "company-sidebar-error",
@@ -52,7 +70,7 @@ export default function CompanySidebar(_ref) {
52
70
  activeFirstMenu = _ref.activeFirstMenu,
53
71
  activeKey = _ref.activeKey,
54
72
  onFirstMenuSelect = _ref.onFirstMenuSelect,
55
- _onMenuClick = _ref.onMenuClick,
73
+ onMenuClick = _ref.onMenuClick,
56
74
  expandedKeys = _ref.expandedKeys,
57
75
  onExpandedKeysChange = _ref.onExpandedKeysChange,
58
76
  secondSidebarFixed = _ref.secondSidebarFixed,
@@ -84,6 +102,20 @@ export default function CompanySidebar(_ref) {
84
102
  var resolvedCustomNavMenus = useMemo(function () {
85
103
  return resolveMenuIcons(customNavMenus);
86
104
  }, [customNavMenus]);
105
+
106
+ // 叶子 key -> 一级菜单 key 反查表(业务菜单树全量)
107
+ var leafToFirstKeyMap = useMemo(function () {
108
+ return buildLeafToFirstKeyMap(businessMenus);
109
+ }, [businessMenus]);
110
+
111
+ // 内部统一的叶子菜单点击处理:命中业务菜单时同步 activeFirstMenu,保证一级导航同步高亮
112
+ var handleLeafMenuClick = useCallback(function (menu) {
113
+ var firstKey = leafToFirstKeyMap.get(menu.key);
114
+ if (firstKey && firstKey !== activeFirstMenu) {
115
+ onFirstMenuSelect(firstKey);
116
+ }
117
+ onMenuClick(menu);
118
+ }, [leafToFirstKeyMap, activeFirstMenu, onFirstMenuSelect, onMenuClick]);
87
119
  useEffect(function () {
88
120
  setState(function (prev) {
89
121
  return _objectSpread(_objectSpread({}, prev), {}, {
@@ -133,19 +165,22 @@ export default function CompanySidebar(_ref) {
133
165
  delayHideSidebar();
134
166
  }, [delayHideSidebar]);
135
167
  var handleFirstMenuClick = useCallback(function (menu) {
136
- onFirstMenuSelect(menu.key);
137
- _onMenuClick(menu);
138
- }, [onFirstMenuSelect, _onMenuClick]);
168
+ var firstKey = leafToFirstKeyMap.get(menu.key) || menu.key;
169
+ if (firstKey !== activeFirstMenu) {
170
+ onFirstMenuSelect(firstKey);
171
+ }
172
+ onMenuClick(menu);
173
+ }, [leafToFirstKeyMap, activeFirstMenu, onFirstMenuSelect, onMenuClick]);
139
174
  var handleMoreSelect = useCallback(function (menu, child) {
140
175
  var target = child || menu;
141
176
  onFirstMenuSelect(menu.key);
142
- _onMenuClick(target);
177
+ onMenuClick(target);
143
178
  setState(function (prev) {
144
179
  return _objectSpread(_objectSpread({}, prev), {}, {
145
180
  moreDrawerOpen: false
146
181
  });
147
182
  });
148
- }, [onFirstMenuSelect, _onMenuClick]);
183
+ }, [onFirstMenuSelect, onMenuClick]);
149
184
  var handleOpenCustomNav = useCallback(function () {
150
185
  setState(function (prev) {
151
186
  return _objectSpread(_objectSpread({}, prev), {}, {
@@ -192,6 +227,7 @@ export default function CompanySidebar(_ref) {
192
227
  businessMenus: resolvedBusinessMenus,
193
228
  customNavMenus: resolvedCustomNavMenus,
194
229
  activeKey: activeKey,
230
+ activeFirstMenu: activeFirstMenu,
195
231
  visibleMenuCount: visibleMenuCount,
196
232
  domainPopoverOpen: state.domainPopoverOpen,
197
233
  adminPopoverOpen: state.adminPopoverOpen,
@@ -232,7 +268,7 @@ export default function CompanySidebar(_ref) {
232
268
  expandedKeys: state.localExpandedKeys,
233
269
  emptyImage: emptyImage,
234
270
  onMenuClick: function onMenuClick(menu) {
235
- _onMenuClick(menu);
271
+ handleLeafMenuClick(menu);
236
272
  if (!secondSidebarFixed) {
237
273
  delayHideSidebar();
238
274
  }
@@ -7,6 +7,8 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
7
7
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
8
8
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
9
9
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
10
+ import { iconNames } from "../../shared-components/SvgIcon/icons";
11
+ var VALID_ICONS = new Set(iconNames);
10
12
  var KEYWORD_ICON_MAP = [{
11
13
  keywords: ["商品", "货品", "物料", "spu", "sku", "product"],
12
14
  icon: "commodity"
@@ -67,7 +69,12 @@ var KEYWORD_ICON_MAP = [{
67
69
  }];
68
70
  var DEFAULT_ICON = "folder-open";
69
71
  export function getMenuIcon(menu) {
70
- if (menu.icon) return menu.icon;
72
+ if (menu.icon) {
73
+ if (VALID_ICONS.has(menu.icon)) return menu.icon;
74
+ if (process.env.NODE_ENV !== "production") {
75
+ console.warn("[CompanySidebar] \u83DC\u5355 \"".concat(menu.label, "\" \u7684 icon \"").concat(menu.icon, "\" \u4E0D\u5728\u5185\u7F6E\u56FE\u6807\u96C6\u4E2D\uFF0C\u5DF2\u56DE\u9000\u4E3A\u5173\u952E\u8BCD\u5339\u914D\u3002\u5185\u7F6E\u56FE\u6807\u952E\u53EF\u67E5\u9605\u6587\u6863\u7AD9 /icon-library \u7CBE\u9009\u96C6\u3002"));
76
+ }
77
+ }
71
78
  var label = (menu.label || "").toLowerCase();
72
79
  var _iterator = _createForOfIteratorHelper(KEYWORD_ICON_MAP),
73
80
  _step;
@@ -1,4 +1,5 @@
1
1
  .detail-page-template {
2
+ box-sizing: border-box; /* 消费方项目未必有全局 border-box reset,模板自持,防止 padding 撑破 inset:0 宽度 */
2
3
  position: absolute;
3
4
  inset: 0;
4
5
  width: 100%;
@@ -1,4 +1,5 @@
1
1
  .form-page-template {
2
+ box-sizing: border-box; /* 消费方项目未必有全局 border-box reset,模板自持,防止 padding 撑破 inset:0 宽度 */
2
3
  position: absolute;
3
4
  inset: 0;
4
5
  width: 100%;
@@ -171,6 +171,9 @@
171
171
  justify-content: flex-end;
172
172
  padding: calc(var(--spacing-md, 16) * 1px);
173
173
  border-top: 1px solid var(--color-border-secondary, rgba(5, 5, 5, 0.06));
174
+
175
+ /* 吸底:表格高度由 scroll.y 控制不一定填满 wrapper,margin-top:auto 保证分页器始终贴白卡底部(对齐 SmartListTemplate 视觉契约) */
176
+ margin-top: auto;
174
177
  }
175
178
  }
176
179
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@donglegeyu/company-ui",
3
- "version": "1.2.39",
3
+ "version": "1.2.40",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/es/index.js",
6
6
  "types": "dist/es/index.d.ts",
@@ -31,7 +31,8 @@
31
31
  "test:run": "vitest run",
32
32
  "test:coverage": "vitest run --coverage",
33
33
  "prepare": "husky",
34
- "prepublishOnly": "bash scripts/check-clean.sh && npm run build"
34
+ "prepublishOnly": "bash scripts/check-clean.sh && npm run build",
35
+ "verify:skill-examples": "node scripts/verify-skill-examples.mjs"
35
36
  },
36
37
  "keywords": [
37
38
  "antd",