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,298 @@
1
+ <template>
2
+ <v-dialog
3
+ v-model="isShownInternal"
4
+ :max-width="width"
5
+ :persistent="persistent"
6
+ :fullscreen="fullscreen"
7
+ @keydown.esc="handleCancel"
8
+ >
9
+ <v-card>
10
+ <!-- 标题栏 -->
11
+ <v-card-title class="d-flex align-center justify-space-between pa-4">
12
+ <span class="text-h6">{{ title }}</span>
13
+ <v-btn
14
+ v-if="closable"
15
+ icon
16
+ small
17
+ @click="handleCancel"
18
+ >
19
+ <v-icon>mdi-close</v-icon>
20
+ </v-btn>
21
+ </v-card-title>
22
+
23
+ <v-divider />
24
+
25
+ <!-- 表单内容 -->
26
+ <v-card-text class="pa-6">
27
+ <!-- 支持完全自定义内容 -->
28
+ <slot name="content">
29
+ <!-- 使用 JhForm 组件渲染表单 -->
30
+ <jh-form
31
+ ref="jhForm"
32
+ :form-ref="formRef"
33
+ :fields="fields"
34
+ :initial-data="initialData"
35
+ :validation-rules="validationRules"
36
+ :default-cols-md="6"
37
+ @field-change="handleFieldChange"
38
+ >
39
+ <!-- 传递自定义字段插槽 -->
40
+ <template v-for="field in slotFields" v-slot:[`field-${field.key}`]="slotProps">
41
+ <slot :name="`field-${field.key}`" v-bind="slotProps"></slot>
42
+ </template>
43
+ </jh-form>
44
+ </slot>
45
+ </v-card-text>
46
+
47
+ <v-divider />
48
+
49
+ <!-- 底部按钮 -->
50
+ <v-card-actions class="pa-4">
51
+ <v-spacer />
52
+ <v-btn
53
+ text
54
+ @click="handleCancel"
55
+ >
56
+ {{ cancelText }}
57
+ </v-btn>
58
+ <v-btn
59
+ v-if="showConfirmButton"
60
+ color="success"
61
+ @click="handleConfirm"
62
+ >
63
+ {{ confirmText }}
64
+ </v-btn>
65
+ </v-card-actions>
66
+ </v-card>
67
+ </v-dialog>
68
+ </template>
69
+
70
+ <script>
71
+ import JhForm from '../JhForm/JhForm.vue';
72
+
73
+ export default {
74
+ name: 'JhModalForm',
75
+
76
+ components: {
77
+ JhForm,
78
+ },
79
+
80
+ props: {
81
+ // v-model 控制显示/隐藏
82
+ value: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+
87
+ // 标题
88
+ title: {
89
+ type: String,
90
+ default: '表单',
91
+ },
92
+
93
+ // 表单字段配置
94
+ fields: {
95
+ type: Array,
96
+ default: () => [],
97
+ },
98
+
99
+ // 初始表单数据
100
+ initialData: {
101
+ type: Object,
102
+ default: () => ({})
103
+ },
104
+
105
+ // 弹窗宽度
106
+ width: {
107
+ type: [Number, String],
108
+ default: 600,
109
+ },
110
+
111
+ // 是否全屏
112
+ fullscreen: {
113
+ type: Boolean,
114
+ default: false,
115
+ },
116
+
117
+ // 是否持久化(点击外部不关闭)
118
+ persistent: {
119
+ type: Boolean,
120
+ default: true,
121
+ },
122
+
123
+ // 是否显示关闭按钮
124
+ closable: {
125
+ type: Boolean,
126
+ default: true,
127
+ },
128
+
129
+ // 按钮配置
130
+ showConfirmButton: {
131
+ type: Boolean,
132
+ default: true
133
+ },
134
+ confirmText: {
135
+ type: String,
136
+ default: '确认'
137
+ },
138
+ cancelText: {
139
+ type: String,
140
+ default: '取消'
141
+ },
142
+
143
+ // 表单引用名称
144
+ formRef: {
145
+ type: String,
146
+ default: 'modalForm'
147
+ },
148
+
149
+ // 是否在确认前验证表单
150
+ validateBeforeConfirm: {
151
+ type: Boolean,
152
+ default: true
153
+ },
154
+
155
+ // 验证规则集合
156
+ validationRules: {
157
+ type: Object,
158
+ default: () => ({
159
+ require: [v => !!v || '必填'],
160
+ email: [v => !v || /.+@.+\..+/.test(v) || '邮箱格式不正确'],
161
+ phone: [v => !v || /^1[3-9]\d{9}$/.test(v) || '手机号格式不正确'],
162
+ number: [v => !v || !isNaN(v) || '请输入数字'],
163
+ integer: [v => !v || Number.isInteger(Number(v)) || '请输入整数']
164
+ })
165
+ }
166
+ },
167
+
168
+ data() {
169
+ return {
170
+ isShownInternal: this.value,
171
+ };
172
+ },
173
+
174
+ computed: {
175
+ // 获取所有 slot 类型的字段
176
+ slotFields() {
177
+ return this.fields.filter(field => field.type === 'slot');
178
+ },
179
+ },
180
+
181
+ watch: {
182
+ value(val) {
183
+ this.isShownInternal = val;
184
+ // 当弹窗打开时,重置表单数据和验证状态
185
+ if (val) {
186
+ this.$nextTick(() => {
187
+ this.resetForm();
188
+ });
189
+ }
190
+ },
191
+ isShownInternal(val) {
192
+ if (!val) {
193
+ this.$emit('input', false);
194
+ this.$emit('close');
195
+ }
196
+ }
197
+ },
198
+
199
+ methods: {
200
+ // 处理取消
201
+ handleCancel() {
202
+ this.$emit('cancel');
203
+ this.isShownInternal = false;
204
+ },
205
+
206
+ // 处理确认
207
+ async handleConfirm() {
208
+ // 如果需要验证表单
209
+ if (this.validateBeforeConfirm) {
210
+ const isValid = await this.validate();
211
+ if (!isValid) {
212
+ return;
213
+ }
214
+ }
215
+
216
+ this.$emit('confirm', this.getFormData());
217
+ },
218
+
219
+ // 处理字段变化
220
+ handleFieldChange(event) {
221
+ this.$emit('field-change', event);
222
+ },
223
+
224
+ // 获取 JhForm 实例
225
+ getJhForm() {
226
+ return this.$refs.jhForm;
227
+ },
228
+
229
+ // 获取表单引用(供父组件调用)
230
+ getForm() {
231
+ const jhForm = this.getJhForm();
232
+ return jhForm ? jhForm.getForm() : null;
233
+ },
234
+
235
+ // 获取表单数据
236
+ getFormData() {
237
+ const jhForm = this.getJhForm();
238
+ return jhForm ? jhForm.getFormData() : {};
239
+ },
240
+
241
+ // 设置表单数据
242
+ setFieldsValue(values) {
243
+ const jhForm = this.getJhForm();
244
+ if (jhForm) {
245
+ jhForm.setFieldsValue(values);
246
+ }
247
+ },
248
+
249
+ // 设置单个字段值
250
+ setFieldValue(key, value) {
251
+ const jhForm = this.getJhForm();
252
+ if (jhForm) {
253
+ jhForm.setFieldValue(key, value);
254
+ }
255
+ },
256
+
257
+ // 重置表单
258
+ resetForm() {
259
+ const jhForm = this.getJhForm();
260
+ if (jhForm) {
261
+ jhForm.resetForm();
262
+ }
263
+ },
264
+
265
+ // 重置表单验证
266
+ resetValidation() {
267
+ const jhForm = this.getJhForm();
268
+ if (jhForm) {
269
+ jhForm.resetValidation();
270
+ }
271
+ },
272
+
273
+ // 验证表单
274
+ async validate() {
275
+ const jhForm = this.getJhForm();
276
+ if (jhForm) {
277
+ return await jhForm.validate();
278
+ }
279
+ return true;
280
+ }
281
+ },
282
+ };
283
+ </script>
284
+
285
+ <style scoped>
286
+ /* 输入标签 */
287
+ .jh-input-label {
288
+ display: block;
289
+ font-size: 14px;
290
+ color: rgba(0, 0, 0, 0.6);
291
+ margin-bottom: 4px;
292
+ }
293
+
294
+ /* 输入框样式 */
295
+ .jh-v-input {
296
+ margin-top: 0;
297
+ }
298
+ </style>
@@ -0,0 +1,409 @@
1
+ # JhPageContainer - 页面容器组件
2
+
3
+ 页面容器组件,提供统一的页面布局结构。这是与 test 目录中组件样式和功能保持一致的基础版本。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ **统一的页面头部布局**: 标准化的页面标题区域
8
+ - ✅ **页面标题显示**: 清晰的页面标识
9
+ - ✅ **帮助按钮**: 可选的帮助功能入口
10
+ - ✅ **搜索栏插槽**: 灵活的搜索过滤区域
11
+ - ✅ **内容区域插槽**: 主要内容展示区域
12
+ - ✅ **响应式布局**: 自动适配不同屏幕尺寸
13
+ - ✅ **内置全局组件**: 集成 JhToast、JhMask、JhConfirmDialog
14
+
15
+ ## 设计理念
16
+
17
+ `JhPageContainer` 是页面级的容器组件,通常与 `JhLayout` 配合使用:
18
+
19
+ - **JhLayout**: 应用级布局(导航、头部、侧边栏、底部)
20
+ - **JhPageContainer**: 页面级容器(页面标题、搜索栏、内容区域)
21
+
22
+ ## 基础用法
23
+
24
+ ```vue
25
+ <template>
26
+ <jh-page-container
27
+ page-name="用户管理"
28
+ :show-help-button="true"
29
+ @help-click="handleHelpClick"
30
+ >
31
+ <template v-slot:search-bar>
32
+ <!-- 搜索栏内容 -->
33
+ <jh-query-filter
34
+ :keyword.sync="keyword"
35
+ :keywordFieldList.sync="keywordFieldList"
36
+ @search="handleSearch"
37
+ />
38
+ </template>
39
+
40
+ <template v-slot:content>
41
+ <!-- 主要内容 -->
42
+ <jh-table
43
+ :headers="headers"
44
+ :items="items"
45
+ />
46
+ </template>
47
+ </jh-page-container>
48
+ </template>
49
+
50
+ <script>
51
+ export default {
52
+ data() {
53
+ return {
54
+ keyword: '',
55
+ keywordFieldList: ['username', 'email'],
56
+ headers: [],
57
+ items: []
58
+ };
59
+ },
60
+ methods: {
61
+ handleHelpClick() {
62
+ // 显示帮助信息
63
+ },
64
+ handleSearch() {
65
+ // 执行搜索
66
+ }
67
+ }
68
+ };
69
+ </script>
70
+ ```
71
+
72
+ ## Props
73
+
74
+ | 参数 | 说明 | 类型 | 默认值 |
75
+ |------|------|------|--------|
76
+ | pageName | 页面标题 | String | '页面标题' |
77
+ | showHelpButton | 是否显示帮助按钮 | Boolean | true |
78
+
79
+ ## 插槽
80
+
81
+ ### menu
82
+ 菜单区域插槽,用于放置顶部菜单组件
83
+
84
+ ```vue
85
+ <jh-page-container page-name="用户管理">
86
+ <template v-slot:menu>
87
+ <jh-menu
88
+ :items="menuItems"
89
+ @select="handleMenuSelect"
90
+ />
91
+ </template>
92
+ </jh-page-container>
93
+ ```
94
+
95
+ ### search-bar
96
+ 搜索栏区域插槽,通常放置搜索过滤组件
97
+
98
+ ```vue
99
+ <jh-page-container page-name="用户管理">
100
+ <template v-slot:search-bar>
101
+ <jh-query-filter
102
+ :keyword.sync="keyword"
103
+ :keywordFieldList.sync="keywordFieldList"
104
+ @search="handleSearch"
105
+ />
106
+ </template>
107
+ </jh-page-container>
108
+ ```
109
+
110
+ ### content
111
+ 主要内容区域插槽,放置页面的主要内容
112
+
113
+ ```vue
114
+ <jh-page-container page-name="用户管理">
115
+ <template v-slot:content>
116
+ <jh-table
117
+ :headers="headers"
118
+ :items="items"
119
+ />
120
+ </template>
121
+ </jh-page-container>
122
+ ```
123
+
124
+ ### default
125
+ 默认插槽,用于放置其他内容(如抽屉、对话框等)
126
+
127
+ ```vue
128
+ <jh-page-container page-name="用户管理">
129
+ <template v-slot:content>
130
+ <!-- 主要内容 -->
131
+ </template>
132
+
133
+ <!-- 默认插槽:抽屉、对话框等 -->
134
+ <jh-drawer v-model="drawerVisible">
135
+ <!-- 抽屉内容 -->
136
+ </jh-drawer>
137
+ </jh-page-container>
138
+ ```
139
+
140
+ ## 事件
141
+
142
+ | 事件名 | 说明 | 回调参数 |
143
+ |--------|------|----------|
144
+ | help-click | 点击帮助按钮时触发 | - |
145
+
146
+ ## 使用场景
147
+
148
+ ### 列表页面
149
+
150
+ ```vue
151
+ <template>
152
+ <jh-page-container
153
+ page-name="用户列表"
154
+ @help-click="showHelp"
155
+ >
156
+ <template v-slot:search-bar>
157
+ <jh-query-filter
158
+ :keyword.sync="keyword"
159
+ :keywordFieldList.sync="keywordFieldList"
160
+ :headers="headers"
161
+ @search="handleSearch"
162
+ />
163
+ </template>
164
+
165
+ <template v-slot:content>
166
+ <jh-table
167
+ :headers="headers"
168
+ :items="users"
169
+ :loading="loading"
170
+ @create-click="handleCreate"
171
+ @update-click="handleUpdate"
172
+ @delete-click="handleDelete"
173
+ />
174
+ </template>
175
+ </jh-page-container>
176
+ </template>
177
+ ```
178
+
179
+ ### 详情页面
180
+
181
+ ```vue
182
+ <template>
183
+ <jh-page-container
184
+ page-name="用户详情"
185
+ :show-help-button="false"
186
+ >
187
+ <template v-slot:content>
188
+ <jh-descriptions
189
+ :columns="columns"
190
+ :data="userDetail"
191
+ />
192
+ </template>
193
+ </jh-page-container>
194
+ </template>
195
+ ```
196
+
197
+ ### 表单页面
198
+
199
+ ```vue
200
+ <template>
201
+ <jh-page-container
202
+ page-name="新增用户"
203
+ :show-help-button="false"
204
+ >
205
+ <template v-slot:content>
206
+ <v-card>
207
+ <v-card-text>
208
+ <v-form>
209
+ <v-text-field label="用户名" v-model="form.username" />
210
+ <v-text-field label="邮箱" v-model="form.email" />
211
+ </v-form>
212
+ </v-card-text>
213
+ <v-card-actions>
214
+ <v-btn color="primary" @click="handleSubmit">提交</v-btn>
215
+ <v-btn @click="handleCancel">取消</v-btn>
216
+ </v-card-actions>
217
+ </v-card>
218
+ </template>
219
+ </jh-page-container>
220
+ </template>
221
+ ```
222
+
223
+ ## 与 JhLayout 配合使用
224
+
225
+ 推荐的完整页面结构:
226
+
227
+ ```vue
228
+ <template>
229
+ <jh-layout
230
+ title="管理系统"
231
+ :menu-data="menuData"
232
+ :current-path="currentPath"
233
+ show-breadcrumb
234
+ :content-padding="false"
235
+ :show-page-header="false"
236
+ >
237
+ <jh-page-container
238
+ page-name="用户管理"
239
+ :show-help-button="true"
240
+ @help-click="handleHelpClick"
241
+ >
242
+ <template v-slot:search-bar>
243
+ <jh-query-filter
244
+ :keyword.sync="keyword"
245
+ :keywordFieldList.sync="keywordFieldList"
246
+ :headers="headers"
247
+ @search="handleSearch"
248
+ />
249
+ </template>
250
+
251
+ <template v-slot:content>
252
+ <jh-table
253
+ :headers="headers"
254
+ :items="items"
255
+ :loading="loading"
256
+ />
257
+ </template>
258
+ </jh-page-container>
259
+ </jh-layout>
260
+ </template>
261
+
262
+ <script>
263
+ export default {
264
+ data() {
265
+ return {
266
+ currentPath: '/users/list',
267
+ menuData: [
268
+ {
269
+ name: '用户管理',
270
+ path: '/users/list',
271
+ icon: 'mdi-account-group'
272
+ }
273
+ ],
274
+ keyword: '',
275
+ keywordFieldList: ['username', 'email'],
276
+ headers: [
277
+ { text: 'ID', value: 'id' },
278
+ { text: '用户名', value: 'username' },
279
+ { text: '邮箱', value: 'email' }
280
+ ],
281
+ items: [],
282
+ loading: false
283
+ };
284
+ },
285
+ methods: {
286
+ handleHelpClick() {
287
+ // 显示帮助信息
288
+ },
289
+ handleSearch() {
290
+ this.loading = true;
291
+ // 执行搜索逻辑
292
+ setTimeout(() => {
293
+ this.loading = false;
294
+ }, 1000);
295
+ }
296
+ }
297
+ };
298
+ </script>
299
+ ```
300
+
301
+ **配置说明**:
302
+ - `JhLayout` 的 `content-padding` 设置为 `false`,避免与 `JhPageContainer` 的内边距重复
303
+ - `JhLayout` 的 `show-page-header` 设置为 `false`,使用 `JhPageContainer` 的页面标题
304
+ - `JhLayout` 提供应用级导航和面包屑
305
+ - `JhPageContainer` 提供页面级标题和搜索栏
306
+
307
+ ## 内置全局组件
308
+
309
+ `JhPageContainer` 内置了以下全局组件,无需额外引入:
310
+
311
+ - **JhToast**: 消息提示组件
312
+ - **JhMask**: 遮罩层组件
313
+ - **JhConfirmDialog**: 确认对话框组件
314
+
315
+ 这些组件可以在页面的任何地方通过事件总线或全局方法调用。
316
+
317
+ ## 响应式设计
318
+
319
+ 组件会自动适配不同屏幕尺寸:
320
+
321
+ - **桌面端(>= 960px)**: 搜索栏在右侧,与标题同行
322
+ - **移动端(< 960px)**: 搜索栏在标题下方,独占一行
323
+
324
+ ## 样式定制
325
+
326
+ 组件使用 Vuetify 的样式系统,可以通过以下方式定制:
327
+
328
+ ```vue
329
+ <jh-page-container page-name="用户管理">
330
+ <template v-slot:search-bar>
331
+ <div class="custom-search-bar">
332
+ <!-- 自定义样式的搜索栏 -->
333
+ </div>
334
+ </template>
335
+ </jh-page-container>
336
+
337
+ <style scoped>
338
+ .custom-search-bar {
339
+ /* 自定义样式 */
340
+ }
341
+ </style>
342
+ ```
343
+
344
+ ## 最佳实践
345
+
346
+ 1. **标题命名**: 使用清晰、简洁的页面标题,便于用户理解当前页面功能
347
+ 2. **帮助按钮**: 对于复杂页面,建议显示帮助按钮,提供操作指引
348
+ 3. **搜索栏**: 列表页面建议使用搜索栏,提供快速过滤功能
349
+ 4. **内容区域**: 主要内容建议使用卡片或表格组件,保持视觉一致性
350
+ 5. **与 JhLayout 配合**: 使用 JhLayout 时,注意避免重复的内边距和头部
351
+
352
+ ## 常见问题
353
+
354
+ ### 如何隐藏帮助按钮?
355
+
356
+ 设置 `show-help-button` 为 `false`:
357
+
358
+ ```vue
359
+ <jh-page-container
360
+ page-name="用户管理"
361
+ :show-help-button="false"
362
+ >
363
+ </jh-page-container>
364
+ ```
365
+
366
+ ### 如何自定义页面标题样式?
367
+
368
+ 页面标题使用 Vuetify 的 `text-body-1` 和 `font-weight-bold` 类,可以通过全局样式覆盖:
369
+
370
+ ```css
371
+ .jh-page-second-bar .text-body-1 {
372
+ font-size: 18px !important;
373
+ color: #333 !important;
374
+ }
375
+ ```
376
+
377
+ ### 可以不使用 JhLayout 吗?
378
+
379
+ 可以。`JhPageContainer` 内置了 `v-app` 和 `v-main`,可以独立使用。但推荐与 `JhLayout` 配合使用,以获得完整的应用布局。
380
+
381
+ ### 如何在内容区域添加多个卡片?
382
+
383
+ 使用 Vuetify 的栅格系统:
384
+
385
+ ```vue
386
+ <jh-page-container page-name="仪表盘">
387
+ <template v-slot:content>
388
+ <v-row>
389
+ <v-col cols="12" md="6">
390
+ <v-card>
391
+ <!-- 卡片 1 -->
392
+ </v-card>
393
+ </v-col>
394
+ <v-col cols="12" md="6">
395
+ <v-card>
396
+ <!-- 卡片 2 -->
397
+ </v-card>
398
+ </v-col>
399
+ </v-row>
400
+ </template>
401
+ </jh-page-container>
402
+ ```
403
+
404
+ ## 参考资料
405
+
406
+ - [JhLayout - 页面布局组件](../JhLayout/JhLayout.md)
407
+ - [JhTable - 数据表格组件](../JhTable/JhTable.md)
408
+ - [JhQueryFilter - 查询过滤组件](../JhQueryFilter/README.md)
409
+ - [Vuetify - Application](https://vuetifyjs.com/en/components/application/)