Feature: 支持在 WebUI 配置文件页中配置默认知识库 (#2437)
* feat: 支持配置默认知识库 * chore: clean code
This commit is contained in:
@@ -121,6 +121,7 @@ DEFAULT_CONFIG = {
|
|||||||
"persona": [], # deprecated
|
"persona": [], # deprecated
|
||||||
"timezone": "Asia/Shanghai",
|
"timezone": "Asia/Shanghai",
|
||||||
"callback_api_base": "",
|
"callback_api_base": "",
|
||||||
|
"default_kb_collection": "", # 默认知识库名称
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -557,10 +558,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"api_base": "https://api.openai.com/v1",
|
"api_base": "https://api.openai.com/v1",
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {"model": "gpt-4o-mini", "temperature": 0.4},
|
||||||
"model": "gpt-4o-mini",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
"hint": "也兼容所有与OpenAI API兼容的服务。",
|
"hint": "也兼容所有与OpenAI API兼容的服务。",
|
||||||
},
|
},
|
||||||
@@ -574,10 +572,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"api_base": "",
|
"api_base": "",
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {"model": "gpt-4o-mini", "temperature": 0.4},
|
||||||
"model": "gpt-4o-mini",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"xAI": {
|
"xAI": {
|
||||||
@@ -589,10 +584,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"api_base": "https://api.x.ai/v1",
|
"api_base": "https://api.x.ai/v1",
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {"model": "grok-2-latest", "temperature": 0.4},
|
||||||
"model": "grok-2-latest",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"Anthropic": {
|
"Anthropic": {
|
||||||
@@ -608,12 +600,12 @@ CONFIG_METADATA_2 = {
|
|||||||
"model_config": {
|
"model_config": {
|
||||||
"model": "claude-3-5-sonnet-latest",
|
"model": "claude-3-5-sonnet-latest",
|
||||||
"max_tokens": 4096,
|
"max_tokens": 4096,
|
||||||
"temperature": 0.2
|
"temperature": 0.2,
|
||||||
},
|
},
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"Ollama": {
|
"Ollama": {
|
||||||
"hint":"启用前请确保已正确安装并运行 Ollama 服务端,Ollama默认不带鉴权,无需修改key",
|
"hint": "启用前请确保已正确安装并运行 Ollama 服务端,Ollama默认不带鉴权,无需修改key",
|
||||||
"id": "ollama_default",
|
"id": "ollama_default",
|
||||||
"provider": "ollama",
|
"provider": "ollama",
|
||||||
"type": "openai_chat_completion",
|
"type": "openai_chat_completion",
|
||||||
@@ -621,10 +613,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"enable": True,
|
"enable": True,
|
||||||
"key": ["ollama"], # ollama 的 key 默认是 ollama
|
"key": ["ollama"], # ollama 的 key 默认是 ollama
|
||||||
"api_base": "http://localhost:11434/v1",
|
"api_base": "http://localhost:11434/v1",
|
||||||
"model_config": {
|
"model_config": {"model": "llama3.1-8b", "temperature": 0.4},
|
||||||
"model": "llama3.1-8b",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"LM Studio": {
|
"LM Studio": {
|
||||||
@@ -651,7 +640,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {
|
||||||
"model": "gemini-1.5-flash",
|
"model": "gemini-1.5-flash",
|
||||||
"temperature": 0.4
|
"temperature": 0.4,
|
||||||
},
|
},
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
@@ -666,7 +655,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {
|
||||||
"model": "gemini-2.0-flash-exp",
|
"model": "gemini-2.0-flash-exp",
|
||||||
"temperature": 0.4
|
"temperature": 0.4,
|
||||||
},
|
},
|
||||||
"gm_resp_image_modal": False,
|
"gm_resp_image_modal": False,
|
||||||
"gm_native_search": False,
|
"gm_native_search": False,
|
||||||
@@ -692,10 +681,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"api_base": "https://api.deepseek.com/v1",
|
"api_base": "https://api.deepseek.com/v1",
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {"model": "deepseek-chat", "temperature": 0.4},
|
||||||
"model": "deepseek-chat",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"302.AI": {
|
"302.AI": {
|
||||||
@@ -707,10 +693,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"api_base": "https://api.302.ai/v1",
|
"api_base": "https://api.302.ai/v1",
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {"model": "gpt-4.1-mini", "temperature": 0.4},
|
||||||
"model": "gpt-4.1-mini",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"硅基流动": {
|
"硅基流动": {
|
||||||
@@ -724,7 +707,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"api_base": "https://api.siliconflow.cn/v1",
|
"api_base": "https://api.siliconflow.cn/v1",
|
||||||
"model_config": {
|
"model_config": {
|
||||||
"model": "deepseek-ai/DeepSeek-V3",
|
"model": "deepseek-ai/DeepSeek-V3",
|
||||||
"temperature": 0.4
|
"temperature": 0.4,
|
||||||
},
|
},
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
@@ -739,7 +722,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"model_config": {
|
"model_config": {
|
||||||
"model": "deepseek/deepseek-r1",
|
"model": "deepseek/deepseek-r1",
|
||||||
"temperature": 0.4
|
"temperature": 0.4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"优云智算": {
|
"优云智算": {
|
||||||
@@ -765,10 +748,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"api_base": "https://api.moonshot.cn/v1",
|
"api_base": "https://api.moonshot.cn/v1",
|
||||||
"model_config": {
|
"model_config": {"model": "moonshot-v1-8k", "temperature": 0.4},
|
||||||
"model": "moonshot-v1-8k",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"智谱 AI": {
|
"智谱 AI": {
|
||||||
@@ -798,7 +778,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"dify_query_input_key": "astrbot_text_query",
|
"dify_query_input_key": "astrbot_text_query",
|
||||||
"variables": {},
|
"variables": {},
|
||||||
"timeout": 60,
|
"timeout": 60,
|
||||||
"hint": "请确保你在 AstrBot 里设置的 APP 类型和 Dify 里面创建的应用的类型一致!"
|
"hint": "请确保你在 AstrBot 里设置的 APP 类型和 Dify 里面创建的应用的类型一致!",
|
||||||
},
|
},
|
||||||
"阿里云百炼应用": {
|
"阿里云百炼应用": {
|
||||||
"id": "dashscope",
|
"id": "dashscope",
|
||||||
@@ -826,10 +806,7 @@ CONFIG_METADATA_2 = {
|
|||||||
"key": [],
|
"key": [],
|
||||||
"timeout": 120,
|
"timeout": 120,
|
||||||
"api_base": "https://api-inference.modelscope.cn/v1",
|
"api_base": "https://api-inference.modelscope.cn/v1",
|
||||||
"model_config": {
|
"model_config": {"model": "Qwen/Qwen3-32B", "temperature": 0.4},
|
||||||
"model": "Qwen/Qwen3-32B",
|
|
||||||
"temperature": 0.4
|
|
||||||
},
|
|
||||||
"modalities": ["text", "image"],
|
"modalities": ["text", "image"],
|
||||||
},
|
},
|
||||||
"FastGPT": {
|
"FastGPT": {
|
||||||
@@ -1794,6 +1771,9 @@ CONFIG_METADATA_2 = {
|
|||||||
"pypi_index_url": {
|
"pypi_index_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
},
|
},
|
||||||
|
"default_kb_collection": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1852,6 +1832,17 @@ CONFIG_METADATA_3 = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"knowledgebase": {
|
||||||
|
"description": "知识库",
|
||||||
|
"type": "object",
|
||||||
|
"items": {
|
||||||
|
"default_kb_collection": {
|
||||||
|
"description": "默认使用的知识库",
|
||||||
|
"type": "string",
|
||||||
|
"_special": "select_knowledgebase",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"websearch": {
|
"websearch": {
|
||||||
"description": "网页搜索",
|
"description": "网页搜索",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ref, computed } from 'vue'
|
|||||||
import ListConfigItem from './ListConfigItem.vue'
|
import ListConfigItem from './ListConfigItem.vue'
|
||||||
import ProviderSelector from './ProviderSelector.vue'
|
import ProviderSelector from './ProviderSelector.vue'
|
||||||
import PersonaSelector from './PersonaSelector.vue'
|
import PersonaSelector from './PersonaSelector.vue'
|
||||||
|
import KnowledgeBaseSelector from './KnowledgeBaseSelector.vue'
|
||||||
import { useI18n } from '@/i18n/composables'
|
import { useI18n } from '@/i18n/composables'
|
||||||
|
|
||||||
|
|
||||||
@@ -196,6 +197,8 @@ function hasVisibleItemsAfter(items, currentIndex) {
|
|||||||
<v-text-field v-else v-model="createSelectorModel(itemKey).value" density="compact" variant="outlined"
|
<v-text-field v-else v-model="createSelectorModel(itemKey).value" density="compact" variant="outlined"
|
||||||
class="config-field" hide-details></v-text-field>
|
class="config-field" hide-details></v-text-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Special handling for specific metadata types -->
|
||||||
<div v-else-if="itemMeta?._special === 'select_provider'">
|
<div v-else-if="itemMeta?._special === 'select_provider'">
|
||||||
<ProviderSelector
|
<ProviderSelector
|
||||||
v-model="createSelectorModel(itemKey).value"
|
v-model="createSelectorModel(itemKey).value"
|
||||||
@@ -232,6 +235,11 @@ function hasVisibleItemsAfter(items, currentIndex) {
|
|||||||
button-text="选择人格池..."
|
button-text="选择人格池..."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="itemMeta?._special === 'select_knowledgebase'">
|
||||||
|
<KnowledgeBaseSelector
|
||||||
|
v-model="createSelectorModel(itemKey).value"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
225
dashboard/src/components/shared/KnowledgeBaseSelector.vue
Normal file
225
dashboard/src/components/shared/KnowledgeBaseSelector.vue
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
<template>
|
||||||
|
<div class="d-flex align-center justify-space-between">
|
||||||
|
<span v-if="!modelValue" style="color: rgb(var(--v-theme-primaryText));">
|
||||||
|
未选择
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
{{ modelValue }}
|
||||||
|
</span>
|
||||||
|
<v-btn size="small" color="primary" variant="tonal" @click="openDialog">
|
||||||
|
{{ buttonText }}
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Knowledge Base Selection Dialog -->
|
||||||
|
<v-dialog v-model="dialog" max-width="600px">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="text-h3 py-4" style="font-weight: normal;">
|
||||||
|
选择知识库
|
||||||
|
</v-card-title>
|
||||||
|
|
||||||
|
<v-card-text class="pa-0" style="max-height: 400px; overflow-y: auto;">
|
||||||
|
<v-progress-linear v-if="loading" indeterminate color="primary"></v-progress-linear>
|
||||||
|
|
||||||
|
<!-- 插件未安装提示 -->
|
||||||
|
<div v-if="!loading && !pluginInstalled" class="text-center py-8">
|
||||||
|
<v-icon size="64" color="grey-lighten-1">mdi-puzzle-outline</v-icon>
|
||||||
|
<p class="text-grey mt-4 mb-4">知识库插件未安装</p>
|
||||||
|
<v-btn color="primary" variant="tonal" @click="goToKnowledgeBasePage">
|
||||||
|
前往知识库页面
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 知识库列表 -->
|
||||||
|
<v-list v-else-if="!loading && pluginInstalled" density="compact">
|
||||||
|
<!-- 不使用选项 -->
|
||||||
|
<v-list-item
|
||||||
|
:value="''"
|
||||||
|
@click="selectKnowledgeBase({ collection_name: '' })"
|
||||||
|
:active="selectedKnowledgeBase === ''"
|
||||||
|
rounded="md"
|
||||||
|
class="ma-1">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon color="grey-lighten-1">mdi-close-circle-outline</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>不使用</v-list-item-title>
|
||||||
|
<v-list-item-subtitle>不使用任何知识库</v-list-item-subtitle>
|
||||||
|
|
||||||
|
<template v-slot:append>
|
||||||
|
<v-icon v-if="selectedKnowledgeBase === ''" color="primary">mdi-check-circle</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-divider v-if="knowledgeBaseList.length > 0" class="my-2"></v-divider>
|
||||||
|
|
||||||
|
<!-- 知识库选项 -->
|
||||||
|
<v-list-item
|
||||||
|
v-for="kb in knowledgeBaseList"
|
||||||
|
:key="kb.collection_name"
|
||||||
|
:value="kb.collection_name"
|
||||||
|
@click="selectKnowledgeBase(kb)"
|
||||||
|
:active="selectedKnowledgeBase === kb.collection_name"
|
||||||
|
rounded="md"
|
||||||
|
class="ma-1">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<span class="emoji-icon">{{ kb.emoji || '🙂' }}</span>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>{{ kb.collection_name }}</v-list-item-title>
|
||||||
|
<v-list-item-subtitle>
|
||||||
|
{{ kb.description || '无描述' }}
|
||||||
|
<span v-if="kb.count !== undefined"> - {{ kb.count }} 项知识</span>
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
|
||||||
|
<template v-slot:append>
|
||||||
|
<v-icon v-if="selectedKnowledgeBase === kb.collection_name" color="primary">mdi-check-circle</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<!-- 当没有知识库时显示创建提示 -->
|
||||||
|
<div v-if="knowledgeBaseList.length === 0" class="text-center py-4">
|
||||||
|
<p class="text-grey mb-4">暂无知识库</p>
|
||||||
|
<v-btn color="primary" variant="tonal" size="small" @click="goToKnowledgeBasePage">
|
||||||
|
创建知识库
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-list>
|
||||||
|
|
||||||
|
<!-- 空状态(插件未安装时保留原有逻辑) -->
|
||||||
|
<div v-else-if="!loading && !pluginInstalled && knowledgeBaseList.length === 0" class="text-center py-8">
|
||||||
|
<v-icon size="64" color="grey-lighten-1">mdi-database-off</v-icon>
|
||||||
|
<p class="text-grey mt-4 mb-4">暂无知识库</p>
|
||||||
|
<v-btn color="primary" variant="tonal" @click="goToKnowledgeBasePage">
|
||||||
|
创建知识库
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="pa-4">
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn variant="text" @click="cancelSelection">取消</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="confirmSelection"
|
||||||
|
:disabled="selectedKnowledgeBase === null || selectedKnowledgeBase === undefined">
|
||||||
|
确认选择
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
type: String,
|
||||||
|
default: '选择知识库...'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const dialog = ref(false)
|
||||||
|
const knowledgeBaseList = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const selectedKnowledgeBase = ref('')
|
||||||
|
const pluginInstalled = ref(false)
|
||||||
|
|
||||||
|
// 监听 modelValue 变化,同步到 selectedKnowledgeBase
|
||||||
|
watch(() => props.modelValue, (newValue) => {
|
||||||
|
selectedKnowledgeBase.value = newValue || ''
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
async function openDialog() {
|
||||||
|
selectedKnowledgeBase.value = props.modelValue || ''
|
||||||
|
dialog.value = true
|
||||||
|
await checkPluginAndLoadKnowledgeBases()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkPluginAndLoadKnowledgeBases() {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
// 首先检查插件是否安装
|
||||||
|
const pluginResponse = await axios.get('/api/plugin/get?name=astrbot_plugin_knowledge_base')
|
||||||
|
|
||||||
|
if (pluginResponse.data.status === 'ok' && pluginResponse.data.data.length > 0) {
|
||||||
|
pluginInstalled.value = true
|
||||||
|
// 插件已安装,获取知识库列表
|
||||||
|
await loadKnowledgeBases()
|
||||||
|
} else {
|
||||||
|
pluginInstalled.value = false
|
||||||
|
knowledgeBaseList.value = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查知识库插件失败:', error)
|
||||||
|
pluginInstalled.value = false
|
||||||
|
knowledgeBaseList.value = []
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadKnowledgeBases() {
|
||||||
|
try {
|
||||||
|
const response = await axios.get('/api/plug/alkaid/kb/collections')
|
||||||
|
if (response.data.status === 'ok') {
|
||||||
|
knowledgeBaseList.value = response.data.data || []
|
||||||
|
} else {
|
||||||
|
knowledgeBaseList.value = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载知识库列表失败:', error)
|
||||||
|
knowledgeBaseList.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectKnowledgeBase(kb) {
|
||||||
|
selectedKnowledgeBase.value = kb.collection_name
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmSelection() {
|
||||||
|
emit('update:modelValue', selectedKnowledgeBase.value)
|
||||||
|
dialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelSelection() {
|
||||||
|
selectedKnowledgeBase.value = props.modelValue || ''
|
||||||
|
dialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToKnowledgeBasePage() {
|
||||||
|
dialog.value = false
|
||||||
|
router.push('/alkaid/knowledge-base')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.v-list-item {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-item:hover {
|
||||||
|
background-color: rgba(var(--v-theme-primary), 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-list-item.v-list-item--active {
|
||||||
|
background-color: rgba(var(--v-theme-primary), 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 8px;
|
||||||
|
min-width: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -47,8 +47,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-divider></v-divider>
|
|
||||||
|
|
||||||
<v-card-actions class="pa-4">
|
<v-card-actions class="pa-4">
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn variant="text" @click="cancelSelection">取消</v-btn>
|
<v-btn variant="text" @click="cancelSelection">取消</v-btn>
|
||||||
|
|||||||
Reference in New Issue
Block a user