updates
This commit is contained in:
parent
57f7937c2d
commit
256c34d5af
|
|
@ -1,5 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useScoreStore } from '~/stores/score'
|
||||
import { type SaveScoreRequest } from '~/service/api/score'
|
||||
import message from '~/utils/message'
|
||||
|
||||
const scoreStore = useScoreStore()
|
||||
|
||||
// 定义回传的数据类型
|
||||
export interface ScoreFormData {
|
||||
|
|
@ -25,6 +30,7 @@ const examType = ref('历史组')
|
|||
const selectedElectives = ref<string[]>([])
|
||||
const majorCategory = ref('')
|
||||
const selectedSubMajors = ref<string[]>([])
|
||||
const isSubmitting = ref(false)
|
||||
|
||||
// Score inputs
|
||||
const scores = ref({
|
||||
|
|
@ -54,6 +60,8 @@ const electiveOptions = [
|
|||
{ label: '政治', value: '政治' },
|
||||
{ label: '化学', value: '化学' },
|
||||
{ label: '生物', value: '生物' },
|
||||
{ label: '历史', value: '历史' },
|
||||
{ label: '物理', value: '物理' },
|
||||
]
|
||||
|
||||
const majorCategoryOptions = [
|
||||
|
|
@ -194,7 +202,7 @@ function validateForm() {
|
|||
}
|
||||
|
||||
// --- Submit ---
|
||||
function handleSubmit() {
|
||||
async function handleSubmit() {
|
||||
if (validateForm()) {
|
||||
// 组装数据
|
||||
const formData: ScoreFormData = {
|
||||
|
|
@ -205,11 +213,60 @@ function handleSubmit() {
|
|||
scores: { ...scores.value },
|
||||
}
|
||||
|
||||
// Transform to API request
|
||||
const requestData: SaveScoreRequest = {
|
||||
cognitioPolyclinic: examType.value === '历史组' ? '文科' : '理科',
|
||||
subjectList: selectedElectives.value,
|
||||
professionalCategory: majorCategory.value,
|
||||
professionalCategoryChildren: selectedSubMajors.value,
|
||||
professionalCategoryChildrenScore: {},
|
||||
professionalScore: Number(scores.value.unified) || 0,
|
||||
culturalScore: Number(scores.value.culture) || 0,
|
||||
englishScore: Number(scores.value.english) || 0,
|
||||
chineseScore: Number(scores.value.chinese) || 0,
|
||||
province: '河南', // Default
|
||||
}
|
||||
|
||||
try {
|
||||
isSubmitting.value = true
|
||||
await scoreStore.saveScore(requestData)
|
||||
// 刷新本地数据
|
||||
scoreStore.fetchScore()
|
||||
message.success('保存成功')
|
||||
// 抛出事件
|
||||
emit('confirm', formData)
|
||||
} catch (e: any) {
|
||||
message.error(e.message || '保存失败')
|
||||
} finally {
|
||||
isSubmitting.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Init ---
|
||||
function initForm() {
|
||||
console.warn('initForm', scoreStore.scoreInfo)
|
||||
if (scoreStore.scoreInfo) {
|
||||
const info = scoreStore.scoreInfo
|
||||
examType.value = info.cognitioPolyclinic === '文科' ? '历史组' : '物理组'
|
||||
selectedElectives.value = info.subjectList || []
|
||||
majorCategory.value = info.professionalCategory || ''
|
||||
selectedSubMajors.value = info.professionalCategoryChildren || []
|
||||
scores.value.unified = info.professionalScore?.toString() || ''
|
||||
scores.value.culture = info.culturalScore?.toString() || ''
|
||||
scores.value.chinese = info.chineseScore?.toString() || ''
|
||||
scores.value.english = info.englishScore?.toString() || ''
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initForm()
|
||||
})
|
||||
|
||||
watch(() => scoreStore.scoreInfo, () => {
|
||||
initForm()
|
||||
})
|
||||
|
||||
// 暴露重置方法给父组件(如果需要)
|
||||
defineExpose({
|
||||
resetForm: () => {
|
||||
|
|
@ -333,8 +390,8 @@ defineExpose({
|
|||
v-model="scores.culture"
|
||||
type="number"
|
||||
min="0"
|
||||
max="300"
|
||||
placeholder="0-300"
|
||||
max="750"
|
||||
placeholder="0-750"
|
||||
class="w-full border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<div v-if="errors.scores.culture" class="mt-2 text-sm text-red-600">
|
||||
|
|
@ -377,7 +434,7 @@ defineExpose({
|
|||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button
|
||||
<button :disabled="isSubmitting"
|
||||
class="w-full rounded-full bg-blue-600 px-6 py-3 text-lg text-white font-semibold shadow-lg transition-colors hover:bg-blue-700 hover:shadow-xl"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
import type { ScoreFormData } from './ScoreForm.vue'
|
||||
import { useWindowScroll } from '@vueuse/core' // 假设你使用了 VueUse
|
||||
import { ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useUserStore } from '../stores/user'
|
||||
import { useScoreStore } from '../stores/score'
|
||||
import message from '~/utils/message'
|
||||
import { logout as apiLogout } from '~/service/api/auth'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const scoreStore = useScoreStore()
|
||||
const isLoginModalOpen = ref(false)
|
||||
// 新增:控制移动端菜单开关的状态
|
||||
const isMobileMenuOpen = ref(false)
|
||||
|
|
@ -259,10 +262,16 @@ function handleMobileLinkClick() {
|
|||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="mb-3 flex items-center px-3">
|
||||
<span class="border-r-2 border-gray-3 pr-2 text-sm text-gray-700 dark:text-gray-200">音乐类</span>
|
||||
<div v-if="scoreStore.scoreInfo" class="mb-3 flex items-center px-3">
|
||||
<span class="border-r-2 border-gray-3 pr-2 text-sm text-gray-700 dark:text-gray-200">{{ scoreStore.scoreInfo.professionalCategory || '未设置' }}</span>
|
||||
<span class="border-r-2 border-gray-3 pl-2 pr-2 text-sm text-gray-700 dark:text-gray-200">文化成绩</span>
|
||||
<span class="pl-2 pr-2 text-sm text-gray-700 dark:text-gray-200">334</span>
|
||||
<span class="pl-2 pr-2 text-sm text-gray-700 dark:text-gray-200">{{ scoreStore.scoreInfo.culturalScore }}</span>
|
||||
<a target="_blank" class="cursor-pointer text-gray-400 transition-colors hover:text-gray-500 dark:hover:text-gray-300" @click="openScoreFormModal">
|
||||
<div i-carbon:edit class="text-xs" />
|
||||
</a>
|
||||
</div>
|
||||
<div v-else class="mb-3 flex items-center px-3">
|
||||
<span class="text-sm text-gray-700 dark:text-gray-200">未设置分数</span>
|
||||
<a target="_blank" class="cursor-pointer text-gray-400 transition-colors hover:text-gray-500 dark:hover:text-gray-300" @click="openScoreFormModal">
|
||||
<div i-carbon:edit class="text-xs" />
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ export interface LoginResult {
|
|||
}
|
||||
|
||||
export function login(params: LoginParams) {
|
||||
return request.post<LoginResult>('/auth/login', params)
|
||||
return request.post<LoginResult>('/user/auth/login', params)
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
return request.post<null>('/auth/logout')
|
||||
return request.post<null>('/user/auth/logout')
|
||||
}
|
||||
|
||||
export function getUserInfo() {
|
||||
return request.get<UserInfo>('/auth/info')
|
||||
return request.get<UserInfo>('/user/auth/info')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
import request from '../request'
|
||||
|
||||
export interface SaveScoreRequest {
|
||||
cognitioPolyclinic: string
|
||||
subjectList: string[]
|
||||
professionalCategory: string
|
||||
professionalCategoryChildren: string[]
|
||||
professionalCategoryChildrenScore: Record<string, number>
|
||||
professionalScore: number
|
||||
culturalScore: number
|
||||
englishScore: number
|
||||
chineseScore: number
|
||||
province: string
|
||||
}
|
||||
|
||||
export interface ScoreInfo {
|
||||
id: string
|
||||
type: string
|
||||
educationalLevel: string
|
||||
cognitioPolyclinic: string
|
||||
subjectList: string[]
|
||||
professionalCategory: string
|
||||
professionalCategoryChildren: string[]
|
||||
professionalCategoryChildrenScore: Record<string, number>
|
||||
professionalScore: number
|
||||
culturalScore: number
|
||||
englishScore: number
|
||||
chineseScore: number
|
||||
province: string
|
||||
state: string
|
||||
}
|
||||
|
||||
export function saveScore(data: SaveScoreRequest) {
|
||||
return request.post<ScoreInfo>('/user/score/save-score', data)
|
||||
}
|
||||
|
||||
export function getScore() {
|
||||
return request.get<ScoreInfo>('/user/score')
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import CryptoJS from 'crypto-js'
|
|||
import { useUserStore } from '~/stores/user'
|
||||
import message from '~/utils/message'
|
||||
import { InternalAxiosRequestConfig } from 'axios'
|
||||
|
||||
interface CustomRequestConfig extends InternalAxiosRequestConfig {
|
||||
showLoading?: boolean,
|
||||
showError?: boolean
|
||||
|
|
@ -81,7 +82,10 @@ class Request {
|
|||
case 401:
|
||||
msg = backendMsg || 'Unauthorized'
|
||||
const userStore = useUserStore()
|
||||
userStore.logout()
|
||||
userStore.clearToken()
|
||||
userStore.clearUserInfo()
|
||||
window.location.href= '/'
|
||||
// userStore.logout()
|
||||
// router push login?
|
||||
break
|
||||
case 403:
|
||||
|
|
@ -98,9 +102,9 @@ class Request {
|
|||
}
|
||||
}
|
||||
|
||||
if (config?.showError !== false) {
|
||||
message.error(msg)
|
||||
}
|
||||
// if (config?.showError !== false) {
|
||||
// message.error(msg)
|
||||
// }
|
||||
// 返回包含具体错误信息的 Error 对象
|
||||
return Promise.reject(new Error(msg))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { acceptHMRUpdate, defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getScore, saveScore as apiSaveScore, type SaveScoreRequest, type ScoreInfo } from '~/service/api/score'
|
||||
|
||||
export const useScoreStore = defineStore('score', () => {
|
||||
const scoreInfo = ref<ScoreInfo | null>(null)
|
||||
|
||||
async function fetchScore() {
|
||||
try {
|
||||
const data = await getScore()
|
||||
scoreInfo.value = data
|
||||
return data
|
||||
} catch (error) {
|
||||
// If error occurs (e.g. 404 not found if user hasn't set score), we might want to handle it.
|
||||
// For now, just throw or log.
|
||||
console.error('Failed to fetch score', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function saveScore(data: SaveScoreRequest) {
|
||||
try {
|
||||
const response = await apiSaveScore(data)
|
||||
scoreInfo.value = response
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('Failed to save score', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
function clearScore() {
|
||||
scoreInfo.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
scoreInfo,
|
||||
fetchScore,
|
||||
saveScore,
|
||||
clearScore,
|
||||
}
|
||||
})
|
||||
|
||||
if (import.meta.hot)
|
||||
import.meta.hot.accept(acceptHMRUpdate(useScoreStore as any, import.meta.hot))
|
||||
|
|
@ -81,6 +81,8 @@ export const useUserStore = defineStore('user', () => {
|
|||
userInfo,
|
||||
setToken,
|
||||
setUserInfo,
|
||||
clearToken,
|
||||
clearUserInfo,
|
||||
login,
|
||||
logout,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue