背景
我将为您提供一个完整的基于Uniapp+UView前端和FastAdmin后端的性格测试小程序方案。
一、数据库设计 (FastAdmin)
1. 创建数据库表
在FastAdmin中创建以下两张表:
-- 测试题目表
CREATE TABLE `fa_test_questions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`question_text` text NOT NULL COMMENT '问题内容',
`option_a` varchar(255) NOT NULL COMMENT '选项A',
`option_b` varchar(255) NOT NULL COMMENT '选项B',
`trait_a` char(1) DEFAULT '' COMMENT 'A选项对应特质',
`trait_b` char(1) DEFAULT '' COMMENT 'B选项对应特质',
`sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
`createtime` int(11) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试题目表';
-- 测试结果表
CREATE TABLE `fa_test_results` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT '0' COMMENT '用户ID',
`user_name` varchar(100) DEFAULT '' COMMENT '用户姓名',
`answers` varchar(100) NOT NULL COMMENT '用户答案',
`score_e` tinyint(4) NOT NULL DEFAULT '0' COMMENT '外向性得分',
`score_a` tinyint(4) NOT NULL DEFAULT '0' COMMENT '宜人性得分',
`score_c` tinyint(4) NOT NULL DEFAULT '0' COMMENT '尽责性得分',
`score_n` tinyint(4) NOT NULL DEFAULT '0' COMMENT '情绪稳定性得分',
`score_o` tinyint(4) NOT NULL DEFAULT '0' COMMENT '开放性得分',
`personality_type` varchar(50) NOT NULL DEFAULT '' COMMENT '性格类型',
`description` text NOT NULL COMMENT '性格描述',
`createtime` int(11) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试结果表';
2. 插入测试题目数据
INSERT INTO `fa_test_questions` (`question_text`, `option_a`, `option_b`, `trait_a`, `trait_b`, `sort_order`, `createtime`, `updatetime`) VALUES
('我喜欢尝试新鲜事物,充满好奇心。', 'A. 是的', 'B. 不是', 'O', '', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('在聚会中,我通常是活跃和引人注目的。', 'A. 是的', 'B. 不是', 'E', '', 2, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我倾向于直接相信他人是诚实和善良的。', 'A. 是的', 'B. 不是', 'A', '', 3, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我的物品和工作文件总是整理得井井有条。', 'A. 是的', 'B. 不是', 'C', '', 4, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我很容易感到焦虑或压力。', 'A. 是的', 'B. 不是', '', 'N', 5, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我对艺术、音乐和文学有浓厚的兴趣。', 'A. 是的', 'B. 不是', 'O', '', 6, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我喜欢成为大家关注的焦点。', 'A. 是的', 'B. 不是', 'E', '', 7, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我乐于助人,并尽量满足他人的请求。', 'A. 是的', 'B. 不是', 'A', '', 8, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我做事有明确的计划和 deadline,并严格执行。', 'A. 是的', 'B. 不是', 'C', '', 9, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()),
('我经常沉浸在自我的情绪和想法中。', 'A. 是的', 'B. 不是', '', 'N', 10, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
二、FastAdmin后端API
1. 创建API控制器
在FastAdmin中创建app/api/controller/Test.php
:
<?php
namespace app\api\controller;
use app\common\controller\Api;
use think\Db;
/**
* 性格测试API
*/
class Test extends Api
{
protected $noNeedLogin = ['*'];
protected $noNeedRight = ['*'];
/**
* 获取测试题目
*/
public function getQuestions()
{
$questions = Db::name('test_questions')
->field('id, question_text, option_a, option_b')
->order('sort_order ASC')
->select();
$this->success('获取成功', $questions);
}
/**
* 提交测试答案
*/
public function submitTest()
{
$userName = $this->request->post('user_name');
$answers = $this->request->post('answers/a');
if (empty($userName)) {
$this->error('请输入姓名');
}
if (count($answers) !== 10) {
$this->error('请完成所有题目');
}
// 获取题目和计分规则
$questions = Db::name('test_questions')
->field('id, trait_a, trait_b')
->order('sort_order ASC')
->select();
// 计算得分
$scores = [
'E' => 0, // 外向性
'A' => 0, // 宜人性
'C' => 0, // 尽责性
'N' => 0, // 情绪稳定性
'O' => 0 // 开放性
];
foreach ($questions as $index => $question) {
$answer = $answers[$index];
if ($answer === 'A' && !empty($question['trait_a'])) {
$scores[$question['trait_a']]++;
} elseif ($answer === 'B' && !empty($question['trait_b'])) {
$scores[$question['trait_b']]++;
}
}
// 确定主要性格类型
$primaryTrait = '';
$maxScore = 0;
foreach ($scores as $trait => $score) {
if ($score > $maxScore) {
$maxScore = $score;
$primaryTrait = $trait;
}
}
// 生成性格描述
$descriptions = [
'E' => '外向型:您性格外向,善于社交,喜欢与人互动,能从社交活动中获得能量。',
'A' => '宜人型:您待人友善,富有同情心,乐于合作,注重人际和谐。',
'C' => '尽责型:您做事有条理,负责任,有组织性,注重细节和计划。',
'N' => '稳定型:您情绪稳定,抗压能力强,能够冷静应对挑战和压力。',
'O' => '开放型:您思维开放,富有创造力,喜欢尝试新事物,对新鲜 ideas 持开放态度。'
];
$personalityType = $primaryTrait . '型人格';
$description = $descriptions[$primaryTrait] ?? '均衡型人格:您的性格特点较为均衡。';
// 添加额外描述
if ($scores['O'] >= 1) {
$description .= " 您还具有开放的思维,愿意接受新观念。";
}
if ($scores['C'] >= 1) {
$description .= " 同时您做事认真负责,有条理性。";
}
if ($scores['N'] >= 1) {
$description .= " 您的情绪较为稳定,能够较好地应对压力。";
}
// 保存测试结果
$data = [
'user_name' => $userName,
'answers' => implode(',', $answers),
'score_e' => $scores['E'],
'score_a' => $scores['A'],
'score_c' => $scores['C'],
'score_n' => $scores['N'],
'score_o' => $scores['O'],
'personality_type' => $personalityType,
'description' => $description,
'createtime' => time()
];
$resultId = Db::name('test_results')->insertGetId($data);
if ($resultId) {
$result = [
'user_name' => $userName,
'scores' => $scores,
'personality_type' => $personalityType,
'description' => $description
];
$this->success('提交成功', $result);
} else {
$this->error('提交失败,请重试');
}
}
}
三、Uniapp + UView 前端实现
1. 安装UView UI
在Uniapp项目中安装UView UI:
npm install uview-ui
在main.js
中引入UView:
import uView from 'uview-ui';
Vue.use(uView);
2. 测试页面 (pages/test/index.vue)
<template>
<view class="container">
<u-navbar :title="title" :autoBack="true"></u-navbar>
<view class="content">
<u-form :model="form" ref="uForm">
<view class="question-card" v-for="(item, index) in questions" :key="item.id">
<view class="question-title">{{ index + 1 }}. {{ item.question_text }}</view>
<u-radio-group v-model="answers[index]" @change="radioChange">
<u-radio
:name="'A'"
class="radio-item"
active-color="#2979ff"
>
{{ item.option_a }}
</u-radio>
<u-radio
:name="'B'"
class="radio-item"
active-color="#2979ff"
>
{{ item.option_b }}
</u-radio>
</u-radio-group>
</view>
<view class="user-info">
<u-form-item label="您的姓名" prop="userName" label-width="150">
<u-input v-model="form.userName" placeholder="请输入姓名" border="surround" />
</u-form-item>
</view>
<u-button
type="primary"
@click="submitTest"
:disabled="!canSubmit"
:loading="loading"
class="submit-btn"
>
提交测试
</u-button>
</u-form>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: '性格测试',
questions: [],
answers: new Array(10).fill(''),
form: {
userName: ''
},
loading: false
}
},
computed: {
canSubmit() {
return this.answers.every(answer => answer !== '') && this.form.userName.trim() !== '';
}
},
onLoad() {
this.getQuestions();
},
methods: {
async getQuestions() {
try {
const res = await this.$u.api.getQuestions();
this.questions = res.data;
} catch (error) {
this.$u.toast('获取题目失败');
}
},
radioChange() {
// 触发视图更新
this.$forceUpdate();
},
async submitTest() {
if (!this.canSubmit) return;
this.loading = true;
try {
const res = await this.$u.api.submitTest({
user_name: this.form.userName,
answers: this.answers
});
// 跳转到结果页面
uni.navigateTo({
url: `/pages/test/result?data=${encodeURIComponent(JSON.stringify(res.data))}`
});
} catch (error) {
this.$u.toast(error.message || '提交失败');
} finally {
this.loading = false;
}
}
}
}
</script>
<style scoped>
.container {
min-height: 100vh;
background-color: #f5f7fa;
}
.content {
padding: 20rpx;
}
.question-card {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.question-title {
font-size: 32rpx;
font-weight: 500;
margin-bottom: 30rpx;
color: #303133;
}
.radio-item {
margin-bottom: 20rpx;
}
.user-info {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 40rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.submit-btn {
margin-top: 40rpx;
height: 90rpx;
border-radius: 45rpx;
font-size: 32rpx;
}
</style>
3. 结果页面 (pages/test/result.vue)
<template>
<view class="container">
<u-navbar :title="title" :autoBack="true"></u-navbar>
<view class="content">
<view class="result-card">
<view class="result-header">
<u-icon name="account-fill" color="#2979ff" size="40"></u-icon>
<text class="user-name">{{ result.user_name }}</text>
</view>
<view class="type-badge">
{{ result.personality_type }}
</view>
<view class="description">
{{ result.description }}
</view>
<view class="score-title">维度得分</view>
<view class="scores">
<view class="score-item" v-for="(score, key) in result.scores" :key="key">
<view class="score-value">{{ score }}</view>
<view class="score-label">{{ scoreLabels[key] }}</view>
</view>
</view>
</view>
<view class="action-buttons">
<u-button type="primary" plain @click="redoTest">重新测试</u-button>
<u-button type="primary" @click="shareResult">分享结果</u-button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: '测试结果',
result: {},
scoreLabels: {
'E': '外向性',
'A': '宜人性',
'C': '尽责性',
'N': '情绪稳定性',
'O': '开放性'
}
}
},
onLoad(options) {
if (options.data) {
this.result = JSON.parse(decodeURIComponent(options.data));
}
},
methods: {
redoTest() {
uni.navigateBack();
},
shareResult() {
// 这里可以集成微信分享API
uni.showToast({
title: '已生成分享图片',
icon: 'success'
});
}
}
}
</script>
<style scoped>
.container {
min-height: 100vh;
background-color: #f5f7fa;
}
.content {
padding: 20rpx;
}
.result-card {
background-color: #fff;
border-radius: 16rpx;
padding: 40rpx;
margin-bottom: 40rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.result-header {
display: flex;
align-items: center;
margin-bottom: 30rpx;
}
.user-name {
font-size: 36rpx;
font-weight: 500;
margin-left: 16rpx;
color: #303133;
}
.type-badge {
display: inline-block;
background-color: #ecf5ff;
color: #2979ff;
padding: 10rpx 20rpx;
border-radius: 8rpx;
font-size: 28rpx;
margin-bottom: 30rpx;
}
.description {
font-size: 30rpx;
line-height: 1.6;
color: #606266;
margin-bottom: 40rpx;
}
.score-title {
font-size: 32rpx;
font-weight: 500;
margin-bottom: 30rpx;
color: #303133;
}
.scores {
display: flex;
justify-content: space-between;
}
.score-item {
text-align: center;
flex: 1;
}
.score-value {
font-size: 40rpx;
font-weight: bold;
color: #2979ff;
margin-bottom: 10rpx;
}
.score-label {
font-size: 24rpx;
color: #909399;
}
.action-buttons {
display: flex;
gap: 20rpx;
}
.action-buttons button {
flex: 1;
}
</style>
4. API封装 (utils/api.js)
import { baseUrl } from '@/config';
/**
* 封装API请求
*/
class Api {
constructor() {
this.baseUrl = baseUrl;
}
// 通用请求方法
async request(url, data = {}, method = 'GET') {
return new Promise((resolve, reject) => {
uni.request({
url: this.baseUrl + url,
data,
method,
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: (res) => {
if (res.data.code === 1) {
resolve(res.data);
} else {
reject(new Error(res.data.msg || '请求失败'));
}
},
fail: (err) => {
reject(new Error('网络请求失败'));
}
});
});
}
// 获取测试题目
getQuestions() {
return this.request('/api/test/getQuestions');
}
// 提交测试答案
submitTest(data) {
return this.request('/api/test/submitTest', data, 'POST');
}
}
export default new Api();
5. 配置文件 (config.js)
// 开发环境配置
const dev = {
baseUrl: 'http://localhost/fastadmin' // 替换为您的FastAdmin域名
};
// 生产环境配置
const prod = {
baseUrl: 'https://yourdomain.com/fastadmin' // 替换为您的生产环境域名
};
// 根据环境选择配置
export const baseUrl = process.env.NODE_ENV === 'development' ? dev.baseUrl : prod.baseUrl;
四、部署说明
将FastAdmin后端代码部署到服务器
创建数据库并导入表结构
修改FastAdmin的API控制器路径和数据库配置
在Uniapp中修改
config.js
中的API地址编译Uniapp项目并上传到微信小程序平台
五、扩展功能建议
用户系统集成:可以连接企业微信或钉钉用户系统,自动获取用户信息
测试结果统计:为企业HR提供测试结果统计和分析功能
多版本测试:开发不同岗位的性格测试版本
报告导出:支持将测试结果导出为PDF报告
历史记录:为用户保存历史测试记录,支持查看对比
这个方案提供了完整的性格测试功能,适合入职人员使用。您可以根据实际需求进行调整和扩展。