答题完整代码

This commit is contained in:
Strange 2024-08-27 17:24:44 +08:00
parent d3ce47bd52
commit 23cb65e721
17 changed files with 988 additions and 698 deletions

View File

@ -1,2 +1,2 @@
# VITE_APP_BASE_API = 'http://127.0.0.1:8088' # VITE_APP_BASE_API = 'http://127.0.0.1:8088'
VITE_APP_BASE_API = 'http://aw.9miao.fun/prod-api' VITE_APP_BASE_API = 'https://xuaua.com/prod-api'

View File

@ -1 +1 @@
VITE_APP_BASE_API = 'http://aw.9miao.fun/prod-api' VITE_APP_BASE_API = 'https://xuaua.com/prod-api'

View File

@ -2,10 +2,10 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/logo.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="//unpkg.com/@element-plus/icons-vue"></script> <script src="//unpkg.com/@element-plus/icons-vue"></script>
<title>Vite App</title> <title>Xuaxua</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

47
package-lock.json generated
View File

@ -12,7 +12,9 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"element-plus": "^2.7.7", "element-plus": "^2.7.7",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"swiper": "^8.4.7",
"vue": "^3.4.29", "vue": "^3.4.29",
"vue-awesome-swiper": "^5.0.1",
"vue-router": "^4.3.3" "vue-router": "^4.3.3"
}, },
"devDependencies": { "devDependencies": {
@ -1371,6 +1373,14 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/dom7": {
"version": "4.0.6",
"resolved": "https://registry.npmmirror.com/dom7/-/dom7-4.0.6.tgz",
"integrity": "sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==",
"dependencies": {
"ssr-window": "^4.0.0"
}
},
"node_modules/element-plus": { "node_modules/element-plus": {
"version": "2.7.7", "version": "2.7.7",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.7.7.tgz", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.7.7.tgz",
@ -2654,6 +2664,11 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/ssr-window": {
"version": "4.0.2",
"resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-4.0.2.tgz",
"integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ=="
},
"node_modules/strip-ansi": { "node_modules/strip-ansi": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@ -2702,6 +2717,29 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/swiper": {
"version": "8.4.7",
"resolved": "https://registry.npmmirror.com/swiper/-/swiper-8.4.7.tgz",
"integrity": "sha512-VwO/KU3i9IV2Sf+W2NqyzwWob4yX9Qdedq6vBtS0rFqJ6Fa5iLUJwxQkuD4I38w0WDJwmFl8ojkdcRFPHWD+2g==",
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/swiperjs"
},
{
"type": "open_collective",
"url": "http://opencollective.com/swiper"
}
],
"hasInstallScript": true,
"dependencies": {
"dom7": "^4.0.4",
"ssr-window": "^4.0.2"
},
"engines": {
"node": ">= 4.7.0"
}
},
"node_modules/text-table": { "node_modules/text-table": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -3016,6 +3054,15 @@
} }
} }
}, },
"node_modules/vue-awesome-swiper": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/vue-awesome-swiper/-/vue-awesome-swiper-5.0.1.tgz",
"integrity": "sha512-mWjFJzUqA4lG+DmsmibvMpoiBnl+IH2SSeiiQ3i5M0t1y9FknTxnGT0DsMb2YdJLgjYMEK3sYOWzqgLnZMH8Lg==",
"peerDependencies": {
"swiper": "^7.0.0 || ^8.0.0",
"vue": "3.x"
}
},
"node_modules/vue-eslint-parser": { "node_modules/vue-eslint-parser": {
"version": "9.4.3", "version": "9.4.3",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",

View File

@ -14,7 +14,9 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"element-plus": "^2.7.7", "element-plus": "^2.7.7",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"swiper": "^8.4.7",
"vue": "^3.4.29", "vue": "^3.4.29",
"vue-awesome-swiper": "^5.0.1",
"vue-router": "^4.3.3" "vue-router": "^4.3.3"
}, },
"devDependencies": { "devDependencies": {

View File

@ -8,4 +8,7 @@ import { RouterView } from 'vue-router'
</template> </template>
<style scoped> <style scoped>
img{
width: 60%;
}
</style> </style>

View File

@ -1,4 +1,5 @@
import http from "@/utils/http"; import http from "@/utils/http";
import keyboard from "uview-ui/libs/config/props/keyboard";
//获取题目 //获取题目
export const getQuestion= (type)=>{ export const getQuestion= (type)=>{
if(type==null||type==undefined){ if(type==null||type==undefined){
@ -47,3 +48,20 @@ export const validationAnswer = ({questionId,answer})=>{
} }
}) })
} }
export const answered = (questionId)=>{
return http({
url:"/question/answered",
method:"get",
params:{
questionId
}
})
}
export const searchQuestion = (data)=>{
return http({
url:"/search",
method:"get",
params:data
})
}

View File

