@ticatec/uniface-element 0.2.0 → 0.2.1

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/README.md +273 -1
  2. package/README_CN.md +341 -0
  3. package/dist/common/MouseClickHandler.d.ts +1 -1
  4. package/dist/dialog/CommonDialog.svelte +6 -3
  5. package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
  6. package/dist/dialog/Dialog.svelte +36 -10
  7. package/dist/dialog/Dialog.svelte.d.ts +4 -3
  8. package/dist/dialog/DialogBoard.svelte +11 -8
  9. package/dist/dialog/DialogWrapper.svelte +10 -0
  10. package/dist/dialog/DialogWrapper.svelte.d.ts +22 -0
  11. package/dist/dialog/Dialogs.js +1 -1
  12. package/dist/dialog/ModalResult.d.ts +5 -0
  13. package/dist/dialog/ModalResult.js +5 -0
  14. package/docs/buttons/cn/ActionBar.md +459 -0
  15. package/docs/buttons/cn/Button.md +228 -0
  16. package/docs/buttons/cn/IconButton.md +294 -0
  17. package/docs/buttons/cn/README.md +600 -0
  18. package/docs/buttons/cn/TextButton.md +163 -0
  19. package/docs/buttons/en/ActionBar.md +459 -0
  20. package/docs/buttons/en/Button.md +228 -0
  21. package/docs/buttons/en/IconButton.md +294 -0
  22. package/docs/buttons/en/README.md +600 -0
  23. package/docs/buttons/en/TextButton.md +163 -0
  24. package/docs/containers/cn/accordion.md +622 -0
  25. package/docs/containers/cn/box.md +445 -0
  26. package/docs/containers/cn/card.md +404 -0
  27. package/docs/containers/cn/page.md +576 -0
  28. package/docs/containers/cn/tabs.md +686 -0
  29. package/docs/containers/en/accordion.md +622 -0
  30. package/docs/containers/en/box.md +445 -0
  31. package/docs/containers/en/card.md +404 -0
  32. package/docs/containers/en/page.md +576 -0
  33. package/docs/containers/en/tabs.md +686 -0
  34. package/docs/data-display/cn/concise-data-table.md +731 -0
  35. package/docs/data-display/cn/listbox.md +786 -0
  36. package/docs/data-display/cn/treeview.md +863 -0
  37. package/docs/data-display/en/concise-data-table.md +732 -0
  38. package/docs/data-display/en/listbox.md +786 -0
  39. package/docs/data-display/en/treeview.md +863 -0
  40. package/docs/data-table/cn/README.md +596 -0
  41. package/docs/data-table/en/README.md +596 -0
  42. package/docs/dialog/cn/README.md +767 -0
  43. package/docs/dialog/en/README.md +767 -0
  44. package/docs/form/cn/README.md +847 -0
  45. package/docs/form/en/README.md +847 -0
  46. package/docs/form-components/cn/README.md +495 -0
  47. package/docs/form-components/cn/attachmentfilesfield.md +757 -0
  48. package/docs/form-components/cn/cascade-options-select.md +374 -0
  49. package/docs/form-components/cn/checkbox.md +58 -0
  50. package/docs/form-components/cn/date-picker.md +138 -0
  51. package/docs/form-components/cn/datetime-picker.md +228 -0
  52. package/docs/form-components/cn/group-checkbox.md +405 -0
  53. package/docs/form-components/cn/group-radiobox.md +525 -0
  54. package/docs/form-components/cn/imagefilesfield.md +651 -0
  55. package/docs/form-components/cn/input-options-select.md +250 -0
  56. package/docs/form-components/cn/lookup-editor.md +406 -0
  57. package/docs/form-components/cn/memoeditor.md +409 -0
  58. package/docs/form-components/cn/number-editor.md +261 -0
  59. package/docs/form-components/cn/options-multi-select.md +177 -0
  60. package/docs/form-components/cn/options-select.md +83 -0
  61. package/docs/form-components/cn/passwordeditor.md +538 -0
  62. package/docs/form-components/cn/prompts-text-editor.md +241 -0
  63. package/docs/form-components/cn/radiobutton.md +84 -0
  64. package/docs/form-components/cn/switch.md +178 -0
  65. package/docs/form-components/cn/text-editor.md +142 -0
  66. package/docs/form-components/cn/time-editor.md +159 -0
  67. package/docs/form-components/cn/unit-number-editor.md +164 -0
  68. package/docs/form-components/en/README.md +463 -0
  69. package/docs/form-components/en/attachmentfilesfield.md +757 -0
  70. package/docs/form-components/en/cascade-options-select.md +358 -0
  71. package/docs/form-components/en/checkbox.md +59 -0
  72. package/docs/form-components/en/date-picker.md +138 -0
  73. package/docs/form-components/en/datetime-picker.md +228 -0
  74. package/docs/form-components/en/group-checkbox.md +395 -0
  75. package/docs/form-components/en/group-radiobox.md +498 -0
  76. package/docs/form-components/en/imagefilesfield.md +651 -0
  77. package/docs/form-components/en/input-options-select.md +239 -0
  78. package/docs/form-components/en/lookup-editor.md +389 -0
  79. package/docs/form-components/en/memoeditor.md +409 -0
  80. package/docs/form-components/en/number-editor.md +249 -0
  81. package/docs/form-components/en/options-multi-select.md +177 -0
  82. package/docs/form-components/en/options-select.md +83 -0
  83. package/docs/form-components/en/passwordeditor.md +538 -0
  84. package/docs/form-components/en/prompts-text-editor.md +241 -0
  85. package/docs/form-components/en/radiobutton.md +84 -0
  86. package/docs/form-components/en/switch.md +180 -0
  87. package/docs/form-components/en/text-editor.md +142 -0
  88. package/docs/form-components/en/time-editor.md +159 -0
  89. package/docs/form-components/en/unit-number-editor.md +164 -0
  90. package/docs/form-layout/cn/criteria-field.md +652 -0
  91. package/docs/form-layout/cn/flex-form.md +454 -0
  92. package/docs/form-layout/cn/flex-row-form.md +542 -0
  93. package/docs/form-layout/cn/form-field.md +923 -0
  94. package/docs/form-layout/cn/grid-form.md +676 -0
  95. package/docs/form-layout/en/criteria-field.md +652 -0
  96. package/docs/form-layout/en/flex-form.md +454 -0
  97. package/docs/form-layout/en/flex-row-form.md +542 -0
  98. package/docs/form-layout/en/form-field.md +923 -0
  99. package/docs/form-layout/en/grid-form.md +676 -0
  100. package/docs/global/cn/README.md +534 -0
  101. package/docs/global/en/README.md +534 -0
  102. package/docs/layout/cn/classiclayout.md +460 -0
  103. package/docs/layout/cn/headerlayout.md +524 -0
  104. package/docs/layout/cn/sidebarlayout.md +263 -0
  105. package/docs/layout/en/classiclayout.md +951 -0
  106. package/docs/layout/en/headerlayout.md +524 -0
  107. package/docs/layout/en/sidebarlayout.md +262 -0
  108. package/docs/misc/cn/README.md +1217 -0
  109. package/docs/misc/en/README.md +1217 -0
  110. package/docs/navigation/cn/breadcrumb.md +291 -0
  111. package/docs/navigation/cn/navigator.md +322 -0
  112. package/docs/navigation/cn/navigatormenu.md +512 -0
  113. package/docs/navigation/cn/progressbar.md +199 -0
  114. package/docs/navigation/cn/progressstepbar.md +299 -0
  115. package/docs/navigation/en/breadcrumb.md +291 -0
  116. package/docs/navigation/en/navigator.md +322 -0
  117. package/docs/navigation/en/navigatormenu.md +512 -0
  118. package/docs/navigation/en/progressbar.md +199 -0
  119. package/docs/navigation/en/progressstepbar.md +299 -0
  120. package/docs/search-filters/cn/daterange.md +1156 -0
  121. package/docs/search-filters/cn/numberrange.md +688 -0
  122. package/docs/search-filters/cn/searchbox.md +1582 -0
  123. package/docs/search-filters/en/daterange.md +1156 -0
  124. package/docs/search-filters/en/numberrange.md +688 -0
  125. package/docs/search-filters/en/searchbox.md +1582 -0
  126. package/package.json +38 -5
