我的志愿明细:删除-提交
This commit is contained in:
parent
da16f9fdca
commit
57c6de808d
|
|
@ -37,8 +37,15 @@
|
||||||
- **Purpose**: Displays the Privacy Policy.
|
- **Purpose**: Displays the Privacy Policy.
|
||||||
- **Features**: Static content detailing data collection, usage, and protection. Includes contact information. Responsive layout.
|
- **Features**: Static content detailing data collection, usage, and protection. Includes contact information. Responsive layout.
|
||||||
|
|
||||||
|
### `src/service/api/volunteer.ts`
|
||||||
|
- **Purpose**: API definitions for volunteer filling management.
|
||||||
|
- **Methods**: `saveVolunteer`, `getVolunteerDetail`.
|
||||||
|
- **Types**: `VolunteerInfo`, `VolunteerItem`, `VolunteerDetailResponse`.
|
||||||
|
|
||||||
### `src/pages/simulate.vue`
|
### `src/pages/simulate.vue`
|
||||||
- **Purpose**: Volunteer simulation page.
|
- **Updated**:
|
||||||
- **Features**:
|
- Integrated `getVolunteerDetail` and `saveVolunteer`.
|
||||||
- Panel A: Displays recommended majors list fetched from API (`/user/major/list`). Supports infinite scroll and filtering by probability.
|
- Implemented `isModified` state for unsaved changes detection.
|
||||||
- Panel B: Displays user's selected volunteers (Mock data for now).
|
- Added route leave protection and panel switch protection.
|
||||||
|
- Updated Panel B template to dynamic matching backend data structure.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,27 @@
|
||||||
- [Result]:
|
- [Result]:
|
||||||
- Updated `UserMajorListResponse` to support `{ list: { items: [], probCount: {} } }` structure.
|
- Updated `UserMajorListResponse` to support `{ list: { items: [], probCount: {} } }` structure.
|
||||||
- Added 'stable' (较稳妥) tab to `simulate.vue`.
|
- Added 'stable' (较稳妥) tab to `simulate.vue`.
|
||||||
- Implemented dynamic update of tab counts using `probCount` from API response.
|
|
||||||
|
|
||||||
## 2026-01-23
|
## 2026-01-23
|
||||||
|
|
||||||
### [Task 8] Fix TypeScript type error in `simulate.vue`
|
### [Task 8] Fix TypeScript type error in `simulate.vue`
|
||||||
- **Time**: 2026-01-23
|
- **Time**: 2026-01-23
|
||||||
- **Goal**: Fix type error `Argument of type '"stable"' is not assignable to parameter of type 'TabKey'`.
|
- **Goal**: Fix type error `Argument of type '"stable"' is not assignable to parameter of type 'TabKey'`.
|
||||||
- **Scope**: `src/pages/simulate.vue`
|
- **Scope**: `src/pages/simulate.vue`
|
||||||
- **Preparing**: Update `TabKey` definition to include `'stable'` and remove unused `'all'`.
|
- **Result**: Updated `TabKey` definition to include `'stable'` and remove unused `'all'`.
|
||||||
|
|
||||||
|
## 2026-01-24
|
||||||
|
|
||||||
|
### [Task 9] Volunteer Filling Logic Perfection
|
||||||
|
- **Time**: 2026-01-24
|
||||||
|
- **Goal**: Implement real API integration for saving and fetching volunteers, with modification detection.
|
||||||
|
- **Scope**:
|
||||||
|
- `src/service/api/volunteer.ts` (New)
|
||||||
|
- `src/pages/simulate.vue` (Update)
|
||||||
|
- **Result**:
|
||||||
|
- Created `volunteer.ts` with `saveVolunteer` and `getVolunteerDetail`.
|
||||||
|
- Integrated these into `simulate.vue`.
|
||||||
|
- Added `isModified` logic for reordering and deletion.
|
||||||
|
- Added `onBeforeRouteLeave` and `watch(activePanel)` protection for unsaved changes.
|
||||||
|
- Updated Panel B template to use real API data structure.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@
|
||||||
- `src/pages/agreement.vue`: User agreement page.
|
- `src/pages/agreement.vue`: User agreement page.
|
||||||
- `src/pages/privacy-policy.vue`: Privacy policy page.
|
- `src/pages/privacy-policy.vue`: Privacy policy page.
|
||||||
- `src/pages/simulate.vue`: Simulation and volunteer filling page.
|
- `src/pages/simulate.vue`: Simulation and volunteer filling page.
|
||||||
|
- `src/service/api/volunteer.ts`: Volunteer management API.
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
|
|
||||||
- [x] [Task 6] User Recommended Major List API Integration <!-- id: 32 -->
|
- [x] [Task 6] User Recommended Major List API Integration <!-- id: 32 -->
|
||||||
- [x] Create `src/service/api/major.ts` with types and API method <!-- id: 33 -->
|
- [x] [Task 8] Fix TypeScript type error in `simulate.vue` <!-- id: 36 -->
|
||||||
- [x] Integrate API in `src/pages/simulate.vue` (Panel A) <!-- id: 34 -->
|
- [x] [Task 9] Volunteer Filling Logic Perfection <!-- id: 39 -->
|
||||||
- [x] Update template to display real data <!-- id: 35 -->
|
- [x] Encapsulate volunteer APIs (`src/service/api/volunteer.ts`) <!-- id: 40 -->
|
||||||
- [ ] [Task 8] Fix TypeScript type error in `simulate.vue` <!-- id: 36 -->
|
- [x] Integrate save/detail logic in `simulate.vue` <!-- id: 41 -->
|
||||||
- [ ] Add `'stable'` to `TabKey` type definition <!-- id: 37 -->
|
- [x] Implement modification detection and leave protection <!-- id: 42 -->
|
||||||
- [ ] Cleanup unused `'all'` type if necessary <!-- id: 38 -->
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FilterState } from '~/components/FilterBar.vue'
|
import type { FilterState } from '~/components/FilterBar.vue'
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { onMounted, ref, watch, computed } from 'vue'
|
||||||
|
import { onBeforeRouteLeave } from 'vue-router'
|
||||||
import { getUserMajorList, type MajorItem } from '~/service/api/major'
|
import { getUserMajorList, type MajorItem } from '~/service/api/major'
|
||||||
|
import { saveVolunteer, getVolunteerDetail, type VolunteerItem, type VolunteerInfo } from '~/service/api/volunteer'
|
||||||
|
|
||||||
// --- 类型定义 ---
|
// --- 类型定义 ---
|
||||||
type TabKey = 'all' | 'hard' | 'risky' | 'safe' | 'stable' | '本科' | '专科' | '985/211/双一流' | '公办本科' | '民办本科'
|
type TabKey = 'all' | 'hard' | 'risky' | 'safe' | 'stable' | '本科' | '专科' | '985/211/双一流' | '公办本科' | '民办本科'
|
||||||
|
|
@ -14,31 +16,6 @@ interface VolunteerTab {
|
||||||
max: number
|
max: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface YearData {
|
|
||||||
count?: number
|
|
||||||
minScore?: number
|
|
||||||
diff?: number
|
|
||||||
method?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 仅用于 Panel B 的本地模拟数据接口
|
|
||||||
interface VolunteerSchool {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
tags: string[]
|
|
||||||
code: string
|
|
||||||
probability: string
|
|
||||||
statusLabel: '保' | '冲' | '稳' | '难'
|
|
||||||
calcScore: number
|
|
||||||
diffScore: number
|
|
||||||
majorName: string
|
|
||||||
requirements: string
|
|
||||||
tuition: string
|
|
||||||
majorCode: string
|
|
||||||
planCount: number
|
|
||||||
history: { [key: string]: YearData }
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MajorDetail {
|
interface MajorDetail {
|
||||||
code: string
|
code: string
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -82,21 +59,18 @@ const volunteerPlans = ref([
|
||||||
])
|
])
|
||||||
|
|
||||||
const activePanel = ref<PanelType>('market') // 当前激活的面板
|
const activePanel = ref<PanelType>('market') // 当前激活的面板
|
||||||
|
const myVolunteers = ref<VolunteerItem[]>([])
|
||||||
// 模拟“我的志愿”数据 (为了演示Panel B,初始化一些数据)
|
const originalVolunteers = ref<VolunteerItem[]>([]) // 用于对比变动
|
||||||
// 在实际业务中,这应该由 selectedMajorCodes 对应的完整数据填充
|
const currentVolunteerInfo = ref<VolunteerInfo | null>(null)
|
||||||
const myVolunteers = ref<VolunteerSchool[]>([
|
|
||||||
{ id: '2025121426', name: '志愿2025121426', code: "1001", tags: ['手动'], probability: "80.5%", statusLabel: '保', calcScore: 450, diffScore: 250, majorName: '计算机科学与技术', requirements: '物化生', tuition: '', majorCode:'2003', planCount: 10, history: { '2025': {count: 10,minScore: 1,diff: 4,method: 'q'} } },
|
|
||||||
{ id: '2025121427', name: '志愿2025121427', code: "1001", tags: ['手动'], probability: "80.5%", statusLabel: '保', calcScore: 450, diffScore: 250, majorName: '计算机科学与技术', requirements: '物化生', tuition: '', majorCode:'2003', planCount: 10, history: { '2025': {count: 10,minScore: 1,diff: 4,method: 'q'} } }
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
// 志愿Tab
|
// 志愿Tab
|
||||||
const volunteerCurrentTab = ref<TabKey>('本科')
|
const volunteerCurrentTab = ref<string>('本科批')
|
||||||
const volunteerTabs = [
|
const volunteerTabs = ref([
|
||||||
{ key: '本科', label: '本科', count: 1, max: 64 },
|
{ key: '提前批', label: '提前批', count: 0, max: 64 },
|
||||||
{ key: '专科', label: '专科', count: 2, max: 64 },
|
{ key: '本科批', label: '本科批', count: 0, max: 64 },
|
||||||
] as VolunteerTab[]
|
{ key: '专科批', label: '专科批', count: 0, max: 64 },
|
||||||
|
]) as any
|
||||||
|
|
||||||
|
|
||||||
//============= Panel A 数据
|
//============= Panel A 数据
|
||||||
|
|
@ -246,6 +220,20 @@ watch(currentProbTab, () => {
|
||||||
loadMore(true)
|
loadMore(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(activePanel, (newVal, oldVal) => {
|
||||||
|
if (oldVal === 'my-volunteers' && newVal === 'market' && isModified.value) {
|
||||||
|
const confirmRevert = window.confirm('您有未保存的志愿变动,切换回模拟填报将恢复初始状态,确认吗?')
|
||||||
|
if (confirmRevert) {
|
||||||
|
// 恢复数据
|
||||||
|
myVolunteers.value = JSON.parse(JSON.stringify(originalVolunteers.value))
|
||||||
|
} else {
|
||||||
|
// 阻止切换 (由于 watch 是在变化后触发的,这里需要 nextTick 或者特殊处理)
|
||||||
|
// 注意:直接修改 activePanel.value 会再次触发 watch,但因为满足 newVal === 'my-volunteers' 不会再次弹窗
|
||||||
|
activePanel.value = 'my-volunteers'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
|
|
@ -274,14 +262,14 @@ async function openMajorModal(school: MajorItem) {
|
||||||
// Mock data for now
|
// Mock data for now
|
||||||
modalMajors.value = [
|
modalMajors.value = [
|
||||||
{
|
{
|
||||||
code: '02',
|
code: currentSchool.value!.majorCode,
|
||||||
name: '汉语言文学',
|
name: currentSchool.value!.majorName,
|
||||||
prob: 98,
|
prob: currentSchool.value!.enrollProbability,
|
||||||
score: 460,
|
score: currentSchool.value!.studentScore,
|
||||||
diff: 45,
|
diff: 0,
|
||||||
plan: 12,
|
plan: currentSchool.value!.planNum,
|
||||||
req: '历史+不限',
|
req: currentSchool.value!.mainSubjects,
|
||||||
tuition: '4000/年',
|
tuition: currentSchool.value!.tuition,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
modalLoading.value = false
|
modalLoading.value = false
|
||||||
|
|
@ -310,25 +298,106 @@ function getVolunteerBtnText(code: string) {
|
||||||
return '加入志愿单'
|
return '加入志愿单'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取志愿详情
|
||||||
|
*/
|
||||||
|
async function fetchVolunteerDetail() {
|
||||||
|
try {
|
||||||
|
const res = await getVolunteerDetail()
|
||||||
|
if (res && res.volunteer) {
|
||||||
|
currentVolunteerInfo.value = res.volunteer
|
||||||
|
// 合并所有批次数据用于 Panel B 显示(根据当前 Tab 过滤)
|
||||||
|
const allItems: VolunteerItem[] = []
|
||||||
|
Object.keys(res.items).forEach(batch => {
|
||||||
|
const items = res.items[batch].map(item => ({...item, batchName: batch}))
|
||||||
|
allItems.push(...items)
|
||||||
|
|
||||||
|
// 更新 Tab 计数
|
||||||
|
const tab = volunteerTabs.value.find((t: any) => t.key === batch)
|
||||||
|
if (tab) {
|
||||||
|
tab.count = res.items[batch].length
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
myVolunteers.value = allItems
|
||||||
|
// 备份原始数据用于变动对比
|
||||||
|
originalVolunteers.value = JSON.parse(JSON.stringify(allItems))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取志愿详情失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤后的当前显示志愿(Panel B)
|
||||||
|
*/
|
||||||
|
const filteredVolunteers = computed(() => {
|
||||||
|
// 根据 volunteerCurrentTab 过滤
|
||||||
|
// 直接从 myVolunteers 中过滤出属于该批次的
|
||||||
|
// 注意:fetchVolunteerDetail 时我们需要给 item 加上 batch 标识,或者重新设计存储
|
||||||
|
return myVolunteers.value.filter(v => (v as any).batchName === volunteerCurrentTab.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否修改了志愿列表(拖拽排序或删除)
|
||||||
|
*/
|
||||||
|
const isModified = computed(() => {
|
||||||
|
if (myVolunteers.value.length !== originalVolunteers.value.length) return true
|
||||||
|
// 检查 ID 顺序是否一致
|
||||||
|
return myVolunteers.value.some((v, i) => v.id !== originalVolunteers.value[i]?.id)
|
||||||
|
})
|
||||||
|
|
||||||
// 3. 保存逻辑
|
// 3. 保存逻辑
|
||||||
async function saveVolunteers() {
|
async function saveVolunteers() {
|
||||||
if (isSaving.value)
|
if (isSaving.value)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
const codesToSave = activePanel.value === 'market'
|
||||||
|
? selectedMajorCodes.value
|
||||||
|
: myVolunteers.value.map(v => `${v.schoolCode}_${v.majorCode}_${v.enrollmentCode}`)
|
||||||
|
|
||||||
|
if (codesToSave.length === 0 && activePanel.value === 'market') {
|
||||||
|
// 弹窗中没选专业
|
||||||
|
showSaveConfirm.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
isSaving.value = true
|
isSaving.value = true
|
||||||
|
|
||||||
// 模拟 API 调用
|
try {
|
||||||
setTimeout(() => {
|
await saveVolunteer(codesToSave)
|
||||||
console.warn('保存成功,已选专业代码:', selectedMajorCodes.value)
|
console.warn('保存成功')
|
||||||
|
|
||||||
// 成功后关闭
|
// 成功后刷新详情
|
||||||
|
await fetchVolunteerDetail()
|
||||||
|
|
||||||
|
// 成功后逻辑
|
||||||
isSaving.value = false
|
isSaving.value = false
|
||||||
showSaveConfirm.value = false
|
showSaveConfirm.value = false
|
||||||
closeModal()
|
if (showModal.value) closeModal()
|
||||||
|
|
||||||
// 这里可以加一个全局 Toast 提示 "保存成功"
|
// Toast 提示
|
||||||
console.warn('保存志愿成功!')
|
// @ts-ignore
|
||||||
}, 1000)
|
window.$message?.success?.('保存志愿成功!')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
isSaving.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面离开保护
|
||||||
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
|
if (isModified.value) {
|
||||||
|
const confirmLeave = window.confirm('您有未保存的志愿变动,确定要离开吗?')
|
||||||
|
if (confirmLeave) {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
showModal.value = false
|
showModal.value = false
|
||||||
|
|
@ -340,6 +409,7 @@ onMounted(() => {
|
||||||
// 检查窗口宽度是否大于 1024px
|
// 检查窗口宽度是否大于 1024px
|
||||||
if (window.innerWidth >= 1024) {
|
if (window.innerWidth >= 1024) {
|
||||||
loadMore()
|
loadMore()
|
||||||
|
fetchVolunteerDetail()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成一些模拟的“我的志愿”数据
|
// 生成一些模拟的“我的志愿”数据
|
||||||
|
|
@ -402,12 +472,17 @@ function handleDrop(index: number) {
|
||||||
if (dragStartIndex.value === null || dragStartIndex.value === index)
|
if (dragStartIndex.value === null || dragStartIndex.value === index)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
const draggedItem = filteredVolunteers.value[dragStartIndex.value]
|
||||||
|
const targetItem = filteredVolunteers.value[index]
|
||||||
|
|
||||||
|
const realStartIdx = myVolunteers.value.findIndex(v => v.id === draggedItem.id)
|
||||||
|
const realTargetIdx = myVolunteers.value.findIndex(v => v.id === targetItem.id)
|
||||||
|
|
||||||
|
if (realStartIdx === -1 || realTargetIdx === -1) return
|
||||||
|
|
||||||
// 移动数组元素
|
// 移动数组元素
|
||||||
const draggedItem = myVolunteers.value[dragStartIndex.value]
|
const [removed] = myVolunteers.value.splice(realStartIdx, 1)
|
||||||
// 1. 删除原位置
|
myVolunteers.value.splice(realTargetIdx, 0, removed)
|
||||||
myVolunteers.value.splice(dragStartIndex.value, 1)
|
|
||||||
// 2. 插入新位置
|
|
||||||
myVolunteers.value.splice(index, 0, draggedItem)
|
|
||||||
|
|
||||||
// 触发结束事件
|
// 触发结束事件
|
||||||
handleDragEnd()
|
handleDragEnd()
|
||||||
|
|
@ -421,6 +496,7 @@ function handleDragEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeVolunteer(index: number) {
|
function removeVolunteer(index: number) {
|
||||||
|
// index 是在 myVolunteers 中的索引
|
||||||
myVolunteers.value.splice(index, 1)
|
myVolunteers.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -907,8 +983,11 @@ function deletePlan(planId: string) {
|
||||||
<!-- 提交按钮 (突出显示) -->
|
<!-- 提交按钮 (突出显示) -->
|
||||||
<div class="mx-1 h-6 w-px bg-slate-200" />
|
<div class="mx-1 h-6 w-px bg-slate-200" />
|
||||||
<button
|
<button
|
||||||
class="ml-1 rounded bg-blue-600 px-5 py-2 text-sm text-white font-medium shadow-md transition-all active:scale-95 hover:bg-blue-700"
|
:disabled="!isModified || isSaving"
|
||||||
|
class="ml-1 rounded bg-blue-600 px-5 py-2 text-sm text-white font-medium shadow-md transition-all active:scale-95 hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
@click="saveVolunteers"
|
||||||
>
|
>
|
||||||
|
<span v-if="isSaving" class="mr-1 inline-block h-3 w-3 animate-spin border-2 border-white/30 border-t-white rounded-full"></span>
|
||||||
提交志愿表
|
提交志愿表
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -958,7 +1037,7 @@ function deletePlan(planId: string) {
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-slate-200">
|
<tbody class="divide-y divide-slate-200">
|
||||||
<tr
|
<tr
|
||||||
v-for="(vol, index) in myVolunteers" :key="vol.id"
|
v-for="(vol, index) in filteredVolunteers" :key="vol.id"
|
||||||
class="group bg-white transition-colors hover:bg-slate-50" :draggable="dragEnabledIndex === index"
|
class="group bg-white transition-colors hover:bg-slate-50" :draggable="dragEnabledIndex === index"
|
||||||
@dragstart="handleDragStart($event, index)" @dragover="handleDragOver($event)"
|
@dragstart="handleDragStart($event, index)" @dragover="handleDragOver($event)"
|
||||||
@drop="handleDrop(index)"
|
@drop="handleDrop(index)"
|
||||||
|
|
@ -984,16 +1063,16 @@ function deletePlan(planId: string) {
|
||||||
<!-- 院校信息 -->
|
<!-- 院校信息 -->
|
||||||
<td class="border-r border-slate-200 p-4 text-left">
|
<td class="border-r border-slate-200 p-4 text-left">
|
||||||
<div class="text-base text-slate-900 font-bold">
|
<div class="text-base text-slate-900 font-bold">
|
||||||
{{ vol.name }}
|
{{ vol.schoolName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 flex gap-2">
|
<div class="mt-1 flex gap-2">
|
||||||
<span
|
<span
|
||||||
v-for="tag in vol.tags" :key="tag"
|
v-for="tag in (vol.tags || [vol.province, vol.schoolNature].filter(Boolean))" :key="tag"
|
||||||
class="rounded bg-slate-100 px-1.5 py-0.5 text-xs text-slate-500"
|
class="rounded bg-slate-100 px-1.5 py-0.5 text-xs text-slate-500"
|
||||||
>{{ tag }}</span>
|
>{{ tag }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 text-xs text-slate-400">
|
<div class="mt-1 text-xs text-slate-400">
|
||||||
代码: {{ vol.code }}
|
代码: {{ vol.schoolCode }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
@ -1003,7 +1082,7 @@ function deletePlan(planId: string) {
|
||||||
{{ vol.majorName }}
|
{{ vol.majorName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 text-xs text-slate-500">
|
<div class="mt-1 text-xs text-slate-500">
|
||||||
{{ vol.requirements }} | {{ vol.tuition }}
|
{{ vol.tuition || '-' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs text-slate-400">
|
<div class="text-xs text-slate-400">
|
||||||
代码: {{ vol.majorCode }}
|
代码: {{ vol.majorCode }}
|
||||||
|
|
@ -1013,23 +1092,23 @@ function deletePlan(planId: string) {
|
||||||
<!-- 分数/概率 -->
|
<!-- 分数/概率 -->
|
||||||
<td class="border-r border-slate-200 p-4 text-center">
|
<td class="border-r border-slate-200 p-4 text-center">
|
||||||
<div class="text-lg text-blue-600 font-bold">
|
<div class="text-lg text-blue-600 font-bold">
|
||||||
{{ vol.probability }}%
|
{{ vol.enrollProbability }}%
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-1 text-xs text-slate-500">
|
<div class="mt-1 text-xs text-slate-500">
|
||||||
最低 {{ vol.calcScore }}分
|
排名 {{ vol.indexs }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="mt-1 inline-block border rounded px-2 py-0.5 text-xs"
|
class="mt-1 inline-block border rounded px-2 py-0.5 text-xs"
|
||||||
:class="getStatusColor(vol.statusLabel)"
|
:class="getStatusColor(getProbabilityLabel(vol.enrollProbability))"
|
||||||
>
|
>
|
||||||
{{ vol.statusLabel }}
|
{{ getProbabilityLabel(vol.enrollProbability) }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<!-- 25省内招生 -->
|
<!-- 25省内招生 -->
|
||||||
<td class="border-r border-slate-200 p-4 text-center">
|
<td class="border-r border-slate-200 p-4 text-center">
|
||||||
<div class="text-lg font-bold">
|
<div class="text-lg font-bold">
|
||||||
{{ vol.planCount }}人
|
{{ vol.planNum }}人
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
import request from '../request'
|
||||||
|
|
||||||
|
export interface VolunteerInfo {
|
||||||
|
id: string
|
||||||
|
volunteerName: string
|
||||||
|
scoreId: string
|
||||||
|
createTime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VolunteerItem {
|
||||||
|
id: string
|
||||||
|
schoolCode: string
|
||||||
|
schoolName: string
|
||||||
|
majorName: string
|
||||||
|
province: string
|
||||||
|
schoolNature: string
|
||||||
|
planNum: number
|
||||||
|
enrollProbability: number
|
||||||
|
indexs: number
|
||||||
|
majorCode?: string
|
||||||
|
enrollmentCode?: string
|
||||||
|
tuition?: string
|
||||||
|
tags?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VolunteerDetailResponse {
|
||||||
|
volunteer: VolunteerInfo
|
||||||
|
items: Record<string, VolunteerItem[]>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存志愿明细
|
||||||
|
* @param data schoolCode_majorCode_enrollmentCode 字符串数组
|
||||||
|
*/
|
||||||
|
export function saveVolunteer(data: string[]) {
|
||||||
|
return request.post('/user/volunteer/save', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前志愿单详情
|
||||||
|
*/
|
||||||
|
export function getVolunteerDetail() {
|
||||||
|
return request.get<VolunteerDetailResponse>('/user/volunteer/detail')
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue