feat: 页面适配审核需求

master
xjs 2025-04-25 10:57:24 +08:00
parent 1b4b545b65
commit 1171acbd27
21 changed files with 363 additions and 35 deletions

View File

@ -4,6 +4,7 @@
class="flex items-center justify-between mx-[34rpx] py-[26rpx]"
style="border-bottom: 2rpx solid #ededed"
@click="handleChange"
v-if="userStore.userInfo.openid"
>
<text class="text-[44rpx] text-[#333]">
{{
@ -17,7 +18,14 @@
src="https://api.static.ycymedu.com/src/images/home/pen.svg"
></image>
</view>
<view class="mt-[56rpx] flex items-center justify-between">
<view class="flex items-center justify-center" v-else>
<image
class="w-[74%] h-[50rpx]"
mode="widthFix"
src="https://api.static.ycymedu.com/images/homepageheadtmp.png"
/>
</view>
<view class="mt-[56rpx] flex items-center justify-between" v-if="userStore.userInfo.openid">
<button
class="w-[240rpx]! h-[88rpx]! border-[#1580FF]! text-[#1580FF]! text-[30rpx]! font-normal! mr-[32rpx] flex! items-center! justify-center! rounded-[8rpx]!"
plain
@ -32,6 +40,14 @@
智能填报
</button>
</view>
<view class="flex items-center justify-between mt-[26rpx]" v-else>
<button
class="h-[88rpx]! w-full! text-[#fff]! text-[30rpx]! bg-[#1580FF]! font-normal flex! items-center! justify-center! rounded-[8rpx]!"
@click="navigatorToLogin"
>
登录/注册
</button>
</view>
</view>
</template>
@ -65,4 +81,10 @@ const navigatorToAi = () => {
})
}
}
const navigatorToLogin = () => {
uni.navigateTo({
url: '/login-sub/index',
})
}
</script>

View File

