伤心客 发表于 2024-9-9 09:52:10

MBTI 性格测试小程序实战

MBTI 性格测试应用介绍

参考项目:16Personalities(https://www.16personalities.com/ch)
https://img-blog.csdnimg.cn/img_convert/b52daf930ecf84abefbe11812467c02e.png
https://img-blog.csdnimg.cn/img_convert/43a85d458b1990e41770d706b6d88981.png
https://img-blog.csdnimg.cn/img_convert/4255743427f7003485bd3c8c5dbdcfd8.png
https://img-blog.csdnimg.cn/img_convert/2a6aa762c7f27d6aaae07e9a9544cd78.png

MBTI 实现方案介绍

核心构成:


[*]题目
[*]用户答案
[*]评分规则
题目布局

暂时使用JSON,便于明确,result代表题目对应的结果
[
    {
      "title": "你通常更喜欢",
      "options": [
            {
                "result": "I",
                "value": "独自工作",
                "key": "A"
            },
            {
                "result": "E",
                "value": "与他人合作",
                "key": "B"
            }
      ]
    }
]
优点:灵活、容易排序
相比于用选项作为key,布局更清楚,更易于明确和扩展,前后端都可声明类型;缺点是占用空间(可以进行预处理)
{
    "title": "题目",
    "a": "结果1",
    "b": "结果2",
    "c": "结果3"
}

用户答案布局

用户提交答案的时间,进需要通报一个数组,数组内是选项:["A","B"],按数组顺序匹配对应的题目。
优点:相较于直接将答案放到题目当中一起提交,数组不用再完备的通报题目布局,节省传输体积,进步性能。
["A","A","A","B","A","A","A","B","B","A"]

评分规则


MBTI 评分原理

迈尔斯-布里格斯性格分类法
   迈尔斯-布里格斯类型指标(英语:Myers-Briggs Type Indicator,简称MBTI,或译麦布二氏生理类型量表)是一种品德类型的评量工具,由荣格的类型理论发展而来,它表明人们天生在感知和决策的方式上存在差别生理偏好。其理论中最浅显的部分是四组相反的先天偏好:内向与外向(Introversion-Extraversion)、实感与直觉(Sensing-iNtuition)、思索与情感(Thinking-Feeling)、判定与感知(Judging-Perceiving),四项偏好可构成16种稳固的品德类型。该指标旨在让健康个体明确自己和彼此的认知与决策倾向,并不反映本领或风致。
MBTI是由两名美国人——凯瑟琳·库克·布里格斯和她的女儿伊莎贝尔·布里格斯·迈尔斯所建构,最早于1944年发表。
    MBTI将生理差异分类为4个对立的组合(或称“二分法”),一个人在每个组合中各拥有1个偏好:


[*]内向与外向(I/E)
[*]实感与直觉(S/N)
[*]思索与情感(T/F)
[*]判定与感知(J/P)
四个字母的组合依照E/I、S/N、T/F、J/P的顺序,由此产生了16种可能的字母组合,如ESTJ、ISFP、INFJ、ENTP等16种独特的类型。在MBTI的理论中,“类型”表达的讯息量不只是“4个偏好”,它代表了功能(S、N、T、F)、能量态度(E、I)以及对外界的态度(J、P)之间的一组复杂的动态关系。
https://img-blog.csdnimg.cn/img_convert/b993e6c102f27e7a13feab9a9346cc85.png
每道题目都是四个组合的此中之一设定,为了判定找个人属于组合里的哪个偏好。
如,为了判定是I人照旧E人(result字段):
[
    {
      "title": "你通常更喜欢",
      "options": [
            {
                "result": "I",
                "value": "独自工作",
                "key": "A"
            },
            {
                "result": "E",
                "value": "与他人合作",
                "key": "B"
            }
      ]
    }
]
按照这个思路,可以统计题目中所有的偏好,比如答完题目,统计一共选了10个I,2个E,很容易判定答题者是I人,同理可判定其他型品德。
所以出题的时间,给每个选项的答案对应设置一个属性。如:


[*]第一题A对应I,B对应E
[*]第二题A对应E,B对应I
[*]第三题A对应S,B对应N
[*]第四题A对应T,B对应F
[*]第五题A对应P,B对应J
如果用户选择了,两个I,一个S,一个T,一个P,很明显是ISTP品德。

评分结果计算原理


[*]创建一个评分结果集,预先创建包括MBTI的所有16中角色(品德)
https://img-blog.csdnimg.cn/img_convert/4d276c94da5b59dff5e8ef3c895f4b18.png
题目评分结果对应的json布局:
[
{
    "resultProp": [
      "I",
      "S",
      "T",
      "J"
    ],
    "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
    "resultPicture": "icon_url_istj",
    "resultName": "ISTJ(物流师)"
},
{
    "resultProp": [
      "I",
      "S",
      "F",
      "J"
    ],
    "resultDesc": "善良贴心,以同情心和责任为特点。",
    "resultPicture": "icon_url_isfj",
    "resultName": "ISFJ(守护者)"
}
]


[*]怎样计算结果
每个结果有一个resultProp字段,是一个元素不重复的数组(属性聚集),里面的内容和题目选项的result字段匹配。
[
    {
      "title": "你通常更喜欢",
      "options": [
            {
                "result": "I",
                "value": "独自工作",
                "key": "A"
            },
            {
                "result": "E",
                "value": "与他人合作",
                "key": "B"
            }
      ]
    }
]
如果用户第一题选了A,对应的属性如果是I,那么遍历这16种结果,然后判定角色对应的resultProp里面是否包含I,包含则对应角色就 +1 分,不包含不得分。
最终遍历完所有题目后,可以得出16种结果中,哪个角色得分最高,即最终的评分结果。

MBTI 小程序 Demo 数据


题目列表

每个选项包含了对应的结果,questions.json:
[
    {
      "options": [
            {
                "result": "I",
                "value": "独自工作",
                "key": "A"
            },
            {
                "result": "E",
                "value": "与他人合作",
                "key": "B"
            }
      ],
      "title": "你通常更喜欢"
    },
    {
      "options": [
            {
                "result": "J",
                "value": "喜欢有明确的计划",
                "key": "A"
            },
            {
                "result": "P",
                "value": "更愿意随机应变",
                "key": "B"
            }
      ],
      "title": "当安排活动时"
    },
    {
      "options": [
            {
                "result": "T",
                "value": "认为应该严格遵守",
                "key": "A"
            },
            {
                "result": "F",
                "value": "认为应灵活运用",
                "key": "B"
            }
      ],
      "title": "你如何看待规则"
    },
    {
      "options": [
            {
                "result": "E",
                "value": "经常是说话的人",
                "key": "A"
            },
            {
                "result": "I",
                "value": "更倾向于倾听",
                "key": "B"
            }
      ],
      "title": "在社交场合中"
    },
    {
      "options": [
            {
                "result": "J",
                "value": "先研究再行动",
                "key": "A"
            },
            {
                "result": "P",
                "value": "边做边学习",
                "key": "B"
            }
      ],
      "title": "面对新的挑战"
    },
    {
      "options": [
            {
                "result": "S",
                "value": "注重细节和事实",
                "key": "A"
            },
            {
                "result": "N",
                "value": "注重概念和想象",
                "key": "B"
            }
      ],
      "title": "在日常生活中"
    },
    {
      "options": [
            {
                "result": "T",
                "value": "更多基于逻辑分析",
                "key": "A"
            },
            {
                "result": "F",
                "value": "更多基于个人情感",
                "key": "B"
            }
      ],
      "title": "做决定时"
    },
    {
      "options": [
            {
                "result": "S",
                "value": "喜欢有结构和常规",
                "key": "A"
            },
            {
                "result": "N",
                "value": "喜欢自由和灵活性",
                "key": "B"
            }
      ],
      "title": "对于日常安排"
    },
    {
      "options": [
            {
                "result": "P",
                "value": "首先考虑可能性",
                "key": "A"
            },
            {
                "result": "J",
                "value": "首先考虑后果",
                "key": "B"
            }
      ],
      "title": "当遇到问题时"
    },
    {
      "options": [
            {
                "result": "T",
                "value": "时间是一种宝贵的资源",
                "key": "A"
            },
            {
                "result": "F",
                "value": "时间是相对灵活的概念",
                "key": "B"
            }
      ],
      "title": "你如何看待时间"
    }
]

题目结果表

question_results.json
[
{
    "resultProp": [
      "I",
      "S",
      "T",
      "J"
    ],
    "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
    "resultPicture": "icon_url_istj",
    "resultName": "ISTJ(物流师)"
},
{
    "resultProp": [
      "I",
      "S",
      "F",
      "J"
    ],
    "resultDesc": "善良贴心,以同情心和责任为特点。",
    "resultPicture": "icon_url_isfj",
    "resultName": "ISFJ(守护者)"
},
{
    "resultProp": [
      "I",
      "N",
      "F",
      "J"
    ],
    "resultDesc": "理想主义者,有着深刻的洞察力,善于理解他人。",
    "resultPicture": "icon_url_infj",
    "resultName": "INFJ(占有者)"
},
{
    "resultProp": [
      "I",
      "N",
      "T",
      "J"
    ],
    "resultDesc": "独立思考者,善于规划和实现目标,理性而果断。",
    "resultPicture": "icon_url_intj",
    "resultName": "INTJ(设计师)"
},
{
    "resultProp": [
      "I",
      "S",
      "T",
      "P"
    ],
    "resultDesc": "冷静自持,善于解决问题,擅长实践技能。",
    "resultPicture": "icon_url_istp",
    "resultName": "ISTP(运动员)"
},
{
    "resultProp": [
      "I",
      "S",
      "F",
      "P"
    ],
    "resultDesc": "具有艺术感和敏感性,珍视个人空间和自由。",
    "resultPicture": "icon_url_isfp",
    "resultName": "ISFP(艺术家)"
},
{
    "resultProp": [
      "I",
      "N",
      "F",
      "P"
    ],
    "resultDesc": "理想主义者,富有创造力,以同情心和理解他人著称。",
    "resultPicture": "icon_url_infp",
    "resultName": "INFP(治愈者)"
},
{
    "resultProp": [
      "I",
      "N",
      "T",
      "P"
    ],
    "resultDesc": "思维清晰,探索精神,独立思考且理性。",
    "resultPicture": "icon_url_intp",
    "resultName": "INTP(学者)"
},
{
    "resultProp": [
      "E",
      "S",
      "T",
      "P"
    ],
    "resultDesc": "敢于冒险,乐于冒险,思维敏捷,行动果断。",
    "resultPicture": "icon_url_estp",
    "resultName": "ESTP(拓荒者)"
},
{
    "resultProp": [
      "E",
      "S",
      "F",
      "P"
    ],
    "resultDesc": "热情开朗,善于社交,热爱生活,乐于助人。",
    "resultPicture": "icon_url_esfp",
    "resultName": "ESFP(表演者)"
},
{
    "resultProp": [
      "E",
      "N",
      "F",
      "P"
    ],
    "resultDesc": "富有想象力,充满热情,善于激发他人的活力和潜力。",
    "resultPicture": "icon_url_enfp",
    "resultName": "ENFP(倡导者)"
},
{
    "resultProp": [
      "E",
      "N",
      "T",
      "P"
    ],
    "resultDesc": "充满创造力,善于辩论,挑战传统,喜欢探索新领域。",
    "resultPicture": "icon_url_entp",
    "resultName": "ENTP(发明家)"
},
{
    "resultProp": [
      "E",
      "S",
      "T",
      "J"
    ],
    "resultDesc": "务实果断,善于组织和管理,重视效率和目标。",
    "resultPicture": "icon_url_estj",
    "resultName": "ESTJ(主管)"
},
{
    "resultProp": [
      "E",
      "S",
      "F",
      "J"
    ],
    "resultDesc": "友善热心,以协调、耐心和关怀为特点,善于团队合作。",
    "resultPicture": "icon_url_esfj",
    "resultName": "ESFJ(尽责者)"
},
{
    "resultProp": [
      "E",
      "N",
      "F",
      "J"
    ],
    "resultDesc": "热情关爱,善于帮助他人,具有领导力和社交能力。",
    "resultPicture": "icon_url_enfj",
    "resultName": "ENFJ(教导着)"
},
{
    "resultProp": [
      "E",
      "N",
      "T",
      "J"
    ],
    "resultDesc": "果断自信,具有领导才能,善于规划和执行目标。",
    "resultPicture": "icon_url_entj",
    "resultName": "ENTJ(统帅)"
}
]

其他资源

主页背景图片等资源,可以借助AI生成

Taro跨端小程序入门


为什么开发小程序?



[*]基于微信生态,易于流传分享
[*]不用下载,直接打开使用即可
小程序开发和网页开发基本一致,都具有在线热更新、调试、版本兼容、打包上线。
小程序开发的真正痛点:可能有一些权限或者功能必须要企业号。

技能选型



[*]Taro
[*]Taro UI组件库
[*]React
[*]TypeScript
Taro官方文档:https://taro-docs.jd.com/docs/
做项目建议选用一个组件库,提升开发效率!
推荐使用与Taro官方框架兼容的组件库,否则容易出现跨端后样式丢失的题目。


[*]taro-ui:https://taro-ui.jd.com/#/(推荐)
[*]nut-ui
开发准备

微信开发者工具:https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

入门指南


项目初始化

官方文档:https://taro-docs.jd.com/docs/GETTING-STARTED
Taro版本:这里选择3.x
node.js版本:>=16.20(我用的18.18.0)
npm版本:>=8(我用的9.8.1)
1)安装
# 使用 npm 安装 CLI
$ npm install -g @tarojs/cli

