feat: 新的保存逻辑

share-code
xjs 2026-06-01 10:41:00 +08:00
parent 7a4d32eaa2
commit b7b3baf17b
10 changed files with 142 additions and 194 deletions

View File

@ -35,6 +35,10 @@ const props = defineProps({
readonly: {
type: Boolean,
default: false
},
inputDirection: {
type: String as PropType<'text-left' | 'text-right' | 'text-center'>,
default: 'text-left'
}
})
@ -52,7 +56,7 @@ const innerValue = computed({
<template>
<view class="relative w-full" :class="rootClass">
<input :type="type" v-model="innerValue" :placeholder="placeholder" confirm-type="done" :disabled="readonly"
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left" />
:placeholder-style="`color:#C5C8D1;font-size:30rpx;${inputDirection === 'text-right' ? 'text-align:right;' : inputDirection === 'text-center' ? 'text-align:center;' : 'text-align:left;'} `" />
<view class="absolute top-0 left-0 w-full h-full" v-if="readonly"></view>
</view>
</template>

View File

@ -1,78 +1,89 @@
<script setup lang="ts">
type RadioValue = string | number | null | undefined
type RadioOptionValue = string | number | null | undefined
type RadioOption = Record<string, RadioOptionValue>
const props = defineProps({
value: {
type: [String,Number],
default: ""
},
options: {
type: Array,
default: () => []
},
valueKey: {
type: String,
default: ''
},
labelKey: {
type: String,
default: ''
},
interface RadioProps {
value?: RadioValue
options?: RadioOption[]
valueKey?: string
labelKey?: string
customRootClass?: string
customRootWidth?: string
customRootColsClass?: string
customItemClass?: string
defaultItemClass?: string
activeItemClass?: string
}
customRootClass: {
type: String,
default: ""
},
customRootWidth:{
type: String,
default: ""
},
customRootColsClass:{
type: String,
default: "grid gap-[20rpx] grid-cols-3"
},
customItemClass:{
type: String,
default: ""
},
defaultItemClass:{
type: String,
default: "bg-[#F3F4F8] border-[#F3F4F8]"
},
activeItemClass:{
type:String,
default: "bg-white text-[#1580FF] border-[#1580FF]"
}
const props = withDefaults(defineProps<RadioProps>(), {
value: '',
options: () => [],
valueKey: '',
labelKey: '',
customRootClass: '',
customRootWidth: '',
customRootColsClass: 'grid gap-[20rpx] grid-cols-3',
customItemClass: '',
defaultItemClass: 'bg-[#F3F4F8] border-[#F3F4F8]',
activeItemClass: 'bg-white text-[#1580FF] border-[#1580FF]',
})
const emits = defineEmits<{
'update:value': [value: RadioValue]
'update:label': [label: string]
'change': []
}>()
type ToggleFn = (value: RadioValue) => void
const getOptionValue = (option: RadioOption): RadioValue => option[props.valueKey]
function getOptionLabel(option: RadioOption): string {
const label = option[props.labelKey]
return label == null ? '' : String(label)
}
function getOptionKey(option: RadioOption, index: number): string | number {
const value = getOptionValue(option)
return value ?? index
}
const innerValue = computed({
get: () => props.value,
set: (val) => emits("update:value",val)
get: () => props.value,
set: val => emits('update:value', val),
})
const emits = defineEmits(["update:value","update:label","change"])
const handleToggle = (val:any) => {
const chooseItem = props.options.filter(item => item[props.valueKey] === val)
emits("update:value",val)
emits("update:label",chooseItem[0][props.labelKey])
emits("change")
function handleToggle(val: RadioValue) {
const chooseItem = props.options.find(item => getOptionValue(item) === val)
emits('update:value', val)
emits('update:label', chooseItem ? getOptionLabel(chooseItem) : '')
emits('change')
}
function handleOptionClick(option: RadioOption, toggle: ToggleFn) {
const value = getOptionValue(option)
toggle(value)
handleToggle(value)
}
</script>
<template>
<sar-radio-group v-model="innerValue">
<template #custom="{ toggle, value }">
<view :class="`bg-white rounded-[0_0_12rpx_12rpx] ${customRootClass} ${customRootColsClass}`">
<view v-for="val in options" :key="val[valueKey]"
:class="`${val[valueKey] === value ? activeItemClass : defaultItemClass} ${customItemClass} rounded-[12rpx] text-[28rpx]`"
@click="() => {toggle(val[valueKey]); handleToggle(val[valueKey])}">
{{ val[labelKey] }}
</view>
</view>
</template>
</sar-radio-group>
</template>
<sar-radio-group v-model="innerValue">
<template #custom="{ toggle, value: currentValue }">
<view :class="`bg-white rounded-[0_0_12rpx_12rpx] ${customRootClass} ${customRootColsClass}`">
<view
v-for="(option, index) in options" :key="getOptionKey(option, index)"
:class="`${getOptionValue(option) === currentValue ? activeItemClass : defaultItemClass} ${customItemClass} rounded-[12rpx] text-[28rpx]`"
@click="handleOptionClick(option, toggle)"
>
{{ getOptionLabel(option) }}
</view>
</view>
</template>
</sar-radio-group>
</template>

View File

@ -28,8 +28,8 @@ const handleBack = () => {
uni.navigateBack({ delta: 1 })
}
const areaList = ref([])
const natureList = ref([])
const areaList = ref<any[]>([])
const natureList = ref<any[]>()
@ -80,8 +80,8 @@ const visibleFlag1 = ref(false)
const visibleFlag2 = ref(false)
const visibleFlag3 = ref(false)
const partialData = ref([])
const yearList = ref([])
const partialData = ref<any[]>([])
const yearList = ref<any[]>([])
const handleChange = () => {
visibleFlag1.value = false;

View File

@ -9,9 +9,9 @@ definePage({
})
const wishlistStore = useWishlistStore()
const wishlist = ref([])
const wishlist = ref<any[]>([])
const handleDeleteWishlist = (val,index) => {
const handleDeleteWishlist = (val:any,index:number) => {
uni.showModal({
title: "确认需要删除吗?", success: ({confirm,cancel}) => {
if(confirm){
@ -23,15 +23,15 @@ const handleDeleteWishlist = (val,index) => {
})
}
const getTag = (val) => {
const getTag = (val:any) => {
let content = JSON.parse(val.contents)
let schools = content.schools
let zbsTag = schools.some(item => item.type === '指标生')
let zbsTag = schools.some((item:{type:string}) => item.type === '指标生')
let adjustTag = content.adjust
return zbsTag ? "指标生" : adjustTag ? "服从调剂" : false
}
const navigateToDetail = (val) => {
const navigateToDetail = (val:any) => {
let content = JSON.parse(val.contents)
wishlistStore.setExtendWishlist({title:val.title,contents:val.contents,adjust:content.adjust,batchName:val.batchName})
uni.navigateTo({url:"/pages-sub/me/wishlistInfo"})

View File

@ -5,7 +5,7 @@ import MxRadio from "@/pages-sub/components/radio/index.vue?async"
import { getAreaList, getBusSchoolAdmission, getSchoolNature } from "@/service"
import { useWishlistStore } from "@/store"
const tableData = ref([])
const tableData = ref<any[]>([])
const tableColumns = [
{ title: '院校名称', prop: 'schoolName', width: '40%', align: 'left' },
{ title: '冲稳保', prop: 'tags', width: "15%", align: "center" },
@ -14,10 +14,10 @@ const tableColumns = [
] as const
const wishlistStore = useWishlistStore()
const chooseData = ref([])
const chooseData = ref<any[]>([])
const chooseDataMap = new Map()
const handleChoose = (val) => {
const handleChoose = (val:any) => {
if (chooseData.value.includes(val.schoolId)) {
const index = chooseData.value.indexOf(val.schoolId);
@ -27,13 +27,13 @@ const handleChoose = (val) => {
}
} else {
if (chooseData.value.length > 2) {
uni.showToast({ title: "第二志愿最多只能3个", icon: "none" })
uni.showToast({ title: "志愿最多只能3个", icon: "none" })
return;
}
chooseData.value.push(val.schoolId);
chooseDataMap.set(val.schoolId, val)
}
let tempSchool = []
let tempSchool:any[] = []
chooseDataMap.forEach((val, key) => {
tempSchool.push({ ...val, type: "secondBatch" })
})

View File

@ -2,11 +2,10 @@
import { systemInfo } from '@/utils/systemInfo'
import MxRadio from "@/pages-sub/components/radio/index.vue"
import MxInput from "@/pages-sub/components/input/index.vue"
import { getGradeList, getAreaList, saveUserInfo } from "@/service"
import { getGradeList, getAreaList, saveUserAreaScore } from "@/service"
import { useUserStore } from "@/store"
import { storeToRefs } from "pinia";
import { checkEmptyValues } from '@/utils'
// #ifdef MP-WEIXIN
definePage({
@ -45,22 +44,15 @@ const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore)
const handleSubmit = () => {
if (!userInfo.value.nickName || !userInfo.value.sex || checkEmptyValues(userInfo.value.userExtend, ["gradeId", "schoolName", "area"])) {
uni.showToast({ title: "完善所需信息", icon: "error" })
return
}
let params = {
nickName: userInfo.value.nickName,
gradeId: userInfo.value.userExtend.gradeId,
gradeName: userInfo.value.userExtend.gradeName,
areaName: userInfo.value.userExtend.area,
schoolName: userInfo.value.userExtend.schoolName,
sex: userInfo.value.sex,
rank: userInfo.value.userExtend.rank
totalScore: userInfo.value.userExtend.score,
id: userInfo.value.userExtend.id
}
saveUserInfo({ data: params }).then((resp) => {
saveUserAreaScore({ data: params }).then((resp) => {
if (resp.code === 200) {
uni.navigateTo({ url: '/pages-sub/wishlist/create/second' })
uni.navigateTo({ url: '/pages-sub/wishlist/create/secondBatch' })
}
})
}
@ -117,16 +109,13 @@ onShow(() => {
</sar-navbar>
<view class="flex items-center mx-[30rpx] mb-[20rpx]">
<view class="w-[112rpx] h-[104rpx] flex items-center">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_01.png" mode="scaleToFill"
class="w-[112rpx] h-[104rpx]" />
</view>
<view class="flex flex-col ml-[10rpx]">
<view class="text-[44rpx] font-500 mb-[14rpx]">完善基础信息</view>
<view class="text-[#B0B3B8] text-[30rpx]">详细的信息获取精准推荐</view>
<view class="text-[44rpx] font-500 mb-[14rpx]">一键生成志愿表</view>
<view class="text-[#B0B3B8] text-[30rpx]">生成我的专属志愿表</view>
</view>
<view class="w-[160rpx] h-[160rpx] ml-auto">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_zk01.png" mode="scaleToFill"
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_zk03.png" mode="scaleToFill"
class="w-[160rpx] h-[160rpx]" />
</view>
</view>
@ -134,86 +123,47 @@ onShow(() => {
<form @submit="handleSubmit" class="flex-1 pb-safe">
<view class="flex flex-col h-full">
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">学生姓名</view>
<view class="flex-1">
<input type="text" v-model="userInfo.nickName" placeholder="请输入姓名" confirm-type="done"
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left">
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] px-[30rpx] bg-[#F7F8FA] mb-[20rpx]">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">总分</view>
<view class="flex-1 flex items-center">
<MxInput type="number" v-model:value="userInfo.userExtend.score" placeholder="请填写"
root-class="text-right" class="w-full" inputDirection="text-right"/>
</view>
</view>
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">性别</view>
<view class="flex-1 flex items-center" @click="handleOpenPopup('gender')">
<MxInput v-model:value="formData.genderLabel" placeholder="请选择您的性别" root-class="text-left"
:readonly="true" />
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
</view>
</view>
</view>
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx]">年级</view>
<view class="flex-1 flex items-center" @click="handleOpenPopup('grade')">
<MxInput v-model:value="userInfo.userExtend.gradeName" placeholder="请选择您的年级"
root-class="text-left" :readonly="true" />
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
</view>
</view>
</view>
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] px-[30rpx] bg-[#F7F8FA]">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">中考所在区</view>
<view class="flex-1 flex items-center" @click="handleOpenPopup('examinationArea')">
<MxInput v-model:value="userInfo.userExtend.area" placeholder="请选择您的中考所在区"
root-class="text-left" :readonly="true" />
root-class="text-right" class="w-full" inputDirection="text-right" :readonly="true" />
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
<view class="w-[18rpx] h-[36rpx] flex items-center ml-[10rpx]">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
</view>
</view>
</view>
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">就读学校</view>
<view class="flex-1 flex items-center" @click="navigateToSchool">
<view class="flex-1">
<MxInput v-model:value="userInfo.userExtend.schoolName" placeholder="请选择您的就读学校"
root-class="text-left" :readonly="true" />
</view>
<view class="w-[18rpx] h-[36rpx] flex items-center ml-auto">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_jiantou.png"
mode="scaleToFill" class="w-[18rpx] h-[36rpx]" />
<view class="mx-[40rpx] mt-[68rpx] bg-[#FEF6F6] rounded-[16rpx]">
<view class="h-[52rpx] w-[178rpx] flex items-center m-[-8rpx] ml-[20rpx]">
<image src="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/img/home/tb_shuoming.png" mode="scaleToFill"
class="h-[52rpx] w-[178rpx]" />
</view>
<view class="flex flex-col text-[#E03C33] mt-[20rpx] pl-[26rpx] pr-[34rpx]">
<view class="text-[24rpx] mt-[4rpx]">
<view>根据济南2026年中考招生政策进入模拟志愿填报阶段的考生默认历史生物地理道法等水平考试等级均已达到普通高中基础填报要求C级及以上本产品仅用于统招平行志愿的模拟</view>
</view>
</view>
</view>
<view
class="flex items-center text-[30rpx] justify-between mx-[40rpx] py-[34rpx] border-b-1 border-b-[#eaeaea] border-b-solid">
<view class="text-[#404142] text-left min-w-[150rpx] mr-[40rpx] ">校内名次</view>
<view class="flex-1 flex items-center">
<input type="number" inputmode="numeric" v-model="userInfo.userExtend.rank"
placeholder="请输入您的校内名次" confirm-type="done"
placeholder-style="color:#C5C8D1;font-size:30rpx;text-align:left;" class="text-left">
</view>
</view>
<view class="px-[30rpx] py-[16rpx] border-t-solid border-t-[#ededed] border-t-1 mt-auto">
<button form-type="submit" class="rounded-[16rpx] bg-[#1580FF] text-[#fff] submit-btn">下一步</button>
<button form-type="submit" class="rounded-[16rpx] bg-[#1580FF] text-[#fff] submit-btn">开始推荐</button>
</view>
</view>
</form>
@ -227,19 +177,8 @@ onShow(() => {
mode="scaleToFill" class="w-[36rpx] h-[36rpx]" />
</view>
</view>
<MxRadio v-model:value="userInfo.sex" v-model:label="formData.genderLabel" v-if="activeType == 'gender'"
:options="genderClassification" label-key="label" value-key="value"
custom-root-cols-class="grid grid-cols-2 items-center gap-[20rpx]"
custom-root-class="pb-[20rpx]" custom-item-class="py-[12rpx] text-center "
active-item-class="bg-white text-[#1580FF] border-[#1580FF] border-[2rpx] border-solid" @change="visible = false" />
<MxRadio v-model:value="userInfo.userExtend.gradeId" v-model:label="userInfo.userExtend.gradeName"
v-if="activeType == 'grade'" :options="gradeClassification" label-key="label" value-key="value"
custom-root-cols-class="grid grid-cols-3 items-center gap-[20rpx]"
custom-root-class="pb-[20rpx]" custom-item-class="py-[12rpx] text-center "
active-item-class="bg-white text-[#1580FF] border-[#1580FF] border-[2rpx] border-solid" @change="visible = false"/>
<MxRadio v-model:value="userInfo.userExtend.area" v-if="activeType == 'examinationArea'"
:options="areaList" label-key="label" value-key="value"
custom-root-cols-class="grid grid-cols-3 items-center gap-[20rpx]"

View File

@ -58,10 +58,15 @@ onBackPress(() => {
<view v-for="(val, index) in schools" :key="index" class="flex mt-[26rpx]">
<view
class="py-[29rpx] text-[30rpx] text-[#333] grid gap-[8rpx] bg-white px-[30rpx] py-[20rpx] not-last:mb-[30rpx] rounded-[16rpx] w-full">
<view class="text-[32rpx] font-600">{{ val.schoolName }}</view>
<view class="text-[32rpx] font-600 flex items-center gap-[10rpx]">
<view
class="w-[44rpx] h-[44rpx] rounded-[8rpx] text-[26rpx] font-600 flex items-center justify-center"
:class="`${val.tags === '稳' ? 'text-[#FA8E23] bg-[#ffeede]' : val.tags === '保' ? 'bg-[#dcf6f0] text-[#15C496]' : 'bg-[#fce5e3] text-[#EB5241]'}`">
{{ val.tags }}</view>
{{ val.schoolName }}</view>
<view class="text-[24rpx] text-[#333]">{{new Date().getFullYear()}}计划招生{{ val.planCount }}</view>
<!-- <view class="flex items-center">
<view class="text-[#666] bg-[#F8F8F8] rounded-[8rpx] px-[10rpx] py-[4rpx]"
<view class="rgb(173 116 116) bg-[#F8F8F8] rounded-[8rpx] px-[10rpx] py-[4rpx]"
v-for="value in 2" :key="value">重点高中</view>
</view> -->
<view class="text-[#333] text-[24rpx]">
@ -70,24 +75,6 @@ onBackPress(() => {
</view>
</view>
<view class=" bg-[#FEF6F6] rounded-[16rpx] mt-[30rpx]">
<view class="h-[52rpx] w-[178rpx] flex items-center m-[-8rpx] ml-[20rpx]">
<image src="https://lwzk.ycymedu.com/img/tianbao/tb_shuoming.png"
mode="scaleToFill" class="h-[52rpx] w-[178rpx]" />
</view>
<view class="flex flex-col text-[#E03C33] py-[20rpx] pl-[26rpx] pr-[34rpx]">
<view class="text-[26rpx] mt-[4rpx]">
<view>
二志愿录取成功后不再进入后续批次
</view>
<view>
建议选择目标明确的学校同时关注第三批次平行志愿机会
</view>
</view>
</view>
</view>
</view>
<view class="grid grid-cols-2 gap-[20rpx] px-[28rpx] py-[16rpx]">
<view class="rounded-[16rpx] bg-[#f5f5f5] text-[#333] text-[36rpx] py-[18rpx] text-center" @click="navigateToHome"></view>

View File

@ -51,7 +51,7 @@ const disableSubmit = computed(() => {
<sar-navbar show-back @back="handleBack" :fixed="true" fixation-style="top:unset;"
:root-style="{ '--sar-navbar-bg': `transparent`, '--sar-navbar-item-color': 'black', 'padding-top': `${systemInfo?.statusBarHeight}px` }">
<template #title>
<view class="flex justify-center">第二批次</view>
<view class="flex justify-center">志愿表</view>
</template>
</sar-navbar>
<view class="flex-1 overflow-y-auto">

View File

@ -61,7 +61,7 @@ const navigateToFirst = () => {
const totalScore = ref(0)
onLoad(()=>{
getMyScore().then(resp => {
getMyScore().then(resp => {
if (resp.code === 200 && resp.result) {
totalScore.value = resp.result.totalScore
}

View File

@ -299,4 +299,11 @@ export const getHistoryYearList = () => {
return request<API.Response>('/api/busSchoolAdmission/historicalYears', {
method: 'GET',
});
}
export const saveUserAreaScore = (options: { data: any }) => {
return request<API.Response>('/api/busMiddleSchoolApply/add', {
method: "POST",
...options
})
}