Files
resume-agent/frontend/src/components/DegreeSelector.vue
T
hypandClaude ae2d9b128d feat: builder 简历生成 + 轻度优化 + 简历导入交付副本
自内部仓库剥离深度优化与 RAG 知识库后的交付版本:
- Builder 对话式简历生成(FSM + 意图路由 LLM 兜底增强)
- 条目级轻度优化:事实覆盖门禁 + STAR/bullet 修复链,功能/简介/成果与技术栈同级保护
- 简历导入:DOCX/PDF 解析、结构归一、手机号脱敏
- PostgreSQL 运行时 + Alembic 迁移链

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 11:08:30 +08:00

114 lines
3.2 KiB
Vue

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import type { ChoiceOption, ComponentSubmission } from '../types/resumeAgent'
import { initialValue, optionList, stringValue } from '../utils/componentData'
import FormCard from './shared/FormCard.vue'
const props = withDefaults(
defineProps<{
data: Record<string, unknown>
value?: unknown
readOnly?: boolean
pending?: boolean
}>(),
{ value: undefined, readOnly: false, pending: false },
)
const emit = defineEmits<{ submit: [submission: ComponentSubmission] }>()
const fallbackOptions: ChoiceOption[] = [
{ value: 'doctor', label: '博士' },
{ value: 'master', label: '硕士' },
{ value: 'bachelor', label: '本科' },
{ value: 'associate', label: '大专' },
{ value: 'high_school', label: '高中 / 中专' },
{ value: 'other', label: '其他' },
]
const options = computed(() => optionList(props.data.options ?? props.data.choices, fallbackOptions))
const sourceValue = computed(() =>
typeof props.value === 'string' ? props.value : initialValue(props.data),
)
const selected = ref(sourceValue.value)
watch(sourceValue, (next) => {
selected.value = next
})
const selectedLabel = computed(
() => options.value.find((option) => option.value === selected.value)?.label || selected.value,
)
function submit() {
if (!selected.value || props.readOnly || props.pending) return
emit('submit', {
event: 'select',
payload: { value: selected.value, degree: selected.value },
})
}
</script>
<template>
<FormCard
eyebrow="教育背景"
:title="stringValue(data.title, '你的最高学历是?')"
:description="stringValue(data.description, '选择已经获得或正在就读的最高学历。')"
:read-only="readOnly"
:pending="pending"
>
<div v-if="readOnly" class="read-only-value">{{ selectedLabel || '学历已记录' }}</div>
<form v-else @submit.prevent="submit">
<div class="degree-grid" role="radiogroup" aria-label="最高学历">
<button
v-for="option in options"
:key="option.value"
class="degree-option"
:class="{ 'degree-option--selected': selected === option.value }"
type="button"
role="radio"
:aria-checked="selected === option.value"
:disabled="pending || option.disabled"
@click="selected = option.value"
>
{{ option.label }}
</button>
</div>
<div class="component-actions">
<button class="primary-button" type="submit" :disabled="!selected || pending">
确认学历
</button>
</div>
</form>
</FormCard>
</template>
<style scoped>
.degree-grid {
display: flex;
flex-wrap: wrap;
gap: 9px;
}
.degree-option {
min-height: 44px;
padding: 0 16px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--ink-soft);
background: #f8fbfa;
font-size: 14px;
font-weight: 680;
transition: color 160ms ease, border-color 160ms ease, background 160ms ease, transform 160ms ease;
}
.degree-option:hover:not(:disabled) {
transform: translateY(-1px);
border-color: #91cbc7;
color: var(--ink);
}
.degree-option--selected {
border-color: var(--brand-dark);
color: #fff;
background: var(--brand-dark);
}
</style>