feat: 学习风格报告

master
xjs 2025-04-10 10:15:12 +08:00
parent 5887cfaf5c
commit f23605497b
13 changed files with 233 additions and 64 deletions

View File

@ -7,14 +7,31 @@
}
</route>
<template>
<web-view :src="url" @message="handleChildMessage" :update-title="false" />
<!-- <web-view :src="url" @message="handleChildMessage" :update-title="false" /> -->
<input
v-model="message"
type="text"
placeholder="请输入你的高考分数"
confirm-type="done"
class="flex-auto"
@confirm="handleMessage"
/>
</template>
<script setup lang="ts">
import { useUserStore } from '@/store'
import { sendMessage } from '@/service/index/api'
const userStore = useUserStore()
const message = ref('')
const handleMessage = () => {
sendMessage({ conversation_id: '123', user: '1234', query: '山东省计算机考研推荐' }).then(
(resp) => {},
)
}
//chat.ycymedu.com
const url = ref(
`https://chat.ycymedu.com?userId=${userStore.userInfo.estimatedAchievement.wxId}&subjectGroup=${userStore.userInfo.estimatedAchievement.subjectGroup}&expectedScore=${userStore.userInfo.estimatedAchievement.expectedScore}&provinceName=${userStore.userInfo.estimatedAchievement.provinceName}`,

View File

@ -33,7 +33,9 @@ const httpInterceptor = {
// 3. 添加 token 请求头标识
const userStore = useUserStore()
const { token } = userStore.userInfo as unknown as IUserInfo
if (token) {
if (options.url.includes('coze.cn')) {
options.header.Authorization = `Bearer pat_NhhZGW7sxkuyP4mJrPrVyZx20b3m6lymg0y2Ln9EyM0CV9q2f9t3rlGbtzppLQua`
} else if (token) {
options.header.Authorization = `Bearer ${token}`
}
},

View File

@ -31,7 +31,7 @@
class="px-[32rpx] py-[16rpx] bg-[#3370FF] rounded-[40rpx] text-white text-[32rpx] font-medium flex items-center justify-center"
@click="handleLogin"
>
立即登
立即登
</view>
</view>
<LoginMask v-model:show="show" @auth-ready="handleAuthReady" />

View File

@ -4,7 +4,9 @@
<view v-for="(item, index) in items" :key="index" class="suggestion-item">
<view class="text-[32rpx]">{{ item.title }}</view>
<view class="text-[26rpx] font-400 mt-[10rpx]">{{ item.description }}</view>
<view class="text-[26rpx] font-400 mt-[10rpx]">
{{ item.description instanceof Array ? item.description.join(',') : item.description }}
</view>
</view>
</view>
</template>
@ -13,7 +15,7 @@
import TitleBar from './TitleBar.vue'
defineProps({
items: {
type: Array<{ title: string; description: string }>,
type: Array<{ title: string; description: string | [] }>,
default: () => [],
},
title: {

View File

@ -0,0 +1,18 @@
<template>
<view class="mt-[30rpx] bg-white rounded-[20rpx] p-[30rpx]">
<TitleBar :title="title" />
</view>
</template>
<script lang="ts" setup>
import TitleBar from './TitleBar.vue'
defineProps({
items: {
type: Array<{ title: string; description: string | [] }>,
default: () => [],
},
title: {
type: String,
default: '',
},
})
</script>

View File

@ -0,0 +1,147 @@
<template>
<view class="bg-white rounded-[20rpx] pb-[20rpx] custom-background">
<view class="h-[586rpx] z-1">
<LEchart ref="echart" :customStyle="`z-index:1;`"></LEchart>
</view>
<view class="relative mt-[68rpx] bg-[#F5FAFF] mx-[20rpx] px-[24rpx] pt-[58rpx] pb-[20rpx]">
<image
src="https://api.static.ycymedu.com/src/images/home/test-icon.png"
mode="scaleToFill"
class="w-[180rpx] h-[52rpx] absolute top-[-9rpx] left-[20rpx]"
/>
<view v-for="item in innerParsing">{{ item.split(',').join(':') }}</view>
</view>
</view>
</template>
<script lang="ts" setup>
import LEchart from '@/pages-evaluation-sub/uni_modules/lime-echart/components/l-echart/l-echart.vue'
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
const echart = ref(null)
const props = defineProps({
picData: {
type: Array,
default: () => [],
},
parsing: {
type: String,
default: '',
},
})
const innerParsing = ref([])
watch(
() => props.parsing,
(newV) => {
const _val = JSON.parse(newV) as {
tags: { title: string; items: { title: string; desc: string }[] }[]
}
_val.tags.forEach((item, index) => {
if (item.title === '策略偏好') {
return
}
innerParsing.value.push(...item.items.map((item) => `${item.title},${item.desc}`))
})
console.log(innerParsing.value)
},
)
//
watch(
() => props.picData,
(newData) => {
if (!newData || newData.length === 0) return
if (echart.value) {
echart.value.init(echarts, (chart) => {
const option = {
radar: {
center: ['50%', '50%'],
radius: '65%',
indicator: newData.map((item: any) => ({
name: `${item.type},${item.desc}`,
})),
shape: 'polygon',
splitNumber: 4,
axisName: {
color: '#333',
fontSize: 12,
formatter: (value: string) => {
//
const maxLength = 4
const result = []
let _val = value.split(',')
for (let i = 0; i < _val[0].length; i += maxLength) {
result.push(value.slice(i, i + maxLength))
}
result.push(_val[1])
return result.join('\n')
},
},
splitArea: {
areaStyle: {
color: ['rgba(255,255,255,0.3)'],
},
},
axisLine: {
lineStyle: {
color: '#E5E6EB',
},
},
splitLine: {
lineStyle: {
color: '#E5E6EB',
},
},
},
series: [
{
type: 'radar',
data: [
{
value: newData.map((item: any) => item.value),
name: '学习风格',
areaStyle: {
color: 'rgba(64, 158, 255, 0.3)',
},
lineStyle: {
color: '#409EFF',
},
itemStyle: {
color: '#409EFF',
},
label: {
show: true,
formatter: (params: any) => {
return params.value
},
color: '#1580FF',
fontSize: 12,
},
},
],
},
],
}
chart.setOption(option)
})
}
},
{ immediate: true },
)
onBeforeMount(() => {
if (echart.value) {
echart.value.dispose()
}
})
</script>
<style scoped>
.custom-background {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, #ffffff 6%);
}
</style>

View File

@ -16,21 +16,14 @@
bg-color="transparent"
>
<template #title>
<text class="text-[#1F2329] text-[36rpx] font-medium text-[#fff]">考试焦虑测评报告</text>
<text class="text-[#1F2329] text-[36rpx] font-medium text-[#fff]">Solomon学习风格报告</text>
</template>
</Navbar>
<view class="flex-1 overflow-auto pb-safe relative mx-[24rpx]">
<!-- 顶部卡片 -->
<view class="mt-[60rpx]">
<StatusCard
:score="score"
:rules="anxietyRules"
tip="结果只做参考,不能准确判断是否有焦虑症。"
:level="level"
:description="studyRecord.description"
:tagName="studyRecord.tagName"
/>
<learnStyleChart :pic-data="chartData" :parsing="parsing" />
</view>
<view class="mt-[30rpx]"></view>
</view>
@ -38,41 +31,12 @@
</template>
<script setup lang="ts">
import Navbar from '@/pages-evaluation-sub/components/navbar/Navbar.vue'
import StatusCard from '../components/StatusCard.vue'
import learnStyleChart from '../components/studyChart/LearnStyleChart.vue'
import { getCustomScaleExplains } from '@/service/index/api'
const pageType = ref(0)
const pageId = ref(0)
const anxietyRules = [
{
label: '正常范围',
range: '<50分',
color: '#00B281',
itemColorName: 'green',
},
{
label: '轻度焦虑',
range: '50-59分',
color: '#F8B801',
itemColorName: 'yellow',
},
{
label: '中度焦虑',
range: '60-69分',
color: '#F79C33',
itemColorName: 'origin',
},
{
label: '重度焦虑',
range: '≥70分',
color: '#F5663E',
itemColorName: 'red',
},
]
const score = ref(0)
const level = ref(0)
const handleBack = () => {
uni.navigateBack()
@ -83,20 +47,11 @@ const studyRecord = ref({
title: '',
result: '',
tagName: '',
suggestions: '',
})
const calcLevel = (val: string) => {
let _s = JSON.parse(val)
if (_s[0].Total >= 70) {
return 3
} else if (_s[0].Total >= 60) {
return 2
} else if (_s[0].Total >= 50) {
return 1
} else {
return 0
}
}
const chartData = ref([])
const parsing = ref('')
onLoad((options) => {
pageType.value = +options.type
@ -109,9 +64,10 @@ onLoad((options) => {
title: string
result: string
tagName: string
suggestions: string
}
level.value = calcLevel(studyRecord.value.result)
score.value = JSON.parse(studyRecord.value.result)[0].Total
chartData.value = JSON.parse(studyRecord.value.result)
parsing.value = studyRecord.value.suggestions
}
})
})

View File

@ -37,7 +37,10 @@
universityBaseInfo?.universityResult.level === 0 ? '本科' : '专科'
}}·{{ universityBaseInfo?.universityResult.nature }}
</text>
<text class="mt-[14rpx] text-[22rpx] font-normal text-[#303030] max-w-[400rpx] truncate">
<text
class="mt-[14rpx] text-[22rpx] font-normal text-[#303030] max-w-[400rpx] truncate"
@click="show = true"
>
{{ universityBaseInfo?.universityResult.features.slice(0, 4).join('/&nbsp;') }}
</text>
</view>
@ -97,6 +100,12 @@
<EnrollmentMark class="flex-1" :id="collegeId" v-show="currentTab === 3" />
<Situation class="flex-1" :id="collegeId" v-show="currentTab === 4" />
</view>
<ActionSheet v-model:show="show" title="院校特色" :show-close="true">
<view class="text-[24rpx] text-[#636363] px-[32rpx] pt-[32rpx]">
{{ universityBaseInfo?.universityResult.features.join('/&nbsp;') }}
</view>
</ActionSheet>
</view>
</template>
@ -110,6 +119,7 @@ import EnrollmentMark from './components/EnrollmentMark.vue'
import Situation from './components/Situation.vue'
import zTabs from '@/pages-sub/uni_modules/z-tabs/components/z-tabs/z-tabs.vue'
import Navbar from '@/pages-sub/components/navbar/Navbar.vue'
import ActionSheet from '@/pages-sub/components/ActionSheet.vue'
import {
getUniversityInfo,
@ -128,6 +138,8 @@ const universityBaseInfo = ref()
const collegeId = ref(0)
const show = ref(false)
const handlePreviewImage = (src: string, index: number) => {
uni.previewImage({
urls: universityBaseInfo.value?.universityResult.imglist,

View File

@ -70,10 +70,10 @@
<view class="flex items-center py-[16rpx] pl-[42rpx] w-[37%] border-right">
<text>{{ item.universityName }}</text>
</view>
<view class="flex items-center justify-center py-[16rpx] w-[35%] border-right">
<view class="flex items-center justify-center py-[16rpx] w-[35%] border-right h-full">
<text>{{ item.locationName }}</text>
</view>
<view class="flex items-center justify-center py-[16rpx] w-[28%]">
<view class="flex items-center justify-center py-[16rpx] w-[28%] h-full">
<text :style="{ color: item.type === 1 ? '#FF4242' : '#000' }">
{{ item.type === 1 ? '虚假大学' : '真实大学' }}
</text>

View File

@ -20,7 +20,9 @@
<text class="text-[32rpx] text-[#000] font-semibold truncate max-w-[400rpx]">
{{ major.major.replace(/(\r\n|\n|\r)/g, '') }}
</text>
<text class="text-[22rpx] text-[#1F2329] mt-[14rpx]">{{ major.remark }}</text>
<text class="text-[22rpx] text-[#1F2329] mt-[14rpx] line-clamp-2">
{{ major.remark }}
</text>
<view class="flex justify-between text-[22rpx] text-[#1F2329] mt-[14rpx]">
<view class="flex flex-col gap-[6rpx]">
<text>代码{{ major.majorCode }}</text>
@ -34,7 +36,7 @@
</view>
<view
:class="`w-[104rpx] h-[52rpx] rounded-[8rpx] text-[24rpx] custom-btn ${checkActive(major) ? 'active-btn' : ''}`"
:class="`w-[104rpx] min-w-[104rpx] h-[52rpx] rounded-[8rpx] text-[24rpx] custom-btn ${checkActive(major) ? 'active-btn' : ''}`"
@click.stop="handleClick(major)"
>
{{ checkActive(major) ? '已填报' : '填报' }}

View File

@ -9,7 +9,7 @@
<view class="flex items-stretch gap-[30rpx] justify-between">
<view class="flex flex-col gap-[29rpx] mt-[16rpx]">
<view class="text-[#333] text-[40rpx] font-semibold">{{ item.name }}</view>
<view class="text-[24rpx] text-[#999]">
<view class="text-[24rpx] text-[#999] line-clamp-3">
{{ item.summary }}
</view>
</view>

View File

@ -453,3 +453,15 @@ export const getBatchDynamicData = (params: { LocationCode: string; Course: stri
export const getCustomScaleExplains = (params: { CustomScaleId: number }) => {
return http.get('/api/busScale/GetCustomScaleExplains', params)
}
export const sendMessage = (params: { conversation_id: string; user: string; query: string }) => {
return http.post(
'https://api.coze.cn/open_api/v2/chat',
{
...params,
stream: true,
bot_id: '7456409430717480998',
},
{ haPrefix: true },
)
}

View File

@ -7,6 +7,7 @@ export const http = <T>(options: CustomRequestOptions) => {
if (options.query?.staticType === 'static') {
options.url = `${staticBaseUrl}${options.url}`
} else if (options.query?.haPrefix) {
console.log(options.query)
} else {
options.url = `${baseUrl}${options.url}`
}