# OR 使用 yarn 安装 CLI
$ yarn global add @tarojs/cli

# OR 安装了 cnpm,使用 cnpm 安装 CLI
$ cnpm install -g @tarojs/cli
这样会默认安装最新的版本,我们可以指定版本安装(如果安装了最新版本,直接再次安装指定版本即可):
npm install -g @tarojs/cli@3.6.28
使用taro -v检察版本信息:
https://img-blog.csdnimg.cn/img_convert/f9053937bc055d04f290d79d142de153.png
2)新建目录question-craft,初始化git项目
https://img-blog.csdnimg.cn/img_convert/83430e6fd6916397046bdf045943f0cd.png
3)执行下令,初始化小程序项目
taro init mbti-test-mini
https://img-blog.csdnimg.cn/img_convert/4c9408ffa3589ba6f2aca17b4e6e4378.png

项目运行

使用WebStorm打开项目,进入终端执行npm install,发现依赖下载失败:
PS E:\E\IDEAWorkSpace\question-craft\mbti-test-mini> npm install
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!                                          
npm ERR! While resolving: mbti-test-mini@1.0.0   
npm ERR! Found: react@18.2.0                     
npm ERR! node_modules/react
npm ERR!   react@"^18.0.0" from the root project
npm ERR!   peer react@">=16.13.0" from taro-ui@3.3.0
npm ERR!   node_modules/taro-ui
npm ERR!   taro-ui@"^3.2.1" from the root project
npm ERR!   2 more (@tarojs/taro-rn, react-native)
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^18.3.1" from react-dom@18.3.1
npm ERR! node_modules/react-dom
npm ERR!   react-dom@"^18.0.0" from the root project
npm ERR!   peer react-dom@">=16.13.0" from taro-ui@3.3.0
npm ERR!   node_modules/taro-ui
npm ERR!   taro-ui@"^3.2.1" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR!
npm ERR! For a full report see:
npm ERR! C:\Users\ada\AppData\Local\npm-cache\_logs\2024-08-10T03_43_08_487Z-eresolve-report.txt

