vitesse-yitisheng-web/src/pages/volunteer.vue

316 lines
11 KiB
Vue

<template>
<div class="p-6 max-w-4xl mx-auto">
<h1 class="text-2xl font-bold mb-6">高校专业志愿填报</h1>
<div class="space-y-6">
<!-- 基本信息 -->
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-4">基本信息</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">省份 *</label>
<select
v-model="formData.province"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
required
>
<option value="">请选择省份</option>
<option
v-for="item in dictStore.getDictItems('provinces')"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">学历层次 *</label>
<select
v-model="formData.educationalLevel"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
required
>
<option value="">请选择学历层次</option>
<option
v-for="item in dictStore.getDictItems('educationalLevel')"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</option>
</select>
</div>
</div>
</div>
<!-- 专业选择 -->
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-4">专业选择</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">专业类别 *</label>
<select
v-model="formData.professionalCategory"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
required
>
<option value="">请选择专业类别</option>
<option
v-for="item in dictStore.getDictItems('professionalCategory')"
:key="item.value"
:value="item.value"
>
{{ item.label }}
</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">选考科目 (最多3门) *</label>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
<label
v-for="item in dictStore.getDictItems('subjectList')"
:key="item.value"
class="flex items-center space-x-2 p-2 border rounded cursor-pointer hover:bg-gray-50"
:class="{ 'bg-blue-50 border-blue-300': formData.subjectList.includes(item.value) }"
>
<input
type="checkbox"
:value="item.value"
v-model="formData.subjectList"
:disabled="formData.subjectList.length >= 3 && !formData.subjectList.includes(item.value)"
class="h-4 w-4 text-blue-600 rounded focus:ring-blue-500"
/>
<span>{{ item.label }}</span>
</label>
</div>
<div class="text-sm text-gray-500 mt-1">
已选择 {{ formData.subjectList.length }}/3 门科目
<span v-if="formData.subjectList.length >= 3" class="text-red-500">已达到上限</span>
</div>
</div>
</div>
</div>
<!-- 成绩信息 -->
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold mb-4">成绩信息</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">专业成绩</label>
<input
v-model.number="formData.professionalScore"
type="number"
step="0.01"
min="0"
max="300"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="请输入专业成绩 (0-300)"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">文化成绩</label>
<input
v-model.number="formData.culturalScore"
type="number"
step="0.01"
min="0"
max="750"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="请输入文化成绩 (0-750)"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">语文成绩</label>
<input
v-model.number="formData.chineseScore"
type="number"
step="0.01"
min="0"
max="150"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="请输入语文成绩 (0-150)"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">英语成绩</label>
<input
v-model.number="formData.englishScore"
type="number"
step="0.01"
min="0"
max="150"
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="请输入英语成绩 (0-150)"
/>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="flex justify-end space-x-4 pt-4">
<button
type="button"
@click="resetForm"
class="px-6 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
重置
</button>
<button
type="submit"
@click="submitForm"
class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
:disabled="!isFormValid"
>
{{ isSubmitting ? '提交中...' : '提交' }}
</button>
</div>
</div>
<!-- 表单验证错误提示 -->
<div v-if="errors.length > 0" class="mt-4 p-4 bg-red-50 border border-red-200 rounded-md">
<h3 class="text-red-800 font-medium mb-2">请修正以下错误:</h3>
<ul class="list-disc list-inside text-red-700 space-y-1">
<li v-for="(error, index) in errors" :key="index">{{ error }}</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { useDictStore } from '~/stores/dict'
import { useScoreStore } from '~/stores/score'
import { SaveScoreRequest } from '~/service/api/score'
import message from '~/utils/message'
// 使用字典Store和成绩Store
const dictStore = useDictStore()
const scoreStore = useScoreStore()
// 表单数据
const formData = reactive<SaveScoreRequest>({
cognitioPolyclinic: '',
subjectList: [],
professionalCategory: '',
professionalCategoryChildren: [],
professionalCategoryChildrenScore: {},
professionalScore: 0,
culturalScore: 0,
englishScore: 0,
chineseScore: 0,
province: '',
})
// 状态
const isSubmitting = ref(false)
// 错误信息
const errors = ref<string[]>([])
// 计算属性
const isFormValid = computed(() => {
return formData.province &&
formData.professionalCategory &&
formData.subjectList.length > 0
})
// 提交表单
const submitForm = async () => {
errors.value = []
// 基本验证
if (!formData.province) {
errors.value.push('请选择省份')
}
if (!formData.professionalCategory) {
errors.value.push('请选择专业类别')
}
if (formData.subjectList.length === 0) {
errors.value.push('请至少选择一门选考科目')
}
if (errors.value.length > 0) {
return
}
isSubmitting.value = true
try {
// 更新认知门诊字段 - 根据省份和专业类别推断
formData.cognitioPolyclinic = formData.province.includes('beijing') || formData.province.includes('shanghai')
? '综合改革'
: formData.subjectList.includes('physics') || formData.subjectList.includes('chemistry')
? '理科'
: '文科'
// 保存数据
await scoreStore.saveScore(formData)
message.success('志愿信息保存成功!', 2000)
// 可以在这里添加导航到其他页面的逻辑
} catch (error) {
console.error('提交失败:', error)
message.error('提交失败,请检查网络连接或稍后重试', 3000)
} finally {
isSubmitting.value = false
}
}
// 重置表单
const resetForm = () => {
formData.cognitioPolyclinic = ''
formData.subjectList = []
formData.professionalCategory = ''
formData.professionalCategoryChildren = []
formData.professionalCategoryChildrenScore = {}
formData.professionalScore = 0
formData.culturalScore = 0
formData.englishScore = 0
formData.chineseScore = 0
formData.province = ''
errors.value = []
}
// 页面加载时初始化
onMounted(async () => {
// 尝试加载字典数据
if (Object.keys(dictStore.allDicts).length === 0) {
try {
await dictStore.loadDynamicDicts()
} catch (error) {
console.warn('加载字典数据失败,使用默认值:', error)
}
}
// 尝试加载已保存的成绩数据
try {
const scoreInfo = await scoreStore.fetchScore()
if (scoreInfo) {
// 使用解构赋值更新表单数据
Object.assign(formData, {
cognitioPolyclinic: scoreInfo.cognitioPolyclinic || '',
subjectList: scoreInfo.subjectList || [],
professionalCategory: scoreInfo.professionalCategory || '',
professionalCategoryChildren: scoreInfo.professionalCategoryChildren || [],
professionalCategoryChildrenScore: scoreInfo.professionalCategoryChildrenScore || {},
professionalScore: scoreInfo.professionalScore || 0,
culturalScore: scoreInfo.culturalScore || 0,
englishScore: scoreInfo.englishScore || 0,
chineseScore: scoreInfo.chineseScore || 0,
province: scoreInfo.province || '',
})
}
} catch (error) {
console.warn('加载成绩数据失败:', error)
// 忽略错误,用户可能没有保存过数据
}
})
</script>