jianghu-ui 1.0.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 (112) hide show
  1. package/README.md +376 -0
  2. package/dist/jianghu-ui.css +2318 -0
  3. package/dist/jianghu-ui.js +2 -0
  4. package/dist/jianghu-ui.js.LICENSE.txt +1 -0
  5. package/package.json +56 -0
  6. package/src/Design.stories.mdx +195 -0
  7. package/src/Introduction.stories.mdx +148 -0
  8. package/src/components/JhAddressSelect/JhAddressSelect.md +250 -0
  9. package/src/components/JhAddressSelect/JhAddressSelect.stories.js +282 -0
  10. package/src/components/JhAddressSelect/JhAddressSelect.vue +261 -0
  11. package/src/components/JhCard/JhCard.md +246 -0
  12. package/src/components/JhCard/JhCard.stories.js +688 -0
  13. package/src/components/JhCard/JhCard.vue +604 -0
  14. package/src/components/JhCheckCard/JhCheckCard.md +245 -0
  15. package/src/components/JhCheckCard/JhCheckCard.stories.js +750 -0
  16. package/src/components/JhCheckCard/JhCheckCard.vue +476 -0
  17. package/src/components/JhConfirmDialog/JhConfirmDialog.md +70 -0
  18. package/src/components/JhConfirmDialog/JhConfirmDialog.stories.js +550 -0
  19. package/src/components/JhConfirmDialog/JhConfirmDialog.vue +181 -0
  20. package/src/components/JhDateRangePicker/JhDateRangePicker.md +56 -0
  21. package/src/components/JhDateRangePicker/JhDateRangePicker.stories.js +320 -0
  22. package/src/components/JhDateRangePicker/JhDateRangePicker.vue +307 -0
  23. package/src/components/JhDescriptions/JhDescriptions.md +724 -0
  24. package/src/components/JhDescriptions/JhDescriptions.stories.js +858 -0
  25. package/src/components/JhDescriptions/JhDescriptions.vue +933 -0
  26. package/src/components/JhDraggable/JhDraggable.md +66 -0
  27. package/src/components/JhDraggable/JhDraggable.stories.js +161 -0
  28. package/src/components/JhDraggable/JhDraggable.vue +254 -0
  29. package/src/components/JhDrawer/JhDrawer.md +68 -0
  30. package/src/components/JhDrawer/JhDrawer.stories.js +478 -0
  31. package/src/components/JhDrawer/JhDrawer.vue +281 -0
  32. package/src/components/JhDrawerForm/JhDrawerForm.md +69 -0
  33. package/src/components/JhDrawerForm/JhDrawerForm.stories.js +492 -0
  34. package/src/components/JhDrawerForm/JhDrawerForm.vue +297 -0
  35. package/src/components/JhEditableTable/JhEditableTable.md +507 -0
  36. package/src/components/JhEditableTable/JhEditableTable.stories.js +615 -0
  37. package/src/components/JhEditableTable/JhEditableTable.vue +685 -0
  38. package/src/components/JhFileInput/JhFileInput.md +56 -0
  39. package/src/components/JhFileInput/JhFileInput.stories.js +103 -0
  40. package/src/components/JhFileInput/JhFileInput.vue +253 -0
  41. package/src/components/JhForm/JhForm.md +676 -0
  42. package/src/components/JhForm/JhForm.stories.js +1375 -0
  43. package/src/components/JhForm/JhForm.vue +657 -0
  44. package/src/components/JhFormField/JhFormField.stories.js +217 -0
  45. package/src/components/JhFormField/JhFormField.vue +439 -0
  46. package/src/components/JhFormFields/JhFormFields.md +647 -0
  47. package/src/components/JhFormFields/JhFormFields.stories.js +922 -0
  48. package/src/components/JhFormFields/JhFormFields.vue +998 -0
  49. package/src/components/JhFormList/JhFormList.md +303 -0
  50. package/src/components/JhFormList/JhFormList.stories.js +661 -0
  51. package/src/components/JhFormList/JhFormList.vue +1127 -0
  52. package/src/components/JhJsonEditor/JhJsonEditor.md +54 -0
  53. package/src/components/JhJsonEditor/JhJsonEditor.stories.js +157 -0
  54. package/src/components/JhJsonEditor/JhJsonEditor.vue +178 -0
  55. package/src/components/JhLayout/JhLayout.md +580 -0
  56. package/src/components/JhLayout/JhLayout.stories.js +414 -0
  57. package/src/components/JhLayout/JhLayout.vue +387 -0
  58. package/src/components/JhList/JhList.md +441 -0
  59. package/src/components/JhList/JhList.stories.js +524 -0
  60. package/src/components/JhList/JhList.vue +571 -0
  61. package/src/components/JhMarkdownEditor/JhMarkdownEditor.md +56 -0
  62. package/src/components/JhMarkdownEditor/JhMarkdownEditor.stories.js +191 -0
  63. package/src/components/JhMarkdownEditor/JhMarkdownEditor.vue +188 -0
  64. package/src/components/JhMask/JhMask.md +62 -0
  65. package/src/components/JhMask/JhMask.stories.js +270 -0
  66. package/src/components/JhMask/JhMask.vue +123 -0
  67. package/src/components/JhMenu/JhMenu.md +85 -0
  68. package/src/components/JhMenu/JhMenu.stories.js +384 -0
  69. package/src/components/JhMenu/JhMenu.vue +545 -0
  70. package/src/components/JhModal/JhModal.md +68 -0
  71. package/src/components/JhModal/JhModal.stories.js +562 -0
  72. package/src/components/JhModal/JhModal.vue +235 -0
  73. package/src/components/JhModalForm/JhModalForm.md +69 -0
  74. package/src/components/JhModalForm/JhModalForm.stories.js +592 -0
  75. package/src/components/JhModalForm/JhModalForm.vue +298 -0
  76. package/src/components/JhPageContainer/JhPageContainer.md +409 -0
  77. package/src/components/JhPageContainer/JhPageContainer.stories.js +209 -0
  78. package/src/components/JhPageContainer/JhPageContainer.vue +72 -0
  79. package/src/components/JhQueryFilter/JhQueryFilter.md +77 -0
  80. package/src/components/JhQueryFilter/JhQueryFilter.stories.js +684 -0
  81. package/src/components/JhQueryFilter/JhQueryFilter.vue +429 -0
  82. package/src/components/JhScene/JhScene.md +64 -0
  83. package/src/components/JhScene/JhScene.stories.js +317 -0
  84. package/src/components/JhScene/JhScene.vue +376 -0
  85. package/src/components/JhStatisticCard/JhStatisticCard.md +363 -0
  86. package/src/components/JhStatisticCard/JhStatisticCard.stories.js +847 -0
  87. package/src/components/JhStatisticCard/JhStatisticCard.vue +459 -0
  88. package/src/components/JhStepsForm/JhStepsForm.md +666 -0
  89. package/src/components/JhStepsForm/JhStepsForm.stories.js +1224 -0
  90. package/src/components/JhStepsForm/JhStepsForm.vue +749 -0
  91. package/src/components/JhTable/JhTable.md +730 -0
  92. package/src/components/JhTable/JhTable.stories.js +1444 -0
  93. package/src/components/JhTable/JhTable.vue +2298 -0
  94. package/src/components/JhTableAttachment/JhTableAttachment.md +70 -0
  95. package/src/components/JhTableAttachment/JhTableAttachment.stories.js +198 -0
  96. package/src/components/JhTableAttachment/JhTableAttachment.vue +264 -0
  97. package/src/components/JhToast/JhToast.md +67 -0
  98. package/src/components/JhToast/JhToast.stories.js +386 -0
  99. package/src/components/JhToast/JhToast.vue +239 -0
  100. package/src/components/JhTreeSelect/JhTreeSelect.md +82 -0
  101. package/src/components/JhTreeSelect/JhTreeSelect.stories.js +391 -0
  102. package/src/components/JhTreeSelect/JhTreeSelect.vue +727 -0
  103. package/src/components/JhWaterMark/JhWaterMark.md +190 -0
  104. package/src/components/JhWaterMark/JhWaterMark.stories.js +675 -0
  105. package/src/components/JhWaterMark/JhWaterMark.vue +351 -0
  106. package/src/components/README.md +52 -0
  107. package/src/index.js +135 -0
  108. package/src/style/globalCSSJHV4.css +348 -0
  109. package/src/style/globalCSSVuetifyV4.css +637 -0
  110. package/src/style/storybook.css +4 -0
  111. package/src/tailwind.css +3 -0
  112. package/src/utils/vuetify.js +31 -0