npm ERR! A complete log of this run can be found in: C:\Users\ada\AppData\Local\npm-cache\_logs\2024-08-10T03_43_08_487Z-debug-0.log
PS E:\E\IDEAWorkSpace\question-craft\mbti-test-mini>
可以查阅资料,或者问问AI,执行npm install --force,强制安装成功(不要使用邪术上网)
执行npm run dev:weapp,或者打开package.json文件,点击对应脚本运行:
https://img-blog.csdnimg.cn/img_convert/0e0c49cd41b420def528960800f9dcd5.png
dev:weapp:开发测试使用,即时编译,自动更新
build:weapp:打包上线使用,体积更小
运行之后使用微信开发者工具打开项目:
https://img-blog.csdnimg.cn/img_convert/c6b0c231ca3de133f8650ed8ea0682c3.png
https://img-blog.csdnimg.cn/img_convert/80a48eb823111e353af2150a3eeaaa2c.png

设置开发规范



[*]eslint:代码规范
[*]prettier:代码美化(格式)
https://img-blog.csdnimg.cn/img_convert/f5860c1d494dc6631b97ad878302b31e.png
https://img-blog.csdnimg.cn/img_convert/d644e0b0ed27f242bbe30cf9f8ae00e4.png
eslint补充设置,关闭双引号校验:
{
"extends": ["taro/react"],
"rules": {
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off",
    "jsx-quotes": "off"
}
}
https://img-blog.csdnimg.cn/img_convert/3a25173d49a16860ca48be4d40669656.png

