@hsu-react/ui 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/es/components/Chart/Bar/index.d.ts +5 -1
  2. package/es/components/Chart/Bar/index.js +84 -9
  3. package/es/components/Chart/Line/index.d.ts +5 -1
  4. package/es/components/Chart/Line/index.js +84 -9
  5. package/es/components/Chart/_utils/autoSmooth.d.ts +2 -0
  6. package/es/components/Chart/_utils/autoSmooth.js +12 -2
  7. package/es/components/Chart/_utils/cartesian.d.ts +11 -0
  8. package/es/components/Chart/_utils/cartesian.js +19 -0
  9. package/es/components/Chart/chartUtils/chartTooltipFormatter.d.ts +2 -0
  10. package/es/components/Chart/chartUtils/chartTooltipFormatter.js +13 -3
  11. package/es/components/Chart/chartUtils/index.d.ts +5 -2
  12. package/es/components/Chart/chartUtils/index.js +3 -1
  13. package/es/components/Chart/chartUtils/useDataZoomWindow.d.ts +19 -0
  14. package/es/components/Chart/chartUtils/useDataZoomWindow.js +37 -0
  15. package/es/components/Chart/chartUtils/useLegendSelection.d.ts +14 -0
  16. package/es/components/Chart/chartUtils/useLegendSelection.js +35 -0
  17. package/es/components/FormItem/ItemContainer/index.d.ts +2 -0
  18. package/es/components/FormItem/ItemContainer/index.js +4 -15
  19. package/es/components/Modal/index.module.scss +1 -0
  20. package/es/components/Panel/ListPanel/ListModalPanel/index.js +33 -5
  21. package/es/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
  22. package/es/components/Panel/ListPanel/index.module.scss +11 -12
  23. package/es/components/Search/{_components → SearchAdvanced/_components}/AdvancedFiltersDrawer/index.d.ts +3 -3
  24. package/es/components/Search/{_components → SearchAdvanced/_components}/AdvancedFiltersDrawer/index.js +3 -3
  25. package/es/components/Search/SearchAdvanced/index.js +26 -148
  26. package/es/components/Search/SearchCard/index.js +1 -1
  27. package/es/components/Search/{_components → SearchCollapsible/_components}/CollapseToggle/index.js +2 -2
  28. package/es/components/Search/SearchCollapsible/index.js +17 -138
  29. package/es/components/Search/SearchWithFilter/index.js +4 -143
  30. package/es/components/Search/SearchWithMore/index.js +11 -142
  31. package/es/components/Search/_components/FilterDropdown/index.js +5 -6
  32. package/es/components/Search/_components/SearchBase/index.d.ts +32 -0
  33. package/es/components/Search/_components/SearchBase/index.js +185 -0
  34. package/es/components/Search/_hooks/useSearchCommon.js +5 -11
  35. package/es/components/Search/_hooks/useSearchExpand.js +4 -13
  36. package/es/components/Search/_utils/calculateButtonGroupAndColumnWidth.js +3 -10
  37. package/es/components/Search/_utils/calculateVisibleItems.js +4 -5
  38. package/es/components/Search/_utils/index.d.ts +2 -0
  39. package/es/components/Search/_utils/index.js +3 -1
  40. package/es/components/Search/_utils/measureButtonGroupWidth.d.ts +6 -0
  41. package/es/components/Search/_utils/measureButtonGroupWidth.js +18 -0
  42. package/es/components/Search/_utils/shouldDisplayExtraItem.d.ts +11 -0
  43. package/es/components/Search/_utils/shouldDisplayExtraItem.js +13 -0
  44. package/es/components/Search/index.d.ts +4 -0
  45. package/es/components/Search/index.js +6 -133
  46. package/es/components/Table/_hooks/useTableColumns.js +11 -0
  47. package/lib/components/Chart/Bar/index.d.ts +5 -1
  48. package/lib/components/Chart/Bar/index.js +68 -4
  49. package/lib/components/Chart/Line/index.d.ts +5 -1
  50. package/lib/components/Chart/Line/index.js +68 -4
  51. package/lib/components/Chart/_utils/autoSmooth.d.ts +2 -0
  52. package/lib/components/Chart/_utils/autoSmooth.js +11 -1
  53. package/lib/components/Chart/_utils/cartesian.d.ts +11 -0
  54. package/lib/components/Chart/_utils/cartesian.js +21 -1
  55. package/lib/components/Chart/chartUtils/chartTooltipFormatter.d.ts +2 -0
  56. package/lib/components/Chart/chartUtils/chartTooltipFormatter.js +5 -3
  57. package/lib/components/Chart/chartUtils/index.d.ts +5 -2
  58. package/lib/components/Chart/chartUtils/index.js +14 -0
  59. package/lib/components/Chart/chartUtils/useDataZoomWindow.d.ts +19 -0
  60. package/lib/components/Chart/chartUtils/useDataZoomWindow.js +31 -0
  61. package/lib/components/Chart/chartUtils/useLegendSelection.d.ts +14 -0
  62. package/lib/components/Chart/chartUtils/useLegendSelection.js +26 -0
  63. package/lib/components/FormItem/ItemContainer/index.d.ts +2 -0
  64. package/lib/components/FormItem/ItemContainer/index.js +2 -5
  65. package/lib/components/Modal/index.module.scss +1 -0
  66. package/lib/components/Panel/ListPanel/ListModalPanel/index.js +21 -2
  67. package/lib/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
  68. package/lib/components/Panel/ListPanel/index.module.scss +11 -12
  69. package/lib/components/Search/{_components → SearchAdvanced/_components}/AdvancedFiltersDrawer/index.d.ts +3 -3
  70. package/lib/components/Search/{_components → SearchAdvanced/_components}/AdvancedFiltersDrawer/index.js +3 -3
  71. package/lib/components/Search/SearchAdvanced/index.js +19 -134
  72. package/lib/components/Search/SearchCard/index.js +1 -1
  73. package/lib/components/Search/{_components → SearchCollapsible/_components}/CollapseToggle/index.js +2 -2
  74. package/lib/components/Search/SearchCollapsible/index.js +12 -124
  75. package/lib/components/Search/SearchWithFilter/index.js +5 -129
  76. package/lib/components/Search/SearchWithMore/index.js +7 -126
  77. package/lib/components/Search/_components/FilterDropdown/index.js +5 -6
  78. package/lib/components/Search/_components/SearchBase/index.d.ts +32 -0
  79. package/lib/components/Search/_components/SearchBase/index.js +169 -0
  80. package/lib/components/Search/_hooks/useSearchCommon.js +4 -6
  81. package/lib/components/Search/_hooks/useSearchExpand.js +2 -13
  82. package/lib/components/Search/_utils/calculateButtonGroupAndColumnWidth.js +2 -10
  83. package/lib/components/Search/_utils/calculateVisibleItems.js +3 -5
  84. package/lib/components/Search/_utils/index.d.ts +2 -0
  85. package/lib/components/Search/_utils/index.js +15 -1
  86. package/lib/components/Search/_utils/measureButtonGroupWidth.d.ts +6 -0
  87. package/lib/components/Search/_utils/measureButtonGroupWidth.js +24 -0
  88. package/lib/components/Search/_utils/shouldDisplayExtraItem.d.ts +11 -0
  89. package/lib/components/Search/_utils/shouldDisplayExtraItem.js +19 -0
  90. package/lib/components/Search/index.d.ts +4 -0
  91. package/lib/components/Search/index.js +8 -119
  92. package/lib/components/Table/_hooks/useTableColumns.js +11 -0
  93. package/package.json +1 -1
  94. package/src/components/Chart/Bar/index.tsx +132 -2
  95. package/src/components/Chart/Line/index.tsx +132 -2
  96. package/src/components/Chart/_utils/autoSmooth.ts +181 -164
  97. package/src/components/Chart/_utils/cartesian.ts +28 -0
  98. package/src/components/Chart/chartUtils/chartTooltipFormatter.ts +11 -2
  99. package/src/components/Chart/chartUtils/index.ts +53 -37
  100. package/src/components/Chart/chartUtils/useDataZoomWindow.ts +61 -0
  101. package/src/components/Chart/chartUtils/useLegendSelection.ts +35 -0
  102. package/src/components/FormItem/ItemContainer/index.tsx +4 -7
  103. package/src/components/Modal/index.module.scss +1 -0
  104. package/src/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
  105. package/src/components/Panel/ListPanel/ListModalPanel/index.tsx +261 -233
  106. package/src/components/Panel/ListPanel/index.module.scss +11 -12
  107. package/src/components/Search/{_components → SearchAdvanced/_components}/AdvancedFiltersDrawer/index.tsx +6 -6
  108. package/src/components/Search/SearchAdvanced/index.tsx +25 -164
  109. package/src/components/Search/SearchCard/index.tsx +1 -1
  110. package/src/components/Search/{_components → SearchCollapsible/_components}/CollapseToggle/index.tsx +2 -2
  111. package/src/components/Search/SearchCollapsible/index.tsx +13 -162
  112. package/src/components/Search/SearchWithFilter/index.tsx +2 -164
  113. package/src/components/Search/SearchWithMore/index.tsx +9 -161
  114. package/src/components/Search/_components/FilterDropdown/index.tsx +5 -6
  115. package/src/components/Search/_components/SearchBase/index.tsx +224 -0
  116. package/src/components/Search/_hooks/useSearchCommon.ts +10 -13
  117. package/src/components/Search/_hooks/useSearchExpand.ts +3 -13
  118. package/src/components/Search/_utils/calculateButtonGroupAndColumnWidth.ts +2 -10
  119. package/src/components/Search/_utils/calculateVisibleItems.ts +10 -11
  120. package/src/components/Search/_utils/index.ts +2 -0
  121. package/src/components/Search/_utils/measureButtonGroupWidth.ts +23 -0
  122. package/src/components/Search/_utils/shouldDisplayExtraItem.ts +23 -0
  123. package/src/components/Search/index.tsx +7 -153
  124. package/src/components/Table/_hooks/useTableColumns.tsx +17 -0
  125. /package/es/components/Search/{_components → SearchCollapsible/_components}/CollapseToggle/index.d.ts +0 -0
  126. /package/lib/components/Search/{_components → SearchCollapsible/_components}/CollapseToggle/index.d.ts +0 -0
