提交 2fad7fba 编写于 作者: 不想努力了TT's avatar 不想努力了TT

initail commit

上级 2a45c939
# 页面标题
VUE_APP_TITLE = 在线答题系统
# 开发环境配置
ENV = 'development'
# 若依管理系统/开发环境
VUE_APP_BASE_API = 'http://localhost:80'
# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true
# 页面标题
VUE_APP_TITLE = 在线答题系统
# 生产环境配置
ENV = 'production'
# 若依管理系统/生产环境
VUE_APP_SERVER_URL = 'http://localhost:80'
# front
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
此差异已折叠。
......@@ -8,8 +8,17 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.27.2",
"core-js": "^3.8.3",
"vue": "^2.6.14"
"element-ui": "^2.15.10",
"js-cookie": "^3.0.1",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"qs": "^6.11.0",
"save": "^2.5.0",
"vue": "^2.6.14",
"vue-router": "^3.6.5",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
......
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<MainBody/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import MainBody from './components/MainBody';
// import { getToken, removeToken } from '@/utils/auth';
export default {
name: 'App',
components: {
HelloWorld
}
MainBody
},
created() {
// 在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem('store')) {
this.$store.replaceState(
Object.assign(
{},
this.$store.state,
JSON.parse(sessionStorage.getItem('store'))
)
)
}
// 在页面刷新时将vuex里的信息保存到sessionStorage里,beforeunload事件在页面刷新时先触发
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('store', JSON.stringify(this.$store.state))
})
},
// created(){
// if (getToken() != null) {
// removeToken()
// }
// }
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
import http from "@/utils/http";
// 根据类型获取题目的id列表
export async function getQuestionIdListByType(type) {
const resp = await Promise.resolve(http.get("/admin/ques/search", {
type: type
}))
if (resp.data.code != 200) return [];
var a = resp.data.data;
const res = {
"quesCnt": a.quesCnt,
"lt": a.IdList
};
return JSON.stringify(res);
}
// 根据题目id获取所有题目的信息
export async function getQuesInfoById(userId,quesId) {
const resp = await Promise.resolve(http.get("/admin/ques/info", {
quesId: quesId
}))
if (resp.data.code != 200) return null;
const collectState = await Promise.resolve(http.get("/user/ques/collectState",{
userId,
quesId
}));
let c = collectState.data.data.exists;
let res = resp.data.data.detail;
res["collected"]=c
return res;
}
import http from "@/utils/http";
// 用户登录
export async function login(username,password){
const resp = await Promise.resolve(http.post("/user/login",{
username,
password
}));
return resp.data
}
// 用户注册
export async function register(username,password){
const resp = await Promise.resolve(http.post("/user/register",{
username,
password
}))
return resp.data;
}
// 更新用户信息
export async function uptInfo(mp){
let info = JSON.parse(mp)
let userId = info.userId; // 必选,其余可选
let nikeName = info.nikeName;
let realName = info.realName;
let gender = info.gender;
let tel = info.tel;
let email = info.email;
let introduction = info.introduction;
let time = info.createTime;
await Promise.resolve(http.post("/user/info",{
userId,
nikeName,
realName,
gender,
tel,
email,
introduction,
createTime:time
}));
}
// 用户退出
export async function logout(){
await Promise.resolve(http.get("/user/logout"));
}
// 获取个人信息
export async function getInfo(userId){
const resp = await Promise.resolve(http.get("/user/info",{
userId
}));
if (resp.data.code == 200) return resp.data.data
return null
}
// 用户收藏/取消收藏一个题目
export async function collectOne(userId, quesId,type,method) {
// method: del or add
// type: quesType
const resp = await Promise.resolve(http.post("/user/ques/collected",{
userId,
quesId,
type,
method
}));
if (resp.data.code != 200) {
return "收藏失败,请稍后再试"
}
return "收藏成功"
}
// 获取收藏记录
export async function getCollections(userId){
const resp = await Promise.resolve(http.get("/user/ques/collected",{
userId
}));
if (resp.data.code != 200) {
return "获取失败,请稍后再试"
}
return JSON.stringify(resp.data.data)
}
export async function getCollectState(userId,quesId){
const resp = await Promise.resolve(http.get("/user/ques/collectState",{
userId,
quesId
}));
// console.log(JSON.stringify(resp.data))
return resp.data.data.exists;
}
// 加入历史记录
export async function addHistory(userId,quesId){
const resp = await Promise.resolve(http.put("/user/ques/history",{
userId:userId,
quesId:quesId
}));
if (resp.data.code != 200) {
return "失败"
}
return "成功"
}
// 获取历史记录
export async function getHistory(userId){
const resp1 = await Promise.resolve(http.get("/user/ques/history",{
userId:userId
}))
if (resp1.data.code != 200) return null;
return JSON.stringify(resp1.data.data);
}
\ No newline at end of file
src/assets/logo.png

6.7 KB | W: | H:

src/assets/logo.png

9.4 KB | W: | H:

src/assets/logo.png
src/assets/logo.png
src/assets/logo.png
src/assets/logo.png
  • 2-up
  • Swipe
  • Onion skin