测试组件引入

官网文档:https://taro-ui.jd.com/#/docs/quickstart
在src/app.ts中全局引入taro-ui:
import 'taro-ui/dist/style/index.scss' // 引入组件样式 - 方式一
随便找个组件复制进项目进行测试,检察是否成功引入。

开发示例页面


[*]在全局设置文件src/app.config.ts,新增页面路由
[*]复制已有页面,创建新页面
[*]根据自己的需要,复制组件,拼出完备页面
[*]按照需求,定制开发
[*]页面跳转
MBTI 跨端小程序实战


全局规范和设置

依照函数式组件写法:
export default () => {
return (
    <View className="index">
      <Text>Hello world!</Text>
    </View>
);
};
修改应用标题src/app.config.ts:
export default defineAppConfig({
pages: [
    'pages/index/index'
],
window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'MBTI 性格测试',
    navigationBarTextStyle: 'black'
}
})
再将src/pages/index/index.config.ts下的标题注释掉:
相当于每个页面可以有自己的标题,在对应页面的.config.ts中声明即可,这里我们直接注释掉
export default definePageConfig({
// navigationBarTitleText: '首页'
})
https://img-blog.csdnimg.cn/img_convert/2a91f36d3c40b4f24ca4b7b7c0a66006.png

主页


结果图

