Browse Source

基本的text页面设计,继续完善业务功能

milestone-20251107-股票知识测评
chenzhen 2 months ago
parent
commit
24b8accbd1
  1. 6
      src/router/index.js
  2. 2
      src/views/HomeView.vue
  3. 891
      src/views/TextView.vue

6
src/router/index.js

@ -1,6 +1,7 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import TestView from '@/views/TestView.vue'
import TextView from '@/views/TextView.vue'
import ReportView from '@/views/ReportView.vue'
import ProblemView from '@/views/ProblemView.vue'
// import { component } from 'vue/types/umd'
@ -20,6 +21,11 @@ const routes = [
component: TestView
},
{
path: '/text',
name: 'TextView',
component: TextView
},
{
path: '/report',
name: 'ReportView',
component: ReportView

2
src/views/HomeView.vue

@ -1,6 +1,6 @@
<template>
<div>
<router-link to="/test" class="center">
<router-link to="/text" class="center">
<span class="text">进入测试系统</span>
</router-link>
</div>

891
src/views/TextView.vue

@ -0,0 +1,891 @@
<template>
<div class="home">
<div class="top">
<h1>📈股票知识评测系统</h1>
<p>全方面评估您的股票投资知识水平获取个性化学习建议</p>
</div>
<div class="clearfix">
<div class="content">
<div class="block">
<div class="schedule" :style="{ width: progress + '%' }"></div>
</div>
<div class="question-block" v-if="currentQuestion">
<div class="question">
<span class="text-lg font-bold mr-2">{{ currentQuestionIndex + 1 }}</span>
{{ currentQuestion.question }}
</div>
<div class="options">
<label
class="option"
:class="{ 'selected': selectedOption === option.value }"
v-for="option in currentQuestion.options"
:key="option.value"
>
<input
type="radio"
:name="'answer' + (currentQuestionIndex + 1)"
:value="option.value"
v-model="selectedOption"
>
<span class="label">{{ option.label }}</span>
</label>
</div>
</div>
<div class="question-block" v-if="currentQuestion">
<div class="question">
<span class="text-lg font-bold mr-2">{{ currentQuestionIndex + 2 }}</span>
{{ currentQuestion.question }}
</div>
<div class="options">
<label
class="option"
:class="{ 'selected': selectedOption === option.value }"
v-for="option in currentQuestion.options"
:key="option.value"
>
<input
type="radio"
:name="'answer' + (currentQuestionIndex + 2)"
:value="option.value"
v-model="selectedOption"
>
<span class="label">{{ option.label }}</span>
</label>
</div>
</div>
<div class="nav-buttons">
<button
class="nav-btn prev"
@click="prevQuestion"
:disabled="currentQuestionIndex === 0"
>
上一题
</button>
<button
class="nav-btn next"
@click="nextQuestion"
:disabled="currentQuestionIndex === questions.length - 1"
>
下一题
</button>
</div>
</div>
<div class="right">
<div class="time-module">
<h3> 考试时间</h3>
<div class="current-time">{{ currentTime }}</div>
<div class="countdown">倒计时: {{ countdown }}</div>
</div>
<div class="question-nav">
<h3>📝 题目导航</h3>
<div class="question-grid">
<div
class="question-number"
:class="getQuestionStatusClass(i)"
@click="goToQuestion(i)"
v-for="i in questions.length"
:key="i"
>
{{ i }}
</div>
</div>
<div class="pagination">
<button
class="pagination-btn"
@click="changePage(page - 1)"
:disabled="page === 1"
>
上一页
</button>
<span> {{ page }} / {{ totalPages }} </span>
<button
class="pagination-btn"
@click="changePage(page + 1)"
:disabled="page === totalPages"
>
下一页
</button>
</div>
</div>
<div class="statistics">
<h3>📊 答题统计</h3>
<div class="statistics-item">
<span class="statistics-label">总题数:</span>
<span class="statistics-value">{{ questions.length }}</span>
</div>
<div class="statistics-item">
<span class="statistics-label">已答题数:</span>
<span class="statistics-value">{{ answeredCount }}</span>
</div>
<div class="statistics-item">
<span class="statistics-label">未答题数:</span>
<span class="statistics-value">{{ questions.length - answeredCount }}</span>
</div>
<div class="statistics-item">
<span class="statistics-label">完成率:</span>
<span class="statistics-value">{{ completionRate.toFixed(1) }}%</span>
</div>
</div>
<button
class="submit-btn"
@click="submitTest"
:disabled="answeredCount === 0"
>
🚀 提交试卷
</button>
</div>
</div>
</div>
</template>
<script>
//
const stockQuestions = [
{
id: 1,
question: "以下哪项不是股票的基本特征?",
options: [
{ value: "A", label: "A. 收益性" },
{ value: "B", label: "B. 风险性" },
{ value: "C", label: "C. 流动性" },
{ value: "D", label: "D. 固定性" }
],
answer: "D"
},
{
id: 2,
question: "股票市场中,'IPO'的全称是什么?",
options: [
{ value: "A", label: "A. Initial Public Offering" },
{ value: "B", label: "B. International Public Offering" },
{ value: "C", label: "C. Initial Private Offering" },
{ value: "D", label: "D. International Private Offering" }
],
answer: "A"
},
{
id: 3,
question: "以下哪个指标不属于股票的技术分析指标?",
options: [
{ value: "A", label: "A. MACD" },
{ value: "B", label: "B. KDJ" },
{ value: "C", label: "C. ROE" },
{ value: "D", label: "D. RSI" }
],
answer: "C"
},
{
id: 4,
question: "股票代码以'60'开头的是哪个交易所的股票?",
options: [
{ value: "A", label: "A. 深圳证券交易所" },
{ value: "B", label: "B. 上海证券交易所" },
{ value: "C", label: "C. 香港交易所" },
{ value: "D", label: "D. 美国纳斯达克" }
],
answer: "B"
},
{
id: 5,
question: "以下哪项不属于基本面分析的范畴?",
options: [
{ value: "A", label: "A. 公司财务报表分析" },
{ value: "B", label: "B. 行业发展趋势分析" },
{ value: "C", label: "C. 宏观经济环境分析" },
{ value: "D", label: "D. 股票价格走势图分析" }
],
answer: "D"
},
{
id: 6,
question: "股票交易中,'涨停板'是指股票价格上涨到什么程度后停止交易?",
options: [
{ value: "A", label: "A. 5%" },
{ value: "B", label: "B. 10%" },
{ value: "C", label: "C. 15%" },
{ value: "D", label: "D. 20%" }
],
answer: "B"
},
{
id: 7,
question: "以下哪个不是股票指数?",
options: [
{ value: "A", label: "A. 上证指数" },
{ value: "B", label: "B. 深证成指" },
{ value: "C", label: "C. 恒生指数" },
{ value: "D", label: "D. GDP指数" }
],
answer: "D"
},
{
id: 8,
question: "股票投资中,'PE比率'指的是什么?",
options: [
{ value: "A", label: "A. 市盈率" },
{ value: "B", label: "B. 市净率" },
{ value: "C", label: "C. 收益率" },
{ value: "D", label: "D. 波动率" }
],
answer: "A"
},
{
id: 9,
question: "以下哪种订单类型可以确保以指定价格或更好的价格成交?",
options: [
{ value: "A", label: "A. 市价单" },
{ value: "B", label: "B. 限价单" },
{ value: "C", label: "C. 止损单" },
{ value: "D", label: "D. 止盈单" }
],
answer: "B"
},
{
id: 10,
question: "股票市场中,'熊市'指的是什么市场状态?",
options: [
{ value: "A", label: "A. 市场持续上涨" },
{ value: "B", label: "B. 市场持续下跌" },
{ value: "C", label: "C. 市场震荡整理" },
{ value: "D", label: "D. 市场活跃度低" }
],
answer: "B"
},
{
id: 11,
question: "以下哪项不是影响股票价格的因素?",
options: [
{ value: "A", label: "A. 公司业绩" },
{ value: "B", label: "B. 宏观经济数据" },
{ value: "C", label: "C. 投资者情绪" },
{ value: "D", label: "D. 公司员工数量" }
],
answer: "D"
},
{
id: 12,
question: "股票交易的最小单位是什么?",
options: [
{ value: "A", label: "A. 1股" },
{ value: "B", label: "B. 10股" },
{ value: "C", label: "C. 100股" },
{ value: "D", label: "D. 1000股" }
],
answer: "C"
},
{
id: 13,
question: "以下哪个不是股票的分类?",
options: [
{ value: "A", label: "A. 普通股" },
{ value: "B", label: "B. 优先股" },
{ value: "C", label: "C. 蓝筹股" },
{ value: "D", label: "D. 债券股" }
],
answer: "D"
},
{
id: 14,
question: "股票投资中的'分散投资'策略主要是为了降低什么风险?",
options: [
{ value: "A", label: "A. 系统性风险" },
{ value: "B", label: "B. 非系统性风险" },
{ value: "C", label: "C. 市场风险" },
{ value: "D", label: "D. 流动性风险" }
],
answer: "B"
},
{
id: 15,
question: "以下哪项不是技术分析的假设前提?",
options: [
{ value: "A", label: "A. 市场行为涵盖一切信息" },
{ value: "B", label: "B. 价格沿趋势移动" },
{ value: "C", label: "C. 历史会重演" },
{ value: "D", label: "D. 公司价值决定股票价格" }
],
answer: "D"
},
{
id: 16,
question: "股票市场中,'量价关系'指的是什么?",
options: [
{ value: "A", label: "A. 股票价格与成交量的关系" },
{ value: "B", label: "B. 股票价格与公司价值的关系" },
{ value: "C", label: "C. 股票价格与市场指数的关系" },
{ value: "D", label: "D. 股票价格与市盈率的关系" }
],
answer: "A"
},
{
id: 17,
question: "以下哪个指标反映了公司的盈利能力?",
options: [
{ value: "A", label: "A. 资产负债率" },
{ value: "B", label: "B. 净利润率" },
{ value: "C", label: "C. 流动比率" },
{ value: "D", label: "D. 资产周转率" }
],
answer: "B"
},
{
id: 18,
question: "股票交易中,'T+1'制度指的是什么?",
options: [
{ value: "A", label: "A. 当天买入的股票当天可以卖出" },
{ value: "B", label: "B. 当天买入的股票次日才能卖出" },
{ value: "C", label: "C. 当天卖出的股票当天可以买入" },
{ value: "D", label: "D. 当天卖出的股票次日才能买入" }
],
answer: "B"
},
{
id: 19,
question: "以下哪项不是股票投资的风险?",
options: [
{ value: "A", label: "A. 市场风险" },
{ value: "B", label: "B. 信用风险" },
{ value: "C", label: "C. 通胀风险" },
{ value: "D", label: "D. 固定收益风险" }
],
answer: "D"
},
{
id: 20,
question: "股票市场中,'龙头股'指的是什么?",
options: [
{ value: "A", label: "A. 市值最大的股票" },
{ value: "B", label: "B. 涨幅最大的股票" },
{ value: "C", label: "C. 在行业中具有领先地位的股票" },
{ value: "D", label: "D. 分红最高的股票" }
],
answer: "C"
},
{
id: 21,
question: "以下哪项不是基本面分析的指标?",
options: [
{ value: "A", label: "A. 每股收益(EPS)" },
{ value: "B", label: "B. 净资产收益率(ROE)" },
{ value: "C", label: "C. 相对强弱指数(RSI)" },
{ value: "D", label: "D. 资产负债率" }
],
answer: "C"
},
{
id: 22,
question: "股票投资中的'止损'策略主要是为了什么?",
options: [
{ value: "A", label: "A. 限制损失" },
{ value: "B", label: "B. 锁定利润" },
{ value: "C", label: "C. 增加收益" },
{ value: "D", label: "D. 降低交易成本" }
],
answer: "A"
},
{
id: 23,
question: "以下哪个不是股票市场的参与者?",
options: [
{ value: "A", label: "A. 个人投资者" },
{ value: "B", label: "B. 机构投资者" },
{ value: "C", label: "C. 中央银行" },
{ value: "D", label: "D. 上市公司" }
],
answer: "C"
},
{
id: 24,
question: "股票市场中,'成交量'指的是什么?",
options: [
{ value: "A", label: "A. 股票成交的金额" },
{ value: "B", label: "B. 股票成交的数量" },
{ value: "C", label: "C. 股票成交的笔数" },
{ value: "D", label: "D. 股票成交的频率" }
],
answer: "B"
},
{
id: 25,
question: "以下哪项不是影响股票市场的宏观经济因素?",
options: [
{ value: "A", label: "A. GDP增长率" },
{ value: "B", label: "B. 通货膨胀率" },
{ value: "C", label: "C. 公司管理层变动" },
{ value: "D", label: "D. 利率水平" }
],
answer: "C"
}
];
export default {
name: 'TextView',
data() {
return {
questions: stockQuestions,
currentQuestionIndex: 0,
selectedOption: '',
answers: {}, // { questionId: selectedOption }
page: 1,
questionsPerPage: 25, // 255×5
startTime: new Date(),
countdownMinutes: 60, // 60
currentTime: '',
countdown: '',
timer: null
};
},
computed: {
currentQuestion() {
return this.questions[this.currentQuestionIndex];
},
totalPages() {
return Math.ceil(this.questions.length / this.questionsPerPage);
},
answeredCount() {
return Object.keys(this.answers).length;
},
completionRate() {
return (this.answeredCount / this.questions.length) * 100;
},
progress() {
return this.completionRate;
}
},
watch: {
currentQuestionIndex() {
//
this.selectedOption = this.answers[this.currentQuestion.id] || '';
//
this.page = Math.ceil((this.currentQuestionIndex + 1) / this.questionsPerPage);
},
selectedOption() {
//
if (this.selectedOption) {
this.$set(this.answers, this.currentQuestion.id, this.selectedOption);
}
}
},
methods: {
//
getQuestionStatusClass(questionNumber) {
const index = questionNumber - 1;
const questionId = this.questions[index].id;
if (index === this.currentQuestionIndex) {
return 'current';
} else if (this.answers[questionId]) {
return 'answered';
} else {
return 'normal';
}
},
//
goToQuestion(questionNumber) {
const index = questionNumber - 1;
if (index >= 0 && index < this.questions.length) {
this.currentQuestionIndex = index;
}
},
//
prevQuestion() {
if (this.currentQuestionIndex > 0) {
this.currentQuestionIndex--;
}
},
//
nextQuestion() {
if (this.currentQuestionIndex < this.questions.length - 1) {
this.currentQuestionIndex++;
}
},
//
changePage(newPage) {
if (newPage >= 1 && newPage <= this.totalPages) {
this.page = newPage;
//
const firstQuestionIndex = (newPage - 1) * this.questionsPerPage;
this.goToQuestion(firstQuestionIndex + 1);
}
},
//
updateCurrentTime() {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
this.currentTime = `${hours}:${minutes}:${seconds}`;
},
//
updateCountdown() {
const now = new Date();
const elapsedMinutes = (now - this.startTime) / (1000 * 60);
const remainingMinutes = Math.max(0, this.countdownMinutes - elapsedMinutes);
const minutes = Math.floor(remainingMinutes).toString().padStart(2, '0');
const seconds = Math.floor((remainingMinutes % 1) * 60).toString().padStart(2, '0');
this.countdown = `${minutes}:${seconds}`;
//
if (remainingMinutes <= 0) {
this.submitTest();
}
},
//
submitTest() {
if (confirm('确定要提交试卷吗?提交后将无法修改答案。')) {
//
let score = 0;
this.questions.forEach(question => {
if (this.answers[question.id] === question.answer) {
score++;
}
});
const percentage = (score / this.questions.length) * 100;
//
alert(`考试结束!\n您的得分:${score}/${this.questions.length} (${percentage.toFixed(1)}%)`);
//
//
}
}
},
mounted() {
//
this.updateCurrentTime();
this.updateCountdown();
//
this.timer = setInterval(() => {
this.updateCurrentTime();
this.updateCountdown();
}, 1000);
//
this.selectedOption = this.answers[this.currentQuestion.id] || '';
},
beforeDestroy() {
//
if (this.timer) {
clearInterval(this.timer);
}
}
};
</script>
<style scoped>
/* 这里放置之前的所有CSS样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
}
.home {
min-height: 100vh;
width: 100%;
background-color: #24293c;
overflow: auto;
padding: 20px;
}
.top {
background: linear-gradient(135deg, #0c4a6e 0%, #075985 100%);
color: white;
padding: 30px;
margin-bottom: 30px;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
position: relative;
overflow: hidden;
text-align: center;
}
.top h1 {
font-size: 2.2em;
margin-bottom: 10px;
background: none;
}
.top p {
font-size: 1.1em;
opacity: 0.9;
background: none;
}
.block {
background: rgba(139, 141, 145, 0.7);
width: 90%;
height: 10px;
border-radius: 5px;
margin: 0 auto 30px;
overflow: hidden;
position: relative;
box-shadow: inset 0 0 10px rgba(0,0,0,0.3);
}
.schedule {
background: linear-gradient(90deg, #0ea5e9 0%, #38bdf8 100%);
height: 100%;
width: 15%;
transition: width 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
position: relative;
}
.content {
float: left;
width: calc(65% - 20px);
border: #183954 solid 2px;
border-radius: 10px;
color: #f1f5f9;
padding: 20px 40px 50px;
margin-right: 20px;
background-color: #2a3147;
}
.question-block {
border: #183954 solid 2px;
border-radius: 10px;
padding: 20px 40px;
margin-bottom: 30px;
background-color: #2f374d;
}
.question {
font-size: 1.3em;
line-height: 1.8;
margin-bottom: 25px;
color: #f1f5f9;
font-weight: 500;
}
.options {
display: flex;
flex-direction: column;
gap: 15px;
}
.option {
border: #183954 solid 2px;
border-radius: 10px;
padding: 12px 15px;
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
background-color: #374151;
}
.option:hover {
border-color: #3b82f6;
background-color: #4b5563;
}
.option input {
margin-right: 15px;
width: 18px;
height: 18px;
accent-color: #3b82f6;
}
.option .label {
font-size: 1.1em;
color: #e5e7eb;
}
.option.selected {
border-color: #3b82f6;
background-color: rgba(59, 130, 246, 0.2);
}
.right {
float: right;
width: calc(35% - 20px);
border: #183954 solid 2px;
border-radius: 10px;
color: #f1f5f9;
padding: 20px;
background-color: #2a3147;
}
.time-module, .question-nav, .statistics {
border: #183954 solid 2px;
border-radius: 10px;
padding: 15px;
margin-bottom: 20px;
background-color: #2f374d;
}
.time-module h3, .question-nav h3, .statistics h3 {
margin-bottom: 15px;
color: #f1f5f9;
font-size: 1.2em;
border-bottom: 1px solid #374151;
padding-bottom: 10px;
}
.current-time {
font-size: 1.8em;
font-weight: bold;
color: #3b82f6;
text-align: center;
margin-bottom: 10px;
}
.countdown {
font-size: 1.5em;
color: #f59e0b;
text-align: center;
}
.question-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 10px;
margin-top: 15px;
}
.question-number {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.question-number.normal {
background-color: #374151;
border: 1px solid #4b5563;
}
.question-number.answered {
background-color: #10b981;
border: 1px solid #059669;
}
.question-number.current {
background-color: #3b82f6;
border: 1px solid #2563eb;
transform: scale(1.1);
}
.question-number:hover {
transform: scale(1.1);
}
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
gap: 10px;
}
.pagination-btn {
padding: 8px 15px;
border-radius: 8px;
border: none;
background-color: #3b82f6;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
}
.pagination-btn:hover {
background-color: #2563eb;
}
.pagination-btn:disabled {
background-color: #4b5563;
cursor: not-allowed;
}
.nav-buttons {
display: flex;
justify-content: space-between;
margin-top: 30px;
}
.nav-btn {
padding: 10px 20px;
border-radius: 8px;
border: none;
background-color: #3b82f6;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 5px;
}
.nav-btn:hover {
background-color: #2563eb;
}
.nav-btn.prev {
background-color: #4b5563;
}
.nav-btn.prev:hover {
background-color: #374151;
}
.nav-btn:disabled {
background-color: #4b5563;
cursor: not-allowed;
}
.statistics-item {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #374151;
}
.statistics-item:last-child {
border-bottom: none;
}
.statistics-label {
color: #e5e7eb;
}
.statistics-value {
font-weight: bold;
color: #3b82f6;
}
.submit-btn {
width: 100%;
padding: 15px;
border-radius: 10px;
border: none;
background-color: #10b981;
color: white;
font-size: 1.2em;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 20px;
}
.submit-btn:hover {
background-color: #059669;
}
.clearfix::after {
content: "";
clear: both;
display: table;
}
@media (max-width: 1200px) {
.content, .right {
float: none;
width: 100%;
margin-right: 0;
margin-bottom: 20px;
}
}
@media (max-width: 768px) {
.content {
padding: 15px 20px 30px;
}
.question-block {
padding: 15px 20px;
}
.question {
font-size: 1.1em;
}
.option .label {
font-size: 1em;
}
.question-grid {
grid-template-columns: repeat(5, 1fr);
}
.question-number {
width: 35px;
height: 35px;
font-size: 0.9em;
}
}
</style>
Loading…
Cancel
Save