perf: Optimize multiple selections

v3.2
wangdan-fit2cloud 2025-10-22 11:19:37 +08:00
parent 147eea4160
commit c3fca96c98
13 changed files with 70 additions and 45 deletions

View File

@ -130,6 +130,7 @@
collapse-tags collapse-tags
filterable filterable
clearable clearable
:reserve-keyword="false"
v-model="formValue.default_value" v-model="formValue.default_value"
:teleported="false" :teleported="false"
popper-class="default-select" popper-class="default-select"

View File

@ -5,6 +5,7 @@
filterable filterable
allow-create allow-create
clearable clearable
:reserve-keyword="false"
v-bind="$attrs" v-bind="$attrs"
v-model="_modelValue" v-model="_modelValue"
> >

View File

@ -48,6 +48,7 @@
filterable filterable
clearable clearable
multiple multiple
:reserve-keyword="false"
collapse-tags collapse-tags
collapse-tags-tooltip collapse-tags-tooltip
style="width: 220px" style="width: 220px"

View File

@ -38,7 +38,7 @@
{{ `MCP ${$t('views.tool.title')}` }} {{ `MCP ${$t('views.tool.title')}` }}
<span class="color-danger">*</span> <span class="color-danger">*</span>
</template> </template>
<el-select v-model="form.mcp_tool_ids" filterable multiple> <el-select v-model="form.mcp_tool_ids" filterable multiple :reserve-keyword="false">
<el-option <el-option
v-for="mcpTool in mcpToolSelectOptions" v-for="mcpTool in mcpToolSelectOptions"
:key="mcpTool.id" :key="mcpTool.id"

View File

@ -52,7 +52,7 @@
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button <el-button
:disabled="index === 0" :disabled="tags.length === 1"
link link
type="info" type="info"
@click="deleteTag(index)" @click="deleteTag(index)"

View File

@ -82,7 +82,7 @@
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button <el-button
:disabled="index === 0" :disabled="tagList.length === 1"
text text
@click="deleteTag(index)" @click="deleteTag(index)"
:style="{ marginTop: index === 0 ? '35px' : '5px' }" :style="{ marginTop: index === 0 ? '35px' : '5px' }"

View File

@ -47,6 +47,7 @@
<el-select <el-select
v-model="form.patterns" v-model="form.patterns"
multiple multiple
:reserve-keyword="false"
allow-create allow-create
default-first-option default-first-option
filterable filterable

View File