https://img-blog.csdnimg.cn/img_convert/b2ec9787d4b322f7281924d91eb8d8b9.png

主页src/pages/index/index.tsx

import { View, Image } from "@tarojs/components";
import { AtButton } from "taro-ui";
import headerBg from "../../assets/headerBg.png";
import "./index.scss";
import GlobalFooter from "../../components/GlobalFooter";

/**
* 主页
*/
export default () => {
return (
    <View className="indexPage">
      <View className="at-article__h1 title">MBTI 性格测试</View>
      <View className="at-article__h2 subTitle">只需2分钟,就能“惊人般准确”地描述出你是谁,以及你为何以这样的方式行事。</View>
      <AtButton type="primary" circle className="enterBtn">
      开始测试
      </AtButton>
      <Image className="headerBg" src={headerBg} />
      <GlobalFooter />
    </View>
);
};

主页样式src/pages/index/index.scss

.indexPage {
background: #5DBFD8;

.title {
    color: white;
    padding-top: 48px;
    text-align: center;
}

.subTitle {
    color: white;
    margin-top: 48px;
}

.enterBtn {
    margin-top: 150px;
    width: 60vw;
}

.headerBg {
    margin-top: 100px;
    height: 300px;
}
}

全局底部栏组件src/components/GlobalFooter/index.tsx

import { View } from "@tarojs/components";
import "./index.scss";

/**
* 全局底部栏组件
*/
export default () => {
return <View className="globalFooter">作者:十六</View>;
};

全局底部栏组件样式src/components/GlobalFooter/index.scss

.globalFooter {
position: fixed;
bottom: 16px;
left: 0;
right: 0;
text-align: center;
}

全局统一样式src/app.scss

.at-button--primary {
background-color: dodgerblue;
boilder-color: dodgerblue;
}

