@zat-design/sisyphus-react 4.5.6-beta.1 → 4.5.6-beta.3

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.
@@ -0,0 +1,58 @@
1
+ /**
2
+ * iframe: 400
3
+ */
4
+
5
+ import { useState } from 'react';
6
+ import { Button, Space } from 'antd';
7
+ import { ProConfigProvider, ProForm } from '@zat-design/sisyphus-react';
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
+ const LocaleDemo = () => {
10
+ const [locale, setLocale] = useState(localStorage.getItem('locale') || 'zh-CN');
11
+ const handleChange = value => {
12
+ setLocale(value);
13
+ localStorage.setItem('locale', value);
14
+ window.location.reload();
15
+ };
16
+ return /*#__PURE__*/_jsxs(Space, {
17
+ direction: "vertical",
18
+ size: 16,
19
+ style: {
20
+ width: '100%'
21
+ },
22
+ children: [/*#__PURE__*/_jsxs(Space, {
23
+ children: [/*#__PURE__*/_jsx(Button, {
24
+ type: locale === 'zh-CN' ? 'primary' : 'default',
25
+ onClick: () => handleChange('zh-CN'),
26
+ children: "\u4E2D\u6587"
27
+ }), /*#__PURE__*/_jsx(Button, {
28
+ type: locale === 'en-US' ? 'primary' : 'default',
29
+ onClick: () => handleChange('en-US'),
30
+ children: "English"
31
+ })]
32
+ }), /*#__PURE__*/_jsx(ProConfigProvider, {
33
+ locale: locale,
34
+ children: /*#__PURE__*/_jsx(ProForm, {
35
+ columns: [{
36
+ type: 'Input',
37
+ label: locale === 'zh-CN' ? '姓名' : 'Name',
38
+ name: 'name',
39
+ required: true
40
+ }, {
41
+ type: 'Select',
42
+ label: locale === 'zh-CN' ? '状态' : 'Status',
43
+ name: 'status',
44
+ fieldProps: {
45
+ options: [{
46
+ label: locale === 'zh-CN' ? '启用' : 'Enabled',
47
+ value: '1'
48
+ }, {
49
+ label: locale === 'zh-CN' ? '禁用' : 'Disabled',
50
+ value: '0'
51
+ }]
52
+ }
53
+ }]
54
+ })
55
+ })]
56
+ });
57
+ };
58
+ export default LocaleDemo;
@@ -9,6 +9,7 @@ import dayjs from 'dayjs';
9
9
  import React from 'react';
10
10
  import { useProConfig } from "../../../../ProConfigProvider";
11
11
  import locale from "../../../../locale";
12
+ import enUS from "../../../../locale/en_US";
12
13
  import ProForm from "../../../../ProForm";
13
14
  import Container from "../../Container";
14
15
  import { useDateRange } from "./useDateRange";