@ -1,17 +1,34 @@
<template> <template>
<el-dialog :title="$t('views.role.member.add')" v-model="dialogVisible" <el-dialog
:close-on-click-modal="false" :title="$t('views.role.member.add')"
:close-on-press-escape="false" :destroy-on-close="true"> v-model="dialogVisible"
<el-form label-position="top" ref="formRef" :rules="rules" :model="form" :close-on-click-modal="false"
require-asterisk-position="right"> :close-on-press-escape="false"
:destroy-on-close="true"
>
<el-form
label-position="top"
ref="formRef"
:rules="rules"
:model="form"
require-asterisk-position="right"
>
<el-form-item :label="$t('views.chatUser.group.usernameOrName')" prop="user"> <el-form-item :label="$t('views.chatUser.group.usernameOrName')" prop="user">
<el-select v-model="form.user" multiple filterable <el-select
:placeholder="$t('common.selectPlaceholder')" v-model="form.user"
:loading="optionLoading" multiple
:filter-method="filterUser" filterable
:reserve-keyword="false"
:placeholder="$t('common.selectPlaceholder')"
:loading="optionLoading"
:filter-method="filterUser"
> >
<el-option v-for="item in chatUserList" :key="item.id" :label="item.nick_name" <el-option
:value="item.id"> v-for="item in chatUserList"
:key="item.id"
:label="item.nick_name"
:value="item.id"
>
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -28,22 +45,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ref, reactive, onBeforeMount} from 'vue' import { ref, reactive, onBeforeMount } from 'vue'
import type {FormInstance} from 'element-plus' import type { FormInstance } from 'element-plus'
import {MsgSuccess} from '@/utils/message' import { MsgSuccess } from '@/utils/message'
import {t} from '@/locales' import { t } from '@/locales'
import SystemGroupApi from '@/api/system/user-group' import SystemGroupApi from '@/api/system/user-group'
import userManageApi from '@/api/system/chat-user' import userManageApi from '@/api/system/chat-user'
import type {ChatUserItem} from '@/api/type/systemChatUser' import type { ChatUserItem } from '@/api/type/systemChatUser'
import {loadPermissionApi} from "@/utils/dynamics-api/permission-api.ts"; import { loadPermissionApi } from '@/utils/dynamics-api/permission-api.ts'
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void
}>(); }>()
const dialogVisible = ref<boolean>(false) const dialogVisible = ref<boolean>(false)
const defaultForm = { const defaultForm = {
user: [] user: [],
} }
const form = ref<{ user: string[] }>({ const form = ref<{ user: string[] }>({
...defaultForm, ...defaultForm,
@ -51,12 +68,12 @@ const form = ref<{ user: string[] }>({
const optionLoading = ref(false) const optionLoading = ref(false)
const chatUserList = ref<ChatUserItem[]>([]) const chatUserList = ref<ChatUserItem[]>([])
const originalChatUserList = ref<ChatUserItem[]>([]); const originalChatUserList = ref<ChatUserItem[]>([])
async function getChatUserList() { async function getChatUserList() {
try { try {
const res = await loadPermissionApi('chatUser').getChatUserList(optionLoading) const res = await loadPermissionApi('chatUser').getChatUserList(optionLoading)
originalChatUserList.value = res.data; originalChatUserList.value = res.data
chatUserList.value = [...res.data]; chatUserList.value = [...res.data]
} catch (e) { } catch (e) {
console.error(e) console.error(e)
} }
@ -64,32 +81,32 @@ async function getChatUserList() {
const filterUser = (query: string) => { const filterUser = (query: string) => {
if (!query) { if (!query) {
chatUserList.value = originalChatUserList.value; chatUserList.value = originalChatUserList.value
return; return
} }
const q = query.toLowerCase(); const q = query.toLowerCase()
chatUserList.value = originalChatUserList.value.filter( chatUserList.value = originalChatUserList.value.filter(
(item) => item.nick_name?.toLowerCase().includes(q) || item.username?.toLowerCase().includes(q) (item) => item.nick_name?.toLowerCase().includes(q) || item.username?.toLowerCase().includes(q),
); )
}; }
onBeforeMount(() => { onBeforeMount(() => {
getChatUserList() getChatUserList()
}) })
const groupId = ref(''); const groupId = ref('')
function open(id: string) { function open(id: string) {
form.value = {...defaultForm} form.value = { ...defaultForm }
groupId.value = id groupId.value = id
dialogVisible.value = true dialogVisible.value = true
} }
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>()
const rules = reactive({ const rules = reactive({
user: [{required: true, message: t('common.selectPlaceholder'), trigger: 'blur'}], user: [{ required: true, message: t('common.selectPlaceholder'), trigger: 'blur' }],
}) })
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
@ -97,14 +114,16 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
await formEl.validate((valid) => { await formEl.validate((valid) => {
if (valid) { if (valid) {
loadPermissionApi('userGroup').postAddMember(groupId.value, {"user_ids": form.value.user}, loading).then(() => { loadPermissionApi('userGroup')
MsgSuccess(t('common.addSuccess')) .postAddMember(groupId.value, { user_ids: form.value.user }, loading)
emit('refresh') .then(() => {
dialogVisible.value = false MsgSuccess(t('common.addSuccess'))
}) emit('refresh')
dialogVisible.value = false
})
} }
}) })
} }
defineExpose({open}) defineExpose({ open })
</script> </script>

View File

@ -46,7 +46,7 @@
filterable filterable
style="width: 220px" style="width: 220px"
> >
<el-option v-for="u in type_options" :value="u.value" :label="u.label"/> <el-option v-for="u in type_options" :key="u.id" :value="u.value" :label="u.label"/>
</el-select> </el-select>
</div> </div>
</div> </div>

View File

@ -45,7 +45,7 @@
filterable filterable
style="width: 220px" style="width: 220px"
> >
<el-option v-for="u in type_options" :value="u.value" :label="u.label" /> <el-option v-for="u in type_options" :key="u.id" :value="u.value" :label="u.label" />
</el-select> </el-select>
</div> </div>
</div> </div>

View File

@ -45,7 +45,7 @@
filterable filterable
style="width: 220px" style="width: 220px"
> >
<el-option v-for="u in type_options" :value="u.value" :label="u.label"/> <el-option v-for="u in type_options" :key="u.id" :value="u.value" :label="u.label"/>
</el-select> </el-select>
</div> </div>
</div> </div>

View File

@ -39,6 +39,7 @@
filterable filterable
clearable clearable
multiple multiple
:reserve-keyword="false"
collapse-tags collapse-tags
collapse-tags-tooltip collapse-tags-tooltip
style="width: 220px" style="width: 220px"

View File

@ -22,6 +22,7 @@
" "
filterable filterable
multiple multiple
:reserve-keyword="false"
style="width: 100%" style="width: 100%"
collapse-tags collapse-tags
collapse-tags-tooltip collapse-tags-tooltip