答题页面


结果图

https://img-blog.csdnimg.cn/img_convert/9781d254a1acdd3fdb1a98d06b53b8dc.png
开发步骤:

[*]先写组件HTML(Radio组件)
[*]再调解样式
[*]最后写逻辑(上一题、下一题)
页面src/pages/doQuestion/index.tsx

import { View, Image } from "@tarojs/components";
import { AtButton } from "taro-ui";
import headerBg from "../../assets/headerBg.png";
import "./index.scss";
import questionResults from "../../data/question_results.json";
import GlobalFooter from "../../components/GlobalFooter";
import Taro from "@tarojs/taro";

/**
* 测试结果页面
*/
export default () => {
const result = questionResults;

return (
    <View className="resultPage">
      <View className="at-article__h1 title">{result.resultName}</View>
      <View className="at-article__h2 subTitle">{result.resultDesc}</View>
      <AtButton type="primary" circle className="enterBtn" onClick={() => {
      // 关闭所有页面,打开到应用内的某个页面
      Taro.reLaunch({
          url: '/pages/index/index'
      })
      }}
      >
      返回主页
      </AtButton>
      <Image className="headerBg" src={headerBg} />
      <GlobalFooter />
    </View>
);
};

样式src/pages/doQuestion/index.scss

.doQuestionPage {
.title {
    margin-bottom: 48px;
}

.options-wrapper {
    margin-bottom: 48px;
}

.controlBtn {
    margin: 24px 48px;
}
}

结果页面


结果图

https://img-blog.csdnimg.cn/img_convert/130672934c89512faa27232e214c26cc.png

页面src/pages/result/index.tsx

使用Taro.reLaunch关闭所有页面,打开到应用内的某个页面,防止页面无限叠加
import { View, Image } from "@tarojs/components";
import { AtButton } from "taro-ui";
import headerBg from "../../assets/headerBg.png";
import "./index.scss";
import questionResults from "../../data/question_results.json";
import GlobalFooter from "../../components/GlobalFooter";
import Taro from "@tarojs/taro";

/**
* 测试结果页面
*/
export default () => {
const result = questionResults;

return (
    <View className="resultPage">
      <View className="at-article__h1 title">{result.resultName}</View>
      <View className="at-article__h2 subTitle">{result.resultDesc}</View>
      <AtButton type="primary" circle className="enterBtn" onClick={() => {
      // 关闭所有页面,打开到应用内的某个页面
      Taro.reLaunch({
          url: '/pages/index/index'
      })
      }}
      >
      返回主页
      </AtButton>
      <Image className="headerBg" src={headerBg} />
      <GlobalFooter />
    </View>
);
};

样式src/pages/result/index.scss

.resultPage {
background: #5DBFD8;

.title {
    color: white;
    padding-top: 48px;
    text-align: center;
}

.subTitle {
    color: white;
    margin-top: 48px;
}

.enterBtn {
    margin-top: 150px;
    width: 60vw;
}

.headerBg {
    margin-top: 100px;
    height: 300px;
}
}

页面设置src/pages/result/index.config.ts

设置页面标题
export default definePageConfig({
navigationBarTitleText: '查看结果', // 设置页面标题
})

路由设置src/app.config.ts

export default defineAppConfig({
pages: [
    'pages/index/index',
    'pages/doQuestion/index',
    'pages/result/index'
],
window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'MBTI 性格测试',
    navigationBarTextStyle: 'black'
}
})

评分模块


CodeGeex生成对应评分算法代码

