2025-08-22 23:17:48 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="agent-config-sidebar" :class="{ 'open': isOpen }">
|
|
|
|
|
|
<!-- 侧边栏头部 -->
|
|
|
|
|
|
<div class="sidebar-header">
|
|
|
|
|
|
<div class="sidebar-title">
|
|
|
|
|
|
<SettingOutlined class="title-icon" />
|
2025-08-26 14:55:39 +08:00
|
|
|
|
<span>{{ selectedAgent?.name || '未选择智能体' }} 配置</span>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="closeSidebar"
|
|
|
|
|
|
class="close-btn"
|
|
|
|
|
|
>
|
|
|
|
|
|
<CloseOutlined />
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 侧边栏内容 -->
|
|
|
|
|
|
<div class="sidebar-content">
|
2025-08-25 01:46:31 +08:00
|
|
|
|
<div class="agent-info" v-if="selectedAgent">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<div class="agent-basic-info">
|
|
|
|
|
|
<p class="agent-description">{{ selectedAgent.description }}</p>
|
2025-08-25 13:57:47 +08:00
|
|
|
|
<!-- <div class="debug-toggle" v-if="selectedAgent.name">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<span class="debug-text">调试信息</span>
|
|
|
|
|
|
<a-switch v-model:checked="debugMode" size="small" />
|
|
|
|
|
|
</div>
|
2025-08-25 13:57:47 +08:00
|
|
|
|
<pre v-if="debugMode && selectedAgent.name" class="debug-info">{{ selectedAgent }}</pre> -->
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<a-divider />
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="selectedAgentId && configSchema" class="config-form-content">
|
|
|
|
|
|
<!-- 配置表单 -->
|
|
|
|
|
|
<a-form :model="agentConfig" layout="vertical" class="config-form">
|
|
|
|
|
|
<a-alert
|
|
|
|
|
|
v-if="isEmptyConfig"
|
|
|
|
|
|
type="warning"
|
|
|
|
|
|
message="该智能体没有配置项"
|
|
|
|
|
|
show-icon
|
|
|
|
|
|
class="config-alert"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<a-alert
|
|
|
|
|
|
v-if="!selectedAgent.has_checkpointer"
|
|
|
|
|
|
type="error"
|
|
|
|
|
|
message="该智能体没有配置 Checkpointer,功能无法正常使用"
|
|
|
|
|
|
show-icon
|
|
|
|
|
|
class="config-alert"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 统一显示所有配置项 -->
|
|
|
|
|
|
<template v-for="(value, key) in configurableItems" :key="key">
|
|
|
|
|
|
<a-form-item
|
|
|
|
|
|
:label="getConfigLabel(key, value)"
|
|
|
|
|
|
:name="key"
|
|
|
|
|
|
class="config-item"
|
|
|
|
|
|
>
|
|
|
|
|
|
<p v-if="value.description" class="config-description">{{ value.description }}</p>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 模型选择 -->
|
|
|
|
|
|
<div v-if="key === 'model'" class="model-selector">
|
|
|
|
|
|
<ModelSelectorComponent
|
|
|
|
|
|
@select-model="handleModelChange"
|
|
|
|
|
|
:model_name="agentConfig[key] ? agentConfig[key].split('/').slice(1).join('/') : ''"
|
|
|
|
|
|
:model_provider="agentConfig[key] ? agentConfig[key].split('/')[0] : ''"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 系统提示词 -->
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-else-if="key === 'system_prompt'"
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-25 13:57:47 +08:00
|
|
|
|
:rows="10"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:placeholder="getPlaceholder(key, value)"
|
|
|
|
|
|
class="system-prompt-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工具选择 -->
|
|
|
|
|
|
<div v-else-if="key === 'tools'" class="tools-selector">
|
|
|
|
|
|
<div class="tools-summary">
|
|
|
|
|
|
<div class="tools-summary-info">
|
|
|
|
|
|
<span class="tools-count">已选择 {{ getSelectedCount(key) }} 个工具</span>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="clearSelection(key)"
|
|
|
|
|
|
v-if="getSelectedCount(key) > 0"
|
|
|
|
|
|
class="clear-btn"
|
|
|
|
|
|
>
|
|
|
|
|
|
清空
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
@click="openToolsModal"
|
|
|
|
|
|
class="select-tools-btn"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
>
|
|
|
|
|
|
选择工具
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-if="getSelectedCount(key) > 0" class="selected-tools-preview">
|
|
|
|
|
|
<a-tag
|
|
|
|
|
|
v-for="toolId in agentConfig[key]"
|
|
|
|
|
|
:key="toolId"
|
|
|
|
|
|
closable
|
|
|
|
|
|
@close="removeSelectedTool(toolId)"
|
|
|
|
|
|
class="tool-tag"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ getToolNameById(toolId) }}
|
|
|
|
|
|
</a-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 布尔类型 -->
|
|
|
|
|
|
<a-switch
|
|
|
|
|
|
v-else-if="typeof agentConfig[key] === 'boolean'"
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:checked="agentConfig[key]"
|
|
|
|
|
|
@update:checked="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 单选 -->
|
|
|
|
|
|
<a-select
|
|
|
|
|
|
v-else-if="value?.options && (value?.type === 'str' || value?.type === 'select')"
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
class="config-select"
|
|
|
|
|
|
>
|
|
|
|
|
|
<a-select-option v-for="option in value.options" :key="option" :value="option">
|
|
|
|
|
|
{{ option.label || option }}
|
|
|
|
|
|
</a-select-option>
|
|
|
|
|
|
</a-select>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 多选 -->
|
|
|
|
|
|
<div v-else-if="value?.options && value?.type === 'list'" class="multi-select-cards">
|
|
|
|
|
|
<div class="multi-select-label">
|
|
|
|
|
|
<span>已选择 {{ getSelectedCount(key) }} 项</span>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
@click="clearSelection(key)"
|
|
|
|
|
|
v-if="getSelectedCount(key) > 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
清空
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="options-grid">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="option in value.options"
|
|
|
|
|
|
:key="option"
|
|
|
|
|
|
class="option-card"
|
|
|
|
|
|
:class="{
|
|
|
|
|
|
'selected': isOptionSelected(key, option),
|
|
|
|
|
|
'unselected': !isOptionSelected(key, option)
|
|
|
|
|
|
}"
|
|
|
|
|
|
@click="toggleOption(key, option)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="option-content">
|
|
|
|
|
|
<span class="option-text">{{ option }}</span>
|
|
|
|
|
|
<div class="option-indicator">
|
|
|
|
|
|
<CheckCircleOutlined v-if="isOptionSelected(key, option)" />
|
|
|
|
|
|
<PlusCircleOutlined v-else />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 数字 -->
|
|
|
|
|
|
<a-input-number
|
|
|
|
|
|
v-else-if="value?.type === 'number'"
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:placeholder="getPlaceholder(key, value)"
|
|
|
|
|
|
class="config-input-number"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 滑块 -->
|
|
|
|
|
|
<a-slider
|
|
|
|
|
|
v-else-if="value?.type === 'slider'"
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:min="value.min"
|
|
|
|
|
|
:max="value.max"
|
|
|
|
|
|
:step="value.step"
|
|
|
|
|
|
class="config-slider"
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 其他类型 -->
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-else
|
2025-08-25 01:46:31 +08:00
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:placeholder="getPlaceholder(key, value)"
|
|
|
|
|
|
class="config-input"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
</a-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 固定在底部的操作按钮 -->
|
|
|
|
|
|
<div class="sidebar-footer" v-if="!isEmptyConfig">
|
|
|
|
|
|
<div class="form-actions">
|
|
|
|
|
|
<a-button type="primary" @click="saveConfig" class="save-btn">
|
|
|
|
|
|
保存配置
|
|
|
|
|
|
</a-button>
|
2025-08-25 13:57:47 +08:00
|
|
|
|
<!-- TODO:BUG 目前有 bug 暂时不展示 -->
|
|
|
|
|
|
<!-- <a-button @click="resetConfig" class="reset-btn">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
重置
|
2025-08-25 13:57:47 +08:00
|
|
|
|
</a-button> -->
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 工具选择弹窗 -->
|
|
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="toolsModalOpen"
|
|
|
|
|
|
title="选择工具"
|
|
|
|
|
|
:width="600"
|
|
|
|
|
|
:footer="null"
|
|
|
|
|
|
:maskClosable="false"
|
|
|
|
|
|
class="tools-modal"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="tools-modal-content">
|
|
|
|
|
|
<div class="tools-search">
|
|
|
|
|
|
<a-input
|
|
|
|
|
|
v-model:value="toolsSearchText"
|
|
|
|
|
|
placeholder="搜索工具..."
|
|
|
|
|
|
allow-clear
|
|
|
|
|
|
class="search-input"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix>
|
|
|
|
|
|
<SearchOutlined class="search-icon" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="tools-list">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="tool in filteredTools"
|
|
|
|
|
|
:key="tool.id"
|
|
|
|
|
|
class="tool-item"
|
|
|
|
|
|
:class="{ 'selected': selectedTools.includes(tool.id) }"
|
|
|
|
|
|
@click="toggleToolSelection(tool.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="tool-content">
|
|
|
|
|
|
<div class="tool-header">
|
|
|
|
|
|
<span class="tool-name">{{ tool.name }}</span>
|
|
|
|
|
|
<div class="tool-indicator">
|
|
|
|
|
|
<CheckCircleOutlined v-if="selectedTools.includes(tool.id)" />
|
|
|
|
|
|
<PlusCircleOutlined v-else />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tool-description">{{ tool.description }}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="tools-modal-footer">
|
|
|
|
|
|
<div class="selected-count">
|
|
|
|
|
|
已选择 {{ selectedTools.length }} 个工具
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="modal-actions">
|
|
|
|
|
|
<a-button @click="cancelToolsSelection">取消</a-button>
|
|
|
|
|
|
<a-button type="primary" @click="confirmToolsSelection">确认</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-modal>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, computed, watch } from 'vue';
|
|
|
|
|
|
import {
|
|
|
|
|
|
SettingOutlined,
|
|
|
|
|
|
CloseOutlined,
|
|
|
|
|
|
CheckCircleOutlined,
|
|
|
|
|
|
PlusCircleOutlined,
|
|
|
|
|
|
SearchOutlined
|
|
|
|
|
|
} from '@ant-design/icons-vue';
|
|
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
|
|
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue';
|
2025-08-25 01:46:31 +08:00
|
|
|
|
import { useAgentStore } from '@/stores/agent';
|
|
|
|
|
|
import { storeToRefs } from 'pinia';
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
// Props
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
isOpen: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Emits
|
|
|
|
|
|
const emit = defineEmits([
|
2025-08-25 01:46:31 +08:00
|
|
|
|
'close'
|
2025-08-22 23:17:48 +08:00
|
|
|
|
]);
|
|
|
|
|
|
|
2025-08-25 01:46:31 +08:00
|
|
|
|
// Store 管理
|
|
|
|
|
|
const agentStore = useAgentStore();
|
|
|
|
|
|
const {
|
|
|
|
|
|
availableTools,
|
|
|
|
|
|
selectedAgent,
|
|
|
|
|
|
selectedAgentId,
|
|
|
|
|
|
agentConfig
|
|
|
|
|
|
} = storeToRefs(agentStore);
|
|
|
|
|
|
|
|
|
|
|
|
// console.log(availableTools.value)
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
// 本地状态
|
|
|
|
|
|
const debugMode = ref(false);
|
|
|
|
|
|
const toolsModalOpen = ref(false);
|
|
|
|
|
|
const selectedTools = ref([]);
|
|
|
|
|
|
const toolsSearchText = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const configSchema = computed(() => selectedAgent.value?.config_schema || {});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const configurableItems = computed(() => {
|
|
|
|
|
|
const items = configSchema.value.configurable_items || {};
|
|
|
|
|
|
// 遍历所有的配置项,将所有的 x_oap_ui_config 的层级提升到上一层
|
|
|
|
|
|
Object.keys(items).forEach(key => {
|
|
|
|
|
|
const item = items[key];
|
|
|
|
|
|
if (item.x_oap_ui_config) {
|
|
|
|
|
|
items[key] = { ...item, ...item.x_oap_ui_config };
|
|
|
|
|
|
delete items[key].x_oap_ui_config;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
return items;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const isEmptyConfig = computed(() => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
return !selectedAgentId.value || Object.keys(configurableItems.value).length === 0;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const filteredTools = computed(() => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const toolsList = availableTools.value ? Object.values(availableTools.value) : [];
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (!toolsSearchText.value) {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
return toolsList;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
const searchLower = toolsSearchText.value.toLowerCase();
|
2025-08-25 01:46:31 +08:00
|
|
|
|
return toolsList.filter(tool =>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
tool.name.toLowerCase().includes(searchLower) ||
|
|
|
|
|
|
tool.description.toLowerCase().includes(searchLower)
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 方法
|
|
|
|
|
|
const closeSidebar = () => {
|
|
|
|
|
|
emit('close');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toggleDebugMode = () => {
|
|
|
|
|
|
debugMode.value = !debugMode.value;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const getConfigLabel = (key, value) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
// console.log(configurableItems)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (value.description && value.name !== key) {
|
|
|
|
|
|
return `${value.name}(${key})`;
|
|
|
|
|
|
}
|
|
|
|
|
|
return key;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const getPlaceholder = (key, value) => {
|
|
|
|
|
|
return `(默认: ${value.default})`;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleModelChange = (data) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
model: `${data.provider}/${data.name}`
|
|
|
|
|
|
});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 多选相关方法
|
|
|
|
|
|
const ensureArray = (key) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const config = agentConfig.value || {};
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (!config[key] || !Array.isArray(config[key])) {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
return [];
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2025-08-25 01:46:31 +08:00
|
|
|
|
return config[key];
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const isOptionSelected = (key, option) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const currentOptions = ensureArray(key);
|
|
|
|
|
|
return currentOptions.includes(option);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const getSelectedCount = (key) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const currentOptions = ensureArray(key);
|
|
|
|
|
|
return currentOptions.length;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toggleOption = (key, option) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const currentOptions = [...ensureArray(key)];
|
2025-08-22 23:17:48 +08:00
|
|
|
|
const index = currentOptions.indexOf(option);
|
|
|
|
|
|
|
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
|
currentOptions.splice(index, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
currentOptions.push(option);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
[key]: currentOptions
|
|
|
|
|
|
});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const clearSelection = (key) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
[key]: []
|
|
|
|
|
|
});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 工具相关方法
|
|
|
|
|
|
const getToolNameById = (toolId) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const toolsList = availableTools.value ? Object.values(availableTools.value) : [];
|
|
|
|
|
|
const tool = toolsList.find(t => t.id === toolId);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
return tool ? tool.name : toolId;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const loadAvailableTools = async () => {
|
|
|
|
|
|
try {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
await agentStore.fetchTools();
|
2025-08-22 23:17:48 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载工具列表失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const openToolsModal = async () => {
|
|
|
|
|
|
try {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
if (!availableTools.value || Object.keys(availableTools.value).length === 0) {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
await loadAvailableTools();
|
|
|
|
|
|
}
|
2025-08-25 01:46:31 +08:00
|
|
|
|
selectedTools.value = [...(agentConfig.value?.tools || [])];
|
2025-08-22 23:17:48 +08:00
|
|
|
|
toolsModalOpen.value = true;
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('打开工具选择弹窗失败:', error);
|
|
|
|
|
|
message.error('打开工具选择弹窗失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toggleToolSelection = (toolId) => {
|
|
|
|
|
|
const index = selectedTools.value.indexOf(toolId);
|
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
|
selectedTools.value.splice(index, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
selectedTools.value.push(toolId);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const removeSelectedTool = (toolId) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
const currentTools = [...(agentConfig.value?.tools || [])];
|
|
|
|
|
|
const index = currentTools.indexOf(toolId);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (index > -1) {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
currentTools.splice(index, 1);
|
|
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
tools: currentTools
|
|
|
|
|
|
});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const confirmToolsSelection = () => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
tools: [...selectedTools.value]
|
|
|
|
|
|
});
|
2025-08-22 23:17:48 +08:00
|
|
|
|
toolsModalOpen.value = false;
|
|
|
|
|
|
toolsSearchText.value = '';
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const cancelToolsSelection = () => {
|
|
|
|
|
|
toolsModalOpen.value = false;
|
|
|
|
|
|
toolsSearchText.value = '';
|
|
|
|
|
|
selectedTools.value = [];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 配置保存和重置
|
|
|
|
|
|
const saveConfig = async () => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
if (!selectedAgentId.value) {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
message.error('没有选择智能体');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
await agentStore.saveAgentConfig();
|
2025-08-22 23:17:48 +08:00
|
|
|
|
message.success('配置已保存到服务器');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('保存配置到服务器出错:', error);
|
|
|
|
|
|
message.error('保存配置到服务器失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const resetConfig = async () => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
if (!selectedAgentId.value) {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
message.error('没有选择智能体');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.resetAgentConfig();
|
2025-08-22 23:17:48 +08:00
|
|
|
|
message.info('配置已重置');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('重置配置出错:', error);
|
|
|
|
|
|
message.error('重置配置失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 监听器
|
|
|
|
|
|
watch(() => props.isOpen, (newVal) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
if (newVal && (!availableTools.value || Object.keys(availableTools.value).length === 0)) {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
loadAvailableTools();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
|
|
|
|
|
|
|
@padding-bottom: 40px;
|
|
|
|
|
|
.agent-config-sidebar {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 0;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-left: 1px solid #e8e8e8;
|
|
|
|
|
|
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
|
|
|
|
|
|
&.open {
|
|
|
|
|
|
width: 400px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10px 20px;
|
|
|
|
|
|
border-bottom: 1px solid var(--gray-200);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
min-width: 400px;
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-title {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
|
|
|
|
|
|
.title-icon {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.close-btn {
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
padding: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
background: var(--gray-100);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-content {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
min-width: 400px;
|
|
|
|
|
|
padding-bottom: @padding-bottom;
|
|
|
|
|
|
|
|
|
|
|
|
.agent-info {
|
|
|
|
|
|
.agent-basic-info {
|
|
|
|
|
|
|
|
|
|
|
|
.agent-description {
|
|
|
|
|
|
margin: 0 0 12px 0;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.debug-toggle {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 8px 0;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
|
|
|
|
.debug-text {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.debug-info {
|
|
|
|
|
|
margin-top: 12px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
max-height: 200px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sidebar-footer {
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
bottom: 16px;
|
|
|
|
|
|
padding: 12px 0;
|
|
|
|
|
|
border-top: 1px solid var(--gray-200);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
// min-width: 400px;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
|
|
|
|
|
|
.form-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
|
|
|
|
.save-btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.reset-btn {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-form-content {
|
|
|
|
|
|
.config-form {
|
|
|
|
|
|
.config-alert {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-item {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.config-description {
|
|
|
|
|
|
margin: 4px 0 8px 0;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.model-selector {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-prompt-input {
|
|
|
|
|
|
resize: vertical;
|
2025-08-25 13:57:47 +08:00
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-select,
|
|
|
|
|
|
.config-input,
|
|
|
|
|
|
.config-input-number {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-slider {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 工具选择器样式
|
|
|
|
|
|
.tools-selector {
|
|
|
|
|
|
.tools-summary {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
|
|
|
|
|
.tools-summary-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
|
|
|
|
|
|
.tools-count {
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.clear-btn {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.select-tools-btn {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.selected-tools-preview {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
|
|
|
|
|
|
.tool-tag {
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
background: var(--gray-100);
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.anticon-close) {
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
margin-left: 4px;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 多选卡片样式
|
|
|
|
|
|
.multi-select-cards {
|
|
|
|
|
|
.multi-select-label {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.options-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-card {
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
padding: 10px 12px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.selected {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
background: var(--main-10);
|
|
|
|
|
|
|
|
|
|
|
|
.option-indicator {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-text {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.unselected {
|
|
|
|
|
|
.option-indicator {
|
|
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-text {
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
|
|
|
|
|
|
.option-text {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.option-indicator {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 工具选择弹窗样式
|
|
|
|
|
|
.tools-modal {
|
|
|
|
|
|
:deep(.ant-modal-content) {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-modal-header) {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-bottom: 1px solid var(--gray-200);
|
|
|
|
|
|
padding: 16px 20px;
|
|
|
|
|
|
|
|
|
|
|
|
.ant-modal-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-modal-body) {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tools-modal-content {
|
|
|
|
|
|
.tools-search {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
|
|
|
|
|
|
.search-input {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
|
|
|
|
|
|
.search-icon {
|
|
|
|
|
|
color: var(--gray-500);
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:focus-within {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
box-shadow: 0 0 0 2px rgba(var(--main-color-rgb), 0.1);
|
2025-08-24 20:12:15 +08:00
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
.search-icon {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--gray-400);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tools-list {
|
2025-08-24 20:12:15 +08:00
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
max-height: max(60vh, 800px);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
background: white;
|
2025-08-24 20:12:15 +08:00
|
|
|
|
|
|
|
|
|
|
// 在小屏幕下调整为单列布局
|
|
|
|
|
|
@media (max-width: 480px) {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
|
|
width: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar-track {
|
|
|
|
|
|
background: var(--gray-100);
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
|
|
|
|
background: var(--gray-400);
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&::-webkit-scrollbar-thumb:hover {
|
|
|
|
|
|
background: var(--gray-500);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tool-item {
|
|
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 4px;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
2025-08-24 20:12:15 +08:00
|
|
|
|
border-color: var(--gray-300);
|
|
|
|
|
|
background: var(--gray-20);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
.tool-content {
|
|
|
|
|
|
.tool-header {
|
|
|
|
|
|
display: flex;
|
2025-08-24 20:12:15 +08:00
|
|
|
|
align-items: center;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
margin-bottom: 6px;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
|
|
|
|
|
|
.tool-name {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tool-indicator {
|
|
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tool-description {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
display: -webkit-box;
|
|
|
|
|
|
-webkit-line-clamp: 2;
|
|
|
|
|
|
-webkit-box-orient: vertical;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-24 20:12:15 +08:00
|
|
|
|
|
|
|
|
|
|
&.selected {
|
|
|
|
|
|
background: var(--main-30);
|
|
|
|
|
|
// border-color: var(--main-color);
|
|
|
|
|
|
|
|
|
|
|
|
.tool-content {
|
|
|
|
|
|
.tool-name {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
.tool-indicator {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.tool-description {
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.tools-modal-footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding-top: 16px;
|
|
|
|
|
|
border-top: 1px solid var(--gray-200);
|
|
|
|
|
|
|
|
|
|
|
|
.selected-count {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
padding: 6px 12px;
|
|
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.modal-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.ant-btn) {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
padding: 0 16px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&.ant-btn-default {
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
color: var(--gray-700);
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.ant-btn-primary {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式适配
|
|
|
|
|
|
@media (max-width: 768px) {
|
2025-08-24 22:32:37 +08:00
|
|
|
|
.agent-config-sidebar.open {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
width: 100vw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|