feat: 志愿表筛选

master
xjs 2025-03-17 13:11:58 +08:00
parent 840dd36f7e
commit e3977c7e89
10 changed files with 151 additions and 65 deletions

View File

@ -3,20 +3,22 @@
<view <view
class="action-sheet-mask" class="action-sheet-mask"
:class="{ 'action-sheet-mask-show': show }" :class="{ 'action-sheet-mask-show': show }"
@click="handleClose" @click.stop="handleClose"
@touchmove.prevent @touchmove.prevent
></view> ></view>
<view class="action-sheet pb-safe" :class="{ 'action-sheet-show': show }" @touchmove.prevent> <view class="action-sheet pb-safe" :class="{ 'action-sheet-show': show }" @touchmove.prevent>
<view class="action-sheet-header" v-if="title"> <template v-if="!lazyRender || show">
<text class="action-sheet-title">{{ title }}</text> <view class="action-sheet-header" v-if="title">
</view> <text class="action-sheet-title">{{ title }}</text>
<slot name="title"></slot> </view>
<scroll-view class="action-sheet-content" :scroll-y="true"> <slot name="title"></slot>
<slot></slot> <scroll-view class="action-sheet-content" :scroll-y="true">
</scroll-view> <slot></slot>
<view class="action-sheet-footer" v-if="$slots.footer"> </scroll-view>
<slot name="footer"></slot> <view class="action-sheet-footer" v-if="$slots.footer">
</view> <slot name="footer"></slot>
</view>
</template>
</view> </view>
</view> </view>
</template> </template>
@ -25,6 +27,7 @@
defineProps<{ defineProps<{
show: boolean show: boolean
title?: string title?: string
lazyRender?: boolean
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
@ -44,7 +47,7 @@ const handleClose = () => {
right: 0; right: 0;
bottom: 0; bottom: 0;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
z-index: 999; z-index: 9;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
transition: all 0.3s ease; transition: all 0.3s ease;

View File

@ -11,7 +11,7 @@
> >
{{ calcTypeName(major.type).text }} {{ calcTypeName(major.type).text }}
</view> </view>
<text class="text-[32rpx] font-semibold text-[#000]">{{ major.percentAge }}%</text> <text class="text-[32rpx] font-semibold text-[#000]">{{ major.percentAge || '0%' }}</text>
</view> </view>
<view class="flex flex-col gap-[16rpx]"> <view class="flex flex-col gap-[16rpx]">
<view class="flex justify-between flex-auto"> <view class="flex justify-between flex-auto">
@ -19,6 +19,7 @@
<text class="text-[32rpx] text-[#000] font-semibold truncate max-w-[400rpx]"> <text class="text-[32rpx] text-[#000] font-semibold truncate max-w-[400rpx]">
{{ major.major.replace(/(\r\n|\n|\r)/g, '') }} {{ major.major.replace(/(\r\n|\n|\r)/g, '') }}
</text> </text>
<text class="text-[22rpx] text-[#1F2329] mt-[14rpx]">{{ major.remark }}</text>
<view class="flex justify-between text-[22rpx] text-[#1F2329] mt-[14rpx]"> <view class="flex justify-between text-[22rpx] text-[#1F2329] mt-[14rpx]">
<view class="flex flex-col gap-[6rpx]"> <view class="flex flex-col gap-[6rpx]">
<text>代码{{ major.majorCode }}</text> <text>代码{{ major.majorCode }}</text>
@ -32,10 +33,10 @@
</view> </view>
<view <view
class="w-[104rpx] h-[52rpx] rounded-[8rpx] custom-btn" :class="`w-[104rpx] h-[52rpx] rounded-[8rpx] text-[24rpx] custom-btn ${checkActive(major) ? 'active-btn' : ''}`"
@click.stop="handleClick(major)" @click.stop="handleClick(major)"
> >
填报 {{ checkActive(major) ? '已填报' : '填报' }}
</view> </view>
</view> </view>
<DataTable :data="major.items" :score="score" /> <DataTable :data="major.items" :score="score" />
@ -57,7 +58,10 @@ const props = defineProps<{
const handleClick = (major: any) => { const handleClick = (major: any) => {
let exitMajorUnList = userStore.userInfo.wishList.find((item) => item.unId === props.item.uId) let exitMajorUnList = userStore.userInfo.wishList.find((item) => item.unId === props.item.uId)
if (exitMajorUnList) { let exitMajor = exitMajorUnList?.vItems.find((item) => item._pId === major.planId)
if (exitMajor) {
userStore.deleteWishListMajor({ unId: props.item.uId, _pId: major.planId })
} else if (exitMajorUnList) {
userStore.setWishListMajor({ userStore.setWishListMajor({
val: { val: {
_pId: major.planId, _pId: major.planId,
@ -89,6 +93,17 @@ const handleClick = (major: any) => {
userStore.setWishListMajorWithUn(_major) userStore.setWishListMajorWithUn(_major)
} }
} }
const checkActive = (major: unknown) => {
const _major = major as { planId: string }
return userStore.userInfo.wishList.find((item) => {
if (item.unId !== props.item.uId) {
return false
} else if (item.vItems.find((vItem) => vItem._pId === _major.planId)) {
return true
}
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -103,4 +118,9 @@ const handleClick = (major: any) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.active-btn {
background-color: #1580ff;
color: #fff;
}
</style> </style>

View File

@ -45,14 +45,16 @@
> >
专业{{ item.items.length }} 专业{{ item.items.length }}
</view> </view>
<text class="text-[20rpx] text-[#8F959E]">已填 1</text> <text class="text-[20rpx] text-[#8F959E]" v-if="collegeMajorCount > 0">
已填 {{ collegeMajorCount }}
</text>
</view> </view>
</view> </view>
<DataTable :data="item.childItems" v-bind="$attrs" /> <DataTable :data="item.childItems" v-bind="$attrs" />
</view> </view>
</view> </view>
<ActionSheet v-model:show="show"> <ActionSheet v-model:show="show" :lazy-render="true">
<template #title> <template #title>
<view class="flex items-center justify-between px-[32rpx] pt-[32rpx] pb-[24rpx]"> <view class="flex items-center justify-between px-[32rpx] pt-[32rpx] pb-[24rpx]">
<view class="flex flex-col gap-[14rpx]"> <view class="flex flex-col gap-[14rpx]">
@ -65,7 +67,7 @@
<view class="i-carbon-close-large w-[40rpx] h-[40rpx]" @click.stop="show = false"></view> <view class="i-carbon-close-large w-[40rpx] h-[40rpx]" @click.stop="show = false"></view>
<view class="text-[22rpx]"> <view class="text-[22rpx]">
<text>已填</text> <text>已填</text>
<text class="text-[#1580FF]">2</text> <text class="text-[#1580FF]">{{ majorCount }}</text>
<text></text> <text></text>
</view> </view>
</view> </view>
@ -94,6 +96,7 @@ const userStore = useUserStore()
const props = defineProps({ const props = defineProps({
item: Object, item: Object,
majorCount: Number,
}) })
const show = ref(false) const show = ref(false)
@ -104,6 +107,12 @@ const handleConfirm = () => {
const handleShow = () => { const handleShow = () => {
show.value = true show.value = true
} }
const collegeMajorCount = computed(() => {
return (
userStore.userInfo.wishList.find((item) => item.unId === props.item.uId)?.vItems.length || 0
)
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -51,8 +51,8 @@
<Slider <Slider
v-model:modelValue="sliderValue" v-model:modelValue="sliderValue"
:min="500" :min="minScore"
:max="600" :max="maxScore"
:step="1" :step="1"
:range="true" :range="true"
@change="handleSliderChange" @change="handleSliderChange"
@ -67,47 +67,48 @@
:id="`zp-id-${item.zp_index}`" :id="`zp-id-${item.zp_index}`"
:key="item.zp_index" :key="item.zp_index"
v-for="(item, index) in schoolList" v-for="(item, index) in schoolList"
@click="itemClick(item, index)"
> >
<ScrollListItem :item="item" :score="score" /> <ScrollListItem :item="item" :score="score" :major-count="majorCount" />
</view> </view>
<ActionSheet v-model:show="show" :title="actionTitle">
<view class="px-[36rpx]">
<Region
v-if="actionType === 2"
width="210rpx"
height="60rpx"
class="px-[32rpx]"
@change-name="handleRegionName"
/>
</view>
<FilterMenu v-if="actionType === 1" :show-phase="false" ref="filterMenuRef" :menuBit="28" />
<CustomPickerView
v-if="actionType === 3"
:list="typeModelList"
v-model:modelValue="collegeSearch.tModelValue"
value-key="value"
label-key="name"
@change="handleTypeModelChange"
/>
<template #footer>
<view class="flex items-center justify-between gap-[30rpx]">
<view class="cancel-btn" @click="show = false">取消</view>
<view class="submit-btn" @click="handleConfirm"></view>
</view>
</template>
</ActionSheet>
<template #bottom> <template #bottom>
<view class="pb-safe px-[32rpx] pt-[32rpx] bg-[#fff]"> <view class="pb-safe px-[32rpx] pt-[32rpx] bg-[#fff]">
<view <view
class="h-[80rpx] rounded-[8rpx] bg-[#1580FF] flex items-center justify-center text-[#fff]" :class="`h-[80rpx] rounded-[8rpx] bg-[#1580FF] flex items-center justify-center text-[#fff] ${majorCount === 0 ? 'disabled-btn' : ''}`"
@click="handlePreview"
> >
预览志愿表(2) 预览志愿表({{ majorCount }})
</view> </view>
</view> </view>
</template> </template>
</z-paging> </z-paging>
<ActionSheet v-model:show="show" :title="actionTitle">
<view class="px-[36rpx]">
<Region
v-if="actionType === 2"
width="210rpx"
height="60rpx"
class="px-[32rpx]"
@change-name="handleRegionName"
/>
</view>
<FilterMenu v-if="actionType === 1" :show-phase="false" ref="filterMenuRef" :menuBit="28" />
<CustomPickerView
v-if="actionType === 3"
:list="typeModelList"
v-model:modelValue="collegeSearch.tModelValue"
value-key="value"
label-key="name"
@change="handleTypeModelChange"
/>
<template #footer>
<view class="flex items-center justify-between gap-[30rpx]">
<view class="cancel-btn" @click="show = false">取消</view>
<view class="submit-btn" @click="handleConfirm"></view>
</view>
</template>
</ActionSheet>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -117,7 +118,7 @@ import Region from '@/pages-sub/home/components/Region.vue'
import FilterMenu from '@/pages-sub/home/components/FilterMenu.vue' import FilterMenu from '@/pages-sub/home/components/FilterMenu.vue'
import Slider from '@/pages-sub/components/Slider.vue' import Slider from '@/pages-sub/components/Slider.vue'
import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue' import CustomPickerView from '@/pages-sub/components/CustomPickerView.vue'
import { getBatchData } from '@/service/index/api' import { getBatchBase } from '@/service/index/api'
import ScrollListItem from './ScrollListItem.vue' import ScrollListItem from './ScrollListItem.vue'
import HeaderTip from './HeaderTip.vue' import HeaderTip from './HeaderTip.vue'
@ -142,6 +143,10 @@ const handleTypeModelChange = ({ item }) => {
collegeSearch.value.tModel = item.name collegeSearch.value.tModel = item.name
} }
const majorCount = computed(() => {
return userStore.userInfo.wishList.reduce((a, b) => a + b.vItems.length, 0)
})
const queryList = (page: number, pageSize: number) => { const queryList = (page: number, pageSize: number) => {
getPlanProListByFilter({ getPlanProListByFilter({
pageIndex: page, pageIndex: page,
@ -158,6 +163,7 @@ const queryList = (page: number, pageSize: number) => {
feature: collegeSearch.value.feature, feature: collegeSearch.value.feature,
majors: collegeSearch.value.majors, majors: collegeSearch.value.majors,
keyword: searchValue.value, keyword: searchValue.value,
type: collegeSearch.value.tModelValue === '-1' ? null : +collegeSearch.value.tModelValue,
}).then((resp) => { }).then((resp) => {
if (resp.code === 200) { if (resp.code === 200) {
paging.value.complete((resp.result as { rows: any[] }).rows) paging.value.complete((resp.result as { rows: any[] }).rows)
@ -219,25 +225,38 @@ const handleRegionName = (val: string[]) => {
province.value = val province.value = val
} }
const sliderValue = ref([550, 590]) const sliderValue = ref([
+userStore.userInfo.estimatedAchievement.expectedScore - 50,
+userStore.userInfo.estimatedAchievement.expectedScore + 50,
])
const handleSliderChange = (val) => { const handleSliderChange = (val) => {
paging.value.reload() paging.value.reload()
} }
const score = ref(0) const score = ref(0)
const minScore = ref(0)
const maxScore = ref(0)
onLoad(() => { onLoad(() => {
getBatchData(userStore.userInfo.batchDataUrl).then((resp) => { getBatchBase({ locationCode: userStore.userInfo.estimatedAchievement.provinceCode }).then(
if (resp.code === 200) { (resp) => {
const _batchData = resp.result as any[] if (resp.code === 200) {
if (_batchData.length > 0) { const _result = resp.result as { batches: any[]; maxScore: number; minScore: number }
const _score = if (_result.batches.length > 0) {
_batchData[0].batches.find((item) => item.batch === userStore.userInfo.batchName) const _score =
?.score || 0 _result.batches.find((item) => item.batch === userStore.userInfo.batchName)?.score || 0
score.value = _score score.value = _score
}
minScore.value = _result.minScore
maxScore.value = _result.maxScore
} }
} },
}) )
}) })
const handlePreview = () => {
uni.navigateTo({ url: '/pages-sub/home/wishesList/wishesList' })
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -250,4 +269,9 @@ onLoad(() => {
.border-top { .border-top {
border-top: 2rpx solid #ededed; border-top: 2rpx solid #ededed;
} }
.disabled-btn {
background-color: #f5f5f5 !important;
color: #999 !important;
}
</style> </style>

View File

@ -1,6 +1,6 @@
export const calcTypeName = (type: number) => { export const calcTypeName = (type: number) => {
const style = { const style = {
0: { 2: {
text: '冲', text: '冲',
color: '#EB5241', color: '#EB5241',
bgColor: 'rgba(235,82,65,0.15)', bgColor: 'rgba(235,82,65,0.15)',
@ -10,7 +10,7 @@ export const calcTypeName = (type: number) => {
color: '#FA8E23', color: '#FA8E23',
bgColor: 'rgba(250,142,35,0.15)', bgColor: 'rgba(250,142,35,0.15)',
}, },
2: { 0: {
text: '保', text: '保',
color: '#15C496', color: '#15C496',
bgColor: 'rgba(21,196,150,0.15)', bgColor: 'rgba(21,196,150,0.15)',

View File

@ -0,0 +1,11 @@
<template>
<view class="">
<HeaderTip :user-info="userStore.userInfo" />
</view>
</template>
<script setup lang="ts">
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
</script>

View File

@ -261,6 +261,10 @@
{ {
"path": "home/wishesList/ScrollListItem", "path": "home/wishesList/ScrollListItem",
"type": "page" "type": "page"
},
{
"path": "home/wishesList/wishesList",
"type": "page"
} }
] ]
}, },

View File

@ -276,3 +276,7 @@ export const aiPreview = (params: {
export const getPlanProListByFilter = (params: AutoFillParams) => { export const getPlanProListByFilter = (params: AutoFillParams) => {
return http.post('/api/PlanPro/aiUniversity', params) return http.post('/api/PlanPro/aiUniversity', params)
} }
export const getBatchBase = (params: { locationCode: string }) => {
return http.get('/api/busBatchBase/batch', params)
}

View File

@ -143,6 +143,15 @@ export const useUserStore = defineStore(
} }
} }
const deleteWishListMajor = ({ unId, _pId }: { unId: string; _pId: string }) => {
userInfo.value.wishList = userInfo.value.wishList.map((item) => {
if (item.unId === unId) {
item.vItems = item.vItems.filter((vItem) => vItem._pId !== _pId)
return item
}
return item
})
}
const setWishListMajorWithUn = (val) => { const setWishListMajorWithUn = (val) => {
userInfo.value.wishList.push({ ...val, sort: userInfo.value.wishList.length + 1 }) userInfo.value.wishList.push({ ...val, sort: userInfo.value.wishList.length + 1 })
} }
@ -181,6 +190,7 @@ export const useUserStore = defineStore(
clearWishList, clearWishList,
setWishListMajor, setWishListMajor,
setWishListMajorWithUn, setWishListMajorWithUn,
deleteWishListMajor,
} }
}, },
{ {

View File

@ -32,6 +32,7 @@ interface NavigateToOptions {
"/pages-sub/home/wishesList/HeaderTip" | "/pages-sub/home/wishesList/HeaderTip" |
"/pages-sub/home/wishesList/index" | "/pages-sub/home/wishesList/index" |
"/pages-sub/home/wishesList/ScrollListItem" | "/pages-sub/home/wishesList/ScrollListItem" |
"/pages-sub/home/wishesList/wishesList" |
"/login-sub/index" | "/login-sub/index" |
"/pages-evaluation-sub/index" | "/pages-evaluation-sub/index" |
"/pages-evaluation-sub/aiAutoFill/index" | "/pages-evaluation-sub/aiAutoFill/index" |