@@ -34,6 +34,8 @@ const ChartBar = props => {
34
34
  insideDataZoom,
35
35
  sliderDataZoom,
36
36
  onClick,
37
+ onLegendSelectChanged,
38
+ onDataZoomWindowChanged,
37
39
  enableLegendAutoScroll = false,
38
40
  legendVisibleCount = 8,
39
41
  legendScrollInterval = 1500,
@@ -42,6 +44,7 @@ const ChartBar = props => {
42
44
  const chartRef = (0, _react.useRef)(null);
43
45
  const chartInstanceRef = (0, _react.useRef)(null);
44
46
  const resizeObserverRef = (0, _react.useRef)(null);
47
+ const prevXAxisKeyRef = (0, _react.useRef)(null);
45
48
  const legendScrollRef = (0, _react.useRef)(null);
46
49
  const normalizedScroll = (0, _react.useMemo)(() => (0, _cartesian.resolveScrollConfig)(scrollConfig), [scrollConfig]);
47
50
 
@@ -198,8 +201,37 @@ const ChartBar = props => {
198
201
  chartInstanceRef.current = chart;
199
202
  }
200
203
 
201
- // 设置配置
204
+ // 设置配置:notMerge 会把 dataZoom 窗口重置回初始位置,
205
+ // x 轴数据未变化时(如坐标轴重算/图例点选触发的重渲染)先记录当前窗口,设置后恢复
206
+ const xAxisKey = xAxisData?.join("\u0001") ?? "";
207
+ const prevZoomRanges = prevXAxisKeyRef.current === xAxisKey ? chart.getOption()?.dataZoom : undefined;
208
+ prevXAxisKeyRef.current = xAxisKey;
202
209
  chart.setOption(chartOption, true);
210
+ const nextZooms = chartOption.dataZoom;
211
+ if (prevZoomRanges?.length && Array.isArray(nextZooms) && nextZooms.length === prevZoomRanges.length) {
212
+ chart.setOption({
213
+ dataZoom: prevZoomRanges.map(z => ({
214
+ start: z.start,
215
+ end: z.end
216
+ }))
217
+ });
218
+ }
219
+
220
+ // 向调用方同步当前可见窗口(初始渲染与恢复后),用于按展示部分重算坐标轴
221
+ if (onDataZoomWindowChanged) {
222
+ const zooms = chart.getOption()?.dataZoom;
223
+ const zoom = zooms?.[0];
224
+ const totalLen = xAxisData?.length ?? 0;
225
+ if (typeof zoom?.start === "number" && typeof zoom?.end === "number") {
226
+ onDataZoomWindowChanged((0, _cartesian.percentWindowToIndexWindow)(zoom.start, zoom.end, totalLen));
227
+ } else {
228
+ // 无 dataZoom(如数据量不足未启用滚动)时窗口即全量,同步一次避免残留旧窗口
229
+ onDataZoomWindowChanged({
230
+ startIndex: 0,
231
+ endIndex: Math.max(0, totalLen - 1)
232
+ });
233
+ }
234
+ }
203
235
 
204
236
  // 添加 resize 监听
205
237
  window.addEventListener("resize", handleResize);
@@ -215,6 +247,31 @@ const ChartBar = props => {
215
247
  chartInstanceRef.current?.on("click", onClick);
216
248
  }
217
249
 
250
+ // 图例点选事件
251
+ const handleLegendSelectChanged = params => {
252
+ onLegendSelectChanged?.(params.selected);
253
+ };
254
+ if (onLegendSelectChanged) {
255
+ chartInstanceRef.current?.on("legendselectchanged", handleLegendSelectChanged);
256
+ }
257
+
258
+ // dataZoom 原生交互(slider 拖动 / inside 缩放)→ 同步可见窗口
259
+ const handleDataZoom = params => {
260
+ const raw = params;
261
+ const info = raw?.batch?.[0] ?? raw;
262
+ if (typeof info?.startValue === "number" && typeof info?.endValue === "number") {
263
+ onDataZoomWindowChanged?.({
264
+ startIndex: Math.max(0, Math.round(info.startValue)),
265
+ endIndex: Math.max(0, Math.round(info.endValue))
266
+ });
267
+ } else if (typeof info?.start === "number" && typeof info?.end === "number") {
268
+ onDataZoomWindowChanged?.((0, _cartesian.percentWindowToIndexWindow)(info.start, info.end, xAxisData?.length ?? 0));
269
+ }
270
+ };
271
+ if (onDataZoomWindowChanged) {
272
+ chartInstanceRef.current?.on("datazoom", handleDataZoom);
273
+ }
274
+
218
275
  // 图例自动滚动(参考 Pie 组件)
219
276
  const opt = chartOption;
220
277
  const legendDataLen = Array.isArray(opt.legend) ? opt.legend[0]?.data?.length : opt.legend?.data?.length;
@@ -239,12 +296,18 @@ const ChartBar = props => {
239
296
  if (onClick) {
240
297
  chartInstanceRef.current?.off("click", onClick);
241
298
  }
299
+ if (onLegendSelectChanged) {
300
+ chartInstanceRef.current?.off("legendselectchanged", handleLegendSelectChanged);
301
+ }
302
+ if (onDataZoomWindowChanged) {
303
+ chartInstanceRef.current?.off("datazoom", handleDataZoom);
304
+ }
242
305
  if (legendScrollRef.current) {
243
306
  legendScrollRef.current.dispose();
244
307
  legendScrollRef.current = null;
245
308
  }
246
309
  };
247
- }, [chartOption, handleResize, onClick, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval]);
310
+ }, [chartOption, handleResize, onClick, onLegendSelectChanged, onDataZoomWindowChanged, xAxisData, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval]);
248
311
 
