Files
YG_FT/frontend/src/views/data-process/create/StructuredOptionsPanel.vue
caoxiaozhu e580ec4791 refactor: 数据处理向导拆分组合式函数与子面板
提取 useDataProcessDraft、useDataProcessGeneration 与 dataProcessCreateState 管理向导状态,新增 StructuredOptionsPanel、UnstructuredOptionsPanel、DatasetSplitEditor 子面板组件,样式抽离为独立 scss,DataProcessCreateView 与 TaskSetupStep 大幅瘦身,回归脚本适配。
2026-07-13 15:28:48 +08:00

271 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import type { ModelItem } from '@/types'
import type {
GenerationControlOptions,
PreprocessOption,
StructuredProcessOptions,
} from './types'
import DatasetSplitEditor from './DatasetSplitEditor.vue'
import GenerationOptionsPanel from './GenerationOptionsPanel.vue'
const props = defineProps<{
options: StructuredProcessOptions
generationModels: ModelItem[]
validationAttempted: boolean
generationValidationMessage: string
}>()
const emit = defineEmits<{
'update:options': [value: StructuredProcessOptions]
}>()
const PREPROCESS_OPTIONS: Array<{
value: PreprocessOption
label: string
description: string
}> = [
{ value: 'clean_invalid', label: '清理无效数据', description: '处理空行、空列和残缺行' },
{ value: 'detect_structure', label: '识别表格结构', description: '识别表头、多级表头和合并单元格' },
{ value: 'deduplicate', label: '重复数据去重', description: '删除完全重复或关键字段重复的数据' },
{ value: 'normalize_format', label: '数据格式标准化', description: '统一日期、数字、单位和枚举值格式' },
{ value: 'filter_anomaly', label: '异常数据过滤', description: '过滤乱码、无效内容和异常记录' },
{ value: 'desensitize', label: '敏感信息脱敏', description: '处理姓名、手机号、邮箱等敏感信息' },
]
function updateField<K extends keyof StructuredProcessOptions>(
field: K,
value: StructuredProcessOptions[K],
) {
emit('update:options', { ...props.options, [field]: value })
}
function updateGenerationOptions(value: GenerationControlOptions) {
emit('update:options', { ...props.options, ...value })
}
function updatePreprocessOptions(value: Array<string | number | boolean>) {
const allowedValues = new Set(PREPROCESS_OPTIONS.map((option) => option.value))
const preprocessOptions = value.filter(
(option): option is PreprocessOption => typeof option === 'string' && allowedValues.has(option as PreprocessOption),
)
updateField('preprocessOptions', preprocessOptions)
}
</script>
<template>
<div class="form-section structured-options-section">
<div class="section-title-row">
<div>
<h3>预处理选项</h3>
<p>选择在生成问答对之前需要执行的数据处理方式</p>
</div>
</div>
<el-checkbox-group
:model-value="options.preprocessOptions"
class="preprocess-option-grid"
@update:model-value="updatePreprocessOptions"
>
<el-checkbox
v-for="option in PREPROCESS_OPTIONS"
:key="option.value"
:value="option.value"
class="preprocess-option"
>
<span class="preprocess-option-copy">
<strong>{{ option.label }}</strong>
<small>{{ option.description }}</small>
</span>
</el-checkbox>
</el-checkbox-group>
</div>
<div class="form-section generation-options-section">
<div class="section-title-row">
<div>
<h3>生成选项</h3>
<p>配置每条结构化记录生成问答对的方式和数量</p>
</div>
</div>
<div class="generation-option-list">
<GenerationOptionsPanel
:options="options"
:models="generationModels"
section="quality"
:validation-message="validationAttempted ? generationValidationMessage : ''"
@update:options="updateGenerationOptions"
/>
<div class="generation-option-row">
<div class="generation-option-copy">
<strong>语义丰富表达</strong>
<small>使用大模型将问答表述得更自然柔和</small>
</div>
<el-switch
:model-value="options.semanticEnrichment"
inline-prompt
active-text=""
inactive-text=""
@update:model-value="updateField('semanticEnrichment', Boolean($event))"
/>
</div>
<div class="generation-option-row">
<div class="generation-option-copy">
<strong>每行生成数量</strong>
<small>每行结构化数据生成的问答对数量</small>
</div>
<el-input-number
:model-value="options.qaPairsPerRow"
:min="1"
:max="5"
:step="1"
controls-position="right"
@update:model-value="updateField('qaPairsPerRow', Number($event) || 1)"
/>
</div>
<DatasetSplitEditor
:model-value="options.datasetSplit"
@update:model-value="updateField('datasetSplit', $event)"
/>
</div>
</div>
<div class="form-section model-options-section">
<div class="section-title-row">
<div>
<h3>大模型</h3>
<p>选择数据生成模型并设置模型输出内容的要求</p>
</div>
</div>
<div class="generation-option-list">
<GenerationOptionsPanel
:options="options"
:models="generationModels"
section="model"
:validation-message="validationAttempted ? generationValidationMessage : ''"
@update:options="updateGenerationOptions"
/>
</div>
</div>
</template>
<style scoped lang="scss">
.form-section {
padding: 0 0 26px;
margin-bottom: 26px;
border-bottom: 1px solid #edf0f5;
&:last-child {
margin-bottom: 0;
border-bottom: 0;
}
h3 {
margin: 0 0 16px;
color: #2f3747;
font-size: 15px;
font-weight: 650;
}
}
.section-title-row {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
h3 {
margin-bottom: 5px;
}
p {
margin: 0;
color: #8a93a3;
font-size: 12px;
}
}
.preprocess-option-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
margin-top: 16px;
}
.preprocess-option {
width: 100%;
min-height: 64px;
margin-right: 0;
padding: 12px 14px;
box-sizing: border-box;
align-items: flex-start;
border: 1px solid #e2e5ec;
border-radius: 8px;
transition: border-color 0.18s ease, background-color 0.18s ease;
&:hover {
border-color: #b7b2f7;
}
&.is-checked {
background: #fafaff;
border-color: #8b82f4;
}
:deep(.el-checkbox__input) {
margin-top: 3px;
}
:deep(.el-checkbox__label) {
min-width: 0;
padding-left: 10px;
white-space: normal;
}
}
.preprocess-option-copy,
.generation-option-copy {
display: grid;
gap: 4px;
strong {
color: #344054;
font-size: 13px;
font-weight: 600;
}
small {
color: #8a93a3;
font-size: 12px;
line-height: 1.5;
}
}
.generation-option-list {
display: grid;
gap: 12px;
margin-top: 16px;
}
.generation-option-row {
display: flex;
min-height: 64px;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 12px 14px;
box-sizing: border-box;
border: 1px solid #e2e5ec;
border-radius: 8px;
}
@media (max-width: 900px) {
.preprocess-option-grid {
grid-template-columns: minmax(0, 1fr);
}
.generation-option-row {
align-items: flex-start;
flex-direction: column;
}
}
</style>