Files
YG_FT/frontend/src/views/data-process/create/DatasetSplitEditor.vue

186 lines
4.2 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { computed } from 'vue'
import type { DatasetSplitOptions } from './types'
const props = withDefaults(defineProps<{
modelValue: DatasetSplitOptions
ariaLabelPrefix?: string
}>(), {
ariaLabelPrefix: '',
})
const emit = defineEmits<{
'update:modelValue': [value: DatasetSplitOptions]
}>()
const splitTotal = computed(() => {
const { train, validation, test } = props.modelValue
return train + validation + test
})
function updateField(field: keyof DatasetSplitOptions, value: number | undefined) {
emit('update:modelValue', {
...props.modelValue,
[field]: Math.min(100, Math.max(0, Number(value) || 0)),
})
}
function ariaLabel(label: string) {
return `${props.ariaLabelPrefix}${label}比例`
}
</script>
<template>
<div class="generation-option-row dataset-split-row">
<div class="generation-option-copy">
<strong>数据集划分</strong>
<small>按比例将生成后的问答对随机划分为训练集验证集和测试集</small>
</div>
<div class="dataset-split-config">
<div class="dataset-split-grid">
<label class="dataset-split-field">
<span>训练集</span>
<span class="dataset-split-input">
<el-input-number
:model-value="modelValue.train"
:min="0"
:max="100"
:step="1"
:precision="0"
controls-position="right"
:aria-label="ariaLabel('训练集')"
@update:model-value="updateField('train', $event)"
/>
<span>%</span>
</span>
</label>
<label class="dataset-split-field">
<span>验证集</span>
<span class="dataset-split-input">
<el-input-number
:model-value="modelValue.validation"
:min="0"
:max="100"
:step="1"
:precision="0"
controls-position="right"
:aria-label="ariaLabel('验证集')"
@update:model-value="updateField('validation', $event)"
/>
<span>%</span>
</span>
</label>
<label class="dataset-split-field">
<span>测试集</span>
<span class="dataset-split-input">
<el-input-number
:model-value="modelValue.test"
:min="0"
:max="100"
:step="1"
:precision="0"
controls-position="right"
:aria-label="ariaLabel('测试集')"
@update:model-value="updateField('test', $event)"
/>
<span>%</span>
</span>
</label>
</div>
<div class="dataset-split-summary" :class="{ 'is-invalid': splitTotal !== 100 }">
<span>总计 {{ splitTotal }}%</span>
<span v-if="splitTotal !== 100" role="alert">
训练集验证集和测试集比例总和必须为 100%
</span>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.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;
}
.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;
}
}
.dataset-split-row {
align-items: stretch;
flex-direction: column;
}
.dataset-split-config {
display: grid;
gap: 10px;
}
.dataset-split-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}
.dataset-split-field {
display: grid;
gap: 7px;
color: #5f6878;
font-size: 12px;
}
.dataset-split-input {
display: flex;
align-items: center;
gap: 8px;
:deep(.el-input-number) {
width: 100%;
}
}
.dataset-split-summary {
display: flex;
justify-content: space-between;
gap: 12px;
color: #2ca66a;
font-size: 12px;
&.is-invalid {
color: #dc2626;
}
}
@media (max-width: 900px) {
.dataset-split-grid {
grid-template-columns: minmax(0, 1fr);
}
.dataset-split-summary {
align-items: flex-start;
flex-direction: column;
}
}
</style>