249
312
  // 处理自动播放
250
313
  (0, _react.useEffect)(() => {
@@ -260,10 +323,11 @@ const ChartBar = props => {
260
323
  interval: normalizedScroll.interval,
261
324
  startIndex: normalizedScroll.startIndex,
262
325
  autoPlay: normalizedScroll.autoScroll,
263
- enableWheelScroll
326
+ enableWheelScroll,
327
+ onWindowChange: onDataZoomWindowChanged ? (startPercent, endPercent) => onDataZoomWindowChanged((0, _cartesian.percentWindowToIndexWindow)(startPercent, endPercent, xAxisData.length)) : undefined
264
328
  });
265
329
  return dispose;
266
- }, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData]);
330
+ }, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData, onDataZoomWindowChanged]);
267
331
 
268
332
  // 组件卸载时清理资源
269
333
  (0, _react.useEffect)(() => {
@@ -1,7 +1,7 @@
1
1
  import * as echarts from "echarts";
2
2
  import { ChartCommonProps, SeriesDataType } from "..";
3
3
  import React from "react";
4
- import { ChartScrollConfig } from "../_utils/cartesian";
4
+ import { ChartScrollConfig, DataZoomIndexWindow } from "../_utils/cartesian";
5
5
  export interface ChartLineProps extends ChartCommonProps {
6
6
  chartTitle?: string;
7
7
  xAxisData?: Array<string>;
@@ -10,6 +10,10 @@ export interface ChartLineProps extends ChartCommonProps {
10
10
  scrollConfig?: ChartScrollConfig;
11
11
  yAxisNameOffsets?: number[];
12
12
  onClick?: (event: echarts.ECElementEvent) => void;
13
+ /** 图例点选变化回调,参数为当前各系列选中状态(配合 legend.selected 可实现坐标轴重算) */
14
+ onLegendSelectChanged?: (selected: Record<string, boolean>) => void;
15
+ /** dataZoom 可见窗口变化回调(滑块/滚轮/自动滚动/初始同步均触发),参数为当前可见的 x 轴索引区间(配合 useDataZoomWindow 可按展示部分重算坐标轴) */
16
+ onDataZoomWindowChanged?: (window: DataZoomIndexWindow) => void;
13
17
  /** 是否启用图例自动滚动,默认 false */
14
18
  enableLegendAutoScroll?: boolean;
15
19
  /** 图例每页可见数量,默认 8 */
@@ -34,6 +34,8 @@ const ChartLine = props => {
34
34
  insideDataZoom,
35
35
  sliderDataZoom,
36
36
  onClick,
37
+ onLegendSelectChanged,
38
+ onDataZoomWindowChanged,
37
39
  enableLegendAutoScroll = false,
38
40
  legendVisibleCount = 8,
39
41
  legendScrollInterval = 1500,
@@ -42,6 +44,7 @@ const ChartLine = props => {
42
44
  const chartRef = (0, _react.useRef)(null);
43
45
  const chartInstanceRef = (0, _react.useRef)(null);
44
46
  const resizeObserverRef = (0, _react.useRef)(null);
47
+ const prevXAxisKeyRef = (0, _react.useRef)(null);
45
48
  const legendScrollRef = (0, _react.useRef)(null);
46
49
  const normalizedScroll = (0, _react.useMemo)(() => (0, _cartesian.resolveScrollConfig)(scrollConfig), [scrollConfig]);
47
50
 
@@ -194,8 +197,37 @@ const ChartLine = props => {
194
197
  chartInstanceRef.current = chart;
195
198
  }
196
199
 
197
- // 设置配置
200
+ // 设置配置:notMerge 会把 dataZoom 窗口重置回初始位置,
201
+ // x 轴数据未变化时(如坐标轴重算/图例点选触发的重渲染)先记录当前窗口,设置后恢复
202
+ const xAxisKey = xAxisData?.join("\u0001") ?? "";
203
+ const prevZoomRanges = prevXAxisKeyRef.current === xAxisKey ? chart.getOption()?.dataZoom : undefined;
204
+ prevXAxisKeyRef.current = xAxisKey;
198
205
  chart.setOption(chartOption, true);
206
+ const nextZooms = chartOption.dataZoom;
207
+ if (prevZoomRanges?.length && Array.isArray(nextZooms) && nextZooms.length === prevZoomRanges.length) {
208
+ chart.setOption({
209
+ dataZoom: prevZoomRanges.map(z => ({
210
+ start: z.start,
211
+ end: z.end
212
+ }))
213
+ });
214
+ }
215
+
216
+ // 向调用方同步当前可见窗口(初始渲染与恢复后),用于按展示部分重算坐标轴
217
+ if (onDataZoomWindowChanged) {
218
+ const zooms = chart.getOption()?.dataZoom;
219
+ const zoom = zooms?.[0];
220
+ const totalLen = xAxisData?.length ?? 0;
221
+ if (typeof zoom?.start === "number" && typeof zoom?.end === "number") {
222
+ onDataZoomWindowChanged((0, _cartesian.percentWindowToIndexWindow)(zoom.start, zoom.end, totalLen));
223
+ } else {
224
+ // 无 dataZoom(如数据量不足未启用滚动)时窗口即全量,同步一次避免残留旧窗口
225
+ onDataZoomWindowChanged({
226
+ startIndex: 0,
227
+ endIndex: Math.max(0, totalLen - 1)
228
+ });
229
+ }
230
+ }
199
231
 
200
232
  // 添加 resize 监听
201
233
  window.addEventListener("resize", handleResize);
@@ -211,6 +243,31 @@ const ChartLine = props => {
211
243
  chartInstanceRef.current?.on("click", onClick);
212
244
  }
213
245
 
246
+ // 图例点选事件
247
+ const handleLegendSelectChanged = params => {
248
+ onLegendSelectChanged?.(params.selected);
249
+ };
250
+ if (onLegendSelectChanged) {
251
+ chartInstanceRef.current?.on("legendselectchanged", handleLegendSelectChanged);
252
+ }
253
+
254
+ // dataZoom 原生交互(slider 拖动 / inside 缩放)→ 同步可见窗口
255
+ const handleDataZoom = params => {
256
+ const raw = params;
257
+ const info = raw?.batch?.[0] ?? raw;
258
+ if (typeof info?.startValue === "number" && typeof info?.endValue === "number") {
259
+ onDataZoomWindowChanged?.({
260
+ startIndex: Math.max(0, Math.round(info.startValue)),
261
+ endIndex: Math.max(0, Math.round(info.endValue))
262
+ });
263
+ } else if (typeof info?.start === "number" && typeof info?.end === "number") {
264
+ onDataZoomWindowChanged?.((0, _cartesian.percentWindowToIndexWindow)(info.start, info.end, xAxisData?.length ?? 0));
265
+ }
266
+ };
267
+ if (onDataZoomWindowChanged) {
268
+ chartInstanceRef.current?.on("datazoom", handleDataZoom);
269
+ }
270
+
214
271
  // 图例自动滚动(与 Pie/Bar 一致)
215
272
  const opt = chartOption;
216
273
  const legendDataLen = Array.isArray(opt.legend) ? opt.legend[0]?.data?.length : opt.legend?.data?.length;
@@ -235,12 +292,18 @@ const ChartLine = props => {
235
292
  if (onClick) {
236
293
  chartInstanceRef.current?.off("click", onClick);
237
294
  }
295
+ if (onLegendSelectChanged) {
296
+ chartInstanceRef.current?.off("legendselectchanged", handleLegendSelectChanged);
297
+ }
298
+ if (onDataZoomWindowChanged) {
299
+ chartInstanceRef.current?.off("datazoom", handleDataZoom);
300
+ }
238
301
  if (legendScrollRef.current) {
239
302
  legendScrollRef.current.dispose();
240
303
  legendScrollRef.current = null;
241
304
  }
242
305
  };
243
- }, [chartOption, handleResize, onClick, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval]);
306
+ }, [chartOption, handleResize, onClick, onLegendSelectChanged, onDataZoomWindowChanged, xAxisData, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval]);
244
307
 
245
308
  // 处理自动播放
246
309
  (0, _react.useEffect)(() => {
@@ -256,10 +319,11 @@ const ChartLine = props => {
256
319
  interval: normalizedScroll.interval,
257
320
  startIndex: normalizedScroll.startIndex,
258
321
  autoPlay: normalizedScroll.autoScroll,
259
- enableWheelScroll
322
+ enableWheelScroll,
323
+ onWindowChange: onDataZoomWindowChanged ? (startPercent, endPercent) => onDataZoomWindowChanged((0, _cartesian.percentWindowToIndexWindow)(startPercent, endPercent, xAxisData.length)) : undefined
260
324
  });
261
325
  return dispose;
262
- }, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData]);
326
+ }, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData, onDataZoomWindowChanged]);
263
327
 