@ -1,7 +1,9 @@
import { TabesItem } from '@/service/app'
import { sysDictType } from '@/service/index/api'
import { useUserStore } from '@/store'
const tabbarList = ref<TabesItem[]>([])
const userStore = useUserStore()
sysDictType({ id: 619330547859525 }).then((res) => {
const { code, result } = res
@ -52,8 +54,10 @@ sysDictType({ id: 619330547859525 }).then((res) => {
if (code === 200) {
if (status === 1) {
tabbarList.value = _tabbarList.filter((item) => item.id !== 2)
userStore.setIsShowAi(false)
} else {
tabbarList.value = _tabbarList
userStore.setIsShowAi(true)
}
}
})

View File

@ -15,22 +15,30 @@
</text>
<button
class="w-[493rpx]! mb-[40rpx] h-[88rpx]! rounded-[44rpx] text-[32rpx] text-white flex items-center justify-center"
:class="checked ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'"
:class="checked.length > 0 ? 'bg-[#1580FF]' : 'bg-[#BFBFBF]'"
@click.stop="handleClick"
open-type="getPhoneNumber"
@getphonenumber="getPhoneNumber"
:disabled="!checked"
:disabled="checked.length === 0"
>
手机号快捷登录
</button>
<view class="flex items-center flex-nowrap" @click.stop="checked = 1">
<RadioGroup v-model="checked" custom-class="mr-10rpx">
<Radio :name="1"></Radio>
</RadioGroup>
<view class="flex items-center flex-nowrap">
<CheckboxGroup v-model="checked" class="check-class mr-[10rpx]">
<Checkbox name="1" cell shape="button" class="custom-checkbox"></Checkbox>
</CheckboxGroup>
<view class="flex items-center">
<text class="text-[24rpx] whitespace-nowrap">
已阅读并同意服务条款隐私条款
已阅读并同意
<text class="text-[#1580FF]" @click.stop="handleClickUserAgreement">
<text>用户协议</text>
</text>
<text class="text-[#1580FF]" @click.stop="handleClickPrivacyPolicy">
<text>隐私条款</text>
</text>
</text>
</view>
</view>
@ -44,6 +52,9 @@ import { useLogin } from '@/login-sub/hooks/useUserInfo'
import Overlay from './Overlay.vue'
import RadioGroup from './radio-group/RadioGroup.vue'
import Radio from './radio-group/Radio.vue'
import Checkbox from './check-group/Checkbox.vue'
import CheckboxGroup from './check-group/CheckboxGroup.vue'
import {
getSessionKey,
getVolunteerInitialization,
@ -74,9 +85,21 @@ const handleClose = () => {
}
const phone = ref(true) //
const checked = ref(0) //
const checked = ref([]) //
const getPhoneInfo = ref(null)
const handleClickUserAgreement = () => {
uni.navigateTo({
url: '/login-sub/userAgreement',
})
}
const handleClickPrivacyPolicy = () => {
uni.navigateTo({
url: '/login-sub/privacyPolicy',
})
}
const getPhoneNumber = async (e: any) => {
if (e.detail.errMsg == 'getPhoneNumber:ok') {
const detail = e.detail
@ -169,7 +192,27 @@ const getUserInfo = async (code: string) => {
</script>
<style lang="scss" scoped>
:deep(.wd-radio) {
--wot-radio-margin: 0;
:deep(.custom-checkbox) {
display: flex;
align-items: center;
justify-content: center;
.checkbox__icon {
border-radius: 50%;
height: 32rpx;
width: 32rpx;
margin: 0;
}
.custom-box {
width: 32rpx;
height: 32rpx;
border: 1px solid #ddd;
border-radius: 50%;
}
}
:deep(.checkbox-active) {
border-color: #fff !important;
background-color: #fff !important;
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<view
class="checkbox"
:class="{
'checkbox--disabled': isDisabled,
'checkbox-active': isChecked,
'checkbox-disabled': isDisabled,
}"
@click="handleClick"
>
<view class="checkbox__icon" :class="{ 'checkbox__icon--checked': isChecked }">
<text v-show="isChecked" class="i-carbon-checkmark checkbox__icon-check"></text>
</view>
<view class="checkbox__label">
<slot>{{ label }}</slot>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed, inject } from 'vue'
const props = defineProps({
name: {
type: [String, Number],
required: true,
},
label: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['change'])
interface CheckboxGroupContext {
modelValue: ComputedRef<any[]>
disabled: ComputedRef<boolean>
max: ComputedRef<number>
selectedCount: ComputedRef<number>
toggleOption: (option: { value: string | number }) => void
}
// checkbox group
const checkboxGroup = inject<CheckboxGroupContext>('checkboxGroup', {
modelValue: computed(() => []),
disabled: computed(() => false),
max: computed(() => 0),
selectedCount: computed(() => 0),
toggleOption: () => {},
})
//
const isChecked = computed(() => {
const modelValue = checkboxGroup.modelValue.value
return modelValue.includes(props.name)
})
//
const isDisabled = computed(() => {
const max = checkboxGroup.max.value
const selectedCount = checkboxGroup.selectedCount.value
// group
return (
props.disabled ||
checkboxGroup.disabled.value ||
(max > 1 && !isChecked.value && selectedCount >= max)
)
})
//
const handleClick = () => {
if (isDisabled.value) return
checkboxGroup.toggleOption({
value: props.name,
})
}
</script>
<style scoped>
.checkbox {
display: inline-flex;
align-items: center;
cursor: pointer;
font-size: 28rpx;
}
.checkbox--disabled {
cursor: not-allowed;
opacity: 0.5;
}
.checkbox__icon {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #dcdfe6;
border-radius: 4rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8rpx;
transition: all 0.2s;
}
.checkbox__icon--checked {
background-color: #0083ff;
border-color: #0083ff;
}
.checkbox__icon-check {
color: #fff;
font-size: 32rpx;
}
.checkbox__label {
line-height: 1;
}
.checkbox-active {
background-color: #0083ff;
border-color: #0083ff;
}
.checkbox-disabled {
opacity: 0.5;
cursor: not-allowed !important;
}
</style>

View File

@ -0,0 +1,72 @@
<template>
<view class="checkbox-group">
<slot></slot>
</view>
</template>
<script lang="ts" setup>
import { provide, computed } from 'vue'
const props = defineProps({
modelValue: {
type: Array,
default: () => [],
},
max: {
type: Number,
default: 0,
},
disabled: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['update:modelValue', 'change'])
//
const innerValue = computed(() => props.modelValue)
//
const toggleOption = (option: { label: string; value: string | number }) => {
const currentValue = innerValue.value
const index = currentValue.indexOf(option.value)
let newValue = [...currentValue]
if (index === -1) {
if (props.max === 1) {
newValue = [option.value]
} else if (props.max && currentValue.length >= props.max) {
uni.showToast({
title: `最多只能选择${props.max}`,
icon: 'none',
})
return
} else {
newValue.push(option.value)
}
} else {
newValue.splice(index, 1)
}
emit('update:modelValue', newValue)
emit('change', newValue)
}
// checkbox
provide('checkboxGroup', {
modelValue: computed(() => props.modelValue),
disabled: computed(() => props.disabled),
max: computed(() => props.max),
selectedCount: computed(() => props.modelValue.length),
toggleOption,
})
</script>
<style scoped lang="scss">
.checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
</style>

View File

@ -0,0 +1,7 @@
<template>
<web-view src="https://api.static.ycymedu.com/lwxy.html" />
</template>
<script lang="ts" setup></script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,7 @@
<template>
<web-view src="https://api.static.ycymedu.com/lwuser.html" />
</template>
<script lang="ts" setup></script>
<style scoped lang="scss"></style>

View File

@ -3,6 +3,7 @@
<view
class="pt-[16rpx] px-[32rpx] mt-[20rpx] flex items-center justify-center bg-[#fff] pb-safe sticky bottom-0 z-999"
@click="toAiAssistant"
v-if="userStore.userInfo.isShowAi"
>
<view
class="rounded-[8rpx] border-[#1580FF] border-[2rpx] border-solid w-full py-[14rpx] flex items-center justify-center"
@ -14,9 +15,12 @@
<text class="text-[#1580FF] text-[32rpx] font-700">智能AI顾问</text>
</view>
</view>
<view v-else class="pb-safe"></view>
</template>
<script setup lang="ts">
import { useUserStore } from '@/store'
const userStore = useUserStore()
const props = defineProps({
pageId: {
type: Number,

View File

@ -3,7 +3,6 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>
<template>

View File

@ -3,6 +3,7 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>

View File

@ -3,7 +3,6 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>

View File

@ -3,6 +3,7 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>

View File

@ -3,7 +3,6 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>
<template>

View File

@ -63,24 +63,21 @@
"type": "page",
"style": {
"navigationBarTitleText": "测评"
},
"needLogin": true
}
},
{
"path": "pages/expert/index/index",
"type": "page",
"style": {
"navigationBarTitleText": "专家"
},
"needLogin": true
}
},
{
"path": "pages/ucenter/index/index",
"type": "page",
"style": {
"navigationStyle": "custom"
},
"needLogin": true
}
}
],
"preloadRule": {
@ -141,15 +138,15 @@
"type": "page",
"style": {
"navigationStyle": "custom"
},
"needLogin": true
}
},
{
"path": "home/career/info",
"type": "page",
"style": {
"navigationStyle": "custom"
}
},
"needLogin": true
},
{
"path": "home/city/index",
@ -170,15 +167,15 @@
"type": "page",
"style": {
"navigationStyle": "custom"
},
"needLogin": true
}
},
{
"path": "home/college/info",
"type": "page",
"style": {
"navigationStyle": "custom"
}
},
"needLogin": true
},
{
"path": "home/distinguish/index",
@ -214,8 +211,7 @@
"type": "page",
"style": {
"navigationStyle": "custom"
},
"needLogin": true
}
},
{
"path": "home/major/info",
@ -323,6 +319,14 @@
"style": {
"navigationStyle": "custom"
}
},
{
"path": "privacyPolicy",
"type": "page"
},
{
"path": "userAgreement",
"type": "page"
}
]
},