AI Prompt
请根据我下面的题目评分算法原理,帮我用 js 获取到得分最高的题目评分结果,要求算法清楚易懂,性能要求高,多补充一些注释。
用户提交的答案 answerList: [“A”]
题目列表 questions:
[
    {
      "title": "你通常更喜欢",
      "options": [
            {
                "result": "I",
                "value": "独自工作",
                "key": "A"
            },
            {
                "result": "E",
                "value": "与他人合作",
                "key": "B"
            }
      ]
    }
]
题目评分结果 question_results:
[
{
    "resultProp": [
      "I",
      "S",
      "T",
      "J"
    ],
    "resultDesc": "忠诚可靠,被公认为务实,注重细节。",
    "resultPicture": "icon_url_istj",
    "resultName": "ISTJ(物流师)"
},
]
评分原理:答案数组的每个元素和题目数组中每个元素的某个选项的key对应,从而获取到对应的 result 属性;题目评分结果的 resultProp 聚会合如果包含该属性,就+1分,最后计算哪个评分结果(question_result)分数最高。
AI 结果
这个函数起首遍历题目列表和答案列表,统计每个选项的计数。然后遍历评分结果列表,计算每个评分结果的分数,最后返回最高分数和最高分数对应的评分结果。
function getMaxScore(answerList, questions, question_results) {
// 初始化一个对象,用于存储每个选项的计数
const optionCount = {};

// 遍历题目列表
for (const question of questions) {
    // 遍历答案列表
    for (const answer of answerList) {
      // 遍历题目中的选项
      for (const option of question.options) {
      // 如果答案和选项的key匹配
      if (option.key === answer) {
          // 获取选项的result属性
          const result = option.result;

          // 如果result属性不在optionCount中,初始化为0
          if (!optionCount) {
            optionCount = 0;
          }

          // 在optionCount中增加计数
          optionCount++;
      }
      }
    }
}

// 初始化最高分数和最高分数对应的评分结果
let maxScore = 0;
let maxScoreResult = null;

// 遍历评分结果列表
for (const result of question_results) {
    // 计算当前评分结果的分数
    const score = result.resultProp.reduce((count, prop) => {
      return count + (optionCount || 0);
    }, 0);

    // 如果分数高于当前最高分数,更新最高分数和最高分数对应的评分结果
    if (score > maxScore) {
      maxScore = score;
      maxScoreResult = result;
    }
}

// 返回最高分数和最高分数对应的评分结果
return maxScoreResult;
}

const answerList = ["A"];
const questions = [
{
    title: "你通常更喜欢",
    options: [
      {
      result: "I",
      value: "独自工作",
      key: "A",
      },
      {
      result: "E",
      value: "与他人合作",
      key: "B",
      },
    ],
},
];
const question_results = [
{
    resultProp: ["I", "S", "T", "J"],
    resultDesc: "忠诚可靠,被公认为务实,注重细节。",
    resultPicture: "icon_url_istj",
    resultName: "ISTJ(物流师)",
},
];

console.log(getMaxScore(answerList, questions, question_results));
留意:AI结果不稳固,可以连续优化

代码整合

修改代码并新建src/utis/bitUtils.ts
/**
* 获取最佳题目评分结果
* @param answerList
* @param questions
* @param question_results
*/
function getBestQuestionResult(answerList, questions, question_results) {
// 初始化一个对象,用于存储每个选项的计数
const optionCount = {};

// 遍历题目列表
for (const question of questions) {
    // 遍历答案列表
    for (const answer of answerList) {
      // 遍历题目中的选项
      for (const option of question.options) {
      // 如果答案和选项的key匹配
      if (option.key === answer) {
          // 获取选项的result属性
          const result = option.result;

          // 如果result属性不在optionCount中,初始化为0
          if (!optionCount) {
            optionCount = 0;
          }

          // 在optionCount中增加计数
          optionCount++;
      }
      }
    }
}

// 初始化最高分数和最高分数对应的评分结果
let maxScore = 0;
let maxScoreResult = question_results;

// 遍历评分结果列表
for (const result of question_results) {
    // 计算当前评分结果的分数
    const score = result.resultProp.reduce((count, prop) => {
      return count + (optionCount || 0);
    }, 0);

    // 如果分数高于当前最高分数,更新最高分数和最高分数对应的评分结果
    if (score > maxScore) {
      maxScore = score;
      maxScoreResult = result;
    }
}

// 返回最高分数和最高分数对应的评分结果
return maxScoreResult;
}