@@ -0,0 +1,688 @@
1
+ # NumberRange 数值范围组件
2
+
3
+ 一个数值范围输入组件,允许用户指定两个数字之间的范围,通常用于按数值条件过滤数据,如价格范围、年龄范围或数量过滤器。
4
+
5
+ ## 概述
6
+
7
+ NumberRange 组件为选择数值范围提供了直观的界面,具有内置验证、自动范围约束和清除功能。它具有两个相互连接的数字输入框,可以智能地相互验证,确保"从"值始终小于或等于"到"值。非常适合搜索过滤器、数据查询和任何需要数值范围选择的应用程序。
8
+
9
+ ## 安装
10
+
11
+ ```typescript
12
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
13
+ import type { OnChangeHandler } from '@ticatec/uniface-element/NumberRange';
14
+ ```
15
+
16
+ ## 基本用法
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
21
+
22
+ let fromValue: number = 0;
23
+ let toValue: number = 100;
24
+ </script>
25
+
26
+ <NumberRange
27
+ bind:fromValue
28
+ bind:toValue
29
+ variant="outlined"
30
+ />
31
+ ```
32
+
33
+ ## 属性
34
+
35
+ | 属性 | 类型 | 默认值 | 描述 |
36
+ |------|------|--------|------|
37
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉样式变体 |
38
+ | `compact` | `boolean` | `false` | 启用紧凑布局以适应密集表单 |
39
+ | `class` | `string` | `''` | 额外的 CSS 类名 |
40
+ | `style` | `string` | `''` | 自定义内联样式 |
41
+ | `min` | `number \| null` | `null` | 全局最小允许值 |
42
+ | `max` | `number \| null` | `null` | 全局最大允许值 |
43
+ | `fromValue` | `number` | - | 范围的起始值(可绑定) |
44
+ | `toValue` | `number` | - | 范围的结束值(可绑定) |
45
+ | `allowNegative` | `boolean` | `false` | 在输入框中允许负数 |
46
+
47
+ ## 功能特性
48
+
49
+ - **智能验证**:自动验证范围约束(从 ≤ 到)
50
+ - **跨字段限制**:"从"值设置"到"的最大值,"到"值设置"从"的最小值
51
+ - **清除功能**:当存在值时显示的内置清除按钮
52
+ - **自动聚焦**:清除值后聚焦第一个输入框
53
+ - **负数支持**:可选支持负数范围
54
+ - **一致样式**:通过变体支持与其他表单组件匹配
55
+
56
+ ## 类型定义
57
+
58
+ ```typescript
59
+ /**
60
+ * 变更事件处理器类型
61
+ */
62
+ type OnChangeHandler<T> = (value: T) => void;
63
+ ```
64
+
65
+ ## 使用示例
66
+
67
+ ### 价格范围过滤器
68
+
69
+ ```svelte
70
+ <script lang="ts">
71
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
72
+
73
+ let minPrice: number = 0;
74
+ let maxPrice: number = 1000;
75
+
76
+ // 响应式语句处理价格范围变化
77
+ $: if (minPrice !== undefined && maxPrice !== undefined) {
78
+ filterProductsByPrice(minPrice, maxPrice);
79
+ }
80
+
81
+ function filterProductsByPrice(min: number, max: number) {
82
+ console.log(`过滤产品价格范围:¥${min} 到 ¥${max}`);
83
+ // 在此实现过滤逻辑
84
+ }
85
+
86
+ function resetPriceFilter() {
87
+ minPrice = 0;
88
+ maxPrice = 1000;
89
+ }
90
+ </script>
91
+
92
+ <div class="price-filter">
93
+ <h3>价格范围</h3>
94
+
95
+ <NumberRange
96
+ bind:fromValue={minPrice}
97
+ bind:toValue={maxPrice}
98
+ variant="outlined"
99
+ min={0}
100
+ max={10000}
101
+ style="width: 300px;"
102
+ />
103
+
104
+ <div class="price-display">
105
+ <span class="price-label">
106
+ ¥{minPrice?.toLocaleString() || 0} - ¥{maxPrice?.toLocaleString() || 0}
107
+ </span>
108
+ </div>
109
+
110
+ <button class="reset-btn" on:click={resetPriceFilter}>
111
+ 重置过滤器
112
+ </button>
113
+ </div>
114
+
115
+ <style>
116
+ .price-filter {
117
+ padding: 16px;
118
+ background: #f8f9fa;
119
+ border-radius: 8px;
120
+ max-width: 400px;
121
+ }
122
+
123
+ .price-filter h3 {
124
+ margin: 0 0 12px 0;
125
+ color: #333;
126
+ font-size: 1.1rem;
127
+ }
128
+
129
+ .price-display {
130
+ margin: 12px 0;
131
+ text-align: center;
132
+ }
133
+
134
+ .price-label {
135
+ font-weight: 500;
136
+ color: #007bff;
137
+ font-size: 1.1rem;
138
+ }
139
+
140
+ .reset-btn {
141
+ width: 100%;
142
+ padding: 8px 16px;
143
+ background: #6c757d;
144
+ color: white;
145
+ border: none;
146
+ border-radius: 4px;
147
+ cursor: pointer;
148
+ margin-top: 8px;
149
+ }
150
+
151
+ .reset-btn:hover {
152
+ background: #5a6268;
153
+ }
154
+ </style>
155
+ ```
156
+
157
+ ### 年龄范围选择器
158
+
159
+ ```svelte
160
+ <script lang="ts">
161
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
162
+
163
+ let minAge: number = 18;
164
+ let maxAge: number = 65;
165
+ let selectedProfiles = [];
166
+
167
+ // 按年龄过滤用户资料的函数
168
+ function filterProfilesByAge(min: number, max: number) {
169
+ // 模拟资料数据
170
+ const allProfiles = [
171
+ { id: 1, name: '张小明', age: 25 },
172
+ { id: 2, name: '李小红', age: 35 },
173
+ { id: 3, name: '王小刚', age: 45 },
174
+ { id: 4, name: '赵小丽', age: 28 },
175
+ { id: 5, name: '陈小华', age: 52 }
176
+ ];
177
+
178
+ selectedProfiles = allProfiles.filter(profile =>
179
+ profile.age >= min && profile.age <= max
180
+ );
181
+ }
182
+
183
+ // 初始加载和值变化时进行过滤
184
+ $: filterProfilesByAge(minAge || 0, maxAge || 100);
185
+ </script>
186
+
187
+ <div class="age-filter-demo">
188
+ <div class="filter-section">
189
+ <h3>按年龄范围过滤</h3>
190
+
191
+ <NumberRange
192
+ bind:fromValue={minAge}
193
+ bind:toValue={maxAge}
194
+ variant="filled"
195
+ min={16}
196
+ max={100}
197
+ style="width: 250px;"
198
+ compact={true}
199
+ />
200
+
201
+ <div class="age-summary">
202
+ <p>显示年龄 {minAge} 到 {maxAge} 岁的资料</p>
203
+ <p class="result-count">找到 {selectedProfiles.length} 个资料</p>
204
+ </div>
205
+ </div>
206
+
207
+ <div class="results-section">
208
+ <h4>匹配的资料</h4>
209
+ {#if selectedProfiles.length > 0}
210
+ <div class="profiles-grid">
211
+ {#each selectedProfiles as profile}
212
+ <div class="profile-card">
213
+ <div class="profile-name">{profile.name}</div>
214
+ <div class="profile-age">年龄: {profile.age}</div>
215
+ </div>
216
+ {/each}
217
+ </div>
218
+ {:else}
219
+ <p class="no-results">没有资料匹配所选年龄范围</p>
220
+ {/if}
221
+ </div>
222
+ </div>
223
+
224
+ <style>
225
+ .age-filter-demo {
226
+ max-width: 600px;
227
+ margin: 0 auto;
228
+ padding: 20px;
229
+ }
230
+
231
+ .filter-section {
232
+ background: #ffffff;
233
+ padding: 20px;
234
+ border-radius: 8px;
235
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
236
+ margin-bottom: 20px;
237
+ }
238
+
239
+ .filter-section h3 {
240
+ margin: 0 0 16px 0;
241
+ color: #333;
242
+ }
243
+
244
+ .age-summary {
245
+ margin-top: 12px;
246
+ padding: 12px;
247
+ background: #e3f2fd;
248
+ border-radius: 4px;
249
+ text-align: center;
250
+ }
251
+
252
+ .result-count {
253
+ font-weight: 600;
254
+ color: #1976d2;
255
+ margin: 4px 0 0 0;
256
+ }
257
+
258
+ .results-section h4 {
259
+ margin: 0 0 16px 0;
260
+ color: #333;
261
+ }
262
+
263
+ .profiles-grid {
264
+ display: grid;
265
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
266
+ gap: 12px;
267
+ }
268
+
269
+ .profile-card {
270
+ padding: 16px;
271
+ background: #f8f9fa;
272
+ border-radius: 6px;
273
+ border-left: 4px solid #007bff;
274
+ }
275
+
276
+ .profile-name {
277
+ font-weight: 500;
278
+ color: #333;
279
+ margin-bottom: 4px;
280
+ }
281
+
282
+ .profile-age {
283
+ color: #666;
284
+ font-size: 0.9rem;
285
+ }
286
+
287
+ .no-results {
288
+ text-align: center;
289
+ color: #666;
290
+ font-style: italic;
291
+ padding: 40px 20px;
292
+ }
293
+ </style>
294
+ ```
295
+
296
+ ### 库存范围查询
297
+
298
+ ```svelte
299
+ <script lang="ts">
300
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
301
+
302
+ let minQuantity: number = 0;
303
+ let maxQuantity: number = 500;
304
+
305
+ // 模拟库存数据
306
+ let inventoryItems = [
307
+ { id: 'A001', name: 'Widget Alpha', quantity: 45, category: '电子产品' },
308
+ { id: 'B002', name: 'Gadget Beta', quantity: 120, category: '工具' },
309
+ { id: 'C003', name: 'Device Gamma', quantity: 8, category: '电子产品' },
310
+ { id: 'D004', name: 'Tool Delta', quantity: 300, category: '工具' },
311
+ { id: 'E005', name: 'Part Epsilon', quantity: 750, category: '配件' }
312
+ ];
313
+
314
+ let filteredItems = [];
315
+
316
+ function applyQuantityFilter() {
317
+ filteredItems = inventoryItems.filter(item =>
318
+ item.quantity >= (minQuantity || 0) &&
319
+ item.quantity <= (maxQuantity || Infinity)
320
+ );
321
+ }
322
+
323
+ // 当范围变化时应用过滤器
324
+ $: {
325
+ minQuantity, maxQuantity;
326
+ applyQuantityFilter();
327
+ }
328
+
329
+ function exportResults() {
330
+ const csvContent = [
331
+ 'ID,名称,数量,类别',
332
+ ...filteredItems.map(item =>
333
+ `${item.id},${item.name},${item.quantity},${item.category}`
334
+ )
335
+ ].join('\n');
336
+
337
+ console.log('导出数据:', csvContent);
338
+ alert('数据已导出到控制台');
339
+ }
340
+
341
+ // 预定义范围预设
342
+ const presets = [
343
+ { label: '低库存 (0-50)', min: 0, max: 50 },
344
+ { label: '中等库存 (51-200)', min: 51, max: 200 },
345
+ { label: '高库存 (201-500)', min: 201, max: 500 },
346
+ { label: '库存过多 (500+)', min: 500, max: 1000 }
347
+ ];
348
+
349
+ function applyPreset(preset) {
350
+ minQuantity = preset.min;
351
+ maxQuantity = preset.max;
352
+ }
353
+ </script>
354
+
355
+ <div class="inventory-query">
356
+ <header class="query-header">
357
+ <h2>库存数量过滤器</h2>
358
+ <p>按数量范围过滤库存物品</p>
359
+ </header>
360
+
361
+ <div class="filter-controls">
362
+ <div class="range-input-section">
363
+ <label>数量范围:</label>
364
+ <NumberRange
365
+ bind:fromValue={minQuantity}
366
+ bind:toValue={maxQuantity}
367
+ variant="outlined"
368
+ min={0}
369
+ max={1000}
370
+ style="width: 280px;"
371
+ />
372
+ </div>
373
+
374
+ <div class="presets-section">
375
+ <label>快速预设:</label>
376
+ <div class="preset-buttons">
377
+ {#each presets as preset}
378
+ <button
379
+ class="preset-btn"
380
+ on:click={() => applyPreset(preset)}
381
+ >
382
+ {preset.label}
383
+ </button>
384
+ {/each}
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <div class="results-section">
390
+ <div class="results-header">
391
+ <h3>结果 ({filteredItems.length} 项)</h3>
392
+ {#if filteredItems.length > 0}
393
+ <button class="export-btn" on:click={exportResults}>
394
+ 导出 CSV
395
+ </button>
396
+ {/if}
397
+ </div>
398
+
399
+ <div class="results-table">
400
+ {#if filteredItems.length > 0}
401
+ <table>
402
+ <thead>
403
+ <tr>
404
+ <th>物品 ID</th>
405
+ <th>名称</th>
406
+ <th>数量</th>
407
+ <th>类别</th>
408
+ <th>状态</th>
409
+ </tr>
410
+ </thead>
411
+ <tbody>
412
+ {#each filteredItems as item}
413
+ <tr>
414
+ <td class="item-id">{item.id}</td>
415
+ <td class="item-name">{item.name}</td>
416
+ <td class="item-quantity">{item.quantity}</td>
417
+ <td class="item-category">{item.category}</td>
418
+ <td class="item-status">
419
+ <span class="status-badge status-{item.quantity < 50 ? 'low' : item.quantity < 200 ? 'medium' : 'high'}">
420
+ {item.quantity < 50 ? '低' : item.quantity < 200 ? '中' : '高'}
421
+ </span>
422
+ </td>
423
+ </tr>
424
+ {/each}
425
+ </tbody>
426
+ </table>
427
+ {:else}
428
+ <div class="no-results">
429
+ <p>在指定数量范围内未找到库存物品。</p>
430
+ <p class="suggestion">尝试调整范围或使用预设过滤器。</p>
431
+ </div>
432
+ {/if}
433
+ </div>
434
+ </div>
435
+ </div>
436
+
437
+ <style>
438
+ .inventory-query {
439
+ max-width: 900px;
440
+ margin: 0 auto;
441
+ padding: 20px;
442
+ }
443
+
444
+ .query-header {
445
+ text-align: center;
446
+ margin-bottom: 30px;
447
+ }
448
+
449
+ .query-header h2 {
450
+ color: #333;
451
+ margin: 0 0 8px 0;
452
+ }
453
+
454
+ .query-header p {
455
+ color: #666;
456
+ margin: 0;
457
+ }
458
+
459
+ .filter-controls {
460
+ display: flex;
461
+ flex-wrap: wrap;
462
+ gap: 30px;
463
+ align-items: flex-end;
464
+ margin-bottom: 30px;
465
+ padding: 20px;
466
+ background: #f8f9fa;
467
+ border-radius: 8px;
468
+ }
469
+
470
+ .range-input-section,
471
+ .presets-section {
472
+ flex: 1;
473
+ min-width: 250px;
474
+ }
475
+
476
+ .range-input-section label,
477
+ .presets-section label {
478
+ display: block;
479
+ font-weight: 500;
480
+ margin-bottom: 8px;
481
+ color: #333;
482
+ }
483
+
484
+ .preset-buttons {
485
+ display: flex;
486
+ flex-wrap: wrap;
487
+ gap: 8px;
488
+ }
489
+
490
+ .preset-btn {
491
+ padding: 6px 12px;
492
+ background: #e9ecef;
493
+ border: 1px solid #ced4da;
494
+ border-radius: 4px;
495
+ cursor: pointer;
496
+ font-size: 0.875rem;
497
+ transition: all 0.2s;
498
+ }
499
+
500
+ .preset-btn:hover {
501
+ background: #dee2e6;
502
+ border-color: #adb5bd;
503
+ }
504
+
505
+ .results-section {
506
+ background: white;
507
+ border-radius: 8px;
508
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
509
+ overflow: hidden;
510
+ }
511
+
512
+ .results-header {
513
+ display: flex;
514
+ justify-content: space-between;
515
+ align-items: center;
516
+ padding: 20px;
517
+ background: #f8f9fa;
518
+ border-bottom: 1px solid #dee2e6;
519
+ }
520
+
521
+ .results-header h3 {
522
+ margin: 0;
523
+ color: #333;
524
+ }
525
+
526
+ .export-btn {
527
+ padding: 8px 16px;
528
+ background: #007bff;
529
+ color: white;
530
+ border: none;
531
+ border-radius: 4px;
532
+ cursor: pointer;
533
+ font-size: 0.875rem;
534
+ }
535
+
536
+ .export-btn:hover {
537
+ background: #0056b3;
538
+ }
539
+
540
+ .results-table {
541
+ padding: 20px;
542
+ }
543
+
544
+ table {
545
+ width: 100%;
546
+ border-collapse: collapse;
547
+ }
548
+
549
+ th, td {
550
+ text-align: left;
551
+ padding: 12px;
552
+ border-bottom: 1px solid #dee2e6;
553
+ }
554
+
555
+ th {
556
+ font-weight: 600;
557
+ color: #333;
558
+ background: #f8f9fa;
559
+ }
560
+
561
+ .item-id {
562
+ font-family: monospace;
563
+ font-weight: 500;
564
+ }
565
+
566
+ .item-quantity {
567
+ text-align: right;
568
+ font-weight: 500;
569
+ }
570
+
571
+ .status-badge {
572
+ padding: 4px 8px;
573
+ border-radius: 12px;
574
+ font-size: 0.75rem;
575
+ font-weight: 500;
576
+ }
577
+
578
+ .status-low {
579
+ background: #ffebee;
580
+ color: #c62828;
581
+ }
582
+
583
+ .status-medium {
584
+ background: #fff3e0;
585
+ color: #ef6c00;
586
+ }
587
+
588
+ .status-high {
589
+ background: #e8f5e8;
590
+ color: #2e7d32;
591
+ }
592
+
593
+ .no-results {
594
+ text-align: center;
595
+ padding: 60px 20px;
596
+ color: #666;
597
+ }
598
+
599
+ .suggestion {
600
+ font-size: 0.9rem;
601
+ color: #888;
602
+ margin-top: 8px;
603
+ }
604
+
605
+ @media (max-width: 768px) {
606
+ .filter-controls {
607
+ flex-direction: column;
608
+ align-items: stretch;
609
+ }
610
+
611
+ .preset-buttons {
612
+ justify-content: center;
613
+ }
614
+
615
+ .results-header {
616
+ flex-direction: column;
617
+ gap: 12px;
618
+ align-items: stretch;
619
+ }
620
+
621
+ table {
622
+ font-size: 0.875rem;
623
+ }
624
+
625
+ th, td {
626
+ padding: 8px;
627
+ }
628
+ }
629
+ </style>
630
+ ```
631
+
632
+ ## 样式
633
+
634
+ NumberRange 组件使用以下 CSS 类:
635
+
636
+ ```css
637
+ .uniface-range-editor {
638
+ /* 主要范围容器 */
639
+ display: flex;
640
+ align-items: center;
641
+ gap: 8px;
642
+ }
643
+
644
+ .uniface-range-editor .range-divider {
645
+ /* 从/到输入框之间的分隔符 */
646
+ color: var(--uniface-editor-border-color, #dee2e6);
647
+ }
648
+
649
+ .uniface-range-editor .action-icon {
650
+ /* 清除按钮样式 */
651
+ cursor: pointer;
652
+ opacity: 0.6;
653
+ transition: opacity 0.2s;
654
+ }
655
+
656
+ .uniface-range-editor .action-icon:hover {
657
+ opacity: 1;
658
+ }
659
+ ```
660
+
661
+ ## API 参考
662
+
663
+ ### NumberRange 组件属性
664
+
665
+ ```typescript
666
+ interface NumberRangeProps {
667
+ variant?: '' | 'plain' | 'outlined' | 'filled'; // 视觉样式变体
668
+ compact?: boolean; // 紧凑布局模式
669
+ class?: string; // CSS 类名
670
+ style?: string; // 自定义内联样式
671
+ min?: number | null; // 全局最小值
672
+ max?: number | null; // 全局最大值
673
+ fromValue: number; // 范围起始值
674
+ toValue: number; // 范围结束值
675
+ allowNegative?: boolean; // 允许负数
676
+ }
677
+ ```
678
+
679
+ ## 最佳实践
680
+
681
+ 1. **验证** - 始终绑定 `fromValue` 和 `toValue` 以实现正确的范围验证
682
+ 2. **限制** - 设置适当的 `min` 和 `max` 值以引导用户输入
683
+ 3. **用户反馈** - 提供所选范围值的清晰指示
684
+ 4. **可访问性** - 确保足够的颜色对比度和键盘导航
685
+ 5. **移动支持** - 在触摸设备上测试输入行为
686
+ 6. **数据类型** - 在响应式语句中优雅处理 undefined/null 值
687
+ 7. **性能** - 对大数据集的过滤操作进行防抖处理
688
+ 8. **清除功能** - 依赖内置清除按钮以保持一致的用户体验