2026山东大学软件学院项目实训个人blog(三)
2026/5/7 23:29:38 网站建设 项目流程

2026山东大学软件学院项目实训个人blog(三)

目录

  • 一、写在前面
  • 二、页面设计:如何让用户愿意填完一份长问卷
    • 2.1 核心痛点分析
    • 2.2 分组渐进式答题
    • 2.3 进度可视化
    • 2.4 自动保存——解决“填了一半不小心关了”的痛点
    • 2.5 结果可视化
    • 2.6 美观性细节
  • 三、核心技术代码解析
    • 3.1 API接口封装
    • 3.2 状态管理核心逻辑
  • 四、前后端联调经验
    • 4.1 接口数据格式约定
    • 4.2 跨域配置
    • 4.3 踩坑与解决
  • 五、总结

一、写在前面

这次做的是中医智能体的体质评估功能,核心任务是让用户通过填写问卷,系统自动判断其属于哪种中医体质类型(平和质、气虚质、阳虚质等九种)。接手这个需求时,我面临一个问题:九种体质、六十多道题目,怎么让用户愿意填完而不是中途放弃?

下面我从页面设计、状态管理、前后端联调三个方面分享一下我的做法和思考。

二、页面设计:如何让用户愿意填完一份长问卷

2.1 核心痛点分析

中医体质问卷有个天然劣势:题目多。标准版本有60道题,如果全部堆在一个页面上,用户大概率看一眼就关掉了。所以我的核心设计目标是——把用户的认知负担降到最低。

2.2 分组渐进式答题

我的方案是按九种体质将题目分组展示,而不是一次性全抛出来。用户一次只面对一个体质组的题目(约6-8道),心理压力小很多。

左侧做一个体质导航栏,列出全部九种体质,右侧展示当前选中体质的题目。每组旁边显示完成进度(如“5/8”),用户能有很强的掌控感,也可以自由跳转到任何一组。

2.3 进度可视化

顶部做了整体进度条,每完成一组就往前走一步。底部操作栏放“上一组”“下一组”按钮,逻辑简单直接,用户不需要思考下一步该干嘛。这种正反馈会推动他继续往下做。

2.4 自动保存——解决“填了一半不小心关了”的痛点

这是我作为用户时最痛的点。我做了答案自动暂存到localStorage,每选一道题就存一次。哪怕用户刷新页面或不小心关掉浏览器,下次进来答案还在,直接接着填就行。

2.5 结果可视化

评估完成后,结果页用雷达图展示九种体质的得分对比。主要体质会单独用大卡片展示,配上体质图标、详细解读和调理建议。如果有历史记录,还会展示与前一次的对比变化曲线。

2.6 美观性细节

配色用了中式美学:墨绿、檀棕、米白,温润内敛。卡片用了16px圆角和柔和阴影,选项按钮hover时有轻微放大效果,这些细节让页面用起来更舒服。

三、核心技术代码解析

3.1 API接口封装

// frontend/src/api/constitution.jsconstconstitutionApi={// 获取问卷题目getQuestions(){returnrequest.get('/constitution/questions')},// 提交评估evaluate(data){returnrequest.post('/constitution/evaluate',data)},// 获取历史记录getHistory(profileId,limit=10){returnrequest.get(`/constitution/profiles/${profileId}/history`,{params:{limit}})},// 获取变化趋势getTrend(profileId){returnrequest.get(`/constitution/profiles/${profileId}/trend`)},// 对比两次评估compare(recordId1,recordId2){returnrequest.post('/constitution/compare',{record_id_1:recordId1,record_id_2:recordId2})}}

设计思路:把所有接口调用集中管理,每个接口语义清晰。组件里只关心调用哪个接口、传什么参数,不关心请求细节。这样后端接口改了只需要改这一个文件。

3.2 状态管理核心逻辑

// frontend/src/store/constitutionStore.jsexportconstuseConstitutionStore=defineStore('constitution',()=>{// ===== 状态 =====constquestions=ref([])// 所有题目constconstitutionTypes=ref([])// 体质类型定义constcurrentEvaluation=ref(null)// 当前评估结果consthistoryList=ref([])// 历史记录// ===== 计算属性:按体质分组 =====constgroupedQuestions=computed(()=>{constgroups={}questions.value.forEach(q=>{constcode=q.constitution_codeif(!groups[code])groups[code]=[]groups[code].push(q)})returngroups})// ===== 加载题目(带缓存)=====constloadQuestions=async()=>{if(questions.value.length>0)return// 已加载则跳过constres=awaitconstitutionApi.getQuestions()questions.value=res.data.questions||[]constitutionTypes.value=res.data.constitution_types||[]}// ===== 提交评估 =====constsubmitEvaluation=async(profileId,basicInfo,answers,freeText='')=>{constres=awaitconstitutionApi.evaluate({profile_id:profileId,basic_info:basicInfo,answers:answers,free_text:freeText})currentEvaluation.value=res.data.datareturncurrentEvaluation.value}// ===== 自动保存到本地 =====constsaveAnswersToLocalStorage=(profileId,answers)=>{localStorage.setItem(`constitution_answers_${profileId}`,JSON.stringify(answers))}// ===== 辅助方法 =====constgetConstitutionName=(code)=>{returnconstitutionTypes.value.find(c=>c.code===code)?.name||code}})

设计思路:

  • groupedQuestions是核心计算属性,把后端返回的扁平题目列表按体质分组,组件直接循环这个分组就能渲染,不用自己处理分组逻辑

  • loadQuestions加了缓存判断,避免组件重复加载浪费请求

  • 自动保存用profileId区分不同用户,页面刷新后能精准恢复自己的答案

四、前后端联调经验

4.1 接口数据格式约定

开始开发前我和后端对齐了格式:

请求体(提交评估):

{"profile_id":123,"basic_info":{"age":30,"gender":"male"},"answers":{"1":3,"2":4},"free_text":"平时容易疲劳"}

响应体(评估结果):

{"code":0,"data":{"primary_constitutions":["qixu","yangxu"],"scores":{"pinghe":65,"qixu":82},"recommendations":{"diet":[],"exercise":[]}}}

4.2 跨域配置

// vite.config.jsexportdefault{server:{proxy:{'/api':{target:'http://localhost:8080',changeOrigin:true}}}}

4.3 踩坑与解决

问题解决方案
历史记录越积越多加limit参数,只取最近10条
60道题一次性渲染卡顿分组渲染,一次只渲染当前体质组
重复调用loadQuestions加缓存判断,已加载则跳过
用户意外关闭页面丢失答案localStorage自动暂存

五、总结

这个体质评估模块的核心设计思路:

  • 页面设计:分组渐进式答题 + 自动保存 + 进度可视化,核心是降低用户认知负担

  • 状态管理:用computed处理分组逻辑,用缓存避免重复请求

  • 接口对接:API层集中管理,格式提前约定,代理解决跨域

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询