Skip to content

Commit fc0d5e7

Browse files
committed
fix: enhance user selection with remote search and dynamic options in AddMemberDrawer
1 parent 6a50366 commit fc0d5e7

File tree

4 files changed

+77
-19
lines changed

4 files changed

+77
-19
lines changed

ui/src/api/type/role.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { RoleTypeEnum } from '@/enums/system'
2-
import type { FormItemRule } from 'element-plus'
1+
import {RoleTypeEnum} from '@/enums/system'
2+
import type {FormItemRule} from 'element-plus'
3+
34
interface RoleItem {
45
id: string,
56
role_name: string,
@@ -56,6 +57,7 @@ interface CreateMemberParamsItem {
5657
}
5758

5859
type Arrayable<T> = T | T[]
60+
5961
interface FormItemModel {
6062
path: string
6163
label?: string
@@ -66,7 +68,18 @@ interface FormItemModel {
6668
placeholder?: string
6769
multiple?: boolean
6870
clearableFunction?: (e: any) => boolean
71+
remoteMethod?: (query: string, element: any) => Promise<{ label: string, value: string }[]>
72+
remoteSearchDebounce?: number
6973
}
7074
}
7175

72-
export type { RoleItem, FormItemModel, RolePermissionItem, RoleTableDataItem, CreateOrUpdateParams, ChildrenPermissionItem, RoleMemberItem, CreateMemberParamsItem }
76+
export type {
77+
RoleItem,
78+
FormItemModel,
79+
RolePermissionItem,
80+
RoleTableDataItem,
81+
CreateOrUpdateParams,
82+
ChildrenPermissionItem,
83+
RoleMemberItem,
84+
CreateMemberParamsItem
85+
}

ui/src/api/user/user.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Result } from '@/request/Result'
2-
import { get, post } from '@/request/index'
3-
import type { User, ResetPasswordRequest, CheckCodeRequest } from '@/api/type/user'
4-
import type { Ref } from 'vue'
1+
import {Result} from '@/request/Result'
2+
import {get, post} from '@/request/index'
3+
import type {User, ResetPasswordRequest, CheckCodeRequest} from '@/api/type/user'
4+
import type {Ref} from 'vue'
5+
56
/**
67
* 获取用户基本信息
78
* @param loading 接口加载器
@@ -20,20 +21,21 @@ const getProfile: (loading?: Ref<boolean>) => Promise<Result<any>> = (loading) =
2021
/**
2122
* 获取全部用户
2223
*/
23-
const getUserList: (loading?: Ref<boolean>) => Promise<Result<Record<string, any>[]>> = (
24+
const getUserList: (arg?: any, loading?: Ref<boolean>) => Promise<Result<Record<string, any>[]>> = (
25+
arg,
2426
loading,
2527
) => {
26-
return get('/user/list', undefined, loading)
28+
return get('/user/list', arg, loading)
2729
}
2830

2931
/**
3032
* 获取全部用户
3133
*/
32-
const getAllMemberList: (arg: string, loading?: Ref<boolean>) => Promise<Result<Record<string, any>[]>> = (
34+
const getAllMemberList: (arg: any, loading?: Ref<boolean>) => Promise<Result<Record<string, any>[]>> = (
3335
arg,
3436
loading,
3537
) => {
36-
return get('/user/list', undefined, loading)
38+
return get('/user/list', arg, loading)
3739
}
3840

3941
/**
@@ -60,7 +62,7 @@ const sendEmit: (
6062
type: 'register' | 'reset_password',
6163
loading?: Ref<boolean>,
6264
) => Promise<Result<boolean>> = (email, type, loading) => {
63-
return post('/user/send_email', { email, type }, undefined, loading)
65+
return post('/user/send_email', {email, type}, undefined, loading)
6466
}
6567

6668
/**

ui/src/views/system/role/component/AddMemberDrawer.vue

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@ const memberFormContentLoading = ref(false)
5151
const formItemModel = ref<FormItemModel[]>([])
5252
const userFormItem = ref<FormItemModel[]>([])
5353
const workspaceFormItem = ref<FormItemModel[]>([])
54+
const userOptions = ref<Array<{ label: string; value: string }>>([])
5455
5556
async function getUserFormItem() {
5657
try {
57-
const res = await UserApi.getUserList(memberFormContentLoading)
58+
const res = await UserApi.getUserList({}, memberFormContentLoading)
59+
userOptions.value = res.data?.map((item) => ({
60+
label: item.nick_name,
61+
value: item.id,
62+
})) || []
5863
userFormItem.value = [
5964
{
6065
path: 'user_ids',
@@ -66,12 +71,19 @@ async function getUserFormItem() {
6671
},
6772
],
6873
selectProps: {
69-
options:
70-
res.data?.map((item) => ({
74+
options: userOptions.value,
75+
placeholder: `${t('common.selectPlaceholder')}${t('views.role.member.title')}`,
76+
remoteSearchDebounce: 300,
77+
remoteMethod: async (query: string, element: any) => {
78+
if (!query) {
79+
return userOptions.value
80+
}
81+
const res = await UserApi.getUserList({nick_name: query}, memberFormContentLoading)
82+
return res.data?.map((item) => ({
7183
label: item.nick_name,
7284
value: item.id,
73-
})) || [],
74-
placeholder: `${t('common.selectPlaceholder')}${t('views.role.member.title')}`,
85+
})) || []
86+
}
7587
},
7688
},
7789
]

ui/src/views/system/role/component/MemberFormContent.vue

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
: true
2222
"
2323
filterable
24+
remote
25+
:remote-method="(query) => handleRemoteSearch(query, element, model)"
26+
:loading="loadingStates[`${index}-${model.path}`]"
2427
multiple
2528
:reserve-keyword="false"
2629
style="width: 100%"
@@ -29,7 +32,7 @@
2932
v-bind="model.selectProps"
3033
>
3134
<el-option
32-
v-for="opt in model.selectProps?.options"
35+
v-for="opt in getOptions(element, model)"
3336
:key="opt.value"
3437
:label="opt.label"
3538
:value="opt.value"
@@ -65,7 +68,7 @@
6568
</template>
6669

6770
<script setup lang="ts">
68-
import {ref, watch, computed} from 'vue'
71+
import {computed, reactive, ref, watch} from 'vue'
6972
import type {FormItemModel} from '@/api/type/role'
7073
7174
const props = withDefaults(defineProps<{
@@ -85,10 +88,38 @@ const form = defineModel<Record<string, any>[]>('form', {
8588
default: [],
8689
})
8790
91+
const loadingStates = reactive<Record<string, boolean>>({})
92+
8893
const selectedRoles = computed(() => {
8994
return form.value.map((item) => item.role_id)
9095
})
9196
97+
function getOptions(element: any, model: FormItemModel) {
98+
const dynamicOptions = element[`_${model.path}_options`]
99+
return dynamicOptions || model.selectProps?.options || []
100+
}
101+
102+
async function handleRemoteSearch(query: string, element: any, model: FormItemModel) {
103+
if (!model.selectProps?.remoteMethod) {
104+
return
105+
}
106+
107+
const key = `${form.value.indexOf(element)}-${model.path}`
108+
loadingStates[key] = true
109+
110+
try {
111+
const debounceTime = model.selectProps.remoteSearchDebounce || 300
112+
await new Promise(resolve => setTimeout(resolve, debounceTime))
113+
114+
element[`_${model.path}_options`] = await model.selectProps.remoteMethod(query, element)
115+
} catch (error) {
116+
console.error('Remote search failed:', error)
117+
element[`_${model.path}_options`] = []
118+
} finally {
119+
loadingStates[key] = false
120+
}
121+
}
122+
92123
function handleAdd() {
93124
form.value.push({...formItem})
94125
}

0 commit comments

Comments
 (0)