@ticatec/uniface-element 0.2.0 → 0.2.2

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 (209) hide show
  1. package/README.md +320 -1
  2. package/README_CN.md +392 -0
  3. package/dist/accordion/Accordion.svelte +1 -1
  4. package/dist/action-bar/ActionBar.svelte +7 -1
  5. package/dist/attachment-files/FileRender.svelte +1 -1
  6. package/dist/attachment-files/FileUploadBar.svelte +7 -6
  7. package/dist/attachment-files/FileUploadPanel.svelte +2 -2
  8. package/dist/base-calendar/DateContext.js +5 -4
  9. package/dist/base-calendar/YearPickupPanel.svelte +4 -4
  10. package/dist/card/Card.svelte +1 -1
  11. package/dist/card/Card.svelte.d.ts +1 -1
  12. package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
  13. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
  14. package/dist/cascade-options-select/CascadePanel.svelte +1 -1
  15. package/dist/checkbox/CheckBox.svelte +1 -1
  16. package/dist/color-picker/ColorPicker.svelte +9 -9
  17. package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
  18. package/dist/color-picker/ColorPickerPanel.svelte +11 -15
  19. package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
  20. package/dist/common/CommonPicker.svelte +2 -2
  21. package/dist/common/CommonPicker.svelte.d.ts +1 -1
  22. package/dist/common/MouseClickHandler.d.ts +1 -1
  23. package/dist/common/Popover.svelte +28 -6
  24. package/dist/common/Popover.svelte.d.ts +9 -3
  25. package/dist/common/uniface-utils.js +6 -4
  26. package/dist/common-editor/CommonEditor.svelte +1 -1
  27. package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
  28. package/dist/common-editor/NumberInput.svelte +1 -1
  29. package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
  30. package/dist/concise-data-table/ConciseListTable.svelte +7 -2
  31. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
  32. package/dist/concise-data-table/DataRow.svelte +1 -1
  33. package/dist/concise-data-table/TableOptions.d.ts +1 -1
  34. package/dist/data-table/DataTable.svelte +1 -1
  35. package/dist/data-table/parts/ActionsPanel.svelte +4 -3
  36. package/dist/data-table/parts/ActionsRow.svelte +3 -3
  37. package/dist/data-table/parts/ContentPanel.svelte +3 -2
  38. package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
  39. package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
  40. package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
  41. package/dist/data-table/parts/FixedRow.svelte +2 -1
  42. package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
  43. package/dist/data-table/parts/HrefCell.svelte +23 -2
  44. package/dist/data-table/parts/PopupMenu.svelte +25 -2
  45. package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
  46. package/dist/date-picker/DatePicker.svelte +0 -1
  47. package/dist/date-picker/DateTimePicker.svelte +3 -3
  48. package/dist/date-picker/ScrollBar.svelte +4 -7
  49. package/dist/date-range/DateRangeEditor.svelte +1 -1
  50. package/dist/dialog/CommonDialog.svelte +8 -5
  51. package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
  52. package/dist/dialog/Dialog.svelte +37 -12
  53. package/dist/dialog/Dialog.svelte.d.ts +4 -3
  54. package/dist/dialog/DialogBoard.svelte +11 -8
  55. package/dist/dialog/DialogWrapper.svelte +10 -0
  56. package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
  57. package/dist/dialog/Dialogs.js +1 -1
  58. package/dist/dialog/ModalResult.d.ts +5 -0
  59. package/dist/dialog/ModalResult.js +5 -0
  60. package/dist/drawer/Drawer.svelte +1 -1
  61. package/dist/form-field/FormField.svelte +2 -1
  62. package/dist/form-field/FormField.svelte.d.ts +1 -0
  63. package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
  64. package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
  65. package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
  66. package/dist/form-panel/grid-form/GridField.svelte +1 -1
  67. package/dist/i18nRes/i18nRes.d.ts +2 -0
  68. package/dist/i18nRes/i18nRes.js +44 -0
  69. package/dist/i18nRes/index.d.ts +2 -0
  70. package/dist/i18nRes/index.js +2 -0
  71. package/dist/image-files/ImageFilesField.svelte +1 -1
  72. package/dist/indicator/IndicatorBoard.svelte +1 -1
  73. package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
  74. package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
  75. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
  76. package/dist/layout/flex/FlexBlock.svelte +1 -1
  77. package/dist/lookup-editor/LookupEditor.svelte +1 -1
  78. package/dist/memo-editor/MemoEditor.svelte +2 -2
  79. package/dist/message-box/IMessageBox.d.ts +2 -4
  80. package/dist/message-box/IMessageBox.js +4 -6
  81. package/dist/message-box/MessageBoxBoard.svelte +1 -3
  82. package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
  83. package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
  84. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
  85. package/dist/property-editor/PropertyEditor.svelte +3 -3
  86. package/dist/text-editor/PasswordEditor.svelte +1 -1
  87. package/dist/transfer/Transfer.svelte +17 -12
  88. package/dist/transfer/Transfer.svelte.d.ts +0 -1
  89. package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
  90. package/docs/buttons/cn/ActionBar.md +459 -0
  91. package/docs/buttons/cn/Button.md +228 -0
  92. package/docs/buttons/cn/IconButton.md +294 -0
  93. package/docs/buttons/cn/README.md +600 -0
  94. package/docs/buttons/cn/TextButton.md +163 -0
  95. package/docs/buttons/en/ActionBar.md +459 -0
  96. package/docs/buttons/en/Button.md +228 -0
  97. package/docs/buttons/en/IconButton.md +294 -0
  98. package/docs/buttons/en/README.md +600 -0
  99. package/docs/buttons/en/TextButton.md +163 -0
  100. package/docs/containers/cn/accordion.md +622 -0
  101. package/docs/containers/cn/box.md +445 -0
  102. package/docs/containers/cn/card.md +404 -0
  103. package/docs/containers/cn/page.md +576 -0
  104. package/docs/containers/cn/tabs.md +686 -0
  105. package/docs/containers/en/accordion.md +622 -0
  106. package/docs/containers/en/box.md +445 -0
  107. package/docs/containers/en/card.md +404 -0
  108. package/docs/containers/en/page.md +576 -0
  109. package/docs/containers/en/tabs.md +686 -0
  110. package/docs/data-display/cn/concise-data-table.md +731 -0
  111. package/docs/data-display/cn/listbox.md +786 -0
  112. package/docs/data-display/cn/treeview.md +863 -0
  113. package/docs/data-display/en/concise-data-table.md +732 -0
  114. package/docs/data-display/en/listbox.md +786 -0
  115. package/docs/data-display/en/treeview.md +863 -0
  116. package/docs/data-table/cn/README.md +596 -0
  117. package/docs/data-table/en/README.md +596 -0
  118. package/docs/dialog/cn/README.md +767 -0
  119. package/docs/dialog/en/README.md +767 -0
  120. package/docs/form/cn/README.md +847 -0
  121. package/docs/form/en/README.md +847 -0
  122. package/docs/form-components/cn/README.md +495 -0
  123. package/docs/form-components/cn/attachmentfilesfield.md +757 -0
  124. package/docs/form-components/cn/cascade-options-select.md +374 -0
  125. package/docs/form-components/cn/checkbox.md +58 -0
  126. package/docs/form-components/cn/date-picker.md +138 -0
  127. package/docs/form-components/cn/datetime-picker.md +228 -0
  128. package/docs/form-components/cn/group-checkbox.md +405 -0
  129. package/docs/form-components/cn/group-radiobox.md +525 -0
  130. package/docs/form-components/cn/imagefilesfield.md +651 -0
  131. package/docs/form-components/cn/input-options-select.md +250 -0
  132. package/docs/form-components/cn/lookup-editor.md +406 -0
  133. package/docs/form-components/cn/memoeditor.md +409 -0
  134. package/docs/form-components/cn/number-editor.md +261 -0
  135. package/docs/form-components/cn/options-multi-select.md +177 -0
  136. package/docs/form-components/cn/options-select.md +83 -0
  137. package/docs/form-components/cn/passwordeditor.md +538 -0
  138. package/docs/form-components/cn/prompts-text-editor.md +241 -0
  139. package/docs/form-components/cn/radiobutton.md +84 -0
  140. package/docs/form-components/cn/switch.md +178 -0
  141. package/docs/form-components/cn/text-editor.md +142 -0
  142. package/docs/form-components/cn/time-editor.md +159 -0
  143. package/docs/form-components/cn/unit-number-editor.md +164 -0
  144. package/docs/form-components/en/README.md +463 -0
  145. package/docs/form-components/en/attachmentfilesfield.md +757 -0
  146. package/docs/form-components/en/cascade-options-select.md +358 -0
  147. package/docs/form-components/en/checkbox.md +59 -0
  148. package/docs/form-components/en/date-picker.md +138 -0
  149. package/docs/form-components/en/datetime-picker.md +228 -0
  150. package/docs/form-components/en/group-checkbox.md +395 -0
  151. package/docs/form-components/en/group-radiobox.md +498 -0
  152. package/docs/form-components/en/imagefilesfield.md +651 -0
  153. package/docs/form-components/en/input-options-select.md +239 -0
  154. package/docs/form-components/en/lookup-editor.md +389 -0
  155. package/docs/form-components/en/memoeditor.md +409 -0
  156. package/docs/form-components/en/number-editor.md +249 -0
  157. package/docs/form-components/en/options-multi-select.md +177 -0
  158. package/docs/form-components/en/options-select.md +83 -0
  159. package/docs/form-components/en/passwordeditor.md +538 -0
  160. package/docs/form-components/en/prompts-text-editor.md +241 -0
  161. package/docs/form-components/en/radiobutton.md +84 -0
  162. package/docs/form-components/en/switch.md +180 -0
  163. package/docs/form-components/en/text-editor.md +142 -0
  164. package/docs/form-components/en/time-editor.md +159 -0
  165. package/docs/form-components/en/unit-number-editor.md +164 -0
  166. package/docs/form-layout/cn/criteria-field.md +652 -0
  167. package/docs/form-layout/cn/flex-form.md +454 -0
  168. package/docs/form-layout/cn/flex-row-form.md +542 -0
  169. package/docs/form-layout/cn/form-field.md +923 -0
  170. package/docs/form-layout/cn/grid-form.md +676 -0
  171. package/docs/form-layout/en/criteria-field.md +652 -0
  172. package/docs/form-layout/en/flex-form.md +454 -0
  173. package/docs/form-layout/en/flex-row-form.md +542 -0
  174. package/docs/form-layout/en/form-field.md +923 -0
  175. package/docs/form-layout/en/grid-form.md +676 -0
  176. package/docs/global/cn/README.md +534 -0
  177. package/docs/global/en/README.md +534 -0
  178. package/docs/layout/cn/classiclayout.md +460 -0
  179. package/docs/layout/cn/headerlayout.md +524 -0
  180. package/docs/layout/cn/sidebarlayout.md +263 -0
  181. package/docs/layout/en/classiclayout.md +951 -0
  182. package/docs/layout/en/headerlayout.md +524 -0
  183. package/docs/layout/en/sidebarlayout.md +262 -0
  184. package/docs/misc/cn/README.md +1217 -0
  185. package/docs/misc/en/README.md +1217 -0
  186. package/docs/navigation/cn/breadcrumb.md +291 -0
  187. package/docs/navigation/cn/navigator.md +322 -0
  188. package/docs/navigation/cn/navigatormenu.md +512 -0
  189. package/docs/navigation/cn/progressbar.md +199 -0
  190. package/docs/navigation/cn/progressstepbar.md +299 -0
  191. package/docs/navigation/en/breadcrumb.md +291 -0
  192. package/docs/navigation/en/navigator.md +322 -0
  193. package/docs/navigation/en/navigatormenu.md +512 -0
  194. package/docs/navigation/en/progressbar.md +199 -0
  195. package/docs/navigation/en/progressstepbar.md +299 -0
  196. package/docs/search-filters/cn/daterange.md +1156 -0
  197. package/docs/search-filters/cn/numberrange.md +688 -0
  198. package/docs/search-filters/cn/searchbox.md +1582 -0
  199. package/docs/search-filters/en/daterange.md +1156 -0
  200. package/docs/search-filters/en/numberrange.md +688 -0
  201. package/docs/search-filters/en/searchbox.md +1582 -0
  202. package/package.json +53 -13
  203. package/dist/common-editor/DateInput.svelte +0 -27
  204. package/dist/i18n_resources/index.d.ts +0 -3
  205. package/dist/i18n_resources/index.js +0 -3
  206. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
  207. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
  208. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
  209. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