View File

@ -52,6 +52,12 @@ const props = defineProps({
})
const toAssessmentPage = () => {
if (!userStore.userInfo.openid) {
uni.navigateTo({
url: '/login-sub/index',
})
return
}
if (props.item.isFree) {
uni.navigateTo({
url: `/pages-sub/evaluation/assessmentPage?id=${props.item.id}&name=${props.item.name}`,

View File

@ -3,7 +3,6 @@
style: {
navigationBarTitleText: '测评',
},
needLogin: true,
}
</route>

View File

@ -3,7 +3,6 @@
style: {
navigationBarTitleText: '专家',
},
needLogin: true,
}
</route>
<template>
@ -63,6 +62,15 @@ const list = ref<any[]>([])
const userStore = useUserStore()
onShow(() => {
if (!userStore.userInfo.openid) {
getBusSpecialListGroup().then((res) => {
if (res.code === 200) {
list.value = res.result as any[]
}
})
return
}
getMySpecialList({
openId: userStore.userInfo?.estimatedAchievement.wxId.toString(),
}).then((_res) => {

View File

@ -3,22 +3,26 @@
style: {
navigationStyle: 'custom',
},
needLogin: true,
}
</route>
<template>
<view class="bg-[#F8F8F8] h-screen flex flex-col gap-[32rpx]">
<view class="background-wrapper">
<Navbar safeAreaInsetTop bg-color="transparent" placeholder :bordered="false"></Navbar>
<view class="flex px-[32rpx] gap-[24rpx] custom-user-info">
<view class="flex px-[32rpx] gap-[24rpx] custom-user-info" @click.stop="goLogin">
<image
:src="userStore.userInfo.avatar"
:src="
userStore.userInfo.avatar ||
'https://private-zhiyuan.oss-cn-beijing.aliyuncs.com/avatar.png'
"
class="w-[112rpx] h-[112rpx] rounded-full z-[1]"
mode="scaleToFill"
/>
<view class="flex flex-col gap-[6rpx] py-[8rpx] z-[1] text-white">
<text class="text-[32rpx] font-semibold">{{ userStore.userInfo.nickname }}</text>
<text class="text-[24rpx]">
<text class="text-[32rpx] font-semibold">
{{ userStore.userInfo.nickname || '未登录' }}
</text>
<text class="text-[24rpx]" v-show="userStore.userInfo.openid">
{{ userStore.userInfo.estimatedAchievement.provinceName }}·{{
userStore.userInfo.estimatedAchievement.expectedScore
}}
@ -176,6 +180,14 @@ const toSetting = () => {
url: '/pages-sub/ucenter/setting/index',
})
}
const goLogin = () => {
if (!userStore.userInfo.openid) {
uni.navigateTo({
url: '/login-sub/index',
})
}
}
</script>
<style lang="scss" scoped>

View File

@ -57,6 +57,7 @@ const initState = {
batchDataUrl: '',
batchName: '',
wishList: [],
isShowAi: false,
}
export const useUserStore = defineStore(
@ -190,6 +191,9 @@ export const useUserStore = defineStore(
const reset = () => {
userInfo.value = { ...initState }
}
const setIsShowAi = (val: boolean) => {
userInfo.value.isShowAi = val
}
const isLoginFlag = computed(() => !!userInfo.value.token)
return {
@ -216,6 +220,7 @@ export const useUserStore = defineStore(
sortWishCollegeList,
setIsVIP,
setVipCode,
setIsShowAi,
}
},
{

View File

@ -63,6 +63,7 @@ export type ExtraUserInfo = {
batchDataUrl: string
batchName: string
wishList: any[]
isShowAi: boolean
} & IUserInfo
export type News = {

View File

@ -37,6 +37,8 @@ interface NavigateToOptions {
"/pages-sub/ucenter/vip/openVip" |
"/pages-sub/ucenter/wishList/wishList" |
"/login-sub/index" |
"/login-sub/privacyPolicy" |
"/login-sub/userAgreement" |
"/pages-evaluation-sub/aiAutoFill/index" |
"/pages-evaluation-sub/rank/index" |
"/pages-evaluation-sub/evaluate/academicReport/capabilityReport" |