2025-08-22 23:17:48 +08:00
|
|
|
|
<template>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<div class="agent-config-sidebar" :class="{ open: isOpen }">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<!-- 侧边栏头部 -->
|
|
|
|
|
|
<div class="sidebar-header">
|
2026-01-15 05:59:13 +08:00
|
|
|
|
<div class="header-center">
|
|
|
|
|
|
<a-segmented v-model:value="activeTab" :options="segmentedOptions" />
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-button type="text" size="small" @click="closeSidebar" class="close-btn">
|
2026-01-22 05:57:13 +08:00
|
|
|
|
<X :size="16" />
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 侧边栏内容 -->
|
|
|
|
|
|
<div class="sidebar-content">
|
2025-08-25 01:46:31 +08:00
|
|
|
|
<div class="agent-info" v-if="selectedAgent">
|
2026-01-22 05:57:13 +08:00
|
|
|
|
<div class="agent-basic-info">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<p class="agent-description">{{ selectedAgent.description }}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-23 19:42:51 +08:00
|
|
|
|
<!-- <a-divider /> -->
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2025-08-31 00:34:26 +08:00
|
|
|
|
<div v-if="selectedAgentId && configurableItems" class="config-form-content">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<!-- 配置表单 -->
|
|
|
|
|
|
<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
|
2026-01-15 05:59:13 +08:00
|
|
|
|
v-if="shouldShowConfig(key, value)"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:label="getConfigLabel(key, value)"
|
|
|
|
|
|
:name="key"
|
|
|
|
|
|
class="config-item"
|
|
|
|
|
|
>
|
|
|
|
|
|
<p v-if="value.description" class="config-description">{{ value.description }}</p>
|
|
|
|
|
|
|
2025-08-31 00:34:26 +08:00
|
|
|
|
<!-- <div>{{ value }}</div> -->
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<!-- 模型选择 -->
|
2025-08-31 00:34:26 +08:00
|
|
|
|
<div v-if="value.template_metadata.kind === 'llm'" class="model-selector">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<ModelSelectorComponent
|
2025-12-28 22:55:42 +08:00
|
|
|
|
@select-model="(spec) => handleModelChange(key, spec)"
|
2025-10-14 02:27:15 +08:00
|
|
|
|
:model_spec="agentConfig[key] || ''"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 系统提示词 -->
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<div
|
|
|
|
|
|
v-else-if="value.template_metadata.kind === 'prompt'"
|
|
|
|
|
|
class="system-prompt-container"
|
|
|
|
|
|
>
|
2025-09-06 14:04:33 +08:00
|
|
|
|
<!-- 编辑模式 -->
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-if="systemPromptEditMode"
|
|
|
|
|
|
:value="agentConfig[key]"
|
|
|
|
|
|
@update:value="(val) => agentStore.updateAgentConfig({ [key]: val })"
|
|
|
|
|
|
:rows="10"
|
|
|
|
|
|
:placeholder="getPlaceholder(key, value)"
|
|
|
|
|
|
class="system-prompt-input"
|
|
|
|
|
|
@blur="systemPromptEditMode = false"
|
|
|
|
|
|
ref="systemPromptTextarea"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<!-- 显示模式 -->
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<div v-else class="system-prompt-display" @click="enterEditMode">
|
2025-09-06 14:04:33 +08:00
|
|
|
|
<div
|
|
|
|
|
|
class="system-prompt-content"
|
|
|
|
|
|
:class="{ 'is-placeholder': !agentConfig[key] }"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ agentConfig[key] || getPlaceholder(key, value) }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="edit-hint">点击编辑</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 工具选择 -->
|
2026-01-22 11:16:15 +08:00
|
|
|
|
<!-- <div v-else-if="value.template_metadata.kind === 'tools'" class="tools-selector">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<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>
|
2026-01-22 11:16:15 +08:00
|
|
|
|
</div> -->
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 布尔类型 -->
|
|
|
|
|
|
<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
|
2026-01-15 06:01:34 +08:00
|
|
|
|
v-else-if="
|
|
|
|
|
|
value?.options.length > 0 && (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>
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<!-- 多选 / 工具列表 (统一处理) -->
|
|
|
|
|
|
<div v-else-if="isListConfig(key, value)" class="list-config-container">
|
|
|
|
|
|
<!-- Case 1: <= 5 options, inline list -->
|
|
|
|
|
|
<div v-if="getConfigOptions(value).length <= 5" class="multi-select-cards">
|
|
|
|
|
|
<div class="multi-select-label">
|
|
|
|
|
|
<span>已选择 {{ getSelectedCount(key) }} 项</span>
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="clear-btn"
|
|
|
|
|
|
@click="clearSelection(key)"
|
|
|
|
|
|
v-if="getSelectedCount(key) > 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
清空
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="options-grid">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="option in getConfigOptions(value)"
|
|
|
|
|
|
:key="getOptionValue(option)"
|
|
|
|
|
|
class="option-card"
|
|
|
|
|
|
:class="{
|
|
|
|
|
|
selected: isOptionSelected(key, getOptionValue(option)),
|
|
|
|
|
|
unselected: !isOptionSelected(key, getOptionValue(option))
|
|
|
|
|
|
}"
|
|
|
|
|
|
@click="toggleOption(key, getOptionValue(option))"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="option-content">
|
|
|
|
|
|
<span class="option-text">{{ getOptionLabel(option) }}</span>
|
|
|
|
|
|
<div class="option-indicator">
|
|
|
|
|
|
<Check
|
|
|
|
|
|
v-if="isOptionSelected(key, getOptionValue(option))"
|
|
|
|
|
|
:size="16"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Plus v-else :size="16" />
|
|
|
|
|
|
</div>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-22 11:40:09 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- Case 2: > 5 options, Modal trigger -->
|
|
|
|
|
|
|
|
|
|
|
|
<div v-else class="selection-container">
|
|
|
|
|
|
<div class="selection-summary">
|
|
|
|
|
|
<div class="selection-summary-info">
|
|
|
|
|
|
<span class="selection-count">已选择 {{ getSelectedCount(key) }} 项</span>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="link"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="clear-btn"
|
|
|
|
|
|
@click="clearSelection(key)"
|
|
|
|
|
|
v-if="getSelectedCount(key) > 0"
|
|
|
|
|
|
>
|
|
|
|
|
|
清空
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="primary"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
class="selection-trigger-btn"
|
|
|
|
|
|
@click="openSelectionModal(key)"
|
|
|
|
|
|
>
|
|
|
|
|
|
选择...
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Selected Preview Tags -->
|
|
|
|
|
|
|
|
|
|
|
|
<div v-if="getSelectedCount(key) > 0" class="selection-preview">
|
|
|
|
|
|
<a-tag
|
|
|
|
|
|
v-for="val in agentConfig[key]"
|
|
|
|
|
|
:key="val"
|
|
|
|
|
|
closable
|
|
|
|
|
|
@close="toggleOption(key, val)"
|
|
|
|
|
|
class="selection-tag"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ getOptionLabelFromValue(key, val) }}
|
|
|
|
|
|
</a-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</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>
|
2026-01-15 05:59:13 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 固定在底部的操作按钮 -->
|
2026-01-22 05:57:13 +08:00
|
|
|
|
<div class="sidebar-footer" v-if="!isEmptyConfig && userStore.isAdmin">
|
2026-01-15 05:59:13 +08:00
|
|
|
|
<div class="form-actions">
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-button
|
2026-01-22 05:57:13 +08:00
|
|
|
|
type="primary"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
@click="saveConfig"
|
|
|
|
|
|
class="save-btn"
|
|
|
|
|
|
:class="{ changed: agentStore.hasConfigChanges }"
|
2026-01-22 05:57:13 +08:00
|
|
|
|
:disabled="isSavingConfig"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
>
|
2026-01-22 05:57:13 +08:00
|
|
|
|
保存
|
2026-01-15 05:59:13 +08:00
|
|
|
|
</a-button>
|
2026-01-22 05:57:13 +08:00
|
|
|
|
|
|
|
|
|
|
<a-tooltip :title="isCurrentDefault ? '当前已是默认配置' : '设为默认配置'">
|
|
|
|
|
|
<a-button type="text" shape="circle" class="icon-btn" @click="setAsDefault">
|
|
|
|
|
|
<Star
|
|
|
|
|
|
:size="18"
|
|
|
|
|
|
:fill="isCurrentDefault ? 'currentColor' : 'none'"
|
|
|
|
|
|
:class="{ 'is-default': isCurrentDefault }"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
|
|
|
|
|
|
<a-tooltip title="删除配置">
|
|
|
|
|
|
<a-button
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
shape="circle"
|
|
|
|
|
|
danger
|
|
|
|
|
|
class="icon-btn"
|
|
|
|
|
|
@click="confirmDeleteConfig"
|
|
|
|
|
|
:disabled="isDeletingConfig"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Trash2 :size="18" />
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</a-tooltip>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<!-- 通用选择弹窗 -->
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<a-modal
|
2026-01-22 11:40:09 +08:00
|
|
|
|
v-model:open="selectionModalOpen"
|
|
|
|
|
|
:title="`选择${configurableItems[currentConfigKey]?.name || '项目'}`"
|
2025-10-14 01:46:43 +08:00
|
|
|
|
:width="800"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
:footer="null"
|
|
|
|
|
|
:maskClosable="false"
|
2026-01-22 11:40:09 +08:00
|
|
|
|
class="selection-modal"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
>
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<div class="selection-modal-content">
|
|
|
|
|
|
<div class="selection-search">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<a-input
|
2026-01-22 11:40:09 +08:00
|
|
|
|
v-model:value="selectionSearchText"
|
|
|
|
|
|
placeholder="搜索..."
|
2025-08-22 23:17:48 +08:00
|
|
|
|
allow-clear
|
|
|
|
|
|
class="search-input"
|
|
|
|
|
|
>
|
|
|
|
|
|
<template #prefix>
|
2026-01-22 05:57:13 +08:00
|
|
|
|
<Search :size="16" class="search-icon" />
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
</a-input>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<div class="selection-list">
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<div
|
2026-01-22 11:40:09 +08:00
|
|
|
|
v-for="option in filteredOptions"
|
|
|
|
|
|
:key="getOptionValue(option)"
|
|
|
|
|
|
class="selection-item"
|
|
|
|
|
|
:class="{ selected: tempSelectedValues.includes(getOptionValue(option)) }"
|
|
|
|
|
|
@click="toggleModalSelection(getOptionValue(option))"
|
2025-08-22 23:17:48 +08:00
|
|
|
|
>
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<div class="selection-item-content">
|
|
|
|
|
|
<div class="selection-item-header">
|
|
|
|
|
|
<span class="selection-item-name">{{ getOptionLabel(option) }}</span>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="selection-item-indicator">
|
|
|
|
|
|
<Check v-if="tempSelectedValues.includes(getOptionValue(option))" :size="16" />
|
|
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
<Plus v-else :size="16" />
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-22 11:40:09 +08:00
|
|
|
|
|
|
|
|
|
|
<div v-if="getOptionDescription(option)" class="selection-item-description">
|
|
|
|
|
|
{{ getOptionDescription(option) }}
|
|
|
|
|
|
</div>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<div class="selection-modal-footer">
|
|
|
|
|
|
<div class="selected-count">已选择 {{ tempSelectedValues.length }} 项</div>
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
<div class="modal-actions">
|
2026-01-22 11:40:09 +08:00
|
|
|
|
<a-button @click="closeSelectionModal">取消</a-button>
|
|
|
|
|
|
|
|
|
|
|
|
<a-button type="primary" @click="confirmSelection">确认</a-button>
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</a-modal>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-01-22 12:15:46 +08:00
|
|
|
|
import { ref, computed, nextTick, watch } from 'vue'
|
2026-01-22 05:57:13 +08:00
|
|
|
|
import { message, Modal } from 'ant-design-vue'
|
2026-01-22 11:40:09 +08:00
|
|
|
|
import { X, Trash2, Check, Plus, Search, Star } from 'lucide-vue-next'
|
2026-01-15 06:01:34 +08:00
|
|
|
|
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue'
|
|
|
|
|
|
import { useAgentStore } from '@/stores/agent'
|
2026-01-22 05:57:13 +08:00
|
|
|
|
import { useUserStore } from '@/stores/user'
|
2026-01-22 12:15:46 +08:00
|
|
|
|
import { useDatabaseStore } from '@/stores/database'
|
2026-01-15 06:01:34 +08:00
|
|
|
|
import { storeToRefs } from 'pinia'
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
// Props
|
2026-01-22 12:15:46 +08:00
|
|
|
|
const props = defineProps({
|
2025-08-22 23:17:48 +08:00
|
|
|
|
isOpen: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
2026-01-22 05:57:13 +08:00
|
|
|
|
},
|
|
|
|
|
|
disabled: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
// Emits
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const emit = defineEmits(['close'])
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2025-08-25 01:46:31 +08:00
|
|
|
|
// Store 管理
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const agentStore = useAgentStore()
|
2026-01-22 05:57:13 +08:00
|
|
|
|
const userStore = useUserStore()
|
2026-01-22 12:15:46 +08:00
|
|
|
|
const databaseStore = useDatabaseStore()
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => props.isOpen,
|
|
|
|
|
|
(val) => {
|
|
|
|
|
|
if (val) {
|
|
|
|
|
|
databaseStore.loadDatabases().catch(() => {})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
const {
|
|
|
|
|
|
availableTools,
|
|
|
|
|
|
selectedAgent,
|
|
|
|
|
|
selectedAgentId,
|
|
|
|
|
|
selectedAgentConfigId,
|
|
|
|
|
|
selectedConfigSummary,
|
|
|
|
|
|
agentConfigs,
|
|
|
|
|
|
agentConfig,
|
|
|
|
|
|
configurableItems
|
|
|
|
|
|
} = storeToRefs(agentStore)
|
2025-08-25 01:46:31 +08:00
|
|
|
|
|
|
|
|
|
|
// console.log(availableTools.value)
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
// 本地状态
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const selectionModalOpen = ref(false)
|
|
|
|
|
|
const currentConfigKey = ref(null)
|
|
|
|
|
|
const tempSelectedValues = ref([])
|
|
|
|
|
|
const selectionSearchText = ref('')
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const systemPromptEditMode = ref(false)
|
|
|
|
|
|
const activeTab = ref('basic')
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const isEmptyConfig = computed(() => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return !selectedAgentId.value || Object.keys(configurableItems.value).length === 0
|
|
|
|
|
|
})
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
const isCurrentDefault = computed(() => {
|
|
|
|
|
|
return !!selectedConfigSummary.value?.is_default
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const isSavingConfig = ref(false)
|
|
|
|
|
|
const isDeletingConfig = ref(false)
|
|
|
|
|
|
|
2026-01-15 05:59:13 +08:00
|
|
|
|
const hasOtherConfigs = computed(() => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
if (isEmptyConfig.value) return false
|
2026-01-22 11:40:09 +08:00
|
|
|
|
return Object.entries(configurableItems.value).some(([, value]) => {
|
|
|
|
|
|
const isBasic =
|
|
|
|
|
|
value.template_metadata?.kind === 'prompt' || value.template_metadata?.kind === 'llm'
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const isTools =
|
2026-01-22 11:16:15 +08:00
|
|
|
|
value.template_metadata?.kind === 'mcps' ||
|
|
|
|
|
|
value.template_metadata?.kind === 'knowledges' ||
|
|
|
|
|
|
value.template_metadata?.kind === 'tools'
|
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return !isBasic && !isTools
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
const segmentedOptions = computed(() => {
|
|
|
|
|
|
const options = [
|
|
|
|
|
|
{ label: '基础', value: 'basic' },
|
|
|
|
|
|
{ label: '工具', value: 'tools' }
|
2026-01-15 06:01:34 +08:00
|
|
|
|
]
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
if (hasOtherConfigs.value) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
options.push({ label: '其他', value: 'other' })
|
2026-01-15 05:59:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return options
|
|
|
|
|
|
})
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
// 通用选项获取与处理
|
|
|
|
|
|
const getConfigOptions = (value) => {
|
|
|
|
|
|
if (value?.template_metadata?.kind === 'tools') {
|
|
|
|
|
|
return availableTools.value ? Object.values(availableTools.value) : []
|
|
|
|
|
|
}
|
2026-01-22 12:15:46 +08:00
|
|
|
|
if (value?.template_metadata?.kind === 'knowledges') {
|
|
|
|
|
|
return databaseStore.databases || []
|
|
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
return value?.options || []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const isListConfig = (key, value) => {
|
|
|
|
|
|
const isTools = value?.template_metadata?.kind === 'tools'
|
|
|
|
|
|
const isList = value?.type === 'list'
|
|
|
|
|
|
return isTools || isList
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getOptionValue = (option) => {
|
|
|
|
|
|
if (typeof option === 'object' && option !== null) {
|
|
|
|
|
|
return option.id || option.value || option.name
|
|
|
|
|
|
}
|
|
|
|
|
|
return option
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getOptionLabel = (option) => {
|
|
|
|
|
|
if (typeof option === 'object' && option !== null) {
|
|
|
|
|
|
return option.name || option.label || option.id
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
return option
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getOptionDescription = (option) => {
|
|
|
|
|
|
if (typeof option === 'object' && option !== null) {
|
|
|
|
|
|
return option.description || '暂无描述'
|
|
|
|
|
|
}
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const filteredOptions = computed(() => {
|
|
|
|
|
|
if (!currentConfigKey.value) return []
|
|
|
|
|
|
const key = currentConfigKey.value
|
|
|
|
|
|
const configItem = configurableItems.value[key]
|
|
|
|
|
|
const options = getConfigOptions(configItem)
|
|
|
|
|
|
|
|
|
|
|
|
if (!selectionSearchText.value) return options
|
|
|
|
|
|
|
|
|
|
|
|
const search = selectionSearchText.value.toLowerCase()
|
|
|
|
|
|
return options.filter((opt) => {
|
|
|
|
|
|
const label = String(getOptionLabel(opt)).toLowerCase()
|
|
|
|
|
|
const desc = String(getOptionDescription(opt) || '').toLowerCase()
|
|
|
|
|
|
return label.includes(search) || desc.includes(search)
|
|
|
|
|
|
})
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 方法
|
2026-01-15 05:59:13 +08:00
|
|
|
|
const shouldShowConfig = (key, value) => {
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const isBasic =
|
|
|
|
|
|
value.template_metadata?.kind === 'prompt' || value.template_metadata?.kind === 'llm'
|
2026-01-22 11:16:15 +08:00
|
|
|
|
const isTools =
|
|
|
|
|
|
value.template_metadata?.kind === 'mcps' ||
|
|
|
|
|
|
value.template_metadata?.kind === 'knowledges' ||
|
|
|
|
|
|
value.template_metadata?.kind === 'tools'
|
|
|
|
|
|
|
2026-01-15 05:59:13 +08:00
|
|
|
|
if (activeTab.value === 'basic') {
|
|
|
|
|
|
// 基础:System Prompt, LLM Model
|
2026-01-22 11:16:15 +08:00
|
|
|
|
return isBasic
|
2026-01-15 05:59:13 +08:00
|
|
|
|
} else if (activeTab.value === 'tools') {
|
|
|
|
|
|
// 工具:Tools, MCPs, Knowledges
|
2026-01-22 11:16:15 +08:00
|
|
|
|
return isTools
|
2026-01-15 05:59:13 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 其他:剩余所有配置
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return !isBasic && !isTools
|
2026-01-15 05:59:13 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
const closeSidebar = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
emit('close')
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
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) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return `${value.name}`
|
2025-11-23 19:42:51 +08:00
|
|
|
|
// return `${value.name}(${key})`;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return key
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const getPlaceholder = (key, value) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return `(默认: ${value.default})`
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2025-12-28 22:55:42 +08:00
|
|
|
|
const handleModelChange = (key, spec) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
if (typeof spec !== 'string' || !spec) return
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
2025-12-28 22:55:42 +08:00
|
|
|
|
[key]: spec
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 多选相关方法
|
|
|
|
|
|
const ensureArray = (key) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const config = agentConfig.value || {}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (!config[key] || !Array.isArray(config[key])) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return []
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return config[key]
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const isOptionSelected = (key, option) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const currentOptions = ensureArray(key)
|
|
|
|
|
|
return currentOptions.includes(option)
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const getSelectedCount = (key) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const currentOptions = ensureArray(key)
|
|
|
|
|
|
return currentOptions.length
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const toggleOption = (key, option) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const currentOptions = [...ensureArray(key)]
|
|
|
|
|
|
const index = currentOptions.indexOf(option)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
if (index > -1) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
currentOptions.splice(index, 1)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
} else {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
currentOptions.push(option)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
[key]: currentOptions
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
const clearSelection = (key) => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
|
|
|
|
|
[key]: []
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
// 统一选择弹窗相关方法
|
|
|
|
|
|
const getOptionLabelFromValue = (key, val) => {
|
|
|
|
|
|
const options = getConfigOptions(configurableItems.value[key])
|
|
|
|
|
|
const option = options.find((opt) => getOptionValue(opt) === val)
|
|
|
|
|
|
return option ? getOptionLabel(option) : val
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const openSelectionModal = async (key) => {
|
|
|
|
|
|
currentConfigKey.value = key
|
|
|
|
|
|
// 如果是工具,可能需要刷新
|
|
|
|
|
|
if (configurableItems.value[key]?.template_metadata?.kind === 'tools' && selectedAgentId.value) {
|
|
|
|
|
|
try {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
await agentStore.fetchAgentDetail(selectedAgentId.value, true)
|
2026-01-22 11:40:09 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('刷新工具列表失败:', error)
|
2025-12-24 18:52:14 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-22 12:15:46 +08:00
|
|
|
|
// 如果是知识库,需要获取知识库列表
|
|
|
|
|
|
if (configurableItems.value[key]?.template_metadata?.kind === 'knowledges') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await databaseStore.loadDatabases()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载知识库列表失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const currentValues = agentConfig.value[key] || []
|
|
|
|
|
|
tempSelectedValues.value = [...currentValues]
|
|
|
|
|
|
selectionModalOpen.value = true
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const toggleModalSelection = (optionValue) => {
|
|
|
|
|
|
const index = tempSelectedValues.value.indexOf(optionValue)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
if (index > -1) {
|
2026-01-22 11:40:09 +08:00
|
|
|
|
tempSelectedValues.value.splice(index, 1)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
} else {
|
2026-01-22 11:40:09 +08:00
|
|
|
|
tempSelectedValues.value.push(optionValue)
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const confirmSelection = () => {
|
|
|
|
|
|
if (currentConfigKey.value) {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
agentStore.updateAgentConfig({
|
2026-01-22 11:40:09 +08:00
|
|
|
|
[currentConfigKey.value]: [...tempSelectedValues.value]
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
closeSelectionModal()
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
const closeSelectionModal = () => {
|
|
|
|
|
|
selectionModalOpen.value = false
|
|
|
|
|
|
currentConfigKey.value = null
|
|
|
|
|
|
tempSelectedValues.value = []
|
|
|
|
|
|
selectionSearchText.value = ''
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2025-09-06 14:04:33 +08:00
|
|
|
|
// 系统提示词编辑相关方法
|
|
|
|
|
|
const enterEditMode = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
systemPromptEditMode.value = true
|
2025-09-06 14:04:33 +08:00
|
|
|
|
// 使用 nextTick 确保 DOM 更新后再聚焦
|
|
|
|
|
|
nextTick(() => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const textarea = document.querySelector('.system-prompt-input')
|
2025-09-06 14:04:33 +08:00
|
|
|
|
if (textarea) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
textarea.focus()
|
2025-09-06 14:04:33 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-09-06 14:04:33 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 验证和过滤配置项
|
|
|
|
|
|
const validateAndFilterConfig = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const validatedConfig = { ...agentConfig.value }
|
|
|
|
|
|
const configItems = configurableItems.value
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 遍历所有配置项
|
2026-01-15 06:01:34 +08:00
|
|
|
|
Object.keys(configItems).forEach((key) => {
|
|
|
|
|
|
const configItem = configItems[key]
|
|
|
|
|
|
const currentValue = validatedConfig[key]
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 检查工具配置
|
|
|
|
|
|
if (configItem.template_metadata?.kind === 'tools' && Array.isArray(currentValue)) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const availableToolIds = availableTools.value
|
|
|
|
|
|
? Object.values(availableTools.value).map((tool) => tool.id)
|
|
|
|
|
|
: []
|
|
|
|
|
|
validatedConfig[key] = currentValue.filter((toolId) => availableToolIds.includes(toolId))
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
if (validatedConfig[key].length !== currentValue.length) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.warn(`工具配置 ${key} 中包含无效的工具ID,已自动过滤`)
|
2025-09-01 22:28:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 检查多选配置项 (type === 'list' 且有 options)
|
|
|
|
|
|
else if (configItem.type === 'list' && configItem.options && Array.isArray(currentValue)) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const validOptions = configItem.options
|
|
|
|
|
|
validatedConfig[key] = currentValue.filter((value) => validOptions.includes(value))
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
if (validatedConfig[key].length !== currentValue.length) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.warn(`配置项 ${key} 中包含无效的选项,已自动过滤`)
|
2025-09-01 22:28:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
return validatedConfig
|
|
|
|
|
|
}
|
2025-09-01 22:28:07 +08:00
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
// 配置保存和重置
|
|
|
|
|
|
const saveConfig = async () => {
|
2025-08-25 01:46:31 +08:00
|
|
|
|
if (!selectedAgentId.value) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
message.error('没有选择智能体')
|
|
|
|
|
|
return
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
if (!agentStore.hasConfigChanges) return
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
try {
|
2026-01-22 05:57:13 +08:00
|
|
|
|
isSavingConfig.value = true
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 验证和过滤配置
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const validatedConfig = validateAndFilterConfig()
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2025-09-01 22:28:07 +08:00
|
|
|
|
// 如果配置有变化,先更新到store
|
|
|
|
|
|
if (JSON.stringify(validatedConfig) !== JSON.stringify(agentConfig.value)) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
agentStore.updateAgentConfig(validatedConfig)
|
|
|
|
|
|
message.info('检测到无效配置项,已自动过滤')
|
2025-09-01 22:28:07 +08:00
|
|
|
|
}
|
2025-09-02 19:53:12 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
await agentStore.saveAgentConfig()
|
|
|
|
|
|
message.success('配置已保存到服务器')
|
2025-08-22 23:17:48 +08:00
|
|
|
|
} catch (error) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.error('保存配置到服务器出错:', error)
|
|
|
|
|
|
message.error('保存配置到服务器失败')
|
2026-01-22 05:57:13 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
isSavingConfig.value = false
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
const setAsDefault = async () => {
|
|
|
|
|
|
if (!selectedAgentId.value || !selectedAgentConfigId.value) return
|
|
|
|
|
|
try {
|
|
|
|
|
|
await agentStore.setSelectedAgentConfigDefault()
|
|
|
|
|
|
message.success('已设为默认配置')
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('设置默认配置出错:', error)
|
|
|
|
|
|
message.error('设置默认配置失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const confirmDeleteConfig = async () => {
|
|
|
|
|
|
if (!selectedAgentId.value || !selectedAgentConfigId.value) return
|
|
|
|
|
|
|
|
|
|
|
|
const currentName = selectedConfigSummary.value?.name || '当前配置'
|
|
|
|
|
|
const list = agentConfigs.value[selectedAgentId.value] || []
|
|
|
|
|
|
const content =
|
|
|
|
|
|
list.length <= 1
|
|
|
|
|
|
? `将删除「${currentName}」。删除后系统会自动创建一个新的默认配置。`
|
|
|
|
|
|
: `将删除「${currentName}」。`
|
|
|
|
|
|
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: '确认删除配置?',
|
|
|
|
|
|
content,
|
|
|
|
|
|
okText: '删除',
|
|
|
|
|
|
okType: 'danger',
|
|
|
|
|
|
cancelText: '取消',
|
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
|
isDeletingConfig.value = true
|
|
|
|
|
|
try {
|
|
|
|
|
|
await agentStore.deleteSelectedAgentConfigProfile()
|
|
|
|
|
|
message.success('配置已删除')
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('删除配置出错:', error)
|
|
|
|
|
|
message.error('删除配置失败')
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
isDeletingConfig.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
2025-10-14 01:46:43 +08:00
|
|
|
|
@padding-bottom: 0px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
.agent-config-sidebar {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 0;
|
|
|
|
|
|
height: 100vh;
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
|
|
|
|
|
border-left: 1px solid var(--gray-200);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
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;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
padding: 0 20px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
border-bottom: 1px solid var(--gray-200);
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
min-width: 400px;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
height: 56px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-15 05:59:13 +08:00
|
|
|
|
.header-center {
|
|
|
|
|
|
flex: 1;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
display: flex;
|
2026-01-15 05:59:13 +08:00
|
|
|
|
justify-content: center;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-form-content {
|
2026-01-15 05:59:13 +08:00
|
|
|
|
margin-bottom: 20px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
.config-form {
|
|
|
|
|
|
.config-alert {
|
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-item {
|
2025-12-07 23:38:20 +08:00
|
|
|
|
background-color: var(--gray-25);
|
2025-11-23 19:42:51 +08:00
|
|
|
|
padding: 12px;
|
|
|
|
|
|
border-radius: 8px;
|
2025-12-23 01:51:05 +08:00
|
|
|
|
border: 1px solid var(--gray-100);
|
|
|
|
|
|
// box-shadow: 0px 0px 2px var(--shadow-3);
|
2025-11-23 19:42:51 +08:00
|
|
|
|
|
2026-01-22 12:15:46 +08:00
|
|
|
|
:deep(.ant-form-item-label > label) {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-23 19:42:51 +08:00
|
|
|
|
:deep(label.form_item_model) {
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
.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
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-06 14:04:33 +08:00
|
|
|
|
.system-prompt-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-prompt-display {
|
|
|
|
|
|
min-height: 60px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
background: var(--gray-25);
|
|
|
|
|
|
|
|
|
|
|
|
.edit-hint {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.system-prompt-content {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
font-size: 14px;
|
2025-09-06 14:04:33 +08:00
|
|
|
|
// min-height: 100px;
|
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
&.is-placeholder {
|
|
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
font-style: italic;
|
|
|
|
|
|
}
|
2025-09-06 14:04:33 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
&:empty::before {
|
|
|
|
|
|
content: attr(data-placeholder);
|
|
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-06 14:04:33 +08:00
|
|
|
|
|
|
|
|
|
|
.edit-hint {
|
|
|
|
|
|
position: absolute;
|
2026-01-15 06:01:34 +08:00
|
|
|
|
top: -32px;
|
|
|
|
|
|
right: 0px;
|
2025-09-06 14:04:33 +08:00
|
|
|
|
font-size: 12px;
|
2026-01-15 06:01:34 +08:00
|
|
|
|
color: var(--main-800);
|
2025-09-06 14:04:33 +08:00
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transition: opacity 0.2s ease;
|
2025-11-25 22:34:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-09-06 14:04:33 +08:00
|
|
|
|
padding: 2px 6px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
.config-select,
|
|
|
|
|
|
.config-input,
|
|
|
|
|
|
.config-input-number {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.config-slider {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
.sidebar-footer {
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
border-top: 1px solid var(--gray-100);
|
|
|
|
|
|
background: var(--gray-0);
|
|
|
|
|
|
// min-width: 400px;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
flex-shrink: 0; // Ensure footer doesn't shrink
|
|
|
|
|
|
|
|
|
|
|
|
.form-actions {
|
|
|
|
|
|
display: flex;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
flex-direction: row;
|
2026-01-15 05:59:13 +08:00
|
|
|
|
gap: 12px;
|
|
|
|
|
|
justify-content: space-between;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.icon-btn {
|
|
|
|
|
|
width: 36px;
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
background: var(--gray-0);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover:not(:disabled) {
|
|
|
|
|
|
color: var(--main-600);
|
|
|
|
|
|
border-color: var(--main-200);
|
|
|
|
|
|
background: var(--main-10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.is-default {
|
|
|
|
|
|
// color: var(--main-500);
|
|
|
|
|
|
color: var(--color-warning-500);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&[danger]:hover:not(:disabled) {
|
|
|
|
|
|
color: var(--error-600);
|
|
|
|
|
|
border-color: var(--error-200);
|
|
|
|
|
|
background: var(--error-10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
border-color: var(--gray-200);
|
|
|
|
|
|
|
|
|
|
|
|
&.is-default {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
.save-btn {
|
|
|
|
|
|
flex: 1;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
height: 36px;
|
2026-01-15 05:59:13 +08:00
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
font-size: 14px;
|
2026-01-22 05:57:13 +08:00
|
|
|
|
background-color: var(--gray-100);
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
transition: all 0.2s ease;
|
2026-01-15 05:59:13 +08:00
|
|
|
|
|
|
|
|
|
|
&.changed {
|
|
|
|
|
|
background-color: var(--main-color);
|
|
|
|
|
|
color: var(--gray-0);
|
2026-01-22 05:57:13 +08:00
|
|
|
|
border-color: var(--main-color);
|
2026-01-15 05:59:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
&:hover:not(:disabled) {
|
2026-01-15 05:59:13 +08:00
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 05:57:13 +08:00
|
|
|
|
&:disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
background-color: var(--gray-100);
|
|
|
|
|
|
border-color: var(--gray-200);
|
|
|
|
|
|
color: var(--gray-400);
|
2026-01-15 05:59:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
// 选择器样式
|
|
|
|
|
|
.selection-container {
|
|
|
|
|
|
.selection-summary {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 6px 12px;
|
2025-10-02 19:59:35 +08:00
|
|
|
|
background: var(--gray-20);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-summary-info {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
font-size: 13px;
|
2025-10-02 19:59:35 +08:00
|
|
|
|
color: var(--gray-900);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-count {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-trigger-btn {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
border: none;
|
2025-10-02 19:59:35 +08:00
|
|
|
|
border-radius: 4px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
height: 28px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-preview {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-tag {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 4px 8px;
|
2026-01-22 11:40:09 +08:00
|
|
|
|
border-radius: 8px;
|
2025-10-02 19:59:35 +08:00
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
border: 1px solid var(--gray-200);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
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);
|
2025-11-25 22:34:44 +08:00
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 8px 12px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s ease;
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
&: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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
// 选择弹窗样式
|
|
|
|
|
|
.selection-modal {
|
|
|
|
|
|
.selection-modal-content {
|
|
|
|
|
|
.selection-search {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
|
|
|
|
|
|
|
.search-input {
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
border: 1px solid var(--gray-300);
|
|
|
|
|
|
height: 36px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-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;
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
padding: 12px 16px;
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-bottom: 4px;
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
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
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-content {
|
|
|
|
|
|
.selection-item-header {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
display: flex;
|
2025-08-24 20:12:15 +08:00
|
|
|
|
align-items: center;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
gap: 8px;
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-name {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: var(--gray-900);
|
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-indicator {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
color: var(--gray-400);
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-description {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
line-height: 1.4;
|
2026-01-22 11:40:09 +08:00
|
|
|
|
margin-top: 6px;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
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 {
|
2026-01-22 11:40:09 +08:00
|
|
|
|
background: var(--main-10);
|
|
|
|
|
|
border-color: var(--main-color);
|
2025-08-24 20:12:15 +08:00
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-content {
|
|
|
|
|
|
.selection-item-name {
|
2025-11-25 22:34:44 +08:00
|
|
|
|
color: var(--main-800);
|
2025-08-24 20:12:15 +08:00
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-indicator {
|
2025-11-25 22:34:44 +08:00
|
|
|
|
color: var(--main-800);
|
2025-08-24 20:12:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-item-description {
|
2025-11-25 22:34:44 +08:00
|
|
|
|
color: var(--gray-900);
|
2025-08-24 20:12:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 11:40:09 +08:00
|
|
|
|
.selection-modal-footer {
|
2025-08-22 23:17:48 +08:00
|
|
|
|
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);
|
2025-11-23 01:39:44 +08:00
|
|
|
|
background: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.ant-btn-primary {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
border: none;
|
2025-11-23 01:39:44 +08:00
|
|
|
|
color: var(--gray-0);
|
2025-08-22 23:17:48 +08:00
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background: var(--main-color);
|
|
|
|
|
|
opacity: 0.9;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-30 19:01:45 +08:00
|
|
|
|
.clear-btn {
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--main-700);
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
color: var(--main-800);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-22 23:17:48 +08:00
|
|
|
|
// 响应式适配
|
|
|
|
|
|
@media (max-width: 768px) {
|
2025-08-24 22:32:37 +08:00
|
|
|
|
.agent-config-sidebar.open {
|
2026-01-15 04:54:53 +08:00
|
|
|
|
width: 100%;
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2026-01-22 05:57:13 +08:00
|
|
|
|
|
|
|
|
|
|
.sidebar-header,
|
|
|
|
|
|
.sidebar-content {
|
|
|
|
|
|
min-width: 100% !important;
|
|
|
|
|
|
}
|
2025-08-22 23:17:48 +08:00
|
|
|
|
}
|
2025-10-14 01:46:43 +08:00
|
|
|
|
</style>
|