264
328
  // 组件卸载时清理资源
265
329
  (0, _react.useEffect)(() => {
@@ -7,6 +7,8 @@ export interface AutoScrollByItemProps {
7
7
  startIndex?: number;
8
8
  autoPlay?: boolean;
9
9
  enableWheelScroll?: boolean;
10
+ /** 窗口变化回调(创建同步、自动滚动、滚轮、resize 均触发),参数为当前窗口 start/end 百分比 */
11
+ onWindowChange?: (startPercent: number, endPercent: number) => void;
10
12
  }
11
13
  export declare function autoScrollByItem(props: AutoScrollByItemProps): {
12
14
  pause: () => void;
@@ -12,7 +12,8 @@ function autoScrollByItem(props) {
12
12
  interval = 2000,
13
13
  startIndex = 0,
14
14
  autoPlay = true,
15
- enableWheelScroll = true
15
+ enableWheelScroll = true,
16
+ onWindowChange
16
17
  } = props;
17
18
  const total = xAxisData?.length ?? 0;
18
19
  if (total <= 0) {
@@ -28,6 +29,14 @@ function autoScrollByItem(props) {
28
29
  const initialStartPercent = total > 0 ? initialStartIndex / total * 100 : 0;
29
30
  let start = initialStartPercent;
30
31
  let end = Math.min(initialStartPercent + windowSizePercent, 100);
32
+
33
+ // 图表已有 dataZoom 窗口时(组件重渲染重建滚动器)从当前位置继续,
34
+ // 避免图例点选、坐标轴重算等触发的重渲染把已滚动位置重置回初始窗口
35
+ const currentZoom = chart.getOption()?.dataZoom?.[0];
36
+ if (typeof currentZoom?.start === "number" && typeof currentZoom?.end === "number") {
37
+ start = currentZoom.start;
38
+ end = currentZoom.end;
39
+ }
31
40
  const syncDataZoomRange = () => {
32
41
  const option = chart.getOption();
33
42
  const currentDataZoom = option?.dataZoom;
@@ -39,6 +48,7 @@ function autoScrollByItem(props) {
39
48
  end
40
49
  }))
41
50
  });
51
+ onWindowChange?.(start, end);
42
52
  };
43
53
  syncDataZoomRange();
44
54
  let timer = null;
@@ -18,6 +18,17 @@ export interface NormalizedScrollConfig {
18
18
  sliderVisible?: boolean;
19
19
  wheelModeWhenSliderHidden: "scroll" | "none";
20
20
  }
21
+ /** dataZoom 当前可见窗口对应的 x 轴索引区间(闭区间) */
22
+ export interface DataZoomIndexWindow {
23
+ startIndex: number;
24
+ endIndex: number;
25
+ }
26
+ /**
27
+ * 把 dataZoom 的 start/end 百分比换算为 x 轴索引窗口。
28
+ * 与本组件族写入 dataZoom 的百分比约定一致(index / total * 100),
29
+ * 对 echarts 原生交互产生的百分比做外扩取整,边界最多多含一项,不影响坐标轴量级。
30
+ */
31
+ export declare const percentWindowToIndexWindow: (startPercent: number, endPercent: number, total: number) => DataZoomIndexWindow;
21
32
  export declare const createDefaultCategoryXAxis: (xAxisData?: Array<string>) => ChartOptionType;
22
33
  export declare const createDefaultValueYAxis: (mode?: "bar" | "line") => ChartOptionType;
23
34
  export declare const buildCartesianSeriesOptions: (mode: "bar" | "line", seriesData?: SeriesDataType, series?: echarts.SeriesOption | echarts.SeriesOption[]) => echarts.SeriesOption[];
@@ -3,7 +3,27 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.resolveScrollConfig = exports.getSliderShow = exports.createDefaultValueYAxis = exports.createDefaultCategoryXAxis = exports.buildCartesianSeriesOptions = void 0;
6
+ exports.resolveScrollConfig = exports.percentWindowToIndexWindow = exports.getSliderShow = exports.createDefaultValueYAxis = exports.createDefaultCategoryXAxis = exports.buildCartesianSeriesOptions = void 0;
7
+ /** dataZoom 当前可见窗口对应的 x 轴索引区间(闭区间) */
8
+
9
+ /**
10
+ * 把 dataZoom 的 start/end 百分比换算为 x 轴索引窗口。
11
+ * 与本组件族写入 dataZoom 的百分比约定一致(index / total * 100),
12
+ * 对 echarts 原生交互产生的百分比做外扩取整,边界最多多含一项,不影响坐标轴量级。
13
+ */
14
+ const percentWindowToIndexWindow = (startPercent, endPercent, total) => {
15
+ if (total <= 0) return {
16
+ startIndex: 0,
17
+ endIndex: 0
18
+ };
19
+ const startIndex = Math.max(0, Math.min(total - 1, Math.floor(startPercent / 100 * total)));
20
+ const endIndex = Math.max(startIndex, Math.min(total - 1, Math.ceil(endPercent / 100 * total) - 1));
21
+ return {
22
+ startIndex,
23
+ endIndex
24
+ };
25
+ };
26
+ exports.percentWindowToIndexWindow = percentWindowToIndexWindow;
7
27
  const createDefaultCategoryXAxis = xAxisData => ({
8
28
  type: "category",
9
29
  boundaryGap: true,
@@ -18,6 +18,8 @@ export interface ChartTooltipFormatterProps {
18
18
  hideMarker?: boolean;
19
19
  textStyle?: Record<string, unknown>;
20
20
  unit?: string;
21
+ /** 多系列时按数值从大到小排序展示(大的在上) */
22
+ sortDescending?: boolean;
21
23
  }
22
24
  declare const chartTooltipFormatter: (props: ChartTooltipFormatterProps) => string;
23
25
  export default chartTooltipFormatter;
@@ -14,7 +14,8 @@ const chartTooltipFormatter = props => {
14
14
  color: "#666",
15
15
  fontWeight: 400
16
16
  },
17
- unit
17
+ unit,
18
+ sortDescending
18
19
  } = props;
19
20
  if (!Array.isArray(params)) {
20
21
  return `
@@ -43,10 +44,11 @@ const chartTooltipFormatter = props => {
43
44
  </div>
44
45
  `;
45
46
  }
46
- const items = params?.map((item, idx) => {
47
+ const sortedParams = sortDescending ? [...params].sort((a, b) => (Number(b.value) || 0) - (Number(a.value) || 0)) : params;
48
+ const items = sortedParams?.map((item, idx) => {
47
49
  const value = item.value ?? "";
48
50
  return `
49
- <div style="margin: 0 0 ${idx === params.length - 1 ? "0" : "10px"} 0;line-height:1;">
51
+ <div style="margin: 0 0 ${idx === sortedParams.length - 1 ? "0" : "10px"} 0;line-height:1;">
50
52
  <div style="margin: 0px 0 0;line-height:1;">
51
53
  ${hideMarker ? "" : `${item?.marker}`}
52
54
  <span style="font-size:${textStyle?.fontSize}px;color:${textStyle?.color};font-weight:${textStyle?.fontWeight};margin-left:2px">${item?.seriesName}</span>
@@ -2,6 +2,9 @@ import chartTooltipFormatter from "./chartTooltipFormatter";
2
2
  import { TooltipParams, ChartTooltipFormatterProps } from "./chartTooltipFormatter";
3
3
  import { autoScrollLegend, AutoScrollLegendProps } from "../_utils/autoScrollLegend";
4
4
  import { calculateAxisConfig } from "./calculateAxisConfig";
5
+ import { useLegendSelection, LegendSelectionResult } from "./useLegendSelection";
6
+ import { useDataZoomWindow, DataZoomWindowOptions, DataZoomWindowResult } from "./useDataZoomWindow";
7
+ import { DataZoomIndexWindow } from "../_utils/cartesian";
5
8
  import { MB_PER_GB, MB_PER_TB, trimAxisNumber, chineseMagnitudeDivisor, formatChineseMagnitudeTick, mbDisplayTier, formatMbAxisTick } from "./yAxisDisplayUnit";
6
- export { chartTooltipFormatter, autoScrollLegend, calculateAxisConfig, MB_PER_GB, MB_PER_TB, trimAxisNumber, chineseMagnitudeDivisor, formatChineseMagnitudeTick, mbDisplayTier, formatMbAxisTick, };
7
- export type { TooltipParams, ChartTooltipFormatterProps, AutoScrollLegendProps, };
9
+ export { chartTooltipFormatter, autoScrollLegend, calculateAxisConfig, useLegendSelection, useDataZoomWindow, MB_PER_GB, MB_PER_TB, trimAxisNumber, chineseMagnitudeDivisor, formatChineseMagnitudeTick, mbDisplayTier, formatMbAxisTick, };
10
+ export type { TooltipParams, ChartTooltipFormatterProps, AutoScrollLegendProps, LegendSelectionResult, DataZoomWindowOptions, DataZoomWindowResult, DataZoomIndexWindow, };
@@ -63,8 +63,22 @@ Object.defineProperty(exports, "trimAxisNumber", {
63
63
  return _yAxisDisplayUnit.trimAxisNumber;
64
64
  }
65
65
  });
66
+ Object.defineProperty(exports, "useDataZoomWindow", {
67
+ enumerable: true,
68
+ get: function () {
69
+ return _useDataZoomWindow.useDataZoomWindow;
70
+ }
71
+ });
72
+ Object.defineProperty(exports, "useLegendSelection", {
73
+ enumerable: true,
74
+ get: function () {
75
+ return _useLegendSelection.useLegendSelection;
76
+ }
77
+ });
66
78
  var _chartTooltipFormatter = _interopRequireDefault(require("./chartTooltipFormatter"));
67
79
  var _autoScrollLegend = require("../_utils/autoScrollLegend");
68
80
  var _calculateAxisConfig = require("./calculateAxisConfig");
81
+ var _useLegendSelection = require("./useLegendSelection");
82
+ var _useDataZoomWindow = require("./useDataZoomWindow");
69
83
  var _yAxisDisplayUnit = require("./yAxisDisplayUnit");
70
84
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -0,0 +1,19 @@
1
+ import { DataZoomIndexWindow } from "../_utils/cartesian";
2
+ export interface DataZoomWindowOptions {
3
+ /** 开关:是否按 dataZoom 当前可见窗口重算坐标轴,默认开启 */
4
+ enabled?: boolean;
5
+ }
6
+ export interface DataZoomWindowResult {
7
+ /** 当前可见窗口;开关关闭或尚未收到回调时为 null(表示全量) */
8
+ zoomWindow: DataZoomIndexWindow | null;
9
+ /** 传给 Chart.Bar / Chart.Line 的 onDataZoomWindowChanged;开关关闭时为 undefined(不绑定事件) */
10
+ onDataZoomWindowChanged?: (window: DataZoomIndexWindow) => void;
11
+ /** 按当前可见窗口裁剪系列数据,配合 calculateAxisConfig 只对展示部分重算坐标轴 */
12
+ sliceByZoomWindow: <T>(values?: T[] | null) => T[];
13
+ }
14
+ /**
15
+ * dataZoom 可见窗口管理:配合 Chart.Bar / Chart.Line 的 onDataZoomWindowChanged,
16
+ * 在调用方按"当前可见窗口"裁剪数据后重算 Y 轴 min/max/interval(calculateAxisConfig),
17
+ * 实现滑块拖动/滚轮/自动滚动时坐标轴跟随展示部分动态重算;可与 useLegendSelection 叠加。
18
+ */
19
+ export declare function useDataZoomWindow(options?: DataZoomWindowOptions): DataZoomWindowResult;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useDataZoomWindow = useDataZoomWindow;
7
+ var _react = require("react");
8
+ /**
9
+ * dataZoom 可见窗口管理:配合 Chart.Bar / Chart.Line 的 onDataZoomWindowChanged,
10
+ * 在调用方按"当前可见窗口"裁剪数据后重算 Y 轴 min/max/interval(calculateAxisConfig),
11
+ * 实现滑块拖动/滚轮/自动滚动时坐标轴跟随展示部分动态重算;可与 useLegendSelection 叠加。
12
+ */
13
+ function useDataZoomWindow(options) {
14
+ const enabled = options?.enabled ?? true;
15
+ const [zoomWindow, setZoomWindow] = (0, _react.useState)(null);
16
+ const onDataZoomWindowChanged = (0, _react.useCallback)(next => {
17
+ // 窗口未变化时保持原引用,避免重渲染 → 同步回调 → 再重渲染的循环
18
+ setZoomWindow(prev => prev && prev.startIndex === next.startIndex && prev.endIndex === next.endIndex ? prev : next);
19
+ }, []);
20
+ const effectiveWindow = enabled ? zoomWindow : null;
21
+ const sliceByZoomWindow = (0, _react.useCallback)(values => {
22
+ if (!values) return [];
23
+ if (!effectiveWindow) return values;
24
+ return values.slice(effectiveWindow.startIndex, effectiveWindow.endIndex + 1);
25
+ }, [effectiveWindow]);
26
+ return {
27
+ zoomWindow: effectiveWindow,
28
+ onDataZoomWindowChanged: enabled ? onDataZoomWindowChanged : undefined,
29
+ sliceByZoomWindow
30
+ };
31
+ }
@@ -0,0 +1,14 @@
1
+ export interface LegendSelectionResult {
2
+ /** 传给图表 legend.selected,保证重渲染(setOption notMerge)后隐藏状态不丢 */
3
+ legendSelected: Record<string, boolean>;
4
+ /** 传给图表 onLegendSelectChanged */
5
+ onLegendSelectChanged: (selected: Record<string, boolean>) => void;
6
+ /** 判断某系列当前是否可见(未点过的系列默认可见) */
7
+ isSeriesVisible: (name?: string | null) => boolean;
8
+ }
9
+ /**
10
+ * 图例选中状态管理:配合 Chart.Bar / Chart.Line 的 onLegendSelectChanged,
11
+ * 在调用方按"当前可见系列"重算 Y 轴 min/max/interval(calculateAxisConfig),
12
+ * 实现图例隐藏某一项后坐标轴自动重算。
13
+ */
14
+ export declare function useLegendSelection(): LegendSelectionResult;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useLegendSelection = useLegendSelection;
7
+ var _react = require("react");
8
+ /**
9
+ * 图例选中状态管理:配合 Chart.Bar / Chart.Line 的 onLegendSelectChanged,
10
+ * 在调用方按"当前可见系列"重算 Y 轴 min/max/interval(calculateAxisConfig),
11
+ * 实现图例隐藏某一项后坐标轴自动重算。
12
+ */
13
+ function useLegendSelection() {
14
+ const [legendSelected, setLegendSelected] = (0, _react.useState)({});
15
+ const onLegendSelectChanged = (0, _react.useCallback)(selected => {
16
+ setLegendSelected({
17
+ ...selected
18
+ });
19
+ }, []);
20
+ const isSeriesVisible = (0, _react.useCallback)(name => name == null || legendSelected[name] !== false, [legendSelected]);
21
+ return {
22
+ legendSelected,
23
+ onLegendSelectChanged,
24
+ isSeriesVisible
25
+ };
26
+ }
@@ -35,6 +35,8 @@ export interface ItemContainerProps extends FormItemProps {
35
35
  labelBreak?: boolean;
36
36
  hideAdditiona?: boolean;
37
37
  hideLabel?: boolean;
38
+ /** 显隐开关,由 FormItem 消费;在此解构剥离,避免透传到 DOM */
39
+ visible?: boolean;
38
40
  }
39
41
  declare const ItemContainer: React.FC<ItemContainerProps>;
40
42
  export default ItemContainer;
@@ -55,6 +55,7 @@ const ItemContainer = props => {
55
55
  labelBreak = false,
56
56
  hideAdditiona = false,
57
57
  hideLabel = false,
58
+ visible: _visible,
58
59
  ...formItemProps
59
60
  } = props;
60
61
  const {
@@ -149,12 +150,8 @@ const ItemContainer = props => {
149
150
  if (!permitted) {
150
151
  return null;
151
152
  }
152
-
153
- // 页面层 FormItemProps 的展示控制属性(如 visible)不属于 antd Form.Item,
154
- // 剥离后再透传,避免被 antd 转发到 DOM 触发 React 非法属性警告。
155
- const restFormItemProps = Object.fromEntries(Object.entries(formItemProps).filter(([key]) => key !== "visible"));
156
153
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Form.Item, {
157
- ...restFormItemProps,
154
+ ...formItemProps,
158
155
  name: name,
159
156
  rules: [{
160
157
  required,
@@ -62,6 +62,7 @@
62
62
  align-items: center;
63
63
  justify-content: flex-end;
64
64
  column-gap: 10px;
65
+ margin-left: auto; // title 为空时仍保持靠右
65
66
  }
66
67
  }
67
68
  }
@@ -7,6 +7,7 @@ exports.default = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _Search = _interopRequireDefault(require("../../../Search"));
9
9
  var _Table = _interopRequireDefault(require("../../../Table"));
10
+ var _icons = require("@ant-design/icons");
10
11
  var _classnames = _interopRequireDefault(require("classnames"));
11
12
  var _lodash = require("lodash");
12
13
  var _indexModule = _interopRequireDefault(require("./index.module.scss"));
@@ -49,6 +50,12 @@ const ListModalPanel = props => {
49
50
  } = (0, _usePermissions.default)(hasPermi);
50
51
  const [_columns, setColumns] = (0, _react.useState)(columns);
51
52
  const [showColumnMgt, setShowColumnMgt] = (0, _react.useState)(false);
53
+ const [isFullscreen, setIsFullscreen] = (0, _react.useState)(false);
54
+ (0, _react.useEffect)(() => {
55
+ if (modalConfig.open) {
56
+ setIsFullscreen(false);
57
+ }
58
+ }, [modalConfig.open]);
52
59
  (0, _react.useEffect)(() => {
53
60
  if (columnMgt && columns?.length) {
54
61
  const _columns = columns?.map(col => {
@@ -109,9 +116,20 @@ const ListModalPanel = props => {
109
116
  }
110
117
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
111
118
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Modal.default, {
112
- width: 1400,
113
- className: (0, _classnames.default)(modalClassName),
114
119
  ...modalConfig,
120
+ width: isFullscreen ? "100vw" : modalConfig.width ?? 1400,
121
+ ...(isFullscreen ? {
122
+ full: true
123
+ } : {}),
124
+ className: (0, _classnames.default)(_indexModule.default.modal, modalClassName, {
125
+ [_indexModule.default.fullscreen]: isFullscreen
126
+ }),
127
+ titleButtonGroup: [{
128
+ type: "text",
129
+ icon: isFullscreen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.FullscreenExitOutlined, {}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.FullscreenOutlined, {}),
130
+ title: isFullscreen ? "退出全屏" : "全屏",
131
+ onClick: () => setIsFullscreen(v => !v)
132
+ }, ...(modalConfig.titleButtonGroup ?? [])],
115
133
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
116
134
  className: (0, _classnames.default)(_indexModule.default.ListModalPanel, className),
117
135
  children: [extraContent, SearchComponent, /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
@@ -130,6 +148,7 @@ const ListModalPanel = props => {
130
148
  scroll: true,
131
149
  serialNumberColumn: true,
132
150
  bordered: true,
151
+ fillPanel: true,
133
152
  ...tableConfig,
134
153
  columns: _columns
135
154
  })]
@@ -1,10 +1,25 @@
1
+ .modal {
2
+ // 定高让内部“height: 100%”链路可解析(antd Modal 默认内容自适应,内层设置 height/max-height 无效)
3
+ height: 700px;
4
+
5
+ &.fullscreen {
6
+ top: 0;
7
+
8
+ width: 100vw !important;
9
+ max-width: 100vw !important;
10
+ height: 100vh !important;
11
+
12
+ margin: 0;
13
+ padding-bottom: 0;
14
+ }
15
+ }
16
+
1
17
  .ListModalPanel {
2
18
  display: flex;
3
19
  flex-direction: column;
4
20
  row-gap: 10px;
5
21
 
6
- height: max-content;
7
- max-height: 70vh;
22
+ height: 100%;
8
23
 
9
24
  .search {
10
25
  padding: 0px;