@@ -35,13 +36,7 @@ const getDefaultFormat = picker => {
35
36
 
36
37
  // 获取默认快捷选项(presets 格式)
37
38
  const getDefaultPresets = () => {
38
- const rangeLabels = locale?.RangePicker?.ranges || {
39
- today: '今天',
40
- lastWeek: '近1周',
41
- lastMonth: '近1月',
42
- last3Months: '近3月',
43
- lastYear: '近1年'
44
- };
39
+ const rangeLabels = locale?.RangePicker?.ranges || enUS.RangePicker.ranges;
45
40
  return [{
46
41
  label: rangeLabels.today,
47
42
  value: [dayjs().startOf('day'), dayjs().endOf('day')]
@@ -3,10 +3,11 @@ import _isFunction from "lodash/isFunction";
3
3
  import React from 'react';
4
4
  import { Modal } from 'antd';
5
5
  import ProForm from "../../index";
6
+ import locale from "../../../locale";
6
7
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
7
8
  const defaultConfirmProps = {
8
- title: '操作提示',
9
- content: '确定要修改该字段吗?'
9
+ title: locale.ProForm.confirmTitle,
10
+ content: locale.ProForm.confirmContent
10
11
  };
11
12
  const ConfirmWrapper = props => {
12
13
  const {
@@ -115,7 +115,7 @@ const RenderFields = props => {
115
115
  }
116
116
  if (component && /*#__PURE__*/React.isValidElement(component)) {
117
117
  const newComponent = component;
118
- const isProEditTable = newComponent?.props?.onlyOneLineMsg === '请先保存数据';
118
+ const isProEditTable = newComponent?.props?.onlyOneLineMsg != null;
119
119
  TargetComponent = _isView ? viewRenderHandle || '' : component;
120
120
  // 可编辑表格内部支持
121
121
  if (isProEditTable) {
@@ -172,7 +172,7 @@ export interface ProHeaderType {
172
172
  */
173
173
  fixedTop?: string | number;
174
174
  /**
175
- * @description 是否显示返回按钮
175
+ * @description 是否显示返回按钮。显式传值优先;不传时若有 onBack 则显示,否则由 autoBack 按浏览器历史长度判断
176
176
  * @default -
177
177
  */
178
178
  showBack?: boolean;
@@ -198,8 +198,8 @@ export interface ProHeaderType {
198
198
  */
199
199
  zIndex?: number;
200
200
  /**
201
- * @description 返回
202
- * @default 100
201
+ * @description 返回按钮点击回调;不传时默认执行 window.history.back()
202
+ * @default -
203
203
  */
204
204
  onBack?: () => void;
205
205
  [key: string]: any;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import type { DescribeColumnType } from '../../PropTypes';
3
+ /** 描述项里的单条值(link / copyable / tag 组合),对应 items 数组元素 */
4
+ type DescribeValueItem = Pick<DescribeColumnType, 'tag' | 'link' | 'value' | 'copyable'>;
5
+ /**
6
+ * 标签渲染:数组 tag 逐个渲染,单值渲染一个,空则不渲染
7
+ */
8
+ export declare const DescribeTag: ({ tag, parentKey, }: {
9
+ tag?: DescribeColumnType["tag"];
10
+ parentKey: string;
11
+ }) => import("react/jsx-runtime").JSX.Element;
12
+ /**
13
+ * 单行值渲染:link → <a>,copyable+字符串 → 复制按钮,末尾追加 tag
14
+ */
15
+ export declare const DescribeValue: ({ value, link, copyable, tag, parentKey, }: DescribeValueItem & {
16
+ parentKey: string;
17
+ }) => import("react/jsx-runtime").JSX.Element;
18
+ /**
19
+ * 多值渲染:以「、」连接;超 3 个显示「共N个,」前缀;内容溢出时显示「...」并用 Tooltip 展示全部
20
+ */
21
+ export declare const DescribeItems: ({ items, parentKey, containerRef, }: {
22
+ items: DescribeValueItem[];
23
+ parentKey: string;
24
+ containerRef: React.RefObject<HTMLDivElement>;
25
+ }) => import("react/jsx-runtime").JSX.Element;
26
+ export {};
@@ -0,0 +1,109 @@
1
+ import _isString from "lodash/isString";
2
+ import React from 'react';
3
+ import { Space, Tooltip } from 'antd';
4
+ import classnames from 'classnames';
5
+ import Copy from "../Copy";
6
+ import { checkDescribeItemsHidden, getTagKey, getDescribeValueKey } from "../../utils";
7
+ import locale, { formatMessage } from "../../../../../locale";
8
+
9
+ /** 描述项里的单条值(link / copyable / tag 组合),对应 items 数组元素 */
10
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
+ /**
12
+ * 标签渲染:数组 tag 逐个渲染,单值渲染一个,空则不渲染
13
+ */
14
+ export const DescribeTag = ({
15
+ tag,
16
+ parentKey
17
+ }) => {
18
+ if (Array.isArray(tag) && tag.length) {
19
+ return /*#__PURE__*/_jsx(Space, {
20
+ size: 4,
21
+ children: tag.map((tagItem, tagIndex) => /*#__PURE__*/_jsx("div", {
22
+ className: "pro-header-tag",
23
+ children: tagItem
24
+ }, getTagKey(tagItem, parentKey, tagIndex)))
25
+ });
26
+ }
27
+ return tag ? /*#__PURE__*/_jsx("div", {
28
+ className: "pro-header-tag",
29
+ children: tag
30
+ }) : null;
31
+ };
32
+
33
+ /**
34
+ * 单行值渲染:link → <a>,copyable+字符串 → 复制按钮,末尾追加 tag
35
+ */
36
+ export const DescribeValue = ({
37
+ value,
38
+ link,
39
+ copyable,
40
+ tag,
41
+ parentKey
42
+ }) => {
43
+ return /*#__PURE__*/_jsxs(Space, {
44
+ size: 4,
45
+ align: tag ? 'baseline' : 'center',
46
+ children: [link ? /*#__PURE__*/_jsx("a", {
47
+ onClick: () => {
48
+ const newWindow = window.open(link);
49
+ newWindow.opener = null;
50
+ },
51
+ children: value
52
+ }) : value, copyable && _isString(value) ? /*#__PURE__*/_jsx(Copy, {
53
+ text: value
54
+ }) : null, /*#__PURE__*/_jsx(DescribeTag, {
55
+ tag: tag,
56
+ parentKey: parentKey
57
+ })]
58
+ });
59
+ };
60
+
61
+ /**
62
+ * 多值渲染:以「、」连接;超 3 个显示「共N个,」前缀;内容溢出时显示「...」并用 Tooltip 展示全部
63
+ */
64
+ export const DescribeItems = ({
65
+ items,
66
+ parentKey,
67
+ containerRef
68
+ }) => {
69
+ // items 配置是否超长,超长则展示 ... + tip 提示
70
+ const itemsHidden = checkDescribeItemsHidden(containerRef?.current);
71
+ const result = /*#__PURE__*/_jsxs("div", {
72
+ ref: containerRef,
73
+ className: classnames({
74
+ 'pro-header-describe-items': true,
75
+ 'pro-header-describe-items-more': items.length >= 2
76
+ }),
77
+ children: [items?.length > 3 ? formatMessage(locale.ProHeader.itemsCountPrefix, {
78
+ count: items.length
79
+ }) : null, items.map((item, itemIndex) => /*#__PURE__*/_jsxs("span", {
80
+ children: [/*#__PURE__*/_jsx(DescribeValue, {
81
+ ...item,
82
+ parentKey: parentKey
83
+ }), items?.length !== itemIndex + 1 ? locale.ProHeader.itemsSeparator : null]
84
+ }, getDescribeValueKey(item, parentKey, itemIndex))), itemsHidden ? /*#__PURE__*/_jsx("span", {
85
+ className: "pro-header-describe-items-omit",
86
+ children: "..."
87
+ }) : null]
88
+ });
89
+ if (itemsHidden) {
90
+ const tipResult = /*#__PURE__*/_jsx(_Fragment, {
91
+ children: items.map((item, itemIndex) => /*#__PURE__*/_jsx("p", {
92
+ className: "pro-header-describe-items-tip-value",
93
+ children: /*#__PURE__*/_jsx(DescribeValue, {
94
+ ...item,
95
+ parentKey: parentKey
96
+ })
97
+ }, getDescribeValueKey(item, parentKey, itemIndex)))
98
+ });
99
+ return /*#__PURE__*/_jsx(Tooltip, {
100
+ placement: "bottomLeft",
101
+ classNames: {
102
+ root: 'pro-header-describe-items-tip'
103
+ },
104
+ title: tipResult,
105
+ children: result
106
+ });
107
+ }
108
+ return result;
109
+ };
@@ -7,26 +7,18 @@ import React, { memo, useEffect, useState, useRef } from 'react';
7
7
  import { tools } from '@zat-design/utils';
8
8
  import classnames from 'classnames';
9
9
  import dayjs from 'dayjs';
10
- import { useToggle, useSize } from 'ahooks';
10
+ import { useToggle } from 'ahooks';
11
11
  import { ReactSVG } from 'react-svg';
12
12
  import foldSvg from "../../../assets/arrow.svg";
13
13
  import { Copy, ProBackBtn } from "./components";
14
+ import { DescribeItems, DescribeValue } from "./components/Describe";
14
15
  import getEnumLabel from "../../../ProEnum/utils/getEnumLabel";
15
16
  import locale from "../../../locale";
16
- import { checkDescribeItemsHidden } from "./utils";
17
+ import { toKeyPart, getDescribeColumnKey, getTagKey, getSubDescribeKey } from "./utils";
17
18
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
18
19
  const {
19
20
  formatAmount
20
21
  } = tools;
21
- const toKeyPart = value => {
22
- if (value == null || value === '') return undefined;
23
- if (typeof value === 'string' || typeof value === 'number') return String(value);
24
- return undefined;
25
- };
26
- const getDescribeColumnKey = (item, index) => toKeyPart(item.label) ?? toKeyPart(item.value) ?? `describe-${index}`;
27
- const getDescribeValueKey = (item, parentKey, index) => toKeyPart(item.link) ?? toKeyPart(item.value) ?? `${parentKey}-value-${index}`;
28
- const getTagKey = (tagItem, parentKey, index) => toKeyPart(tagItem) ?? `${parentKey}-tag-${index}`;
29
- const getSubDescribeKey = (item, index) => toKeyPart(item.label) ?? toKeyPart(item.code) ?? `sub-describe-${index}`;
30
22
  const ProHeader = props => {
31
23
  const {
32
24
  breadcrumbColumns,
@@ -37,7 +29,6 @@ const ProHeader = props => {
37
29
  className,
38
30
  bodyOverFlowHidden = false,
39
31
  fixedTop,
40
- showBack = true,
41
32
  showShadow = false,
42
33
  zIndex = 98,
43
34
  title,
@@ -47,19 +38,32 @@ const ProHeader = props => {
47
38
  isConfirmBack = false,
48
39
  isConfirmBackModalProps = {}
49
40
  } = props;
50
- const [backState, setBackState] = useState(showBack);
41
+
42
+ // 返回按钮是否显示。
43
+ // 显式意图优先于 autoBack 启发式:
44
+ // 1) 用户显式传了 showBack → 完全尊重该值;
45
+ // 2) 传了 onBack(返回不依赖浏览器历史,如 tab 内返回 / 自定义跳转)→ 显示;
46
+ // 3) 都没传(纯默认,返回兜底走 window.history.back)→ 由 autoBack 按历史长度智能判断:
47
+ // 新开页面(history.length <= autoBack)无处可返回,则隐藏。
48
+ const computeBackState = () => {
49
+ if (props.showBack !== undefined) return props.showBack;
50
+ if (onBack) return true;
51
+ return window.history.length > autoBack;
52
+ };
53
+ const [backState, setBackState] = useState(computeBackState);
51
54
  const [fold, {
52
55
  toggle
53
56
  }] = useToggle(collapsed);
54
57
  const ref = useRef(null);
55
- const size = useSize(ref);
56
- let _title = title;
58
+
59
+ // 最终用于渲染的标题(title + showBack 时会被转成面包屑,此处置空)
60
+ let finalTitle = title;
57
61
 
58
62
  // 面包屑配置数据源
59
- const _breadcrumbColumns = breadcrumbColumns || [];
63
+ const finalBreadcrumbColumns = breadcrumbColumns || [];
60
64
 
61
65
  // 次级配置数据源
62
- const _subDescribeColumns = subDescribeColumns || [];
66
+ const finalSubDescribeColumns = subDescribeColumns || [];
63
67
  useEffect(() => {
64
68
  if (bodyOverFlowHidden) {
65
69
  const bodyElement = document.querySelector('body');
@@ -70,13 +74,11 @@ const ProHeader = props => {
70
74
  bodyElement.style.overflow = '';
71
75
  };
72
76
  }, [bodyOverFlowHidden]);
77
+
78
+ // showBack / onBack / autoBack 变化时同步 backState(避免 props 更新后按钮显隐不同步)
73
79
  useEffect(() => {
74
- const isNewPage = window.history.length;
75
- // history的记录,默认2,代办新开页面
76
- if (isNewPage <= autoBack) {
77
- setBackState(false);
78
- }
79
- }, []);
80
+ setBackState(computeBackState());
81
+ }, [props.showBack, onBack, autoBack]);
80
82
 
81
83
  /**
82
84
  * 主级描述数据渲染
@@ -108,82 +110,6 @@ const ProHeader = props => {
108
110
  return null;
109
111
  }
110
112
  const onlyTag = tag && !label && !value;
111
- const tagRender = params => {
112
- if (Array.isArray(params?.tag) && params?.tag.length) {
113
- return /*#__PURE__*/_jsx(Space, {
114
- size: 4,
115
- children: params.tag.map((tagItem, tagIndex) => {
116
- return /*#__PURE__*/_jsx("div", {
117
- className: "pro-header-tag",
118
- children: tagItem
119
- }, getTagKey(tagItem, describeItemKey, tagIndex));
120
- })
121
- });
122
- }
123
- return params?.tag ? /*#__PURE__*/_jsx("div", {
124
- className: "pro-header-tag",
125
- children: params?.tag
126
- }) : null;
127
- };
128
-
129
- /** 单行渲染 */
130
- const valueRender = params => {
131
- return /*#__PURE__*/_jsxs(Space, {
132
- size: 4,
133
- align: params?.tag ? 'baseline' : 'center',
134
- children: [params?.link ? /*#__PURE__*/_jsx("a", {
135
- onClick: () => {
136
- const newWindow = window.open(params.link);
137
- newWindow.opener = null;
138
- },
139
- children: params?.value
140
- }) : params?.value, params?.copyable && _isString(params?.value) ? /*#__PURE__*/_jsx(Copy, {
141
- text: params.value
142
- }) : null, tagRender({
143
- tag: params?.tag
144
- })]
145
- });
146
- };
147
-
148
- /** 多行渲染 */
149
- const itemsRender = () => {
150
- // items配置是否超长,超长配置... + tip 提示
151
- const itemsHidden = checkDescribeItemsHidden(ref?.current);
152
- const result = /*#__PURE__*/_jsxs("div", {
153
- ref: ref,
154
- className: classnames({
155
- 'pro-header-describe-items': true,
156
- 'pro-header-describe-items-more': items.length >= 2
157
- }),
158
- children: [items?.length > 3 ? `共${items?.length}个,` : null, items.map((item, itemIndex) => {
159
- return /*#__PURE__*/_jsxs("span", {
160
- children: [valueRender(item), items?.length !== itemIndex + 1 ? ' 、' : null]
161
- }, getDescribeValueKey(item, describeItemKey, itemIndex));
162
- }), itemsHidden ? /*#__PURE__*/_jsx("span", {
163
- className: "pro-header-describe-items-omit",
164
- children: "..."
165
- }) : null]
166
- });
167
- if (itemsHidden) {
168
- const tipResult = /*#__PURE__*/_jsx(_Fragment, {
169
- children: items.map((item, itemIndex) => {
170
- return /*#__PURE__*/_jsx("p", {
171
- className: "pro-header-describe-items-tip-value",
172
- children: valueRender(item)
173
- }, getDescribeValueKey(item, describeItemKey, itemIndex));
174
- })
175
- });
176
- return /*#__PURE__*/_jsx(Tooltip, {
177
- placement: "bottomLeft",
178
- classNames: {
179
- root: 'pro-header-describe-items-tip'
180
- },
181
- title: tipResult,
182
- children: result
183
- });
184
- }
185
- return result;
186
- };
187
113
  const tagCls = classnames({
188
114
  'pro-header-only-tag': onlyTag,
189
115
  'pro-header-describe-items-calc': _isString(width) ? width.includes('calc') : false
@@ -200,12 +126,17 @@ const ProHeader = props => {
200
126
  children: label
201
127
  }) : null, /*#__PURE__*/_jsx("span", {
202
128
  className: "pro-header-describe-value",
203
- children: items?.length ? itemsRender() : /*#__PURE__*/_jsx("span", {
204
- children: valueRender({
205
- value,
206
- copyable,
207
- tag,
208
- link
129
+ children: items?.length ? /*#__PURE__*/_jsx(DescribeItems, {
130
+ items: items,
131
+ parentKey: describeItemKey,
132
+ containerRef: ref
133
+ }) : /*#__PURE__*/_jsx("span", {
134
+ children: /*#__PURE__*/_jsx(DescribeValue, {
135
+ value: value,
136
+ copyable: copyable,
137
+ tag: tag,
138
+ link: link,
139
+ parentKey: describeItemKey
209
140
  })
210
141
  })
211
142
  })]
@@ -302,10 +233,10 @@ const ProHeader = props => {
302
233
  * 总结信息面板渲染
303
234
  */
304
235
  const breadcrumbRender = () => {
305
- if (Array.isArray(_breadcrumbColumns) && !_breadcrumbColumns.length) {
236
+ if (Array.isArray(finalBreadcrumbColumns) && !finalBreadcrumbColumns.length) {
306
237
  return [];
307
238
  }
308
- const list = _breadcrumbColumns?.filter(item => {
239
+ const list = finalBreadcrumbColumns?.filter(item => {
309
240
  return item.type === 'breadcrumb';
310
241
  });
311
242
  return list.map((item, index) => {
@@ -355,10 +286,10 @@ const ProHeader = props => {
355
286
  * 头部左侧导航栏后业务信息
356
287
  */
357
288
  const infoRender = () => {
358
- if (!Array.isArray(_breadcrumbColumns)) {
289
+ if (!Array.isArray(finalBreadcrumbColumns)) {
359
290
  return '';
360
291
  }
361
- const list = _breadcrumbColumns?.filter(item => {
292
+ const list = finalBreadcrumbColumns?.filter(item => {
362
293
  return item.type !== 'breadcrumb';
363
294
  });
364
295
  if (!list.length) {
@@ -436,24 +367,29 @@ const ProHeader = props => {
436
367
  })
437
368
  });
438
369
  };
370
+
371
+ // 说明:以下两个 class 的判断沿用原有等价逻辑(去掉了原表达式里对 describeColumns 的重复判断)。
372
+ // has = 有次级描述 或 有主级描述;no = 无主级描述。二者非严格互斥(原实现即如此,未改动其行为)。
373
+ const noDescribe = _isEmpty(describeColumns);
374
+ const hasDescribe = !_isEmpty(finalSubDescribeColumns) || !noDescribe;
439
375
  const cls = classnames({
440
376
  'pro-header': true,
441
377
  'pro-header-fixed': fixedTop,
442
378
  'pro-header-shadow': showShadow,
443
379
  // 内部窗口滚动自带阴影场景
444
380
  'pro-header-no-back': !backState,
445
- 'pro-header-has-describe': !_isEmpty(_subDescribeColumns) || !_isEmpty(describeColumns) || !_isEmpty(describeColumns),
446
- 'pro-header-no-describe': _isEmpty(_subDescribeColumns) && _isEmpty(describeColumns) || _isEmpty(describeColumns),
381
+ 'pro-header-has-describe': hasDescribe,
382
+ 'pro-header-no-describe': noDescribe,
447
383
  [`${className}`]: className
448
384
  });
449
- if (title && !_isEmpty(_breadcrumbColumns)) {
385
+ if (title && !_isEmpty(finalBreadcrumbColumns)) {
450
386
  console.error('warning: The title and the breadcrumbList cannot be used together');
451
387
  }
452
388
 
453
389
  // title默认不显示返回按钮,只有showBack设置为true时才显示
454
390
  if (title && props.showBack) {
455
- _title = null;
456
- _breadcrumbColumns.push({
391
+ finalTitle = null;
392
+ finalBreadcrumbColumns.push({
457
393
  type: 'breadcrumb',
458
394
  value: title
459
395
  });
@@ -492,9 +428,9 @@ const ProHeader = props => {
492
428
  top: fixedTop,
493
429
  zIndex
494
430
  },
495
- children: _title ? /*#__PURE__*/_jsx("div", {
431
+ children: finalTitle ? /*#__PURE__*/_jsx("div", {
496
432
  className: "pro-header-title",
497
- children: _title
433
+ children: finalTitle
498
434
  }) : /*#__PURE__*/_jsxs(_Fragment, {
499
435
  children: [/*#__PURE__*/_jsxs("div", {
500
436
  className: "pro-header-top",
@@ -516,14 +452,14 @@ const ProHeader = props => {
516
452
  className: "pro-header-right",
517
453
  children: actionsRender()
518
454
  })]
519
- }), describeRender(describeColumns), !_isEmpty(_subDescribeColumns) ? /*#__PURE__*/_jsxs("div", {
455
+ }), describeRender(describeColumns), !_isEmpty(finalSubDescribeColumns) ? /*#__PURE__*/_jsxs("div", {
520
456
  className: classnames({
521
457
  'pro-header-nav': true,
522
458
  'pro-header-nav-open': fold,
523
459
  'pro-header-nav-hidden': !fold
524
460
  }),
525
461
  children: [/*#__PURE__*/_jsx("ul", {
526
- children: _subDescribeColumns.map((item, index) => {
462
+ children: finalSubDescribeColumns.map((item, index) => {
527
463
  return /*#__PURE__*/_jsx("li", {
528
464
  children: subDescribeRender(item)
529
465
  }, getSubDescribeKey(item, index));
@@ -1,5 +1,20 @@
1
+ import type React from 'react';
2
+ import type { DescribeColumnType, SubDescribeColumnType } from '../PropTypes';
1
3
  /**
2
4
  * 检查描述dom是否部分隐藏
3
5
  * @param ele dom节点
4
6
  */
5
7
  export declare const checkDescribeItemsHidden: (ele?: any) => boolean;
8
+ /**
9
+ * 将值转为可用于 React key 的字符串片段
10
+ * 仅 string / number 有效,其余(含 ReactNode、对象、数组、boolean)返回 undefined
11
+ */
12
+ export declare const toKeyPart: (value: unknown) => string | undefined;
13
+ /** 主级描述项 key:label → value → describe-${index} */
14
+ export declare const getDescribeColumnKey: (item: DescribeColumnType, index: number) => string;
15
+ /** 描述值 key:link → value → ${parentKey}-value-${index} */
16
+ export declare const getDescribeValueKey: (item: Pick<DescribeColumnType, "tag" | "link" | "value" | "copyable">, parentKey: string, index: number) => string;
17
+ /** 标签 key:tagItem → ${parentKey}-tag-${index} */
18
+ export declare const getTagKey: (tagItem: string | React.ReactNode, parentKey: string, index: number) => string;
19
+ /** 次级描述项 key:label → code → sub-describe-${index} */
20
+ export declare const getSubDescribeKey: (item: SubDescribeColumnType, index: number) => string;
@@ -11,4 +11,26 @@ export const checkDescribeItemsHidden = ele => {
11
11
  const itemsScrollWidth = element.scrollWidth;
12
12
  const itemsClientWidth = element.clientWidth;
13
13
  return itemsScrollWidth > itemsClientWidth;
14
- };
14
+ };
15
+
16
+ /**
17
+ * 将值转为可用于 React key 的字符串片段
18
+ * 仅 string / number 有效,其余(含 ReactNode、对象、数组、boolean)返回 undefined
19
+ */
20
+ export const toKeyPart = value => {
21
+ if (value == null || value === '') return undefined;
22
+ if (typeof value === 'string' || typeof value === 'number') return String(value);
23
+ return undefined;
24
+ };
25
+
26
+ /** 主级描述项 key:label → value → describe-${index} */
27
+ export const getDescribeColumnKey = (item, index) => toKeyPart(item.label) ?? toKeyPart(item.value) ?? `describe-${index}`;
28
+
29
+ /** 描述值 key:link → value → ${parentKey}-value-${index} */
30
+ export const getDescribeValueKey = (item, parentKey, index) => toKeyPart(item.link) ?? toKeyPart(item.value) ?? `${parentKey}-value-${index}`;
31
+
32
+ /** 标签 key:tagItem → ${parentKey}-tag-${index} */
33
+ export const getTagKey = (tagItem, parentKey, index) => toKeyPart(tagItem) ?? `${parentKey}-tag-${index}`;
34
+
35
+ /** 次级描述项 key:label → code → sub-describe-${index} */
36
+ export const getSubDescribeKey = (item, index) => toKeyPart(item.label) ?? toKeyPart(item.code) ?? `sub-describe-${index}`;
@@ -1,9 +1,11 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  import { Dropdown } from 'antd';
3
- import { jsx as _jsx } from "react/jsx-runtime";
3
+ import locale from "../../../../locale";
4
+
4
5
  /**
5
6
  * 右键菜单组件 - 兼容Antd 4.x和5.x
6
7
  */
8
+ import { jsx as _jsx } from "react/jsx-runtime";
7
9
  function TabContextMenu({
8
10
  tabId,
9
11
  children,
@@ -53,17 +55,17 @@ function TabContextMenu({
53
55
  // 默认右键菜单配置 - 统一使用items方式(antd 4.20+都支持)
54
56
  const defaultMenuItems = [{
55
57
  key: 'close',
56
- label: '关闭',
58
+ label: locale.ProLayout.tabMenuClose,
57
59
  disabled: !closable
58
60
  }, {
59
61
  key: 'closeOthers',
60
- label: '关闭其他'
62
+ label: locale.ProLayout.tabMenuCloseOthers
61
63
  }, {
62
64
  key: 'closeRight',
63
- label: '关闭右侧标签页'
65
+ label: locale.ProLayout.tabMenuCloseRight
64
66
  }, {
65
67
  key: 'closeAll',
66
- label: '关闭全部'
68
+ label: locale.ProLayout.tabMenuCloseAll
67
69
  }];
68
70
 
69
71
  // 合并自定义菜单项和默认菜单项