sohelp-eleplus 1.1.27 → 1.1.28

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 (202) hide show
  1. package/components.js +1 -0
  2. package/package.json +2 -2
  3. package/sohelp-ace-editor/README.md +32 -42
  4. package/sohelp-ace-editor/index.vue +166 -156
  5. package/sohelp-api-doc/README.md +36 -0
  6. package/sohelp-api-doc/index.vue +160 -0
  7. package/sohelp-application-select/README.md +9 -7
  8. package/sohelp-application-select/index.vue +10 -13
  9. package/sohelp-autocode/README.md +14 -26
  10. package/sohelp-calendar-view/README.md +9 -7
  11. package/sohelp-calendar-view/index.vue +10 -9
  12. package/sohelp-card/README.md +15 -17
  13. package/sohelp-card/index.vue +1 -1
  14. package/sohelp-card-view/README.md +9 -7
  15. package/sohelp-card-view/index.vue +10 -9
  16. package/sohelp-condition/README.md +29 -49
  17. package/sohelp-condition/index.vue +2 -1
  18. package/sohelp-country-select/README.md +15 -123
  19. package/sohelp-cry-input/README.md +19 -195
  20. package/sohelp-cry-input/index.vue +5 -1
  21. package/sohelp-date/README.md +12 -15
  22. package/sohelp-datetime/README.md +15 -17
  23. package/sohelp-datetime-picker/README.md +18 -18
  24. package/sohelp-datetime-picker/index.vue +11 -4
  25. package/sohelp-datetime-range/README.md +20 -23
  26. package/sohelp-demo-block/README.md +43 -0
  27. package/sohelp-demo-block/index.vue +229 -0
  28. package/sohelp-dict/README.md +28 -23
  29. package/sohelp-dict/index.vue +17 -17
  30. package/sohelp-drawer/README.md +28 -26
  31. package/sohelp-drop-card/README.md +29 -28
  32. package/sohelp-drop-card/index.vue +0 -1
  33. package/sohelp-dyn-select/README.md +31 -16
  34. package/sohelp-dyn-select/index.vue +65 -67
  35. package/sohelp-dyn-tree/README.md +26 -20
  36. package/sohelp-dyn-tree/index.vue +2 -2
  37. package/sohelp-dyn-tree-select/README.md +28 -19
  38. package/sohelp-dyn-tree-select/index.vue +23 -7
  39. package/sohelp-entity-form/README.md +65 -30
  40. package/sohelp-entity-form/index.vue +3 -2
  41. package/sohelp-entity-grid/README.md +13 -11
  42. package/sohelp-entity-grid/index.vue +1 -1
  43. package/sohelp-file-upload/README.md +25 -27
  44. package/sohelp-file-upload/index.vue +1 -1
  45. package/sohelp-filter-scheme/README.md +34 -30
  46. package/sohelp-filter-scheme/index.vue +2 -2
  47. package/sohelp-grid/README.md +52 -33
  48. package/sohelp-grid/index.vue +2217 -2210
  49. package/sohelp-grid/js/SohelpGridConfig.js +3 -3
  50. package/sohelp-grid/js/useSohelpGridConfig.js +641 -642
  51. package/sohelp-grid-select/README.md +32 -27
  52. package/sohelp-grid-select/index.vue +6 -5
  53. package/sohelp-grid-view/README.md +51 -22
  54. package/sohelp-grid-view-select/README.md +33 -25
  55. package/sohelp-grid-view-select/index.vue +2 -1
  56. package/sohelp-group-view/README.md +14 -4
  57. package/sohelp-group-view/index.vue +10 -9
  58. package/sohelp-icon-select/README.md +14 -12
  59. package/sohelp-image-upload/README.md +27 -27
  60. package/sohelp-image-upload/index.vue +2 -2
  61. package/sohelp-import/README.md +25 -24
  62. package/sohelp-input/README.md +27 -11
  63. package/sohelp-input/index.vue +15 -2
  64. package/sohelp-input-tag/README.md +53 -0
  65. package/sohelp-input-tag/index.vue +337 -0
  66. package/sohelp-modal/README.md +42 -16
  67. package/sohelp-modal/index.vue +21 -4
  68. package/sohelp-modal-select/README.md +745 -0
  69. package/sohelp-modal-select/index.vue +705 -0
  70. package/sohelp-module/README.md +24 -13
  71. package/sohelp-number-input/README.md +15 -8
  72. package/sohelp-number-input/index.vue +3 -0
  73. package/sohelp-number-range/README.md +22 -12
  74. package/sohelp-number-range/index.vue +3 -11
  75. package/sohelp-org-modal-select/README.md +47 -0
  76. package/sohelp-org-modal-select/index.vue +411 -0
  77. package/sohelp-org-select/README.md +23 -10
  78. package/sohelp-org-select/index.vue +41 -24
  79. package/sohelp-org-tree/README.md +19 -7
  80. package/sohelp-org-tree/index.vue +1 -2
  81. package/sohelp-org-tree-select/README.md +22 -11
  82. package/sohelp-org-tree-select/index.vue +1 -2
  83. package/sohelp-org-user-tree/README.md +19 -7
  84. package/sohelp-org-user-tree/index.vue +1 -2
  85. package/sohelp-org-user-tree-select/README.md +8 -3
  86. package/sohelp-org-user-tree-select/index.vue +8 -7
  87. package/sohelp-page/README.md +20 -11
  88. package/sohelp-page/index.vue +1 -1
  89. package/sohelp-pagination/README.md +14 -6
  90. package/sohelp-pagination/index.vue +1 -1
  91. package/sohelp-power/README.md +34 -19
  92. package/sohelp-power/index.vue +2 -2
  93. package/sohelp-pro-form/README.md +64 -21
  94. package/sohelp-pro-layout/README.md +10 -4
  95. package/sohelp-pro-layout/index.vue +8 -7
  96. package/sohelp-pro-table/README.md +30 -6
  97. package/sohelp-process/README.md +26 -13
  98. package/sohelp-process/index.vue +6 -6
  99. package/sohelp-rate/README.md +24 -12
  100. package/sohelp-rate/index.vue +5 -1
  101. package/sohelp-relation/README.md +10 -4
  102. package/sohelp-relation/index.vue +8 -7
  103. package/sohelp-relation-modal-select/README.md +41 -0
  104. package/sohelp-relation-modal-select/index.vue +70 -0
  105. package/sohelp-rich-text/README.md +29 -11
  106. package/sohelp-rich-text/index.vue +21 -20
  107. package/sohelp-richtext/README.md +12 -2
  108. package/sohelp-richtext/index.vue +8 -6
  109. package/sohelp-role-modal-select/README.md +45 -0
  110. package/sohelp-role-modal-select/index.vue +111 -0
  111. package/sohelp-role-select/README.md +18 -10
  112. package/sohelp-role-select/index.vue +36 -27
  113. package/sohelp-search/README.md +12 -4
  114. package/sohelp-search/index.vue +2 -2
  115. package/sohelp-search-pro-form/README.md +15 -1
  116. package/sohelp-search-pro-form/index.vue +2 -1
  117. package/sohelp-select/README.md +31 -30
  118. package/sohelp-select/index.vue +79 -84
  119. package/sohelp-split-panel/README.md +17 -18
  120. package/sohelp-switch/README.md +21 -19
  121. package/sohelp-switch/index.vue +34 -33
  122. package/sohelp-table/README.md +35 -27
  123. package/sohelp-table/index.vue +110 -109
  124. package/sohelp-table-select/README.md +55 -0
  125. package/sohelp-tenant-select/README.md +19 -18
  126. package/sohelp-tenant-select/index.vue +105 -109
  127. package/sohelp-text/README.md +16 -10
  128. package/sohelp-text/index.vue +5 -5
  129. package/sohelp-textarea-input/README.md +19 -12
  130. package/sohelp-time/README.md +11 -10
  131. package/sohelp-tree/README.md +24 -19
  132. package/sohelp-tree/index.vue +21 -23
  133. package/sohelp-tree-select/README.md +23 -10
  134. package/sohelp-user-modal-select/README.md +739 -0
  135. package/sohelp-user-modal-select/index.vue +87 -0
  136. package/sohelp-user-select/README.md +26 -15
  137. package/sohelp-user-select/index.vue +6 -2
  138. package/sohelp-user-tag/README.md +5 -7
  139. package/sohelp-user-tag/index.vue +8 -8
  140. package/sohelp-user-tree/README.md +5 -8
  141. package/sohelp-user-tree/index.vue +8 -7
  142. package/sohelp-vform-drawer/README.md +36 -18
  143. package/sohelp-vform-drawer/index.vue +2 -2
  144. package/sohelp-vform-eleplus/README.md +33 -31
  145. package/sohelp-vform-eleplus/index.vue +2 -2
  146. package/sohelp-vform-eleplus/tinymce/langs/zh_CN.js +461 -461
  147. package/sohelp-vform-eleplus/tinymce/langs/zh_TW.js +418 -418
  148. package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.css +72 -72
  149. package/sohelp-vform-eleplus/tinymce/skins/content/dark/content.min.css +7 -7
  150. package/sohelp-vform-eleplus/tinymce/skins/content/default/content.css +67 -67
  151. package/sohelp-vform-eleplus/tinymce/skins/content/default/content.min.css +7 -7
  152. package/sohelp-vform-eleplus/tinymce/skins/content/document/content.css +72 -72
  153. package/sohelp-vform-eleplus/tinymce/skins/content/document/content.min.css +7 -7
  154. package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.css +68 -68
  155. package/sohelp-vform-eleplus/tinymce/skins/content/writer/content.min.css +7 -7
  156. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.css +732 -732
  157. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.css +726 -726
  158. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.inline.min.css +7 -7
  159. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.min.css +7 -7
  160. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.css +29 -29
  161. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/content.mobile.min.css +7 -7
  162. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.css +3047 -3047
  163. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.min.css +7 -7
  164. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.css +673 -673
  165. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.mobile.min.css +7 -7
  166. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.css +37 -37
  167. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide/skin.shadowdom.min.css +7 -7
  168. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.css +714 -714
  169. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.css +726 -726
  170. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.inline.min.css +7 -7
  171. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.min.css +7 -7
  172. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.css +29 -29
  173. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/content.mobile.min.css +7 -7
  174. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.css +3047 -3047
  175. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.min.css +7 -7
  176. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.css +673 -673
  177. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.mobile.min.css +7 -7
  178. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.css +37 -37
  179. package/sohelp-vform-eleplus/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css +7 -7
  180. package/sohelp-vform-modal/README.md +36 -18
  181. package/sohelp-vform-modal/index.vue +2 -2
  182. package/sohelp-vform-select/README.md +9 -7
  183. package/sohelp-vform-select/index.vue +8 -7
  184. package/sohelp-vxe-grid/DefaultGridOptions.js +5 -3
  185. package/sohelp-vxe-grid/DefaultProps.js +0 -1
  186. package/sohelp-vxe-grid/README.md +540 -35
  187. package/sohelp-vxe-grid/SohelpGridConfig.js +8 -6
  188. package/sohelp-vxe-grid/index.vue +141 -94
  189. package/sohelp-vxe-grid-select/README.md +41 -26
  190. package/sohelp-vxe-table/README.md +23 -20
  191. package/sohelp-vxe-table/index.vue +5 -4
  192. package/sohelp-workflow/README.md +21 -17
  193. package/sohelp-workflow/index.vue +25 -22
  194. package/sohelp-workflow-drawer/README.md +41 -28
  195. package/sohelp-workflow-drawer/components/table.vue +158 -158
  196. package/sohelp-workflow-drawer/index.vue +86 -71
  197. package/sohelp-workflow-drawer/js/index.js +15 -13
  198. package/style/index.scss +0 -0
  199. package/utils/safe-eval.js +89 -0
  200. package/sohelp-dyn-select/props.js +0 -67
  201. package/sohelp-user-select/index.vue~ +0 -53
  202. package/sohelp-user-select/props.js +0 -71