const answerList = ["B","B","B","A"];
const questions = [
{
    title: "你通常更喜欢",
    options: [
      {
      result: "I",
      value: "独自工作",
      key: "A",
      },
      {
      result: "E",
      value: "与他人合作",
      key: "B",
      },
    ],
},
{
    options: [
      {
      result: "S",
      value: "喜欢有结构和常规",
      key: "A",
      },
      {
      result: "N",
      value: "喜欢自由和灵活性",
      key: "B",
      },
    ],
    title: "对于日常安排",
},
{
    options: [
      {
      result: "P",
      value: "首先考虑可能性",
      key: "A",
      },
      {
      result: "J",
      value: "首先考虑后果",
      key: "B",
      },
    ],
    title: "当遇到问题时",
},
{
    options: [
      {
      result: "T",
      value: "时间是一种宝贵的资源",
      key: "A",
      },
      {
      result: "F",
      value: "时间是相对灵活的概念",
      key: "B",
      },
    ],
    title: "你如何看待时间",
},
];
const question_results = [
{
    resultProp: ["I", "S", "T", "J"],
    resultDesc: "忠诚可靠,被公认为务实,注重细节。",
    resultPicture: "icon_url_istj",
    resultName: "ISTJ(物流师)",
},
{
    resultProp: ["I", "S", "F", "J"],
    resultDesc: "善良贴心,以同情心和责任为特点。",
    resultPicture: "icon_url_isfj",
    resultName: "ISFJ(守护者)",
},
];

console.log(getBestQuestionResult(answerList, questions, question_results));

可以修改测试用例,进入\src\utis目录终端进行测试node .\bizUtils.ts
https://img-blog.csdnimg.cn/img_convert/2fb332387d9310b707dd2924749e8e09.png
导出函数,以便外部引用(src/utis/bitUtils.ts):
export function getBestQuestionResult(answerList, questions, question_results) {

页面间数据通报

需求:题目结果页面需要得到做题页面用户选择的答案列表,才能进行评分。


[*]方法 1:url params

[*] https://taro-docs.jd.com/docs/apis/route/navigateTo
[*]比如:result?answerList=

[*]方法 2:全局状态

[*] https://taro-docs.jd.com/docs/context#contextprovider

[*]方法 3:本地数据存储(推荐,较为简单)

[*] https://taro-docs.jd.com/docs/apis/storage/setStorageSync

做题页面通报数据src/pages/doQuestion/index.tsx

      {current == questions.length && (
      <AtButton
          type="primary"
          circle
          className="controlBtn"
          disabled={!currentAnswer}
          onClick={() => {
            // 传递答案列表
            Taro.setStorage({
            key:"answerList",
            data:answerList
            });
            // 跳转结果页面
            Taro.navigateTo({
            url: "/pages/result/index",
            });
          }}
      >
          查看结果
      </AtButton>
      )}

结果页面使用数据src/pages/result/index.tsx

// 获取从答题页面传递过来的答案列表
const answerList = Taro.getStorageSync("answerList");
if (!answerList || answerList.length < 0) {
    Taro.showToast({
      title: "答案为空!",
      icon: "error",
      duration: 2000
    });
}
// 根据答案列表获取对应的测试结果
const result = getBestQuestionResult(answerList, questions, questionResults);

MBTI 性格测试小程序测试

https://img-blog.csdnimg.cn/img_convert/253195e529e09ac0178e2bf1c08dcc8b.png

留意事项

出现题目在清除代码题目的环境下:


[*]清算开发工具缓存
[*]重启项目
[*]重启微信开发者工具
扩展



[*] 美满MBTI性格测试小程序(参考http://sssch.net/ArticleDetail.aspx?ArticleID=13188130318)
[*] 做题进度条
[*] 优化结果样式(联合每种性格和用户性别展示差别的图片)
[*] 将数据放进后端管理
进度条

在答题页面src/pages/doQuestion/index.tsx添加taro-ui的进度条组件,使用用户的答题数除以题目数计算即可:
      <AtProgress
      className="progress"
      // 进度条的百分比
      percent={(answerList.length / questions.length) * 100}
      // 进度条的宽度
      strokeWidth={10}
      // 进度条的颜色
      activeColor="#1aad19"
      />
https://img-blog.csdnimg.cn/img_convert/edfa989b24cd122f9e4121847717e6c1.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: MBTI 性格测试小程序实战