@@ -0,0 +1,1156 @@
1
+ # DateRange 日期范围组件
2
+
3
+ 一个日期范围选择器组件,允许用户通过直观的双日历界面选择起始和结束日期,通常用于按日期周期过滤数据,如报告范围、预订周期或事件计划。
4
+
5
+ ## 概述
6
+
7
+ DateRange 组件通过双日历显示、灵活的日期格式化和强大的验证功能提供全面的日期选择体验。它具有只读输入字段,打开带有并排日历的弹出框,便于范围选择。该组件支持各种日期格式、最小/最大日期约束,并与表单验证系统无缝集成。
8
+
9
+ ## 安装
10
+
11
+ ```typescript
12
+ import DateRange from '@ticatec/uniface-element/DateRange';
13
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
14
+ ```
15
+
16
+ ## 基本用法
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import DateRange from '@ticatec/uniface-element/DateRange';
21
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
22
+
23
+ let fromDate: UniDate = null;
24
+ let toDate: UniDate = null;
25
+ </script>
26
+
27
+ <DateRange
28
+ bind:fromValue={fromDate}
29
+ bind:toValue={toDate}
30
+ variant="outlined"
31
+ />
32
+ ```
33
+
34
+ ## 属性
35
+
36
+ | 属性 | 类型 | 默认值 | 描述 |
37
+ |------|------|--------|------|
38
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉样式变体 |
39
+ | `compact` | `boolean` | `false` | 启用紧凑布局以适应密集表单 |
40
+ | `class` | `string` | `''` | 额外的 CSS 类名 |
41
+ | `style` | `string` | `''` | 自定义内联样式 |
42
+ | `fromValue` | `UniDate` | `null` | 起始日期(可绑定) |
43
+ | `toValue` | `UniDate` | `null` | 结束日期(可绑定) |
44
+ | `format` | `string` | `"YYYY-MM-DD"` | 日期显示格式(dayjs 格式) |
45
+ | `min` | `string \| Date \| null` | `null` | 最小可选日期 |
46
+ | `max` | `string \| Date \| null` | `null` | 最大可选日期 |
47
+
48
+ ## 类型定义
49
+
50
+ ```typescript
51
+ /**
52
+ * 支持多种格式的灵活日期类型
53
+ */
54
+ type UniDate = dayjs.Dayjs | Date | string | null;
55
+ ```
56
+
57
+ ## 功能特性
58
+
59
+ - **双日历界面**:并排日历视图用于直观的范围选择
60
+ - **灵活的日期类型**:支持 Date 对象、字符串和 dayjs 实例
61
+ - **自定义格式化**:使用 dayjs 模式的可配置日期显示格式
62
+ - **范围验证**:自动验证确保起始日期 ≤ 结束日期
63
+ - **最小/最大约束**:可选的日期边界来限制选择
64
+ - **弹出日历**:带集成日期选择器的清洁日历弹出框
65
+ - **清除功能**:选择日期时的内置清除操作
66
+ - **只读输入**:防止手动输入以保持一致的日期格式
67
+
68
+ ## 使用示例
69
+
70
+ ### 报告日期范围选择器
71
+
72
+ ```svelte
73
+ <script lang="ts">
74
+ import DateRange from '@ticatec/uniface-element/DateRange';
75
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
76
+ import dayjs from 'dayjs';
77
+
78
+ let reportFrom: UniDate = dayjs().subtract(30, 'day');
79
+ let reportTo: UniDate = dayjs();
80
+
81
+ // 演示用销售数据
82
+ let salesData = [
83
+ { date: '2024-03-01', sales: 12500, orders: 45 },
84
+ { date: '2024-03-02', sales: 8900, orders: 32 },
85
+ { date: '2024-03-03', sales: 15600, orders: 58 },
86
+ { date: '2024-03-04', sales: 11200, orders: 41 },
87
+ { date: '2024-03-05', sales: 9800, orders: 35 }
88
+ ];
89
+
90
+ let filteredData = [];
91
+ let totalSales = 0;
92
+ let totalOrders = 0;
93
+
94
+ // 基于选定日期范围过滤数据
95
+ function filterSalesData() {
96
+ if (!reportFrom || !reportTo) {
97
+ filteredData = salesData;
98
+ } else {
99
+ const fromDate = dayjs(reportFrom);
100
+ const toDate = dayjs(reportTo);
101
+
102
+ filteredData = salesData.filter(item => {
103
+ const itemDate = dayjs(item.date);
104
+ return itemDate.isBetween(fromDate, toDate, 'day', '[]');
105
+ });
106
+ }
107
+
108
+ // 计算总计
109
+ totalSales = filteredData.reduce((sum, item) => sum + item.sales, 0);
110
+ totalOrders = filteredData.reduce((sum, item) => sum + item.orders, 0);
111
+ }
112
+
113
+ // 响应式过滤
114
+ $: {
115
+ reportFrom, reportTo;
116
+ filterSalesData();
117
+ }
118
+
119
+ // 快速日期范围预设
120
+ function setDateRange(days: number) {
121
+ reportFrom = dayjs().subtract(days, 'day');
122
+ reportTo = dayjs();
123
+ }
124
+
125
+ function setThisMonth() {
126
+ reportFrom = dayjs().startOf('month');
127
+ reportTo = dayjs().endOf('month');
128
+ }
129
+
130
+ function setLastMonth() {
131
+ reportFrom = dayjs().subtract(1, 'month').startOf('month');
132
+ reportTo = dayjs().subtract(1, 'month').endOf('month');
133
+ }
134
+ </script>
135
+
136
+ <div class="sales-report">
137
+ <header class="report-header">
138
+ <h2>销售报告仪表板</h2>
139
+ <p>选择日期范围以查看销售分析</p>
140
+ </header>
141
+
142
+ <div class="date-controls">
143
+ <div class="date-range-section">
144
+ <label>报告周期:</label>
145
+ <DateRange
146
+ bind:fromValue={reportFrom}
147
+ bind:toValue={reportTo}
148
+ variant="outlined"
149
+ format="YYYY年MM月DD日"
150
+ style="width: 320px;"
151
+ />
152
+ </div>
153
+
154
+ <div class="quick-presets">
155
+ <label>快速预设:</label>
156
+ <div class="preset-buttons">
157
+ <button class="preset-btn" on:click={() => setDateRange(7)}>最近7天</button>
158
+ <button class="preset-btn" on:click={() => setDateRange(30)}>最近30天</button>
159
+ <button class="preset-btn" on:click={setThisMonth}>本月</button>
160
+ <button class="preset-btn" on:click={setLastMonth}>上月</button>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="report-summary">
166
+ <div class="summary-card">
167
+ <h3>总销售额</h3>
168
+ <div class="metric-value">¥{totalSales.toLocaleString()}</div>
169
+ </div>
170
+ <div class="summary-card">
171
+ <h3>总订单数</h3>
172
+ <div class="metric-value">{totalOrders}</div>
173
+ </div>
174
+ <div class="summary-card">
175
+ <h3>平均订单</h3>
176
+ <div class="metric-value">
177
+ ¥{totalOrders > 0 ? (totalSales / totalOrders).toFixed(2) : '0.00'}
178
+ </div>
179
+ </div>
180
+ </div>
181
+
182
+ <div class="data-table">
183
+ <h3>每日明细 ({filteredData.length} 天)</h3>
184
+ {#if filteredData.length > 0}
185
+ <table>
186
+ <thead>
187
+ <tr>
188
+ <th>日期</th>
189
+ <th>销售额</th>
190
+ <th>订单数</th>
191
+ <th>平均订单</th>
192
+ </tr>
193
+ </thead>
194
+ <tbody>
195
+ {#each filteredData as item}
196
+ <tr>
197
+ <td>{dayjs(item.date).format('YYYY年MM月DD日')}</td>
198
+ <td>¥{item.sales.toLocaleString()}</td>
199
+ <td>{item.orders}</td>
200
+ <td>¥{(item.sales / item.orders).toFixed(2)}</td>
201
+ </tr>
202
+ {/each}
203
+ </tbody>
204
+ </table>
205
+ {:else}
206
+ <div class="no-data">
207
+ <p>所选日期范围内没有销售数据。</p>
208
+ </div>
209
+ {/if}
210
+ </div>
211
+ </div>
212
+
213
+ <style>
214
+ .sales-report {
215
+ max-width: 900px;
216
+ margin: 0 auto;
217
+ padding: 20px;
218
+ }
219
+
220
+ .report-header {
221
+ text-align: center;
222
+ margin-bottom: 30px;
223
+ }
224
+
225
+ .report-header h2 {
226
+ color: #333;
227
+ margin: 0 0 8px 0;
228
+ }
229
+
230
+ .report-header p {
231
+ color: #666;
232
+ margin: 0;
233
+ }
234
+
235
+ .date-controls {
236
+ display: flex;
237
+ flex-wrap: wrap;
238
+ gap: 30px;
239
+ align-items: flex-end;
240
+ margin-bottom: 30px;
241
+ padding: 20px;
242
+ background: #f8f9fa;
243
+ border-radius: 8px;
244
+ }
245
+
246
+ .date-range-section,
247
+ .quick-presets {
248
+ flex: 1;
249
+ min-width: 280px;
250
+ }
251
+
252
+ .date-range-section label,
253
+ .quick-presets label {
254
+ display: block;
255
+ font-weight: 500;
256
+ margin-bottom: 8px;
257
+ color: #333;
258
+ }
259
+
260
+ .preset-buttons {
261
+ display: flex;
262
+ flex-wrap: wrap;
263
+ gap: 8px;
264
+ }
265
+
266
+ .preset-btn {
267
+ padding: 6px 12px;
268
+ background: #e9ecef;
269
+ border: 1px solid #ced4da;
270
+ border-radius: 4px;
271
+ cursor: pointer;
272
+ font-size: 0.875rem;
273
+ transition: all 0.2s;
274
+ }
275
+
276
+ .preset-btn:hover {
277
+ background: #007bff;
278
+ color: white;
279
+ border-color: #007bff;
280
+ }
281
+
282
+ .report-summary {
283
+ display: grid;
284
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
285
+ gap: 20px;
286
+ margin-bottom: 30px;
287
+ }
288
+
289
+ .summary-card {
290
+ background: white;
291
+ padding: 20px;
292
+ border-radius: 8px;
293
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
294
+ text-align: center;
295
+ }
296
+
297
+ .summary-card h3 {
298
+ margin: 0 0 12px 0;
299
+ color: #666;
300
+ font-size: 0.9rem;
301
+ text-transform: uppercase;
302
+ letter-spacing: 0.5px;
303
+ }
304
+
305
+ .metric-value {
306
+ font-size: 2rem;
307
+ font-weight: 700;
308
+ color: #007bff;
309
+ }
310
+
311
+ .data-table {
312
+ background: white;
313
+ border-radius: 8px;
314
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
315
+ overflow: hidden;
316
+ }
317
+
318
+ .data-table h3 {
319
+ margin: 0;
320
+ padding: 20px;
321
+ background: #f8f9fa;
322
+ border-bottom: 1px solid #dee2e6;
323
+ color: #333;
324
+ }
325
+
326
+ table {
327
+ width: 100%;
328
+ border-collapse: collapse;
329
+ }
330
+
331
+ th, td {
332
+ text-align: left;
333
+ padding: 12px 20px;
334
+ border-bottom: 1px solid #dee2e6;
335
+ }
336
+
337
+ th {
338
+ font-weight: 600;
339
+ color: #333;
340
+ background: #f8f9fa;
341
+ }
342
+
343
+ .no-data {
344
+ padding: 60px 20px;
345
+ text-align: center;
346
+ color: #666;
347
+ }
348
+
349
+ @media (max-width: 768px) {
350
+ .date-controls {
351
+ flex-direction: column;
352
+ align-items: stretch;
353
+ }
354
+
355
+ .preset-buttons {
356
+ justify-content: center;
357
+ }
358
+
359
+ .report-summary {
360
+ grid-template-columns: 1fr;
361
+ }
362
+
363
+ table {
364
+ font-size: 0.875rem;
365
+ }
366
+ }
367
+ </style>
368
+ ```
369
+
370
+ ### 活动预订日期范围
371
+
372
+ ```svelte
373
+ <script lang="ts">
374
+ import DateRange from '@ticatec/uniface-element/DateRange';
375
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
376
+ import dayjs from 'dayjs';
377
+
378
+ let checkInDate: UniDate = null;
379
+ let checkOutDate: UniDate = null;
380
+
381
+ // 酒店预订数据
382
+ let availableRooms = [
383
+ { id: 1, type: '标准房', price: 120, available: true },
384
+ { id: 2, type: '豪华房', price: 180, available: true },
385
+ { id: 3, type: '套房', price: 320, available: false },
386
+ { id: 4, type: '行政房', price: 220, available: true }
387
+ ];
388
+
389
+ let selectedRoom = null;
390
+ let totalNights = 0;
391
+ let totalCost = 0;
392
+
393
+ // 计算住宿时长和费用
394
+ function calculateStay() {
395
+ if (checkInDate && checkOutDate) {
396
+ const checkin = dayjs(checkInDate);
397
+ const checkout = dayjs(checkOutDate);
398
+ totalNights = checkout.diff(checkin, 'day');
399
+
400
+ if (selectedRoom) {
401
+ totalCost = totalNights * selectedRoom.price;
402
+ }
403
+ } else {
404
+ totalNights = 0;
405
+ totalCost = 0;
406
+ }
407
+ }
408
+
409
+ // 响应式计算
410
+ $: {
411
+ checkInDate, checkOutDate, selectedRoom;
412
+ calculateStay();
413
+ }
414
+
415
+ function selectRoom(room) {
416
+ selectedRoom = room;
417
+ }
418
+
419
+ function bookRoom() {
420
+ if (selectedRoom && checkInDate && checkOutDate) {
421
+ alert(`预订确认!\n房型:${selectedRoom.type}\n入住:${dayjs(checkInDate).format('YYYY年MM月DD日')}\n退房:${dayjs(checkOutDate).format('YYYY年MM月DD日')}\n总计:¥${totalCost}`);
422
+ }
423
+ }
424
+ </script>
425
+
426
+ <div class="booking-system">
427
+ <header class="booking-header">
428
+ <h2>酒店客房预订</h2>
429
+ <p>选择您的住宿日期并选择房间</p>
430
+ </header>
431
+
432
+ <div class="booking-form">
433
+ <div class="date-selection">
434
+ <h3>选择您的住宿日期</h3>
435
+ <DateRange
436
+ bind:fromValue={checkInDate}
437
+ bind:toValue={checkOutDate}
438
+ variant="outlined"
439
+ format="YYYY年MM月DD日"
440
+ min={dayjs().format('YYYY-MM-DD')}
441
+ max={dayjs().add(1, 'year').format('YYYY-MM-DD')}
442
+ style="width: 350px;"
443
+ />
444
+
445
+ {#if totalNights > 0}
446
+ <div class="stay-info">
447
+ <p><strong>{totalNights}</strong> 晚住宿</p>
448
+ <p>入住:{dayjs(checkInDate).format('YYYY年MM月DD日 dddd')}</p>
449
+ <p>退房:{dayjs(checkOutDate).format('YYYY年MM月DD日 dddd')}</p>
450
+ </div>
451
+ {/if}
452
+ </div>
453
+
454
+ {#if checkInDate && checkOutDate && totalNights > 0}
455
+ <div class="room-selection">
456
+ <h3>可用房间</h3>
457
+ <div class="rooms-grid">
458
+ {#each availableRooms as room}
459
+ <div
460
+ class="room-card"
461
+ class:selected={selectedRoom?.id === room.id}
462
+ class:unavailable={!room.available}
463
+ on:click={() => room.available && selectRoom(room)}
464
+ >
465
+ <div class="room-type">{room.type}</div>
466
+ <div class="room-price">¥{room.price}/晚</div>
467
+ <div class="room-total">
468
+ {#if room.available}
469
+ 总计:¥{room.price * totalNights}({totalNights}晚)
470
+ {:else}
471
+ <span class="unavailable-text">暂不可用</span>
472
+ {/if}
473
+ </div>
474
+ {#if selectedRoom?.id === room.id}
475
+ <div class="selected-indicator">✓ 已选择</div>
476
+ {/if}
477
+ </div>
478
+ {/each}
479
+ </div>
480
+ </div>
481
+
482
+ {#if selectedRoom}
483
+ <div class="booking-summary">
484
+ <h3>预订摘要</h3>
485
+ <div class="summary-details">
486
+ <div class="detail-row">
487
+ <span>房型:</span>
488
+ <span>{selectedRoom.type}</span>
489
+ </div>
490
+ <div class="detail-row">
491
+ <span>入住日期:</span>
492
+ <span>{dayjs(checkInDate).format('YYYY年MM月DD日')}</span>
493
+ </div>
494
+ <div class="detail-row">
495
+ <span>退房日期:</span>
496
+ <span>{dayjs(checkOutDate).format('YYYY年MM月DD日')}</span>
497
+ </div>
498
+ <div class="detail-row">
499
+ <span>住宿晚数:</span>
500
+ <span>{totalNights}</span>
501
+ </div>
502
+ <div class="detail-row">
503
+ <span>每晚价格:</span>
504
+ <span>¥{selectedRoom.price}</span>
505
+ </div>
506
+ <div class="detail-row total">
507
+ <span>总费用:</span>
508
+ <span>¥{totalCost}</span>
509
+ </div>
510
+ </div>
511
+
512
+ <button class="book-btn" on:click={bookRoom}>
513
+ 预订房间 - ¥{totalCost}
514
+ </button>
515
+ </div>
516
+ {/if}
517
+ {/if}
518
+ </div>
519
+ </div>
520
+
521
+ <style>
522
+ .booking-system {
523
+ max-width: 800px;
524
+ margin: 0 auto;
525
+ padding: 20px;
526
+ }
527
+
528
+ .booking-header {
529
+ text-align: center;
530
+ margin-bottom: 30px;
531
+ }
532
+
533
+ .booking-header h2 {
534
+ color: #333;
535
+ margin: 0 0 8px 0;
536
+ }
537
+
538
+ .booking-header p {
539
+ color: #666;
540
+ margin: 0;
541
+ }
542
+
543
+ .booking-form {
544
+ display: flex;
545
+ flex-direction: column;
546
+ gap: 30px;
547
+ }
548
+
549
+ .date-selection {
550
+ background: white;
551
+ padding: 25px;
552
+ border-radius: 8px;
553
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
554
+ }
555
+
556
+ .date-selection h3 {
557
+ margin: 0 0 20px 0;
558
+ color: #333;
559
+ }
560
+
561
+ .stay-info {
562
+ margin-top: 20px;
563
+ padding: 16px;
564
+ background: #e3f2fd;
565
+ border-radius: 6px;
566
+ }
567
+
568
+ .stay-info p {
569
+ margin: 4px 0;
570
+ color: #1976d2;
571
+ }
572
+
573
+ .room-selection {
574
+ background: white;
575
+ padding: 25px;
576
+ border-radius: 8px;
577
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
578
+ }
579
+
580
+ .room-selection h3 {
581
+ margin: 0 0 20px 0;
582
+ color: #333;
583
+ }
584
+
585
+ .rooms-grid {
586
+ display: grid;
587
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
588
+ gap: 16px;
589
+ }
590
+
591
+ .room-card {
592
+ padding: 20px;
593
+ border: 2px solid #e9ecef;
594
+ border-radius: 8px;
595
+ cursor: pointer;
596
+ transition: all 0.2s;
597
+ position: relative;
598
+ }
599
+
600
+ .room-card:hover:not(.unavailable) {
601
+ border-color: #007bff;
602
+ transform: translateY(-2px);
603
+ box-shadow: 0 4px 8px rgba(0,123,255,0.15);
604
+ }
605
+
606
+ .room-card.selected {
607
+ border-color: #007bff;
608
+ background: #f0f8ff;
609
+ }
610
+
611
+ .room-card.unavailable {
612
+ opacity: 0.5;
613
+ cursor: not-allowed;
614
+ background: #f8f9fa;
615
+ }
616
+
617
+ .room-type {
618
+ font-size: 1.2rem;
619
+ font-weight: 600;
620
+ color: #333;
621
+ margin-bottom: 8px;
622
+ }
623
+
624
+ .room-price {
625
+ font-size: 1.1rem;
626
+ font-weight: 500;
627
+ color: #007bff;
628
+ margin-bottom: 8px;
629
+ }
630
+
631
+ .room-total {
632
+ font-size: 0.9rem;
633
+ color: #666;
634
+ }
635
+
636
+ .unavailable-text {
637
+ color: #dc3545;
638
+ font-weight: 500;
639
+ }
640
+
641
+ .selected-indicator {
642
+ position: absolute;
643
+ top: 10px;
644
+ right: 10px;
645
+ background: #28a745;
646
+ color: white;
647
+ padding: 4px 8px;
648
+ border-radius: 4px;
649
+ font-size: 0.75rem;
650
+ font-weight: 500;
651
+ }
652
+
653
+ .booking-summary {
654
+ background: white;
655
+ padding: 25px;
656
+ border-radius: 8px;
657
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
658
+ }
659
+
660
+ .booking-summary h3 {
661
+ margin: 0 0 20px 0;
662
+ color: #333;
663
+ }
664
+
665
+ .summary-details {
666
+ margin-bottom: 20px;
667
+ }
668
+
669
+ .detail-row {
670
+ display: flex;
671
+ justify-content: space-between;
672
+ padding: 8px 0;
673
+ border-bottom: 1px solid #f0f0f0;
674
+ }
675
+
676
+ .detail-row.total {
677
+ font-weight: 600;
678
+ font-size: 1.1rem;
679
+ color: #333;
680
+ border-bottom: 2px solid #007bff;
681
+ margin-top: 10px;
682
+ }
683
+
684
+ .book-btn {
685
+ width: 100%;
686
+ padding: 12px 24px;
687
+ background: #28a745;
688
+ color: white;
689
+ border: none;
690
+ border-radius: 6px;
691
+ font-size: 1.1rem;
692
+ font-weight: 600;
693
+ cursor: pointer;
694
+ transition: background-color 0.2s;
695
+ }
696
+
697
+ .book-btn:hover {
698
+ background: #218838;
699
+ }
700
+
701
+ @media (max-width: 768px) {
702
+ .rooms-grid {
703
+ grid-template-columns: 1fr;
704
+ }
705
+
706
+ .detail-row {
707
+ font-size: 0.9rem;
708
+ }
709
+ }
710
+ </style>
711
+ ```
712
+
713
+ ### 高级搜索过滤器
714
+
715
+ ```svelte
716
+ <script lang="ts">
717
+ import DateRange from '@ticatec/uniface-element/DateRange';
718
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
719
+ import dayjs from 'dayjs';
720
+
721
+ // 搜索条件
722
+ let createdFrom: UniDate = null;
723
+ let createdTo: UniDate = null;
724
+ let modifiedFrom: UniDate = null;
725
+ let modifiedTo: UniDate = null;
726
+
727
+ // 模拟文档数据
728
+ let allDocuments = [
729
+ { id: 1, title: '项目提案', type: '文档', created: '2024-02-15', modified: '2024-03-01', status: '草稿' },
730
+ { id: 2, title: '预算报告', type: '电子表格', created: '2024-02-20', modified: '2024-02-28', status: '最终版' },
731
+ { id: 3, title: '会议纪要', type: '文档', created: '2024-03-01', modified: '2024-03-05', status: '草稿' },
732
+ { id: 4, title: '合同模板', type: '模板', created: '2024-01-10', modified: '2024-02-15', status: '最终版' },
733
+ { id: 5, title: '营销计划', type: '演示文稿', created: '2024-03-05', modified: '2024-03-10', status: '审核中' }
734
+ ];
735
+
736
+ let filteredDocuments = [];
737
+
738
+ // 基于日期范围过滤文档
739
+ function filterDocuments() {
740
+ filteredDocuments = allDocuments.filter(doc => {
741
+ let matchesCreated = true;
742
+ let matchesModified = true;
743
+
744
+ // 检查创建日期范围
745
+ if (createdFrom || createdTo) {
746
+ const createdDate = dayjs(doc.created);
747
+ if (createdFrom && createdDate.isBefore(dayjs(createdFrom))) {
748
+ matchesCreated = false;
749
+ }
750
+ if (createdTo && createdDate.isAfter(dayjs(createdTo))) {
751
+ matchesCreated = false;
752
+ }
753
+ }
754
+
755
+ // 检查修改日期范围
756
+ if (modifiedFrom || modifiedTo) {
757
+ const modifiedDate = dayjs(doc.modified);
758
+ if (modifiedFrom && modifiedDate.isBefore(dayjs(modifiedFrom))) {
759
+ matchesModified = false;
760
+ }
761
+ if (modifiedTo && modifiedDate.isAfter(dayjs(modifiedTo))) {
762
+ matchesModified = false;
763
+ }
764
+ }
765
+
766
+ return matchesCreated && matchesModified;
767
+ });
768
+ }
769
+
770
+ // 响应式过滤
771
+ $: {
772
+ createdFrom, createdTo, modifiedFrom, modifiedTo;
773
+ filterDocuments();
774
+ }
775
+
776
+ function clearAllFilters() {
777
+ createdFrom = null;
778
+ createdTo = null;
779
+ modifiedFrom = null;
780
+ modifiedTo = null;
781
+ }
782
+
783
+ function setRecentFilter() {
784
+ createdFrom = dayjs().subtract(30, 'day');
785
+ createdTo = dayjs();
786
+ }
787
+
788
+ function exportResults() {
789
+ console.log('导出的文档:', filteredDocuments);
790
+ alert(`导出了 ${filteredDocuments.length} 个文档`);
791
+ }
792
+ </script>
793
+
794
+ <div class="advanced-search">
795
+ <header class="search-header">
796
+ <h2>文档搜索与过滤</h2>
797
+ <p>使用日期范围按创建和修改日期查找文档</p>
798
+ </header>
799
+
800
+ <div class="filter-panel">
801
+ <div class="filter-section">
802
+ <h3>创建日期范围</h3>
803
+ <DateRange
804
+ bind:fromValue={createdFrom}
805
+ bind:toValue={createdTo}
806
+ variant="outlined"
807
+ format="YYYY年MM月DD日"
808
+ compact={true}
809
+ style="width: 300px;"
810
+ />
811
+ </div>
812
+
813
+ <div class="filter-section">
814
+ <h3>修改日期范围</h3>
815
+ <DateRange
816
+ bind:fromValue={modifiedFrom}
817
+ bind:toValue={modifiedTo}
818
+ variant="outlined"
819
+ format="YYYY年MM月DD日"
820
+ compact={true}
821
+ style="width: 300px;"
822
+ />
823
+ </div>
824
+
825
+ <div class="filter-actions">
826
+ <button class="action-btn secondary" on:click={setRecentFilter}>最近30天</button>
827
+ <button class="action-btn secondary" on:click={clearAllFilters}>清除所有</button>
828
+ {#if filteredDocuments.length > 0}
829
+ <button class="action-btn primary" on:click={exportResults}>导出 ({filteredDocuments.length})</button>
830
+ {/if}
831
+ </div>
832
+ </div>
833
+
834
+ <div class="results-section">
835
+ <div class="results-header">
836
+ <h3>搜索结果</h3>
837
+ <span class="result-count">{filteredDocuments.length} / {allDocuments.length} 个文档</span>
838
+ </div>
839
+
840
+ <div class="documents-list">
841
+ {#if filteredDocuments.length > 0}
842
+ {#each filteredDocuments as doc}
843
+ <div class="document-card">
844
+ <div class="doc-header">
845
+ <div class="doc-title">{doc.title}</div>
846
+ <div class="doc-type">{doc.type}</div>
847
+ </div>
848
+ <div class="doc-dates">
849
+ <div class="date-info">
850
+ <span class="date-label">创建:</span>
851
+ <span class="date-value">{dayjs(doc.created).format('YYYY年MM月DD日')}</span>
852
+ </div>
853
+ <div class="date-info">
854
+ <span class="date-label">修改:</span>
855
+ <span class="date-value">{dayjs(doc.modified).format('YYYY年MM月DD日')}</span>
856
+ </div>
857
+ </div>
858
+ <div class="doc-status">
859
+ <span class="status-badge status-{doc.status.replace('版', '').replace('中', '')}">{doc.status}</span>
860
+ </div>
861
+ </div>
862
+ {/each}
863
+ {:else}
864
+ <div class="no-results">
865
+ <h4>未找到文档</h4>
866
+ <p>尝试调整您的日期范围过滤器或清除所有过滤器以查看更多结果。</p>
867
+ </div>
868
+ {/if}
869
+ </div>
870
+ </div>
871
+ </div>
872
+
873
+ <style>
874
+ .advanced-search {
875
+ max-width: 1000px;
876
+ margin: 0 auto;
877
+ padding: 20px;
878
+ }
879
+
880
+ .search-header {
881
+ text-align: center;
882
+ margin-bottom: 30px;
883
+ }
884
+
885
+ .search-header h2 {
886
+ color: #333;
887
+ margin: 0 0 8px 0;
888
+ }
889
+
890
+ .search-header p {
891
+ color: #666;
892
+ margin: 0;
893
+ }
894
+
895
+ .filter-panel {
896
+ background: #f8f9fa;
897
+ padding: 25px;
898
+ border-radius: 8px;
899
+ margin-bottom: 30px;
900
+ display: flex;
901
+ flex-wrap: wrap;
902
+ gap: 25px;
903
+ align-items: flex-end;
904
+ }
905
+
906
+ .filter-section {
907
+ flex: 1;
908
+ min-width: 280px;
909
+ }
910
+
911
+ .filter-section h3 {
912
+ margin: 0 0 12px 0;
913
+ color: #333;
914
+ font-size: 1rem;
915
+ }
916
+
917
+ .filter-actions {
918
+ display: flex;
919
+ flex-wrap: wrap;
920
+ gap: 10px;
921
+ align-items: center;
922
+ }
923
+
924
+ .action-btn {
925
+ padding: 8px 16px;
926
+ border: none;
927
+ border-radius: 4px;
928
+ cursor: pointer;
929
+ font-size: 0.875rem;
930
+ font-weight: 500;
931
+ transition: all 0.2s;
932
+ }
933
+
934
+ .action-btn.primary {
935
+ background: #007bff;
936
+ color: white;
937
+ }
938
+
939
+ .action-btn.primary:hover {
940
+ background: #0056b3;
941
+ }
942
+
943
+ .action-btn.secondary {
944
+ background: #6c757d;
945
+ color: white;
946
+ }
947
+
948
+ .action-btn.secondary:hover {
949
+ background: #5a6268;
950
+ }
951
+
952
+ .results-section {
953
+ background: white;
954
+ border-radius: 8px;
955
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
956
+ overflow: hidden;
957
+ }
958
+
959
+ .results-header {
960
+ display: flex;
961
+ justify-content: space-between;
962
+ align-items: center;
963
+ padding: 20px 25px;
964
+ background: #f8f9fa;
965
+ border-bottom: 1px solid #dee2e6;
966
+ }
967
+
968
+ .results-header h3 {
969
+ margin: 0;
970
+ color: #333;
971
+ }
972
+
973
+ .result-count {
974
+ color: #666;
975
+ font-size: 0.9rem;
976
+ }
977
+
978
+ .documents-list {
979
+ padding: 20px;
980
+ }
981
+
982
+ .document-card {
983
+ border: 1px solid #e9ecef;
984
+ border-radius: 6px;
985
+ padding: 16px;
986
+ margin-bottom: 12px;
987
+ transition: all 0.2s;
988
+ }
989
+
990
+ .document-card:hover {
991
+ border-color: #007bff;
992
+ box-shadow: 0 2px 4px rgba(0,123,255,0.15);
993
+ }
994
+
995
+ .doc-header {
996
+ display: flex;
997
+ justify-content: space-between;
998
+ align-items: center;
999
+ margin-bottom: 12px;
1000
+ }
1001
+
1002
+ .doc-title {
1003
+ font-weight: 600;
1004
+ color: #333;
1005
+ font-size: 1.1rem;
1006
+ }
1007
+
1008
+ .doc-type {
1009
+ background: #e9ecef;
1010
+ color: #495057;
1011
+ padding: 4px 8px;
1012
+ border-radius: 4px;
1013
+ font-size: 0.75rem;
1014
+ font-weight: 500;
1015
+ }
1016
+
1017
+ .doc-dates {
1018
+ display: flex;
1019
+ gap: 20px;
1020
+ margin-bottom: 12px;
1021
+ }
1022
+
1023
+ .date-info {
1024
+ font-size: 0.875rem;
1025
+ }
1026
+
1027
+ .date-label {
1028
+ color: #666;
1029
+ margin-right: 6px;
1030
+ }
1031
+
1032
+ .date-value {
1033
+ color: #333;
1034
+ font-weight: 500;
1035
+ }
1036
+
1037
+ .status-badge {
1038
+ padding: 4px 8px;
1039
+ border-radius: 12px;
1040
+ font-size: 0.75rem;
1041
+ font-weight: 500;
1042
+ }
1043
+
1044
+ .status-草稿 {
1045
+ background: #fff3cd;
1046
+ color: #856404;
1047
+ }
1048
+
1049
+ .status-最终 {
1050
+ background: #d4edda;
1051
+ color: #155724;
1052
+ }
1053
+
1054
+ .status-审核 {
1055
+ background: #cce5ff;
1056
+ color: #004085;
1057
+ }
1058
+
1059
+ .no-results {
1060
+ text-align: center;
1061
+ padding: 60px 20px;
1062
+ color: #666;
1063
+ }
1064
+
1065
+ .no-results h4 {
1066
+ margin: 0 0 12px 0;
1067
+ color: #333;
1068
+ }
1069
+
1070
+ @media (max-width: 768px) {
1071
+ .filter-panel {
1072
+ flex-direction: column;
1073
+ align-items: stretch;
1074
+ }
1075
+
1076
+ .filter-actions {
1077
+ justify-content: center;
1078
+ }
1079
+
1080
+ .doc-header {
1081
+ flex-direction: column;
1082
+ align-items: flex-start;
1083
+ gap: 8px;
1084
+ }
1085
+
1086
+ .doc-dates {
1087
+ flex-direction: column;
1088
+ gap: 4px;
1089
+ }
1090
+ }
1091
+ </style>
1092
+ ```
1093
+
1094
+ ## 样式
1095
+
1096
+ DateRange 组件使用以下 CSS 类:
1097
+
1098
+ ```css
1099
+ .uniface-range-editor {
1100
+ /* 主要范围容器 */
1101
+ display: flex;
1102
+ align-items: center;
1103
+ gap: 8px;
1104
+ }
1105
+
1106
+ .uniface-range-editor .calendar-icon {
1107
+ /* 日历触发图标 */
1108
+ cursor: pointer;
1109
+ opacity: 0.7;
1110
+ transition: opacity 0.2s;
1111
+ }
1112
+
1113
+ .uniface-range-editor .calendar-icon:hover {
1114
+ opacity: 1;
1115
+ }
1116
+
1117
+ /* 日历弹出框样式 */
1118
+ .calendar-popover {
1119
+ /* 日历弹出容器 */
1120
+ background: white;
1121
+ border-radius: 8px;
1122
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1123
+ padding: 16px;
1124
+ }
1125
+ ```
1126
+
1127
+ ## API 参考
1128
+
1129
+ ### DateRange 组件属性
1130
+
1131
+ ```typescript
1132
+ interface DateRangeProps {
1133
+ variant?: '' | 'plain' | 'outlined' | 'filled'; // 视觉样式变体
1134
+ compact?: boolean; // 紧凑布局模式
1135
+ class?: string; // CSS 类名
1136
+ style?: string; // 自定义内联样式
1137
+ fromValue: UniDate; // 起始日期值
1138
+ toValue: UniDate; // 结束日期值
1139
+ format?: string; // 日期显示格式
1140
+ min?: string | Date | null; // 最小可选日期
1141
+ max?: string | Date | null; // 最大可选日期
1142
+ }
1143
+ ```
1144
+
1145
+ ## 最佳实践
1146
+
1147
+ 1. **日期验证** - 始终验证起始日期在结束日期之前或等于结束日期
1148
+ 2. **格式一致性** - 在应用程序中使用一致的日期格式
1149
+ 3. **最小/最大边界** - 为您的用例设置适当的日期边界
1150
+ 4. **用户反馈** - 为选定的日期范围提供清晰的视觉反馈
1151
+ 5. **移动支持** - 在触摸设备上测试日历交互
1152
+ 6. **可访问性** - 确保日历导航支持键盘操作
1153
+ 7. **时区处理** - 在应用程序中明确时区处理方式
1154
+ 8. **清除功能** - 允许用户轻松清除日期选择
1155
+ 9. **性能** - 对依赖于日期范围的过滤操作进行防抖处理
1156
+ 10. **本地化** - 考虑国际用户的日期格式偏好