@@ -0,0 +1,739 @@
1
+ # SohelpUserModalSelect 用户选择器
2
+
3
+ 基于 `sohelp-modal-select` 封装的用户选择组件,预置了用户列表接口和列配置,支持单选/多选用户。开箱即用,无需手动配置表格列。
4
+
5
+ ## ✨ 特性
6
+
7
+ - 🎯 **开箱即用** - 预置用户接口和列配置
8
+ - 🔍 **内置搜索** - 支持用户名、登录名、昵称搜索
9
+ - 📊 **分页加载** - 默认每页 5 条数据
10
+ - 🎨 **灵活显示** - 默认显示格式:`${user_name}-${login_name}`
11
+ - ⚙️ **可自定义** - 支持覆盖默认接口和列配置
12
+ - 🔄 **双向绑定** - 完整的 v-model 和 v-model:data 支持
13
+ - 🪝 **钩子函数** - 支持 beforeOpen、confirm 等回调
14
+
15
+ ## 📖 基础用法
16
+
17
+ ### 多选用户
18
+
19
+ ```vue
20
+ <template>
21
+ <sohelp-user-modal-select
22
+ v-model="selectedUserIds"
23
+ v-model:data="selectedUserData"
24
+ multiple
25
+ placeholder="请选择用户"
26
+ />
27
+ </template>
28
+
29
+ <script setup>
30
+ import { ref } from 'vue';
31
+
32
+ const selectedUserIds = ref([]);
33
+ const selectedUserData = ref([]);
34
+ </script>
35
+ ```
36
+
37
+ ### 单选用户
38
+
39
+ ```vue
40
+ <template>
41
+ <sohelp-user-modal-select
42
+ v-model="selectedUserId"
43
+ v-model:data="selectedUserData"
44
+ :multiple="false"
45
+ placeholder="请选择用户"
46
+ />
47
+ </template>
48
+
49
+ <script setup>
50
+ import { ref } from 'vue';
51
+
52
+ const selectedUserId = ref('');
53
+ const selectedUserData = ref({});
54
+ </script>
55
+ ```
56
+
57
+ ### 自定义弹窗标题和宽度
58
+
59
+ ```vue
60
+ <template>
61
+ <sohelp-user-modal-select
62
+ v-model="selectedUserIds"
63
+ v-model:data="selectedUserData"
64
+ :modalProps="{
65
+ title: '选择审批人',
66
+ width: '900px',
67
+ minHeight: 600
68
+ }"
69
+ placeholder="请选择审批人"
70
+ />
71
+ </template>
72
+
73
+ <script setup>
74
+ import { ref } from 'vue';
75
+
76
+ const selectedUserIds = ref([]);
77
+ const selectedUserData = ref([]);
78
+ </script>
79
+ ```
80
+
81
+ ### 自定义显示格式
82
+
83
+ ```vue
84
+ <template>
85
+ <sohelp-user-modal-select
86
+ v-model="selectedUserIds"
87
+ v-model:data="selectedUserData"
88
+ selectionTemplate="${user_name} (${nickname})"
89
+ placeholder="请选择用户"
90
+ />
91
+ </template>
92
+
93
+ <script setup>
94
+ import { ref } from 'vue';
95
+
96
+ const selectedUserIds = ref([]);
97
+ const selectedUserData = ref([]);
98
+ </script>
99
+ ```
100
+
101
+ ### 自定义字段
102
+
103
+ ```vue
104
+ <template>
105
+ <sohelp-user-modal-select
106
+ v-model="selectedUserIds"
107
+ v-model:data="selectedUserData"
108
+ :labelField="nickname"
109
+ :valueField="user_id"
110
+ selectionTemplate="${nickname}"
111
+ placeholder="请选择用户"
112
+ />
113
+ </template>
114
+
115
+ <script setup>
116
+ import { ref } from 'vue';
117
+
118
+ const selectedUserIds = ref([]);
119
+ const selectedUserData = ref([]);
120
+ </script>
121
+ ```
122
+
123
+ ### 覆盖默认接口和列配置
124
+
125
+ ```vue
126
+ <template>
127
+ <sohelp-user-modal-select
128
+ v-model="selectedUserIds"
129
+ v-model:data="selectedUserData"
130
+ :gridProps="{
131
+ url: '/api/custom/user/page',
132
+ gridOptions: {
133
+ columns: [
134
+ { field: 'user_name', title: '姓名', width: 150 },
135
+ { field: 'login_name', title: '登录名', width: 180 },
136
+ { field: 'nickname', title: '昵称', width: 150 },
137
+ { field: 'email', title: '邮箱', width: 200 },
138
+ { field: 'phone', title: '手机号', width: 150 }
139
+ ],
140
+ pagerConfig: {
141
+ pageSize: 10
142
+ }
143
+ }
144
+ }"
145
+ placeholder="请选择用户"
146
+ />
147
+ </template>
148
+
149
+ <script setup>
150
+ import { ref } from 'vue';
151
+
152
+ const selectedUserIds = ref([]);
153
+ const selectedUserData = ref([]);
154
+ </script>
155
+ ```
156
+
157
+ ### 使用钩子函数
158
+
159
+ ```vue
160
+ <template>
161
+ <sohelp-user-modal-select
162
+ v-model="selectedUserIds"
163
+ v-model:data="selectedUserData"
164
+ :beforeOpen="handleBeforeOpen"
165
+ @confirm="handleConfirm"
166
+ placeholder="请选择用户"
167
+ />
168
+ </template>
169
+
170
+ <script setup>
171
+ import { ref } from 'vue';
172
+ import { ElMessage } from 'element-plus';
173
+
174
+ const selectedUserIds = ref([]);
175
+ const selectedUserData = ref([]);
176
+
177
+ // 打开前钩子
178
+ const handleBeforeOpen = (modelValue, data) => {
179
+ console.log('当前选中用户:', data);
180
+ // 可以在这里做一些校验或数据预处理
181
+ return true;
182
+ };
183
+
184
+ // 确认事件
185
+ const handleConfirm = (selectedIds, selectedData) => {
186
+ ElMessage.success(`已选择 ${selectedIds.length} 个用户`);
187
+ console.log('选中的用户:', selectedData);
188
+ };
189
+ </script>
190
+ ```
191
+
192
+ ### 表单验证场景
193
+
194
+ ```vue
195
+ <template>
196
+ <el-form :model="form" :rules="rules" ref="formRef">
197
+ <el-form-item label="审批人" prop="approverIds">
198
+ <sohelp-user-modal-select
199
+ v-model="form.approverIds"
200
+ v-model:data="form.approverData"
201
+ :modalProps="{ title: '选择审批人' }"
202
+ placeholder="请选择审批人"
203
+ />
204
+ </el-form-item>
205
+
206
+ <el-form-item label="抄送人" prop="ccIds">
207
+ <sohelp-user-modal-select
208
+ v-model="form.ccIds"
209
+ v-model:data="form.ccData"
210
+ multiple
211
+ placeholder="请选择抄送人"
212
+ />
213
+ </el-form-item>
214
+
215
+ <el-form-item>
216
+ <el-button type="primary" @click="submitForm">提交</el-button>
217
+ </el-form-item>
218
+ </el-form>
219
+ </template>
220
+
221
+ <script setup>
222
+ import { ref } from 'vue';
223
+
224
+ const formRef = ref(null);
225
+ const form = ref({
226
+ approverIds: '',
227
+ approverData: {},
228
+ ccIds: [],
229
+ ccData: []
230
+ });
231
+
232
+ const rules = {
233
+ approverIds: [
234
+ { required: true, message: '请选择审批人', trigger: 'change' }
235
+ ],
236
+ ccIds: [
237
+ { type: 'array', required: true, message: '请选择抄送人', trigger: 'change' }
238
+ ]
239
+ };
240
+
241
+ const submitForm = async () => {
242
+ await formRef.value?.validate();
243
+ console.log('提交表单:', form.value);
244
+ };
245
+ </script>
246
+ ```
247
+
248
+ ### 数据回显场景
249
+
250
+ ```vue
251
+ <template>
252
+ <sohelp-user-modal-select
253
+ v-model="form.approverIds"
254
+ v-model:data="form.approverData"
255
+ placeholder="请选择审批人"
256
+ />
257
+ </template>
258
+
259
+ <script setup>
260
+ import { ref, onMounted } from 'vue';
261
+
262
+ const form = ref({
263
+ approverIds: '',
264
+ approverData: {}
265
+ });
266
+
267
+ // 模拟从后端加载数据
268
+ onMounted(async () => {
269
+ const response = await fetch('/api/approval/detail');
270
+ const data = await response.json();
271
+
272
+ form.value.approverIds = data.approverId;
273
+ form.value.approverData = {
274
+ id: data.approverId,
275
+ user_name: data.approverName,
276
+ login_name: data.approverLoginName
277
+ };
278
+
279
+ // 组件会自动回显
280
+ });
281
+ </script>
282
+ ```
283
+
284
+ ### 禁用/只读状态
285
+
286
+ ```vue
287
+ <template>
288
+ <div>
289
+ <!-- 禁用 -->
290
+ <sohelp-user-modal-select
291
+ v-model="selectedUserIds"
292
+ v-model:data="selectedUserData"
293
+ disabled
294
+ placeholder="禁用状态"
295
+ />
296
+
297
+ <!-- 只读 -->
298
+ <sohelp-user-modal-select
299
+ v-model="selectedUserIds"
300
+ v-model:data="selectedUserData"
301
+ readonly
302
+ placeholder="只读状态"
303
+ />
304
+ </div>
305
+ </template>
306
+
307
+ <script setup>
308
+ import { ref } from 'vue';
309
+
310
+ const selectedUserIds = ref([]);
311
+ const selectedUserData = ref([]);
312
+ </script>
313
+ ```
314
+
315
+ ### 动态过滤用户
316
+
317
+ ```vue
318
+ <template>
319
+ <div>
320
+ <el-select v-model="deptId" placeholder="请选择部门" style="width: 200px; margin-right: 10px;">
321
+ <el-option label="全部" value="" />
322
+ <el-option label="技术部" value="1" />
323
+ <el-option label="市场部" value="2" />
324
+ <el-option label="销售部" value="3" />
325
+ </el-select>
326
+
327
+ <sohelp-user-modal-select
328
+ v-model="selectedUserIds"
329
+ v-model:data="selectedUserData"
330
+ :gridProps="dynamicGridProps"
331
+ placeholder="请选择用户"
332
+ />
333
+ </div>
334
+ </template>
335
+
336
+ <script setup>
337
+ import { ref, computed } from 'vue';
338
+
339
+ const deptId = ref('');
340
+ const selectedUserIds = ref([]);
341
+ const selectedUserData = ref([]);
342
+
343
+ const dynamicGridProps = computed(() => ({
344
+ url: deptId.value ? `/api/user/page?deptId=${deptId.value}` : '/admin/system/user/page',
345
+ gridOptions: {
346
+ columns: [
347
+ { field: 'user_name', title: '姓名', width: 120 },
348
+ { field: 'login_name', title: '登录名', width: 180 },
349
+ { field: 'nickname', title: '昵称', width: 120 }
350
+ ]
351
+ }
352
+ }));
353
+ </script>
354
+ ```
355
+
356
+ ### 清空选中
357
+
358
+ ```vue
359
+ <template>
360
+ <div>
361
+ <sohelp-user-modal-select
362
+ ref="userSelectRef"
363
+ v-model="selectedUserIds"
364
+ v-model:data="selectedUserData"
365
+ placeholder="请选择用户"
366
+ />
367
+
368
+ <el-button @click="clearSelection">清空选中</el-button>
369
+ </div>
370
+ </template>
371
+
372
+ <script setup>
373
+ import { ref } from 'vue';
374
+
375
+ const userSelectRef = ref(null);
376
+ const selectedUserIds = ref([]);
377
+ const selectedUserData = ref([]);
378
+
379
+ const clearSelection = () => {
380
+ userSelectRef.value?.clearAll();
381
+ };
382
+ </script>
383
+ ```
384
+
385
+ ## 📋 属性 (Props)
386
+
387
+ | 属性名 | 类型 | 默认值 | 必填 | 说明 |
388
+ | --- | --- | --- | --- | --- |
389
+ | modelValue (v-model) | String / Array | - | 否 | 选中用户的 ID 值 |
390
+ | data (v-model:data) | Array / Object | - | 否 | 选中用户的完整数据 |
391
+ | valueField | String | `'id'` | 否 | 值字段名 |
392
+ | labelField | String | `'user_name'` | 否 | 显示字段名 |
393
+ | multiple | Boolean | `true` | 否 | 是否多选 |
394
+ | selectionTemplate | String | `'${user_name}-${login_name}'` | 否 | 已选列表的显示模板 |
395
+ | modalProps | Object | `{}` | 否 | 传递给弹窗的属性配置 |
396
+ | gridProps | Object | `{}` | 否 | 传递给表格的属性配置 |
397
+
398
+ ### 默认配置
399
+
400
+ ```javascript
401
+ // 默认接口
402
+ url: '/admin/system/user/page'
403
+
404
+ // 默认列配置
405
+ columns: [
406
+ { field: 'user_name', title: '用户姓名', width: 120 },
407
+ { field: 'login_name', title: '登录账户', width: 200 },
408
+ { field: 'nickname', title: '昵称', width: 120 }
409
+ ]
410
+
411
+ // 默认分页
412
+ pageSize: 5
413
+
414
+ // 默认弹窗
415
+ title: '选择用户'
416
+ width: 800
417
+
418
+ // 默认字段
419
+ valueField: 'id'
420
+ labelField: 'user_name'
421
+ selectionTemplate: '${user_name}-${login_name}'
422
+ ```
423
+
424
+ ## 🔄 双向绑定 (v-model)
425
+
426
+ | 属性名 | 类型 | 说明 |
427
+ | --- | --- | --- |
428
+ | modelValue | String / Array | 选中用户的 ID 值,多选时为数组,单选时为字符串 |
429
+ | data | Array / Object | 选中用户的完整数据对象,多选时为数组,单选时为对象 |
430
+
431
+ ## 🎯 事件 (Events)
432
+
433
+ | 事件名 | 回调参数 | 说明 |
434
+ | --- | --- | --- |
435
+ | update:modelValue | `(selectedIds)` | 选中值变化时触发 |
436
+ | confirm | `(selectedIds, selectedData)` | 点击确认后触发 |
437
+ | page-change | `(pageInfo)` | 分页变化时触发 |
438
+
439
+ ## 🔧 方法 (Methods)
440
+
441
+ 通过 `ref` 可以调用以下方法:
442
+
443
+ | 方法名 | 参数 | 返回值 | 说明 |
444
+ | --- | --- | --- | --- |
445
+ | clearAll | - | - | 清空所有选中数据 |
446
+
447
+ ## 📝 数据结构
448
+
449
+ ### 选中数据对象(单选)
450
+
451
+ ```javascript
452
+ {
453
+ id: '1',
454
+ user_name: '张三',
455
+ login_name: 'zhangsan',
456
+ nickname: '张三'
457
+ }
458
+ ```
459
+
460
+ ### 选中数据数组(多选)
461
+
462
+ ```javascript
463
+ [
464
+ {
465
+ id: '1',
466
+ user_name: '张三',
467
+ login_name: 'zhangsan',
468
+ nickname: '张三'
469
+ },
470
+ {
471
+ id: '2',
472
+ user_name: '李四',
473
+ login_name: 'lisi',
474
+ nickname: '李四'
475
+ }
476
+ ]
477
+ ```
478
+
479
+ ## 🎯 最佳实践
480
+
481
+ ### 1. 审批流程场景
482
+
483
+ ```vue
484
+ <template>
485
+ <el-form :model="form">
486
+ <el-form-item label="申请人">
487
+ <el-input v-model="form.applicantName" disabled />
488
+ </el-form-item>
489
+
490
+ <el-form-item label="审批人">
491
+ <sohelp-user-modal-select
492
+ v-model="form.approverId"
493
+ v-model:data="form.approverData"
494
+ :multiple="false"
495
+ :modalProps="{ title: '选择审批人' }"
496
+ placeholder="请选择审批人"
497
+ />
498
+ </el-form-item>
499
+
500
+ <el-form-item label="抄送人">
501
+ <sohelp-user-modal-select
502
+ v-model="form.ccIds"
503
+ v-model:data="form.ccData"
504
+ :modalProps="{ title: '选择抄送人' }"
505
+ placeholder="请选择抄送人"
506
+ />
507
+ </el-form-item>
508
+ </el-form>
509
+ </template>
510
+
511
+ <script setup>
512
+ import { ref } from 'vue';
513
+
514
+ const form = ref({
515
+ applicantName: '张三',
516
+ approverId: '',
517
+ approverData: {},
518
+ ccIds: [],
519
+ ccData: []
520
+ });
521
+ </script>
522
+ ```
523
+
524
+ ### 2. 团队管理场景
525
+
526
+ ```vue
527
+ <template>
528
+ <el-form :model="form">
529
+ <el-form-item label="团队名称">
530
+ <el-input v-model="form.teamName" placeholder="请输入团队名称" />
531
+ </el-form-item>
532
+
533
+ <el-form-item label="团队负责人">
534
+ <sohelp-user-modal-select
535
+ v-model="form.leaderId"
536
+ v-model:data="form.leaderData"
537
+ :multiple="false"
538
+ selectionTemplate="${user_name} (${nickname})"
539
+ placeholder="请选择团队负责人"
540
+ />
541
+ </el-form-item>
542
+
543
+ <el-form-item label="团队成员">
544
+ <sohelp-user-modal-select
545
+ v-model="form.memberIds"
546
+ v-model:data="form.memberData"
547
+ :gridProps="{
548
+ gridOptions: {
549
+ pagerConfig: {
550
+ pageSize: 10
551
+ }
552
+ }
553
+ }"
554
+ placeholder="请选择团队成员"
555
+ />
556
+ </el-form-item>
557
+ </el-form>
558
+ </template>
559
+
560
+ <script setup>
561
+ import { ref } from 'vue';
562
+
563
+ const form = ref({
564
+ teamName: '',
565
+ leaderId: '',
566
+ leaderData: {},
567
+ memberIds: [],
568
+ memberData: []
569
+ });
570
+ </script>
571
+ ```
572
+
573
+ ### 3. 权限分配场景
574
+
575
+ ```vue
576
+ <template>
577
+ <el-form :model="form">
578
+ <el-form-item label="角色名称">
579
+ <el-input v-model="form.roleName" placeholder="请输入角色名称" />
580
+ </el-form-item>
581
+
582
+ <el-form-item label="角色管理员">
583
+ <sohelp-user-modal-select
584
+ v-model="form.adminIds"
585
+ v-model:data="form.adminData"
586
+ :modalProps="{ title: '选择角色管理员' }"
587
+ placeholder="请选择角色管理员"
588
+ />
589
+ </el-form-item>
590
+ </el-form>
591
+ </template>
592
+
593
+ <script setup>
594
+ import { ref } from 'vue';
595
+
596
+ const form = ref({
597
+ roleName: '',
598
+ adminIds: [],
599
+ adminData: []
600
+ });
601
+ </script>
602
+ ```
603
+
604
+ ## ❓ 常见问题
605
+
606
+ ### Q1: 如何修改默认的列配置?
607
+
608
+ **A**: 通过 `gridProps.gridOptions.columns` 覆盖默认配置:
609
+
610
+ ```vue
611
+ <sohelp-user-modal-select
612
+ v-model="selectedIds"
613
+ v-model:data="selectedData"
614
+ :gridProps="{
615
+ gridOptions: {
616
+ columns: [
617
+ { field: 'user_name', title: '姓名', width: 150 },
618
+ { field: 'login_name', title: '登录名', width: 180 },
619
+ { field: 'email', title: '邮箱', width: 200 },
620
+ { field: 'phone', title: '手机号', width: 150 }
621
+ ]
622
+ }
623
+ }"
624
+ />
625
+ ```
626
+
627
+ ### Q2: 如何修改默认的分页大小?
628
+
629
+ **A**: 通过 `gridProps.gridOptions.pagerConfig.pageSize` 设置:
630
+
631
+ ```vue
632
+ <sohelp-user-modal-select
633
+ v-model="selectedIds"
634
+ v-model:data="selectedData"
635
+ :gridProps="{
636
+ gridOptions: {
637
+ pagerConfig: {
638
+ pageSize: 20
639
+ }
640
+ }
641
+ }"
642
+ />
643
+ ```
644
+
645
+ ### Q3: 如何修改默认的接口地址?
646
+
647
+ **A**: 通过 `gridProps.url` 覆盖:
648
+
649
+ ```vue
650
+ <sohelp-user-modal-select
651
+ v-model="selectedIds"
652
+ v-model:data="selectedData"
653
+ :gridProps="{
654
+ url: '/api/custom/user/page'
655
+ }"
656
+ />
657
+ ```
658
+
659
+ ### Q4: 单选和多选有什么区别?
660
+
661
+ **A**:
662
+ - 单选:`multiple="false"`,`modelValue` 为字符串,弹窗显示 radio 列
663
+ - 多选:`multiple="true"`(默认),`modelValue` 为数组,弹窗显示 checkbox 列和已选列表
664
+
665
+ ### Q5: 如何实现按部门筛选用户?
666
+
667
+ **A**: 使用计算属性动态修改 `gridProps.url`:
668
+
669
+ ```vue
670
+ <script setup>
671
+ import { ref, computed } from 'vue';
672
+
673
+ const deptId = ref('1');
674
+ const selectedIds = ref([]);
675
+ const selectedData = ref([]);
676
+
677
+ const dynamicGridProps = computed(() => ({
678
+ url: `/api/user/page?deptId=${deptId.value}`,
679
+ gridOptions: {
680
+ columns: [
681
+ { field: 'user_name', title: '姓名' },
682
+ { field: 'login_name', title: '登录名' }
683
+ ]
684
+ }
685
+ }));
686
+ </script>
687
+ ```
688
+
689
+ ### Q6: 为什么显示格式是 `${user_name}-${login_name}`?
690
+
691
+ **A**: 这是组件的默认配置,通过 `selectionTemplate` 属性设置。你可以自定义:
692
+
693
+ ```vue
694
+ <sohelp-user-modal-select
695
+ v-model="selectedIds"
696
+ v-model:data="selectedData"
697
+ selectionTemplate="${nickname}"
698
+ placeholder="请选择用户"
699
+ />
700
+ ```
701
+
702
+ ### Q7: 如何限制只能选择一定数量的用户?
703
+
704
+ **A**: 使用 `beforeOpen` 钩子:
705
+
706
+ ```vue
707
+ <script setup>
708
+ const MAX_USERS = 10;
709
+
710
+ const handleBeforeOpen = (modelValue, data) => {
711
+ const currentCount = Array.isArray(modelValue) ? modelValue.length : 0;
712
+ if (currentCount >= MAX_USERS) {
713
+ ElMessage.warning(`最多只能选择 ${MAX_USERS} 个用户`);
714
+ return false;
715
+ }
716
+ return true;
717
+ };
718
+ </script>
719
+ ```
720
+
721
+ ## 🔗 相关组件
722
+
723
+ - [sohelp-modal-select](../sohelp-modal-select/README.md) - 弹窗选择器(通用)
724
+ - [sohelp-vxe-grid](../sohelp-vxe-grid/README.md) - 数据网格组件
725
+ - [sohelp-modal](../sohelp-modal/README.md) - 弹窗组件
726
+
727
+ ## 📝 更新日志
728
+
729
+ ### v1.2.0
730
+ - ✨ 优化默认显示格式为 `${user_name}-${login_name}`
731
+ - ✨ 改进数据回显逻辑
732
+ - 🐛 修复取消操作后数据一致性问题
733
+
734
+ ### v1.1.0
735
+ - ✨ 支持自定义 `selectionTemplate`
736
+ - ✨ 支持自定义字段配置
737
+
738
+ ### v1.0.0
739
+ - 🎉 初始版本