@ -1,13 +1,19 @@
<template> <template>
<div class="topicInfoBox"> <div class="topicInfoBox">
<div class="introduce title"> <!-- <el-image :src="question.questionImage" style="width: 80%;pointer-events: none;"></el-image> -->
<!-- <div class="introduce title">
[{{ props.type == "select" ? "选择题" : "填空题" }}]{{ props.introduce }} [{{ props.type == "select" ? "选择题" : "填空题" }}]{{ props.introduce }}
</div> </div>
<div class="introduce tag"> <div class="introduce tag">
<el-tag v-for="itme in props.tags" :key="itme.name" type="primary">{{ itme.name}}</el-tag>&nbsp; <el-tag v-for="itme in props.tags" :key="itme.name" type="primary">{{
itme.name
}}</el-tag
>&nbsp;
</div> </div>
<div class="introduce hod" > <div class="introduce hod" >
{{ props.topicTitle }} <div v-html="props.topicTitle" style="width: 400px;">
</div>
</div> </div>
<div class="introduce"> <div class="introduce">
<el-radio-group v-if="props.type != 'fill_topic'" v-model="radio"> <el-radio-group v-if="props.type != 'fill_topic'" v-model="radio">
@ -18,19 +24,25 @@
>{{ itme.key + "." + itme.name }}</el-radio >{{ itme.key + "." + itme.name }}</el-radio
> >
</el-radio-group> </el-radio-group>
<el-input v-else v-model="radio" type="textarea" :rows="2" placeholder="请输入内容" ></el-input> <el-input
v-else
v-model="radio"
type="textarea"
:rows="2"
placeholder="请输入内容"
></el-input>
</div> </div>
<div class="introduce"> -->
<el-button v-if="radio != null" type="success" @click="tupClick">提交</el-button> <div class="button">
<el-button type="primary" @click="tupClick"
>作答</el-button
>
</div> </div>
<div v-if="native.isAnswer" class="introduce jg"> <!-- <el-button type="primary" style="z-index: 9;" @click="show=true">查看答案</el-button>
已作答,<span v-if="!native.correct" style="color: red;">答案错误</span> <div class="introduce jg" v-if="show">
<span v-else style="color: rgb(17, 255, 0);">答案正确</span><br>
<br>
<span>你的答案{{ native.userAnswer }}</span><br>
<br>
<span>正确答案{{ ArrayToString(native.correctAnswer) }}</span> <span>正确答案{{ ArrayToString(native.correctAnswer) }}</span>
</div> </div> -->
</div> </div>
</template> </template>
<script setup> <script setup>
@ -38,7 +50,8 @@ import { onMounted, ref } from "vue";
import { useTopicStore } from "@/stores/topic.js"; import { useTopicStore } from "@/stores/topic.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const topStore = useTopicStore(); const topStore = useTopicStore();
const radio = ref(''); const radio = ref("");
const show = ref(false);
const props = defineProps({ const props = defineProps({
id: { type: Number, default: null }, id: { type: Number, default: null },
videoUrl: { type: String, default: null }, videoUrl: { type: String, default: null },
@ -53,12 +66,18 @@ const props = defineProps({
default: () => { default: () => {
return { return {
isAnswer: false, isAnswer: false,
analysis:'解析', analysis: "解析",
correctAnswer:'正确答案', correctAnswer: "正确答案",
// //
correct: false, correct: false,
} };
} },
},
question: {
type: Object,
default: () => {
return {};
},
}, },
type: { type: String, default: null }, type: { type: String, default: null },
topicTitle: { type: String, default: "题目" }, topicTitle: { type: String, default: "题目" },
@ -66,13 +85,10 @@ const props = defineProps({
tags: { type: Array, default: null }, tags: { type: Array, default: null },
}); });
const tupClick = async () => { const tupClick = async () => {
if(radio.value==null){
ElMessage.error("请选择答案");
}
console.log("radio.value",radio.value)
let res = await topStore.submitAnswer(radio.value); let res = await topStore.submitAnswer(radio.value);
console.log("res",res);''
} };
const ArrayToString = (arr) => { const ArrayToString = (arr) => {
if (arr instanceof Array) { if (arr instanceof Array) {
return arr.join(","); return arr.join(",");
@ -81,28 +97,40 @@ const ArrayToString=(arr)=>{
} else { } else {
return arr; return arr;
} }
} };
const topicSelect = ref([]); const topicSelect = ref([]);
console.log("props.native", props.question);
onMounted(() => { onMounted(() => {
topicSelect.value = props.topicList; topicSelect.value = props.topicList;
radio.value = props.native.userAnswer ? props.native.userAnswer : null; radio.value = props.native.userAnswer ? props.native.userAnswer : null;
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.button{
z-index: 99;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-end;
}
.topicInfoBox { .topicInfoBox {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-family: "KaiTi" font-family: "KaiTi";
} }
.introduce { .introduce {
z-index: 9;
margin: 10px auto; margin: 10px auto;
width: 90%; width: 90%;
word-break: normal; word-break: normal;
word-wrap: break-word; word-wrap: break-word;
img {
width: 60%;
}
} }
.title { .title {
font-size: 17px; font-size: 17px;

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="video-container"> <div class="video-container">
<video <video
style="height: inherit;"
ref="videoRef" ref="videoRef"
:src="props.src" :src="props.src"
width="100%" width="100%"
@ -49,8 +50,9 @@
.video-container { .video-container {
position: relative; position: relative;
width: 100%; width: 100%;
max-width: 640px; /* 可以根据需要调整 */ max-width: 100%; /* 可以根据需要调整 */
/* margin: 0 auto; */ height: 100%;
margin: 0 auto;
} }
button { button {

View File

@ -1,115 +1,141 @@
<template> <template>
<div class="nav"> <div class="nav">
<div class="logo-box"><span class="loogText">Xuaua</span></div> <div class="logo-box">
<span class="logo-text" v-if="pageType!='view'">Xuaua</span>
<span class="logo-text" v-else @click="goback">
<svg t="1724411009623" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6748" width="48" height="48"><path d="M512 65C264.66 65 65 264.66 65 512s199.66 447 447 447 447-199.66 447-447S759.34 65 512 65z m253.32 470.93h-0.8c-18.93 0.42-37.92 0-56.85 0H312.21l88.31 86.91 64.68 63.66c9.53 9.38 8.71 24.35 0 33.84s-24.91 8.79-33.84 0L407.69 697l-103.1-101.43-64.69-63.66c-9.28-9.14-9-24.69 0-33.84l23.52-23.88 103.15-104.74 64.79-65.79c9.38-9.53 24.35-8.71 33.84 0s8.79 24.91 0 33.84l-23.52 23.88q-51.57 52.38-103.15 104.74l-21.44 21.77c12.44 0 24.88 0.18 37.3 0.18h410.93c13.41 0 23.35 11 23.93 23.93s-11.41 23.93-23.93 23.93z" p-id="6749" fill="#e6e6e6"></path></svg>
</span>
</div>
<div> <div>
<el-popover :width="700" trigger="click">
<template #reference>
<div class="search-box"> <div class="search-box">
<div class="selectInput"> <div class="selectInput">
<div @click="selectClick"> <div>
<el-icon :size="20"> <el-icon :size="20">
<Search /> <Search />
</el-icon> </el-icon>
</div> </div>
<input type="text" placeholder="搜索关键词" v-model="type" /> <input type="text" @click="goSearch" placeholder="搜索关键词" />
</div> </div>
</div> </div>
</template>
<TypeSelect @select="selectInput" :type="type"></TypeSelect>
</el-popover>
</div> </div>
<div @click="toUser" class="user-avatar"> <div @click="toUser" class="user-avatar">
<el-avatar :size="40" :src="useSotr.avatar" />{{ useSotr.username }} <el-avatar :size="40" :src="user.avatar" />{{ user.nickname || "用户" }}
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
// import {defineProps} from "vue"
import TypeSelect from "@/components/TypeSelect.vue";
import { debounceRef } from "@/utils/debounceRef";
import router from "@/router";
import { useTopicStore } from "@/stores/topic.js";
import { useUserStore } from "@/stores/user.js"; import { useUserStore } from "@/stores/user.js";
import { useTopicStore } from "@/stores/topic.js";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import "element-plus/theme-chalk/el-message.css";
const useSotr=useUserStore();
const topStore = useTopicStore();
// import { ref } from 'vue'
import { Search } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import router from "@/router";
import { debounceRef } from "@/utils/debounceRef";
import {computed, defineProps,defineEmits} from "vue"
const useSotr = useUserStore();
const emit = defineEmits(["back"])
const user = computed(() => {
return useSotr.user;
});
const topStore = useTopicStore();
const type = debounceRef("", 300); const type = debounceRef("", 300);
const selectInput = (a) => { const {pageType} = defineProps({
type.value = a; pageType:{
}; type:String,
default:''
}
})
function goback(){
// router.go(-1);
emit("back")
}
const toUser = () => { const toUser = () => {
router.push({ router.push({
path:"/user" path: "/user",
}) });
} };
const goSearch = () => {
router.replace({
path: "/search",
});
};
const selectClick = () => { const selectClick = () => {
// console.log("")
console.log("123",useSotr)
topStore.loadData(type.value); topStore.loadData(type.value);
ElMessage({ message: "已切换标签", type: "success" }); ElMessage({ message: "已切换标签", type: "success" });
};
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.selectInput {
display: flex;
width: 100%;
height: 100%;
padding: 7px 10px;
border: 2px #000000 solid;
border-radius: 30px;
input {
background-color: #00000000; /* 透明背景 */
border: none; /* 无边框 */
outline: none; /* 去除聚焦时的轮廓 */
padding: 0; /* 无内边距 */
margin: 0; /* 无外边距 */
width: 100%;
}
}
.nav { .nav {
width: 100%; width: 100%;
height: 70px; height: 70px;
background-color: #fff; background: linear-gradient(135deg, #409eff, #66b1ff);
border-radius: 0 0 15px 15px;
display: flex; display: flex;
// justify-content: space-between;
align-items: center; align-items: center;
padding: 0 20px;
.logo-box { .logo-box {
margin-top: 11px;
margin-left: 52px; margin-left: 52px;
margin-bottom: 11px; .logo-text {
font-size: 30px;
font-weight: bold;
color: #ffffff;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
} }
.input-with-select {
border-radius: 30px;
} }
.search-box { .search-box {
position: relative; position: relative;
left: 210px; margin-left: 30px;
border-radius: 30px; margin-right: auto;
overflow: hidden;
padding: 5px; padding: 5px;
background: #fefefe;
// .search-input{
// width: 400px;
// height: 38px;
// border-radius: 30px;
// }
} }
div {
.selectInput {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; padding: 7px 15px;
border: 2px solid #ffffff;
border-radius: 30px;
background-color: rgba(255, 255, 255, 0.1);
transition: background-color 0.3s ease, border-color 0.3s ease;
&:hover {
background-color: rgba(255, 255, 255, 0.3);
border-color: #dcdfe6;
} }
input {
background-color: transparent;
border: none;
outline: none;
color: #ffffff;
margin-left: 10px;
font-size: 16px;
width: 100%;
&::placeholder {
color: #dcdfe6;
}
}
.el-icon {
color: #ffffff;
}
}
.user-avatar { .user-avatar {
position: absolute; position: absolute;
right: 2%; right: 20px;
} display: flex;
.loogText { align-items: center;
font-size: 30px; cursor: pointer;
margin-left: 10px; color: #ffffff;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
} }
} }
</style> </style>

View File

@ -1,21 +1,26 @@
import './assets/main.css' import { createApp } from 'vue';
import { createPinia } from 'pinia';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import App from './App.vue';
import router from './router';
import './assets/main.css';
import 'swiper/css';
const app = createApp(App);
import { createApp } from 'vue' import VueAwesomeSwiper from 'vue-awesome-swiper'
import { createPinia } from 'pinia' import 'swiper/swiper-bundle.css'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
// 如果您正在使用CDN引入请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App) // import 'swiper/swiper-bundle.css'
app.use(VueAwesomeSwiper)
app.use(createPinia());
app.use(router);
app.use(ElementPlus);
app.use(createPinia()) // Register Element Plus icons globally
app.use(router) Object.entries(ElementPlusIconsVue).forEach(([key, component]) => {
app.use(ElementPlus) app.component(key, component);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { });
app.component(key, component)
}
app.mount('#app') app.mount('#app');

View File

@ -2,7 +2,7 @@ import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router'
import TokenService from '@/utils/token' import TokenService from '@/utils/token'
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL), history: createWebHashHistory(),
routes: [ routes: [
{ {
path: '/', path: '/',
@ -18,6 +18,10 @@ const router = createRouter({
path: '/user', path: '/user',
name: 'USER', name: 'USER',
component: () => import('@/views/user/index.vue') component: () => import('@/views/user/index.vue')
},
{
path:"/search",
component:()=>import('@/views/search/index.vue')
} }
] ]
}) })

View File

@ -1,15 +1,22 @@
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from "vue";
import { defineStore } from 'pinia' import { defineStore } from "pinia";
import { getQuestionByTagName ,validationAnswer} from '@/api/question/question' import {
import {collect, cancelCollect ,getCollectList} from '@/api/collect/collect' getQuestionByTagName,
validationAnswer,
getQuestion,
answered,
} from "@/api/question/question";
import { collect, cancelCollect, getCollectList } from "@/api/collect/collect";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import "element-plus/theme-chalk/el-message.css"; import "element-plus/theme-chalk/el-message.css";
import router from "@/router";
import { ElLoading } from 'element-plus'
// import { fa } from 'element-plus/es/locale'; // import { fa } from 'element-plus/es/locale';
export const useTopicStore = defineStore('useTopicStore', () => { export const useTopicStore = defineStore("useTopicStore", () => {
//当前标签 //当前标签
const tagName = ref(''); const tagName = ref("");
//当前索引 //当前索引
const index = ref(1); const index = ref(0);
//题目列表 //题目列表
const Topics = ref([]); const Topics = ref([]);
//当前题目 //当前题目
@ -20,10 +27,11 @@ export const useTopicStore = defineStore('useTopicStore', () => {
const collectTopics = ref([]); const collectTopics = ref([]);
//收藏列表id //收藏列表id
const collectTopicIds = computed(() => { const collectTopicIds = computed(() => {
return collectTopics.value.map(item=>item.id); return collectTopics.value.map((item) => item.id);
}) });
const count = computed(() => Topics.value.length); const count = computed(() => Topics.value.length);
const init = () => { const init = () => {
index.value = 0;
if (Topics.value.length == 0) { if (Topics.value.length == 0) {
CollectList(); CollectList();
getData(); getData();
@ -31,56 +39,101 @@ export const useTopicStore = defineStore('useTopicStore', () => {
} else { } else {
console.log("已存在"); console.log("已存在");
} }
};
} const setQuestion = (question) => {
CollectList();
Topics.value = [];
Topic.value = question;
Topics.value.push({
...question,
isCollect: collectTopicIds.value.includes(question.id),
});
};
const setQuestions = (questions,item) => {
CollectList();
index.value =0
Topics.value = [];
Topic.value = item;
questions.forEach(e => {
Topics.value.push({
...e,
isCollect: collectTopicIds.value.includes(e.id),
});
});
};
//获取题目
//设置标签 //设置标签
const setTagName = (name) => { const setTagName = (name) => {
tagName.value = name; tagName.value = name;
} };
//根据传入标签情况判断是刷新还是加载 //根据传入标签情况判断是刷新还是加载
const loadData = async (name) => { const loadData = async (name) => {
if (name === tagName.value) { if (name === tagName.value) {
await getData(); await getData();
} else { } else {
setTagName(name) setTagName(name);
await refresh(); await refresh();
} }
} };
//刷新 //刷新
const refresh = async () => { const refresh = async () => {
clear(); clear();
let res=await getQuestionByTagName(tagName.value); let res = await getQuestion("refresh");
if (res.code == 200) { if (res.code == 200) {
res.data=res.data.map(e=>{ if (res.data.length == 0) {
ElMessage({ message: "题库为空你已经打完所有题目", type: "warning" });
return;
}
res.data = res.data.map((e) => {
return { return {
...e, ...e,
isCollect:collectTopicIds.value.includes(e.id), // isCollect: collectTopicIds.value.includes(e.id),
};
}}) });
Topics.value = res.data; Topics.value = res.data;
index.value = Topics.value.length > 0 ? 1 : 0; index.value = Topics.value.length > 0 ? 1 : 0;
} }
} };
//加载数据 //加载数据
const getData = async () => { const getData = async () => {
let res=await getQuestionByTagName(tagName.value); const loadingInstance = ElLoading.service()
let res = await getQuestion();
if (res.code == 200) { if (res.code == 200) {
res.data=res.data.map(e=>{ if (res.data.length == 0) {
ElMessage({ message: "题库为空你已经打完所有题目", type: "warning" });
res.data = [
{
id: 0,
question: "没有题目了",
analysis: "没有题目了",
correctAnswer: "没有题目了",
correct: false,
userAnswer: "没有题目了",
isAnswer: false,
isCollect: false,
},
];
}
res.data = res.data.map((e) => {
return { return {
...e, ...e,
isCollect:collectTopicIds.value.includes(e.id), // isCollect: collectTopicIds.value.includes(e.id),
};
}}) });
Topics.value = [...Topics.value, ...res.data]; Topics.value = [...Topics.value, ...res.data];
loadingInstance.close()
} }
} };
//清空数据 //清空数据
const clear = () => { const clear = () => {
index.value = 0; index.value = 0;
Topics.value = []; Topics.value = [];
collectTopics.value = []; collectTopics.value = [];
};
}
//提交答案 //提交答案
const submitAnswer = async (answer) => { const submitAnswer = async (answer) => {
//先判断是否已经答过 //先判断是否已经答过
@ -88,34 +141,42 @@ export const useTopicStore = defineStore('useTopicStore', () => {
// ElMessage({ message: "已经做过了", type: "warning" }); // ElMessage({ message: "已经做过了", type: "warning" });
// return; // return;
// } // }
console.log(Topic.value) // console.log(Topic.value);
let res=await validationAnswer({questionId:Topic.value.id,answer}); // let res = await validationAnswer({ questionId: Topic.value.id, answer });
console.log(res); // console.log(res);
if(res.code==200){ // if (res.code == 200) {
setAnswer({ // setAnswer({
isAnswer:true, // isAnswer: true,
analysis:res.data.analysis, // analysis: res.data.analysis,
correctAnswer:res.data.correctAnswer?res.data.correctAnswer:answer, // correctAnswer: res.data.correctAnswer ? res.data.correctAnswer : answer,
correct:res.data.correct, // correct: res.data.correct,
userAnswer:answer // userAnswer: answer,
}); // });
} // }
let res = await answered(Topic.value.id);
} ElMessage({ message: res.msg, type: "info" });
refresh();
};
//设置答题情况 //设置答题情况
const setAnswer=({isAnswer,analysis,userAnswer,correctAnswer,correct})=>{ const setAnswer = ({
isAnswer,
analysis,
userAnswer,
correctAnswer,
correct,
}) => {
Topics.value[index.value - 1] = { Topics.value[index.value - 1] = {
...Topic.value, ...Topic.value,
isAnswer, isAnswer,
analysis, analysis,
correctAnswer, correctAnswer,
correct, correct,
userAnswer userAnswer,
} };
} };
//收藏题目 //收藏题目
const Collect = async () => { const Collect = async () => {
console.log("执行") console.log("执行");
let res; let res;
if (isCollect()) { if (isCollect()) {
res = await cancelCollect(Topic.value.id); res = await cancelCollect(Topic.value.id);
@ -131,7 +192,7 @@ export const useTopicStore = defineStore('useTopicStore', () => {
} }
} }
await CollectList(); await CollectList();
} };
//上一题 //上一题
const prev = () => { const prev = () => {
if (index.value >= 1) { if (index.value >= 1) {
@ -139,7 +200,7 @@ export const useTopicStore = defineStore('useTopicStore', () => {
return true; return true;
} }
return false; return false;
} };
//下一题 //下一题
const next = () => { const next = () => {
index.value++; index.value++;
@ -147,30 +208,54 @@ export const useTopicStore = defineStore('useTopicStore', () => {
index.value = count.value; index.value = count.value;
return false; return false;
} }
const type = router.currentRoute.value.query.type;
if (type == "view") {
return true;
}
if (index.value == count.value) { if (index.value == count.value) {
getData(); getData();
} }
return true; return true;
} };
//获取收藏题目列表 //获取收藏题目列表
const CollectList = async () => { const CollectList = async () => {
let res = await getCollectList(); let res = await getCollectList();
if (res.code == 200) { if (res.code == 200) {
collectTopics.value=res.data.map(item=>item.questionVo); collectTopics.value = res.data.map((item) => item.questionVo);
}
} }
};
//判断是否收藏 //判断是否收藏
const isCollect = () => { const isCollect = () => {
if (count.value == 0) { if (count.value == 0) {
return false; return false;
} }
console.log("123",Topic.value,index.value) console.log("123", Topic.value, index.value);
return collectTopicIds.value.includes(Topic.value.id); return collectTopicIds.value.includes(Topic.value.id);
} };
onMounted(()=>{ // onMounted(() => {
init(); // init();
}) // });
return { index, Topics, count,collectTopics ,collectTopicIds,Topic, return {
setAnswer,loadData,setTagName,refresh,submitAnswer,Collect,isCollect,clear,getData, index,
prev,next,CollectList,init} Topics,
}) count,
collectTopics,
collectTopicIds,
Topic,
setAnswer,
loadData,
setTagName,
refresh,
submitAnswer,
Collect,
isCollect,
clear,
getData,
prev,
next,
CollectList,
init,
setQuestion,
setQuestions
};
});

View File

@ -1,27 +1,24 @@
import { ref, onMounted } from 'vue' import { ref, onMounted, reactive } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { getUserInfo } from '../api/user/user' import { getUserInfo } from '../api/user/user'
export const useUserStore = defineStore('useUserStore', () => { // export const useUserStore = defineStore('useUserStore', () => {
//用户头像 // state: () => ({
const avatar = ref('') // user:{}
const username = ref('') // }),
//手机号 // actions: {
const phone = ref('')
//备注 // },
const remark = ref('') // })
//获取用户信息
const UserInfo = async() => { export const useUserStore = defineStore('useUserStore', {
let res= await getUserInfo(); state: () => ({
console.log("用户信息",res) user:{}
if(res.code==200){ }),
avatar.value=res.data.avatar; actions: {
username.value=res.data.username; UserInfo(){
phone.value=res.data.phone; getUserInfo().then(res => {
remark.value=res.data.remark; this.user = res.data
}
}
onMounted(()=>{
UserInfo();
}) })
return { avatar, username,phone,remark,UserInfo} }
},
}) })

View File

@ -1,43 +1,49 @@
<template> <template>
<div class="homeBox"> <div ref="topicInfoRef" class="scroll-container">
<div
ref="topicInfoItemRef"
:style="{
height: '100%',
width: '100%',
transition: '0.7s',
marginTop: top,
}"
>
<div
v-for="item in questionList"
:key="item.id"
style="overflow: hidden"
class="homeBox"
>
<div> <div>
<xuaua-header></xuaua-header> <xuaua-header :page-type="PageType" @back="PageRest()"></xuaua-header>
</div> </div>
<div class="main"> <div class="main">
<div class="mainBox"> <div class="mainBox">
<div class="topicInfo" ref="topicInfoRef" @click="huadong">
<div <div
ref="topicInfoItemRef" class="topicInfo"
style=" :style="{ backgroundImage: `url(${item.questionImage})` }"
position: absolute; @click="huadong"
height: 100%;
width: 100%;
transition: 0.7s;
"
:style="'top:' + top"
>
<div
v-for="itme in topStore.Topics"
:key="itme.id"
class="topicInfoItem"
> >
<div class="topicInfoItem">
<TopicBox <TopicBox
:id="itme.id" :id="item.id"
:videoUrl="itme.videoUrl" :question="item"
:introduce="itme.introduce" :videoUrl="item.videoUrl"
:tags="itme.tags" :introduce="item.introduce"
:topicTitle="itme.topicTitle" :tags="item.tags"
:type="itme.type" :topicTitle="item.topicTitle"
:topicList="itme.xuauaQuestionAnswerList" :type="item.type"
:native="itme" :topicList="item.xuauaQuestionAnswerList"
:native="item"
/> />
</div> </div>
</div> </div>
</div>
<div class="topicAnswer"> <div class="topicAnswer">
<div class="answerNav"> <div class="answerNav">
<div style="flex: 1;"> <div style="width: 80%; display: flex; justify-content: center">
<el-tabs <el-tabs
style="margin: 0 auto"
v-model="activeName" v-model="activeName"
class="demo-tabs" class="demo-tabs"
@tab-change="handleClick" @tab-change="handleClick"
@ -46,30 +52,32 @@
<el-tab-pane label="解析" name="解析"></el-tab-pane> <el-tab-pane label="解析" name="解析"></el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
<div class="StarIcon" @click="addCollect"> <div class="StarIcon" @click="addCollect">
<el-icon <el-icon
v-if="topStore.Topic?.isCollect == true" v-if="topStore.Topic?.isCollect"
:size="30" :size="30"
color="#FEE082" color="#FEE082"
> >
<!-- <Star /> -->
<StarFilled /> <StarFilled />
</el-icon> </el-icon>
<el-icon v-else :size="30" color="#2B2B2B"> <el-icon v-else :size="30" color="#2B2B2B">
<Star /> <Star />
<!-- <StarFilled /> -->
</el-icon> </el-icon>
{{ topStore.Topic?.isCollect == true ? "已" : "未" }}收藏 {{ topStore.Topic?.isCollect ? "已" : "未" }}收藏
</div> </div>
</div> </div>
<div class="answerInfo"> <div class="answerInfo">
<VideoBox <VideoBox
v-if="activeName == '视频'" v-if="activeName === '视频'"
:src="topStore.Topic?.videoUrl" :src="topStore.Topic?.videoUrl"
></VideoBox> ></VideoBox>
<div class="jiexi" v-else>{{ topStore.Topic.analysis }}</div> <div
class="jiexi"
v-else
v-html="topStore.Topic?.analysis"
></div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -78,103 +86,180 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, computed } from "vue"; import { ref, onMounted, computed, watch, onUnmounted } from "vue";
import xuauaHeader from "@/components/Xuaua_header.vue"; import xuauaHeader from "@/components/Xuaua_header.vue";
import TopicBox from "@/components/TopicBox.vue"; import TopicBox from "@/components/TopicBox.vue";
import VideoBox from "@/components/VideoBox.vue"; import VideoBox from "@/components/VideoBox.vue";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import "element-plus/theme-chalk/el-message.css";
import { useTopicStore } from "@/stores/topic.js"; import { useTopicStore } from "@/stores/topic.js";
import { debounce } from '@/utils/debounceRef' import { debounce } from "@/utils/debounceRef";
import router from "@/router";
import { useUserStore } from "@/stores/user";
const PageType = ref("home");
const topicInfoItemRef = ref(null); const topicInfoItemRef = ref(null);
const topicInfoRef = ref(null);
const topStore = useTopicStore(); const topStore = useTopicStore();
const activeName = ref("视频"); const activeName = ref("视频");
let mouseDown = false; let mouseDown = false;
let lastY = null; let lastY = null;
let currentY = null; let currentY = null;
const questionList = computed(() => {
return topStore.Topics;
});
const top = computed(() => { const top = computed(() => {
const height = topicInfoItemRef?.value?.clientHeight || 0; const height = topicInfoItemRef.value?.clientHeight || 0;
return `-${(topStore.index - 1 < 0 ? 0 : topStore.index - 1) * height}px`; return `-${(topStore.index - 1 < 0 ? 0 : topStore.index - 1) * height}px`;
}); });
const isCollect = computed(() => {
return topStore.isCollect(); const isFlipping = ref(false);
});
const addCollect = () => { const addCollect = () => {
debounce(()=>{ debounce(
// alert(1) () => {
topStore.Collect(); topStore.Collect();
},500,true)(); },
500,
true
)();
}; };
document.addEventListener("mousedown", function (event) {
const setScrollY = (y) => {
if (topicInfoRef.value) {
topicInfoRef.value.scrollTop -= y;
}
};
const flipPage = (y) => {
if (topicInfoRef.value) {
topicInfoRef.value.scrollTop = 0;
if (y < -80) {
if (!topStore.next()) {
ElMessage({ message: "没有更多了", type: "warning" });
}
isFlipping.value = true;
} else if (y > 80) {
if (!topStore.prev()) {
ElMessage({ message: "到顶了", type: "warning" });
}
isFlipping.value = true;
}
}
};
const handleClick = (e) => {
// if (e === "" && !topStore.Topics[topStore.index - 1]?.isAnswer) {
// ElMessage({ message: "", type: "warning" });
// setTimeout(() => {
// activeName.value = "";
// }, 1);
// }
};
const onMouseMove = (event) => {
const deltaY = event.clientY - currentY;
currentY = event.clientY;
setScrollY(deltaY);
};
document.addEventListener("mousedown", (event) => {
mouseDown = true; mouseDown = true;
lastY = event.clientY; lastY = event.clientY;
currentY = event.clientY; currentY = event.clientY;
document.addEventListener("mousemove", onMouseMove); document.addEventListener("mousemove", onMouseMove);
}); });
//
function onMouseMove(event) { document.addEventListener("mouseup", (event) => {
if (mouseDown) {
let deltaY = event.clientY - currentY;
currentY = event.clientY;
setScrollY(deltaY);
}
}
//
document.addEventListener("mouseup", function (event) {
mouseDown = false; mouseDown = false;
let deltaY = event.clientY - lastY; const deltaY = event.clientY - lastY;
console.log("变化", deltaY);
flipPage(deltaY); flipPage(deltaY);
document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mousemove", onMouseMove);
}); });
const topicInfoRef = ref(null);
const setScrollY = (y) => { const preventScroll = (event) => {
if (topicInfoRef.value) { event.preventDefault();
topicInfoRef.value.scrollTop = topicInfoRef.value.scrollTop - y;
}
}; };
const flipPage = (y) => {
if (topicInfoItemRef.value) { function PageRest() {
topicInfoRef.value.scrollTop = 0; const type = router.currentRoute.value.query.type;
if (y < -80) {
let is = topStore.next(); if (type == "view") {
if (!is) { PageType.value = "home";
ElMessage({ message: "没有更多了", type: "warning" });
}
}
else if (y > 80) {
let is = topStore.prev();
if (!is) {
ElMessage({ message: "到顶了", type: "warning" });
}
}
}
};
const handleClick = (e) => {
if (e == "解析" && !topStore.Topics[topStore.index-1].isAnswer) {
ElMessage({ message: "未作答不能查看解析", type: "warning" });
setTimeout(() => {
activeName.value = "视频";
}, 1);
}
};
onMounted(() => {
topStore.init(); topStore.init();
router.back();
return;
}
topStore.init();
router.replace({
path: "/",
});
// router.back()
}
function pageInit() {
useUserStore().UserInfo();
const type = router.currentRoute.value.query.type;
console.log(type);
if (type == "view") {
//
console.log(questionList.value);
PageType.value = "view";
return;
}
topStore.init();
}
pageInit();
onMounted(() => {
document.addEventListener("wheel", onScroll, { passive: true });
document.addEventListener("wheel", preventScroll, { passive: false });
});
const onScroll = (event) => {
if (isFlipping.value) return;
const deltaY = event.deltaY;
flipPage(-deltaY);
};
onUnmounted(() => {
document.removeEventListener("wheel", onScroll);
document.removeEventListener("wheel", preventScroll);
});
watch(isFlipping, (newVal) => {
if (newVal) {
setTimeout(() => {
isFlipping.value = false;
}, 700);
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
img {
width: 100%;
}
.scroll-container {
overflow: hidden;
width: 100vw;
height: 100vh;
}
.homeBox { .homeBox {
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-image: url("@/assets/image/loginback.jpg"); background-image: url("@/assets/image/loginback.jpg");
background-size: cover; // background-size: cover;
// background-position: center; // background-repeat: no-repeat;
background-repeat: no-repeat; // transition: transform 0.7s;
transform-style: preserve-3d;
}
.main { .main {
width: 100%; width: 100%;
//
flex: 1; flex: 1;
background-color: #ededed; background-color: #ededed;
display: flex; display: flex;
@ -189,87 +274,64 @@ onMounted(() => {
justify-content: space-between; justify-content: space-between;
box-sizing: border-box; box-sizing: border-box;
padding: 20px; padding: 20px;
.topicInfo { .topicInfo {
// animation-duration: 2s;
// animation-delay: 250ms;
width: 30%; width: 30%;
height: 100%; height: 100%;
// background-color: #f0f9cc;
overflow: hidden; overflow: hidden;
position: relative; // background-image: url("@/assets/image/tibg.jpg");
background-image: url("@/assets/image/tibg.jpg");
background-size: cover; // background-size: contain;
// background-position: center; // background-repeat: no-repeat;
background-repeat: no-repeat; // background-position: center;
background-position: left left;
.topicInfoItem { .topicInfoItem {
// top: -10px;
// animation-duration: 2s;
// animation-delay: 250ms;
height: 100%; height: 100%;
width: 100%; width: 100%;
box-sizing: content-box;
// border: 1px solid red;
} }
} }
.topicAnswer { .topicAnswer {
width: 69%; width: 69%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
.SelectAnswer {
width: 97%;
margin: 0 auto;
border-bottom: 1px #43cf7c solid;
height: 7%;
display: flex;
align-items: center;
justify-content: space-around;
}
.answerInfo { .answerInfo {
width: 100%; width: 100%;
height: 92%; height: 92%;
box-sizing: border-box; box-sizing: border-box;
padding: 20px; padding: 20px;
// background-color: #f0f9cc; // background-image: url("@/assets/image/videoBack.jpg");
background-image: url("@/assets/image/videoBack.jpg"); background-size: cover;
background-size: cover; // background-position: center;
background-position: center; // background-repeat: no-repeat;
background-repeat: no-repeat; //
}
// background-color: #F0F9CC;
}
}
}
}
.selectInput {
display: flex; display: flex;
width: 100%; flex-direction: column;
height: 100%; align-items: center;
padding: 7px 10px; justify-content: center;
border: 2px #000000 solid;
border-radius: 30px;
input {
background-color: #00000000; /* 透明背景 */
border: none; /* 无边框 */
outline: none; /* 去除聚焦时的轮廓 */
padding: 0; /* 无内边距 */
margin: 0; /* 无外边距 */
width: 100%;
} }
} }
}
}
.jiexi { .jiexi {
word-break: normal; word-break: normal;
word-wrap: break-word; word-wrap: break-word;
} }
.answerNav { .answerNav {
display: flex; display: flex;
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
} }
.StarIcon { .StarIcon {
// float: right;
margin-right: 3vw; margin-right: 3vw;
display: flex;
align-content: center;
justify-content: center;
align-items: center;
} }
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="userPage"> <div class="userPage">
<div style="height: 3vh;margin: 0 auto;width: 97%;"> <div style="height: 3vh;margin: 0 auto;width: 97%;">
<el-page-header @back="router.push('/')"> <el-page-header @back="goback()">
<template #content> <template #content>
<span class="text-large font-600 mr-3"> 个人信息 </span> <span class="text-large font-600 mr-3"> 个人信息 </span>
</template> </template>
@ -14,9 +14,9 @@
<div class="userBox"> <div class="userBox">
<div class="userInfo"> <div class="userInfo">
<div class="userT" @click="drawer = true"> <div class="userT" @click="drawer = true">
<el-avatar :size="150" :src="useSotr.avatar" /> <el-avatar :size="150" :src="userInfo.avatar" />
</div> </div>
<div class="userName">{{ useSotr.username }}</div> <div class="userName">{{ userInfo.nickname }}</div>
<!-- <div class="userName" @click="router.push('/')">返回首页</div> --> <!-- <div class="userName" @click="router.push('/')">返回首页</div> -->
</div> </div>
<div class="collectionTopic"> <div class="collectionTopic">
@ -24,9 +24,10 @@
<div class="collectionList"> <div class="collectionList">
<div <div
class="collectionTme" class="collectionTme"
v-for="emit in topStore.collectTopics" v-for="emit in cpllectList"
:key="emit.id" :key="emit.id"
:Topic="emit" :Topic="emit"
@click="goQuestion(emit)"
> >
<p> <p>
[{{ emit.type == "select" ? "选择题" : "填空题" }}]{{ [{{ emit.type == "select" ? "选择题" : "填空题" }}]{{
@ -68,7 +69,7 @@
<div class="infoItme"> <div class="infoItme">
<div class="text">用户名</div> <div class="text">用户名</div>
<el-input <el-input
v-model="userForm.username" v-model="userForm.nickname"
style="width: 240px" style="width: 240px"
placeholder="Please input" placeholder="Please input"
:disabled="!isUpdata" :disabled="!isUpdata"
@ -138,6 +139,167 @@
</el-dialog> </el-dialog>
</template> </template>
<script setup>
import router from "@/router";
import ImageUpload from "@/components/ImageUpload.vue";
import { ElMessage, ElStep } from "element-plus";
import { ElMessageBox } from "element-plus";
import "element-plus/theme-chalk/el-message.css";
import { login } from "@/api/user/user";
import { updateUserInfo } from "@/api/user/user";
import { computed, onMounted, reactive, ref } from "vue";
import { useTopicStore } from "@/stores/topic.js";
import { useUserStore } from "@/stores/user.js";
import TokenService from "@/utils/token";
const cpllectList = computed(() => topStore.collectTopics);
function goQuestion(item){
useTopicStore().setQuestions(cpllectList.value,item)
router.push({
path: "/",
query: {
type: 'view'
}
});
}
function goback(){
router.go(-1);
}
const upload = (url) => {
console.log(url);
userForm.value.avatar = url;
};
const utLogin = () => {
TokenService.removeToken();
router.push("/login");
};
const dialogFormVisible = ref(false);
const useSotr = useUserStore();
const userInfo = computed(() => useSotr.user);
const topStore = useTopicStore();
const ruleFormRef = ref(null);
const drawer = ref(false);
const isUpdata = ref(false);
let userForm = ref({
username: null,
phone: null,
remark: null,
avatar: null,
});
const updateClick = async () => {
if (
! userForm.value
) {
ElMessage({ message: "请完善信息", type: "error" });
return;
}
let res = await updateUserInfo(userForm.value);
if (res.code == 200) {
ElMessage({ message: "更新成功", type: "success" });
isUpdata.value = false;
await useSotr.UserInfo();
userForm.value = userInfo.value
}
console.log(res);
};
const handleClose = (done) => {
if (isUpdata.value) {
ElMessageBox.confirm("更改未保存,确定退出吗?", {
confirmButtonText: "确定退出",
cancelButtonText: "继续修改",
})
.then(() => {
userForm.value = userInfo.value
isUpdata.value = false;
done();
})
.catch(() => {
// catch error
});
}
else {
done();
}
};
const ruleForm = reactive({
password: "",
newPassword: "",
newPassword2: "",
});
const usernamevalidate = async (rule, value, callback) => {
if (value === "") {
callback(new Error("请输旧密码"));
}
else {
let res = await login({ username: useSotr.username, password: value });
if (res.code == 200) {
callback();
}
else {
callback(new Error("密码错误"));
}
}
};
const validatePass = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输新入密码"));
}
else {
if (ruleForm.password !== "") {
if (!ruleFormRef.value) return;
ruleFormRef.value.validateField("》》");
}
callback();
}
};
const validatePass2 = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输确认新密码"));
}
else if (value !== ruleForm.newPassword) {
callback(new Error("密码不一致"));
}
else {
callback();
}
};
const submitForm = () => {
ruleFormRef.value.validate(async (valid) => {
if (valid) {
let res = await updateUserInfo({
password: ruleForm.newPassword,
});
if (res.code == 200) {
ElMessage({ message: "更新成功,请重新登录账号", type: "success" });
dialogFormVisible.value = false;
ruleForm.password = "";
ruleForm.newPassword = "";
ruleForm.newPassword2 = "";
TokenService.removeToken();
router.push("/login");
// await useSotr.UserInfo();
}
}
});
};
const rules = reactive({
password: [{ validator: usernamevalidate, trigger: "blur" }],
newPassword: [{ validator: validatePass, trigger: "blur" }],
newPassword2: [{ validator: validatePass2, trigger: "blur" }],
});
onMounted(async () => {
await useSotr.UserInfo();
userForm.value = userInfo.value;
setTimeout(() => {
console.log(userInfo.value)
}, 400);
});
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
.userPage { .userPage {
height: 100vh; height: 100vh;
@ -265,155 +427,3 @@
flex-direction: column; flex-direction: column;
} }
</style> </style>
<script setup>
import router from "@/router";
import ImageUpload from "@/components/ImageUpload.vue";
import { ElMessage, ElStep } from "element-plus";
import { ElMessageBox } from "element-plus";
import "element-plus/theme-chalk/el-message.css";
import { login } from "@/api/user/user";
import { updateUserInfo } from "@/api/user/user";
import { onMounted, reactive, ref } from "vue";
import { useTopicStore } from "@/stores/topic.js";
import { useUserStore } from "@/stores/user.js";
import TokenService from "@/utils/token";
const upload = (url) => {
userForm.avatar = url;
};
const utLogin = () => {
TokenService.removeToken();
router.push("/login");
};
const dialogFormVisible = ref(false);
const useSotr = useUserStore();
const topStore = useTopicStore();
const ruleFormRef = ref(null);
const drawer = ref(false);
const isUpdata = ref(false);
const userForm = reactive({
username: null,
phone: null,
remark: null,
avatar: null,
});
const updateClick = async () => {
if (
userForm.username == null ||
userForm.phone == null ||
userForm.avatar == null
) {
ElMessage({ message: "请完善信息", type: "error" });
return;
}
let res = await updateUserInfo(userForm);
if (res.code == 200) {
ElMessage({ message: "更新成功", type: "success" });
isUpdata.value = false;
await useSotr.UserInfo();
userForm.username = useSotr.username;
userForm.phone = useSotr.phone;
userForm.remark = useSotr.remark;
userForm.avatar = useSotr.avatar;
isUpdata.value = false;
}
console.log(res);
};
const handleClose = (done) => {
if (isUpdata.value) {
ElMessageBox.confirm("更改未保存,确定退出吗?", {
confirmButtonText: "确定退出",
cancelButtonText: "继续修改",
})
.then(() => {
userForm.username = useSotr.username;
userForm.phone = useSotr.phone;
userForm.remark = useSotr.remark;
userForm.avatar = useSotr.avatar;
isUpdata.value = false;
done();
})
.catch(() => {
// catch error
});
}
else {
done();
}
};
const ruleForm = reactive({
password: "",
newPassword: "",
newPassword2: "",
});
const usernamevalidate = async (rule, value, callback) => {
if (value === "") {
callback(new Error("请输旧密码"));
}
else {
let res = await login({ username: useSotr.username, password: value });
if (res.code == 200) {
callback();
}
else {
callback(new Error("密码错误"));
}
}
};
const validatePass = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输新入密码"));
}
else {
if (ruleForm.password !== "") {
if (!ruleFormRef.value) return;
ruleFormRef.value.validateField("》》");
}
callback();
}
};
const validatePass2 = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输确认新密码"));
}
else if (value !== ruleForm.newPassword) {
callback(new Error("密码不一致"));
}
else {
callback();
}
};
const submitForm = () => {
ruleFormRef.value.validate(async (valid) => {
if (valid) {
let res = await updateUserInfo({
password: ruleForm.newPassword,
});
if (res.code == 200) {
ElMessage({ message: "更新成功,请重新登录账号", type: "success" });
dialogFormVisible.value = false;
ruleForm.password = "";
ruleForm.newPassword = "";
ruleForm.newPassword2 = "";
TokenService.removeToken();
router.push("/login");
// await useSotr.UserInfo();
}
}
});
};
const rules = reactive({
password: [{ validator: usernamevalidate, trigger: "blur" }],
newPassword: [{ validator: validatePass, trigger: "blur" }],
newPassword2: [{ validator: validatePass2, trigger: "blur" }],
});
onMounted(async () => {
await useSotr.UserInfo();
userForm.username = useSotr.username;
userForm.phone = useSotr.phone;
userForm.remark = useSotr.remark;
userForm.avatar = useSotr.avatar;
});
</script>

View File

@ -22,6 +22,7 @@ export default defineConfig({
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) '@': fileURLToPath(new URL('./src', import.meta.url))
} }
} }
}) })