2025-12-09 16:21:18 +08:00
|
|
|
|
<template>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-modal
|
|
|
|
|
|
v-model:open="visible"
|
|
|
|
|
|
title="自动生成评估基准"
|
|
|
|
|
|
width="600px"
|
2026-05-19 14:52:54 +08:00
|
|
|
|
:mask-closable="!generating"
|
|
|
|
|
|
:closable="!generating"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
@cancel="handleCancel"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-form ref="formRef" :model="formState" :rules="rules" layout="vertical">
|
|
|
|
|
|
<a-form-item label="基准名称" name="name">
|
|
|
|
|
|
<a-input v-model:value="formState.name" placeholder="请输入评估基准名称" />
|
|
|
|
|
|
</a-form-item>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-form-item label="描述" name="description">
|
|
|
|
|
|
<a-textarea
|
|
|
|
|
|
v-model:value="formState.description"
|
|
|
|
|
|
placeholder="请输入评估基准描述(可选)"
|
|
|
|
|
|
:rows="3"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
2025-12-10 22:48:53 +08:00
|
|
|
|
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<a-form-item label="构建方式" name="generation_mode">
|
|
|
|
|
|
<div class="generation-mode-cards" role="radiogroup" aria-label="构建方式">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="option in generationModeOptions"
|
|
|
|
|
|
:key="option.value"
|
|
|
|
|
|
class="generation-mode-card"
|
|
|
|
|
|
:class="{
|
|
|
|
|
|
active: formState.generation_mode === option.value,
|
|
|
|
|
|
disabled: option.disabled
|
|
|
|
|
|
}"
|
|
|
|
|
|
role="radio"
|
|
|
|
|
|
:aria-checked="formState.generation_mode === option.value"
|
|
|
|
|
|
:aria-disabled="option.disabled"
|
|
|
|
|
|
:tabindex="option.disabled ? -1 : 0"
|
|
|
|
|
|
@click="selectGenerationMode(option)"
|
|
|
|
|
|
@keydown.enter.prevent="selectGenerationMode(option)"
|
|
|
|
|
|
@keydown.space.prevent="selectGenerationMode(option)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="card-header">
|
|
|
|
|
|
<component :is="option.icon" class="mode-icon" />
|
|
|
|
|
|
<span class="mode-title">{{ option.label }}</span>
|
|
|
|
|
|
<a-tag v-if="option.tag" class="mode-tag" size="small">{{ option.tag }}</a-tag>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="card-description">{{ option.description }}</div>
|
|
|
|
|
|
<div v-if="option.helper" class="card-helper" :class="{ warning: option.disabled }">
|
|
|
|
|
|
{{ option.helper }}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-05-20 10:25:01 +08:00
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<a-form-item
|
|
|
|
|
|
label="LLM模型配置"
|
|
|
|
|
|
name="llm_model_spec"
|
|
|
|
|
|
:rules="[{ required: true, message: '请选择LLM模型' }]"
|
|
|
|
|
|
>
|
|
|
|
|
|
<ModelSelectorComponent
|
|
|
|
|
|
:model_spec="formState.llm_model_spec"
|
|
|
|
|
|
placeholder="选择用于生成问题的LLM模型"
|
|
|
|
|
|
@select-model="handleSelectLLMModel"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
|
|
|
|
|
|
<a-form-item label="生成参数" name="params">
|
2025-12-09 16:21:18 +08:00
|
|
|
|
<a-row :gutter="16">
|
|
|
|
|
|
<a-col :span="12">
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-form-item
|
|
|
|
|
|
label="问题数量"
|
|
|
|
|
|
name="count"
|
|
|
|
|
|
:labelCol="{ span: 24 }"
|
|
|
|
|
|
:wrapperCol="{ span: 24 }"
|
|
|
|
|
|
>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
<a-input-number
|
2026-01-15 06:01:34 +08:00
|
|
|
|
v-model:value="formState.count"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="100"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
style="width: 100%"
|
2026-01-15 06:01:34 +08:00
|
|
|
|
placeholder="生成问题数量"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-col>
|
|
|
|
|
|
<a-col :span="12">
|
2026-01-15 06:01:34 +08:00
|
|
|
|
<a-form-item
|
|
|
|
|
|
name="neighbors_count"
|
|
|
|
|
|
:labelCol="{ span: 24 }"
|
|
|
|
|
|
:wrapperCol="{ span: 24 }"
|
|
|
|
|
|
>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<template #label>
|
|
|
|
|
|
<span class="field-label-with-help">
|
|
|
|
|
|
候选 Chunk 数量
|
|
|
|
|
|
<a-tooltip title="每次生成问题时参考的候选 Chunk 总数">
|
|
|
|
|
|
<CircleHelp class="help-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
<a-input-number
|
2026-01-15 06:01:34 +08:00
|
|
|
|
v-model:value="formState.neighbors_count"
|
|
|
|
|
|
:min="0"
|
|
|
|
|
|
:max="10"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
style="width: 100%"
|
2026-05-21 22:09:19 +08:00
|
|
|
|
placeholder="默认 1"
|
2025-12-09 16:21:18 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-col>
|
2026-05-19 14:52:54 +08:00
|
|
|
|
<a-col :span="12">
|
|
|
|
|
|
<a-form-item
|
|
|
|
|
|
name="concurrency_count"
|
|
|
|
|
|
:labelCol="{ span: 24 }"
|
|
|
|
|
|
:wrapperCol="{ span: 24 }"
|
|
|
|
|
|
>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<template #label>
|
|
|
|
|
|
<span class="field-label-with-help">
|
|
|
|
|
|
构建并发数
|
|
|
|
|
|
<a-tooltip title="同时生成评估题目的 worker 数,过高可能触发模型服务限流">
|
|
|
|
|
|
<CircleHelp class="help-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
2026-05-19 14:52:54 +08:00
|
|
|
|
<a-input-number
|
|
|
|
|
|
v-model:value="formState.concurrency_count"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="20"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
placeholder="默认 10"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-col>
|
2026-05-20 10:25:01 +08:00
|
|
|
|
<a-col v-if="formState.generation_mode === 'graph_enhanced'" :span="12">
|
|
|
|
|
|
<a-form-item
|
|
|
|
|
|
name="graph_expand_top_k"
|
|
|
|
|
|
:labelCol="{ span: 24 }"
|
|
|
|
|
|
:wrapperCol="{ span: 24 }"
|
|
|
|
|
|
>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<template #label>
|
|
|
|
|
|
<span class="field-label-with-help">
|
|
|
|
|
|
每轮扩展 Chunk 数
|
|
|
|
|
|
<a-tooltip title="PPR 扩散后每轮加入的最高分 Chunk 数">
|
|
|
|
|
|
<CircleHelp class="help-icon" />
|
|
|
|
|
|
</a-tooltip>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</template>
|
2026-05-20 10:25:01 +08:00
|
|
|
|
<a-input-number
|
|
|
|
|
|
v-model:value="formState.graph_expand_top_k"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="3"
|
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
|
placeholder="默认 1"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a-form-item>
|
|
|
|
|
|
</a-col>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
</a-row>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
</a-form-item>
|
2025-12-11 01:34:49 +08:00
|
|
|
|
</a-form>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
<template #footer>
|
|
|
|
|
|
<div class="benchmark-modal-footer">
|
|
|
|
|
|
<div class="benchmark-help-text">
|
|
|
|
|
|
需要了解评估基准生成原理?查看
|
|
|
|
|
|
<a
|
|
|
|
|
|
class="benchmark-help-link"
|
|
|
|
|
|
href="https://xerrors.github.io/Yuxi/intro/evaluation.html"
|
|
|
|
|
|
target="_blank"
|
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
|
>
|
|
|
|
|
|
使用说明
|
|
|
|
|
|
</a>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="footer-actions">
|
|
|
|
|
|
<a-button :disabled="generating" @click="handleCancel">取消</a-button>
|
|
|
|
|
|
<a-button type="primary" :loading="generating" :disabled="generating" @click="handleGenerate">
|
|
|
|
|
|
确定
|
|
|
|
|
|
</a-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
2026-01-15 06:01:34 +08:00
|
|
|
|
</a-modal>
|
2025-12-09 16:21:18 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
import { ref, reactive, computed, watch } from 'vue'
|
2026-01-15 06:01:34 +08:00
|
|
|
|
import { message } from 'ant-design-vue'
|
2026-05-21 22:09:19 +08:00
|
|
|
|
import { CircleHelp, Database, Network } from 'lucide-vue-next'
|
2026-05-20 10:25:01 +08:00
|
|
|
|
import { evaluationApi, graphBuildApi } from '@/apis/knowledge_api'
|
2026-05-06 22:12:09 +08:00
|
|
|
|
import { useConfigStore } from '@/stores/config'
|
2026-01-15 06:01:34 +08:00
|
|
|
|
import ModelSelectorComponent from '@/components/ModelSelectorComponent.vue'
|
2026-05-06 22:12:09 +08:00
|
|
|
|
|
|
|
|
|
|
const configStore = useConfigStore()
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
visible: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
2026-05-21 19:33:00 +08:00
|
|
|
|
kbId: {
|
2025-12-09 16:21:18 +08:00
|
|
|
|
type: String,
|
|
|
|
|
|
required: true
|
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const emit = defineEmits(['update:visible', 'success'])
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-05-06 22:12:09 +08:00
|
|
|
|
// 默认基准名称
|
|
|
|
|
|
const defaultBenchmarkName = () => {
|
|
|
|
|
|
const today = new Date().toISOString().slice(0, 10)
|
2026-05-21 23:06:33 +08:00
|
|
|
|
const suffix = Array.from(
|
|
|
|
|
|
{ length: 4 },
|
|
|
|
|
|
() => '0123456789abcdefghijklmnopqrstuvwxyz'[Math.floor(Math.random() * 36)]
|
|
|
|
|
|
).join('')
|
2026-05-06 22:12:09 +08:00
|
|
|
|
return `Test-${today}-${suffix}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
// 响应式数据
|
2026-01-15 06:01:34 +08:00
|
|
|
|
const formRef = ref()
|
|
|
|
|
|
const generating = ref(false)
|
2026-05-20 10:25:01 +08:00
|
|
|
|
const graphIndexedChunks = ref(0)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
const formState = reactive({
|
2026-05-06 22:12:09 +08:00
|
|
|
|
name: defaultBenchmarkName(),
|
2025-12-09 16:21:18 +08:00
|
|
|
|
description: '',
|
|
|
|
|
|
count: 10,
|
2026-05-06 22:12:09 +08:00
|
|
|
|
neighbors_count: 1,
|
2026-05-19 14:52:54 +08:00
|
|
|
|
concurrency_count: 10,
|
2026-05-20 10:25:01 +08:00
|
|
|
|
generation_mode: 'vector',
|
|
|
|
|
|
graph_expand_top_k: 1,
|
2026-05-06 22:12:09 +08:00
|
|
|
|
llm_model_spec: configStore.config?.default_model || ''
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 表单验证规则
|
|
|
|
|
|
const rules = {
|
|
|
|
|
|
name: [
|
|
|
|
|
|
{ required: true, message: '请输入基准名称', trigger: 'blur' },
|
|
|
|
|
|
{ min: 2, max: 100, message: '基准名称长度应在2-100个字符之间', trigger: 'blur' }
|
|
|
|
|
|
],
|
2026-05-19 14:52:54 +08:00
|
|
|
|
count: [{ required: true, message: '请输入生成问题数量', trigger: 'blur' }],
|
|
|
|
|
|
concurrency_count: [{ required: true, message: '请输入构建并发数', trigger: 'blur' }]
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 双向绑定visible
|
|
|
|
|
|
const visible = computed({
|
|
|
|
|
|
get: () => props.visible,
|
|
|
|
|
|
set: (val) => emit('update:visible', val)
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-05-20 10:25:01 +08:00
|
|
|
|
const graphEnhancedDisabled = computed(() => graphIndexedChunks.value <= 0)
|
|
|
|
|
|
|
2026-05-21 22:09:19 +08:00
|
|
|
|
const generationModeOptions = computed(() => [
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 'vector',
|
|
|
|
|
|
label: '向量构建',
|
|
|
|
|
|
tag: '默认',
|
|
|
|
|
|
description: '基于向量相似度召回 chunks,稳定适用于所有知识库。',
|
|
|
|
|
|
helper: '适合快速生成通用评估基准。',
|
|
|
|
|
|
icon: Database,
|
|
|
|
|
|
disabled: false
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 'graph_enhanced',
|
|
|
|
|
|
label: '图增强构建',
|
|
|
|
|
|
tag: '图谱',
|
|
|
|
|
|
description: '在向量召回基础上结合知识图谱扩展相关 chunks。',
|
|
|
|
|
|
helper: graphEnhancedDisabled.value
|
|
|
|
|
|
? '当前知识库尚未完成图谱构建,暂不能使用图增强构建'
|
|
|
|
|
|
: `已构建图谱的 chunks:${graphIndexedChunks.value}`,
|
|
|
|
|
|
icon: Network,
|
|
|
|
|
|
disabled: graphEnhancedDisabled.value
|
|
|
|
|
|
}
|
|
|
|
|
|
])
|
2025-12-14 18:13:46 +08:00
|
|
|
|
|
2026-05-20 10:25:01 +08:00
|
|
|
|
const loadGraphBuildStatus = async () => {
|
2026-05-21 19:33:00 +08:00
|
|
|
|
if (!props.kbId) return
|
2026-05-20 10:25:01 +08:00
|
|
|
|
try {
|
2026-05-21 19:33:00 +08:00
|
|
|
|
const status = await graphBuildApi.getStatus(props.kbId)
|
2026-05-20 10:25:01 +08:00
|
|
|
|
graphIndexedChunks.value = Number(status?.indexed_chunks || 0)
|
|
|
|
|
|
if (graphEnhancedDisabled.value && formState.generation_mode === 'graph_enhanced') {
|
|
|
|
|
|
formState.generation_mode = 'vector'
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载图谱构建状态失败:', error)
|
|
|
|
|
|
graphIndexedChunks.value = 0
|
|
|
|
|
|
if (formState.generation_mode === 'graph_enhanced') {
|
|
|
|
|
|
formState.generation_mode = 'vector'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-21 22:09:19 +08:00
|
|
|
|
const selectGenerationMode = (option) => {
|
|
|
|
|
|
if (option.disabled) return
|
|
|
|
|
|
formState.generation_mode = option.value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
// 生成基准
|
|
|
|
|
|
const handleGenerate = async () => {
|
2026-05-19 14:52:54 +08:00
|
|
|
|
if (generating.value) return
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 表单验证
|
2026-01-15 06:01:34 +08:00
|
|
|
|
await formRef.value.validate()
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
|
generating.value = true
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
name: formState.name,
|
|
|
|
|
|
description: formState.description,
|
|
|
|
|
|
count: formState.count,
|
2025-12-10 22:48:53 +08:00
|
|
|
|
neighbors_count: formState.neighbors_count,
|
2026-05-19 14:52:54 +08:00
|
|
|
|
concurrency_count: formState.concurrency_count,
|
2026-05-20 10:25:01 +08:00
|
|
|
|
generation_mode: formState.generation_mode,
|
|
|
|
|
|
graph_expand_top_k: formState.graph_expand_top_k,
|
2026-05-06 22:12:09 +08:00
|
|
|
|
llm_model_spec: formState.llm_model_spec
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
2026-05-21 19:33:00 +08:00
|
|
|
|
const response = await evaluationApi.generateDataset(props.kbId, params)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
if (response.message === 'success') {
|
2026-05-19 14:52:54 +08:00
|
|
|
|
message.success('生成任务已提交')
|
|
|
|
|
|
visible.value = false
|
|
|
|
|
|
resetForm()
|
2026-01-15 06:01:34 +08:00
|
|
|
|
emit('success')
|
2025-12-09 16:21:18 +08:00
|
|
|
|
} else {
|
2026-05-19 14:52:54 +08:00
|
|
|
|
generating.value = false
|
2026-01-15 06:01:34 +08:00
|
|
|
|
message.error(response.message || '生成失败')
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
console.error('生成失败:', error)
|
|
|
|
|
|
generating.value = false
|
2026-05-20 10:25:01 +08:00
|
|
|
|
message.error(error?.response?.data?.detail || '生成失败')
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 取消操作
|
|
|
|
|
|
const handleCancel = () => {
|
2026-05-19 14:52:54 +08:00
|
|
|
|
if (generating.value) return
|
2026-01-15 06:01:34 +08:00
|
|
|
|
visible.value = false
|
|
|
|
|
|
resetForm()
|
|
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 重置表单
|
|
|
|
|
|
const resetForm = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
formRef.value?.resetFields()
|
2025-12-09 16:21:18 +08:00
|
|
|
|
Object.assign(formState, {
|
2026-05-06 22:12:09 +08:00
|
|
|
|
name: defaultBenchmarkName(),
|
2025-12-09 16:21:18 +08:00
|
|
|
|
description: '',
|
|
|
|
|
|
count: 10,
|
2026-05-06 22:12:09 +08:00
|
|
|
|
neighbors_count: 1,
|
2026-05-19 14:52:54 +08:00
|
|
|
|
concurrency_count: 10,
|
2026-05-20 10:25:01 +08:00
|
|
|
|
generation_mode: 'vector',
|
|
|
|
|
|
graph_expand_top_k: 1,
|
2026-05-06 22:12:09 +08:00
|
|
|
|
llm_model_spec: configStore.config?.default_model || ''
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
|
|
|
|
|
generating.value = false
|
|
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 选择LLM模型
|
|
|
|
|
|
const handleSelectLLMModel = (modelSpec) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
formState.llm_model_spec = modelSpec
|
|
|
|
|
|
}
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听visible变化
|
|
|
|
|
|
watch(visible, (val) => {
|
2026-05-19 14:52:54 +08:00
|
|
|
|
if (val && !generating.value) {
|
2026-01-15 06:01:34 +08:00
|
|
|
|
resetForm()
|
2026-05-20 10:25:01 +08:00
|
|
|
|
loadGraphBuildStatus()
|
2025-12-09 16:21:18 +08:00
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
|
})
|
2025-12-09 16:21:18 +08:00
|
|
|
|
</script>
|
2026-05-21 22:09:19 +08:00
|
|
|
|
|
|
|
|
|
|
<style scoped lang="less">
|
|
|
|
|
|
.generation-mode-cards {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.field-label-with-help {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.help-icon {
|
|
|
|
|
|
width: 14px;
|
|
|
|
|
|
height: 14px;
|
|
|
|
|
|
color: var(--gray-500);
|
|
|
|
|
|
cursor: help;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benchmark-modal-footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 16px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benchmark-help-text {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benchmark-help-link {
|
|
|
|
|
|
margin-left: 2px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer-actions {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.generation-mode-card {
|
|
|
|
|
|
border: 1px solid var(--gray-150);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 14px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s ease;
|
|
|
|
|
|
background: var(--gray-0);
|
|
|
|
|
|
outline: none;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover,
|
|
|
|
|
|
&:focus-visible {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&:focus-visible {
|
|
|
|
|
|
box-shadow: 0 0 0 2px var(--main-20);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.active {
|
|
|
|
|
|
border-color: var(--main-color);
|
|
|
|
|
|
background: var(--main-10);
|
|
|
|
|
|
box-shadow: 0 0 0 1px var(--main-20);
|
|
|
|
|
|
|
|
|
|
|
|
.mode-icon {
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
&.disabled {
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
opacity: 0.72;
|
|
|
|
|
|
background: var(--gray-50);
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: var(--gray-150);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mode-icon {
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
color: var(--main-color);
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mode-title {
|
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--gray-800);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mode-tag {
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
margin-right: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-description {
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
color: var(--gray-600);
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.card-helper {
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
color: var(--gray-500);
|
|
|
|
|
|
|
|
|
|
|
|
&.warning {
|
|
|
|
|
|
color: var(--color-warning-500);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media (max-width: 640px) {
|
|
|
|
|
|
.generation-mode-cards {
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.benchmark-modal-footer {
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer-actions {
|
|
|
|
|
|
align-self: flex-end;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|