<template>
<div>Copyright © 2022 - 2024 lyf. All Rights Reserved.</div>
</template>
<script>
export default {
name: "FooterInfo",
};
</script>
<style scoped>
div{
width: 100%;
margin-top: 10px;
text-align: center;
font-size: smaller;
color: gray;
}
</style>
\ No newline at end of file
<template>
<el-menu class="el-menu-demo" mode="horizontal" :router="true">
<el-menu-item
><a style="width: 140px"
><img alt="logo" src="../../assets/logo.png" width="120px" /></a
></el-menu-item>
<!-- <el-menu-item index="/">主页</el-menu-item> -->
<el-menu-item index="/quesBank">题库</el-menu-item>
<!-- <el-menu-item index="/paper" >试卷</el-menu-item> -->
<el-menu-item style="float: right" v-show="islogin" @click="logout">退出</el-menu-item>
<el-menu-item index="/personal" style="float: right" v-show="islogin">个人中心</el-menu-item>
<el-menu-item index="/register" style="float: right" v-show="!islogin">注册</el-menu-item>
<el-menu-item index="/" style="float: right" v-show="!islogin">登录</el-menu-item>
</el-menu>
</template>
<script>
import { logout } from '@/api/user'
import { Message } from 'element-ui';
import { removeToken } from '@/utils/auth';
export default {
name: "HeaderNav",
data() {
return {
};
},
computed:{
islogin(){
return this.$store.state.islogin
}
},
methods:{
logout(){
logout()
this.$store.state.islogin = false
removeToken()
Message.success("退出成功")
this.$router.push({
path:"/"
})
}
},
};
</script>
\ No newline at end of file
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
<template>
<div>这是首页</div>
</template>
<script>
export default {
name : "HomePage"
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<!-- <div>登录界面</div> -->
<el-row>
<el-col :span="9"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="6" :offset="9">
<div class="grid-content bg-purple-light">
<div class="form">
<div class="inner">
<div>
<img alt="Vue logo" src="../../assets/logo.png" width="130px" />
</div>
<span>账号密码登录</span> <br />
<el-input v-model="username" placeholder="请输入用户名" autofocus></el-input> <br />
<el-input v-model="psd" placeholder="请输入密码" show-password></el-input> <br />
<el-button type="primary" round @click="checkValid()">登录</el-button> <br/>
<router-link to="/"><el-link type="info">忘记密码?</el-link></router-link>
<router-link to="/register"><el-link type="info">注册</el-link></router-link> <br/>
<el-checkbox v-model="agreed"></el-checkbox>同意<router-link to="/terms">《用户协议》</router-link><router-link to="/private">《隐私协议》</router-link>
</div>
</div>
</div>
</el-col>
<el-col :span="9"><div class="grid-content bg-purple"></div></el-col>
</el-row>
</template>
<script>
import { login,getInfo } from "@/api/user"
import { setToken } from "@/utils/auth"
import { Message } from "element-ui";
export default {
name: "LoginPage",
data() {
return {
username: "",
psd: "",
agreed:false
};
},
computed:{
userId(){
return this.$store.state.userInfo.userId
}
},
methods:{
checkValid(){
// 先看是否同意协议
if (this.agreed){
// 然后判断用户名和密码
login(this.username,this.psd).then((res) => {
console.log("res" + JSON.stringify(res))
if (res.code == 200){
setToken(res.token)
let userId = res.userId
this.$store.state.userInfo.userId = userId;
this.$store.state.islogin = true;
// 获取个人信息
getInfo(userId).then((info)=>{
console.log("info"+info)
this.$store.state.userInfo.nikeName = info==null?"":(info.nikeName==null?"":info.nikeName);
this.$store.state.userInfo.realName = info==null?"":(info.realName==null?"":info.realName);
this.$store.state.userInfo.gender = info==null?"":(info.gender==null?"":info.gender);
this.$store.state.userInfo.tel = info==null?"":(info.tel==null?"":info.tel);
this.$store.state.userInfo.email = info==null?"":(info.email==null?"":info.email);
this.$store.state.userInfo.introduction = info==null?"":(info.introduction==null?"":info.introduction);
this.$store.state.userInfo.createTime = info==null?"":(info.createTime==null?"":info.createTime);
})
this.$store.commit('setLogin', true)
Message.success("登录成功")
this.$router.push("/quesBank")
}else {
Message.warning(res.msg)
}
})
}else {
Message.info("请先勾选协议!")
}
},
}
};
</script>
<style scoped>
.form {
width: 380px;
height: 540px;
border-radius: 30px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.inner {
width: 300px;
height: 430px;
padding-top: 70px;
margin: auto;
}
</style>
\ No newline at end of file
<template>
<el-container>
<el-header>
<HeaderNav />
</el-header>
<el-main>
<router-view />
</el-main>
<el-footer>
<FooterInfo />
</el-footer>
</el-container>
</template>
<script>
import FooterInfo from "../FooterInfo";
import HeaderNav from "../HeaderNav";
export default {
name: "MainBody",
components: {
HeaderNav,
FooterInfo,
}
};
</script>
<template>
<div>
这是试卷界面.
</div>
</template>
<script>
export default {
name:"PaperBank",
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<el-col :span="5"></el-col>
<el-col :span="14" :offset="5">
<SingleQuestion :quesId="info.quesId" />
<el-collapse accordion style="margin:10px">
<el-collapse-item>
<template slot="title">
查看答案及解析
</template>
<div>正确答案: {{info.quesAnswer}}</div>
<div>解析:{{info.quesAnalysis}}</div>
</el-collapse-item>
</el-collapse>
</el-col>
<el-col :span="5"></el-col>
</div>
</template>
<script>
import SingleQuestion from '../QuestionDetail/QuestionTemplate'
export default {
name: "OneQuestion",
data(){
return{
info:JSON.parse(this.itemInfo)
}
},
components:{
SingleQuestion
},
props:["itemInfo"]
}
</script>
<template>
<div id="mainbody">
<div class="contentList">
<div class="card" v-for="(item,index) in this.info" :key="index" :class="item.theClass">
<div class="ques">
<div class="ques_info">
<div class="ques_info_content">
{{item.detail.quesContent}}
</div>
<div class="ques_info_options">
A : {{item.detail.option1}}
B : {{item.detail.option2}}
C : {{item.detail.option3}}
D : {{item.detail.option4}}
</div>
</div>
<div class="ques_type">
<el-tag type="success">{{item.theClass}}</el-tag>
</div>
</div>
<div class="icon">
<el-button :id="`ques`+index" @click="collect(index)">取消收藏</el-button>
</div>
</div>
</div>
<div class="pages">
分页条
</div>
</div>
</template>
<script>
import { collectOne,getCollections } from '@/api/user';
export default {
name:"PersonalCollected",
data(){
return {
info: [],
}
},
computed:{
userId(){
return this.$store.state.userInfo.userId;
}
},
methods:{
collect(index){
let detail = this.info.at(index).detail
console.log("detail"+ JSON.stringify(detail))
collectOne(this.userId,detail.quesId,detail.quesType,"del").then(()=>{
this.$router.go(0)
})
},
// 初始化列表
init(){
getCollections(this.userId).then(res=>{
this.info = JSON.parse(res)
})
}
},
created(){
this.init()
}
}
</script>
<style scoped>
#mainbody{
width: 750px;
height: 600px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.contentList{
width: 700px;
height: 540px;
padding-top: 20px;
padding-left: 25px;
}
.pages{
width: 700px;
padding-left: 25px;
}
.card{
width: 100%;
height: 100px;
}
.ques{
width: 650px;
height: 60px;
float: left;
}
.icon{
width: 50px;
height: 60px;
float: left;
}
.ques_info{
width: 600px;
height: 60px;
float: left;
}
.ques_info_content{
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; /*超出部分用...代替*/
}
.ques_type{
width: 50px;
height: 60px;
float: left;
text-align: center;
margin:auto
}
</style>
\ No newline at end of file
<template>
<div id="mainbody">
<div class="timelineBlock">
<div class="desc" v-show="this.historyList.length != 0">当前只显示最近10条记录</div>
<el-timeline>
<el-timeline-item v-for="(item,index) in historyList" :key="index" :timestamp="item.time" placement="top">
<el-card shadow="hover" >
<div @click="toDetail(item.detail)">
<span>{{item.detail.quesContent}}</span>
<div class="preview" v-show="item.detail.quesType=='single_select' || item.detail.quesType=='multi_select'">A :{{item.detail.option1}} B :{{item.detail.option2}} C : {{item.detail.option3}} D : {{item.detail.option4}}</div>
<div class="preview" v-show="item.quesType=='judge' ">A : 正确 B : 错误</div>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
<div class="empty" v-show="this.historyList.length == 0">
<el-empty description="当前没有历史做题记录"></el-empty>
</div>
</div>
</div>
</template>
<script>
import { getHistory } from "@/api/user"
export default {
name:"PersonalHistory",
data(){
return{
historyList:[],
}
},
computed:{
userId(){
return this.$store.state.userInfo.userId;
},
},
methods:{
// 这里要跳转到新的页面,展示单个题目
toDetail(item){
this.$router.push(
{
name:"oneQuestion",
params:{
itemInfo:JSON.stringify(item)
}
}
)
},
// 获取历史记录列表
async init(){
await getHistory(this.userId).then((res)=>{
this.historyList = JSON.parse(res);
})
},
},
created(){
this.init();
}
}
</script>
<style scoped>
#mainbody{
width: 750px;
/* height: 600px; */
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
text-align: left;
}
.desc{
width: 200px;
height: 30px;
margin: 20px;
color: rgba(96, 93, 92, 0.519);
font-size: smaller;
}
.timelineBlock{
width: 700px;
/* height: 540px; */
padding-top: 20px;
}
.preview{
width: 500px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; /*超出部分用...代替*/
}
.empty{
width: 100%;
}
</style>
\ No newline at end of file
<template>
<div id="mainbody">
<div id="content">
<!-- 展示 个人信息 -->
<div class="personalInfo">
<div class="info_head">
基本信息
</div>
<div class="info_content">
<div class="info_content_show">
<ul>
<!-- 用户名 -->
<li class="info_line">
<div class="info_left">用户名: </div>
<div class="info_right">
<span>{{userInfo.nikeName}}</span>
</div>
</li>
<!-- 真实姓名 -->
<li class="info_line">
<div class="info_left">真实姓名: </div>
<div v-if="this.editable[1].state">
<input type="text" id="realName" :value="userInfo.realName"/>
<button @click="save(1)">保存</button>
<button @click="cancel(1)">取消</button>
</div>
<div class="info_right" v-else>
<span>{{userInfo.realName}}</span>
<button class="el-icon-edit" @click="edit(1)">编辑</button>
</div>
</li>
<!-- 性别 -->
<li class="info_line">
<div class="info_left">性别: </div>
<div v-if="this.editable[2].state">
<input :value="g" id="gender" hidden />
<input type="radio" name="gender" value="0" v-model="g"/>
<input type="radio" name="gender" value="1" v-model="g"/>
<button @click="save(2)">保存</button>
<button @click="cancel(2)">取消</button>
</div>
<div class="info_right" v-else>
<span>{{userInfo.gender}}</span>
<button class="el-icon-edit" @click="edit(2)">编辑</button>
</div>
</li>
<!-- 电话号码 -->
<li class="info_line">
<div class="info_left">电话号码: </div>
<div v-if="this.editable[3].state">
<input type="text" id="tel" :value="userInfo.tel"/>
<button @click="save(3)">保存</button>
<button @click="cancel(3)">取消</button>
</div>
<div class="info_right" v-else>
<span>{{userInfo.tel}}</span>
<button class="el-icon-edit" @click="edit(3)">编辑</button>
</div>
</li>
<!-- 电子邮箱 -->
<li class="info_line">
<div class="info_left">电子邮箱: </div>
<div v-if="this.editable[4].state">
<input type="text" id="email" :value="userInfo.email"/>
<button @click="save(4)">保存</button>
<button @click="cancel(4)">取消</button>
</div>
<div class="info_right" v-else>
<span>{{userInfo.email}}</span>
<button class="el-icon-edit" @click="edit(4)">编辑</button>
</div>
</li>
<!-- 个人简介 -->
<li class="info_line">
<div class="info_left">个人简介: </div>
<div class="info_right" v-if="this.editable[5].state">
<input type="text" id="introduction" :value="userInfo.introduction"/>
<button @click="save(5)">保存</button>
<button @click="cancel(5)">取消</button>
</div>
<div class="info_right" v-else>
<span>{{userInfo.introduction}}</span>
<button class="el-icon-edit" @click="edit(5)">编辑</button>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { uptInfo } from '@/api/user';
export default {
name:"PersonalInfo",
data(){
return{
g:"",
editable:[
{id:1,name:"nikeName",state:false},
{id:2,name:"realName",state:false},
{id:3,name:"gender",state:false},
{id:4,name:"tel",state:false},
{id:5,name:"email",state:false},
{id:6,name:"introduction",state:false}
]
}
},
computed:{
userInfo(){
return this.$store.state.userInfo;
}
},
methods:{
edit(index){
this.editable.at(index).state = true
},
save(index){
let n = this.editable.at(index).name;
let value = document.getElementById(n).value;
// 修改editable状态,保存值
// 发送请求修改后端数据
switch (index){
case 0:{
this.$store.state.userInfo.nikeName = value
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
nikeName:value
}))
break
}
case 1:{
this.$store.state.userInfo.realName = value
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
realName:value
}))
break
}
case 2:{
let gender = value==0?"":""
this.$store.state.userInfo.gender = gender
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
gender:gender
}))
break
}
case 3:{
this.$store.state.userInfo.tel = value
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
tel:value
}))
break
}
case 4:{
this.$store.state.userInfo.email = value
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
email:value
}))
break
}
case 5:{
this.$store.state.userInfo.introduction = value
uptInfo(JSON.stringify({
userId:this.userInfo.userId,
introduction:value
}))
break
}
}
this.editable.at(index).state = false
},
cancel(index){
this.editable.at(index).state = false
}
},
created(){
this.g = this.userInfo.gender == ""?"0":"1"
}
}
</script>
<style scoped>
#mainbody{
width: 750px;
height: 600px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
#content{
width: 660px;
height: 500px;
margin-left: 30px;
padding-left: 30px;
padding-top: 30px;
}
.personalInfo{
width: 100%;
height: 300px;
padding-top: 30px;
}
.info_head{
width: 100%;
height: 30px;
font-weight: bold;
}
.info_content{
width: 100%;
}
.info_content_show{
width: 90%;
padding-left: 10px;
}
ul{
list-style: none;
}
.info_line{
clear: both;
width: 400px;
height: 30px;
margin: 10px;
}
.info_left{
width: 80px;
float: left;
}
.info_right{
width: 320px;
float: left;
}
</style>
\ No newline at end of file
<template>
<div id="mainbody">
<div class="contentList">
做题记录分析:
<div class="block1">
<div>过去一个月做题数:</div>
<div></div>
</div>
</div>
</div>
</template>
<script>
export default {
name:"SituationAnalysis",
data(){
return {
}
},
computed:{
userId(){
return this.$store.state.userInfo.userId;
}
},
created(){
}
}
</script>
<style scoped>
#mainbody{
width: 750px;
height: 600px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.contentList{
width: 700px;
height: 540px;
padding-top: 20px;
padding-left: 25px;
}
.block1{
width:660px;
height: 200px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>
\ No newline at end of file
<template>
<div>
<el-row>
<el-col :span="5"></el-col>
<el-col :span="14" :offset="5">
<!-- 头像+昵称 -->
<div class="title">
<img alt="icon" src="../../assets/logo.png" width="130px" />
{{nikeName}}
</div>
<!-- 模块: 收藏列表、历史记录、修改个人信息 -->
<div>
<el-row>
<el-col :span="8">
<!-- 侧边栏 -->
<div class="leftNav">
<div class="navList">
<!-- <div class="eachItem">
<router-link active-class="active" to="/personal/analysis">做题分析</router-link>
</div> -->
<div class="eachItem">
<router-link active-class="active" to="/personal/history">历史做题记录</router-link>
</div>
<div class="eachItem">
<router-link active-class="active" to="/personal/collected">收藏记录</router-link>
</div>
<div class="eachItem">
<router-link active-class="active" to="/personal/info">个人信息</router-link>
</div>
</div>
</div>
</el-col>
<el-col :span="16">
<!-- 信息展示 -->
<router-view/>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="5"></el-col>
</el-row>
</div>
</template>
<script>
export default {
name : "PersonalCenter",
data() {
return {
}
},
computed:{
userId(){
return this.$store.state.userInfo.userId
},
nikeName(){
return this.$store.state.userInfo.nikeName
}
}
}
</script>
<style scoped>
.title{
margin: 20px;
}
.leftNav{
width: 250px;
height: 600px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
text-align: center;
}
.navList{
widows: 200px;
height: 500px;
margin-left: 25px;
padding-top: 20px;
}
.eachItem{
padding-top: 10px;
/* margin: 20px; */
text-align: left;
}
</style>
\ No newline at end of file
<template>
<div>
这是隐私协议
</div>
</template>
<script>
export default {
name : "PrivatePage"
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<el-card class="box-card" style="margin:auto">
<div slot="header" class="clearfix">
<span>{{name}}</span>
</div>
<div v-for="(o,index) in ContentList" :key="index" class="text item">
{{o.name}}
<el-button style="float: right; padding: 3px 0" type="text" @click="toDetail(o)">开始答题</el-button>
</div>
</el-card>
</template>
<script>
import {getQuestionIdListByType} from '@/api/sys'
export default {
name : "QuestionCard",
data(){
return {
}
},
props : {
name : {
type : String,
required : true
},
ContentList : {
type : Array,
default: () => []
}
},
methods : {
toDetail(o){
this.getQuesList(o.classes).then(res => {
this.$router.push({
name : 'QuestionDetail',
query : {
name : o.name,
classes : o.classes,
IdListInfo : res,
}
})
});
},
async getQuesList(classes) {
return await getQuestionIdListByType(classes);
}
}
}
</script>
<template>
<el-row>
<el-col :span="6"
><div class="grid-content bg-purple">
<div style="border-radius: 30px; position: fixed" class="el-icon-sunny">
那些未能打败你的,终将使你变得强大.
<el-divider></el-divider>
</div></div
></el-col>
<el-col :span="12" :offset="6"
><div class="grid-content bg-purple-light">
<QuestionCard
name="数据结构"
:content-list="[
{ name: '数组', classes: 'array' },
{ name: '字符串', classes: 'string' },
{ name: '链表', classes: 'list' },
{ name: '队列', classes: 'queue' },
{ name: '树', classes: 'tree' },
{ name: '图', classes: 'diagram' }
]"
></QuestionCard>
<el-divider></el-divider>
<QuestionCard
name="计算机基础"
:content-list="[
{ name: '网络基础', classes: 'network' },
{ name: '数据库', classes: 'database' },
{ name: '操作系统', classes: 'os' },
{ name: '设计模式', classes: 'design' },
{ name: '软件工程', classes: 'software' },
]"
></QuestionCard>
<el-divider></el-divider>
<QuestionCard
name="编程语言"
:content-list="[
{ name: 'C语言', classes: 'c' },
{ name: 'C++', classes: 'cpp' },
{ name: 'Java', classes: 'java' },
{ name: 'JavaScript', classes: 'javascript' },
{ name: 'Python', classes: 'python' },
{ name: 'Go', classes: 'go' },
]"
></QuestionCard>
</div></el-col
>
<el-col :span="6"><div class="grid-content bg-purple"></div></el-col>
</el-row>
</template>
<script>
import { getToken } from '@/utils/auth';
import { Message } from 'element-ui';
import QuestionCard from "./QuestionCard";
export default {
name: "QuestionBank",
data() {
return {};
},
components: {
QuestionCard,
},
created(){
// 未登录则返回!
if (getToken() == null) {
Message.info("请先登录!")
let t = 0
setTimeout(()=>{
t ++ ;
if (t == 1) {
location.href="/"
}
},1000)
}
}
};
</script>
<style>
.text {
font-size: 14px;
}
.item {
margin-bottom: 18px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.box-card {
width: 600px;
}
</style>
\ No newline at end of file
<template>
<div>
<el-row>
<el-col :span="5"></el-col>
<el-col :span="14" :offset="5">
<div v-for="(id,index) in quesIdList" :key="index" class="quesBlock">
<QuestionResult :index="index" :quesId="id" :yourAns="getOneAns(id)" />
</div>
</el-col>
<el-col :span="5"></el-col>
</el-row>
</div>
</template>
<script>
import QuestionResult from './QuestionResult';
export default {
name: "AnswerResults",
data(){
return {
yourAnsMap:new Map()
}
},
props: ["quesCnt", "quesIdList", "yourAnsList"],
components:{
QuestionResult,
},
methods:{
list2map(){
for (let item of JSON.parse(this.yourAnsList)) {
this.yourAnsMap.set(item[0],item[1])
}
},
getOneAns(quesId){
return this.yourAnsMap.get(quesId);
}
},
created() {
this.list2map()
}
}
</script>
<style scoped>
.quesBlock{
margin-top: 20px;
width: 100%;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)
}
</style>
\ No newline at end of file
<!-- 用于 AnswerResults.vue 的题目展示 -->
<template>
<div>
<table class="headInfo">
<tr style="border-collapse: separate; border-spacing: 10px">
<td><el-tag type="success">{{ index+1 }}</el-tag></td>
<td><el-tag type="success">{{ getTypeName(quesType) }}</el-tag></td>
<td><el-tag type="success">{{ quesLevel }}</el-tag></td>
<td><el-tag type="success">来源:{{ quesSource }}</el-tag></td>
<td><el-button circle :class="this.collectIcon" @click="collectOne"></el-button></td>
</tr>
</table>
{{ quesContent }}
<!-- 选择题选项模块 -->
<div v-if="isShow(quesType, 'single_select')">
<div style="margin-top: 20px">
<el-radio-group v-model="yourAnswer" size="mini">
<el-radio label="A" border disabled>A: {{options.option1.desc}}</el-radio><br />
<el-radio label="B" border disabled>B: {{options.option2.desc}}</el-radio><br />
<el-radio label="C" border disabled>C: {{options.option3.desc}}</el-radio><br />
<el-radio label="D" border disabled>D: {{options.option4.desc}}</el-radio>
</el-radio-group>
</div>
</div>
<!-- 多选题模块 -->
<div v-if="isShow(quesType, 'multi_select')">
<div style="margin-top: 20px">
<el-checkbox-group v-model="yourAnswer" size="mini">
<el-checkbox label="A" border disabled>A: {{options.option1.desc}}</el-checkbox><br />
<el-checkbox label="B" border disabled>B: {{options.option2.desc}}</el-checkbox><br />
<el-checkbox label="C" border disabled>C: {{options.option3.desc}}</el-checkbox><br />
<el-checkbox label="D" border disabled>D: {{options.option4.desc}}</el-checkbox>
</el-checkbox-group>
</div>
</div>
<!-- 判断题选项模块 -->
<div v-if="isShow(quesType, 'judge')">
<div style="margin-top: 20px">
<el-radio-group v-model="yourAnswer" size="mini">
<el-radio label="A" border disabled>A: 正确</el-radio> <br />
<el-radio label="B" border disabled>B: 错误</el-radio>
</el-radio-group>
</div>
</div>
<span>你的答案: {{ansStr}}</span> <br/>
<span>正确答案: {{correctAns}}</span>
<div style="white-space: pre-wrap;">答案解析: {{analysis}}</div>
</div>
</template>
<script>
import { getQuesInfoById } from "@/api/sys";
import { collectOne } from "@/api/user";
import { addHistory } from "@/api/user"
export default {
name: "QuestionResult",
data() {
return {
quesInfo: {},
quesType: "",
quesLevel: "",
quesSource: "",
quesContent: "",
options: {},
yourAnswer: [],
collected: false,
collectIcon: "",
correctAns:"",
analysis:""
};
},
props: ["index", "quesId", "yourAns"],
computed: {
userId(){
return this.$store.state.userInfo.userId
},
ansStr(){
if (typeof(this.yourAnswer) === "object"){
let tmp = ""
for (let item of this.yourAnswer) {
tmp += item
}
return tmp
}
return this.yourAnswer
}
},
methods: {
// 收藏/取消收藏操作
collectOne() {
if (this.collected) {
// 取消收藏
collectOne(this.userId, this.quesId, this.quesType, "del");
this.$message({
message: "取消收藏成功!",
type: "success",
});
this.collectIcon = "el-icon-star-off";
} else {
// 收藏
collectOne(this.userId, this.quesId, this.quesType, "add");
this.$message({
message: "收藏成功!",
type: "success",
});
this.collectIcon = "el-icon-star-on";
}
this.collected = !this.collected;
},
getTypeName(type) {
switch (type) {
case "single_select":
return "单选题";
case "multi_select":
return "多选题";
case "judge":
return "判断题";
case "discuss":
return "简答题";
}
},
getLevel(level) {
switch (level) {
case "easy":
return "简单";
case "middle":
return "中等";
case "hard":
return "困难";
}
},
getOptions(detail) {
return {
option1: {
desc: detail.option1,
checked: false,
},
option2: {
desc: detail.option2,
checked: false,
},
option3: {
desc: detail.option3,
checked: false,
},
option4: {
desc: detail.option4,
checked: false,
},
};
},
/** 根据题目类型是否展示 */
isShow(quesType, typediv) {
return quesType == typediv;
},
/** 刷新data中的题目信息 */
reFlashInfo(userId,quesId) {
this.getSingleQuestion(userId,quesId).then((res) => {
console.log("rrr" + JSON.stringify(res))
this.quesInfo = JSON.parse(JSON.stringify(res));
// 给data中的元素重新赋值
this.quesType = this.quesInfo.quesType;
this.quesLevel = this.getLevel(this.quesInfo.quesLevel);
this.quesSource = this.quesInfo.quesSource;
this.quesContent = this.quesInfo.quesContent;
this.options = this.getOptions(this.quesInfo);
this.yourAnswer = this.yourAns;
if (typeof(this.yourAnswer) === "object") this.yourAnswer.sort(this.desc);
this.collected = this.quesInfo.collected;
this.collectIcon = this.collected
? "el-icon-star-on"
: "el-icon-star-off";
this.correctAns = this.quesInfo.quesAnswer;
this.analysis = this.quesInfo.quesAnalysis;
});
},
/** 获取题目信息 */
async getSingleQuestion(userId,quesId) {
return await getQuesInfoById(userId,quesId);
},
},
created() {
this.reFlashInfo(this.userId,this.quesId); // 初始化
// 加入历史记录中
addHistory(this.userId,this.quesId)
},
};
</script>
<!-- 这里是不同类型题目的板子,展示单个题目 -->
<template>
<div>
<table class="headInfo">
<tr style="border-collapse: separate;border-spacing: 10px;">
<!-- <td><el-tag type="info">{{nowIndex+1}}/{{quesCnt}}</el-tag></td> -->
<td><el-tag type="success">{{getTypeName(quesType)}}</el-tag></td>
<td><el-tag type="success">{{quesLevel}}</el-tag></td>
<td><el-tag type="success">来源:{{quesSource}}</el-tag></td>
<td><el-button circle :class="this.collectIcon" @click="collectOne" ></el-button></td>
</tr>
</table>
{{quesContent}}
<!-- 选择题选项模块 -->
<div v-if="isShow(quesType,'single_select')">
<div style="margin-top: 20px">
<el-radio-group v-model="yourAnswer" size="mini" >
<el-radio label="A" border >A: {{options.option1.desc}}</el-radio> <br/>
<el-radio label="B" border >B: {{options.option2.desc}}</el-radio> <br/>
<el-radio label="C" border >C: {{options.option3.desc}}</el-radio> <br/>
<el-radio label="D" border >D: {{options.option4.desc}}</el-radio>
</el-radio-group>
</div>
</div>
<!-- 多选题模块 -->
<div v-if="isShow(quesType,'multi_select')">
<div style="margin-top: 20px">
<el-checkbox-group v-model="yourAnswer" size="mini">
<el-checkbox label="A" border>A: {{options.option1.desc}}</el-checkbox> <br/>
<el-checkbox label="B" border>B: {{options.option2.desc}}</el-checkbox> <br/>
<el-checkbox label="C" border>C: {{options.option3.desc}}</el-checkbox> <br/>
<el-checkbox label="D" border>D: {{options.option4.desc}}</el-checkbox>
</el-checkbox-group>
</div>
</div>
<!-- 判断题选项模块 -->
<div v-if="isShow(quesType,'judge')">
<div style="margin-top: 20px">
<el-radio-group v-model="yourAnswer" size="mini" >
<el-radio label="A" border >A: 正确</el-radio> <br/>
<el-radio label="B" border >B: 错误</el-radio>
</el-radio-group>
</div>
</div>
</div>
</template>
<script>
import { getQuesInfoById } from "@/api/sys";
import { collectOne } from "@/api/user";
export default {
name: "SingleQuestion",
data() {
return {
quesInfo: {},
quesType: "",
quesLevel:"",
quesSource:"",
quesContent:"",
options:{},
yourAnswer:[],
collected:false
};
},
props: ["quesId","yourAns"],
computed: {
userId(){
return this.$store.state.userInfo.userId
},
collectIcon(){
return this.collected?"el-icon-star-on":"el-icon-star-off"
}
},
methods: {
// 收藏/取消收藏操作
collectOne(){
if (this.collected) {
// 取消收藏
collectOne(this.userId,this.quesId,this.quesType,"del")
this.$message({
message: '取消收藏!',
type: 'success'
});
this.collectIcon = "el-icon-star-off"
}else {
// 收藏
collectOne(this.userId,this.quesId,this.quesType,"add")
this.$message({
message: '收藏成功!',
type: 'success'
});
this.collectIcon = "el-icon-star-on"
}
this.collected = !this.collected
},
getTypeName(type){
switch(type) {
case ("single_select"): return "选择题"
case ("multi_select"): return "多选题"
case ("judge"): return "判断题"
case ("discuss"): return "简答题"
}
},
getLevel(level) {
switch(level) {
case ("easy"): return "简单"
case ("middle"): return "中等"
case ("hard"): return "困难"
}
},
getOptions(detail){
return {
option1 : {
desc : detail.option1,
checked : false
},
option2 : {
desc : detail.option2,
checked : false
},
option3 : {
desc : detail.option3,
checked : false
},
option4 : {
desc : detail.option4,
checked : false
},
}
},
/** 根据题目类型是否展示 */
isShow(quesType,typediv){
return quesType == typediv
},
/** 刷新data中的题目信息 */
reFlashInfo(userId,quesId){
this.getSingleQuestion(userId,quesId).then((res) => {
console.log("detail: " + JSON.stringify(res))
this.quesInfo = JSON.parse(JSON.stringify(res));
// 给data中的元素重新赋值
this.quesType = this.quesInfo.quesType
this.quesLevel = this.getLevel(this.quesInfo.quesLevel)
this.quesSource = this.quesInfo.quesSource
this.quesContent = this.quesInfo.quesContent
this.options = this.getOptions(this.quesInfo)
this.yourAnswer = []
this.collected = this.quesInfo.collected
});
},
/** 获取题目信息 */
async getSingleQuestion(userId,quesId) {
return await getQuesInfoById(userId,quesId);
},
},
created() {
// 获取题目的所有信息展示
this.reFlashInfo(this.userId,this.quesId)
},
watch: {
quesId: function (newquesId) {
this.reFlashInfo(this.userId,newquesId)
},
yourAnswer: function(newAns){
this.$emit("getAns",this.quesId,newAns)
}
}
};
</script>
<style>
.headInfo td{
padding: 5px;
width: 50px;
text-align: left;
}
</style>
\ No newline at end of file
<template>
<div>
<el-row>
<el-col :span="5"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="14" :offset="5"><div class="grid-content bg-purple-light">
<el-card class="box-card" style="margin:auto;width: 800px;">
<div slot="header" class="clearfix">
<span>{{name}}问题专项练习</span>
</div>
<el-tag type="info"> 做题进度:{{nowIndex+1}}/{{quesCnt}}</el-tag>
<!-- 这里每次用一个题目ID来放单个题目的组件视图,通过prop传递参数,传递函数获取子组件的答案 -->
<!-- <SingleQuestion :nowIndex="nowIndex" :quesCnt="quesCnt" :quesId="nowId" :yourAns="ans" @getAns="getChildRes" /> -->
<SingleQuestion :quesId="nowId" :yourAns="ans" @getAns="getChildRes" />
<el-button type="primary" plain @click="nowIndex--" :disabled="beforeButton">上一题</el-button>
<el-button type="success" plain @click="nowIndex++" :disabled="afterButton">下一题</el-button>
<el-button type="success" plain @click="submitAns()" :display="submitButton">交卷</el-button>
</el-card>
</div></el-col>
<el-col :span="5"><div class="grid-content bg-purple">
做题情况:<br/>
<el-progress type="circle" :percentage="this.process" style="left:50px;padding;:20px"></el-progress> <br/>
答题卡
<div >
<el-button :id="setId(i)" v-for="i in quesCnt" :key="i" @click="toi(i)" >{{i}}</el-button>
</div>
</div></el-col>
</el-row>
</div>
</template>
<script>
import SingleQuestion from './QuestionTemplate'
export default {
name : "QuestionDetail",
data(){
return {
nowIndex:0,
quesCnt : (JSON.parse(this.IdListInfo)).quesCnt,
quesIdList : (JSON.parse(this.IdListInfo)).lt,
answers : new Map(),
process: 0,
}
},
props:['name','classes','IdListInfo'],
components:{
SingleQuestion
},
computed:{
beforeButton(){
return this.nowIndex === 0;
},
afterButton(){
return this.nowIndex === this.quesCnt-1;
},
submitButton(){
return 'false';
},
nowId(){
return this.quesIdList[this.nowIndex];
},
ans(){
if (this.answers.has(this.nowId)){
return this.answers.get(this.nowId);
}
return [];
}
},
methods : {
getCardCellType(i){
let id = this.quesIdList[i-1];
if (this.answers.has(id)) {
let item = this.answers.get(id)
if (item==''){
return ""
}else {
return "success"
}
}else {
return ""
}
},
setCardCellType(quesId){
// 获取quesIdList中index
let index = 1
for (let item of this.quesIdList){
if (item == quesId)
break;
index += 1
}
let card = document.getElementById("Card"+index)
// 设置type样式
let tmp = this.getCardCellType(index)
if (tmp == "success"){
card.setAttribute("class","el-button el-button--success")
}else {
card.setAttribute("class","el-button el-button--default")
}
},
setId(i){
return "Card"+i;
},
getDoneCnt(){
let cnt = 0
for (let item of this.answers){
if (typeof(item[1]) == "object") {
if (item[1].length != 0) {
cnt += 1
}
}else {
cnt += 1
}
}
return cnt
},
toi(i){
this.nowIndex = i-1
},
submitAns(){
//提交answer中的数据进行判断,然后跳转到新的一个结果页面
const yourAnsList = this.map2list(this.answers)
//传quesList,quesCnt
this.$router.push({
path:"/answerResults",
query:{
quesCnt:this.quesCnt,
quesIdList:this.quesIdList,
yourAnsList: JSON.stringify(yourAnsList)
}
})
},
getChildRes(quesId,ans){
this.answers.set(quesId,ans) // 设置答案
this.setCardCellType(quesId) // 设置右侧跳转框类型
this.process = parseFloat((this.getDoneCnt()*100/this.quesCnt).toFixed(2)) // 计算完成度
},
map2list(ansMap){
const list = []
for (let item of ansMap) {
list.push(item)
}
return list
}
}
}
</script>
<template>
<!-- <div>登录界面</div> -->
<el-row>
<el-col :span="9"><div class="grid-content bg-purple"></div></el-col>
<el-col :span="6" :offset="9">
<div class="grid-content bg-purple-light">
<div class="form">
<div class="inner">
<div>
<img alt="Vue logo" src="../../assets/logo.png" width="130px" />
</div>
<span>用户注册</span> <br />
<el-input v-model="username" placeholder="请输入用户名" autofocus></el-input> <br />
<el-input v-model="psd" placeholder="请输入密码" show-password></el-input> <br />
<el-input v-model="confirmPsd" placeholder="确认密码" show-password></el-input> <br />
<el-button type="primary" round @click="register()">注册</el-button> <br/>
<router-link to="/"><el-link type="info">已有账号,登录</el-link></router-link> <br/>
<el-checkbox v-model="agreed"></el-checkbox>同意<router-link to="/terms">《用户协议》</router-link><router-link to="/private">《隐私协议》</router-link>
</div>
</div>
</div>
</el-col>
<el-col :span="9"><div class="grid-content bg-purple"></div></el-col>
</el-row>
</template>
<script>
import { register,login,uptInfo } from '@/api/user';
import { setToken } from "@/utils/auth"
import { Message } from 'element-ui';
export default {
name: "RegisterPage",
data() {
return {
username: "",
psd: "",
confirmPsd: "",
agreed:false
};
},
computed:{
userId(){
return this.$store.state.userInfo.userId
}
},
methods:{
register(){
if (this.agreed){
if (this.psd != this.confirmPsd) {
Message.warning("两次密码输入不一致!")
}else{
register(this.username,this.psd).then(()=>{
this.autologin(this.username,this.psd)
})
}
}else {
Message.info("请先勾选协议!")
}
},
// 自动登录
autologin(username,password){
login(username,password).then((res) => {
if (res.code == 200){
setToken(res.token)
let userId = res.userId
this.$store.state.userInfo.userId = userId;
this.$store.state.userInfo.nikeName = username;
this.$store.state.islogin = true;
let time = this.formatDate()
// 初始化用户个人信息
const info = {
userId:userId,
nikeName:username,
createTime:time
}
uptInfo(JSON.stringify(info))
Message.success("注册成功!")
this.$router.push("/quesBank")
}else {
Message.warning(res.msg)
}
})
},
// 获取当前格式化时间戳
formatDate(){
var datetime = new Date().getTime();
var date = new Date(datetime)// 时间戳为10位需*1000,时间戳为13位的话不需乘1000
var year = date.getFullYear()
var month = ('0' + (date.getMonth() + 1)).slice(-2)
var sdate = ('0' + date.getDate()).slice(-2)
var hour = ('0' + date.getHours()).slice(-2)
var minute = ('0' + date.getMinutes()).slice(-2)
var second = ('0' + date.getSeconds()).slice(-2)
// 拼接
var result = year + '-' + month + '-' + sdate + ' ' + hour + ':' + minute + ':' + second
// 返回
return result
}
}
};
</script>
<style scoped>
.form {
width: 380px;
height: 540px;
border-radius: 30px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.inner {
width: 300px;
height: 430px;
padding-top: 70px;
margin: auto;
}
</style>
\ No newline at end of file
<template>
<div>这是用户协议</div>
</template>
<script>
export default {
name:"TermsPage"
}
</script>
<style>
</style>
\ No newline at end of file
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router' // 引入路由
import router from './router';
// 下面两行引入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import store from './store' // 引入store
// 关闭生产提示
Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.use(ElementUI)
new Vue({
render: h => h(App),
router,
store
}).$mount('#app')
// 专门用于创建vue-router 路由器
import VueRouter from 'vue-router'
// 引入组件
import HomePage from '../components/HomePage'
import LoginPage from '../components/Login'
import RegisterPage from '../components/Register'
import TermsPage from '../components/Terms'
import PrivatePage from '../components/Private'
import QuestionBank from '../components/QuestionBank'
import QuestionDetail from '../components/QuestionDetail'
import AnswerResults from '@/components/QuestionDetail/AnswerResults'
import PaperBank from '../components/PaperBank'
import PersonalCenter from '../components/Personal'
import PersonalInfo from '@/components/Personal/PersonalInfo'
import PersonalHistory from '@/components/Personal/PersonalHistory'
import PersonalCollected from '@/components/Personal/PersonalCollected'
import SituationAnalysis from '@/components/Personal/SituationAnalysis'
import OneQuestion from '@/components/Personal/OneQuestion'
// 创建并暴露一个路由器
export default new VueRouter({
routes: [
{ //设置默认主页
path: '/',
redirect: '/login'
},
{ // 主页
path: '/home',
component: HomePage
},
{ // 登录页面
path: '/login',
component: LoginPage
},
{ // 注册页面
path: '/register',
component: RegisterPage
},
{ // 用户协议
path: '/terms',
component: TermsPage
},
{ // 隐私协议
path: '/private',
component: PrivatePage
},
{ // 题库页面
path: '/quesBank',
component: QuestionBank
},
{ // 问题详情页面
name: "QuestionDetail",
path: '/questionDetail',
component: QuestionDetail,
// props : true
props({
query: {
name,
classes,
IdListInfo
}
}) {
return {
name,
classes,
IdListInfo
}
}
},
{ // 答题结果展示页面
path:"/answerResults",
component : AnswerResults,
props({query:{quesCnt,quesIdList,yourAnsList}}){
return {
quesCnt,
quesIdList,
yourAnsList
}
}
},
{ // 单个题目页面
path:"/oneQuestion",
name:"oneQuestion",
component:OneQuestion,
props($router){
return {
itemInfo:$router.params.itemInfo
}
}
},
{ // 试卷库界面
path: '/paper',
component: PaperBank
},
{ // 个人中心
path: '/personal',
redirect:'/personal/history', // 个人中心默认页
component: PersonalCenter,
children:[
{
path:"info", // 个人信息页面
component:PersonalInfo
},
{
path:"history", // 历史记录页面
component:PersonalHistory
},
{
path:"collected", // 收藏列表
component:PersonalCollected
},
{
path:"analysis", // 做题分析
component:SituationAnalysis
},
]
}
]
})
\ No newline at end of file
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// dispatch
const actions = {
}
// commit
const mutations = {
setLogin(state, value) {
state.islogin = value
}
}
// data
const state = {
islogin:false, // 登录状态
userInfo:{
userId:"", // 用户id
nikeName:"", // 用户昵称
realName:"", // 真实姓名
gender:"", // 性别
tel:"", // 电话号码
email:"", // 邮箱
introduction:"", //个人简介
createTime:"", // 创建时间
}
}
// computed
const getters = {
}
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
import Cookies from 'js-cookie';
const TokenKey = 'Token';
export function getToken () {
return Cookies.get(TokenKey);
}
export function setToken (token) {
return Cookies.set(TokenKey, token);
}
export function removeToken () {
return Cookies.remove(TokenKey);
}
/**** http.js ****/
// 导入封装好的axios实例
import request from './request'
const http = {
/** * methods: 请求 * @param url 请求地址 * @param params 请求参数 */
get(url, params) {
const config = {
method: 'get',
url: url
}
if (params) config.params = params
return request(config)
},
post(url, params) {
const config = {
method: 'post',
url: url
}
if (params) config.data = params
return request(config)
},
put(url, params) {
const config = {
method: 'put',
url: url
}
if (params) config.data = params
return request(config)
},
delete(url, params) {
const config = {
method: 'delete',
url: url
}
if (params) config.data = params
return request(config)
}
}
//导出
export default http
\ No newline at end of file
/**** request.js ****/
// 导入axios
import axios from 'axios'
// 使用element-ui Message做消息提醒
import {
Message
} from 'element-ui';
import { getToken,removeToken } from './auth';
//1. 创建新的axios实例,
const service = axios.create({
// 公共接口--这里注意后面会讲
baseURL: '/api', //把原来的项目地址,改成api,解决跨域问题
// 超时时间 单位是ms,这里设置了8s的超时时间
timeout: 8 * 1000
})
// 2.请求拦截器
service.interceptors.request.use(config => {
//发请求前做的一些处理,数据转化,配置请求头,设置token,设置loading等,根据需求去添加
config.data = JSON.stringify(config.data); //数据转化,也可以使用qs转换
config.headers = {
'Content-Type': 'application/json', //配置请求头
'Access-Control-Allow-Origin': "*"
}
//如有需要:注意使用token的时候需要引入cookie方法或者用本地localStorage等方法,推荐js-cookie
const token = getToken() //这里取token之前,你肯定需要先拿到token,存一下
if(token){
// config.params = {'token':token} //如果要求携带在参数中
config.headers.token= token; //如果要求携带在请求头中
}
return config
}, error => {
Promise.reject(error)
})
// 3.响应拦截器
service.interceptors.response.use(response => {
//接收到响应数据并成功后的一些共有的处理,关闭loading等
return response;
}, error => {
/***** 接收到异常响应的处理开始 *****/
if (error && error.response) {
// 1.公共错误处理
// 2.根据响应码具体处理
switch (error.response.status) {
case 400:
error.message = '错误请求'
break;
case 401:
error.message = '未授权,请重新登录'
// 清除token, 返回到登录界面
removeToken()
Message({
message:"未授权,请重新登录",
type:"warning"
})
var t = 0
window.setInterval(function(){
t++;
if (t == 1) {
window.location.href = "/"
}
},1000)
// window.location.href = "/"
break;
case 403:
error.message = '拒绝访问'
break;
case 404:
error.message = '请求错误,未找到该资源'
window.location.href = "/NotFound"
break;
case 405:
error.message = '请求方法未允许'
break;
case 408:
error.message = '请求超时'
break;
case 500:
error.message = '服务器端出错'
break;
case 501:
error.message = '网络未实现'
break;
case 502:
error.message = '网络错误'
break;
case 503:
error.message = '服务不可用'
break;
case 504:
error.message = '网络超时'
break;
case 505:
error.message = 'http版本不支持该请求'
break;
default:
error.message = `连接错误${error.response.status}`
}
} else {
// 超时处理
if (JSON.stringify(error).includes('timeout')) {
Message.error('服务器响应超时,请刷新当前页')
}
error.message = '连接服务器失败'
}
Message.error(error.message)
/***** 处理结束 *****/
//如果不需要错误处理,以上的处理过程都可省略
return Promise.resolve(error.response)
})
//4.导入文件
export default service
\ No newline at end of file
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
transpileDependencies: true,
devServer: {
// 配置端口
port: 4444,
// 不检查host
// disableHostCheck: true,
https:false,
// 配置代理
proxy: {
'/api': {
// 配置URL
target: 'http://120.26.50.171:5555',
// 是否允许跨域
changeOrigin: true,
// 请求重写,替换成空串
pathRewrite: {
'^/api': ''
}
}
}
}
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册