@@ -0,0 +1,429 @@
1
+ <template>
2
+ <div class="jh-query-filter">
3
+ <!-- 查询表单 -->
4
+ <v-form ref="queryForm" @submit.prevent="handleSearch">
5
+ <v-row :class="rowClass">
6
+ <!-- 使用 JhFormFields 渲染字段 -->
7
+ <JhFormFields
8
+ v-model="formData"
9
+ :fields="visibleFieldsWithConfig"
10
+ :showLabels="showLabels"
11
+ :labelClass="labelClass"
12
+ :inputClass="inputClass"
13
+ :defaultDense="dense"
14
+ :defaultFilled="filled"
15
+ :defaultOutlined="outlined"
16
+ :defaultSingleLine="singleLine"
17
+ :hideDetails="true"
18
+ layout="vertical"
19
+ @field-change="handleFieldChange"
20
+ >
21
+ <!-- 透传自定义字段插槽 -->
22
+ <template v-for="field in fields" v-slot:[`field-${field.key}`]="slotProps">
23
+ <slot :name="`field-${field.key}`" v-bind="slotProps"></slot>
24
+ </template>
25
+ </JhFormFields>
26
+
27
+ <!-- 操作按钮列 -->
28
+ <v-col class="d-flex align-end flex-column justify-center">
29
+ <span class="opacity-0" v-if="showLabels" :class="labelClass">
30
+ 工具栏
31
+ </span>
32
+
33
+ <slot name="buttons" :formData="formData" :search="handleSearch" :reset="handleReset">
34
+ <div class="jh-query-filter-buttons" :class="buttonClass">
35
+ <!-- 查询按钮 -->
36
+ <v-btn
37
+ color="primary"
38
+ :small="buttonSize === 'small'"
39
+ :dense="buttonSize === 'small'"
40
+ depressed
41
+ @click="handleSearch"
42
+ :loading="searching"
43
+ class="jh-query-filter-search-btn"
44
+ >
45
+ <v-icon left small>mdi-magnify</v-icon>
46
+ {{ searchText }}
47
+ </v-btn>
48
+
49
+ <!-- 重置按钮 -->
50
+ <v-btn
51
+ outlined
52
+ :small="buttonSize === 'small'"
53
+ :dense="buttonSize === 'small'"
54
+ @click="handleReset"
55
+ class="jh-query-filter-reset-btn"
56
+ >
57
+ <v-icon left small>mdi-refresh</v-icon>
58
+ {{ resetText }}
59
+ </v-btn>
60
+
61
+ <!-- 展开/收起按钮 -->
62
+ <v-btn
63
+ v-if="collapsible && fields.length > defaultVisibleCount"
64
+ text
65
+ :small="buttonSize === 'small'"
66
+ :dense="buttonSize === 'small'"
67
+ color="primary"
68
+ @click="toggleCollapse"
69
+ class="jh-query-filter-collapse-btn"
70
+ >
71
+ {{ collapsed ? expandText : collapseText }}
72
+ <v-icon right small>{{ collapsed ? 'mdi-chevron-down' : 'mdi-chevron-up' }}</v-icon>
73
+ </v-btn>
74
+ </div>
75
+ </slot>
76
+ </v-col>
77
+ </v-row>
78
+ </v-form>
79
+ </div>
80
+ </template>
81
+
82
+ <script>
83
+ import JhFormFields from '../JhFormFields/JhFormFields.vue';
84
+
85
+ export default {
86
+ name: 'JhQueryFilter',
87
+
88
+ components: {
89
+ JhFormFields,
90
+ },
91
+
92
+ props: {
93
+ // 查询字段配置
94
+ fields: {
95
+ type: Array,
96
+ default: () => [],
97
+ },
98
+
99
+ // 初始查询数据
100
+ initialValues: {
101
+ type: Object,
102
+ default: () => ({}),
103
+ },
104
+
105
+ // 是否可折叠
106
+ collapsible: {
107
+ type: Boolean,
108
+ default: true,
109
+ },
110
+
111
+ // 默认是否折叠
112
+ defaultCollapsed: {
113
+ type: Boolean,
114
+ default: true,
115
+ },
116
+
117
+ // 默认显示字段数量(折叠时)
118
+ defaultVisibleCount: {
119
+ type: Number,
120
+ default: 3,
121
+ },
122
+
123
+ // 列宽配置(响应式)
124
+ colSpan: {
125
+ type: Object,
126
+ default: () => ({
127
+ xs: 24,
128
+ sm: 12,
129
+ md: 6,
130
+ lg: 4,
131
+ }),
132
+ },
133
+
134
+ // 是否显示标签
135
+ showLabels: {
136
+ type: Boolean,
137
+ default: true,
138
+ },
139
+
140
+ // 输入框样式
141
+ dense: {
142
+ type: Boolean,
143
+ default: true,
144
+ },
145
+
146
+ // 是否使用 filled 风格输入框
147
+ filled: {
148
+ type: Boolean,
149
+ default: true,
150
+ },
151
+
152
+ // 是否使用 outlined 风格输入框
153
+ outlined: {
154
+ type: Boolean,
155
+ default: false,
156
+ },
157
+
158
+ // 是否单行显示标签
159
+ singleLine: {
160
+ type: Boolean,
161
+ default: true,
162
+ },
163
+
164
+ // 按钮文本
165
+ searchText: {
166
+ type: String,
167
+ default: '查询',
168
+ },
169
+
170
+ // 重置按钮文案
171
+ resetText: {
172
+ type: String,
173
+ default: '重置',
174
+ },
175
+
176
+ // 折叠状态下展示“展开”按钮文案
177
+ expandText: {
178
+ type: String,
179
+ default: '展开',
180
+ },
181
+
182
+ // 展开状态下展示“收起”按钮文案
183
+ collapseText: {
184
+ type: String,
185
+ default: '收起',
186
+ },
187
+
188
+ // 按钮大小
189
+ buttonSize: {
190
+ type: String,
191
+ default: 'small',
192
+ validator: (v) => ['small', 'default', 'large'].includes(v),
193
+ },
194
+
195
+ // 按钮对齐方式
196
+ buttonAlign: {
197
+ type: String,
198
+ default: 'left',
199
+ validator: (v) => ['left', 'right', 'center'].includes(v),
200
+ },
201
+
202
+ // 加载状态
203
+ loading: {
204
+ type: Boolean,
205
+ default: false,
206
+ },
207
+
208
+ // 自定义样式类
209
+ labelClass: {
210
+ type: String,
211
+ default: 'jh-input-label',
212
+ },
213
+
214
+ inputClass: {
215
+ type: String,
216
+ default: 'jh-v-input',
217
+ },
218
+
219
+ // 每行容器的自定义类,用于控制间距
220
+ rowClass: {
221
+ type: String,
222
+ default: 'ma-0',
223
+ },
224
+
225
+ // 按钮区域根元素类名
226
+ buttonClass: {
227
+ type: String,
228
+ default: 'gap-2',
229
+ },
230
+
231
+ // 按钮列(v-col)的类名
232
+ buttonColumnClass: {
233
+ type: String,
234
+ default: '',
235
+ },
236
+ },
237
+
238
+ data() {
239
+ return {
240
+ formData: {},
241
+ collapsed: this.defaultCollapsed,
242
+ searching: false,
243
+ };
244
+ },
245
+
246
+ computed: {
247
+ // 可见的字段列表
248
+ visibleFields() {
249
+ if (!this.collapsible || !this.collapsed) {
250
+ return this.fields;
251
+ }
252
+ return this.fields.slice(0, this.defaultVisibleCount);
253
+ },
254
+
255
+ // 为字段添加查询过滤器特有的配置
256
+ visibleFieldsWithConfig() {
257
+ return this.visibleFields.map(field => ({
258
+ ...field,
259
+ // 设置列宽配置
260
+ cols: field.cols || {
261
+ xs: this.colSpan.xs || 12,
262
+ sm: this.colSpan.sm || 12,
263
+ md: this.colSpan.md || 8,
264
+ lg: this.colSpan.lg || 6,
265
+ },
266
+ // 查询过滤器字段默认可清空
267
+ props: {
268
+ clearable: true,
269
+ placeholder: field.placeholder || `请输入${field.text}`,
270
+ ...field.props,
271
+ },
272
+ }));
273
+ },
274
+ },
275
+
276
+ watch: {
277
+ initialValues: {
278
+ handler(val) {
279
+ this.formData = { ...val };
280
+ },
281
+ immediate: true,
282
+ deep: true,
283
+ },
284
+
285
+ loading(val) {
286
+ this.searching = val;
287
+ },
288
+ },
289
+
290
+ mounted() {
291
+ this.initFormData();
292
+ },
293
+
294
+ methods: {
295
+ // 初始化表单数据
296
+ initFormData() {
297
+ const data = { ...this.initialValues };
298
+
299
+ // 从 fields 中提取默认值
300
+ this.fields.forEach(field => {
301
+ if (field.defaultValue !== undefined && data[field.key] === undefined) {
302
+ data[field.key] = field.defaultValue;
303
+ }
304
+ });
305
+
306
+ this.formData = data;
307
+ },
308
+
309
+ // 处理字段变化
310
+ handleFieldChange({ key, value }) {
311
+ this.$emit('field-change', { key, value, formData: this.formData });
312
+
313
+ // 如果配置了实时查询
314
+ if (this.fields.find(f => f.key === key)?.realtime) {
315
+ this.handleSearch();
316
+ }
317
+ },
318
+
319
+ // 切换折叠状态
320
+ toggleCollapse() {
321
+ this.collapsed = !this.collapsed;
322
+ this.$emit('collapse-change', this.collapsed);
323
+ },
324
+
325
+ // 处理查询
326
+ async handleSearch() {
327
+ this.searching = true;
328
+ try {
329
+ // 过滤掉空值
330
+ const queryData = {};
331
+ Object.keys(this.formData).forEach(key => {
332
+ const value = this.formData[key];
333
+ if (value !== null && value !== undefined && value !== '') {
334
+ // 日期范围特殊处理
335
+ if (Array.isArray(value) && value.length === 0) {
336
+ return;
337
+ }
338
+ queryData[key] = value;
339
+ }
340
+ });
341
+
342
+ this.$emit('search', queryData);
343
+ } finally {
344
+ if (!this.loading) {
345
+ this.searching = false;
346
+ }
347
+ }
348
+ },
349
+
350
+ // 处理重置
351
+ handleReset() {
352
+ // 重置表单数据
353
+ this.initFormData();
354
+
355
+ // 清空所有字段
356
+ this.fields.forEach(field => {
357
+ this.$set(this.formData, field.key, field.defaultValue !== undefined ? field.defaultValue : '');
358
+ });
359
+
360
+ this.$emit('reset');
361
+
362
+ // 自动触发查询
363
+ this.handleSearch();
364
+ },
365
+
366
+ // 获取表单数据
367
+ getFormData() {
368
+ return { ...this.formData };
369
+ },
370
+
371
+ // 设置表单数据
372
+ setFieldsValue(values) {
373
+ this.formData = { ...this.formData, ...values };
374
+ },
375
+
376
+ // 设置单个字段值
377
+ setFieldValue(key, value) {
378
+ this.$set(this.formData, key, value);
379
+ },
380
+ },
381
+ };
382
+ </script>
383
+
384
+ <style scoped>
385
+ .jh-query-filter {
386
+ padding: 16px;
387
+ background: #fff;
388
+ border-radius: 4px;
389
+ }
390
+
391
+ /* 按钮容器样式 */
392
+ .jh-query-filter-buttons {
393
+ display: flex;
394
+ align-items: center;
395
+ gap: 8px;
396
+ }
397
+
398
+ /* 查询按钮样式 */
399
+ .jh-query-filter-search-btn {
400
+ min-width: 80px;
401
+ }
402
+
403
+ /* 重置按钮样式 */
404
+ .jh-query-filter-reset-btn {
405
+ min-width: 80px;
406
+ }
407
+
408
+ /* 展开/收起按钮样式 */
409
+ .jh-query-filter-collapse-btn {
410
+ margin-left: 8px;
411
+ }
412
+
413
+ /* Flex 工具类 */
414
+ .d-flex {
415
+ display: flex;
416
+ }
417
+
418
+ .align-center {
419
+ align-items: center;
420
+ }
421
+
422
+ .align-end {
423
+ align-items: flex-end;
424
+ }
425
+
426
+ .gap-2 {
427
+ gap: 8px;
428
+ }
429
+ </style>
@@ -0,0 +1,64 @@
1
+ # JhScene - 场景切换组件
2
+
3
+ JhScene 用于保存并切换用户的查询/配置场景,支持本地存储、场景管理弹窗,适用于列表筛选方案、仪表盘布局等。
4
+
5
+ ## 功能特性
6
+
7
+ - 🧭 **快速切换**:通过按钮组切换系统场景或自定义场景
8
+ - 🧺 **场景管理**:内置新增、删除弹窗,可管理自定义场景列表
9
+ - 💾 **持久化**:可选择写入 localStorage,刷新后仍保存
10
+ - 🧱 **外部联动**:切换后会将场景对象回传,父组件可更新查询条件
11
+ - 🧩 **可插槽扩展**:提供 `form` 插槽以渲染自定义筛选表单
12
+
13
+ ## 基础用法
14
+
15
+ ```vue
16
+ <template>
17
+ <jh-scene
18
+ :scenes="defaultScenes"
19
+ :init-form-data="query"
20
+ storage-key="customer-scene"
21
+ :use-local-storage="true"
22
+ @scene-change="applyScene"
23
+ @scene-created="saveScene"
24
+ >
25
+ <template #form="{ form }">
26
+ <customer-filter v-model="form" />
27
+ </template>
28
+ </jh-scene>
29
+ </template>
30
+ ```
31
+
32
+ ## API
33
+
34
+ ### Props
35
+
36
+ | 参数 | 说明 | 类型 | 默认值 |
37
+ | --- | --- | --- | --- |
38
+ | initFormData | 新建场景时复制的初始表单数据 | object | `{}` |
39
+ | storageKey | 使用 localStorage 时的键名 | string | `jh-scene-list` |
40
+ | scenes | 系统内置场景列表 | Array | [] |
41
+ | currentSceneId | 默认选中的场景 id | string | null |
42
+ | showActionBtn | 是否显示“新建/管理”动作按钮 | boolean | true |
43
+ | useLocalStorage | 是否启用 localStorage 持久化 | boolean | false |
44
+
45
+ ### Events
46
+
47
+ | 事件名 | 说明 | 回调参数 |
48
+ | --- | --- | --- |
49
+ | scene-change | 切换场景后触发 | (scene: object) |
50
+ | scene-created | 新建场景成功时触发 | (scene: object) |
51
+ | scene-deleted | 删除场景时触发 | (scene: object) |
52
+ | error | 创建失败(如重名)时触发 | (message: string) |
53
+
54
+ ### Slots
55
+
56
+ | 名称 | 说明 |
57
+ | --- | --- |
58
+ | form | 新建场景弹窗中的“筛选条件”区域,参数 `{ form }` |
59
+
60
+ ## 使用建议
61
+
62
+ - 每个场景对象建议包含 `{ id, name, form, system, default }` 等字段,方便控制默认场景
63
+ - 当 `useLocalStorage` 为 true 时,组件自动将所有场景写入浏览器存储
64
+ - 切换场景时会将完整对象抛出,可直接将其 form 数据写回查询条件